comp.lang.ada
 help / color / mirror / Atom feed
From: "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de>
Subject: Re: Ada DB bindings and APQ
Date: Wed, 15 Dec 2004 19:26:58 +0100
Date: 2004-12-15T19:26:58+01:00	[thread overview]
Message-ID: <5s8i4q5psxsn.ap1vrcl5pf02$.dlg@40tude.net> (raw)
In-Reply-To: 4KOvd.54$jT5.8@read1.cgocable.net

On Tue, 14 Dec 2004 23:05:17 -0500, Warren W. Gay VE3WWG wrote:

> Dmitry A. Kazakov wrote:

>> Connection could be just a handle to some dynamic-scope connection object
>> with reference counting. This will solve both the problem of above and
>> still allow cloning connections.
> 
> I didn't like the use of handles for database objects. I purposely
> stuck to using controlled objects, so that they can go out of
> scope gracefully, be finalized (perhaps committed or rolled back)
> and then destructed. Handles, like open Ada File_Types, never
> get that maintenance.

Let's make them derived from Ada.Finalization.Controlled. BTW, I have an
implementation in simple components:

http://www.dmitry-kazakov.de/ada/components.htm

if Root_Connection_Type were limited controlled, derived from
Object.Entity, then I could create handles just by instantiating
Object.Handle. Root_Query_Type can hold a handle to its connection. This
will ensure that the connection will not go away until at least one query
is alive.

>> Yes, but from user's perspective, at least one query per connection is
>> always necessary. In some cases the user will need more, but not so often.
>> So the idea is that he just creates a connection and then does with it
>> anything he would do with a query. Further many "connection-level" things
>> require a query, if they return result sets, like "SHOW TABLES".
> 
> The thing is that you normally only create and connect to
> the database once in the whole application (at least in the
> normal case). You pass around the connection in the user
> data in GUI programs or any other way you like in non-GUI
> programs.
> 
> You then create, use and finalize Query_Type objects as
> required, occaisionally specifying a connection when
> required. This is really not that onerous to code. The
> code reads better, because the programmer has a clear
> concept of a connection and a query. By rolling it all
> up into one object that does "all", the programmer must
> visualize the components that are participating behind
> the scenes.

Just call it Database_Type! (:-))

>> BTW, one could get rid of query type altogether if there would be two
>> different connection-cloning. One that returns a handle to a new
>> "connection" (physically just new query) for the same underlying connection
>> object, another that makes a new connection.
>> 
>> I do not see much sense in all that levels of types exposed to the user. In
>> ODBC it is even one more: environment > connection > statement. It is
>> rather implementation details to me. (Everything is a file (:-))
> 
> ODBC is not the only one. Sybase implements an object that
> also fills this role. I believe that you want to keep the
> objects well separated by function, and I'll admit that I
> compromised principle by combining environment & connection.
> But I think OO design principles are such that you don't
> want to roll everything into one massive object.

Right, if the functionality differs. But so far there are little or no
things which can be made with a connection. That is different to ODBC. Also
ODBC has prepared statements. And that all just does ODBC too complex to
use.

> Now having said that, if you really insist on a one-object
> approach, you might want to test drive the idea by
> rolling your own "interface package" if you will, that
> does just that using the APQ provided types. But I believe
> that you'll quickly arrive at the unhappy conclusion that
> it just gets very messy, and results in a more complicated
> to understand object.

I already did it for ODBC (it is presently under test.) Of course it is
rather a specialized package to provide object persistence. But basically
it has only one type: Persistent_Storage_Handle, which is a handle to
Persistent_Storage_Object. I am considering to do the same with APQ. When
do you plan to ship v 2.2, BTW?

> I prefer to have 2 simple objects
> instead of one complicated to understand object. The
> code is much easier to read and understand this way.
> It also separates the finalization of the query from the
> finalization of the connection.

I had in mind:

declare
   DB : DB_Handle := Connect (Engine_MySQL, "localhost", "testdb",...);
