Refactor to eliminate duplicate copies of conninfo default-finding code.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 22 Mar 2012 16:08:34 +0000 (12:08 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 22 Mar 2012 16:08:34 +0000 (12:08 -0400)
Alex Shulgin, lightly edited by me

src/interfaces/libpq/fe-connect.c

index 817d83b9cb4382565e663b92ea86e1dd4adb0c4d..6a20a1485d17b6fdea79cb922ff26c78335388a9 100644 (file)
@@ -121,9 +121,9 @@ static int ldapServiceLookup(const char *purl, PQconninfoOption *options,
  * fallback is available. If after all no value can be determined
  * for an option, an error is returned.
  *
- * The value for the username is treated specially in conninfo_parse.
- * If the Compiled-in resource is specified as a NULL value, the
- * user is determined by pg_fe_getauthname().
+ * The value for the username is treated specially in conninfo_add_defaults.
+ * If the value is not obtained any other way, the username is determined
+ * by pg_fe_getauthname().
  *
  * The Label and Disp-Char entries are provided for applications that
  * want to use PQconndefaults() to create a generic database connection
@@ -292,11 +292,14 @@ static PGconn *makeEmptyPGconn(void);
 static void fillPGconn(PGconn *conn, PQconninfoOption *connOptions);
 static void freePGconn(PGconn *conn);
 static void closePGconn(PGconn *conn);
+static PQconninfoOption *conninfo_init(PQExpBuffer errorMessage);
 static PQconninfoOption *conninfo_parse(const char *conninfo,
               PQExpBuffer errorMessage, bool use_defaults);
 static PQconninfoOption *conninfo_array_parse(const char *const * keywords,
                     const char *const * values, PQExpBuffer errorMessage,
                     bool use_defaults, int expand_dbname);
+static bool conninfo_add_defaults(PQconninfoOption *options,
+                     PQExpBuffer errorMessage);
 static char *conninfo_getval(PQconninfoOption *connOptions,
                const char *keyword);
 static void defaultNoticeReceiver(void *arg, const PGresult *res);
@@ -813,10 +816,9 @@ connectOptions2(PGconn *conn)
 /*
  *     PQconndefaults
  *
- * Parse an empty string like PQconnectdb() would do and return the
- * resulting connection options array, ie, all the default values that are
- * available from the environment etc. On error (eg out of memory),
- * NULL is returned.
+ * Construct a default connection options array, which identifies all the
+ * available options and shows any default values that are available from the
+ * environment etc.  On error (eg out of memory), NULL is returned.
  *
  * Using this function, an application may determine all possible options
  * and their current default values.
@@ -833,10 +835,21 @@ PQconndefaults(void)
    PQExpBufferData errorBuf;
    PQconninfoOption *connOptions;
 
+   /* We don't actually report any errors here, but callees want a buffer */
    initPQExpBuffer(&errorBuf);
    if (PQExpBufferDataBroken(errorBuf))
        return NULL;            /* out of memory already :-( */
-   connOptions = conninfo_parse("", &errorBuf, true);
+
+   connOptions = conninfo_init(&errorBuf);
+   if (connOptions != NULL)
+   {
+       if (!conninfo_add_defaults(connOptions, &errorBuf))
+       {
+           PQconninfoFree(connOptions);
+           connOptions = NULL;
+       }
+   }
+
    termPQExpBuffer(&errorBuf);
    return connOptions;
 }
@@ -3986,6 +3999,25 @@ PQconninfoParse(const char *conninfo, char **errmsg)
    return connOptions;
 }
 
+/*
+ * Build a working copy of the constant PQconninfoOptions array.
+ */
+static PQconninfoOption *
+conninfo_init(PQExpBuffer errorMessage)
+{
+   PQconninfoOption *options;
+
+   options = (PQconninfoOption *) malloc(sizeof(PQconninfoOptions));
+   if (options == NULL)
+   {
+       printfPQExpBuffer(errorMessage,
+                         libpq_gettext("out of memory\n"));
+       return NULL;
+   }
+   memcpy(options, PQconninfoOptions, sizeof(PQconninfoOptions));
+   return options;
+}
+
 /*
  * Conninfo parser routine
  *
@@ -4002,21 +4034,15 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage,
    char       *pname;
    char       *pval;
    char       *buf;
-   char       *tmp;
    char       *cp;
    char       *cp2;
    PQconninfoOption *options;
    PQconninfoOption *option;
 
    /* Make a working copy of PQconninfoOptions */
-   options = malloc(sizeof(PQconninfoOptions));
+   options = conninfo_init(errorMessage);
    if (options == NULL)
-   {
-       printfPQExpBuffer(errorMessage,
-                         libpq_gettext("out of memory\n"));
        return NULL;
-   }
-   memcpy(options, PQconninfoOptions, sizeof(PQconninfoOptions));
 
    /* Need a modifiable copy of the input string */
    if ((buf = strdup(conninfo)) == NULL)
