Remove dead code in ECPGconnect(), and improve documentation.

The stanza in ECPGconnect() that intended to allow specification of a
Unix socket directory path in place of a port has never executed since
it was committed, nearly two decades ago; the preceding strrchr()
already found the last colon so there cannot be another one.  The lack
of complaints about that is doubtless related to the fact that no
user-facing documentation suggested it was possible.

Rather than try to fix that up, let's just remove the unreachable
code, and instead document the way that does work to write a socket
directory path, namely specifying it as a "host" option.

In support of that, make another pass at clarifying the syntax
documentation for ECPG connection targets, particularly documenting
which things are parsed as identifiers and where to use double quotes.
Rearrange some things that seemed poorly ordered, and fix a couple of
minor doc errors.

Kyotaro Horiguchi, per gripe from Shenhao Wang
(docs changes mostly by me)

Discussion: https://postgr.es/m/ae52a416bbbf459c96bab30b3038e06c@G08CNEXMBPEKD06.g08.fujitsu.local
This commit is contained in:
Tom Lane 2021-02-11 15:05:55 -05:00
parent 69036aafb9
commit 62535cae97
2 changed files with 67 additions and 75 deletions

View File

@ -120,7 +120,7 @@ EXEC SQL CONNECT TO <replaceable>target</replaceable> <optional>AS <replaceable>
<listitem>
<simpara>
<literal>unix:postgresql://<replaceable>hostname</replaceable><optional>:<replaceable>port</replaceable></optional><optional>/<replaceable>dbname</replaceable></optional><optional>?<replaceable>options</replaceable></optional></literal>
<literal>unix:postgresql://localhost<optional>:<replaceable>port</replaceable></optional><optional>/<replaceable>dbname</replaceable></optional><optional>?<replaceable>options</replaceable></optional></literal>
</simpara>
</listitem>
@ -143,17 +143,26 @@ EXEC SQL CONNECT TO <replaceable>target</replaceable> <optional>AS <replaceable>
</listitem>
</itemizedlist>
If you specify the connection target literally (that is, not
through a variable reference) and you don't quote the value, then
the case-insensitivity rules of normal SQL are applied. In that
case you can also double-quote the individual parameters separately
as needed. In practice, it is probably less error-prone to use a
(single-quoted) string literal or a variable reference. The
connection target <literal>DEFAULT</literal> initiates a connection
The connection target <literal>DEFAULT</literal> initiates a connection
to the default database under the default user name. No separate
user name or connection name can be specified in that case.
</para>
<para>
If you specify the connection target directly (that is, not as a string
literal or variable reference), then the components of the target are
passed through normal SQL parsing; this means that, for example,
the <replaceable>hostname</replaceable> must look like one or more SQL
identifiers separated by dots, and those identifiers will be
case-folded unless double-quoted. Values of
any <replaceable>options</replaceable> must be SQL identifiers,
integers, or variable references. Of course, you can put nearly
anything into an SQL identifier by double-quoting it.
In practice, it is probably less error-prone to use a (single-quoted)
string literal or a variable reference than to write the connection
target directly.
</para>
<para>
There are also different ways to specify the user name:
@ -201,6 +210,15 @@ EXEC SQL CONNECT TO <replaceable>target</replaceable> <optional>AS <replaceable>
write <literal>&amp;</literal> within a <replaceable>value</replaceable>.
</para>
<para>
Notice that when specifying a socket connection
(with the <literal>unix:</literal> prefix), the host name must be
exactly <literal>localhost</literal>. To select a non-default
socket directory, write the directory's pathname as the value of
a <varname>host</varname> option in
the <replaceable>options</replaceable> part of the target.
</para>
<para>
The <replaceable>connection-name</replaceable> is used to handle
multiple connections in one program. It can be omitted if a
@ -210,6 +228,36 @@ EXEC SQL CONNECT TO <replaceable>target</replaceable> <optional>AS <replaceable>
chapter).
</para>
<para>
Here are some examples of <command>CONNECT</command> statements:
<programlisting>
EXEC SQL CONNECT TO mydb@sql.mydomain.com;
EXEC SQL CONNECT TO tcp:postgresql://sql.mydomain.com/mydb AS myconnection USER john;
EXEC SQL BEGIN DECLARE SECTION;
const char *target = "mydb@sql.mydomain.com";
const char *user = "john";
const char *passwd = "secret";
EXEC SQL END DECLARE SECTION;
...
EXEC SQL CONNECT TO :target USER :user USING :passwd;
/* or EXEC SQL CONNECT TO :target USER :user/:passwd; */
</programlisting>
The last example makes use of the feature referred to above as
character variable references. You will see in later sections how C
variables can be used in SQL statements when you prefix them with a
colon.
</para>
<para>
Be advised that the format of the connection target is not
specified in the SQL standard. So if you want to develop portable
applications, you might want to use something based on the last
example above to encapsulate the connection target string
somewhere.
</para>
<para>
If untrusted users have access to a database that has not adopted a
<link linkend="ddl-schemas-patterns">secure schema usage pattern</link>,
@ -221,36 +269,6 @@ EXEC SQL CONNECT TO <replaceable>target</replaceable> <optional>AS <replaceable>
false);</literal> after connecting. This consideration is not specific to
ECPG; it applies to every interface for executing arbitrary SQL commands.
</para>
<para>
Here are some examples of <command>CONNECT</command> statements:
<programlisting>
EXEC SQL CONNECT TO mydb@sql.mydomain.com;
EXEC SQL CONNECT TO unix:postgresql://sql.mydomain.com/mydb AS myconnection USER john;
EXEC SQL BEGIN DECLARE SECTION;
const char *target = "mydb@sql.mydomain.com";
const char *user = "john";
const char *passwd = "secret";
EXEC SQL END DECLARE SECTION;
...
EXEC SQL CONNECT TO :target USER :user USING :passwd;
/* or EXEC SQL CONNECT TO :target USER :user/:passwd; */
</programlisting>
The last form makes use of the variant referred to above as
character variable reference. You will see in later sections how C
variables can be used in SQL statements when you prefix them with a
colon.
</para>
<para>
Be advised that the format of the connection target is not
specified in the SQL standard. So if you want to develop portable
applications, you might want to use something based on the last
example above to encapsulate the connection target string
somewhere.
</para>
</sect2>
<sect2 id="ecpg-set-connection">