begin
   Prepare (DB, "SELECT ...);
   Execute (DB);
   Fetch (DB);
   ...
end;

>>>>5. Arguably, connection should maintain list of all queries.
>>>
>>>You seem to be at cross purposes. First you want connection
>>>and query rolled into one, and then the connection should
>>>maintain a list of queries?
>> 
>> Internally of course. This could be necessary for "light-weight" connection
>> cloning.
>> 
>> Handle --> Query_Object --> Connection_Object
>> 
>> 1. Handle copy (+1 reference count of Query_Object)
>> 2. Light-weight copy: creates new query (+1 reference count of connection)
>> 3. Heavy-weight copy: creates a new query and a new connection
> 
> When designing an API, I always try to look at the way
> it is going to be used and why it must exist. I shy away
> from unnecessary API, unless it is frequently needed (to
> save or simplify code).
> 
> So coming back to this, I have to ask, what is the
> problem that this is intended to solve?

You will get rid of parallel hierarchy of types:

Root_Connection_Type <- MySQL.Connection_Type
     |                                      |
Root_Query_Type <- MySQL.Query_Type

Ada is unable to provide any consistency here. You can mistakenly use
PostgreSQL.Query_Type with MySQL.Connection_Type. You can finalize
connection before a query that depends on it etc. You will have problems
with aliasing and side effects.

>>>>6. At least a rudimentary tables management:
>>>>
>>>>   Get_Tables (Query : in out Root_Query_Type);
> ...
>> Basically because of PostgreSQL, which lacks SQL query for that.
> 
> I think you can derive it from some "system tables".

PostgreSQL ODBC driver should know...

>> In that case you need to enumerate tables, table columns, their types.
>> Which BTW would require even more complex stuff: to determine Ada data type
>> most fitting to the column type. My case is much simpler. The application
>> starts, it checks if DB exists, if not, it creates that empty. I believe,
>> this is about 80% of needs for small applications.
> 
> These kinds of operations are important for SQL-helper
> tools, but are not the normal kinds of operations for
> normal applications, which tend to be more static.

But somebody should create that tables! It is quite normal that application
initializes tables upon first start. Consider an e-mail program. It should
store it address book into a DB of user choice. How to implement it in a DB
independent way?
 
>> See, this is why they should not be separated (at least, as long as Ada
>> does not support parallel type hierarchies.)
>> 
>> Anyway, there should be a uniform way of putting values into requests
>> separated from SQL-keywords, and, probably, names of tables, of columns
>> etc.
> 
> Doing table names in a portable way is problematic. Some databases
> are not case sensitive, but they are case sensitive when they come
> to TABLE names. Others can be configured to force lowercase table
> names (MySQL IIRC), still others are always case sensitive (Sybase).
> 
> This is why "case policy" was introduced into APQ 2.2. This is also
> why it is necessary to distinguish between certain SQL building
> APIs and other others like Append_Quoted.
> 
> Believe me, if there was a unified way to do it all, I would have
> welcomed it. But the reality is a bit more complicated than that ;-)

The method that places a value into a query should simply dispatch on the
query type. The implementation is then DB specific and will encode the
value as appropriate for the DB.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de



  reply	other threads:[~2004-12-15 18:26 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-12-12 17:42 Ada DB bindings and APQ Dmitry A. Kazakov
2004-12-14  7:25 ` Warren W. Gay VE3WWG
2004-12-14 17:37   ` Dmitry A. Kazakov
2004-12-14 18:29     ` Georg Bauhaus
2004-12-14 19:45       ` Dmitry A. Kazakov
2004-12-14 21:06         ` Georg Bauhaus
2004-12-15  8:19           ` Ole-Hjalmar Kristensen
2004-12-15 17:20           ` Dmitry A. Kazakov
2004-12-16 13:28             ` Georg Bauhaus
2004-12-17 13:23               ` Dmitry A. Kazakov
2004-12-14 23:26         ` Brian May
2004-12-15 17:43           ` Dmitry A. Kazakov
2004-12-15 21:54             ` Brian May
2004-12-15  4:05     ` Warren W. Gay VE3WWG
2004-12-15 18:26       ` Dmitry A. Kazakov [this message]
2004-12-16  2:53         ` Warren W. Gay VE3WWG
2004-12-18 16:43           ` Dmitry A. Kazakov
2004-12-18 20:36             ` Warren W. Gay VE3WWG
2004-12-18 22:21               ` Dmitry A. Kazakov
2004-12-19  0:53                 ` Warren W. Gay VE3WWG
2004-12-19 12:21                   ` Dmitry A. Kazakov
2004-12-20  5:33                     ` Warren W. Gay VE3WWG
2004-12-20 20:01                       ` Dmitry A. Kazakov
2004-12-20 20:54                         ` Warren W. Gay VE3WWG
2004-12-14 22:40   ` Brian May
2004-12-15  3:23     ` Warren W. Gay VE3WWG
2004-12-15 15:01       ` Georg Bauhaus
2004-12-17  4:31         ` Brian May
2004-12-15 10:48   ` Brian May
2004-12-16  1:40     ` Brian May
2004-12-16  3:10       ` Warren W. Gay VE3WWG
2004-12-17  4:55         ` Brian May
2004-12-17 11:13           ` Warren W. Gay VE3WWG
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox