comp.lang.ada
 help / color / mirror / Atom feed
* APQ
@ 2004-12-15 23:31 Brian May
  2004-12-16 11:34 ` APQ Warren W. Gay VE3WWG
  2004-12-17 13:54 ` APQ Dmitry A. Kazakov
  0 siblings, 2 replies; 32+ messages in thread
From: Brian May @ 2004-12-15 23:31 UTC (permalink / raw)


Hello,

Here are my suggested changes to APQ (not actually done or tested).

1. Decide on or write a "smart pointer" library. ie. a library that
manages pointers based on a reference count. Obviously the license
must be compatible with the license of APQ.

2. No change to Connection_Type or Root_Connection_Type.

3. Create new Database_Type. This type should not be
tagged. Applications will use this instead of the
Root_Connection_Type. It has the following data:

* Smart pointer to Root_Connection_Type'Class. This is dynamically
  allocated when the connection is created.

It has the following methods:

  * Connect method takes a string, which is the connection URL.  Note:
    Two ways of implementing:

    1. connect is hard-coded to support every possible database, and
       parses the URL itself.

    2. each database is registered in a global list, connect
       determines the most appropriate database based on prefix in URL
       and calls appropriate connect method with URL.

    The second method is more complicated but more flexible. In any
    case, changing this should not require changing the user API.

  * All methods associated with Root_Connection_Type. This does *not*
    include options to set options specific to the database, like user
    name or password. These call the appropriate routine in the
    Root_Connection_Type'Class. Status information should perhaps be
    cached, so it remains constant even after queries (might be more
    appropriate way to handle errors).

  * New_Query takes a *Database_Type* parameter, not a
    Root_Connection_Type parameter. This function constraints a query
    and saves a smart pointer to the Root_Connection_Type contained
    within the Database_Type variable.

  * Debatable: Function that returns smart pointer to
    Root_Connection_Type'Class.  This might be required to access
    database specific functions. Ideally it shouldn't be required.


4. Modify Root_Query_Type class:

   New_Query is the only function that takes a *Database_Type*
   parameter.

   The functions that use to require Root_Connection_Type now use the
   smart pointer that was saved instead.

   Why not make the procedures abstract instead of having them raise
   an Is_Abstract? This way the checks can be done at compile time.

   Execute already returns exception if not connected.

   Add methods for obtaining and clearing status information. This
   should be cached so if you execute two separate queries (in two
   separate variables) on the same database, you will get two status
   messages saved.


I hope this helps explain what I said earlier... I believe this solves
a number of concerns with the existing system in one go.

The major difference is that I have created a new Database_Type class,
which allows the Connection_Type to be shared in a safe manner between
the user Database_Type and the user Query_Type classes.

This would involve making incompatible changes to Root_Query_Type. It
might be possible to avoid this, not sure if it would be worth the
effort.

Comments?
-- 
Brian May <bam@snoopy.apana.org.au>



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
@ 2004-12-16  4:37 Christoph Karl Walter Grein
  0 siblings, 0 replies; 32+ messages in thread
From: Christoph Karl Walter Grein @ 2004-12-16  4:37 UTC (permalink / raw)
  To: comp.lang.ada

> 1. Decide on or write a "smart pointer" library. ie. a library that
> manages pointers based on a reference count. Obviously the license
> must be compatible with the license of APQ.

You could use my version of this library:

 http://home.t-online.de/home/christ-usch.grein/Ada/Safe_Pointers.html

It was published in Ada User Journal, Volume 20, Number 2 (Juli 1999)
and as a reprint in Ada Letters, Volume XIX, Number 4, December 1999. 
It's in a very liberal license.
__________________________________________________________
Mit WEB.DE FreePhone mit hoechster Qualitaet ab 0 Ct./Min.
weltweit telefonieren! http://freephone.web.de/?mc=021201




^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-15 23:31 APQ Brian May
@ 2004-12-16 11:34 ` Warren W. Gay VE3WWG
  2004-12-16 23:58   ` APQ Randy Brukardt
  2004-12-17 13:54 ` APQ Dmitry A. Kazakov
  1 sibling, 1 reply; 32+ messages in thread
From: Warren W. Gay VE3WWG @ 2004-12-16 11:34 UTC (permalink / raw)


Brian May wrote:
> Hello,
> 
> Here are my suggested changes to APQ (not actually done or tested).

I'll just respond briefly here, since I am on my way to
work..

> 1. Decide on or write a "smart pointer" library. ie. a library that
> manages pointers based on a reference count. Obviously the license
> must be compatible with the license of APQ.
> 
> 2. No change to Connection_Type or Root_Connection_Type.
> 
> 3. Create new Database_Type. This type should not be
> tagged. Applications will use this instead of the
> Root_Connection_Type. It has the following data:
> 
> * Smart pointer to Root_Connection_Type'Class. This is dynamically
>   allocated when the connection is created.
> 
> It has the following methods:
> 
>   * Connect method takes a string, which is the connection URL.  Note:
>     Two ways of implementing:

Ok, this makes sense because you don't know the type
of Connection_Type apriori. I generally favour Booch
components myself, which includes a smart pointer.

...

> 4. Modify Root_Query_Type class:
> 
>    New_Query is the only function that takes a *Database_Type*
>    parameter.
> 
>    The functions that use to require Root_Connection_Type now use the
>    smart pointer that was saved instead.
> 
>    Why not make the procedures abstract instead of having them raise
>    an Is_Abstract? This way the checks can be done at compile time.

Answer: I wanted to put some code at the top level so that I
wouldn't have to repeat it for every database. For some reason
the compiler wouldn't let me do it (perhaps I was missing
something). I would be happy to have this done, but I was
unable to make it so in practice. Maybe someone else can
figure it out.

>    Execute already returns exception if not connected.
> 
>    Add methods for obtaining and clearing status information. This
>    should be cached so if you execute two separate queries (in two
>    separate variables) on the same database, you will get two status
>    messages saved.

You have to be real careful here, because database products
like Sybase use callbacks and things can change. In fact, Sybase
was a monster to tame with its oodles of states and callbacks.

> I hope this helps explain what I said earlier... I believe this solves
> a number of concerns with the existing system in one go.

I'll try to respond more fully later on, but this seems to make
sense.

--
Warren W. Gay VE3WWG
http://home.cogeco.ca/~ve3wwg



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-16 11:34 ` APQ Warren W. Gay VE3WWG
@ 2004-12-16 23:58   ` Randy Brukardt
  2004-12-17  3:45     ` APQ Brian May
  0 siblings, 1 reply; 32+ messages in thread
From: Randy Brukardt @ 2004-12-16 23:58 UTC (permalink / raw)


"Warren W. Gay VE3WWG" <ve3wwg@NoSpam.cogeco.ca> wrote in message
news:Onewd.204$Wt5.95202@read2.cgocable.net...
...
> >    Why not make the procedures abstract instead of having them raise
> >    an Is_Abstract? This way the checks can be done at compile time.
>
> Answer: I wanted to put some code at the top level so that I
> wouldn't have to repeat it for every database. For some reason
> the compiler wouldn't let me do it (perhaps I was missing
> something). I would be happy to have this done, but I was
> unable to make it so in practice. Maybe someone else can
> figure it out.

I haven't looked at the code in question, but it certainly is possible to
have concrete operations and components on an abstract type (the type has be
abstract - if it is tagged - to have abstract subprograms). We do it all the
time in Claw and its related programs. That's the big difference between an
abstract type and an Ada 2005 interface (which can't have any data or
concrete subprograms).

                    Randy.







^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-16 23:58   ` APQ Randy Brukardt
@ 2004-12-17  3:45     ` Brian May
  2004-12-17  4:03       ` APQ Warren W. Gay VE3WWG
                         ` (2 more replies)
  0 siblings, 3 replies; 32+ messages in thread
From: Brian May @ 2004-12-17  3:45 UTC (permalink / raw)


>>>>> "Randy" == Randy Brukardt <randy@rrsoftware.com> writes:

    Randy> I haven't looked at the code in question, but it certainly
    Randy> is possible to have concrete operations and components on
    Randy> an abstract type (the type has be abstract - if it is
    Randy> tagged - to have abstract subprograms). We do it all the
    Randy> time in Claw and its related programs. That's the big
    Randy> difference between an abstract type and an Ada 2005
    Randy> interface (which can't have any data or concrete
    Randy> subprograms).

I tried to get it working, but couldn't:

...

   type Root_Connection_Type is abstract new Ada.Finalization.Limited_Controlled with private;