@@ -4170,73 +4196,14 @@ conninfo_parse(const char *conninfo, PQExpBuffer errorMessage,
    free(buf);
 
    /*
-    * Stop here if caller doesn't want defaults filled in.
-    */
-   if (!use_defaults)
-       return options;
-
-   /*
-    * If there's a service spec, use it to obtain any not-explicitly-given
-    * parameters.
-    */
-   if (parseServiceInfo(options, errorMessage))
-   {
-       PQconninfoFree(options);
-       return NULL;
-   }
-
-   /*
-    * Get the fallback resources for parameters not specified in the conninfo
-    * string nor the service.
+    * Add in defaults if the caller wants that.
     */
-   for (option = options; option->keyword != NULL; option++)
+   if (use_defaults)
    {
-       if (option->val != NULL)
-           continue;           /* Value was in conninfo or service */
-
-       /*
-        * Try to get the environment variable fallback
-        */
-       if (option->envvar != NULL)
+       if (!conninfo_add_defaults(options, errorMessage))
        {
-           if ((tmp = getenv(option->envvar)) != NULL)
-           {
-               option->val = strdup(tmp);
-               if (!option->val)
-               {
-                   printfPQExpBuffer(errorMessage,
-                                     libpq_gettext("out of memory\n"));
-                   PQconninfoFree(options);
-                   return NULL;
-               }
-               continue;
-           }
-       }
-
-       /*
-        * No environment variable specified or this one isn't set - try
-        * compiled in
-        */
-       if (option->compiled != NULL)
-       {
-           option->val = strdup(option->compiled);
-           if (!option->val)
-           {
-               printfPQExpBuffer(errorMessage,
-                                 libpq_gettext("out of memory\n"));
-               PQconninfoFree(options);
-               return NULL;
-           }
-           continue;
-       }
-
-       /*
-        * Special handling for user
-        */
-       if (strcmp(option->keyword, "user") == 0)
-       {
-           option->val = pg_fe_getauthname(errorMessage);
-           continue;
+           PQconninfoFree(options);
+           return NULL;
        }
    }
 
@@ -4262,7 +4229,6 @@ conninfo_array_parse(const char *const * keywords, const char *const * values,
                     PQExpBuffer errorMessage, bool use_defaults,
                     int expand_dbname)
 {
-   char       *tmp;
    PQconninfoOption *options;
    PQconninfoOption *str_options = NULL;
    PQconninfoOption *option;
@@ -4298,18 +4264,15 @@ conninfo_array_parse(const char *const * keywords, const char *const * values,
    }
 
    /* Make a working copy of PQconninfoOptions */
-   options = malloc(sizeof(PQconninfoOptions));
+   options = conninfo_init(errorMessage);
    if (options == NULL)
    {
-       printfPQExpBuffer(errorMessage,
-                         libpq_gettext("out of memory\n"));
        PQconninfoFree(str_options);
        return NULL;
    }
-   memcpy(options, PQconninfoOptions, sizeof(PQconninfoOptions));
 
-   i = 0;
    /* Parse the keywords/values arrays */
+   i = 0;
    while (keywords[i])
    {
        const char *pname = keywords[i];
@@ -4386,20 +4349,42 @@ conninfo_array_parse(const char *const * keywords, const char *const * values,
    PQconninfoFree(str_options);
 
    /*
-    * Stop here if caller doesn't want defaults filled in.
+    * Add in defaults if the caller wants that.
     */
-   if (!use_defaults)
-       return options;
+   if (use_defaults)
+   {
+       if (!conninfo_add_defaults(options, errorMessage))
+       {
+           PQconninfoFree(options);
+           return NULL;
+       }
+   }
+
+   return options;
+}
+
+/*
+ * Add the default values for any unspecified options to the connection
+ * options array.
+ *
+ * Defaults are obtained from a service file, environment variables, etc.
+ *
+ * Returns TRUE if successful, otherwise FALSE; errorMessage is filled in
+ * upon failure.  Note that failure to locate a default value is not an
+ * error condition here --- we just leave the option's value as NULL.
+ */
+static bool
+conninfo_add_defaults(PQconninfoOption *options, PQExpBuffer errorMessage)
+{
+   PQconninfoOption *option;
+   char       *tmp;
 
    /*
     * If there's a service spec, use it to obtain any not-explicitly-given
     * parameters.
     */
-   if (parseServiceInfo(options, errorMessage))
-   {
-       PQconninfoFree(options);
-       return NULL;
-   }
+   if (parseServiceInfo(options, errorMessage) != 0)
+       return false;
 
    /*
     * Get the fallback resources for parameters not specified in the conninfo
@@ -4422,16 +4407,15 @@ conninfo_array_parse(const char *const * keywords, const char *const * values,
                {
                    printfPQExpBuffer(errorMessage,
                                      libpq_gettext("out of memory\n"));
-                   PQconninfoFree(options);
-                   return NULL;
+                   return false;
                }
                continue;
            }
        }
 
        /*
-        * No environment variable specified or this one isn't set - try
-        * compiled in
+        * No environment variable specified or the variable isn't set - try
+        * compiled-in default
         */
        if (option->compiled != NULL)
        {
@@ -4440,14 +4424,13 @@ conninfo_array_parse(const char *const * keywords, const char *const * values,
            {
                printfPQExpBuffer(errorMessage,
                                  libpq_gettext("out of memory\n"));
-               PQconninfoFree(options);
-               return NULL;
+               return false;
            }
            continue;
        }
 
        /*
-        * Special handling for user
+        * Special handling for "user" option
         */
        if (strcmp(option->keyword, "user") == 0)
        {
@@ -4456,7 +4439,7 @@ conninfo_array_parse(const char *const * keywords, const char *const * values,
        }
    }
 
-   return options;
+   return true;
 }
 
 static char *