diff --git a/doc/src/sgml/ecpg.sgml b/doc/src/sgml/ecpg.sgml
index 9310a71166..a21ee477d7 100644
--- a/doc/src/sgml/ecpg.sgml
+++ b/doc/src/sgml/ecpg.sgml
@@ -163,6 +163,16 @@ EXEC SQL CONNECT TO target AS
target directly.
+
+ Same as libpq, the host part can be specified an IPv6 address.
+ To specify an IPv6 address, the string must be specified as
+ SQL string literal and enclose it in square brackets:
+
+
+
+EXEC SQL CONNECT TO 'tcp:postgresql://[2001:db8::1234]/database'
+
+
There are also different ways to specify the user name:
diff --git a/src/interfaces/ecpg/ecpglib/connect.c b/src/interfaces/ecpg/ecpglib/connect.c
index ac65c7ac8b..231d762db3 100644
--- a/src/interfaces/ecpg/ecpglib/connect.c
+++ b/src/interfaces/ecpg/ecpglib/connect.c
@@ -295,9 +295,44 @@ parse_newstyle(int lineno, char *buf, char **host, char **dbname, char **port, c
start = buf + prefix_len + strlen("postgresql://");
p = start;
- /* Look ahead for possible user credentials designator */
- while (*p && *p != ':' && *p != '/' && *p != '?')
- ++p;
+
+ /*
+ * Look for IPv6 address.
+ */
+ if (*p == '[')
+ {
+ start = ++p;
+ while (*p && *p != ']')
+ ++p;
+ if (!*p)
+ {
+ ecpg_log("end of string reached when looking for matching \"]\" in IPv6 host address: \"%s\"\n", buf);
+ return -1;
+ }
+ if (p == start)
+ {
+ ecpg_log("IPv6 host address may not be empty: \"%s\"\n", buf);
+ return -1;
+ }
+ /* Cut off the bracket and advance */
+ *(p++) = '\0';
+
+ /*
+ * The address may be followed by a port specifier or a slash or a
+ * query.
+ */
+ if (*p && *p != ':' && *p != '/' && *p != '?')
+ {
+ ecpg_log("unexpected character \"%c\" at position %d (expected \":\", \"/\" or \"?\"): \"%s]%s\"\n", *p, (int) (p - buf + 1), buf, p);
+ return -1;
+ }
+ }
+ else
+ {
+ /* Look ahead for possible user credentials designator */
+ while (*p && *p != ':' && *p != '/' && *p != '?')
+ ++p;
+ }
/* Save the hostname terminator before we null it */
prevchar = *p;
@@ -328,7 +363,8 @@ parse_newstyle(int lineno, char *buf, char **host, char **dbname, char **port, c
*port = ecpg_strdup(start, lineno);
if (!(*port))
{
- ecpg_free(*host);
+ if (!is_unix)
+ ecpg_free(*host);
return -1;
}
connect_params++;
@@ -352,7 +388,8 @@ parse_newstyle(int lineno, char *buf, char **host, char **dbname, char **port, c
*dbname = ecpg_strdup(start, lineno);
if (!(*dbname))
{
- ecpg_free(*host);
+ if (!is_unix)
+ ecpg_free(*host);
ecpg_free(*port);
return -1;
}
@@ -368,7 +405,8 @@ parse_newstyle(int lineno, char *buf, char **host, char **dbname, char **port, c
*options = ecpg_strdup(start, lineno);
if (!(*options))
{
- ecpg_free(*host);
+ if (!is_unix)
+ ecpg_free(*host);
ecpg_free(*port);
ecpg_free(*dbname);
return -1;
@@ -379,12 +417,13 @@ parse_newstyle(int lineno, char *buf, char **host, char **dbname, char **port, c
if (is_unix)
{
if (strcmp(*host, "localhost") &&
- strcmp(*host, "127.0.0.1"))
+ strcmp(*host, "127.0.0.1") &&
+ strcmp(*host, "::1"))
{
/*
* 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.
+ * compatibility's sake.
*/
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, *dbname ? *dbname : ecpg_gettext(""));
@@ -435,8 +474,43 @@ parse_oldstyle(int lineno, char *buf, char **host, char **dbname, char **port)
{
/* hostname is found */
start = ++p;
- while(*p && *p != ':')
- ++p;
+ /*
+ * Look for IPv6 address.
+ */
+ if (*p == '[')
+ {
+ start = ++p;
+ while (*p && *p != ']')
+ ++p;
+ if (!*p)
+ {
+ ecpg_log("end of string reached when looking for matching \"]\" in IPv6 host address: \"%s\"\n", buf);
+ return -1;
+ }
+ if (p == start)
+ {
+ ecpg_log("IPv6 host address may not be empty: \"%s\"\n", buf);
+ return -1;
+ }
+ /* Cut off the bracket and advance */
+ *(p++) = '\0';
+
+ /*
+ * The address may be followed by a port specifier or a slash or a
+ * query.
+ */
+ if (*p && *p != ':')
+ {
+ ecpg_log("unexpected character \"%c\": \"%s]%s\"\n", *p, buf, p);
+ return -1;
+ }
+ }
+ else
+ {
+ while(*p && *p != ':')
+ ++p;
+
+ }
prevchar = *p;
*p = '\0';
if (strcmp(start, "localhost") && strcmp(start, "127.0.0.1"))
diff --git a/src/interfaces/ecpg/test/connect/test5.pgc b/src/interfaces/ecpg/test/connect/test5.pgc
index e712fa8778..5a6326deeb 100644
--- a/src/interfaces/ecpg/test/connect/test5.pgc
+++ b/src/interfaces/ecpg/test/connect/test5.pgc
@@ -72,5 +72,15 @@ exec sql end declare section;
/* not connected */
exec sql disconnect nonexistent;
+ /* use IPv6 */
+ exec sql connect to 'unix:postgresql://[::1]/ecpg2_regression' as main;
+ exec sql disconnect main;
+
+ exec sql connect to 'unix:postgresql://[::1/ecpg2_regression' as main;
+
+ exec sql connect to 'unix:postgresql://[]/ecpg2_regression' as main;
+
+ exec sql connect to 'unix:postgresql://[::1]&ecpg2_regression' as main;
+
return 0;
}
diff --git a/src/interfaces/ecpg/test/expected/connect-test5.c b/src/interfaces/ecpg/test/expected/connect-test5.c
index 6ae5b589de..9ae7a3e144 100644
--- a/src/interfaces/ecpg/test/expected/connect-test5.c
+++ b/src/interfaces/ecpg/test/expected/connect-test5.c
@@ -158,5 +158,25 @@ main(void)
#line 73 "test5.pgc"
+ /* use IPv6 */
+ { ECPGconnect(__LINE__, 0, "unix:postgresql://[::1]/ecpg2_regression" , NULL, NULL , "main", 0); }
+#line 76 "test5.pgc"
+
+ { ECPGdisconnect(__LINE__, "main");}
+#line 77 "test5.pgc"
+
+
+ { ECPGconnect(__LINE__, 0, "unix:postgresql://[::1/ecpg2_regression" , NULL, NULL , "main", 0); }
+#line 79 "test5.pgc"
+
+
+ { ECPGconnect(__LINE__, 0, "unix:postgresql://[]/ecpg2_regression" , NULL, NULL , "main", 0); }
+#line 81 "test5.pgc"
+
+
+ { ECPGconnect(__LINE__, 0, "unix:postgresql://[::1]&ecpg2_regression" , NULL, NULL , "main", 0); }
+#line 83 "test5.pgc"
+
+
return 0;
}
diff --git a/src/interfaces/ecpg/test/expected/connect-test5.stderr b/src/interfaces/ecpg/test/expected/connect-test5.stderr
index a15f344320..63bc450329 100644
--- a/src/interfaces/ecpg/test/expected/connect-test5.stderr
+++ b/src/interfaces/ecpg/test/expected/connect-test5.stderr
@@ -88,3 +88,13 @@
[NO_PID]: sqlca: code: 0, state: 00000
[NO_PID]: raising sqlcode -220 on line 73: connection "nonexistent" does not exist on line 73
[NO_PID]: sqlca: code: -220, state: 08003
+[NO_PID]: ECPGconnect: opening database ecpg2_regression on port
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_finish: connection main closed
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: end of string reached when looking for matching "]" in IPv6 host address: "unix:postgresql://[::1/ecpg2_regression"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: IPv6 host address may not be empty: "unix:postgresql://[]/ecpg2_regression"
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: unexpected character "&" at position 24 (expected ":", "/" or "?"): "unix:postgresql://[::1]&ecpg2_regression"
+[NO_PID]: sqlca: code: 0, state: 00000