...

   procedure Connect(C : in out Root_Connection_Type) is abstract;
   procedure Connect(C : in out Root_Connection_Type; Same_As : Root_Connection_Type'Class) is abstract;

...

gcc-3.4 -c -gnata -gnatf -gnato -gnatwp -O0 comp_mysql.adb
apq.ads:126:14: abstract subprogram not allowed for type "Root_Connection_Type"
apq.ads:127:14: abstract subprogram not allowed for type "Root_Connection_Type"
apq.ads:584:09: nonabstract type has abstract subprogram "Connect"
gnatmake: "comp_mysql.adb" compilation error
make: *** [mysql1] Error 4

...

What did I do wrong? How do I create a abstract type that is derived
from Ada.Finalization.Limited_Controlled?

I thought I made it quite clear that Root_Connection_Type is abstract.

Should I try the same thing with GNAT?
-- 
Brian May <bam@snoopy.apana.org.au>



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-17  3:45     ` APQ Brian May
@ 2004-12-17  4:03       ` Warren W. Gay VE3WWG
  2004-12-17  4:38         ` APQ Brian May
  2004-12-17  8:59       ` APQ Stephen Leake
  2004-12-17 14:12       ` APQ Dmitry A. Kazakov
  2 siblings, 1 reply; 32+ messages in thread
From: Warren W. Gay VE3WWG @ 2004-12-17  4:03 UTC (permalink / raw)


Brian May wrote:
>>>>>>"Randy" == Randy Brukardt <randy@rrsoftware.com> writes:
>     Randy> I haven't looked at the code in question, but it certainly
>     Randy> is possible to have concrete operations and components on
>     Randy> an abstract type (the type has be abstract - if it is
>     Randy> tagged - to have abstract subprograms). We do it all the
>     Randy> time in Claw and its related programs. That's the big
>     Randy> difference between an abstract type and an Ada 2005
>     Randy> interface (which can't have any data or concrete
>     Randy> subprograms).
> 
> I tried to get it working, but couldn't:
> ...
>    type Root_Connection_Type is abstract new Ada.Finalization.Limited_Controlled with private;
> ...
>    procedure Connect(C : in out Root_Connection_Type) is abstract;
>    procedure Connect(C : in out Root_Connection_Type; Same_As : Root_Connection_Type'Class) is abstract;
> ...
> gcc-3.4 -c -gnata -gnatf -gnato -gnatwp -O0 comp_mysql.adb
> apq.ads:126:14: abstract subprogram not allowed for type "Root_Connection_Type"
> apq.ads:127:14: abstract subprogram not allowed for type "Root_Connection_Type"
> apq.ads:584:09: nonabstract type has abstract subprogram "Connect"
> gnatmake: "comp_mysql.adb" compilation error
> make: *** [mysql1] Error 4
> 
> What did I do wrong? How do I create a abstract type that is derived
> from Ada.Finalization.Limited_Controlled?

The error looks familiar, though I don't understand the reason
for the "limitation" that the compiler is imposing.

Warren.



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-17  4:03       ` APQ Warren W. Gay VE3WWG
@ 2004-12-17  4:38         ` Brian May
  2004-12-17  9:06           ` APQ Egil H. H�vik
  0 siblings, 1 reply; 32+ messages in thread
From: Brian May @ 2004-12-17  4:38 UTC (permalink / raw)


>>>>> "Warren" == Warren W Gay VE3WWG <ve3wwg@NoSpam.cogeco.ca> writes:

    Warren> The error looks familiar, though I don't understand the reason
    Warren> for the "limitation" that the compiler is imposing.

It would make perfect sense if I hadn't declared the type to be
abstract. If a type has any abstract methods, then the type must be
abstract too. This in turn prohibits creating any objects based on
this type. Child types do not need to be defined abstract if the
define all the abstract methods. I believe this is just what we
required for this situation.

However, in this case the type is abstract (or so I believe), hence
the error will not occur.

Obviously, I am wrong, because the error is occurring ;-).
-- 
Brian May <bam@snoopy.apana.org.au>



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-17  3:45     ` APQ Brian May
  2004-12-17  4:03       ` APQ Warren W. Gay VE3WWG
@ 2004-12-17  8:59       ` Stephen Leake
  2004-12-17 14:12       ` APQ Dmitry A. Kazakov
  2 siblings, 0 replies; 32+ messages in thread
From: Stephen Leake @ 2004-12-17  8:59 UTC (permalink / raw)
  To: comp.lang.ada

Brian May <bam@snoopy.apana.org.au> writes:

> I tried to get it working, but couldn't:

please post a _complete_ example, so we can try to compile it. The
most likely answer is that there is something wrong in the code you
didn't post.


-- 
-- Stephe




^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-17  4:38         ` APQ Brian May
@ 2004-12-17  9:06           ` Egil H. H�vik
  2004-12-17 11:42             ` APQ Brian May
  0 siblings, 1 reply; 32+ messages in thread
From: Egil H. H�vik @ 2004-12-17  9:06 UTC (permalink / raw)


"Brian May" <bam@snoopy.apana.org.au> wrote in message
news:sa41xdpsfnt.fsf@snoopy.apana.org.au...
> >>>>> "Warren" == Warren W Gay VE3WWG <ve3wwg@NoSpam.cogeco.ca> writes:
>
>     Warren> The error looks familiar, though I don't understand the reason
>     Warren> for the "limitation" that the compiler is imposing.
>
> It would make perfect sense if I hadn't declared the type to be
> abstract. If a type has any abstract methods, then the type must be
> abstract too. This in turn prohibits creating any objects based on
> this type. Child types do not need to be defined abstract if the
> define all the abstract methods. I believe this is just what we
> required for this situation.
>
> However, in this case the type is abstract (or so I believe), hence
> the error will not occur.
>

My guess is that your full declaration of Root_Connection_Type in the
private part
is not abstract:

...
   type Root_Connection_Type is abstract new
Ada.Finalization.Limited_Controlled with private;
...
private
   type Root_Connection_Type is abstract new
Ada.Finalization.Limited_Controlled with null record;
  -- full declaration. This must also be abstract
...


~egilhh





^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-17  9:06           ` APQ Egil H. H�vik
@ 2004-12-17 11:42             ` Brian May
  2004-12-17 22:55               ` APQ Brian May
  0 siblings, 1 reply; 32+ messages in thread
From: Brian May @ 2004-12-17 11:42 UTC (permalink / raw)


>>>>> "Egil" == Egil H H�vik <egil.harald.hoevik@REMOVEkongsberg.com> writes:

    Egil> My guess is that your full declaration of Root_Connection_Type in the
    Egil> private part
    Egil> is not abstract:

Good point. I meant to change it in both places, but I think I ended
up changing it in only one place...

Thanks for your assistance. Will try it out tomorrow.
-- 
Brian May <bam@snoopy.apana.org.au>



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-15 23:31 APQ Brian May
  2004-12-16 11:34 ` APQ Warren W. Gay VE3WWG
@ 2004-12-17 13:54 ` Dmitry A. Kazakov
  1 sibling, 0 replies; 32+ messages in thread
From: Dmitry A. Kazakov @ 2004-12-17 13:54 UTC (permalink / raw)


On Thu, 16 Dec 2004 10:31:49 +1100, Brian May wrote:

> 1. Decide on or write a "smart pointer" library. ie. a library that
> manages pointers based on a reference count. Obviously the license
> must be compatible with the license of APQ.

I have one in http://www.dmitry-kazakov.de/ada/components.htm
 
> 3. Create new Database_Type. This type should not be
> tagged. Applications will use this instead of the
> Root_Connection_Type. It has the following data:
> 
> * Smart pointer to Root_Connection_Type'Class. This is dynamically
>   allocated when the connection is created.

It should *be* a smart pointer. Generally with components it goes as
follows:

package APQ.Handles is
   type Database_Type is private;
   -- Here all visible methods
   function Connect (...) return Data_Base_Type;
   ...
private
   -- Wrapper type for Root_Connection_Type'Class, to implement
   -- mix-in. Necessary, only because Root_Connection_Type is not
   -- a descendant of Object.Entity. Ptr points to the connection
   -- object allocated by Connect. Data_Base_Object itself is also
   -- allocated by Connect. It is destroyed as soon as the
   -- last handle to it disappears.
   --
   type Root_Connection_Ptr is access Root_Connection_Type'Class;
   type Data_Base_Object is new Object.Entity with record
      Ptr : Root_Connection_Ptr;
   end record;
   type Data_Base_Ptr is access Data_Base_Object'Class;
   --
   -- Finalize deletes Ptr.
   --
   procedure Finalize (Object : Data_Base_Object);
   --
   -- Handles, for internal use, they do not have any
   -- interesting methods.
   --
   package Connection_Handles is
      new Object.Handle (Data_Base_Object, Data_Base_Ptr);
   --
   -- Database_Type is a handle
   --
   type Database_Type is new Connection_Handles.Handle;
end APQ.Handles;

> It has the following methods:
> 
>   * Connect method takes a string, which is the connection URL.  Note:
>     Two ways of implementing:
> 
>     1. connect is hard-coded to support every possible database, and
>        parses the URL itself.
> 
>     2. each database is registered in a global list, connect
>        determines the most appropriate database based on prefix in URL
>        and calls appropriate connect method with URL.
> 
>     The second method is more complicated but more flexible. In any
>     case, changing this should not require changing the user API.
> 
>   * All methods associated with Root_Connection_Type. This does *not*
>     include options to set options specific to the database, like user
>     name or password. These call the appropriate routine in the
>     Root_Connection_Type'Class. Status information should perhaps be
>     cached, so it remains constant even after queries (might be more
>     appropriate way to handle errors).
> 
>   * New_Query takes a *Database_Type* parameter, not a
>     Root_Connection_Type parameter. This function constraints a query
>     and saves a smart pointer to the Root_Connection_Type contained
>     within the Database_Type variable.

