What you proposed here sounds reasonable to me. -- Darren Duncan
On 2014-08-24, 7:15 PM, Chris Travers wrote:
>     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