Thread: Re: [HACKERS] psql commandline conninfo

Re: [HACKERS] psql commandline conninfo

From
Andrew Dunstan
Date:
Tom Lane wrote:
> Martijn van Oosterhout <kleptog@svana.org> writes:
>
>> Does that mean that:
>> psql -d "service=myservice"
>> should Just Work(tm)? That would be nice.
>>
>
> Even more to the point,
>
>     psql "service=myservice"
>
> which is why we want to overload dbname rather than any of the other
> PQsetdbLogin parameters for this --- dbname has pride of place in the
> command line syntax for several of the client programs.
>
>             regards, tom lane
>
>

Right. Here's the patch I just knocked up, which seems to Just Work (tm) ;-)

cheers

andrew


Index: src/interfaces/libpq/fe-connect.c
===================================================================
RCS file: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v
retrieving revision 1.339
diff -c -r1.339 fe-connect.c
*** src/interfaces/libpq/fe-connect.c    21 Nov 2006 16:28:00 -0000    1.339
--- src/interfaces/libpq/fe-connect.c    12 Dec 2006 22:49:28 -0000
***************
*** 567,572 ****
--- 567,573 ----
               const char *pwd)
  {
      PGconn       *conn;
+     bool       have_conninfo = false;

      /*
       * Allocate memory for the conn structure
***************
*** 575,585 ****
      if (conn == NULL)
          return NULL;

      /*
       * Parse an empty conninfo string in order to set up the same defaults
!      * that PQconnectdb() would use.
       */
!     if (!connectOptions1(conn, ""))
          return conn;

      /*
--- 576,609 ----
      if (conn == NULL)
          return NULL;

+     /*
+      * Have we got something that might be a conninfo string?
+      * If so, try that first.
+      */
+     if (dbName && strchr(dbName,'='))
+     {
+         if(connectOptions1(conn,dbName))
+         {
+             /* it was a conninfo string */
+             have_conninfo = true;
+         }
+         else
+         {
+             /* put things back the way they were so we can try again */
+             freePGconn(conn);
+             conn = makeEmptyPGconn();
+             if (conn == NULL)
+                 return NULL;
+
+         }
+     }
+
      /*
       * Parse an empty conninfo string in order to set up the same defaults
!      * that PQconnectdb() would use. Skip this if we already found a
!      * conninfo string.
       */
!     if (!have_conninfo && !connectOptions1(conn, ""))
          return conn;

      /*
***************
*** 613,619 ****
          conn->pgtty = strdup(pgtty);
      }

!     if (dbName && dbName[0] != '\0')
      {
          if (conn->dbName)
              free(conn->dbName);
--- 637,643 ----
          conn->pgtty = strdup(pgtty);
      }

!     if (!have_conninfo && dbName && dbName[0] != '\0')
      {
          if (conn->dbName)
              free(conn->dbName);

Re: [HACKERS] psql commandline conninfo

From
Tom Lane
Date:
Andrew Dunstan <andrew@dunslane.net> writes:
> Right. Here's the patch I just knocked up, which seems to Just Work (tm) ;-)

The main objection I can see to this is that you'd get a fairly
unhelpful message if you intended a conninfo string and there was
anything wrong with your syntax (eg, misspelled keyword).  Maybe we
should go with the conn: bit, although really that doesn't seem any
less likely to collide with actual dbnames than the "does it contain
"="" idea.  Anyone have other ideas how to disambiguate?

            regards, tom lane

Re: [HACKERS] psql commandline conninfo

From
Casey Duncan
Date:
On Dec 12, 2006, at 3:37 PM, Tom Lane wrote:

> Andrew Dunstan <andrew@dunslane.net> writes:
>> Right. Here's the patch I just knocked up, which seems to Just
>> Work (tm) ;-)
>
> The main objection I can see to this is that you'd get a fairly
> unhelpful message if you intended a conninfo string and there was
> anything wrong with your syntax (eg, misspelled keyword).  Maybe we
> should go with the conn: bit, although really that doesn't seem any
> less likely to collide with actual dbnames than the "does it contain
> "="" idea.  Anyone have other ideas how to disambiguate?

I would personally prefer a real option over a prefix, i.e. --
dbconn="service=foo" though the inline conninfo string in place of
the dbname would be ideal.

Perhaps like Tom suggests, if the value matches a conninfo regex
(slightly more rigid than just containing an equals character) then
we assume it is a conninfo string, but never try it as a dbname. If
someone has a database named like a conninfo string (c'mon folks ;^)
then they would need to pass it as explicitly an argument to '-d' or
'--dbname', not as a bare argument.

This is not completely b/w compatible of course, but IMO the added
convenience outweighs the incompatibility.

-Casey

Re: [HACKERS] psql commandline conninfo

From
"Andrew Dunstan"
Date:
Andrew Dunstan wrote:
> Tom Lane wrote:
>> "Andrew Dunstan" <andrew@dunslane.net> writes:
>>
>>> We change libpq from time to time. Besides, how many DBs are there that
>>> match the name pattern /^conn:.*=/ ? My guess is mighty few. So I don't
>>> expect lots of surprise.
>>>
>>
>> Um, but how many DB names have an "=" in them at all?
>>
>> Basically what this proposal is about is migrating from separated
>> dbname/user/host/port/etc parameters to a unified conninfo parameter.
>> That seems to me like a good long-term objective, and so I'm willing
>> to break a few eggs on the way to the omelet, as long as we're not
>> breaking any very likely usages.
>>
>> So: who here has a database with "=" in the name?  And hands up if
>> you've got a database whose name begins with "conn:"?
>>
>> I'm betting zero response rate on both of those, so see no reason to
>> contort the long-term definition for a very marginal difference in
>> the extent of backwards compatibility ...
>>
>>
>>
>
> I'm not sure -hackers is the most representative group to poll regarding
> dbnames in use ...
>
> Anyway, if I understand your current position, the only change needed to
> my current patch would be that if we fail to parse a dbname parameter
> that contains an = we simply fail at that point, rather than retrying it
> as a straight database name.
>
> I'm OK with that.
>


Here's the patch for what I think is the consensus position. If there's no
objection I will apply this and document it.

cheers

andrew

Attachment

Re: [HACKERS] psql commandline conninfo

From
Tom Lane
Date:
"Andrew Dunstan" <andrew@dunslane.net> writes:
> Here's the patch for what I think is the consensus position. If there's no
> objection I will apply this and document it.

Please do something for the comment for the connectOptions1 call.
As you've coded it, that is doing two completely different things
and the comment is almost completely unhelpful at explaining this
complexity.  Oh, and casting away const gets no points for style.

I think you could do worse than to split it into two independent code
paths:

    /*
     * If the dbName parameter contains '=', assume it's a conninfo
     * string.
     */
    if (dbName && strchr(dbName,'='))
    {
        if (!connectOptions1(conn, dbName))
            return conn;
    }
    else
    {
        /*
         * Old-style path: first, parse an empty conninfo string in
         * order to set up the same defaults that PQconnectdb() would use.
         */
        if (!connectOptions1(conn, ""))
            return conn;

        /* Insert dbName parameter value into struct */
        if (dbName && dbName[0] != '\0')
        {
            if (conn->dbName)
                free(conn->dbName);
            conn->dbName = strdup(dbName);
        }
    }

    /*
     * Insert remaining parameters into struct, overriding defaults
     * (as well as any conflicting data from dbName taken as a conninfo).
     */

(This works because there's no reason the dbName parameter can't be
moved up to process before the rest.)

            regards, tom lane

Re: [HACKERS] psql commandline conninfo

From
"Andrew Dunstan"
Date:
Tom Lane wrote:
> "Andrew Dunstan" <andrew@dunslane.net> writes:
>> Here's the patch for what I think is the consensus position. If there's
>> no
>> objection I will apply this and document it.
>
> Please do something for the comment for the connectOptions1 call.
> As you've coded it, that is doing two completely different things
> and the comment is almost completely unhelpful at explaining this
> complexity.  Oh, and casting away const gets no points for style.

ouch. :-)

