List:MySQL++« Previous MessageNext Message »
From:Warren Young Date:August 15 2007 5:35am
Subject:SSQLSv2 design discussion
View as plain text  
It's clear to me that SSQLSv2 needs to be some kind of specialized
declaration language that's translated by a tool to C++ implementation
and header files.  The main goal is to fix the type safety and
debuggability issues people have had with SSQLS.

The make(1) rules for this look like this:

     .SUFFIXES: .ssqls
     .ssqls.cpp:
         ssqlsxlat -i $<

     my-module.o: my-module.cpp stock.cpp

This says my-module.cpp also needs stock.cpp to be built, and how to
build it using ssqlsxlat, the tool we create along with the MySQL++
library.  You can do essentially the same thing in other build systems,
too, or you can run the tool by hand if your declarations change rarely.

What I've not been certain about is what sort of syntax to use in .ssqls
files.  I'm now thinking about something very simple, like the
following.  First, the file stock.ssqls:

     include common.ssqls

     table stock alias SQLStock filebase ssqls_stock:
         field item type bigint alias id not null auto_increment
         field num type bigint
         field weight type double
         field price type double
         field sdate type date

And common.ssqls:

      option implementation_extension cc
      option header_extension hh
      option use_accessors getX

You could put the option declarations into the same file as the table
declaration, but I think this will be a popular way to do things, since
even the MySQL++ examples now have more than one table.  Alternately,
you can put *everything* into a single file, even multiple table
declarations; ssqlsxlat won't care.

The above declarations create ssqls_stock.hh:

     class SQLStock : public mysqlpp::SSQLS {
     public:
	SQLStock();
         SQLStock(
             mysqlpp::sql_bigint f1,
             mysqlpp::sql_bigint f2,
             mysqlpp::sql_double f3,
             mysqlpp::sql_double f4,
             mysqlpp::sql_date f5);

         mysqlpp::sql_bigint getId() const;
         mysqlpp::sql_bigint getNum() const;
         mysqlpp::sql_double getWeight() const;
         mysqlpp::sql_double getPrice() const;
         const mysqlpp::sql_date& getSdate() const;

         void getId(mysqlpp::sql_bigint value);
         void getNum(mysqlpp::sql_bigint value);
         void getWeight(mysqlpp::sql_double value);
         void getPrice(mysqlpp::sql_double value);
         void getSdate(const mysqlpp::sql_date& value);

     private:
         mysqlpp::sql_bigint id_;
         mysqlpp::sql_bigint num_;
         mysqlpp::sql_double weight_;
         mysqlpp::sql_double price_;
         mysqlpp::sql_date sdate_;

         bool id_is_set_;

         static const char* table_name_;
     };

It also creates ssqls_stock.cc, with the implementation of the member
functions declared in the .hh file.

We explicitly set a base name for output files with the "filebase"
keyword in the table declaration; if that isn't given we will use the
table alias if given, or the table name if not.  We've also overridden
the default file name extension style, which is .cpp and .h.

Think of the syntax of .ssqls files as a pastiche of Python and SQL
syntax: whitespace is significant, case is preserved but insignificant
in comparisons, quotes are optional unless needed to preserve spaces in
names, and named options ("type," "alias," "{not_}null," "filebase"...)
let us accept them in any order.  It's a little verbose, but it's better
than the XML ideas I've been kicking around for the last year or so, and
probably nearly as easy to parse.  (I still have to write a tokenizer
this way instead of using an existing XML parser, but after that it's
walking trees no matter which way I go.)

All SSQLSes will derive from a common base class, if for no other reason
than it means we can avoid using so many template member functions in
the Query class.  It will also avoid a lot of repeated code between
SSQLSes, as compared to what is generated in the current scheme.
Hopefully this will bring binary sizes and compile times down a bit;
MySQL++ is a bit of a pig when using SSQLS right now.

Notice that the SSQLS declaration uses SQL type names, not C++ type
names, and generated code uses the types declared in MySQL++'s
sql_types.h.  This frees the programmer from having to guess the correct
C++ type name to use for a given SQL field type.  Maybe there is a good
argument for letting a programmer pick a different C++ type that also
works but has different properties, but if so, that can be supported via
an option along the same lines as "alias".

The "option" statements let you control naming scheme details.  By
default it will output code in a style close to that used within
MySQL++; if we have to pick a default, it might as well be that.  But I
realize this is not the worldwide standard, so wherever possible it
should give you the option to change its output code style.

The "alias" option on a field or table name lets you use a different
name in your C++ code than is used for the corresponding entity in the
database.

I envision a desire for many different accessor styles.  "get_x" is an
obvious one.  Another popular one we could call "unified": the same
method name is used for both get and set operations, the former taking a
value and returning void, and the latter swapping that.  If you declare
no accessor style, you get the same interface as offered by SSQLSv1:
public data members and no accessor methods.

A side benefit of the new accessor feature is a solution to the auto
increment problem brought up recently by Graham Reitz.  Because data
members are hidden behind public member functions, we will know when a
field has been explicitly set ("id_is_set_ == true"), and when it
retains its default.  If it still retains its default and it is also
marked as auto_increment, we will know to leave it out when building an
INSERT or UPDATE query.

The addition of trailing underscores when using private members for the
field variables is not purely a style issue.  It avoids a name conflict
if you use the unified accessor style at the same time.  If you don't
use accessors, it won't decorate the variable names at all.

We can add SSQLSv1 and MySQL database schema parsing (a la dbinfo.cpp)
to ssqlsxlat.  In each case, it spits out a .ssqls file:

     ssqlsxlat -1 module-containing-ssqlsv1-decls.cpp -o tablename.ssqls
     ssqlsxlat -s my.server.org -u fred -p wilma -d dbname \
         -t tablename -o tablename.ssqls

If you give both -i (read from .ssqls file) and -o (write one out) you
get a debugging feature for free.  Programmer sez to tool: "Tell me how
you understand the contents of this file, ssqlsxlat."  This also
suggests how the previous two features work: they just build up the same
type of parse tree created when reading in a .ssqls file, and -o walks
that same tree, writing out its contents in .ssqls syntax.

Thread
SSQLSv2 design discussionWarren Young15 Aug
  • Re: SSQLSv2 design discussionChris Frey15 Aug
    • Re: SSQLSv2 design discussionWarren Young16 Aug
      • Re: SSQLSv2 design discussionChris Frey16 Aug
  • RE: SSQLSv2 design discussionJoel Fielder15 Aug
    • RE: SSQLSv2 design discussionJoel Fielder15 Aug
      • Re: SSQLSv2 design discussionWarren Young16 Aug
        • RE: SSQLSv2 design discussionJoel Fielder17 Aug
    • Re: SSQLSv2 design discussionWarren Young16 Aug