>
>
>>
> I think composite types should be treated in exactly the same manner as
> tuples in regular queries.  Whenever we look up information to parse the
> outside-most tuples of query results, do inner tuples/types then too.


Sure.  There is of course a question of responsibility here.  For OO stuff,
I don't mind saying "it's the object's responsibility to serialize" but we
can't put that in DBD::Pg.  That is, however, the assumption in PGObject.

Because it will make the lazy attribute problems clearer, I will describe
the PGObject framework here.

PGObject.pm is essentially glue which ties in objects to the db via common
defined interfaces (essentially duck typing).  Then the actual object
implementations (currently limited to PGObject::Simple for blessed hashrefs
and PGObject::Simple::Role for /Moo(se)?$/) then provide mapping services
between stored procedures and application methods.  Because of the common
interfaces, object-responsible serialization means one can have a custom
datetime handler which serializes and deserializes appropriately (for
simple types).


>   If it isn't possible to do that at prepare() time, then do it at
> execute() time.  Do not repeat for each row fetched from the result of an
> execute(), assuming data is homogeneous.  This is the simplest way to know
> that the type definitions we're working with are still valid for the
> results.
>

So basically if we see a hashref, we need to know what type it is.  This is
going to be outside SQL.  We can do this with stored procs because we can
look up expected input types.  I don't see how you can do something on an
insert or update statement though without the application specifying type.
 I don't see how this could be done outside a bind_param call.  Nested
tuples at that point cease to be a major problem.

>
> We do not want to add any non-core dependencies.  All that should be
> required to use DBD::Pg is Perl itself, DBI, and DBD::Pg.


Memoize is core and has been since at least 5.8.9 according to what I have
been able to find. This being said, memoization is dangerous when it comes
to db stuff so it should definitely be optional if used at all.

Of course, with a public API, there's no reason one can't memoize a wrapper
function.


>   Any extra dependencies should be optional and user-defined, eg the user
> of DBD::Pg registers some sort of handler against DBI or DBD::Pg to eg
> override behavior to memoize for speed, but DBD::Pg has no knowledge of
> this other than to make the relevant parts possible to override using said
> generic API.


Right.

>
>
>>
>
>  I won't promise
>> proper Moose handling of things like lazy attributes in this version, but
>> it
>> should be able to handle hashrefs.
>>
>> Does that sound like a reasonable plan?
>>
>
> I don't know what lazy attributes have to do with this, unless you're
> talking about only deserializing a composite-typed value if it is actually
> accessed.


No  The problem is you have a moose object with a lazy attribute.  When you
want to serialize it, that attribute may not have been initialized yet.
 There are a number of solutions to this problem:

1.  Make it the object's responsibility to initialize lazy attributes
before calling db methods.  That is what we did in LedgerSMB 1.4, but we
found it error prone.

2.  Go through accessors if available.  This is what I recently did in
PGObject::Simple::Role and that makes things work for other object systems
which don't map to simple hashrefs.

I think the obvious way to do this would be to have DBD::Pg *only* work on
hashrefs, but make the catalog lookups into a public API.  This would allow
other implementations to handle serialization and just hand in a string.

This would keep DBD::Pg's responsibility here to a minimum.


> Either way, DBI/DBD::Pg itself should know nothing about Moose or any
> other non-core object systems and just represent things with what tools the
> core provides; your framework can do that as you see fit though.
>

I am actually thinking that a well-designed public API handling only
hashrefs would be the answer here.  This way you could ask for a type
definition, and generate a hashref with appropriate information.  This
could then be passed in again using a public API so no catalog needs to be
hit.

>
> I don't know if it does this (please tell me), but you know what would be
> an extremely useful feature in Postgres itself?  It is there being a simple
> fast way to query the database if it had any schema changes (anything DDL
> does) since it was last asked the question.  This could take the form of a
> LISTEN/NOTIFY of some system-defined channel.


http://www.postgresql.org/docs/9.3/static/sql-createeventtrigger.html is
the way to do it.  That's outside the scope of DBD::Pg, though with a
public API, an application could listen and ask to requery.


>   If we assume in practice that schema changes are infrequent, then we can
> safely memoize any schema knowledge we have and know it is still valid
> until we get such a message saying there was a change, and then we flush
> the cache and check what we need to know again.
>

Right.  What I do with PGObject.pm's stored proc lookups is make
memoization optional (because I don't know how an app developer wants to
handle db schema upgrades), but where it is memoized, we flush the cache
when we get an error about bad arguments and we provide a public API to
flush the cache. This allows developers to decide how to handle these
changes with a bit of a failsafe if they forget.

I think memoization should be optional.  There are a lot of traps with it
that are way outside DBD::Pg's scope both on the db side and on the app
development side (oops, we used shift on the return value).

>
> -- Darren Duncan
>
>


-- 
Best Wishes,
Chris Travers

Efficito:  Hosted Accounting and ERP.  Robust and Flexible.  No vendor
lock-in.
http://www.efficito.com/learn_more

Reply via email to