You could leave it as is and add a handle to a query, which will be created
from a handle to data base. It is a standard pattern: user interface has
only handles:

Handle to connection  ---> Connection_Object --> Connection_Type

Handle to query  ---> Query_Object --------> Query_Type
                      Handle to connection

Query_Object has a handle to its connection as a component. This ensures
that the Connection_Object will never be finalized before it. The original
Conncetion_Type and Query_Type may be left intact. They will be allocated
by handle constructors and destroyed automatically.

>   * Debatable: Function that returns smart pointer to
>     Root_Connection_Type'Class.  This might be required to access
>     database specific functions. Ideally it shouldn't be required.
> 
> 4. Modify Root_Query_Type class:
> 
>    New_Query is the only function that takes a *Database_Type*
>    parameter.
> 
>    The functions that use to require Root_Connection_Type now use the
>    smart pointer that was saved instead.
> 
>    Why not make the procedures abstract instead of having them raise
>    an Is_Abstract? This way the checks can be done at compile time.
> 
>    Execute already returns exception if not connected.
>
>    Add methods for obtaining and clearing status information. This
>    should be cached so if you execute two separate queries (in two
>    separate variables) on the same database, you will get two status
>    messages saved.
>  
> I hope this helps explain what I said earlier... I believe this solves
> a number of concerns with the existing system in one go.
> 
> The major difference is that I have created a new Database_Type class,
> which allows the Connection_Type to be shared in a safe manner between
> the user Database_Type and the user Query_Type classes.
> 
> This would involve making incompatible changes to Root_Query_Type. It
> might be possible to avoid this, not sure if it would be worth the
> effort.

No, if you would make a handle for Root_Query_Type.

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



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-17  3:45     ` APQ Brian May
  2004-12-17  4:03       ` APQ Warren W. Gay VE3WWG
  2004-12-17  8:59       ` APQ Stephen Leake
@ 2004-12-17 14:12       ` Dmitry A. Kazakov
  2004-12-17 23:20         ` APQ Brian May
  2004-12-21 23:29         ` APQ Brian May
  2 siblings, 2 replies; 32+ messages in thread
From: Dmitry A. Kazakov @ 2004-12-17 14:12 UTC (permalink / raw)


On Fri, 17 Dec 2004 14:45:17 +1100, Brian May wrote:

>    type Root_Connection_Type is abstract new Ada.Finalization.Limited_Controlled with private;

If you are going to rework it, then derive it directly from an abstract
object used for reference counting. That would save one level of
indirection:

  type Root_Connection_Type is abstract new Object.Entity with private;

>    procedure Connect(C : in out Root_Connection_Type) is abstract;

This is 100% legal. Probably you have conflicting views.