Ok, I accept the reproof. In fact I got up this morning, had my coffee,
and thought "That's a silly way to do it, I could make it much neater by
moving the dbName processing up," and lo and behold when I read your email
you had done it :-) It shall be done as you wish.

BTW, what is the approved way to handle warnings about const? Copy the
object?

cheers

andrew


Re: [HACKERS] psql commandline conninfo

From
Tom Lane
Date:
"Andrew Dunstan" <andrew@dunslane.net> writes:
> BTW, what is the approved way to handle warnings about const? Copy the
> object?

Well, in the revised code there shouldn't be any warning at all, but
I think the mistake in your original was to declare the local variable
as "char *" instead of "const char *".

If "const" is being used as intended then a const-violation warning
would indeed suggest that you needed to make a writable copy.
Sometimes the problem is that you're working in a chunk of inadequately
const-ified code, ie, you're passing a const argument to some other
functions that do indeed treat their inputs as read-only but don't
declare them const.  In such cases you can either run around and try to
inject const everywhere it should be, or hold your nose and use a cast,
or give up on marking your own argument const :-(.  But you weren't
presented with that problem here, because connectOptions1() is already
const-ified.

            regards, tom lane

Re: [HACKERS] psql commandline conninfo

From
Bruce Momjian
Date:
I assume this patch will still allow a database name with an equals
sign, right?


    psql "dbname='a=b'"


The libpq documentation isn't clear that single-quotes also escape
equals, but I assume that is true looking at the code:

    http://www.postgresql.org/docs/8.2/static/libpq-connect.html

    The passed string can be empty to use all default parameters, or it can
    contain one or more parameter settings separated by whitespace. Each
    parameter setting is in the form keyword = value. Spaces around the
    equal sign are optional. To write an empty value or a value containing
    spaces, surround it with single quotes, e.g., keyword = 'a value'.
    Single quotes and backslashes within the value must be escaped with a
    backslash, i.e., \' and \\.


---------------------------------------------------------------------------

Andrew Dunstan wrote:
> Andrew Dunstan wrote:
> > Tom Lane wrote:
> >> "Andrew Dunstan" <andrew@dunslane.net> writes:
> >>
> >>> We change libpq from time to time. Besides, how many DBs are there that
> >>> match the name pattern /^conn:.*=/ ? My guess is mighty few. So I don't
> >>> expect lots of surprise.
> >>>
> >>
> >> Um, but how many DB names have an "=" in them at all?
> >>
> >> Basically what this proposal is about is migrating from separated
> >> dbname/user/host/port/etc parameters to a unified conninfo parameter.
> >> That seems to me like a good long-term objective, and so I'm willing
> >> to break a few eggs on the way to the omelet, as long as we're not
> >> breaking any very likely usages.
> >>
> >> So: who here has a database with "=" in the name?  And hands up if
> >> you've got a database whose name begins with "conn:"?
> >>
> >> I'm betting zero response rate on both of those, so see no reason to
> >> contort the long-term definition for a very marginal difference in
> >> the extent of backwards compatibility ...
> >>
> >>
> >>
> >
> > I'm not sure -hackers is the most representative group to poll regarding
> > dbnames in use ...
> >
> > Anyway, if I understand your current position, the only change needed to
> > my current patch would be that if we fail to parse a dbname parameter
> > that contains an = we simply fail at that point, rather than retrying it
> > as a straight database name.
> >
> > I'm OK with that.
> >
>
>
> Here's the patch for what I think is the consensus position. If there's no
> objection I will apply this and document it.
>
> cheers
>
> andrew

[ Attachment, skipping... ]

>
> ---------------------------(end of broadcast)---------------------------
> TIP 9: In versions below 8.0, the planner will ignore your desire to
>        choose an index scan if your joining column's datatypes do not
>        match

--
  Bruce Momjian   bruce@momjian.us
  EnterpriseDB    http://www.enterprisedb.com

  + If your life is a hard drive, Christ can be your backup. +