static globals in SSQL macro expansion -> multiple definitionlinker errors
12 answers - 1906 bytes -

Hi,
While we're talking about wish-lists for version 2.0, I have an item to
contribute. In fact, it surprised me this hasn't been addressed yet, or
maybe I'm missing something.
The SSQL macro expansion will create static globals that are being
defined (assinged) as part of the macro. With the ssqls-pretty tool it
was easy to see that
sql_create_7(PriceData,
6,
7,
Date, date,
int, open,
int, high,
int, low,
int, close,
int, volume,
int, suspended);
expands into
struct PriceData {
[]
static const char *names[];
static const char *_table;
[]
};
[]
const char *PriceData::names[] = {
"date" , "open" , "high" , "low" , "close" , "volume" , "suspended" };
[]
This is fine and dandy, as long as the SSQL macro expansion is used in
only one .cpp source file in the application. If the SSQL macro is put
into a header file and include it into multiple .cpp source files, then
the linker will invariably complain that names and _tables are multiply
defined symbols.
I've only tried this with version 1.7.35 so far, but I haven't seen
anything in the release notes since that this behavior has been changed.
Can this be fixed? Not being able to share SSQL structures across
compilation units inhibits code modularity in cases where the Database
table is the common data structure shared between many different clients
in an application.
Could the macro be split into two or take an extra flag to optionally
not generate the definition for the globals? I'd be glad to give this a
shot, but I wanted to hear from the community if there is any reason
other than lack of volunteers. This has come up before; I found mailing
list articles as far back as 2001 on this.
Cheers,
Wolfram
No.1 | | 1069 bytes |
| 
Wed, Jul 06, 2005 at 01:15:33AM -0700, Wolfram Arnold wrote:
Could the macro be split into two or take an extra flag to optionally
not generate the definition for the globals? I'd be glad to give this a
shot, but I wanted to hear from the community if there is any reason
other than lack of volunteers. This has come up before; I found mailing
list articles as far back as 2001 on this.
Personally, I'd say go for it. Keeping all the logic in one macro / header
(i.e. custom-macros.h) is probably the most maintenance friendly, since the
macro needs to be expanded for the names anyway, and you don't want to
duplicate it anywhere.
Something like this might be useful:
// file: tables.h - define it
sql_create_5(stock, );
// file: stock.cpp - the only file that has the static data
#define SSQLS_GENERATE_STATICS
#include "tables.h"
// file: client.cpp - simple user module
#include "tables.h"
Might take some creativity to do that, but I think it's possible.
- Chris
No.2 | | 1200 bytes |
| 
Thanks for that suggestion, Chris. I'll play with it.
-Wolfram
Wed, 2005-07-06 at 06:39 -0400, Chris Frey wrote:
Wed, Jul 06, 2005 at 01:15:33AM -0700, Wolfram Arnold wrote:
Could the macro be split into two or take an extra flag to optionally
not generate the definition for the globals? I'd be glad to give this a
shot, but I wanted to hear from the community if there is any reason
other than lack of volunteers. This has come up before; I found mailing
list articles as far back as 2001 on this.
Personally, I'd say go for it. Keeping all the logic in one macro / header
(i.e. custom-macros.h) is probably the most maintenance friendly, since the
macro needs to be expanded for the names anyway, and you don't want to
duplicate it anywhere.
Something like this might be useful:
// file: tables.h - define it
sql_create_5(stock, );
// file: stock.cpp - the only file that has the static data
#define SSQLS_GENERATE_STATICS
#include "tables.h"
// file: client.cpp - simple user module
#include "tables.h"
Might take some creativity to do that, but I think it's possible.
- Chris
No.3 | | 1443 bytes |
| 
Wolfram Arnold wrote:
While we're talking about wish-lists for version 2.0,
News to me. Since the beta was just released, the v2.0 feature set is
frozen, as far as I'm concerned. (To me, beta means "feature-complete,
but may have bugs.")
That's not to say that I'm not accepting patches for v2.0. Just that
it's a little late
The SSQL macro expansion will create static globals that are being
defined (assinged) as part of the macro.
This has been on the Wishlist for a long time. The copy you have in
your 1.7.35 version has itlook for "static". I point that out
because it contains two suggestions for fixing it as well.
I added a third possibility recently:
"redesign the SSQLS mechanism entirely. Instead of defining SSQLSes
by instantiating macros, you could declare the structure in, say, an XML
format, which could be tranformed (XSLT? Perl + SAX?) into code very
much like in the current SSQLS macros, except that it would generate
separate .cpp and .h files for each structure. In addition to solving
the static member problem, it would have other advantages, like
side-stepping the Borland C++ macro size limit."
I like this a lot better than the other two choices. The macros are
ugly and unmaintainable. We have the technology to build a better
mechanism.
This would not be a trivial patch, of course.
No.4 | | 224 bytes |
| 
Chris Frey wrote:
// file: stock.cpp - the only file that has the static data
#define SSQLS_GENERATE_STATICS
#include "tables.h"
Doesn't work. I tried it. You can't have an ifdef inside a macro.
No.5 | | 536 bytes |
| 
Wed, Jul 06, 2005 at 11:52:25AM -0600, Warren Young wrote:
Chris Frey wrote:
>// file: stock.cpp - the only file that has the static data
>#define SSQLS_GENERATE_STATICS
>#include "tables.h"
Doesn't work. I tried it. You can't have an ifdef inside a macro.
You can define other sub macros conditionally though, and call them from
the first. The macro that outputs the static definitions would be
defined or empty depending on the #define flag.
- Chris
No.6 | | 1884 bytes |
| 
Chris Frey wrote:
You can define other sub macros conditionally though, and call them from
the first.
True
What do you think of the idea of generating separate .cpp and .h files
for each SSQLS from an XML input file? I like it because:
1. It generates code you can read. (It doesn't _have to_, I know, but
it will be a design requirement.)
2. It generates code you can debug. Ever gotten compiler errors on the
final line of an SSQLS declaration, because of an error in the expanded
macro? I have. These messages are almost completely useless. And
heaven help you should try single-stepping into an SSQLS method call.
3. It gives us the opportunity to trade C macro punctuationitis
(trailing backslashes, token pasting syntax) for a better syntax. I
don't expect the boilerplate code to ever be as readable as pure C++
code, but it can be more readable than it is now.
4. The generated macro concept forces you into generating too much code.
custom.pl generates macros for up to N-member SSQLSes, even if you
never use all the {1N-1} instances. The library maintainer's
incentive is to make N large, so the end user never has to increase N,
even though most programs will never have SSQLSes approaching N members.
Complier limits and good sense, on the other hand, argue for lower
values of N. The closest you can come to a happy medium is when the
minimum number of compilers and bits of end-user code break when
upgrading the library.
5. Last but not least, it solves the static member problem naturally.
My only objection to it is that it requires special setup in the build
environment, or a separate by-hand step for those environments that
don't allow you to set up special build rules. To get those advantages,
I can live with this.
No.7 | | 2581 bytes |
| 
Wed, Jul 06, 2005 at 02:51:20PM -0600, Warren Young wrote:
1. It generates code you can read. (It doesn't _have to_, I know, but
it will be a design requirement.)
2. It generates code you can debug. Ever gotten compiler errors on the
final line of an SSQLS declaration, because of an error in the expanded
macro? I have. These messages are almost completely useless. And
heaven help you should try single-stepping into an SSQLS method call.
3. It gives us the opportunity to trade C macro punctuationitis
(trailing backslashes, token pasting syntax) for a better syntax. I
don't expect the boilerplate code to ever be as readable as pure C++
code, but it can be more readable than it is now.
4. The generated macro concept forces you into generating too much code.
custom.pl generates macros for up to N-member SSQLSes, even if you
never use all the {1N-1} instances. The library maintainer's
incentive is to make N large, so the end user never has to increase N,
even though most programs will never have SSQLSes approaching N members.
Complier limits and good sense, on the other hand, argue for lower
values of N. The closest you can come to a happy medium is when the
minimum number of compilers and bits of end-user code break when
upgrading the library.
5. Last but not least, it solves the static member problem naturally.
I like all those points too. In addition, the fewer macros there are,
the easier it is to separate things into C++ namespaces. When there
are naming conflicts with macros, the choices for fixing them are
limited.
My only objection to it is that it requires special setup in the build
environment, or a separate by-hand step for those environments that
don't allow you to set up special build rules. To get those advantages,
I can live with this.
This is a big disadvantage in my view. It adds a dependency to the
user's build process, not just to mysql++'s.
I would not be keen on writing XML in order to get C That would seem
a step backwards to me, compared to the usability we currently have
with macros. An sql_create() is pretty straightforward.
Every so often I ponder methods to get rid of the macros, but the direction
I would prefer to take would be some C++ method that is as easy to
use as the macros (not sure that's possible though). I'm uncomfortable
going in the other direction toward code generators, even with the above
advantages.
- Chris
No.8 | | 2084 bytes |
| 
Chris Frey wrote:
This is a big disadvantage in my view. It adds a dependency to the
user's build process, not just to mysql++'s.
Yes, it's a problem. But we are beset by problems currently, too. I am
proposing trading a large problem set for a smaller one.
I would not be keen on writing XML in order to get C
even if the library comes with good examples for you to hack up to
meet your personal requirements? I can't imagine it needing a syntax
more complicated than:
<ssqls name="MyStruct">
<int name="MyNumber"/>
<mysqlpp:Date name="MyDate"/>
</ssqls>
Pretty much the same as the current syntax.
Another advantage I forgot to mention is that you could put several of
these declarations into a single file, and the tool would be able to
spit out as many source files as needed.
And another advantage just popped out of the XML syntax I just invented:
because the types are tags, we can verify in advance that the caller is
using appropriate types. Currently, nothing stops someone from saying:
sql_create_3(doomed,
1, 3,
char*, x,
std::complex, y,
MStrangeType, z)
This will generate a perfectly legal C++ structure. But, using it will
at best cause the compiler to barf in the middle of some hideous macros.
Even worse, the code may compile, and then cause who knows what kind
of run-time havoc when trying to do the type conversions.
If the syntax is all that bugs you, we could make the generator accept
the current SSQLS macro syntax. It's pretty straightforward. The main
reasons not to are that it rules out several classes of tools (e.g.
XSLT) and it makes the parser more complex than it has to be. A middle
ground would be to write a translator from the SSQLS syntax to the new one.
I'm uncomfortable
going in the other direction toward code generators, even with the above
advantages.
If those advantages aren't sufficient, what would it take?
No.9 | | 2515 bytes |
| 
Wed, Jul 06, 2005 at 08:24:08PM -0600, Warren Young wrote:
If the syntax is all that bugs you, we could make the generator accept
the current SSQLS macro syntax. It's pretty straightforward. The main
reasons not to are that it rules out several classes of tools (e.g.
XSLT) and it makes the parser more complex than it has to be.
It is the syntax, I must admit (it's so top-heavy with markup), plus needing
some other dependency on my system to build. It's like the boost build
process which used to require a whole other make (Jam). Fortunately their
tarballs come with Jam source, so it is easy to compile it on pretty much
any system with a decent compiler.
I also like that the macros are part of C++ code. It's not some new
language that's added to a project. I'm reminded of Microsoft's special
interface language here.
Also, the idea of generating code usually tells me that something is
broken in the design or abstraction somewhere. The macro is code generation
too, but I consider it broken in the same respect. The downside is that
I can think of no other way to get SSQLS functionality other than using
some kind of code generation, so it is a necessary evil.
But overall, I guess my arguments against XML are more prejudices than
valid reasons. I'm not totally against code generation: I'm pondering
it myself for my own CPPHP project.
Doing it in XML may make it easier to GUI-ify or automate this.
The syntax makes me shudder, but it's the best in the field so far,
it seems. :-)
A middle
ground would be to write a translator from the SSQLS syntax to the new one.
This could be done as a macro itself. :-)
I'm uncomfortable
>going in the other direction toward code generators, even with the above
>advantages.
If those advantages aren't sufficient, what would it take?
If we go with XML, it would be nice to keep the macros around for a major
version cycle, even if marked deprecated with no guarantee that they would
keep up with their XML cousins. Would be easier to compare the advantages
that way.
I've sifted my way though the macros before, so I don't mind supporting
them for a while, even deprecated. They are pretty stable anyway.
If Wolfram sends a patch, I hope it is included, even if XML is the new
direction.
- Chris
No.10 | | 1758 bytes |
| 
Chris Frey wrote:
It is the syntax, I must admit (it's so top-heavy with markup),
XML can be ugly, but take another look at what I posted. It's very
nearly the same number of characters as current SSQLS definitions.
plus needing
some other dependency on my system to build.
Naturally if there's a separate tool, it will be built and installed
along with the library. There may be prerequisites like xsltproc or
Perl, by they're very readily available on all common systems, if not
installed already.
The only inconvenience to the user is when setting up the build system
for their own project. And most people will probably be suitably well
served by cutting-and-pasting from the examples' build system.
I'm reminded of Microsoft's special interface language here.
or Motif's, or Qt's, or There are a great many other projects
that have run into this same wall, and routed around it the same way.
Also, the idea of generating code usually tells me that something is
broken in the design or abstraction somewhere.
We're _creating types_ here, for a statically-typed language. Code must
be generated at or before compile time, somehow. Abstractions don't
enter into it.
I'm not totally against code generation: I'm pondering
it myself for my own CPPHP project.
Then you can consider this a prototype pass for your own effort. Steal
the result when we get it right. :)
The syntax makes me shudder, but it's the best in the field so far,
it seems. :-)
Nobody likes XML for XML's sake. We like it because of all the tools
that have sprung up around it.
No.11 | | 835 bytes |
| 
Hi,
I am using mysql++ very lightlyconnect to a DB, run a
select/insert/update and use the result set. Now I have 2 things I
want to I want to figure how to keep the connection always on
and be able to check if the connection has disconnected and if so,
then connect to the db again.
Is it a big overhead to keep connecting every 1/2 a sec or so? If
it is then I would like to have this feature where I can probably set
a idle time out and be able to check of the connection is down.
Also how do I get how many filed are returned by a select * from
query. I know how to get how many rows, but the col number and names,
how do I get that?
I have few other questions which I will send in a seperate email once
I am alittle clear as to what I want to do.
Thanks a ton
AS
No.12 | | 1122 bytes |
| 
Ankur G35 Saxena wrote:
I am using mysql++ very lightlyconnect to a DB, run a
select/insert/update and use the result set. Now I have 2 things I
want to I want to figure how to keep the connection always on
and be able to check if the connection has disconnected and if so,
then connect to the db again.
Use Connection::ping(). Here's why:
Is it a big overhead to keep connecting every 1/2 a sec or so?
Are you asking us to guess what the results of your benchmark testing
will be? That's a poor substitute for actually doing the tests
Also how do I get how many filed are returned by a select * from
query. I know how to get how many rows, but the col number and names,
how do I get that?
Look at the value_list() and field_list() member functions. See also
the fieldinf1 and dbinfo examples.
I have few other questions which I will send in a seperate email once
I am alittle clear as to what I want to do.
Please avail yourself of the manual first:
Two of the questions you've already asked are already addressed there.