>    procedure Connect(C : in out Root_Connection_Type; Same_As : Root_Connection_Type'Class) is abstract;

Are you going to clone connections between different DBs? The above looks
like an attempt to emulate multiple dispatch.!

It should be:

  procedure Connect
            (  C : in out Root_Connection_Type;
               Same_As : Root_Connection_Type   -- Same types required!
            )  is abstract;

However would be is pretty useless, when you have a class-wide object at
hand.

I suppose that the idea was to make a copy of a limited object. Then it
should better be:

  function Copy (C : Root_Connection_Type)
     return Root_Connection_Ptr is abstract;

This would allocate a copy and connect it to the same DB. Because reference
counting is intended you will need dynamic allocation anyway. The user will
of course do it all with handles:

   function Copy (C : Handle) return Handle is
      Clone_Ptr : Root_Connection_Type_Ptr := Copy (Ptr (C).all);
         -- This clones the object pointed by the handle, the reference
         -- count of the copy is initially 0
   begin
      return Ref (Clone_Ptr);
         -- Result is a handle, and the reference count is 1, now
   end Copy;

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



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-17 11:42             ` APQ Brian May
@ 2004-12-17 22:55               ` Brian May
  2004-12-18 15:52                 ` APQ Warren W. Gay VE3WWG
  0 siblings, 1 reply; 32+ messages in thread
From: Brian May @ 2004-12-17 22:55 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 891 bytes --]

>>>>> "Brian" == Brian May <bam@snoopy.apana.org.au> writes:

    Brian> Good point. I meant to change it in both places, but I think I ended
    Brian> up changing it in only one place...

You were right, I missed it up.

Here is a patch that turns all methods into abstract methods.

Unfortunately, I could not make Finalize abstract, the compiler
complained that abstract methods must be visible (Finalize is in the
private section). This restriction seems strange to me, but I am not
going to argue with the compiler and left the function generating an
exception at run-time.

I suspect Finalize doesn't need to be abstract, but didn't go
exploring enough to verify why it is abstract.

Also, I noticed that the pointers are "access all". I couldn't see any
requirement for "all", and my code still compiles, so I changed them
to "access". This eliminates a potential source of errors.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: patch for abstract methods --]
[-- Type: text/x-patch, Size: 13506 bytes --]

--- apq-2.1-old/apq.ads	2003-09-25 05:56:24.000000000 +1000
+++ apq-2.1/apq.ads	2004-12-18 09:50:31.000000000 +1100
@@ -90,7 +90,7 @@
 
    type Column_Index_Type is new Positive;
 
-   type Root_Connection_Type is new Ada.Finalization.Limited_Controlled with private;
+   type Root_Connection_Type is abstract new Ada.Finalization.Limited_Controlled with private;
 
    type Trace_Mode_Type is (
       Trace_None,                      -- No tracing
@@ -101,10 +101,10 @@
 
    type Fetch_Mode_Type is ( Sequential_Fetch, Random_Fetch );
 
-   type Root_Query_Type is new Ada.Finalization.Controlled with private;
+   type Root_Query_Type is abstract new Ada.Finalization.Controlled with private;
 
 
-   function Engine_Of(C : Root_Connection_Type) return Database_Type;
+   function Engine_Of(C : Root_Connection_Type) return Database_Type is Abstract;
    function New_Query(C : Root_Connection_Type) return Root_Query_Type'Class;
 
    procedure Set_Host_Name(C : in out Root_Connection_Type; Host_Name : String);
@@ -123,13 +123,13 @@
    function User(C : Root_Connection_Type) return String;
    function Password(C : Root_Connection_Type) return String;
 
-   procedure Connect(C : in out Root_Connection_Type);   -- IS ABSTRACT
-   procedure Connect(C : in out Root_Connection_Type; Same_As : Root_Connection_Type'Class); -- IS ABSTRACT
-   procedure Disconnect(C : in out Root_Connection_Type); -- IS ABSTRACT
-
-   function Is_Connected(C : Root_Connection_Type) return Boolean; -- IS ABSTRACT
-   procedure Reset(C : in out Root_Connection_Type); -- IS ABSTRACT
-   function Error_Message(C : Root_Connection_Type) return String; -- IS ABSTRACT
+   procedure Connect(C : in out Root_Connection_Type) is abstract;
+   procedure Connect(C : in out Root_Connection_Type; Same_As : Root_Connection_Type'Class) is abstract;
+   procedure Disconnect(C : in out Root_Connection_Type) is abstract;
+
+   function Is_Connected(C : Root_Connection_Type) return Boolean is abstract;
+   procedure Reset(C : in out Root_Connection_Type) is abstract;
+   function Error_Message(C : Root_Connection_Type) return String is abstract;
 
    function In_Abort_State(C : Root_Connection_Type) return Boolean;
 
@@ -137,7 +137,7 @@
    function Will_Rollback_On_Finalize(C : Root_Connection_Type) return Boolean;
 
 
-   function Engine_Of(Q : Root_Query_Type) return Database_Type;
+   function Engine_Of(Q : Root_Query_Type) return Database_Type is Abstract;
 
    procedure Clear(Q : in out Root_Query_Type);
    function Fetch_Mode(Q : Root_Query_Type) return Fetch_Mode_Type;
@@ -160,40 +160,40 @@
    procedure Append_Quoted(Q : in out Root_Query_Type; Connection : Root_Connection_Type'Class; SQL : String; After : String := "");
    procedure Append_Quoted(Q : in out Root_Query_Type; Connection : Root_Connection_Type'Class; SQL : Ada.Strings.Unbounded.Unbounded_String; After : String := "");
 
-   procedure Execute(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class);
-   procedure Execute_Checked(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class; Msg : String := "");
+   procedure Execute(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class) is abstract;
+   procedure Execute_Checked(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class; Msg : String := "") is abstract;
 
-   procedure Begin_Work(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class);
-   procedure Commit_Work(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class);
-   procedure Rollback_Work(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class);
+   procedure Begin_Work(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class) is abstract;
+   procedure Commit_Work(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class) is abstract;
+   procedure Rollback_Work(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class) is abstract;
 
    procedure Raise_Exceptions(Query : in out Root_Query_Type; Raise_On : Boolean := True);
    procedure Report_Errors(Query : in out Root_Query_Type; Report_On : Boolean := True);
    
-   procedure Rewind(Q : in out Root_Query_Type);
-   procedure Fetch(Q : in out Root_Query_Type);
-   procedure Fetch(Q : in out Root_Query_Type; TX : Tuple_Index_Type);
-
-   function End_of_Query(Q : Root_Query_Type) return Boolean;
-   function Tuple(Q : Root_Query_Type) return Tuple_Index_Type;
-   function Tuples(Q : Root_Query_Type) return Tuple_Count_Type;
+   procedure Rewind(Q : in out Root_Query_Type) is abstract;
+   procedure Fetch(Q : in out Root_Query_Type) is abstract;
+   procedure Fetch(Q : in out Root_Query_Type; TX : Tuple_Index_Type) is abstract;
+
+   function End_of_Query(Q : Root_Query_Type) return Boolean is abstract;
+   function Tuple(Q : Root_Query_Type) return Tuple_Index_Type is abstract;
+   function Tuples(Q : Root_Query_Type) return Tuple_Count_Type is abstract;
 
-   function Value(Query : Root_Query_Type; CX : Column_Index_Type) return String;     -- Abstract
+   function Value(Query : Root_Query_Type; CX : Column_Index_Type) return String is abstract;
 
    procedure Value(Query: Root_Query_Type; CX : Column_Index_Type; V : out String);
    function Value(Query : Root_Query_Type; CX : Column_Index_Type) return Ada.Strings.Unbounded.Unbounded_String;
    function Value(Query : Root_Query_Type; CX : Column_Index_Type) return Row_ID_Type;
    function Value(Query : Root_Query_Type; CX : Column_Index_Type) return APQ_Bitstring;
 
-   function Result(Query : Root_Query_Type) return Natural;    -- Returns Result_Type'Pos()
+   function Result(Query : Root_Query_Type) return Natural is abstract;    -- Returns Result_Type'Pos()
 
-   function Is_Null(Q : Root_Query_Type; CX : Column_Index_Type) return Boolean;
+   function Is_Null(Q : Root_Query_Type; CX : Column_Index_Type) return Boolean is abstract;
 
-   function Command_Oid(Query : Root_Query_Type) return Row_ID_Type;
-   function Null_Oid(Query : Root_Query_Type) return Row_ID_Type;
+   function Command_Oid(Query : Root_Query_Type) return Row_ID_Type is abstract;
+   function Null_Oid(Query : Root_Query_Type) return Row_ID_Type is abstract;
 
-   function Error_Message(Query : Root_Query_Type) return String;
-   function Is_Duplicate_Key(Query : Root_Query_Type) return Boolean;
+   function Error_Message(Query : Root_Query_Type) return String is abstract;
+   function Is_Duplicate_Key(Query : Root_Query_Type) return Boolean is abstract;
    function To_String(Query : Root_Query_Type) return String;
 
 
@@ -573,15 +573,15 @@
 
    package CStr renames Interfaces.C_Streams;
 
-   type String_Ptr is access all String;
+   type String_Ptr is access String;
    type String_Ptr_Array is array(Natural range <>) of String_Ptr;
-   type String_Ptr_Array_Access is access all String_Ptr_Array;
-   type Stream_Element_Array_Ptr is access all Ada.Streams.Stream_Element_Array;
+   type String_Ptr_Array_Access is access String_Ptr_Array;
+   type Stream_Element_Array_Ptr is access Ada.Streams.Stream_Element_Array;
 
    subtype Port_Integer is Integer range 0..32768;
    type Port_Format_Type is ( IP_Port, UNIX_Port );
 
-   type Root_Connection_Type is new Ada.Finalization.Limited_Controlled with
+   type Root_Connection_Type is abstract new Ada.Finalization.Limited_Controlled with
       record
          Host_Name :       String_Ptr;                      -- Host name string or..
          Host_Address :    String_Ptr;                      -- Host IP address
@@ -602,7 +602,7 @@
 
    procedure Clear_Abort_State(C : in out Root_Connection_Type);
 
-   type Root_Query_Type is new Ada.Finalization.Controlled with
+   type Root_Query_Type is abstract new Ada.Finalization.Controlled with
       record
          Count :           Natural := 0;              -- # of elements in the Collection
          Alloc :           Natural := 0;              -- # of allocated elements in the Collection
--- apq-2.1-old/apq.adb	2003-09-25 05:56:24.000000000 +1000
+++ apq-2.1/apq.adb	2004-12-18 09:10:51.000000000 +1100
@@ -198,38 +198,6 @@
 
    -- ABSTRACT PRIMITIVES
 
-   procedure Connect(C : in out Root_Connection_Type) is
-   begin
-      raise Is_Abstract;
-   end Connect;
-
-   procedure Connect(C : in out Root_Connection_Type; Same_As : Root_Connection_Type'Class) is
-   begin
-      raise Is_Abstract;
-   end Connect;
-   
-   procedure Disconnect(C : in out Root_Connection_Type) is
-   begin
-      raise Is_Abstract;
-   end Disconnect;
-
-   function Is_Connected(C : Root_Connection_Type) return Boolean is
-   begin
-      raise Is_Abstract;
-      return False;
-   end Is_Connected;
-   
-   procedure Reset(C : in out Root_Connection_Type) is
-   begin
-      raise Is_Abstract;
-   end Reset;
-   
-   function Error_Message(C : Root_Connection_Type) return String is
-   begin
-      raise Is_Abstract;
-      return "";
-   end Error_Message;
-
    procedure Clear(Q : in out Root_Query_Type) is
    begin
       for X in 1..Q.Count loop
@@ -368,45 +336,6 @@
       end;
    end To_String;
 
-   procedure Rewind(Q : in out Root_Query_Type) is
-   begin
-      raise Is_Abstract;
-   end Rewind;
-
-   procedure Fetch(Q : in out Root_Query_Type) is
-   begin
-      raise Is_Abstract;
-   end Fetch;
-
-   procedure Fetch(Q : in out Root_Query_Type; TX : Tuple_Index_Type) is
-   begin
-      raise Is_Abstract;
-   end Fetch;
-
-   function End_of_Query(Q : Root_Query_Type) return Boolean is
-   begin
-      raise Is_Abstract;
-      return False;
-   end End_of_Query;
-
-   function Tuple(Q : Root_Query_Type) return Tuple_Index_Type is
-   begin
-      raise Is_Abstract;
-      return Tuple_Index_Type'First;
-   end Tuple;
-
-   function Tuples(Q : Root_Query_Type) return Tuple_Count_Type is
-   begin
-      raise Is_Abstract;
-      return Tuple_Count_Type'First;
-   end Tuples;
-
-   function Value(Query : Root_Query_Type; CX : Column_Index_Type) return String is
-   begin
-      raise Is_Abstract;
-      return ":-)";
-   end Value;
-
    function Value(Query : Root_Query_Type; CX : Column_Index_Type) return Ada.Strings.Unbounded.Unbounded_String is
       use Ada.Strings.Unbounded;
    begin
@@ -443,73 +372,6 @@
       return C.Rollback_Finalize;
    end Will_Rollback_On_Finalize;
 
-   function Result(Query : Root_Query_Type) return Natural is
-   begin
-      raise Is_Abstract;         -- This primitive must be overridden by the implementation
-      return 0;                  -- This is just to satisfy the compiler (not executed)
-   end Result;
-
-   function Engine_Of(C : Root_Connection_Type) return Database_Type is
-   begin
-      raise Is_Abstract;            -- Must be overridden
-      return Database_Type'First;   -- To quiet the compiler
-   end Engine_Of;
-
-   function Engine_Of(Q : Root_Query_Type) return Database_Type is
-   begin
-      raise Is_Abstract;            -- Must be overridden
-      return Database_Type'First;   -- To quiet the compiler
-   end Engine_Of;
-
-   function Command_Oid(Query : Root_Query_Type) return Row_ID_Type is
-   begin
-      raise Is_Abstract;
-      return Row_ID_Type'First;
-   end Command_Oid;
-
-   function Null_Oid(Query : Root_Query_Type) return Row_ID_Type is
-   begin
-      raise Is_Abstract;
-      return Row_ID_Type'First;
-   end Null_Oid;
-
-   function Error_Message(Query : Root_Query_Type) return String is
-   begin
-      raise Is_Abstract;
-      return "";
-   end Error_Message;
-
-   function Is_Duplicate_Key(Query : Root_Query_Type) return Boolean is
-   begin
-      raise Is_Abstract;
-      return False;
-   end Is_Duplicate_Key;
-
-   procedure Execute(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class) is
-   begin
-      raise Is_Abstract;
-   end Execute;
-
-   procedure Execute_Checked(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class; Msg : String := "") is
-   begin
-      raise Is_Abstract;
-   end Execute_Checked;
-
-   procedure Begin_Work(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class) is
-   begin
-      raise Is_Abstract;
-   end Begin_Work;
-
-   procedure Commit_Work(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class) is
-   begin
-      raise Is_Abstract;
-   end Commit_Work;
-
-   procedure Rollback_Work(Query : in out Root_Query_Type; Connection : in out Root_Connection_Type'Class) is
-   begin
-      raise Is_Abstract;
-   end Rollback_Work;
-
    function Time_Component(TM : Ada.Calendar.Day_Duration; Unit : Time_Unit) return Natural is
    begin
       case Unit is
@@ -1178,12 +1040,6 @@
       end if;
    end Encode_Bitstring;
 
-   function Is_Null(Q : Root_Query_Type; CX : Column_Index_Type) return Boolean is
-   begin
-      raise Is_Abstract;      -- Must be overriden
-      return False;
-   end Is_Null;
-
    function Column_Is_Null(Q : Root_Query_Type'Class; CX : Column_Index_Type) return Ind_Type is
    begin
       return Ind_Type(Is_Null(Root_Query_Type'Class(Q),CX));
@@ -1373,7 +1229,6 @@
 
    procedure Date_Fetch(Query : Root_Query_Type'Class; CX : Column_Index_Type; V : out Val_Type; Indicator : out Ind_Type) is
       function Value is new Date_Value(Val_Type);
-      D : APQ_Date;
    begin
       Indicator := Ind_Type( Is_Null(Root_Query_Type'Class(Query),CX) );
       if not Indicator then

[-- Attachment #3: Type: text/plain, Size: 40 bytes --]

-- 
Brian May <bam@snoopy.apana.org.au>

^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-17 14:12       ` APQ Dmitry A. Kazakov
@ 2004-12-17 23:20         ` Brian May
  2004-12-18 16:13           ` APQ Dmitry A. Kazakov
  2004-12-21 23:29         ` APQ Brian May
  1 sibling, 1 reply; 32+ messages in thread
From: Brian May @ 2004-12-17 23:20 UTC (permalink / raw)


>>>>> "Dmitry" == Dmitry A Kazakov <mailbox@dmitry-kazakov.de> writes:

    Dmitry> Are you going to clone connections between different DBs?
    Dmitry> The above looks like an attempt to emulate multiple
    Dmitry> dispatch.!

    Dmitry> It should be:

    Dmitry> procedure Connect
    Dmitry> (  C : in out Root_Connection_Type;
    Dmitry> Same_As : Root_Connection_Type   -- Same types required!
    Dmitry> )  is abstract;

I will look in more detail at the rest of what you have written
latter. I think your ideas are good. However, I think the above is
illegal, as Ada doesn't "know" what parameter to use for dispatching
to the correct routine. The same thing, I believe applies to a
function that takes Root_Connection_Type as a parameter and returns a
Root_Connection_Type.
-- 
Brian May <bam@snoopy.apana.org.au>



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-17 22:55               ` APQ Brian May
@ 2004-12-18 15:52                 ` Warren W. Gay VE3WWG
  2004-12-18 18:23                   ` APQ Dmitry A. Kazakov
  2004-12-22 10:07                   ` APQ Martin Krischik
  0 siblings, 2 replies; 32+ messages in thread
From: Warren W. Gay VE3WWG @ 2004-12-18 15:52 UTC (permalink / raw)


Brian May wrote:
>>>>>>"Brian" == Brian May <bam@snoopy.apana.org.au> writes:
> 
> 
>     Brian> Good point. I meant to change it in both places, but I think I ended
>     Brian> up changing it in only one place...
> 
> You were right, I missed it up.
> 
> Here is a patch that turns all methods into abstract methods.

Ok, Brian, hang on to your patches. I am trying to get my
Source Forge account reactivated (something's happened to it),
and then get this project up there.

I am surprised that that was all there was to it. I must have
made the same mistake.

> Unfortunately, I could not make Finalize abstract, the compiler
> complained that abstract methods must be visible (Finalize is in the
> private section). This restriction seems strange to me, but I am not
> going to argue with the compiler and left the function generating an
> exception at run-time.
> 
> I suspect Finalize doesn't need to be abstract, but didn't go
> exploring enough to verify why it is abstract.

Normally, you would want to override Finalize, because you
will have allocated references within the derived object
to clean up etc. However, 90% is better than nothing ;-)

> Also, I noticed that the pointers are "access all". I couldn't see any
> requirement for "all", and my code still compiles, so I changed them
> to "access". This eliminates a potential source of errors.

I can't imagine it making a practical difference here, but
perhaps I lack imagination on this point.

Warren.



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-17 23:20         ` APQ Brian May
@ 2004-12-18 16:13           ` Dmitry A. Kazakov
  0 siblings, 0 replies; 32+ messages in thread
From: Dmitry A. Kazakov @ 2004-12-18 16:13 UTC (permalink / raw)


On Sat, 18 Dec 2004 10:20:25 +1100, Brian May wrote:

>>>>>> "Dmitry" == Dmitry A Kazakov <mailbox@dmitry-kazakov.de> writes:
> 
>     Dmitry> Are you going to clone connections between different DBs?
>     Dmitry> The above looks like an attempt to emulate multiple
>     Dmitry> dispatch.!
> 
>     Dmitry> It should be:
> 
>     Dmitry> procedure Connect
>     Dmitry> (  C : in out Root_Connection_Type;
>     Dmitry> Same_As : Root_Connection_Type   -- Same types required!
>     Dmitry> )  is abstract;
> 
> I will look in more detail at the rest of what you have written
> latter. I think your ideas are good. However, I think the above is
> illegal, as Ada doesn't "know" what parameter to use for dispatching
> to the correct routine.

It is legal. You will have a run-time exception if the tags of actual
parameters are different. In fact it is a limited form of multiple
dispatch.

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



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-18 15:52                 ` APQ Warren W. Gay VE3WWG
@ 2004-12-18 18:23                   ` Dmitry A. Kazakov
  2004-12-21 23:34                     ` APQ Brian May
  2004-12-22 10:07                   ` APQ Martin Krischik
  1 sibling, 1 reply; 32+ messages in thread
From: Dmitry A. Kazakov @ 2004-12-18 18:23 UTC (permalink / raw)


On Sat, 18 Dec 2004 10:52:52 -0500, Warren W. Gay VE3WWG wrote:

> Brian May wrote:

>> Also, I noticed that the pointers are "access all". I couldn't see any
>> requirement for "all", and my code still compiles, so I changed them
>> to "access". This eliminates a potential source of errors.
> 
> I can't imagine it making a practical difference here, but
> perhaps I lack imagination on this point.

Potentially plain access pointers could be more efficient.

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



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-17 14:12       ` APQ Dmitry A. Kazakov
  2004-12-17 23:20         ` APQ Brian May
@ 2004-12-21 23:29         ` Brian May
  2004-12-22  9:14           ` APQ Dmitry A. Kazakov
  2004-12-23 17:04           ` APQ (Connection Cloning) Warren W. Gay VE3WWG
  1 sibling, 2 replies; 32+ messages in thread
From: Brian May @ 2004-12-21 23:29 UTC (permalink / raw)


>>>>> "Dmitry" == Dmitry A Kazakov <mailbox@dmitry-kazakov.de> writes:

    >> procedure Connect(C : in out Root_Connection_Type; Same_As :
    >> Root_Connection_Type'Class) is abstract;

    Dmitry> Are you going to clone connections between different DBs?
    Dmitry> The above looks like an attempt to emulate multiple
    Dmitry> dispatch.!

I read a documentation somewhere that said the code below is not
legal, and the above had to be used instead... The documentation said
the code body could check the types were correct. However, on advice
from Dmitry, I tried a test case with the code below, and it seems to
work fine. Need to keep my eyes open for that reference. Wonder if it
was that dodgy guide on the web about Ada for C++ programmers...

    Dmitry> It should be:

    Dmitry> procedure Connect
    Dmitry> (  C : in out Root_Connection_Type;
    Dmitry> Same_As : Root_Connection_Type   -- Same types required!
    Dmitry> )  is abstract;

    Dmitry> However would be is pretty useless, when you have a
    Dmitry> class-wide object at hand.

    Dmitry> I suppose that the idea was to make a copy of a limited
    Dmitry> object. Then it should better be:

    Dmitry> function Copy (C : Root_Connection_Type)
    Dmitry> return Root_Connection_Ptr is abstract;

    Dmitry> This would allocate a copy and connect it to the same
    Dmitry> DB. Because reference counting is intended you will need
    Dmitry> dynamic allocation anyway. The user will of course do it
    Dmitry> all with handles:

I have a suspicion this would not work as Root_Connection_Type is a
limited type. Or am I yet again mistaken?

Can somebody please let me know what applications a cloning function
has? I frequently hear of such functions, but rarely (if ever) needed
to use one.
-- 
Brian May <bam@snoopy.apana.org.au>



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-18 18:23                   ` APQ Dmitry A. Kazakov
@ 2004-12-21 23:34                     ` Brian May
  2004-12-22  8:57                       ` APQ Dmitry A. Kazakov
  0 siblings, 1 reply; 32+ messages in thread
From: Brian May @ 2004-12-21 23:34 UTC (permalink / raw)


>>>>> "Dmitry" == Dmitry A Kazakov <mailbox@dmitry-kazakov.de> writes:

    Dmitry> Potentially plain access pointers could be more efficient.

There have been other benefits described on this newsgroup. For
instance, it prevents this type of error:

declare
        A : aliased XYZ_Type;
        Ptr : XYZ_Ptr_Type := A'Access;
begin
        ...
        Free(Ptr);
end;

Sure that is obvious in this case, but in a more complicated
situation...

The C++ solution is for programmers to impose rules on themselves,
e.g. this pointer will only point to memory allocated dynamically.

In Ada you can have the compiler enforce these rules, and it makes
sense to let the compiler do this.
-- 
Brian May <bam@snoopy.apana.org.au>



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-21 23:34                     ` APQ Brian May
@ 2004-12-22  8:57                       ` Dmitry A. Kazakov
  0 siblings, 0 replies; 32+ messages in thread
From: Dmitry A. Kazakov @ 2004-12-22  8:57 UTC (permalink / raw)


On Wed, 22 Dec 2004 10:34:12 +1100, Brian May wrote:

>>>>>> "Dmitry" == Dmitry A Kazakov <mailbox@dmitry-kazakov.de> writes:
> 
>     Dmitry> Potentially plain access pointers could be more efficient.
> 
> There have been other benefits described on this newsgroup. For
> instance, it prevents this type of error:
> 
> declare
>         A : aliased XYZ_Type;
>         Ptr : XYZ_Ptr_Type := A'Access;
> begin
>         ...
>         Free(Ptr);
> end;

Good point!

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



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-21 23:29         ` APQ Brian May
@ 2004-12-22  9:14           ` Dmitry A. Kazakov
  2005-01-04 21:32             ` APQ Brian May
  2004-12-23 17:04           ` APQ (Connection Cloning) Warren W. Gay VE3WWG
  1 sibling, 1 reply; 32+ messages in thread
From: Dmitry A. Kazakov @ 2004-12-22  9:14 UTC (permalink / raw)


On Wed, 22 Dec 2004 10:29:01 +1100, Brian May wrote:

>>>>>> "Dmitry" == Dmitry A Kazakov <mailbox@dmitry-kazakov.de> writes:

>     Dmitry> function Copy (C : Root_Connection_Type)
>     Dmitry> return Root_Connection_Ptr is abstract;
> 
>     Dmitry> This would allocate a copy and connect it to the same
>     Dmitry> DB. Because reference counting is intended you will need
>     Dmitry> dynamic allocation anyway. The user will of course do it
>     Dmitry> all with handles:
> 
> I have a suspicion this would not work as Root_Connection_Type is a
> limited type. Or am I yet again mistaken?

You probably mean this:

   function Copy (C : Root_Connection_Type'Class)
      return Root_Connection_Ptr is
   begin
      return new Root_Connection_Type'Class'(C);
   end Copy;

This indeed cannot work for limited types. This was the reason why Copy was
declared abstract primitive instead:

   function Copy (C : Root_Connection_Type)
      return Root_Connection_Ptr is abstract;

It will dispatch to an implementation which knows how to copy itself:

   function Copy (C : My_Connection_Type)
      return Root_Connection_Ptr is
      Result : Root_Connection_Ptr := new My_Connection_Type;
      Object : My_Connection_Type renames My_Connection_Type (Result.all);
   begin
      Object.Field_Foo := C.Field_Foo;
      ... -- Clone me tender
      return Result;
   exception
      when others =>
         Free (Result); -- No memory leaks!
         raise;
   end Copy;

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



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-18 15:52                 ` APQ Warren W. Gay VE3WWG
  2004-12-18 18:23                   ` APQ Dmitry A. Kazakov
@ 2004-12-22 10:07                   ` Martin Krischik
  2004-12-22 13:15                     ` APQ Dmitry A. Kazakov
  1 sibling, 1 reply; 32+ messages in thread
From: Martin Krischik @ 2004-12-22 10:07 UTC (permalink / raw)


Warren W. Gay VE3WWG wrote:

> I can't imagine it making a practical difference here, but
> perhaps I lack imagination on this point.

http://en.wikibooks.org/wiki/Programming:Ada:Types:access#access_vs._access_all

Martin
-- 
mailto://krischik@users.sourceforge.net
http://www.ada.krischik.com



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-22 10:07                   ` APQ Martin Krischik
@ 2004-12-22 13:15                     ` Dmitry A. Kazakov
  2004-12-22 16:53                       ` APQ Martin Krischik
  0 siblings, 1 reply; 32+ messages in thread
From: Dmitry A. Kazakov @ 2004-12-22 13:15 UTC (permalink / raw)


On Wed, 22 Dec 2004 11:07:44 +0100, Martin Krischik wrote:

> Warren W. Gay VE3WWG wrote:
> 
>> I can't imagine it making a practical difference here, but
>> perhaps I lack imagination on this point.
> 
> http://en.wikibooks.org/wiki/Programming:Ada:Types:access#access_vs._access_all

Pool-specific access types do not do well:

1. Upcast/downcast conversions do not work. You'll need
Unchecked_Conversion of pointers. It is nasty and dangerous.

2. '[Unchecked_]Access does not work (otherwise, (1) would be a minor
problem).

3. Rosen's trick does not work. Very bad. Move it to Initialize? That won't
work either, because of 2.

4. Construction/destruction is headache. Wished to insert a newly created
object into a list? Not from Initialize! To delete it from there upon
destruction? Nay!

5. Access discriminants cannot be pool-specific. Converting to general
access to specific one is again an Unchecked_Conversion of worst kind.

6. There is no way to restrict objects allocations to a definite set of
pools. "type X (<>) is ..." does not count.

In general, I think that the issue should be thoroughly reworked.

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



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-22 13:15                     ` APQ Dmitry A. Kazakov
@ 2004-12-22 16:53                       ` Martin Krischik
  2004-12-22 17:21                         ` APQ Dmitry A. Kazakov
  0 siblings, 1 reply; 32+ messages in thread
From: Martin Krischik @ 2004-12-22 16:53 UTC (permalink / raw)


Dmitry A. Kazakov wrote:

> On Wed, 22 Dec 2004 11:07:44 +0100, Martin Krischik wrote:
> 
>> Warren W. Gay VE3WWG wrote:
>> 
>>> I can't imagine it making a practical difference here, but
>>> perhaps I lack imagination on this point.
>> 
>>
http://en.wikibooks.org/wiki/Programming:Ada:Types:access#access_vs._access_all
> 
> Pool-specific access types do not do well:
> 
> 1. Upcast/downcast conversions do not work. You'll need
> Unchecked_Conversion of pointers. It is nasty and dangerous.
> 
> 2. '[Unchecked_]Access does not work (otherwise, (1) would be a minor
> problem).
> 
> 3. Rosen's trick does not work. Very bad. Move it to Initialize? That
> won't work either, because of 2.
> 
> 4. Construction/destruction is headache. Wished to insert a newly created
> object into a list? Not from Initialize! To delete it from there upon
> destruction? Nay!
> 
> 5. Access discriminants cannot be pool-specific. Converting to general
> access to specific one is again an Unchecked_Conversion of worst kind.
> 
> 6. There is no way to restrict objects allocations to a definite set of
> pools. "type X (<>) is ..." does not count.
> 
> In general, I think that the issue should be thoroughly reworked.

Well, ist wiki. Klick on [edit] and make your point. It OK by me - actually
it is he hole point of wiki: incremental impovement.

With Regards

Martin
-- 
mailto://krischik@users.sourceforge.net
http://www.ada.krischik.com



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-22 16:53                       ` APQ Martin Krischik
@ 2004-12-22 17:21                         ` Dmitry A. Kazakov
  2004-12-22 18:23                           ` APQ Martin Krischik
  0 siblings, 1 reply; 32+ messages in thread
From: Dmitry A. Kazakov @ 2004-12-22 17:21 UTC (permalink / raw)


On Wed, 22 Dec 2004 17:53:14 +0100, Martin Krischik wrote:

> Dmitry A. Kazakov wrote:
> 
>> On Wed, 22 Dec 2004 11:07:44 +0100, Martin Krischik wrote:
>> 
>>> Warren W. Gay VE3WWG wrote:
>>> 
>>>> I can't imagine it making a practical difference here, but
>>>> perhaps I lack imagination on this point.
>>> 
>>>
> http://en.wikibooks.org/wiki/Programming:Ada:Types:access#access_vs._access_all
>> 
>> Pool-specific access types do not do well:
>> 
>> 1. Upcast/downcast conversions do not work. You'll need
>> Unchecked_Conversion of pointers. It is nasty and dangerous.
>> 
>> 2. '[Unchecked_]Access does not work (otherwise, (1) would be a minor
>> problem).
>> 
>> 3. Rosen's trick does not work. Very bad. Move it to Initialize? That
>> won't work either, because of 2.
>> 
>> 4. Construction/destruction is headache. Wished to insert a newly created
>> object into a list? Not from Initialize! To delete it from there upon
>> destruction? Nay!
>> 
>> 5. Access discriminants cannot be pool-specific. Converting to general
>> access to specific one is again an Unchecked_Conversion of worst kind.
>> 
>> 6. There is no way to restrict objects allocations to a definite set of
>> pools. "type X (<>) is ..." does not count.
>> 
>> In general, I think that the issue should be thoroughly reworked.
> 
> Well, ist wiki. Klick on [edit] and make your point. It OK by me - actually
> it is he hole point of wiki: incremental impovement.