View File

@ -360,8 +360,7 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
/*------
* new style:
* <tcp|unix>:postgresql://server[:port|:/unixsocket/path:]
* [/db-name][?options]
* <tcp|unix>:postgresql://server[:port][/db-name][?options]
*------
*/
offset += strlen("postgresql://");
@ -385,46 +384,22 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
}
tmp = strrchr(dbname + offset, ':');
if (tmp != NULL) /* port number or Unix socket path given */
if (tmp != NULL) /* port number given */
{
char *tmp2;
*tmp = '\0';
if ((tmp2 = strchr(tmp + 1, ':')) != NULL)
{
*tmp2 = '\0';
host = ecpg_strdup(tmp + 1, lineno);
connect_params++;
if (strncmp(dbname, "unix:", 5) != 0)
{
ecpg_log("ECPGconnect: socketname %s given for TCP connection on line %d\n", host, lineno);
ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : ecpg_gettext("<DEFAULT>"));
if (host)
ecpg_free(host);
/*
* port not set yet if (port) ecpg_free(port);
*/
if (options)
ecpg_free(options);
if (realname)
ecpg_free(realname);
if (dbname)
ecpg_free(dbname);
free(this);
return false;
}
}
else
{
port = ecpg_strdup(tmp + 1, lineno);
connect_params++;
}
port = ecpg_strdup(tmp + 1, lineno);
connect_params++;
}
if (strncmp(dbname, "unix:", 5) == 0)
{
if (strcmp(dbname + offset, "localhost") != 0 && strcmp(dbname + offset, "127.0.0.1") != 0)
/*
* The alternative of using "127.0.0.1" here is deprecated
* and undocumented; we'll keep it for backward
* compatibility's sake, but not extend it to allow IPv6.
*/
if (strcmp(dbname + offset, "localhost") != 0 &&
strcmp(dbname + offset, "127.0.0.1") != 0)
{
ecpg_log("ECPGconnect: non-localhost access via sockets on line %d\n", lineno);
ecpg_raise(lineno, ECPG_CONNECT, ECPG_SQLSTATE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION, realname ? realname : ecpg_gettext("<DEFAULT>"));
@ -450,7 +425,6 @@ ECPGconnect(int lineno, int c, const char *name, const char *user, const char *p
connect_params++;
}
}
}
}
else