Of what? Is wiki =ARG or else [edit button] = AI? (:-))

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



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-22 17:21                         ` APQ Dmitry A. Kazakov
@ 2004-12-22 18:23                           ` Martin Krischik
  0 siblings, 0 replies; 32+ messages in thread
From: Martin Krischik @ 2004-12-22 18:23 UTC (permalink / raw)


Dmitry A. Kazakov wrote:

> On Wed, 22 Dec 2004 17:53:14 +0100, Martin Krischik wrote:
> 
>> Dmitry A. Kazakov wrote:
>> 
>>> On Wed, 22 Dec 2004 11:07:44 +0100, Martin Krischik wrote:
>>> 
>>>> Warren W. Gay VE3WWG wrote:
>>>> 
>>>>> I can't imagine it making a practical difference here, but
>>>>> perhaps I lack imagination on this point.
>>>> 
>>>>
>>
http://en.wikibooks.org/wiki/Programming:Ada:Types:access#access_vs._access_all
>>> 
>>> Pool-specific access types do not do well:
>>> 
>>> 1. Upcast/downcast conversions do not work. You'll need
>>> Unchecked_Conversion of pointers. It is nasty and dangerous.
>>> 
>>> 2. '[Unchecked_]Access does not work (otherwise, (1) would be a minor
>>> problem).
>>> 
>>> 3. Rosen's trick does not work. Very bad. Move it to Initialize? That
>>> won't work either, because of 2.
>>> 
>>> 4. Construction/destruction is headache. Wished to insert a newly
>>> created object into a list? Not from Initialize! To delete it from there
>>> upon destruction? Nay!
>>> 
>>> 5. Access discriminants cannot be pool-specific. Converting to general
>>> access to specific one is again an Unchecked_Conversion of worst kind.
>>> 
>>> 6. There is no way to restrict objects allocations to a definite set of
>>> pools. "type X (<>) is ..." does not count.
>>> 
>>> In general, I think that the issue should be thoroughly reworked.
>> 
>> Well, ist wiki. Klick on [edit] and make your point. It OK by me -
>> actually it is he hole point of wiki: incremental impovement.
> 
> Of what? Is wiki =ARG or else [edit button] = AI? (:-))

I thought you mean that the wiki tutorial "Programming:Ada" need some
reworking as it states the disadvantages of Pool-specific access not clear
enough.

As for ARG and the AI - well I guess you know the procedure - if not I can
tell you :-) .

With Regards Martin.

-- 
mailto://krischik@users.sourceforge.net
http://www.ada.krischik.com



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ (Connection Cloning)
  2004-12-21 23:29         ` APQ Brian May
  2004-12-22  9:14           ` APQ Dmitry A. Kazakov
@ 2004-12-23 17:04           ` Warren W. Gay VE3WWG
  2004-12-23 17:55             ` Georg Bauhaus
  1 sibling, 1 reply; 32+ messages in thread
From: Warren W. Gay VE3WWG @ 2004-12-23 17:04 UTC (permalink / raw)


Brian May wrote:
>>>>>>"Dmitry" == Dmitry A Kazakov <mailbox@dmitry-kazakov.de> writes:
...
> Can somebody please let me know what applications a cloning function
> has? I frequently hear of such functions, but rarely (if ever) needed
> to use one.

The "cloning" calls are for the most part, convenience calls. You can
accomplish the same thing without them, though it is IMHO very inconvenient
and perhaps error prone (because different databases require different
parameters). But if a programmer must do something often enough, then
I believe that the "package" should make it easier and less error
prone for the application writer.

One problem that APQ's API has, is that I rolled the "environment"
into the Connection_Type object (this was discussed earlier). The consequence
of that is that when you need a second database connection (more on that
later), without a clone call, you need to supply all of the same database
connection parameters to create a new connection (userid, password, port
etc.) This is even more painful when you are trying to implement
database portable code, because then you also must concern yourself
with which parameters that must be carried over.

For this reason, it makes sense for APQ to 'care' about this, because
it has intimate knowledge of what has been used for the connection.
So cloning a connection becomes easier for APQ to do, than it would
be for the application writer to do it, without APQ's help.
The programmer simply wants another connection "like that one".

Why a second database connection? The reasons vary, but the following
reasons come to mind right away:

  - If you are maintaining a pool of connections to the same database
    (webserver). Even if you start with a fixed set of connections,
    a server may want to add to the pool as demand increases.

  - Client library limitations: most operations can share the same
    connection, but there are probably some cases where this cannot
    be done (I believe for example, you can only have one active
    transaction going on one connection).

  - You may want to restrict trace (debug) SQL operations, when
    debugging a difficult problem. To reduce the amount of trace
    capture, a cloned connection without tracing may be useful.
    In this case, you would revert back to a single connection
    once the debugging was successfully completed.

This "need" would largely disappear if the database userid, password
etc. was taken out of the Connection_Type and put into a 3rd
object Environment_Type instead. I know Dimitry disagrees with the
yet another object approach, but I believe this is the right
thing to do (TM). In his favour however, I do like the internal
smart pointer idea, to guarantee that essential objects
(connection and environment) do not go out of scope prematurely.

Once the connection "parameters" were placed into their own
Environment_Type object, then multiple Connection_Type objects
can be supplied with a common Environment_Type object instead,
and no "cloning" primitives would be required.

Some of the earlier discussion around internal smart pointers
to these objects starts to make a stronger case as you add yet
another object to the mix. Internally, the Connection_Type object
should hold a smart pointer back to the Environment_Object, and
of course, Query_Type objects would hold a smart pointer back
to the Connection_Type object. Then as has been suggested, you
could drop the Connection_Type object argument in some of the
calls like Execute() et al. The following shows how the objects
are related:

  Environment <- Connection <- Query
      1       <-     N
                     1      <-   N

-- 
Warren W. Gay VE3WWG
http://home.cogeco.ca/~ve3wwg



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ (Connection Cloning)
  2004-12-23 17:04           ` APQ (Connection Cloning) Warren W. Gay VE3WWG
@ 2004-12-23 17:55             ` Georg Bauhaus
  2004-12-23 18:52               ` Warren W. Gay VE3WWG
  0 siblings, 1 reply; 32+ messages in thread
From: Georg Bauhaus @ 2004-12-23 17:55 UTC (permalink / raw)


Warren W. Gay VE3WWG <ve3wwg@nospam.cogeco.ca> wrote:
: Why a second database connection? The reasons vary, but the following
: reasons come to mind right away:

 Another one:
   - one database system is very fast but is more or less a simple SQL
     front end to a quick ISAM store or some such; another database
     system supports transactions, subselects, partial locks, etc..
     But this comes at a price, you cannot use the second database for
     storing larger amounts of data quickly. Solution: use two database
     systems for two needs.

 And another one:
   - say, my application is a component to be integrated with other
     components that use an existing database system. As is, mine comes
     with its own database handling, using a different database system.
     Can all components use the same DBMS?
     There can be various reasons why the existing database system
     may or may not fulfill the requirements of my component, and 
     similarly the other components may not be happy with the DB that
     may component uses by default.

Let alone the cost of integration, of adaption effort, and planning backup
anew.
 

-- Georg



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ (Connection Cloning)
  2004-12-23 17:55             ` Georg Bauhaus
@ 2004-12-23 18:52               ` Warren W. Gay VE3WWG
  2005-01-03  7:40                 ` Frank Piron
  0 siblings, 1 reply; 32+ messages in thread
From: Warren W. Gay VE3WWG @ 2004-12-23 18:52 UTC (permalink / raw)


Georg Bauhaus wrote:
> Warren W. Gay VE3WWG <ve3wwg@nospam.cogeco.ca> wrote:
> : Why a second database connection? The reasons vary, but the following
> : reasons come to mind right away:
> 
>  Another one:
>    - one database system is very fast but is more or less a simple SQL
>      front end to a quick ISAM store or some such; another database
>      system supports transactions, subselects, partial locks, etc..
>      But this comes at a price, you cannot use the second database for
>      storing larger amounts of data quickly. Solution: use two database
>      systems for two needs.
> 
>  And another one:
>    - say, my application is a component to be integrated with other
>      components that use an existing database system. As is, mine comes
>      with its own database handling, using a different database system.
>      Can all components use the same DBMS?
>      There can be various reasons why the existing database system
>      may or may not fulfill the requirements of my component, and 
>      similarly the other components may not be happy with the DB that
>      may component uses by default.
> 
> Let alone the cost of integration, of adaption effort, and planning backup
> anew.
>  
> 
> -- Georg

I think you confused the OP's question. His was along the lines of
"why would you need more than one connection to the very same database
in one application?"

Same database product and same database/schema.  APQ certainly does
not stop anyone from messing with different products or instances
at the same time. In fact I did a lot of this successfully when
I was testing Sybase, with PostgreSQL and MySQL as comparisons on
similar tables.

-- 
Warren W. Gay VE3WWG
http://home.cogeco.ca/~ve3wwg



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ (Connection Cloning)
  2004-12-23 18:52               ` Warren W. Gay VE3WWG
@ 2005-01-03  7:40                 ` Frank Piron
  0 siblings, 0 replies; 32+ messages in thread
From: Frank Piron @ 2005-01-03  7:40 UTC (permalink / raw)


Am Thu, 23 Dec 2004 13:52:24 -0500 schrieb Warren W. Gay VE3WWG 
<ve3wwg@NoSPAM.cogeco.ca>:

> I think you confused the OP's question. His was along the lines of
> "why would you need more than one connection to the very same database
> in one application?"

In the Oracle Call Interface for example you may call a statement
asynchronously. Then you can query a cursor attribute to check
if the statement was processed by the server. But you may not issue
any other call in the connection in which the asynchronously executed
statement is pending. So normally for every asynchronously executed
statement you will reserve a dedicated connection.

-- 
Frank Piron,
defrankatkonaddot
(leftrotate two)



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2004-12-22  9:14           ` APQ Dmitry A. Kazakov
@ 2005-01-04 21:32             ` Brian May
  2005-01-05 11:58               ` APQ Dmitry A. Kazakov
  0 siblings, 1 reply; 32+ messages in thread
From: Brian May @ 2005-01-04 21:32 UTC (permalink / raw)


>>>>> "Dmitry" == Dmitry A Kazakov <mailbox@dmitry-kazakov.de> writes:

    Dmitry> You probably mean this:

    Dmitry> function Copy (C : Root_Connection_Type'Class)
    Dmitry> return Root_Connection_Ptr is
    Dmitry> begin
    Dmitry> return new Root_Connection_Type'Class'(C);
    Dmitry> end Copy;

    Dmitry> This indeed cannot work for limited types. This was the
    Dmitry> reason why Copy was declared abstract primitive instead:

    Dmitry> function Copy (C : Root_Connection_Type)
    Dmitry> return Root_Connection_Ptr is abstract;

    Dmitry> It will dispatch to an implementation which knows how to
    Dmitry> copy itself:

I am under the impression (perhaps wrong impression, I haven't tested
it) that

A := Copy(C);

will not work if C is a limited type, as there is an implied copy
operation from the RHS to the LHS.

Also the thread "Return_By_Reference or Return_By_Copy (GNAT bug?)" might
be relevant here.
-- 
Brian May <bam@snoopy.apana.org.au>



^ permalink raw reply	[flat|nested] 32+ messages in thread

* Re: APQ
  2005-01-04 21:32             ` APQ Brian May
@ 2005-01-05 11:58               ` Dmitry A. Kazakov
  0 siblings, 0 replies; 32+ messages in thread
From: Dmitry A. Kazakov @ 2005-01-05 11:58 UTC (permalink / raw)


On Wed, 05 Jan 2005 08:32:53 +1100, Brian May wrote:

>>>>>> "Dmitry" == Dmitry A Kazakov <mailbox@dmitry-kazakov.de> writes:
> 
>     Dmitry> You probably mean this:
> 
>     Dmitry> function Copy (C : Root_Connection_Type'Class)
>     Dmitry> return Root_Connection_Ptr is
>     Dmitry> begin
>     Dmitry> return new Root_Connection_Type'Class'(C);
>     Dmitry> end Copy;
> 
>     Dmitry> This indeed cannot work for limited types. This was the
>     Dmitry> reason why Copy was declared abstract primitive instead:
> 
>     Dmitry> function Copy (C : Root_Connection_Type)
>     Dmitry> return Root_Connection_Ptr is abstract;
> 
>     Dmitry> It will dispatch to an implementation which knows how to
>     Dmitry> copy itself:
> 
> I am under the impression (perhaps wrong impression, I haven't tested
> it) that
> 
> A := Copy(C);
> 
> will not work if C is a limited type, as there is an implied copy
> operation from the RHS to the LHS.

The following is an fully operational implementation of what I meant based
on Simple Components (http://www.dmitry-kazakov.de/ada/components.htm):

  -- The test program first:

with Connections;  use Connections;
with Connections.My_Connections;

procedure Test_Connections is
   A : Connection; -- Illegal, will not compile
   B : Connection := Connections.My_Connections.Create (10);
   C : Connection := Copy (B); -- Make a copy
   D : Connection := B; -- Reference
begin
   null;
end Test_Connections;

Here B and D are handles to the same internal connection object. They share
it. C is a handle to a copy of the object pointed by B,D. The connection
objects are automatically destroyed when the last handle disappear. User
sees only the type Connection.

   -- Abstract connection interface. A connection is a handle to
   -- the connection object. Handles are not limited, objects are.

with Object;
with Object.Handle;

package Connections is
   type Connection (<>) is private;
   function Copy (C : Connection) return Connection;
   
private
   type Root_Connection_Object is
      abstract new Object.Entity with null record;
   type Root_Connection_Ptr is access Root_Connection_Object'Class;
   function Copy (C : Root_Connection_Object)
      return Root_Connection_Ptr is abstract;

   package Connection_Handles is
      new Object.Handle (Root_Connection_Object, Root_Connection_Ptr);
   type Connection is new Connection_Handles.Handle with null record;
   function Ref (C : Root_Connection_Ptr) return Connection;
end Connections;

package body Connections is
   function Copy (C : Connection) return Connection is
   begin
      return Ref (Copy (Ptr (C).all));
   end Copy;

   function Ref (C : Root_Connection_Ptr) return Connection is
   begin
      return (Connection_Handles.Ref (C) with null record);
   end Ref;
end Connections;

  -- An implementation: My_Connection

package Connections.My_Connections is
   function Create (Parameter : Integer) return Connection;

private
   type My_Connection_Object is new Root_Connection_Object with record
      I : Integer;
   end record;
   function Copy (C : My_Connection_Object) return Root_Connection_Ptr;

end Connections.My_Connections;

package body Connections.My_Connections is
   function Create (Parameter : Integer) return Connection is
      This   : Root_Connection_Ptr := new My_Connection_Object;
      Object : My_Connection_Object
                  renames My_Connection_Object (This.all);
   begin
      Object.I := Parameter;
      return Ref (This);
   end Create;

   function Copy (C : My_Connection_Object) return Root_Connection_Ptr is
      This   : Root_Connection_Ptr := new My_Connection_Object;
      Object : My_Connection_Object
                  renames My_Connection_Object (This.all);
   begin
      Object.I := C.I;
      return This;
   end Copy;

end Connections.My_Connections;

> Also the thread "Return_By_Reference or Return_By_Copy (GNAT bug?)" might
> be relevant here.

Only in Ada 2005 there will be a way to have limited object constructors.
Which will be BTW still too little for a proper construction model. There
still will be no constructors with parameters. No copy constructors. No
class-wide constructors.

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



^ permalink raw reply	[flat|nested] 32+ messages in thread

end of thread, other threads:[~2005-01-05 11:58 UTC | newest]

Thread overview: 32+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-12-15 23:31 APQ Brian May
2004-12-16 11:34 ` APQ Warren W. Gay VE3WWG
2004-12-16 23:58   ` APQ Randy Brukardt
2004-12-17  3:45     ` APQ Brian May
2004-12-17  4:03       ` APQ Warren W. Gay VE3WWG
2004-12-17  4:38         ` APQ Brian May
2004-12-17  9:06           ` APQ Egil H. H�vik
2004-12-17 11:42             ` APQ Brian May
2004-12-17 22:55               ` APQ Brian May
2004-12-18 15:52                 ` APQ Warren W. Gay VE3WWG
2004-12-18 18:23                   ` APQ Dmitry A. Kazakov
2004-12-21 23:34                     ` APQ Brian May
2004-12-22  8:57                       ` APQ Dmitry A. Kazakov
2004-12-22 10:07                   ` APQ Martin Krischik
2004-12-22 13:15                     ` APQ Dmitry A. Kazakov
2004-12-22 16:53                       ` APQ Martin Krischik
2004-12-22 17:21                         ` APQ Dmitry A. Kazakov
2004-12-22 18:23                           ` APQ Martin Krischik
2004-12-17  8:59       ` APQ Stephen Leake
2004-12-17 14:12       ` APQ Dmitry A. Kazakov
2004-12-17 23:20         ` APQ Brian May
2004-12-18 16:13           ` APQ Dmitry A. Kazakov
2004-12-21 23:29         ` APQ Brian May
2004-12-22  9:14           ` APQ Dmitry A. Kazakov
2005-01-04 21:32             ` APQ Brian May
2005-01-05 11:58               ` APQ Dmitry A. Kazakov
2004-12-23 17:04           ` APQ (Connection Cloning) Warren W. Gay VE3WWG
2004-12-23 17:55             ` Georg Bauhaus
2004-12-23 18:52               ` Warren W. Gay VE3WWG
2005-01-03  7:40                 ` Frank Piron
2004-12-17 13:54 ` APQ Dmitry A. Kazakov
  -- strict thread matches above, loose matches on Subject: below --
2004-12-16  4:37 APQ Christoph Karl Walter Grein

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