You can subscribe to this list here.
2010 |
Jan
|
Feb
|
Mar
|
Apr
(4) |
May
(28) |
Jun
(12) |
Jul
(11) |
Aug
(12) |
Sep
(5) |
Oct
(19) |
Nov
(14) |
Dec
(12) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2011 |
Jan
(18) |
Feb
(30) |
Mar
(115) |
Apr
(89) |
May
(50) |
Jun
(44) |
Jul
(22) |
Aug
(13) |
Sep
(11) |
Oct
(30) |
Nov
(28) |
Dec
(39) |
2012 |
Jan
(38) |
Feb
(18) |
Mar
(43) |
Apr
(91) |
May
(108) |
Jun
(46) |
Jul
(37) |
Aug
(44) |
Sep
(33) |
Oct
(29) |
Nov
(36) |
Dec
(15) |
2013 |
Jan
(35) |
Feb
(611) |
Mar
(5) |
Apr
(55) |
May
(30) |
Jun
(28) |
Jul
(458) |
Aug
(34) |
Sep
(9) |
Oct
(39) |
Nov
(22) |
Dec
(32) |
2014 |
Jan
(16) |
Feb
(16) |
Mar
(42) |
Apr
(179) |
May
(7) |
Jun
(6) |
Jul
(9) |
Aug
|
Sep
(4) |
Oct
|
Nov
(3) |
Dec
|
2015 |
Jan
|
Feb
|
Mar
|
Apr
(2) |
May
(4) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
|
|
|
|
|
1
(2) |
2
(3) |
3
|
4
(2) |
5
(3) |
6
(2) |
7
(8) |
8
(12) |
9
|
10
|
11
(17) |
12
(16) |
13
(4) |
14
(3) |
15
(5) |
16
|
17
|
18
(1) |
19
(3) |
20
(2) |
21
(1) |
22
(1) |
23
|
24
|
25
(3) |
26
(1) |
27
|
28
|
29
|
30
|
From: Koichi S. <koi...@us...> - 2011-04-26 06:36:55
|
Project "Postgres-XC". The branch, ha_support has been updated via ea7e9f087bfa99445cfc1efbce6f440b534023ac (commit) via 912be1eaccf2cc1e85409926efed836674bf4b80 (commit) from 2974169569091d02a67feaf2b5dcc93b575965e5 (commit) - Log ----------------------------------------------------------------- commit ea7e9f087bfa99445cfc1efbce6f440b534023ac Author: Koichi Suzuki <koi...@gm...> Date: Tue Apr 26 15:31:04 2011 +0900 This commit is to fix GTM-Proxy problems in registering nodes. Fixed files are as follows: src/gtm/client/gtm_client.c src/gtm/proxy/proxy_main.c src/gtm/recovery/register.c src/include/gtm/gtm_proxy.h The cause of the problem was message format mismatch in GTM-Proxy. MSG_NODE_REGISTER was not handled properly. I collected the order of the values and added missing information both when parsing incoming messge from clients and constructing outgoing message to GTM. This is needed before adding "reconnect" feature to GTM-Standby. diff --git a/src/gtm/client/gtm_client.c b/src/gtm/client/gtm_client.c index fe1a4e8..f22ebe4 100644 --- a/src/gtm/client/gtm_client.c +++ b/src/gtm/client/gtm_client.c @@ -1185,6 +1185,8 @@ node_get_local_addr(GTM_Conn *conn, char *buf, size_t buflen, int *rc) char remote_host[NI_MAXHOST]; char remote_port[NI_MAXSERV]; + *rc = 0; + memset(remote_host, 0, sizeof(remote_host)); memset(remote_port, 0, sizeof(remote_port)); memset(buf, 0, buflen); @@ -1238,15 +1240,25 @@ int node_register2(GTM_Conn *conn, GTM_PGXCNodeType type, const char *host, GTM GTM_PGXCNodeId proxynum = 0; if (gtmpqPutMsgStart('C', true, conn) || + /* Message Type */ gtmpqPutInt(MSG_NODE_REGISTER, sizeof (GTM_MessageType), conn) || + /* Node Type to Register */ gtmpqPutnchar((char *)&type, sizeof(GTM_PGXCNodeType), conn) || + /* Node Number to Register */ gtmpqPutnchar((char *)&nodenum, sizeof(GTM_PGXCNodeId), conn) || + /* Host name length */ gtmpqPutInt(strlen(host), sizeof (GTM_StrLen), conn) || + /* Host name (var-len) */ gtmpqPutnchar(host, strlen(host), conn) || + /* Port number */ gtmpqPutnchar((char *)&port, sizeof(GTM_PGXCNodePort), conn) || + /* Proxy ID (zero if connected to GTM directly) */ gtmpqPutnchar((char *)&proxynum, sizeof(GTM_PGXCNodeId), conn) || + /* Data Folder length */ gtmpqPutInt(strlen(datafolder), sizeof (GTM_StrLen), conn) || + /* Data Folder (var-len) */ gtmpqPutnchar(datafolder, strlen(datafolder), conn) || + /* Node Status */ gtmpqPutInt(status, sizeof(GTM_PGXCNodeStatus), conn)) goto send_failed; diff --git a/src/gtm/proxy/proxy_main.c b/src/gtm/proxy/proxy_main.c index 9e917ee..4ab6f94 100644 --- a/src/gtm/proxy/proxy_main.c +++ b/src/gtm/proxy/proxy_main.c @@ -1333,6 +1333,15 @@ ProcessPGXCNodeCommand(GTMProxy_ConnectionInfo *conninfo, GTM_Conn *gtm_conn, sizeof (GTM_PGXCNodeType)); memcpy(&cmd_data.cd_reg.nodenum, pq_getmsgbytes(message, sizeof (GTM_PGXCNodeId)), sizeof (GTM_PGXCNodeId)); + /* + * Now we have to waste the following host information. It is taken from + * the address field in the conn. + */ + len = pq_getmsgint(message, sizeof(GTM_StrLen)); + pq_getmsgbytes(message, len); + /* + * Then the next is the port number. + */ memcpy(&cmd_data.cd_reg.port, pq_getmsgbytes(message, sizeof (GTM_PGXCNodePort)), sizeof (GTM_PGXCNodePort)); memcpy(&cmd_data.cd_reg.proxynum, pq_getmsgbytes(message, sizeof (GTM_PGXCNodeId)), @@ -1340,6 +1349,11 @@ ProcessPGXCNodeCommand(GTMProxy_ConnectionInfo *conninfo, GTM_Conn *gtm_conn, len = pq_getmsgint(message, sizeof (int)); cmd_data.cd_reg.datafolder = (char *)pq_getmsgbytes(message, len); + + /* + * Now we have one more data to waste, "status" + */ + cmd_data.cd_reg.status = pq_getmsgint(message, sizeof(GTM_PGXCNodeStatus)); pq_getmsgend(message); /* Copy also remote host address in data to be proxied */ @@ -1586,16 +1600,29 @@ static void GTMProxy_ProxyPGXCNodeCommand(GTMProxy_ConnectionInfo *conninfo,GTM_ case MSG_NODE_REGISTER: /* Rebuild the message */ if (gtmpqPutMsgStart('C', true, gtm_conn) || + /* GTM Proxy Header */ gtmpqPutnchar((char *)&proxyhdr, sizeof (GTM_ProxyMsgHeader), gtm_conn) || + /* Message Type */ gtmpqPutInt(MSG_NODE_REGISTER, sizeof (GTM_MessageType), gtm_conn) || + /* Node Type to Register */ gtmpqPutnchar((char *)&cmd_data.cd_reg.type, sizeof(GTM_PGXCNodeType), gtm_conn) || + /* Node Number to Register */ gtmpqPutnchar((char *)&cmd_data.cd_reg.nodenum, sizeof(GTM_PGXCNodeId), gtm_conn) || - gtmpqPutnchar((char *)&cmd_data.cd_reg.port, sizeof(GTM_PGXCNodePort), gtm_conn) || - gtmpqPutnchar((char *)>MProxyID, sizeof(GTM_PGXCNodeId), gtm_conn) || + /* Host Name (length) */ gtmpqPutInt(strlen(cmd_data.cd_reg.ipaddress), sizeof (GTM_StrLen), gtm_conn) || + /* Host Name (var-len) */ gtmpqPutnchar(cmd_data.cd_reg.ipaddress, strlen(cmd_data.cd_reg.ipaddress), gtm_conn) || + /* Port Number */ + gtmpqPutnchar((char *)&cmd_data.cd_reg.port, sizeof(GTM_PGXCNodePort), gtm_conn) || + /* Proxy ID (zero if connected to GTM directly) */ + gtmpqPutnchar((char *)>MProxyID, sizeof(GTM_PGXCNodeId), gtm_conn) || + /* Data Folder length */ gtmpqPutInt(strlen(cmd_data.cd_reg.datafolder), 4, gtm_conn) || - gtmpqPutnchar(cmd_data.cd_reg.datafolder, strlen(cmd_data.cd_reg.datafolder), gtm_conn)) + /* Data folder name (var-len) */ + gtmpqPutnchar(cmd_data.cd_reg.datafolder, strlen(cmd_data.cd_reg.datafolder), gtm_conn) || + /* Node Status */ + gtmpqPutInt(cmd_data.cd_reg.status, sizeof(GTM_PGXCNodeStatus), gtm_conn)) + elog(ERROR, "Error proxing data"); break; diff --git a/src/gtm/recovery/register.c b/src/gtm/recovery/register.c index 5f44425..c5d72d8 100644 --- a/src/gtm/recovery/register.c +++ b/src/gtm/recovery/register.c @@ -35,8 +35,8 @@ #include "gtm/libpq.h" #include "gtm/pqformat.h" #include "gtm/gtm_msg.h" -#include "gtm/gtm_ip.h" #endif +#include "gtm/gtm_ip.h" #define GTM_NODE_FILE "register.node" #define NODE_HASH_TABLE_SIZE 16 @@ -419,7 +419,6 @@ ProcessPGXCNodeRegister(Port *myport, StringInfo message) int strlen; StringInfoData buf; GTM_PGXCNodeStatus status; - size_t hostlen; /* Get the Remote node IP and port to register it */ remote_host[0] = '\0'; @@ -427,7 +426,6 @@ ProcessPGXCNodeRegister(Port *myport, StringInfo message) memset(remote_host, 0, sizeof(remote_host)); -#ifdef NOT_USED if (myport->remote_type != PGXC_NODE_GTM_PROXY) { if (gtm_getnameinfo_all(&myport->raddr.addr, myport->raddr.salen, @@ -445,26 +443,14 @@ ProcessPGXCNodeRegister(Port *myport, StringInfo message) (errmsg_internal("gtm_getnameinfo_all() failed"))); } } -#endif - /* Read Node Type and number */ + /* Read Node Type */ memcpy(&type, pq_getmsgbytes(message, sizeof (GTM_PGXCNodeType)), sizeof (GTM_PGXCNodeType)); + /* Node Number */ memcpy(&nodenum, pq_getmsgbytes(message, sizeof (GTM_PGXCNodeId)), sizeof (GTM_PGXCNodeId)); - /* Read Host Name */ - hostlen = pq_getmsgint(message, sizeof (GTM_StrLen)); - memcpy(remote_host, pq_getmsgbytes(message, hostlen), hostlen); - - /* Read Port Number */ - memcpy(&port, pq_getmsgbytes(message, sizeof (GTM_PGXCNodePort)), - sizeof (GTM_PGXCNodePort)); - - /* Read Proxy ID number (0 if no proxy used) */ - memcpy(&proxynum, pq_getmsgbytes(message, sizeof (GTM_PGXCNodeId)), - sizeof (GTM_PGXCNodeId)); - /* * Message is received from a proxy, get also the remote node address * In the case a proxy registering itself, the remote address @@ -479,12 +465,19 @@ ProcessPGXCNodeRegister(Port *myport, StringInfo message) else ipaddress = remote_host; + /* Read Port Number */ + memcpy(&port, pq_getmsgbytes(message, sizeof (GTM_PGXCNodePort)), + sizeof (GTM_PGXCNodePort)); + + /* Read Proxy ID number (0 if no proxy used) */ + memcpy(&proxynum, pq_getmsgbytes(message, sizeof (GTM_PGXCNodeId)), + sizeof (GTM_PGXCNodeId)); + elog(LOG, "ProcessPGXCNodeRegister: ipaddress = %s", ipaddress); /* * Finish by reading Data Folder (length and then string) */ - strlen = pq_getmsgint(message, sizeof (GTM_StrLen)); datafolder = (char *)pq_getmsgbytes(message, strlen); diff --git a/src/include/gtm/gtm_proxy.h b/src/include/gtm/gtm_proxy.h index 4fcf5f0..2af5ef3 100644 --- a/src/include/gtm/gtm_proxy.h +++ b/src/include/gtm/gtm_proxy.h @@ -173,6 +173,7 @@ typedef union GTMProxy_CommandData GTM_PGXCNodeId proxynum; char *datafolder; char *ipaddress; + GTM_PGXCNodeStatus status; } cd_reg; } GTMProxy_CommandData; commit 912be1eaccf2cc1e85409926efed836674bf4b80 Author: Koichi Suzuki <koi...@gm...> Date: Fri Apr 8 16:32:19 2011 +0900 gtm_ctl.c comment refactoring. diff --git a/src/gtm/gtm_ctl/gtm_ctl.c b/src/gtm/gtm_ctl/gtm_ctl.c index 5092a47..55c11bf 100644 --- a/src/gtm/gtm_ctl/gtm_ctl.c +++ b/src/gtm/gtm_ctl/gtm_ctl.c @@ -618,6 +618,11 @@ do_reconnect(void) exit(1); } read_gtm_opts(); + /* + * Pass reconnect info to GTM-Proxy. + * + * Option arguments are written to newgtm file under -D directory. + */ reconnect_point_file_nam = malloc(strlen(gtm_data) + 8); if (reconnect_point_file_nam == NULL) { @@ -634,14 +639,6 @@ do_reconnect(void) fprintf(reconnect_point_file, "%s", gtm_opts); fclose(reconnect_point_file); free(reconnect_point_file_nam); - /* - * Beofore signaling, we need to set the host and port of the new target GTM. - * - * They should be written to "newgtm" file under -D directory. - * First line is the host name and the second line is port (all in - * text representation). - */ - /* === WIP 20110408 === */ if (kill((pid_t) pid, SIGUSR2) != 0) { write_stderr(_("%s: could not send promote signal (PID: %ld): %s\n"), progname, pid, ----------------------------------------------------------------------- Summary of changes: src/gtm/client/gtm_client.c | 12 ++++++++++++ src/gtm/gtm_ctl/gtm_ctl.c | 13 +++++-------- src/gtm/proxy/proxy_main.c | 33 ++++++++++++++++++++++++++++++--- src/gtm/recovery/register.c | 29 +++++++++++------------------ src/include/gtm/gtm_proxy.h | 1 + 5 files changed, 59 insertions(+), 29 deletions(-) hooks/post-receive -- Postgres-XC |
From: Abbas B. <ga...@us...> - 2011-04-25 17:45:23
|
Project "Postgres-XC". The branch, master has been updated via 7bbb6a36362ac0b9e92191bce988eeaa5dd5b118 (commit) from d7d1c15b38975aa6d88d70bf76c050a7fb887eb7 (commit) - Log ----------------------------------------------------------------- commit 7bbb6a36362ac0b9e92191bce988eeaa5dd5b118 Author: Abbas <abb...@en...> Date: Mon Apr 25 22:44:51 2011 +0500 A few more ORDER BY in portals test case diff --git a/src/test/regress/expected/portals_1.out b/src/test/regress/expected/portals_1.out index 3fa3c82..2fa80ec 100644 --- a/src/test/regress/expected/portals_1.out +++ b/src/test/regress/expected/portals_1.out @@ -978,7 +978,7 @@ FETCH c1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; ERROR: WHERE CURRENT OF clause not yet supported -SELECT f1,f2 FROM uctest; +SELECT f1,f2 FROM uctest ORDER BY 1; ERROR: current transaction is aborted, commands ignored until end of transaction block UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; ERROR: current transaction is aborted, commands ignored until end of transaction block @@ -1011,11 +1011,11 @@ SELECT f1,f2 FROM uctest ORDER BY f1; (3 rows) BEGIN; -DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest FOR UPDATE; +DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest ORDER BY 1 FOR UPDATE; FETCH c1; - f1 | f2 -----+------- - 3 | three + f1 | f2 +----+----- + 1 | one (1 row) UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; @@ -1064,7 +1064,7 @@ SELECT f1,f2 FROM uctest ORDER BY f1; (3 rows) BEGIN; -DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest FOR UPDATE; +DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest ORDER BY 1 FOR UPDATE; FETCH 1 FROM c1; f1 | f2 ----+------- @@ -1094,7 +1094,7 @@ SELECT f1,f2 FROM uctest ORDER BY f1; -- Can update from a self-join, but only if FOR UPDATE says which to use BEGIN; -DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5; +DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 ORDER BY 1; FETCH 1 FROM c1; f1 | f2 ----+----- @@ -1105,7 +1105,7 @@ UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- fail ERROR: WHERE CURRENT OF clause not yet supported ROLLBACK; BEGIN; -DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 FOR UPDATE; +DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 ORDER BY 1 FOR UPDATE; FETCH 1 FROM c1; f1 | f2 ----+----- @@ -1116,7 +1116,7 @@ UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- fail ERROR: WHERE CURRENT OF clause not yet supported ROLLBACK; BEGIN; -DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 FOR SHARE OF a; +DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 ORDER BY 1 FOR SHARE OF a; FETCH 1 FROM c1; f1 | f2 ----+----- @@ -1131,17 +1131,17 @@ ROLLBACK; -- Check various error cases DELETE FROM uctest WHERE CURRENT OF c1; -- fail, no such cursor ERROR: WHERE CURRENT OF clause not yet supported -DECLARE cx CURSOR WITH HOLD FOR SELECT f1,f2 FROM uctest; +DECLARE cx CURSOR WITH HOLD FOR SELECT f1,f2 FROM uctest ORDER BY 1; ERROR: portal "cx" does not exist DELETE FROM uctest WHERE CURRENT OF cx; -- fail, can't use held cursor ERROR: WHERE CURRENT OF clause not yet supported BEGIN; -DECLARE c CURSOR FOR SELECT * FROM tenk2; +DECLARE c CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DELETE FROM uctest WHERE CURRENT OF c; -- fail, cursor on wrong table ERROR: WHERE CURRENT OF clause not yet supported ROLLBACK; BEGIN; -DECLARE c CURSOR FOR SELECT * FROM tenk2 FOR SHARE; +DECLARE c CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2 FOR SHARE; DELETE FROM uctest WHERE CURRENT OF c; -- fail, cursor on wrong table ERROR: WHERE CURRENT OF clause not yet supported ROLLBACK; @@ -1163,7 +1163,7 @@ ERROR: WHERE CURRENT OF clause not yet supported ROLLBACK; -- WHERE CURRENT OF may someday work with views, but today is not that day. -- For now, just make sure it errors out cleanly. -CREATE VIEW ucview AS SELECT f1,f2 FROM uctest; +CREATE VIEW ucview AS SELECT f1,f2 FROM uctest ORDER BY 1; CREATE RULE ucrule AS ON DELETE TO ucview DO INSTEAD DELETE FROM uctest WHERE f1 = OLD.f1; BEGIN; diff --git a/src/test/regress/sql/portals.sql b/src/test/regress/sql/portals.sql index ff0d289..584e015 100644 --- a/src/test/regress/sql/portals.sql +++ b/src/test/regress/sql/portals.sql @@ -355,7 +355,7 @@ BEGIN; DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest; FETCH c1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -SELECT f1,f2 FROM uctest; +SELECT f1,f2 FROM uctest ORDER BY 1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; SELECT f1,f2 FROM uctest ORDER BY 1; -- insensitive cursor should not show effects of updates or deletes @@ -371,7 +371,7 @@ ROLLBACK; SELECT f1,f2 FROM uctest ORDER BY f1; BEGIN; -DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest FOR UPDATE; +DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest ORDER BY 1 FOR UPDATE; FETCH c1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; SELECT f1,f2 FROM uctest ORDER BY f1; @@ -395,7 +395,7 @@ INSERT INTO ucchild values(0, 100, 'hundred'); SELECT f1,f2 FROM uctest ORDER BY f1; BEGIN; -DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest FOR UPDATE; +DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest ORDER BY 1 FOR UPDATE; FETCH 1 FROM c1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; FETCH 1 FROM c1; @@ -408,17 +408,17 @@ SELECT f1,f2 FROM uctest ORDER BY f1; -- Can update from a self-join, but only if FOR UPDATE says which to use BEGIN; -DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5; +DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 ORDER BY 1; FETCH 1 FROM c1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- fail ROLLBACK; BEGIN; -DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 FOR UPDATE; +DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 ORDER BY 1 FOR UPDATE; FETCH 1 FROM c1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- fail ROLLBACK; BEGIN; -DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 FOR SHARE OF a; +DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 ORDER BY 1 FOR SHARE OF a; FETCH 1 FROM c1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; SELECT f1,f2 FROM uctest ORDER BY f1; @@ -427,14 +427,14 @@ ROLLBACK; -- Check various error cases DELETE FROM uctest WHERE CURRENT OF c1; -- fail, no such cursor -DECLARE cx CURSOR WITH HOLD FOR SELECT f1,f2 FROM uctest; +DECLARE cx CURSOR WITH HOLD FOR SELECT f1,f2 FROM uctest ORDER BY 1; DELETE FROM uctest WHERE CURRENT OF cx; -- fail, can't use held cursor BEGIN; -DECLARE c CURSOR FOR SELECT * FROM tenk2; +DECLARE c CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DELETE FROM uctest WHERE CURRENT OF c; -- fail, cursor on wrong table ROLLBACK; BEGIN; -DECLARE c CURSOR FOR SELECT * FROM tenk2 FOR SHARE; +DECLARE c CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2 FOR SHARE; DELETE FROM uctest WHERE CURRENT OF c; -- fail, cursor on wrong table ROLLBACK; BEGIN; @@ -452,7 +452,7 @@ ROLLBACK; -- WHERE CURRENT OF may someday work with views, but today is not that day. -- For now, just make sure it errors out cleanly. -CREATE VIEW ucview AS SELECT f1,f2 FROM uctest; +CREATE VIEW ucview AS SELECT f1,f2 FROM uctest ORDER BY 1; CREATE RULE ucrule AS ON DELETE TO ucview DO INSTEAD DELETE FROM uctest WHERE f1 = OLD.f1; BEGIN; ----------------------------------------------------------------------- Summary of changes: src/test/regress/expected/portals_1.out | 26 +++++++++++++------------- src/test/regress/sql/portals.sql | 20 ++++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) hooks/post-receive -- Postgres-XC |
From: Abbas B. <ga...@us...> - 2011-04-25 17:25:55
|
Project "Postgres-XC". The branch, master has been updated via d7d1c15b38975aa6d88d70bf76c050a7fb887eb7 (commit) from 32db0e37323690b45680e540302d9d8f91e6f102 (commit) - Log ----------------------------------------------------------------- commit d7d1c15b38975aa6d88d70bf76c050a7fb887eb7 Author: Abbas <abb...@en...> Date: Mon Apr 25 22:24:58 2011 +0500 Corrects minor error in expected output of create_misc diff --git a/src/test/regress/output/create_misc_1.source b/src/test/regress/output/create_misc_1.source index 75503b7..3e827fb 100644 --- a/src/test/regress/output/create_misc_1.source +++ b/src/test/regress/output/create_misc_1.source @@ -5,7 +5,7 @@ -- (any resemblance to real life is purely coincidental) -- INSERT INTO tenk2 SELECT * FROM tenk1; -COPY tenk1 FROM '@abs_srcdir@/data/tenk.data'; +COPY tenk2 FROM '@abs_srcdir@/data/tenk.data'; SELECT * INTO TABLE onek2 FROM onek; ERROR: INTO clause not yet supported CREATE TABLE onek2 ( ----------------------------------------------------------------------- Summary of changes: src/test/regress/output/create_misc_1.source | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) hooks/post-receive -- Postgres-XC |
From: Abbas B. <ga...@us...> - 2011-04-25 17:04:51
|
Project "Postgres-XC". The branch, master has been updated via 32db0e37323690b45680e540302d9d8f91e6f102 (commit) from 1c63e1870b95ddad3fdee284a0744f31add39919 (commit) - Log ----------------------------------------------------------------- commit 32db0e37323690b45680e540302d9d8f91e6f102 Author: Abbas <abb...@en...> Date: Mon Apr 25 22:01:54 2011 +0500 This patch fixes bug ID 3237776. Portals test case now passes after a) adding a few ORDER BY. b) adding data in tenk2 table. c) converting temp table and views to permanent ones d) Adding dummy columns to avoid updation to distribution column The output is consistent but is not correct because of the reasons explained in feature request 3291289: 1) WHERE CURRENT OF is not supported 2) XC does not evaluate query of the cursor when it is encountered. 3) Cursors created FOR UPDATE do not behave correctly. 4) Cursors created without specifying SCROLL option default to NO SCROLL. An alternate expected output file has been added. WHERE CURRENT OF is blocked with a decent message. diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 2159a68..bd5e44d 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -1988,6 +1988,12 @@ transformCurrentOfExpr(ParseState *pstate, CurrentOfExpr *cexpr) { int sublevels_up; +#ifdef PGXC + ereport(ERROR, + (errcode(ERRCODE_STATEMENT_TOO_COMPLEX), + (errmsg("WHERE CURRENT OF clause not yet supported")))); +#endif + /* CURRENT OF can only appear at top level of UPDATE/DELETE */ Assert(pstate->p_target_rangetblentry != NULL); cexpr->cvarno = RTERangeTablePosn(pstate, diff --git a/src/test/regress/expected/portals.out b/src/test/regress/expected/portals.out index c837fed..be7348d 100644 --- a/src/test/regress/expected/portals.out +++ b/src/test/regress/expected/portals.out @@ -778,7 +778,7 @@ ERROR: cursor "foo26" does not exist BEGIN; CREATE FUNCTION declares_cursor(text) RETURNS void - AS 'DECLARE c CURSOR FOR SELECT stringu1 FROM tenk1 WHERE stringu1 LIKE $1 ORDER BY stringu1;' + AS 'DECLARE c CURSOR FOR SELECT stringu1 FROM tenk1 WHERE stringu1 LIKE $1;' LANGUAGE SQL; SELECT declares_cursor('AB%'); declares_cursor @@ -904,7 +904,7 @@ COMMIT; -- CREATE TEMP TABLE uctest(f1 int, f2 text); INSERT INTO uctest VALUES (1, 'one'), (2, 'two'), (3, 'three'); -SELECT * FROM uctest ORDER BY f1; +SELECT * FROM uctest; f1 | f2 ----+------- 1 | one @@ -914,7 +914,7 @@ SELECT * FROM uctest ORDER BY f1; -- Check DELETE WHERE CURRENT BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest ORDER BY f1; +DECLARE c1 CURSOR FOR SELECT * FROM uctest; FETCH 2 FROM c1; f1 | f2 ----+----- @@ -923,21 +923,24 @@ FETCH 2 FROM c1; (2 rows) DELETE FROM uctest WHERE CURRENT OF c1; -ERROR: cursor "c1" is not a simply updatable scan of table "uctest" -- should show deletion -SELECT * FROM uctest ORDER BY f1; -ERROR: current transaction is aborted, commands ignored until end of transaction block +SELECT * FROM uctest; + f1 | f2 +----+------- + 1 | one + 3 | three +(2 rows) + -- cursor did not move FETCH ALL FROM c1; -ERROR: current transaction is aborted, commands ignored until end of transaction block + f1 | f2 +----+------- + 3 | three +(1 row) + -- cursor is insensitive MOVE BACKWARD ALL IN c1; -ERROR: current transaction is aborted, commands ignored until end of transaction block FETCH ALL FROM c1; -ERROR: current transaction is aborted, commands ignored until end of transaction block -COMMIT; --- should still see deletion -SELECT * FROM uctest ORDER BY f1; f1 | f2 ----+------- 1 | one @@ -945,6 +948,15 @@ SELECT * FROM uctest ORDER BY f1; 3 | three (3 rows) +COMMIT; +-- should still see deletion +SELECT * FROM uctest; + f1 | f2 +----+------- + 1 | one + 3 | three +(2 rows) + -- Check UPDATE WHERE CURRENT; this time use FOR UPDATE BEGIN; DECLARE c1 CURSOR FOR SELECT * FROM uctest FOR UPDATE; @@ -955,181 +967,159 @@ FETCH c1; (1 row) UPDATE uctest SET f1 = 8 WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; +SELECT * FROM uctest; f1 | f2 ----+------- - 2 | two 3 | three 8 | one -(3 rows) +(2 rows) COMMIT; -SELECT * FROM uctest ORDER BY f1; +SELECT * FROM uctest; f1 | f2 ----+------- - 2 | two 3 | three 8 | one -(3 rows) +(2 rows) -- Check repeated-update and update-then-delete cases BEGIN; DECLARE c1 CURSOR FOR SELECT * FROM uctest; FETCH c1; - f1 | f2 -----+----- - 2 | two + f1 | f2 +----+------- + 3 | three (1 row) UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; SELECT * FROM uctest; f1 | f2 ----+------- - 3 | three 8 | one - 12 | two -(3 rows) + 13 | three +(2 rows) UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY 1; +SELECT * FROM uctest; f1 | f2 ----+------- - 3 | three 8 | one - 22 | two -(3 rows) + 23 | three +(2 rows) -- insensitive cursor should not show effects of updates or deletes FETCH RELATIVE 0 FROM c1; - f1 | f2 -----+----- - 2 | two -(1 row) - -DELETE FROM uctest WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; f1 | f2 ----+------- 3 | three +(1 row) + +DELETE FROM uctest WHERE CURRENT OF c1; +SELECT * FROM uctest; + f1 | f2 +----+----- 8 | one -(2 rows) +(1 row) DELETE FROM uctest WHERE CURRENT OF c1; -- no-op -SELECT * FROM uctest ORDER BY f1; - f1 | f2 -----+------- - 3 | three +SELECT * FROM uctest; + f1 | f2 +----+----- 8 | one -(2 rows) +(1 row) UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- no-op -SELECT * FROM uctest ORDER BY f1; - f1 | f2 -----+------- - 3 | three +SELECT * FROM uctest; + f1 | f2 +----+----- 8 | one -(2 rows) +(1 row) FETCH RELATIVE 0 FROM c1; - f1 | f2 -----+----- - 2 | two + f1 | f2 +----+------- + 3 | three (1 row) ROLLBACK; -SELECT * FROM uctest ORDER BY f1; +SELECT * FROM uctest; f1 | f2 ----+------- - 2 | two 3 | three 8 | one -(3 rows) +(2 rows) BEGIN; DECLARE c1 CURSOR FOR SELECT * FROM uctest FOR UPDATE; FETCH c1; - f1 | f2 -----+----- - 2 | two + f1 | f2 +----+------- + 3 | three (1 row) UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; +SELECT * FROM uctest; f1 | f2 ----+------- - 3 | three 8 | one - 12 | two -(3 rows) + 13 | three +(2 rows) UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; +SELECT * FROM uctest; f1 | f2 ----+------- - 3 | three 8 | one - 22 | two -(3 rows) + 23 | three +(2 rows) DELETE FROM uctest WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; - f1 | f2 -----+------- - 3 | three +SELECT * FROM uctest; + f1 | f2 +----+----- 8 | one -(2 rows) +(1 row) DELETE FROM uctest WHERE CURRENT OF c1; -- no-op -SELECT * FROM uctest ORDER BY f1; - f1 | f2 -----+------- - 3 | three +SELECT * FROM uctest; + f1 | f2 +----+----- 8 | one -(2 rows) +(1 row) UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- no-op -SELECT * FROM uctest ORDER BY f1; - f1 | f2 -----+------- - 3 | three +SELECT * FROM uctest; + f1 | f2 +----+----- 8 | one -(2 rows) +(1 row) --- sensitive cursors can't currently scroll back, so this is an error: FETCH RELATIVE 0 FROM c1; ERROR: cursor can only scan forward HINT: Declare it with SCROLL option to enable backward scan. ROLLBACK; -SELECT * FROM uctest ORDER BY f1; +SELECT * FROM uctest; f1 | f2 ----+------- - 2 | two 3 | three 8 | one -(3 rows) +(2 rows) -- Check inheritance cases CREATE TEMP TABLE ucchild () inherits (uctest); INSERT INTO ucchild values(100, 'hundred'); -SELECT * FROM uctest ORDER BY f1; +SELECT * FROM uctest; f1 | f2 -----+--------- - 2 | two 3 | three 8 | one 100 | hundred -(4 rows) +(3 rows) BEGIN; DECLARE c1 CURSOR FOR SELECT * FROM uctest FOR UPDATE; FETCH 1 FROM c1; - f1 | f2 -----+----- - 2 | two -(1 row) - -UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -FETCH 1 FROM c1; f1 | f2 ----+------- 3 | three @@ -1149,15 +1139,20 @@ FETCH 1 FROM c1; 100 | hundred (1 row) +UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; +FETCH 1 FROM c1; + f1 | f2 +----+---- +(0 rows) + COMMIT; -SELECT * FROM uctest ORDER BY f1; +SELECT * FROM uctest; f1 | f2 -----+--------- - 12 | two 13 | three 18 | one - 100 | hundred -(4 rows) + 110 | hundred +(3 rows) -- Can update from a self-join, but only if FOR UPDATE says which to use BEGIN; @@ -1191,14 +1186,13 @@ FETCH 1 FROM c1; (1 row) UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; +SELECT * FROM uctest; f1 | f2 -----+--------- - 12 | two 13 | three 28 | one - 100 | hundred -(4 rows) + 110 | hundred +(3 rows) ROLLBACK; -- Check various error cases @@ -1240,9 +1234,9 @@ CREATE RULE ucrule AS ON DELETE TO ucview DO INSTEAD BEGIN; DECLARE c1 CURSOR FOR SELECT * FROM ucview; FETCH FROM c1; - f1 | f2 -----+----- - 12 | two + f1 | f2 +----+------- + 13 | three (1 row) DELETE FROM ucview WHERE CURRENT OF c1; -- fail, views not supported diff --git a/src/test/regress/expected/portals.out b/src/test/regress/expected/portals_1.out similarity index 92% copy from src/test/regress/expected/portals.out copy to src/test/regress/expected/portals_1.out index c837fed..3fa3c82 100644 --- a/src/test/regress/expected/portals.out +++ b/src/test/regress/expected/portals_1.out @@ -3,27 +3,27 @@ -- BEGIN; DECLARE foo1 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo2 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo2 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo3 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo4 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo4 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo5 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo6 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo6 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo7 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo8 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo8 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo9 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo10 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo10 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo11 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo12 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo12 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo13 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo14 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo14 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo15 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo16 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo16 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo17 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo18 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo18 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo19 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo20 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo20 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo21 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo22 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo22 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo23 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; FETCH 1 in foo1; unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 @@ -682,15 +682,15 @@ SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors OR name | statement | is_holdable | is_binary | is_scrollable -------+-----------------------------------------------------------------------+-------------+-----------+--------------- foo13 | DECLARE foo13 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; | f | f | t - foo14 | DECLARE foo14 SCROLL CURSOR FOR SELECT * FROM tenk2; | f | f | t + foo14 | DECLARE foo14 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; | f | f | t foo15 | DECLARE foo15 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; | f | f | t - foo16 | DECLARE foo16 SCROLL CURSOR FOR SELECT * FROM tenk2; | f | f | t + foo16 | DECLARE foo16 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; | f | f | t foo17 | DECLARE foo17 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; | f | f | t - foo18 | DECLARE foo18 SCROLL CURSOR FOR SELECT * FROM tenk2; | f | f | t + foo18 | DECLARE foo18 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; | f | f | t foo19 | DECLARE foo19 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; | f | f | t - foo20 | DECLARE foo20 SCROLL CURSOR FOR SELECT * FROM tenk2; | f | f | t + foo20 | DECLARE foo20 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; | f | f | t foo21 | DECLARE foo21 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; | f | f | t - foo22 | DECLARE foo22 SCROLL CURSOR FOR SELECT * FROM tenk2; | f | f | t + foo22 | DECLARE foo22 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; | f | f | t foo23 | DECLARE foo23 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; | f | f | t (11 rows) @@ -724,7 +724,7 @@ SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors; (0 rows) BEGIN; -DECLARE foo25 SCROLL CURSOR WITH HOLD FOR SELECT * FROM tenk2; +DECLARE foo25 SCROLL CURSOR WITH HOLD FOR SELECT * FROM tenk2 ORDER BY unique2; FETCH FROM foo25; unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4 ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+--------- @@ -757,9 +757,9 @@ FETCH ABSOLUTE -1 FROM foo25; (1 row) SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors; - name | statement | is_holdable | is_binary | is_scrollable --------+----------------------------------------------------------------+-------------+-----------+--------------- - foo25 | DECLARE foo25 SCROLL CURSOR WITH HOLD FOR SELECT * FROM tenk2; | t | f | t + name | statement | is_holdable | is_binary | is_scrollable +-------+---------------------------------------------------------------------------------+-------------+-----------+--------------- + foo25 | DECLARE foo25 SCROLL CURSOR WITH HOLD FOR SELECT * FROM tenk2 ORDER BY unique2; | t | f | t (1 row) CLOSE foo25; @@ -812,7 +812,7 @@ ROLLBACK; -- in particular we want to see what happens during commit of a holdable -- cursor -- -create temp table tt1(f1 int); +create table tt1(f1 int); create function count_tt1_v() returns int8 as 'select count(*) from tt1' language sql volatile; create function count_tt1_s() returns int8 as @@ -824,7 +824,7 @@ insert into tt1 values(2); fetch all from c1; count_tt1_v | count_tt1_s -------------+------------- - 2 | 1 + 2 | 2 (1 row) rollback; @@ -837,11 +837,12 @@ delete from tt1; fetch all from c2; count_tt1_v | count_tt1_s -------------+------------- - 2 | 1 + | (1 row) drop function count_tt1_v(); drop function count_tt1_s(); +drop table tt1; -- Create a cursor with the BINARY option and check the pg_cursors view BEGIN; SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors; @@ -854,7 +855,7 @@ DECLARE bc BINARY CURSOR FOR SELECT * FROM tenk1; SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors ORDER BY 1; name | statement | is_holdable | is_binary | is_scrollable ------+----------------------------------------------------------------------+-------------+-----------+--------------- - bc | DECLARE bc BINARY CURSOR FOR SELECT * FROM tenk1; | f | t | t + bc | DECLARE bc BINARY CURSOR FOR SELECT * FROM tenk1; | f | t | f c2 | declare c2 cursor with hold for select count_tt1_v(), count_tt1_s(); | t | f | f (2 rows) @@ -863,12 +864,11 @@ ROLLBACK; -- implement EXECUTE in pg_cursors PREPARE cprep AS SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors; +ERROR: Postgres-XC does not support PREPARE yet +DETAIL: The feature is not currently supported EXECUTE cprep; - name | statement | is_holdable | is_binary | is_scrollable -------+----------------------------------------------------------------------+-------------+-----------+--------------- - c2 | declare c2 cursor with hold for select count_tt1_v(), count_tt1_s(); | t | f | f -(1 row) - +ERROR: Postgres-XC does not support EXECUTE yet +DETAIL: The feature is not currently supported -- test CLOSE ALL; SELECT name FROM pg_cursors ORDER BY 1; name @@ -902,9 +902,9 @@ COMMIT; -- -- Tests for updatable cursors -- -CREATE TEMP TABLE uctest(f1 int, f2 text); -INSERT INTO uctest VALUES (1, 'one'), (2, 'two'), (3, 'three'); -SELECT * FROM uctest ORDER BY f1; +CREATE TABLE uctest(a int, f1 int, f2 text); +INSERT INTO uctest VALUES (11, 1, 'one'), (22, 2, 'two'), (33, 3, 'three'); +SELECT f1,f2 FROM uctest ORDER BY f1; f1 | f2 ----+------- 1 | one @@ -914,7 +914,7 @@ SELECT * FROM uctest ORDER BY f1; -- Check DELETE WHERE CURRENT BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest ORDER BY f1; +DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest ORDER BY f1; FETCH 2 FROM c1; f1 | f2 ----+----- @@ -923,9 +923,9 @@ FETCH 2 FROM c1; (2 rows) DELETE FROM uctest WHERE CURRENT OF c1; -ERROR: cursor "c1" is not a simply updatable scan of table "uctest" +ERROR: WHERE CURRENT OF clause not yet supported -- should show deletion -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; ERROR: current transaction is aborted, commands ignored until end of transaction block -- cursor did not move FETCH ALL FROM c1; @@ -937,7 +937,7 @@ FETCH ALL FROM c1; ERROR: current transaction is aborted, commands ignored until end of transaction block COMMIT; -- should still see deletion -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; f1 | f2 ----+------- 1 | one @@ -947,188 +947,124 @@ SELECT * FROM uctest ORDER BY f1; -- Check UPDATE WHERE CURRENT; this time use FOR UPDATE BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest FOR UPDATE; +DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest FOR UPDATE; FETCH c1; - f1 | f2 -----+----- - 1 | one -(1 row) - -UPDATE uctest SET f1 = 8 WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; f1 | f2 ----+------- - 2 | two 3 | three - 8 | one -(3 rows) +(1 row) +UPDATE uctest SET f1 = 8 WHERE CURRENT OF c1; +ERROR: WHERE CURRENT OF clause not yet supported +SELECT f1,f2 FROM uctest ORDER BY f1; +ERROR: current transaction is aborted, commands ignored until end of transaction block COMMIT; -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; f1 | f2 ----+------- + 1 | one 2 | two 3 | three - 8 | one (3 rows) -- Check repeated-update and update-then-delete cases BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest; +DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest; FETCH c1; - f1 | f2 -----+----- - 2 | two -(1 row) - -UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -SELECT * FROM uctest; f1 | f2 ----+------- 3 | three - 8 | one - 12 | two -(3 rows) +(1 row) UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY 1; - f1 | f2 -----+------- - 3 | three - 8 | one - 22 | two -(3 rows) - +ERROR: WHERE CURRENT OF clause not yet supported +SELECT f1,f2 FROM uctest; +ERROR: current transaction is aborted, commands ignored until end of transaction block +UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; +ERROR: current transaction is aborted, commands ignored until end of transaction block +SELECT f1,f2 FROM uctest ORDER BY 1; +ERROR: current transaction is aborted, commands ignored until end of transaction block -- insensitive cursor should not show effects of updates or deletes FETCH RELATIVE 0 FROM c1; - f1 | f2 -----+----- - 2 | two -(1 row) - +ERROR: current transaction is aborted, commands ignored until end of transaction block DELETE FROM uctest WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; - f1 | f2 -----+------- - 3 | three - 8 | one -(2 rows) - +ERROR: current transaction is aborted, commands ignored until end of transaction block +SELECT f1,f2 FROM uctest ORDER BY f1; +ERROR: current transaction is aborted, commands ignored until end of transaction block DELETE FROM uctest WHERE CURRENT OF c1; -- no-op -SELECT * FROM uctest ORDER BY f1; - f1 | f2 -----+------- - 3 | three - 8 | one -(2 rows) - +ERROR: current transaction is aborted, commands ignored until end of transaction block +SELECT f1,f2 FROM uctest ORDER BY f1; +ERROR: current transaction is aborted, commands ignored until end of transaction block UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- no-op -SELECT * FROM uctest ORDER BY f1; - f1 | f2 -----+------- - 3 | three - 8 | one -(2 rows) - +ERROR: current transaction is aborted, commands ignored until end of transaction block +SELECT f1,f2 FROM uctest ORDER BY f1; +ERROR: current transaction is aborted, commands ignored until end of transaction block FETCH RELATIVE 0 FROM c1; - f1 | f2 -----+----- - 2 | two -(1 row) - +ERROR: current transaction is aborted, commands ignored until end of transaction block ROLLBACK; -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; f1 | f2 ----+------- + 1 | one 2 | two 3 | three - 8 | one (3 rows) BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest FOR UPDATE; +DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest FOR UPDATE; FETCH c1; - f1 | f2 -----+----- - 2 | two -(1 row) - -UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; f1 | f2 ----+------- 3 | three - 8 | one - 12 | two -(3 rows) +(1 row) UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; - f1 | f2 -----+------- - 3 | three - 8 | one - 22 | two -(3 rows) - +ERROR: WHERE CURRENT OF clause not yet supported +SELECT f1,f2 FROM uctest ORDER BY f1; +ERROR: current transaction is aborted, commands ignored until end of transaction block +UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; +ERROR: current transaction is aborted, commands ignored until end of transaction block +SELECT f1,f2 FROM uctest ORDER BY f1; +ERROR: current transaction is aborted, commands ignored until end of transaction block DELETE FROM uctest WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; - f1 | f2 -----+------- - 3 | three - 8 | one -(2 rows) - +ERROR: current transaction is aborted, commands ignored until end of transaction block +SELECT f1,f2 FROM uctest ORDER BY f1; +ERROR: current transaction is aborted, commands ignored until end of transaction block DELETE FROM uctest WHERE CURRENT OF c1; -- no-op -SELECT * FROM uctest ORDER BY f1; - f1 | f2 -----+------- - 3 | three - 8 | one -(2 rows) - +ERROR: current transaction is aborted, commands ignored until end of transaction block +SELECT f1,f2 FROM uctest ORDER BY f1; +ERROR: current transaction is aborted, commands ignored until end of transaction block UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- no-op -SELECT * FROM uctest ORDER BY f1; - f1 | f2 -----+------- - 3 | three - 8 | one -(2 rows) - +ERROR: current transaction is aborted, commands ignored until end of transaction block +SELECT f1,f2 FROM uctest ORDER BY f1; +ERROR: current transaction is aborted, commands ignored until end of transaction block --- sensitive cursors can't currently scroll back, so this is an error: FETCH RELATIVE 0 FROM c1; -ERROR: cursor can only scan forward -HINT: Declare it with SCROLL option to enable backward scan. +ERROR: current transaction is aborted, commands ignored until end of transaction block ROLLBACK; -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; f1 | f2 ----+------- + 1 | one 2 | two 3 | three - 8 | one (3 rows) +DELETE FROM uctest WHERE f1 = 2; +UPDATE uctest SET f1 = 8 WHERE f1=1; -- Check inheritance cases -CREATE TEMP TABLE ucchild () inherits (uctest); -INSERT INTO ucchild values(100, 'hundred'); -SELECT * FROM uctest ORDER BY f1; +CREATE TABLE ucchild () inherits (uctest); +INSERT INTO ucchild values(0, 100, 'hundred'); +SELECT f1,f2 FROM uctest ORDER BY f1; f1 | f2 -----+--------- - 2 | two 3 | three 8 | one 100 | hundred -(4 rows) +(3 rows) BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest FOR UPDATE; -FETCH 1 FROM c1; - f1 | f2 -----+----- - 2 | two -(1 row) - -UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; +DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest FOR UPDATE; FETCH 1 FROM c1; f1 | f2 ----+------- @@ -1136,130 +1072,127 @@ FETCH 1 FROM c1; (1 row) UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; +ERROR: WHERE CURRENT OF clause not yet supported FETCH 1 FROM c1; - f1 | f2 -----+----- - 8 | one -(1 row) - +ERROR: current transaction is aborted, commands ignored until end of transaction block UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; +ERROR: current transaction is aborted, commands ignored until end of transaction block FETCH 1 FROM c1; - f1 | f2 ------+--------- - 100 | hundred -(1 row) - +ERROR: current transaction is aborted, commands ignored until end of transaction block +UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; +ERROR: current transaction is aborted, commands ignored until end of transaction block +FETCH 1 FROM c1; +ERROR: current transaction is aborted, commands ignored until end of transaction block COMMIT; -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; f1 | f2 -----+--------- - 12 | two - 13 | three - 18 | one + 3 | three + 8 | one 100 | hundred -(4 rows) +(3 rows) -- Can update from a self-join, but only if FOR UPDATE says which to use BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5; +DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5; FETCH 1 FROM c1; - f1 | f2 | f1 | f2 -----+-----+----+------- - 18 | one | 13 | three + f1 | f2 +----+----- + 8 | one (1 row) UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- fail -ERROR: cursor "c1" is not a simply updatable scan of table "uctest" +ERROR: WHERE CURRENT OF clause not yet supported ROLLBACK; BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 FOR UPDATE; +DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 FOR UPDATE; FETCH 1 FROM c1; - f1 | f2 | f1 | f2 -----+-----+----+------- - 18 | one | 13 | three + f1 | f2 +----+----- + 8 | one (1 row) UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- fail -ERROR: cursor "c1" has multiple FOR UPDATE/SHARE references to table "uctest" +ERROR: WHERE CURRENT OF clause not yet supported ROLLBACK; BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 FOR SHARE OF a; +DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 FOR SHARE OF a; FETCH 1 FROM c1; - f1 | f2 | f1 | f2 -----+-----+----+------- - 18 | one | 13 | three + f1 | f2 +----+----- + 8 | one (1 row) UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; - f1 | f2 ------+--------- - 12 | two - 13 | three - 28 | one - 100 | hundred -(4 rows) - +ERROR: WHERE CURRENT OF clause not yet supported +SELECT f1,f2 FROM uctest ORDER BY f1; +ERROR: current transaction is aborted, commands ignored until end of transaction block ROLLBACK; -- Check various error cases DELETE FROM uctest WHERE CURRENT OF c1; -- fail, no such cursor -ERROR: cursor "c1" does not exist -DECLARE cx CURSOR WITH HOLD FOR SELECT * FROM uctest; +ERROR: WHERE CURRENT OF clause not yet supported +DECLARE cx CURSOR WITH HOLD FOR SELECT f1,f2 FROM uctest; +ERROR: portal "cx" does not exist DELETE FROM uctest WHERE CURRENT OF cx; -- fail, can't use held cursor -ERROR: cursor "cx" is held from a previous transaction +ERROR: WHERE CURRENT OF clause not yet supported BEGIN; DECLARE c CURSOR FOR SELECT * FROM tenk2; DELETE FROM uctest WHERE CURRENT OF c; -- fail, cursor on wrong table -ERROR: cursor "c" is not a simply updatable scan of table "uctest" +ERROR: WHERE CURRENT OF clause not yet supported ROLLBACK; BEGIN; DECLARE c CURSOR FOR SELECT * FROM tenk2 FOR SHARE; DELETE FROM uctest WHERE CURRENT OF c; -- fail, cursor on wrong table -ERROR: cursor "c" does not have a FOR UPDATE/SHARE reference to table "uctest" +ERROR: WHERE CURRENT OF clause not yet supported ROLLBACK; BEGIN; DECLARE c CURSOR FOR SELECT * FROM tenk1 JOIN tenk2 USING (unique1); DELETE FROM tenk1 WHERE CURRENT OF c; -- fail, cursor is on a join -ERROR: cursor "c" is not a simply updatable scan of table "tenk1" +ERROR: WHERE CURRENT OF clause not yet supported ROLLBACK; BEGIN; DECLARE c CURSOR FOR SELECT f1,count(*) FROM uctest GROUP BY f1; +ERROR: GROUP BY clause is not yet supported DELETE FROM uctest WHERE CURRENT OF c; -- fail, cursor is on aggregation -ERROR: cursor "c" is not a simply updatable scan of table "uctest" +ERROR: current transaction is aborted, commands ignored until end of transaction block ROLLBACK; BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest; +DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest; DELETE FROM uctest WHERE CURRENT OF c1; -- fail, no current row -ERROR: cursor "c1" is not positioned on a row +ERROR: WHERE CURRENT OF clause not yet supported ROLLBACK; -- WHERE CURRENT OF may someday work with views, but today is not that day. -- For now, just make sure it errors out cleanly. -CREATE TEMP VIEW ucview AS SELECT * FROM uctest; +CREATE VIEW ucview AS SELECT f1,f2 FROM uctest; CREATE RULE ucrule AS ON DELETE TO ucview DO INSTEAD DELETE FROM uctest WHERE f1 = OLD.f1; BEGIN; DECLARE c1 CURSOR FOR SELECT * FROM ucview; FETCH FROM c1; - f1 | f2 -----+----- - 12 | two + f1 | f2 +----+------- + 3 | three (1 row) DELETE FROM ucview WHERE CURRENT OF c1; -- fail, views not supported -ERROR: WHERE CURRENT OF on a view is not implemented +ERROR: WHERE CURRENT OF clause not yet supported ROLLBACK; -- Make sure snapshot management works okay, per bug report in -- 235...@ma... BEGIN; SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; -CREATE TABLE cursor (a int); -INSERT INTO cursor VALUES (1); +CREATE TABLE cursor (a int, b int); +INSERT INTO cursor VALUES (1, 0); DECLARE c1 NO SCROLL CURSOR FOR SELECT * FROM cursor FOR UPDATE; -UPDATE cursor SET a = 2; +UPDATE cursor SET b = 2; FETCH ALL FROM c1; - a ---- -(0 rows) + a | b +---+--- + 1 | 2 +(1 row) COMMIT; DROP TABLE cursor; +DROP VIEW ucview; +DROP TABLE ucchild; +DROP TABLE uctest; diff --git a/src/test/regress/input/create_misc.source b/src/test/regress/input/create_misc.source index 30c5ade..882df6a 100644 --- a/src/test/regress/input/create_misc.source +++ b/src/test/regress/input/create_misc.source @@ -7,6 +7,7 @@ -- INSERT INTO tenk2 SELECT * FROM tenk1; +COPY tenk2 FROM '@abs_srcdir@/data/tenk.data'; SELECT * INTO TABLE onek2 FROM onek; diff --git a/src/test/regress/output/create_misc_1.source b/src/test/regress/output/create_misc_1.source index 53fbf2e..75503b7 100644 --- a/src/test/regress/output/create_misc_1.source +++ b/src/test/regress/output/create_misc_1.source @@ -5,6 +5,7 @@ -- (any resemblance to real life is purely coincidental) -- INSERT INTO tenk2 SELECT * FROM tenk1; +COPY tenk1 FROM '@abs_srcdir@/data/tenk.data'; SELECT * INTO TABLE onek2 FROM onek; ERROR: INTO clause not yet supported CREATE TABLE onek2 ( diff --git a/src/test/regress/sql/portals.sql b/src/test/regress/sql/portals.sql index a6c24f7..ff0d289 100644 --- a/src/test/regress/sql/portals.sql +++ b/src/test/regress/sql/portals.sql @@ -6,47 +6,47 @@ BEGIN; DECLARE foo1 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo2 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo2 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo3 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo4 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo4 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo5 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo6 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo6 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo7 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo8 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo8 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo9 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo10 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo10 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo11 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo12 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo12 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo13 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo14 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo14 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo15 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo16 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo16 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo17 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo18 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo18 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo19 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo20 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo20 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo21 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; -DECLARE foo22 SCROLL CURSOR FOR SELECT * FROM tenk2; +DECLARE foo22 SCROLL CURSOR FOR SELECT * FROM tenk2 ORDER BY unique2; DECLARE foo23 SCROLL CURSOR FOR SELECT * FROM tenk1 ORDER BY unique2; @@ -199,7 +199,7 @@ SELECT name, statement, is_holdable, is_binary, is_scrollable FROM pg_cursors; BEGIN; -DECLARE foo25 SCROLL CURSOR WITH HOLD FOR SELECT * FROM tenk2; +DECLARE foo25 SCROLL CURSOR WITH HOLD FOR SELECT * FROM tenk2 ORDER BY unique2; FETCH FROM foo25; @@ -253,7 +253,7 @@ ROLLBACK; -- cursor -- -create temp table tt1(f1 int); +create table tt1(f1 int); create function count_tt1_v() returns int8 as 'select count(*) from tt1' language sql volatile; @@ -290,6 +290,7 @@ fetch all from c2; drop function count_tt1_v(); drop function count_tt1_s(); +drop table tt1; -- Create a cursor with the BINARY option and check the pg_cursors view BEGIN; @@ -320,17 +321,17 @@ COMMIT; -- Tests for updatable cursors -- -CREATE TEMP TABLE uctest(f1 int, f2 text); -INSERT INTO uctest VALUES (1, 'one'), (2, 'two'), (3, 'three'); -SELECT * FROM uctest ORDER BY f1; +CREATE TABLE uctest(a int, f1 int, f2 text); +INSERT INTO uctest VALUES (11, 1, 'one'), (22, 2, 'two'), (33, 3, 'three'); +SELECT f1,f2 FROM uctest ORDER BY f1; -- Check DELETE WHERE CURRENT BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest ORDER BY f1; +DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest ORDER BY f1; FETCH 2 FROM c1; DELETE FROM uctest WHERE CURRENT OF c1; -- should show deletion -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; -- cursor did not move FETCH ALL FROM c1; -- cursor is insensitive @@ -338,62 +339,63 @@ MOVE BACKWARD ALL IN c1; FETCH ALL FROM c1; COMMIT; -- should still see deletion -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; -- Check UPDATE WHERE CURRENT; this time use FOR UPDATE BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest FOR UPDATE; +DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest FOR UPDATE; FETCH c1; UPDATE uctest SET f1 = 8 WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; COMMIT; -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; -- Check repeated-update and update-then-delete cases BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest; +DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest; FETCH c1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -SELECT * FROM uctest; +SELECT f1,f2 FROM uctest; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY 1; +SELECT f1,f2 FROM uctest ORDER BY 1; -- insensitive cursor should not show effects of updates or deletes FETCH RELATIVE 0 FROM c1; DELETE FROM uctest WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; DELETE FROM uctest WHERE CURRENT OF c1; -- no-op -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- no-op -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; FETCH RELATIVE 0 FROM c1; ROLLBACK; -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest FOR UPDATE; +DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest FOR UPDATE; FETCH c1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; DELETE FROM uctest WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; DELETE FROM uctest WHERE CURRENT OF c1; -- no-op -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- no-op -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; --- sensitive cursors can't currently scroll back, so this is an error: FETCH RELATIVE 0 FROM c1; ROLLBACK; -SELECT * FROM uctest ORDER BY f1; - +SELECT f1,f2 FROM uctest ORDER BY f1; +DELETE FROM uctest WHERE f1 = 2; +UPDATE uctest SET f1 = 8 WHERE f1=1; -- Check inheritance cases -CREATE TEMP TABLE ucchild () inherits (uctest); -INSERT INTO ucchild values(100, 'hundred'); -SELECT * FROM uctest ORDER BY f1; +CREATE TABLE ucchild () inherits (uctest); +INSERT INTO ucchild values(0, 100, 'hundred'); +SELECT f1,f2 FROM uctest ORDER BY f1; BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest FOR UPDATE; +DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest FOR UPDATE; FETCH 1 FROM c1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; FETCH 1 FROM c1; @@ -402,30 +404,30 @@ FETCH 1 FROM c1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; FETCH 1 FROM c1; COMMIT; -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; -- Can update from a self-join, but only if FOR UPDATE says which to use BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5; +DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5; FETCH 1 FROM c1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- fail ROLLBACK; BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 FOR UPDATE; +DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 FOR UPDATE; FETCH 1 FROM c1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -- fail ROLLBACK; BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 FOR SHARE OF a; +DECLARE c1 CURSOR FOR SELECT a.f1,a.f2 FROM uctest a, uctest b WHERE a.f1 = b.f1 + 5 FOR SHARE OF a; FETCH 1 FROM c1; UPDATE uctest SET f1 = f1 + 10 WHERE CURRENT OF c1; -SELECT * FROM uctest ORDER BY f1; +SELECT f1,f2 FROM uctest ORDER BY f1; ROLLBACK; -- Check various error cases DELETE FROM uctest WHERE CURRENT OF c1; -- fail, no such cursor -DECLARE cx CURSOR WITH HOLD FOR SELECT * FROM uctest; +DECLARE cx CURSOR WITH HOLD FOR SELECT f1,f2 FROM uctest; DELETE FROM uctest WHERE CURRENT OF cx; -- fail, can't use held cursor BEGIN; DECLARE c CURSOR FOR SELECT * FROM tenk2; @@ -444,13 +446,13 @@ DECLARE c CURSOR FOR SELECT f1,count(*) FROM uctest GROUP BY f1; DELETE FROM uctest WHERE CURRENT OF c; -- fail, cursor is on aggregation ROLLBACK; BEGIN; -DECLARE c1 CURSOR FOR SELECT * FROM uctest; +DECLARE c1 CURSOR FOR SELECT f1,f2 FROM uctest; DELETE FROM uctest WHERE CURRENT OF c1; -- fail, no current row ROLLBACK; -- WHERE CURRENT OF may someday work with views, but today is not that day. -- For now, just make sure it errors out cleanly. -CREATE TEMP VIEW ucview AS SELECT * FROM uctest; +CREATE VIEW ucview AS SELECT f1,f2 FROM uctest; CREATE RULE ucrule AS ON DELETE TO ucview DO INSTEAD DELETE FROM uctest WHERE f1 = OLD.f1; BEGIN; @@ -463,10 +465,15 @@ ROLLBACK; -- 235...@ma... BEGIN; SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; -CREATE TABLE cursor (a int); -INSERT INTO cursor VALUES (1); +CREATE TABLE cursor (a int, b int); +INSERT INTO cursor VALUES (1, 0); DECLARE c1 NO SCROLL CURSOR FOR SELECT * FROM cursor FOR UPDATE; -UPDATE cursor SET a = 2; +UPDATE cursor SET b = 2; FETCH ALL FROM c1; COMMIT; DROP TABLE cursor; + +DROP VIEW ucview; +DROP TABLE ucchild; +DROP TABLE uctest; + ----------------------------------------------------------------------- Summary of changes: src/backend/parser/parse_expr.c | 6 + src/test/regress/expected/portals.out | 198 +++++------ .../expected/{portals.out => portals_1.out} | 365 ++++++++------------ src/test/regress/input/create_misc.source | 1 + src/test/regress/output/create_misc_1.source | 1 + src/test/regress/sql/portals.sql | 111 ++++--- 6 files changed, 312 insertions(+), 370 deletions(-) copy src/test/regress/expected/{portals.out => portals_1.out} (92%) hooks/post-receive -- Postgres-XC |
From: Abbas B. <ga...@us...> - 2011-04-22 03:37:31
|
Project "Postgres-XC". The branch, master has been updated via 1c63e1870b95ddad3fdee284a0744f31add39919 (commit) from 43edae4ce7bc8a2533e49778dbb567829ec45e4e (commit) - Log ----------------------------------------------------------------- commit 1c63e1870b95ddad3fdee284a0744f31add39919 Author: Abbas <abb...@en...> Date: Fri Apr 22 08:25:26 2011 +0500 This patch fixes memory leak problems. Each call to pgxc_get_all_transaction_nodes must be accompanied by a call to pfree_pgxc_all_handles. This patch also corrects a logic mistake in CommitTransaction. diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index 2dbc860..86b903b 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -2041,7 +2041,12 @@ CommitTransaction(bool contact_gtm) * This is called only if it is not necessary to prepare the nodes. */ if (IS_PGXC_COORDINATOR && !IsConnFromCoord() && (!PreparePGXCNodes || IsHoldableCursor) && contact_gtm) - PGXCNodeCommit(!IsHoldableCursor); + { + if (IsHoldableCursor) + PGXCNodeCommit(!PreparePGXCNodes); + else + PGXCNodeCommit(true); + } #endif /* Prevent cancel/die interrupt while cleaning up */ diff --git a/src/backend/pgxc/pool/execRemote.c b/src/backend/pgxc/pool/execRemote.c index 2fc6cbd..c04a98c 100644 --- a/src/backend/pgxc/pool/execRemote.c +++ b/src/backend/pgxc/pool/execRemote.c @@ -1796,6 +1796,9 @@ finish: if (!autocommit) stat_transaction(pgxc_connections->dn_conn_count); + /* Clean up connections */ + pfree_pgxc_all_handles(pgxc_connections); + return res; } @@ -1875,6 +1878,9 @@ finish: is_ddl = false; clear_write_node_list(); + /* Clean up connections */ + pfree_pgxc_all_handles(pgxc_connections); + if (res != 0) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), @@ -4619,6 +4625,9 @@ PGXCNodeIsImplicit2PC(bool *prepare_local_coord) int co_conn_count = pgxc_handles->co_conn_count; int total_count = pgxc_handles->co_conn_count + pgxc_handles->dn_conn_count; + /* Clean up connections */ + pfree_pgxc_all_handles(pgxc_handles); + /* * Prepare Local Coord only if DDL is involved. * Even 1Co/1Dn cluster needs 2PC as more than 1 node is involved. @@ -4676,6 +4685,9 @@ PGXCNodeGetNodeList(PGXC_NodeId **datanodes, */ if (!PersistentConnections) release_handles(); + + /* Clean up connections */ + pfree_pgxc_all_handles(pgxc_connections); } /* ----------------------------------------------------------------------- Summary of changes: src/backend/access/transam/xact.c | 7 ++++++- src/backend/pgxc/pool/execRemote.c | 12 ++++++++++++ 2 files changed, 18 insertions(+), 1 deletions(-) hooks/post-receive -- Postgres-XC |
From: Abbas B. <ga...@us...> - 2011-04-21 16:34:10
|
Project "Postgres-XC". The branch, master has been updated via 43edae4ce7bc8a2533e49778dbb567829ec45e4e (commit) from 90c5e49fd6b6469d6e878570ce9287e1b0978723 (commit) - Log ----------------------------------------------------------------- commit 43edae4ce7bc8a2533e49778dbb567829ec45e4e Author: Abbas <abb...@en...> Date: Thu Apr 21 19:12:29 2011 +0500 This patch fixes a problem with cursors created WITH HOLD option. In this case the CommitTransaction function was sending a BEGIN to data nodes but was not sending the assocaited COMMIT This was causing a test case in portals.sql to fail. diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c index ed6271e..2dbc860 100644 --- a/src/backend/access/transam/xact.c +++ b/src/backend/access/transam/xact.c @@ -1922,6 +1922,7 @@ CommitTransaction(bool contact_gtm) #ifdef PGXC bool PrepareLocalCoord = false; bool PreparePGXCNodes = false; + bool IsHoldableCursor = false; char implicitgid[256]; TransactionId xid = InvalidTransactionId; @@ -2005,6 +2006,8 @@ CommitTransaction(bool contact_gtm) */ if (!CommitHoldablePortals()) break; + else + IsHoldableCursor = true; } /* Now we can shut down the deferred-trigger manager */ @@ -2037,8 +2040,8 @@ CommitTransaction(bool contact_gtm) * * This is called only if it is not necessary to prepare the nodes. */ - if (IS_PGXC_COORDINATOR && !IsConnFromCoord() && !PreparePGXCNodes && contact_gtm) - PGXCNodeCommit(); + if (IS_PGXC_COORDINATOR && !IsConnFromCoord() && (!PreparePGXCNodes || IsHoldableCursor) && contact_gtm) + PGXCNodeCommit(!IsHoldableCursor); #endif /* Prevent cancel/die interrupt while cleaning up */ diff --git a/src/backend/pgxc/pool/execRemote.c b/src/backend/pgxc/pool/execRemote.c index 53f2c1c..2fc6cbd 100644 --- a/src/backend/pgxc/pool/execRemote.c +++ b/src/backend/pgxc/pool/execRemote.c @@ -2195,7 +2195,7 @@ pgxc_node_rollback_prepared(GlobalTransactionId gxid, GlobalTransactionId prepar * So only send a commit to the involved nodes. */ void -PGXCNodeCommit(void) +PGXCNodeCommit(bool bReleaseHandles) { int res = 0; int tran_count; @@ -2218,7 +2218,7 @@ finish: /* In autocommit mode statistics is collected in DataNodeExec */ if (!autocommit) stat_transaction(tran_count); - if (!PersistentConnections) + if (!PersistentConnections && bReleaseHandles) release_handles(); autocommit = true; is_ddl = false; diff --git a/src/include/pgxc/execRemote.h b/src/include/pgxc/execRemote.h index 1113468..c2cd922 100644 --- a/src/include/pgxc/execRemote.h +++ b/src/include/pgxc/execRemote.h @@ -117,7 +117,7 @@ typedef struct RemoteQueryState /* Multinode Executor */ extern void PGXCNodeBegin(void); -extern void PGXCNodeCommit(void); +extern void PGXCNodeCommit(bool bReleaseHandles); extern int PGXCNodeRollback(void); extern bool PGXCNodePrepare(char *gid); extern bool PGXCNodeRollbackPrepared(char *gid); ----------------------------------------------------------------------- Summary of changes: src/backend/access/transam/xact.c | 7 +++++-- src/backend/pgxc/pool/execRemote.c | 4 ++-- src/include/pgxc/execRemote.h | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-20 02:42:39
|
Project "Postgres-XC". The branch, master has been updated via 90c5e49fd6b6469d6e878570ce9287e1b0978723 (commit) from 443c6a8362539d4beee8206012971cf8210502de (commit) - Log ----------------------------------------------------------------- commit 90c5e49fd6b6469d6e878570ce9287e1b0978723 Author: Michael P <mic...@us...> Date: Wed Apr 20 11:38:33 2011 +0900 Fix for bug 3273585: error messages when preparing transaction Last commit contained a partial fix. This one completes it. diff --git a/src/backend/pgxc/pool/execRemote.c b/src/backend/pgxc/pool/execRemote.c index 3f6d751..53f2c1c 100644 --- a/src/backend/pgxc/pool/execRemote.c +++ b/src/backend/pgxc/pool/execRemote.c @@ -2019,7 +2019,8 @@ finish: if (res_gtm < 0) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Could not get GID data from GTM"))); + errmsg("prepared transaction with identifier \"%s\" does not exist", + gid))); if (res != 0) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), @@ -2142,7 +2143,8 @@ finish: if (res_gtm < 0) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), - errmsg("Could not get GID data from GTM"))); + errmsg("prepared transaction with identifier \"%s\" does not exist", + gid))); if (res != 0) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), ----------------------------------------------------------------------- Summary of changes: src/backend/pgxc/pool/execRemote.c | 6 ++++-- 1 files changed, 4 insertions(+), 2 deletions(-) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-20 02:27:58
|
Project "Postgres-XC". The branch, master has been updated via 443c6a8362539d4beee8206012971cf8210502de (commit) from 2610315b335ac97ed88ff532c58239c3a8685206 (commit) - Log ----------------------------------------------------------------- commit 443c6a8362539d4beee8206012971cf8210502de Author: Michael P <mic...@us...> Date: Wed Apr 20 11:18:38 2011 +0900 Fix for bug 3289281: DROP TABLE in prepared transactions In a cluster configuration using a single coordinator, it happened that a transaction involving DDL was not prepared on the single Coordinator but directly committed. This patch fixes this issue by also taking into account special handling such as transactions using only view or sequence DDLs. This commit contains at the same time a fix for bug 3273585. diff --git a/src/backend/pgxc/pool/execRemote.c b/src/backend/pgxc/pool/execRemote.c index 06c971e..3f6d751 100644 --- a/src/backend/pgxc/pool/execRemote.c +++ b/src/backend/pgxc/pool/execRemote.c @@ -49,6 +49,7 @@ #define PRIMARY_NODE_WRITEAHEAD 1024 * 1024 static bool autocommit = true; +static is_ddl = false; static bool implicit_force_autocommit = false; static PGXCNodeHandle **write_node_list = NULL; static int write_node_count = 0; @@ -1565,7 +1566,7 @@ PGXCNodePrepare(char *gid) pgxc_connections = pgxc_get_all_transaction_nodes(HANDLE_DEFAULT); /* DDL involved in transaction, so make a local prepare too */ - if (pgxc_connections->co_conn_count != 0) + if (is_ddl) local_operation = true; /* @@ -1580,9 +1581,9 @@ PGXCNodePrepare(char *gid) * If we do not have open transactions we have nothing to prepare just * report success */ - if (tran_count == 0) + if (tran_count == 0 && !is_ddl) { - elog(WARNING, "Nothing to PREPARE on Datanodes and Coordinators, gid is not used"); + elog(DEBUG1, "Nothing to PREPARE on Datanodes and Coordinators, gid is not used"); goto finish; } @@ -1600,6 +1601,7 @@ finish: if (!PersistentConnections) release_handles(); autocommit = true; + is_ddl = false; clear_write_node_list(); /* Clean up connections */ @@ -1658,12 +1660,27 @@ pgxc_node_prepare(PGXCNodeAllHandles *pgxc_handles, char *gid) * Don't forget to add in the list of Coordinators the coordinator we are on * if a DDL is involved in the transaction. * This one also is being prepared ! + * + * Take also into account the case of a cluster with a single Coordinator + * for a transaction that used DDL. */ if (co_conn_count == 0) real_co_conn_count = co_conn_count; else real_co_conn_count = co_conn_count + 1; + /* + * This is the case of a single Coordinator + * involved in a transaction using DDL. + */ + if (is_ddl && co_conn_count == 0) + { + Assert(NumCoords == 1); + real_co_conn_count = 1; + coordinators = (PGXC_NodeId *) palloc(sizeof(PGXC_NodeId)); + coordinators[0] = PGXCNodeId; + } + result = StartPreparedTranGTM(gxid, gid, dn_conn_count, datanodes, real_co_conn_count, coordinators); @@ -1855,6 +1872,7 @@ finish: if (!PersistentConnections && res == 0) release_handles(); autocommit = true; + is_ddl = false; clear_write_node_list(); if (res != 0) @@ -1987,6 +2005,7 @@ finish: if (!PersistentConnections) release_handles(); autocommit = true; + is_ddl = false; clear_write_node_list(); /* Free node list taken from GTM */ @@ -2109,6 +2128,7 @@ finish: if (!PersistentConnections) release_handles(); autocommit = true; + is_ddl = false; clear_write_node_list(); /* Free node list taken from GTM */ @@ -2199,6 +2219,7 @@ finish: if (!PersistentConnections) release_handles(); autocommit = true; + is_ddl = false; clear_write_node_list(); /* Clean up connections */ @@ -2267,6 +2288,7 @@ finish: if (!PersistentConnections) release_handles(); autocommit = true; + is_ddl = false; clear_write_node_list(); /* Clean up connections */ @@ -4121,6 +4143,9 @@ ExecRemoteUtility(RemoteQuery *node) ExecDirectType exec_direct_type = node->exec_direct_type; int i; + if (!force_autocommit) + is_ddl = true; + implicit_force_autocommit = force_autocommit; remotestate = CreateResponseCombiner(0, node->combine_type); @@ -4590,9 +4615,13 @@ PGXCNodeIsImplicit2PC(bool *prepare_local_coord) { PGXCNodeAllHandles *pgxc_handles = pgxc_get_all_transaction_nodes(HANDLE_DEFAULT); int co_conn_count = pgxc_handles->co_conn_count; + int total_count = pgxc_handles->co_conn_count + pgxc_handles->dn_conn_count; - /* Prepare Local Coord only if DDL is involved on multiple nodes */ - *prepare_local_coord = co_conn_count > 0; + /* + * Prepare Local Coord only if DDL is involved. + * Even 1Co/1Dn cluster needs 2PC as more than 1 node is involved. + */ + *prepare_local_coord = is_ddl && total_count != 0; /* * In case of an autocommit or forced autocommit transaction, 2PC is not involved @@ -4600,6 +4629,7 @@ PGXCNodeIsImplicit2PC(bool *prepare_local_coord) */ if (implicit_force_autocommit) { + *prepare_local_coord = false; implicit_force_autocommit = false; return false; } @@ -4608,7 +4638,7 @@ PGXCNodeIsImplicit2PC(bool *prepare_local_coord) * 2PC is necessary at other Nodes if one Datanode or one Coordinator * other than the local one has been involved in a write operation. */ - return (write_node_count > 1 || co_conn_count > 0); + return (write_node_count > 1 || co_conn_count > 0 || total_count > 0); } /* diff --git a/src/backend/pgxc/pool/pgxcnode.c b/src/backend/pgxc/pool/pgxcnode.c index d7230b0..a0b8da4 100644 --- a/src/backend/pgxc/pool/pgxcnode.c +++ b/src/backend/pgxc/pool/pgxcnode.c @@ -1740,16 +1740,12 @@ collect_pgxcnode_numbers(int conn_count, PGXCNodeHandle **connections, char clie pgxcnodes = (PGXC_NodeId *) palloc(conn_count * sizeof(PGXC_NodeId)); if (!pgxcnodes) - { ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); - } for (i = 0; i < conn_count; i++) - { pgxcnodes[i] = connections[i]->nodenum; - } /* Save here the Coordinator number where we are */ if (client_conn_type == REMOTE_CONN_COORD) ----------------------------------------------------------------------- Summary of changes: src/backend/pgxc/pool/execRemote.c | 42 ++++++++++++++++++++++++++++++----- src/backend/pgxc/pool/pgxcnode.c | 4 --- 2 files changed, 36 insertions(+), 10 deletions(-) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-19 06:21:57
|
Project "Postgres-XC". The branch, master has been updated via 2610315b335ac97ed88ff532c58239c3a8685206 (commit) from e12ca2d640d6c9d09aefeb05bbce1fba01e9549a (commit) - Log ----------------------------------------------------------------- commit 2610315b335ac97ed88ff532c58239c3a8685206 Author: Michael P <mic...@us...> Date: Tue Apr 19 15:17:28 2011 +0900 Fix for regression test with Due to Postgres-XC restrictions (TEMP tables), this output is correct. diff --git a/src/test/regress/expected/with_1.out b/src/test/regress/expected/with_1.out new file mode 100644 index 0000000..5ae3440 --- /dev/null +++ b/src/test/regress/expected/with_1.out @@ -0,0 +1,879 @@ +-- +-- Tests for common table expressions (WITH query, ... SELECT ...) +-- +-- Basic WITH +WITH q1(x,y) AS (SELECT 1,2) +SELECT * FROM q1, q1 AS q2; + x | y | x | y +---+---+---+--- + 1 | 2 | 1 | 2 +(1 row) + +-- Multiple uses are evaluated only once +SELECT count(*) FROM ( + WITH q1(x) AS (SELECT random() FROM generate_series(1, 5)) + SELECT * FROM q1 + UNION + SELECT * FROM q1 +) ss; + count +------- + 5 +(1 row) + +-- WITH RECURSIVE +-- sum of 1..100 +WITH RECURSIVE t(n) AS ( + VALUES (1) +UNION ALL + SELECT n+1 FROM t WHERE n < 100 +) +SELECT sum(n) FROM t; + sum +------ + 5050 +(1 row) + +WITH RECURSIVE t(n) AS ( + SELECT (VALUES(1)) +UNION ALL + SELECT n+1 FROM t WHERE n < 5 +) +SELECT * FROM t ORDER BY n; + n +--- + 1 + 2 + 3 + 4 + 5 +(5 rows) + +-- This is an infinite loop with UNION ALL, but not with UNION +WITH RECURSIVE t(n) AS ( + SELECT 1 +UNION + SELECT 10-n FROM t) +SELECT * FROM t ORDER BY n; + n +--- + 1 + 9 +(2 rows) + +-- This'd be an infinite loop, but outside query reads only as much as needed +WITH RECURSIVE t(n) AS ( + VALUES (1) +UNION ALL + SELECT n+1 FROM t) +SELECT * FROM t LIMIT 10; + n +---- + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 +(10 rows) + +-- UNION case should have same property +WITH RECURSIVE t(n) AS ( + SELECT 1 +UNION + SELECT n+1 FROM t) +SELECT * FROM t LIMIT 10; + n +---- + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 +(10 rows) + +-- Test behavior with an unknown-type literal in the WITH +WITH q AS (SELECT 'foo' AS x) +SELECT x, x IS OF (unknown) as is_unknown FROM q; + x | is_unknown +-----+------------ + foo | t +(1 row) + +WITH RECURSIVE t(n) AS ( + SELECT 'foo' +UNION ALL + SELECT n || ' bar' FROM t WHERE length(n) < 20 +) +SELECT n, n IS OF (text) as is_text FROM t ORDER BY n; + n | is_text +-------------------------+--------- + foo | t + foo bar | t + foo bar bar | t + foo bar bar bar | t + foo bar bar bar bar | t + foo bar bar bar bar bar | t +(6 rows) + +-- +-- Some examples with a tree +-- +-- department structure represented here is as follows: +-- +-- ROOT-+->A-+->B-+->C +-- | | +-- | +->D-+->F +-- +->E-+->G +CREATE TEMP TABLE department ( + id INTEGER PRIMARY KEY, -- department ID + parent_department INTEGER REFERENCES department, -- upper department ID + name TEXT -- department name +); +ERROR: PG-XC does not yet support temporary tables +INSERT INTO department VALUES (0, NULL, 'ROOT'); +ERROR: relation "department" does not exist +LINE 1: INSERT INTO department VALUES (0, NULL, 'ROOT'); + ^ +INSERT INTO department VALUES (1, 0, 'A'); +ERROR: relation "department" does not exist +LINE 1: INSERT INTO department VALUES (1, 0, 'A'); + ^ +INSERT INTO department VALUES (2, 1, 'B'); +ERROR: relation "department" does not exist +LINE 1: INSERT INTO department VALUES (2, 1, 'B'); + ^ +INSERT INTO department VALUES (3, 2, 'C'); +ERROR: relation "department" does not exist +LINE 1: INSERT INTO department VALUES (3, 2, 'C'); + ^ +INSERT INTO department VALUES (4, 2, 'D'); +ERROR: relation "department" does not exist +LINE 1: INSERT INTO department VALUES (4, 2, 'D'); + ^ +INSERT INTO department VALUES (5, 0, 'E'); +ERROR: relation "department" does not exist +LINE 1: INSERT INTO department VALUES (5, 0, 'E'); + ^ +INSERT INTO department VALUES (6, 4, 'F'); +ERROR: relation "department" does not exist +LINE 1: INSERT INTO department VALUES (6, 4, 'F'); + ^ +INSERT INTO department VALUES (7, 5, 'G'); +ERROR: relation "department" does not exist +LINE 1: INSERT INTO department VALUES (7, 5, 'G'); + ^ +-- extract all departments under 'A'. Result should be A, B, C, D and F +WITH RECURSIVE subdepartment AS +( + -- non recursive term + SELECT name as root_name, * FROM department WHERE name = 'A' + UNION ALL + -- recursive term + SELECT sd.root_name, d.* FROM department AS d, subdepartment AS sd + WHERE d.parent_department = sd.id +) +SELECT * FROM subdepartment ORDER BY name; +ERROR: relation "department" does not exist +LINE 4: SELECT name as root_name, * FROM department WHERE name = 'A... + ^ +-- extract all departments under 'A' with "level" number +WITH RECURSIVE subdepartment(level, id, parent_department, name) AS +( + -- non recursive term + SELECT 1, * FROM department WHERE name = 'A' + UNION ALL + -- recursive term + SELECT sd.level + 1, d.* FROM department AS d, subdepartment AS sd + WHERE d.parent_department = sd.id +) +SELECT * FROM subdepartment ORDER BY name; +ERROR: relation "department" does not exist +LINE 4: SELECT 1, * FROM department WHERE name = 'A' + ^ +-- extract all departments under 'A' with "level" number. +-- Only shows level 2 or more +WITH RECURSIVE subdepartment(level, id, parent_department, name) AS +( + -- non recursive term + SELECT 1, * FROM department WHERE name = 'A' + UNION ALL + -- recursive term + SELECT sd.level + 1, d.* FROM department AS d, subdepartment AS sd + WHERE d.parent_department = sd.id +) +SELECT * FROM subdepartment WHERE level >= 2 ORDER BY name; +ERROR: relation "department" does not exist +LINE 4: SELECT 1, * FROM department WHERE name = 'A' + ^ +-- "RECURSIVE" is ignored if the query has no self-reference +WITH RECURSIVE subdepartment AS +( + -- note lack of recursive UNION structure + SELECT * FROM department WHERE name = 'A' +) +SELECT * FROM subdepartment ORDER BY name; +ERROR: relation "department" does not exist +LINE 4: SELECT * FROM department WHERE name = 'A' + ^ +-- inside subqueries +SELECT count(*) FROM ( + WITH RECURSIVE t(n) AS ( + SELECT 1 UNION ALL SELECT n + 1 FROM t WHERE n < 500 + ) + SELECT * FROM t) AS t WHERE n < ( + SELECT count(*) FROM ( + WITH RECURSIVE t(n) AS ( + SELECT 1 UNION ALL SELECT n + 1 FROM t WHERE n < 100 + ) + SELECT * FROM t WHERE n < 50000 + ) AS t WHERE n < 100); + count +------- + 98 +(1 row) + +-- use same CTE twice at different subquery levels +WITH q1(x,y) AS ( + SELECT hundred, sum(ten) FROM tenk1 GROUP BY hundred + ) +SELECT count(*) FROM q1 WHERE y > (SELECT sum(y)/100 FROM q1 qsub); +ERROR: GROUP BY clause is not yet supported +-- via a VIEW +CREATE TEMPORARY VIEW vsubdepartment AS + WITH RECURSIVE subdepartment AS + ( + -- non recursive term + SELECT * FROM department WHERE name = 'A' + UNION ALL + -- recursive term + SELECT d.* FROM department AS d, subdepartment AS sd + WHERE d.parent_department = sd.id + ) + SELECT * FROM subdepartment; +ERROR: relation "department" does not exist +LINE 5: SELECT * FROM department WHERE name = 'A' + ^ +SELECT * FROM vsubdepartment ORDER BY name; +ERROR: relation "vsubdepartment" does not exist +LINE 1: SELECT * FROM vsubdepartment ORDER BY name; + ^ +-- Check reverse listing +SELECT pg_get_viewdef('vsubdepartment'::regclass); +ERROR: relation "vsubdepartment" does not exist +LINE 1: SELECT pg_get_viewdef('vsubdepartment'::regclass); + ^ +SELECT pg_get_viewdef('vsubdepartment'::regclass, true); +ERROR: relation "vsubdepartment" does not exist +LINE 1: SELECT pg_get_viewdef('vsubdepartment'::regclass, true); + ^ +-- corner case in which sub-WITH gets initialized first +with recursive q as ( + (select * from department order by id) + union all + (with x as (select * from q) + select * from x) + ) +select * from q limit 24; +ERROR: relation "department" does not exist +LINE 2: (select * from department order by id) + ^ +with recursive q as ( + (select * from department order by id) + union all + (with recursive x as ( + select * from department + union all + (select * from q union all select * from x) + ) + select * from x) + ) +select * from q limit 32; +ERROR: relation "department" does not exist +LINE 2: (select * from department order by id) + ^ +-- recursive term has sub-UNION +WITH RECURSIVE t(i,j) AS ( + VALUES (1,2) + UNION ALL + SELECT t2.i, t.j+1 FROM + (SELECT 2 AS i UNION ALL SELECT 3 AS i) AS t2 + JOIN t ON (t2.i = t.i+1)) + SELECT * FROM t order by i; + i | j +---+--- + 1 | 2 + 2 | 3 + 3 | 4 +(3 rows) + +-- +-- different tree example +-- +CREATE TEMPORARY TABLE tree( + id INTEGER PRIMARY KEY, + parent_id INTEGER REFERENCES tree(id) +); +ERROR: PG-XC does not yet support temporary tables +INSERT INTO tree +VALUES (1, NULL), (2, 1), (3,1), (4,2), (5,2), (6,2), (7,3), (8,3), + (9,4), (10,4), (11,7), (12,7), (13,7), (14, 9), (15,11), (16,11); +ERROR: relation "tree" does not exist +LINE 1: INSERT INTO tree + ^ +-- +-- get all paths from "second level" nodes to leaf nodes +-- +WITH RECURSIVE t(id, path) AS ( + VALUES(1,ARRAY[]::integer[]) +UNION ALL + SELECT tree.id, t.path || tree.id + FROM tree JOIN t ON (tree.parent_id = t.id) +) +SELECT t1.*, t2.* FROM t AS t1 JOIN t AS t2 ON + (t1.path[1] = t2.path[1] AND + array_upper(t1.path,1) = 1 AND + array_upper(t2.path,1) > 1) + ORDER BY t1.id, t2.id; +ERROR: relation "tree" does not exist +LINE 5: FROM tree JOIN t ON (tree.parent_id = t.id) + ^ +-- just count 'em +WITH RECURSIVE t(id, path) AS ( + VALUES(1,ARRAY[]::integer[]) +UNION ALL + SELECT tree.id, t.path || tree.id + FROM tree JOIN t ON (tree.parent_id = t.id) +) +SELECT t1.id, count(t2.*) FROM t AS t1 JOIN t AS t2 ON + (t1.path[1] = t2.path[1] AND + array_upper(t1.path,1) = 1 AND + array_upper(t2.path,1) > 1) + GROUP BY t1.id + ORDER BY t1.id; +ERROR: relation "tree" does not exist +LINE 5: FROM tree JOIN t ON (tree.parent_id = t.id) + ^ +-- this variant tickled a whole-row-variable bug in 8.4devel +WITH RECURSIVE t(id, path) AS ( + VALUES(1,ARRAY[]::integer[]) +UNION ALL + SELECT tree.id, t.path || tree.id + FROM tree JOIN t ON (tree.parent_id = t.id) +) +SELECT t1.id, t2.path, t2 FROM t AS t1 JOIN t AS t2 ON +(t1.id=t2.id) ORDER BY id; +ERROR: relation "tree" does not exist +LINE 5: FROM tree JOIN t ON (tree.parent_id = t.id) + ^ +-- +-- test cycle detection +-- +create temp table graph( f int, t int, label text ); +ERROR: PG-XC does not yet support temporary tables +insert into graph values + (1, 2, 'arc 1 -> 2'), + (1, 3, 'arc 1 -> 3'), + (2, 3, 'arc 2 -> 3'), + (1, 4, 'arc 1 -> 4'), + (4, 5, 'arc 4 -> 5'), + (5, 1, 'arc 5 -> 1'); +ERROR: relation "graph" does not exist +LINE 1: insert into graph values + ^ +with recursive search_graph(f, t, label, path, cycle) as ( + select *, array[row(g.f, g.t)], false from graph g + union all + select g.*, path || row(g.f, g.t), row(g.f, g.t) = any(path) + from graph g, search_graph sg + where g.f = sg.t and not cycle +) +select * from search_graph order by path; +ERROR: relation "graph" does not exist +LINE 2: select *, array[row(g.f, g.t)], false from graph g + ^ +-- ordering by the path column has same effect as SEARCH DEPTH FIRST +with recursive search_graph(f, t, label, path, cycle) as ( + select *, array[row(g.f, g.t)], false from graph g + union all + select g.*, path || row(g.f, g.t), row(g.f, g.t) = any(path) + from graph g, search_graph sg + where g.f = sg.t and not cycle +) +select * from search_graph order by path; +ERROR: relation "graph" does not exist +LINE 2: select *, array[row(g.f, g.t)], false from graph g + ^ +-- +-- test multiple WITH queries +-- +WITH RECURSIVE + y (id) AS (VALUES (1)), + x (id) AS (SELECT * FROM y UNION ALL SELECT id+1 FROM x WHERE id < 5) +SELECT * FROM x ORDER BY id; + id +---- + 1 + 2 + 3 + 4 + 5 +(5 rows) + +-- forward reference OK +WITH RECURSIVE + x(id) AS (SELECT * FROM y UNION ALL SELECT id+1 FROM x WHERE id < 5), + y(id) AS (values (1)) + SELECT * FROM x ORDER BY id; + id +---- + 1 + 2 + 3 + 4 + 5 +(5 rows) + +WITH RECURSIVE + x(id) AS + (VALUES (1) UNION ALL SELECT id+1 FROM x WHERE id < 5), + y(id) AS + (VALUES (1) UNION ALL SELECT id+1 FROM y WHERE id < 10) + SELECT y.*, x.* FROM y LEFT JOIN x USING (id) ORDER BY 1; + id | id +----+---- + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | + 7 | + 8 | + 9 | + 10 | +(10 rows) + +WITH RECURSIVE + x(id) AS + (VALUES (1) UNION ALL SELECT id+1 FROM x WHERE id < 5), + y(id) AS + (VALUES (1) UNION ALL SELECT id+1 FROM x WHERE id < 10) + SELECT y.*, x.* FROM y LEFT JOIN x USING (id) ORDER BY 1; + id | id +----+---- + 1 | 1 + 2 | 2 + 3 | 3 + 4 | 4 + 5 | 5 + 6 | +(6 rows) + +WITH RECURSIVE + x(id) AS + (SELECT 1 UNION ALL SELECT id+1 FROM x WHERE id < 3 ), + y(id) AS + (SELECT * FROM x UNION ALL SELECT * FROM x), + z(id) AS + (SELECT * FROM x UNION ALL SELECT id+1 FROM z WHERE id < 10) + SELECT * FROM z ORDER BY id; + id +---- + 1 + 2 + 2 + 3 + 3 + 3 + 4 + 4 + 4 + 5 + 5 + 5 + 6 + 6 + 6 + 7 + 7 + 7 + 8 + 8 + 8 + 9 + 9 + 9 + 10 + 10 + 10 +(27 rows) + +WITH RECURSIVE + x(id) AS + (SELECT 1 UNION ALL SELECT id+1 FROM x WHERE id < 3 ), + y(id) AS + (SELECT * FROM x UNION ALL SELECT * FROM x), + z(id) AS + (SELECT * FROM y UNION ALL SELECT id+1 FROM z WHERE id < 10) + SELECT * FROM z ORDER BY id; + id +---- + 1 + 1 + 2 + 2 + 2 + 2 + 3 + 3 + 3 + 3 + 3 + 3 + 4 + 4 + 4 + 4 + 4 + 4 + 5 + 5 + 5 + 5 + 5 + 5 + 6 + 6 + 6 + 6 + 6 + 6 + 7 + 7 + 7 + 7 + 7 + 7 + 8 + 8 + 8 + 8 + 8 + 8 + 9 + 9 + 9 + 9 + 9 + 9 + 10 + 10 + 10 + 10 + 10 + 10 +(54 rows) + +-- +-- error cases +-- +-- INTERSECT +WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT SELECT n+1 FROM x) + SELECT * FROM x; +ERROR: recursive query "x" does not have the form non-recursive-term UNION [ALL] recursive-term +LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT SELECT n+1 FROM x... + ^ +WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT ALL SELECT n+1 FROM x) + SELECT * FROM x; +ERROR: recursive query "x" does not have the form non-recursive-term UNION [ALL] recursive-term +LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 INTERSECT ALL SELECT n+1 FR... + ^ +-- EXCEPT +WITH RECURSIVE x(n) AS (SELECT 1 EXCEPT SELECT n+1 FROM x) + SELECT * FROM x; +ERROR: recursive query "x" does not have the form non-recursive-term UNION [ALL] recursive-term +LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 EXCEPT SELECT n+1 FROM x) + ^ +WITH RECURSIVE x(n) AS (SELECT 1 EXCEPT ALL SELECT n+1 FROM x) + SELECT * FROM x; +ERROR: recursive query "x" does not have the form non-recursive-term UNION [ALL] recursive-term +LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 EXCEPT ALL SELECT n+1 FROM ... + ^ +-- no non-recursive term +WITH RECURSIVE x(n) AS (SELECT n FROM x) + SELECT * FROM x; +ERROR: recursive query "x" does not have the form non-recursive-term UNION [ALL] recursive-term +LINE 1: WITH RECURSIVE x(n) AS (SELECT n FROM x) + ^ +-- recursive term in the left hand side (strictly speaking, should allow this) +WITH RECURSIVE x(n) AS (SELECT n FROM x UNION ALL SELECT 1) + SELECT * FROM x; +ERROR: recursive reference to query "x" must not appear within its non-recursive term +LINE 1: WITH RECURSIVE x(n) AS (SELECT n FROM x UNION ALL SELECT 1) + ^ +CREATE TEMPORARY TABLE y (a INTEGER); +ERROR: PG-XC does not yet support temporary tables +INSERT INTO y SELECT generate_series(1, 10); +ERROR: relation "y" does not exist +LINE 1: INSERT INTO y SELECT generate_series(1, 10); + ^ +-- LEFT JOIN +WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1 + UNION ALL + SELECT x.n+1 FROM y LEFT JOIN x ON x.n = y.a WHERE n < 10) +SELECT * FROM x; +ERROR: recursive reference to query "x" must not appear within an outer join +LINE 3: SELECT x.n+1 FROM y LEFT JOIN x ON x.n = y.a WHERE n < 10) + ^ +-- RIGHT JOIN +WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1 + UNION ALL + SELECT x.n+1 FROM x RIGHT JOIN y ON x.n = y.a WHERE n < 10) +SELECT * FROM x; +ERROR: recursive reference to query "x" must not appear within an outer join +LINE 3: SELECT x.n+1 FROM x RIGHT JOIN y ON x.n = y.a WHERE n < 10) + ^ +-- FULL JOIN +WITH RECURSIVE x(n) AS (SELECT a FROM y WHERE a = 1 + UNION ALL + SELECT x.n+1 FROM x FULL JOIN y ON x.n = y.a WHERE n < 10) +SELECT * FROM x; +ERROR: recursive reference to query "x" must not appear within an outer join +LINE 3: SELECT x.n+1 FROM x FULL JOIN y ON x.n = y.a WHERE n < 10) + ^ +-- subquery +WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x + WHERE n IN (SELECT * FROM x)) + SELECT * FROM x; +ERROR: recursive reference to query "x" must not appear within a subquery +LINE 2: WHERE n IN (SELECT * FROM x)) + ^ +-- aggregate functions +WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT count(*) FROM x) + SELECT * FROM x; +ERROR: aggregate functions not allowed in a recursive query's recursive term +LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT count(*) F... + ^ +WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT sum(n) FROM x) + SELECT * FROM x; +ERROR: aggregate functions not allowed in a recursive query's recursive term +LINE 1: WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT sum(n) FRO... + ^ +-- ORDER BY +WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x ORDER BY 1) + SELECT * FROM x; +ERROR: ORDER BY in a recursive query is not implemented +LINE 1: ...VE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x ORDER BY 1) + ^ +-- LIMIT/OFFSET +WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x LIMIT 10 OFFSET 1) + SELECT * FROM x; +ERROR: OFFSET in a recursive query is not implemented +LINE 1: ... AS (SELECT 1 UNION ALL SELECT n+1 FROM x LIMIT 10 OFFSET 1) + ^ +-- FOR UPDATE +WITH RECURSIVE x(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM x FOR UPDATE) + SELECT * FROM x; +ERROR: FOR UPDATE/SHARE in a recursive query is not implemented +-- target list has a recursive query name +WITH RECURSIVE x(id) AS (values (1) + UNION ALL + SELECT (SELECT * FROM x) FROM x WHERE id < 5 +) SELECT * FROM x; +ERROR: recursive reference to query "x" must not appear within a subquery +LINE 3: SELECT (SELECT * FROM x) FROM x WHERE id < 5 + ^ +-- mutual recursive query (not implemented) +WITH RECURSIVE + x (id) AS (SELECT 1 UNION ALL SELECT id+1 FROM y WHERE id < 5), + y (id) AS (SELECT 1 UNION ALL SELECT id+1 FROM x WHERE id < 5) +SELECT * FROM x; +ERROR: mutual recursion between WITH items is not implemented +LINE 2: x (id) AS (SELECT 1 UNION ALL SELECT id+1 FROM y WHERE id ... + ^ +-- non-linear recursion is not allowed +WITH RECURSIVE foo(i) AS + (values (1) + UNION ALL + (SELECT i+1 FROM foo WHERE i < 10 + UNION ALL + SELECT i+1 FROM foo WHERE i < 5) +) SELECT * FROM foo; +ERROR: recursive reference to query "foo" must not appear more than once +LINE 6: SELECT i+1 FROM foo WHERE i < 5) + ^ +WITH RECURSIVE foo(i) AS + (values (1) + UNION ALL + SELECT * FROM + (SELECT i+1 FROM foo WHERE i < 10 + UNION ALL + SELECT i+1 FROM foo WHERE i < 5) AS t +) SELECT * FROM foo; +ERROR: recursive reference to query "foo" must not appear more than once +LINE 7: SELECT i+1 FROM foo WHERE i < 5) AS t + ^ +WITH RECURSIVE foo(i) AS + (values (1) + UNION ALL + (SELECT i+1 FROM foo WHERE i < 10 + EXCEPT + SELECT i+1 FROM foo WHERE i < 5) +) SELECT * FROM foo; +ERROR: recursive reference to query "foo" must not appear within EXCEPT +LINE 6: SELECT i+1 FROM foo WHERE i < 5) + ^ +WITH RECURSIVE foo(i) AS + (values (1) + UNION ALL + (SELECT i+1 FROM foo WHERE i < 10 + INTERSECT + SELECT i+1 FROM foo WHERE i < 5) +) SELECT * FROM foo; +ERROR: recursive reference to query "foo" must not appear more than once +LINE 6: SELECT i+1 FROM foo WHERE i < 5) + ^ +-- Wrong type induced from non-recursive term +WITH RECURSIVE foo(i) AS + (SELECT i FROM (VALUES(1),(2)) t(i) + UNION ALL + SELECT (i+1)::numeric(10,0) FROM foo WHERE i < 10) +SELECT * FROM foo; +ERROR: recursive query "foo" column 1 has type integer in non-recursive term but type numeric overall +LINE 2: (SELECT i FROM (VALUES(1),(2)) t(i) + ^ +HINT: Cast the output of the non-recursive term to the correct type. +-- rejects different typmod, too (should we allow this?) +WITH RECURSIVE foo(i) AS + (SELECT i::numeric(3,0) FROM (VALUES(1),(2)) t(i) + UNION ALL + SELECT (i+1)::numeric(10,0) FROM foo WHERE i < 10) +SELECT * FROM foo; +ERROR: recursive query "foo" column 1 has type numeric(3,0) in non-recursive term but type numeric overall +LINE 2: (SELECT i::numeric(3,0) FROM (VALUES(1),(2)) t(i) + ^ +HINT: Cast the output of the non-recursive term to the correct type. +-- +-- test for bug #4902 +-- +with cte(foo) as ( values(42) ) values((select foo from cte)); + column1 +--------- + 42 +(1 row) + +with cte(foo) as ( select 42 ) select * from ((select foo from cte)) q; + foo +----- + 42 +(1 row) + +-- test CTE referencing an outer-level variable (to see that changed-parameter +-- signaling still works properly after fixing this bug) +select ( with cte(foo) as ( values(f1) ) + select (select foo from cte) ) +from int4_tbl order by 1; + ?column? +------------- + -2147483647 + -123456 + 0 + 123456 + 2147483647 +(5 rows) + +select ( with cte(foo) as ( values(f1) ) + values((select foo from cte)) ) +from int4_tbl order by 1; + ?column? +------------- + -2147483647 + -123456 + 0 + 123456 + 2147483647 +(5 rows) + +-- +-- test for nested-recursive-WITH bug +-- +WITH RECURSIVE t(j) AS ( + WITH RECURSIVE s(i) AS ( + VALUES (1) + UNION ALL + SELECT i+1 FROM s WHERE i < 10 + ) + SELECT i FROM s + UNION ALL + SELECT j+1 FROM t WHERE j < 10 +) +SELECT * FROM t order by 1; + j +---- + 1 + 2 + 2 + 3 + 3 + 3 + 4 + 4 + 4 + 4 + 5 + 5 + 5 + 5 + 5 + 6 + 6 + 6 + 6 + 6 + 6 + 7 + 7 + 7 + 7 + 7 + 7 + 7 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 8 + 9 + 9 + 9 + 9 + 9 + 9 + 9 + 9 + 9 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 + 10 +(55 rows) + diff --git a/src/test/regress/sql/with.sql b/src/test/regress/sql/with.sql index e40d90d..687c035 100644 --- a/src/test/regress/sql/with.sql +++ b/src/test/regress/sql/with.sql @@ -43,14 +43,14 @@ WITH RECURSIVE t(n) AS ( VALUES (1) UNION ALL SELECT n+1 FROM t) -SELECT * FROM t LIMIT 10 ; +SELECT * FROM t LIMIT 10; -- UNION case should have same property WITH RECURSIVE t(n) AS ( SELECT 1 UNION SELECT n+1 FROM t) -SELECT * FROM t LIMIT 10; +SELECT * FROM t LIMIT 10; -- Test behavior with an unknown-type literal in the WITH WITH q AS (SELECT 'foo' AS x) ----------------------------------------------------------------------- Summary of changes: src/test/regress/expected/{with.out => with_1.out} | 317 +++++-------------- src/test/regress/sql/with.sql | 4 +- 2 files changed, 86 insertions(+), 235 deletions(-) copy src/test/regress/expected/{with.out => with_1.out} (65%) hooks/post-receive -- Postgres-XC |
From: Pavan D. <pa...@us...> - 2011-04-19 05:51:25
|
Project "Postgres-XC". The branch, master has been updated via e12ca2d640d6c9d09aefeb05bbce1fba01e9549a (commit) from e734d31c84a0a557bdfb172ee097a4b46d3868a7 (commit) - Log ----------------------------------------------------------------- commit e12ca2d640d6c9d09aefeb05bbce1fba01e9549a Author: Pavan Deolasee <pav...@gm...> Date: Tue Apr 19 11:18:59 2011 +0530 Fix a bug where we had used a assignment operator instead of a comparison diff --git a/src/backend/pgxc/pool/execRemote.c b/src/backend/pgxc/pool/execRemote.c index 700268a..06c971e 100644 --- a/src/backend/pgxc/pool/execRemote.c +++ b/src/backend/pgxc/pool/execRemote.c @@ -1258,7 +1258,7 @@ FetchTuple(RemoteQueryState *combiner, TupleTableSlot *slot) else combiner->current_conn = 0; } - else if (res = RESPONSE_DATAROW && have_tuple) + else if (res == RESPONSE_DATAROW && have_tuple) { /* * We already have a tuple and received another one, leave it till ----------------------------------------------------------------------- Summary of changes: src/backend/pgxc/pool/execRemote.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) hooks/post-receive -- Postgres-XC |
From: Pavan D. <pa...@us...> - 2011-04-19 05:10:44
|
Project "Postgres-XC". The branch, pgxc-barrier has been updated via 1e74fe24bd50b8e1c8244e2e8f999e10964484dd (commit) from df86ba5f78e6f0a350a229ef565536ca4b5826f8 (commit) - Log ----------------------------------------------------------------- commit 1e74fe24bd50b8e1c8244e2e8f999e10964484dd Author: Pavan Deolasee <pav...@gm...> Date: Mon Apr 18 13:41:47 2011 +0530 Add synchrnization at the commit time diff --git a/src/backend/pgxc/pool/execRemote.c b/src/backend/pgxc/pool/execRemote.c index 849f36b..b07753f 100644 --- a/src/backend/pgxc/pool/execRemote.c +++ b/src/backend/pgxc/pool/execRemote.c @@ -17,6 +17,7 @@ #include <time.h> #include "postgres.h" +#include "access/twophase.h" #include "access/gtm.h" #include "access/xact.h" #include "catalog/pg_type.h" @@ -1834,9 +1835,23 @@ PGXCNodeImplicitCommitPrepared(GlobalTransactionId prepare_xid, goto finish; } + /* + * Barrier: + * + * We should acquire the BarrierLock in SHARE mode here to ensure that + * there are no in-progress barrier at this point. This mechanism would + * work as long as LWLock mechanism does not starve a EXCLUSIVE lock + * requesster + */ + LWLockAcquire(BarrierLock, LW_SHARED); res = pgxc_node_implicit_commit_prepared(prepare_xid, commit_xid, pgxc_connections, gid, is_commit); + /* + * Release the BarrierLock. + */ + LWLockRelease(BarrierLock); + finish: /* Clear nodes, signals are clear */ if (!autocommit) @@ -1920,8 +1935,8 @@ finish: * or not but send the message to all of them. * This avoid to have any additional interaction with GTM when making a 2PC transaction. */ -bool -PGXCNodeCommitPrepared(char *gid) +void +PGXCNodeCommitPrepared(char *gid, bool isTopLevel) { int res = 0; int res_gtm = 0; @@ -1971,7 +1986,15 @@ PGXCNodeCommitPrepared(char *gid) /* * Commit here the prepared transaction to all Datanodes and Coordinators * If necessary, local Coordinator Commit is performed after this DataNodeCommitPrepared. + * + * BARRIER: + * + * Take the BarrierLock in SHARE mode to synchronize on in-progress + * barriers. We should hold on to the lock until the local prepared + * transaction is also committed */ + LWLockAcquire(BarrierLock, LW_SHARED); + res = pgxc_node_commit_prepared(gxid, prepared_gxid, pgxc_handles, gid); finish: @@ -1991,16 +2014,34 @@ finish: free(coordinators); pfree_pgxc_all_handles(pgxc_handles); + if (res_gtm < 0) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Could not get GID data from GTM"))); + if (res != 0) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Could not commit prepared transaction on data nodes"))); - return operation_local; + /* + * A local Coordinator always commits if involved in Prepare. + * 2PC file is created and flushed if a DDL has been involved in the transaction. + * If remote connection is a Coordinator type, the commit prepared has to be done locally + * if and only if the Coordinator number was in the node list received from GTM. + */ + if (operation_local || IsConnFromCoord()) + { + PreventTransactionChain(isTopLevel, "COMMIT PREPARED"); + FinishPreparedTransaction(gid, true); + } + + /* + * Release the barrier lock now so that pending barriers can get moving + */ + LWLockRelease(BarrierLock); + return; } /* @@ -2045,11 +2086,9 @@ finish: /* * Rollback prepared transaction on Datanodes involved in the current transaction - * - * Return whether or not a local operation required. */ -bool -PGXCNodeRollbackPrepared(char *gid) +void +PGXCNodeRollbackPrepared(char *gid, bool isTopLevel) { int res = 0; int res_gtm = 0; @@ -2122,7 +2161,17 @@ finish: (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Could not rollback prepared transaction on Datanodes"))); - return operation_local; + /* + * Local coordinator rollbacks if involved in PREPARE + * If remote connection is a Coordinator type, the commit prepared has to be done locally also. + * This works for both Datanodes and Coordinators. + */ + if (operation_local || IsConnFromCoord()) + { + PreventTransactionChain(isTopLevel, "ROLLBACK PREPARED"); + FinishPreparedTransaction(gid, false); + } + return; } diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index bd13ce3..6b3c138 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -400,22 +400,10 @@ ProcessUtility(Node *parsetree, * Don't send it down to Datanodes. */ if (IS_PGXC_COORDINATOR && !IsConnFromCoord()) - operation_local = PGXCNodeCommitPrepared(stmt->gid); -#endif + PGXCNodeCommitPrepared(stmt->gid, isTopLevel); +#else PreventTransactionChain(isTopLevel, "COMMIT PREPARED"); -#ifdef PGXC - /* - * A local Coordinator always commits if involved in Prepare. - * 2PC file is created and flushed if a DDL has been involved in the transaction. - * If remote connection is a Coordinator type, the commit prepared has to be done locally - * if and only if the Coordinator number was in the node list received from GTM. - */ - if (operation_local || IsConnFromCoord()) - { -#endif FinishPreparedTransaction(stmt->gid, true); -#ifdef PGXC - } #endif break; @@ -426,21 +414,10 @@ ProcessUtility(Node *parsetree, * Don't send it down to Datanodes. */ if (IS_PGXC_COORDINATOR && !IsConnFromCoord()) - operation_local = PGXCNodeRollbackPrepared(stmt->gid); -#endif + PGXCNodeRollbackPrepared(stmt->gid, isTopLevel); +#else PreventTransactionChain(isTopLevel, "ROLLBACK PREPARED"); -#ifdef PGXC - /* - * Local coordinator rollbacks if involved in PREPARE - * If remote connection is a Coordinator type, the commit prepared has to be done locally also. - * This works for both Datanodes and Coordinators. - */ - if (operation_local || IsConnFromCoord()) - { -#endif - FinishPreparedTransaction(stmt->gid, false); -#ifdef PGXC - } + FinishPreparedTransaction(gid, false); #endif break; diff --git a/src/include/pgxc/execRemote.h b/src/include/pgxc/execRemote.h index e9f000f..a50c40c 100644 --- a/src/include/pgxc/execRemote.h +++ b/src/include/pgxc/execRemote.h @@ -120,8 +120,8 @@ extern void PGXCNodeBegin(void); extern void PGXCNodeCommit(void); extern int PGXCNodeRollback(void); extern bool PGXCNodePrepare(char *gid); -extern bool PGXCNodeRollbackPrepared(char *gid); -extern bool PGXCNodeCommitPrepared(char *gid); +extern void PGXCNodeRollbackPrepared(char *gid, bool isTopLevel); +extern void PGXCNodeCommitPrepared(char *gid, bool isTopLevel); extern bool PGXCNodeIsImplicit2PC(bool *prepare_local_coord); extern int PGXCNodeImplicitPrepare(GlobalTransactionId prepare_xid, char *gid); extern void PGXCNodeImplicitCommitPrepared(GlobalTransactionId prepare_xid, ----------------------------------------------------------------------- Summary of changes: src/backend/pgxc/pool/execRemote.c | 65 +++++++++++++++++++++++++++++++---- src/backend/tcop/utility.c | 33 +++--------------- src/include/pgxc/execRemote.h | 4 +- 3 files changed, 64 insertions(+), 38 deletions(-) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-18 06:00:29
|
Project "Postgres-XC". The branch, master has been updated via e734d31c84a0a557bdfb172ee097a4b46d3868a7 (commit) from 719a5c822021427f7fd0eda354842b4b6b7ac381 (commit) - Log ----------------------------------------------------------------- commit e734d31c84a0a557bdfb172ee097a4b46d3868a7 Author: Michael P <mic...@us...> Date: Mon Apr 18 14:51:14 2011 +0900 Fix for bug 3167720: join optimizer error When running a query on multiple tables, if a constant expression was contained in WHERE clause, XC planner examined the constant expression all the time and checked if it was possible to avoid multiple node operation if the constant expression depended on a distributed table. This commits adds a check to verify in the case of multiple tables used in FROM clause if query can be safely pushed down to one target node on depending on the distribution type of each table. If SELECT clause is used on one distributed table and several replicated tables, this can be safely pushed down to a target node but in the case of multiple distributed tables used, all the nodes have to be targetted. diff --git a/src/backend/pgxc/plan/planner.c b/src/backend/pgxc/plan/planner.c index 019b6b8..dd570f4 100644 --- a/src/backend/pgxc/plan/planner.c +++ b/src/backend/pgxc/plan/planner.c @@ -1083,6 +1083,46 @@ examine_conditions_walker(Node *expr_node, XCWalkerContext *context) if (!rel_loc_info1) return true; + /* Check if this constant expression is targetting multiple tables */ + if (list_length(context->query->rtable) > 1) + { + ListCell *lc; + RangeTblEntry *save_rte = NULL; + RelationLocInfo *save_loc_info; + + foreach(lc, context->query->rtable) + { + RangeTblEntry *rte = lfirst(lc); + + if (!save_rte) + { + save_rte = rte; + save_loc_info = GetRelationLocInfo(save_rte->relid); + } + else + { + /* + * If there are two distributed tables at least + * among the multiple tables, push down the query to all nodes. + */ + if (save_rte->relid != rte->relid) + { + RelationLocInfo *loc_info = GetRelationLocInfo(rte->relid); + + if (loc_info->locatorType != LOCATOR_TYPE_REPLICATED && + save_loc_info->locatorType != LOCATOR_TYPE_REPLICATED) + return true; + if (loc_info->locatorType != LOCATOR_TYPE_REPLICATED && + save_loc_info->locatorType == LOCATOR_TYPE_REPLICATED) + { + save_rte = rte; + save_loc_info = loc_info; + } + } + } + } + } + /* If hash or modulo partitioned, check if the part column was used */ if (IsHashColumn(rel_loc_info1, column_base->colname) || IsModuloColumn(rel_loc_info1, column_base->colname)) ----------------------------------------------------------------------- Summary of changes: src/backend/pgxc/plan/planner.c | 40 +++++++++++++++++++++++++++++++++++++++ 1 files changed, 40 insertions(+), 0 deletions(-) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-15 07:21:37
|
Project "Postgres-XC". The branch, master has been updated via 719a5c822021427f7fd0eda354842b4b6b7ac381 (commit) from 8d0c5128fe837f140e932f1b67c318fa2788d98d (commit) - Log ----------------------------------------------------------------- commit 719a5c822021427f7fd0eda354842b4b6b7ac381 Author: Michael P <mic...@us...> Date: Fri Apr 15 16:16:25 2011 +0900 Fix for bug 3219036: gtm_crash when wait is activated Crash was occurring when connection to GTM was tested. Since node registration implementation, a PGXC node ID is necessary in GTM connection protocol. diff --git a/src/gtm/gtm_ctl/gtm_ctl.c b/src/gtm/gtm_ctl/gtm_ctl.c index ba1f20a..4b82e44 100644 --- a/src/gtm/gtm_ctl/gtm_ctl.c +++ b/src/gtm/gtm_ctl/gtm_ctl.c @@ -354,9 +354,11 @@ test_gtm_connection() /* * We need to set a connect timeout otherwise on Windows the SCM will * probably timeout first + * a PGXC node ID has to be set for GTM connection protocol, + * so its value doesn't really matter here. */ snprintf(connstr, sizeof(connstr), - "host=localhost port=%s connect_timeout=5", portstr); + "host=localhost port=%s connect_timeout=5 pgxc_node_id=1", portstr); for (i = 0; i < wait_seconds; i++) { ----------------------------------------------------------------------- Summary of changes: src/gtm/gtm_ctl/gtm_ctl.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-15 07:08:23
|
Project "Postgres-XC". The branch, master has been updated via 8d0c5128fe837f140e932f1b67c318fa2788d98d (commit) from de75b4603d9a13ed45a1b73d855c48a098fc7371 (commit) - Log ----------------------------------------------------------------- commit 8d0c5128fe837f140e932f1b67c318fa2788d98d Author: Michael P <mic...@us...> Date: Fri Apr 15 16:01:54 2011 +0900 Fix for bug 3189885: gtm_ctl to start gtm_proxy Since the implementation of node registration feature, GTM Proxy has a mandatory option -i to indicate its ID when registering on GTM. This mandatory option was not controlled in gtm_ctl. diff --git a/src/gtm/gtm_ctl/gtm_ctl.c b/src/gtm/gtm_ctl/gtm_ctl.c index 2f90bd4..ba1f20a 100644 --- a/src/gtm/gtm_ctl/gtm_ctl.c +++ b/src/gtm/gtm_ctl/gtm_ctl.c @@ -86,6 +86,8 @@ static void read_gtm_opts(void); static bool test_gtm_connection(); static bool gtm_is_alive(pid_t pid); +static void *pg_realloc(void *ptr, size_t size); + static char gtmopts_file[MAXPGPATH]; static char pid_file[MAXPGPATH]; @@ -257,8 +259,8 @@ start_gtm(void) memset(gtm_app_path, 0, MAXPGPATH); memset(cmd, 0, MAXPGPATH); - /* - * Construct gtm binary path. We should leave one byte at the end for '\0' + /* + * Build gtm binary path. We should leave one byte at the end for '\0' */ len = 0; if (gtm_path != NULL) @@ -665,8 +667,10 @@ do_help(void) printf(_("\nCommon options:\n")); printf(_(" -D DATADIR location of the database storage area\n")); + printf(_(" -i NODE_ID set gtm_proxy ID registered on GTM\n")); + printf(_(" (option ignored if used with GTM)\n")); printf(_(" -S set gtm or gtm_proxy to launch one of them\n")); - printf(_(" -s, only print errors, no informational messages\n")); + printf(_(" -s, only print errors, no informational messages\n")); printf(_(" -t SECS seconds to wait when using -w option\n")); printf(_(" -w wait until operation completes\n")); printf(_(" -W do not wait until operation completes\n")); @@ -719,6 +723,7 @@ int main(int argc, char **argv) { int c; + int node_id = 0; /* GTM Proxy ID */ progname = "gtm_ctl"; @@ -765,7 +770,7 @@ main(int argc, char **argv) /* process command-line options */ while (optind < argc) { - while ((c = getopt(argc, argv, "D:l:m:o:p:S:t:wW")) != -1) + while ((c = getopt(argc, argv, "D:i:l:m:o:p:S:t:wW")) != -1) { switch (c) { @@ -785,12 +790,15 @@ main(int argc, char **argv) * variable but we do -D too for clearer gtm * 'ps' display */ - gtmdata_opt = pg_malloc(strlen(gtmdata_D) + 8); + gtmdata_opt = (char *) pg_malloc(strlen(gtmdata_D) + 8); snprintf(gtmdata_opt, strlen(gtmdata_D) + 8, "-D \"%s\" ", gtmdata_D); break; } + case 'i': + node_id = atoi(optarg); + break; case 'l': log_file = xstrdup(optarg); break; @@ -806,13 +814,6 @@ main(int argc, char **argv) break; case 'S': gtm_app = xstrdup(optarg); - if (strcmp(gtm_app,"gtm_proxy") != 0 - && strcmp(gtm_app,"gtm") != 0) - { - write_stderr(_("%s: %s launch name set not correct\n"), progname, gtm_app); - do_advice(); - exit(1); - } break; case 't': wait_seconds = atoi(optarg); @@ -875,7 +876,7 @@ main(int argc, char **argv) if (!gtm_data) { - write_stderr("%s: no database directory specified \n", + write_stderr("%s: no GTM/GTM Proxy directory specified \n", progname); do_advice(); exit(1); @@ -888,12 +889,40 @@ main(int argc, char **argv) */ if (!gtm_app) { - write_stderr("%s: launcher name non specified, see option -S\n", + write_stderr("%s: no launch option not specified\n", progname); do_advice(); exit(1); } + if (strcmp(gtm_app,"gtm_proxy") != 0 && + strcmp(gtm_app,"gtm") != 0) + { + write_stderr(_("%s: launch option incorrect\n"), + progname); + do_advice(); + exit(1); + } + + /* Check if GTM Proxy ID is set, this is not necessary when stopping */ + if (ctl_command == START_COMMAND || + ctl_command == RESTART_COMMAND) + { + if (node_id == 0 && strcmp(gtm_app, "gtm_proxy") == 0) + { + write_stderr("%s: GTM Proxy ID not specified\n", + progname); + do_advice(); + exit(1); + } + /* Rebuild option string to include Proxy ID */ + if (strcmp(gtm_app, "gtm_proxy") == 0) + { + gtmdata_opt = (char *) pg_realloc(gtmdata_opt, strlen(gtmdata_opt) + 9); + sprintf(gtmdata_opt, "%s -i %d ", gtmdata_opt, node_id); + } + } + if (!wait_set) { switch (ctl_command) @@ -910,18 +939,16 @@ main(int argc, char **argv) } } - if (gtm_data) + /* Build strings for pid file and option file */ + if (strcmp(gtm_app,"gtm_proxy") == 0) { - if (strcmp(gtm_app,"gtm_proxy") == 0) - { - snprintf(pid_file, MAXPGPATH, "%s/gtm_proxy.pid", gtm_data); - snprintf(gtmopts_file, MAXPGPATH, "%s/gtm_proxy.opts", gtm_data); - } - else if (strcmp(gtm_app,"gtm") == 0) - { - snprintf(pid_file, MAXPGPATH, "%s/gtm.pid", gtm_data); - snprintf(gtmopts_file, MAXPGPATH, "%s/gtm.opts", gtm_data); - } + snprintf(pid_file, MAXPGPATH, "%s/gtm_proxy.pid", gtm_data); + snprintf(gtmopts_file, MAXPGPATH, "%s/gtm_proxy.opts", gtm_data); + } + else if (strcmp(gtm_app,"gtm") == 0) + { + snprintf(pid_file, MAXPGPATH, "%s/gtm.pid", gtm_data); + snprintf(gtmopts_file, MAXPGPATH, "%s/gtm.opts", gtm_data); } switch (ctl_command) @@ -941,3 +968,19 @@ main(int argc, char **argv) exit(0); } + +/* + * Safer versions of standard realloc C library function. If an + * out-of-memory condition occurs, these functions will bail out + * safely; therefore, its return value is guaranteed to be non-NULL. + */ +static void * +pg_realloc(void *ptr, size_t size) +{ + void *tmp; + + tmp = realloc(ptr, size); + if (!tmp) + write_stderr("out of memory\n"); + return tmp; +} ----------------------------------------------------------------------- Summary of changes: src/gtm/gtm_ctl/gtm_ctl.c | 93 +++++++++++++++++++++++++++++++++------------ 1 files changed, 68 insertions(+), 25 deletions(-) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-15 05:27:05
|
Project "Postgres-XC". The branch, master has been updated via de75b4603d9a13ed45a1b73d855c48a098fc7371 (commit) from 8671a6ea9e630d8f4f60126a79f084ada4eb6280 (commit) - Log ----------------------------------------------------------------- commit de75b4603d9a13ed45a1b73d855c48a098fc7371 Author: Michael P <mic...@us...> Date: Fri Apr 15 14:22:33 2011 +0900 Fix for bug 3240313: log count for sequences Log count was not made correctly, leading to incorrect results when launching a SELECT on a sequence. This commit also contains a fix for regression test sequence. diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 01df64b..8703d7a 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -633,6 +633,9 @@ nextval_internal(Oid relid) incby = seq->increment_by; maxv = seq->max_value; minv = seq->min_value; +#ifdef PGXC + } +#endif fetch = cache = seq->cache_value; log = seq->log_cnt; @@ -677,6 +680,8 @@ nextval_internal(Oid relid) * Check MAXVALUE for ascending sequences and MINVALUE for descending * sequences */ +#ifndef PGXC + /* Result has been checked and received from GTM */ if (incby > 0) { /* ascending sequence */ @@ -723,20 +728,29 @@ nextval_internal(Oid relid) else next += incby; } +#endif fetch--; if (rescnt < cache) { log--; rescnt++; +#ifndef PGXC + /* + * This part is not taken into account, + * result has been received from GTM + */ last = next; if (rescnt == 1) /* if it's first result - */ result = next; /* it's what to return */ +#endif } } log -= fetch; /* adjust for any unfetched numbers */ Assert(log >= 0); +#ifndef PGXC + /* Result has been received from GTM */ /* save info in local cache */ elm->last = result; /* last returned number */ elm->cached = last; /* last fetched number */ @@ -784,8 +798,8 @@ nextval_internal(Oid relid) seq->log_cnt = log; /* how much is logged */ END_CRIT_SECTION(); -#ifdef PGXC /* PGXC_COORD */ - } +#else + seq->log_cnt = log; #endif UnlockReleaseBuffer(buf); diff --git a/src/test/regress/expected/sequence_2.out b/src/test/regress/expected/sequence_2.out new file mode 100644 index 0000000..f7ba11e --- /dev/null +++ b/src/test/regress/expected/sequence_2.out @@ -0,0 +1,301 @@ +--- +--- test creation of SERIAL column +--- + +CREATE TABLE serialTest (f1 text, f2 serial); +ERROR: Postgres-XC does not support SERIAL yet +DETAIL: The feature is not currently supported + +INSERT INTO serialTest VALUES ('foo'); +ERROR: relation "serialtest" does not exist +LINE 1: INSERT INTO serialTest VALUES ('foo'); + ^ +INSERT INTO serialTest VALUES ('bar'); +ERROR: relation "serialtest" does not exist +LINE 1: INSERT INTO serialTest VALUES ('bar'); + ^ +INSERT INTO serialTest VALUES ('force', 100); +ERROR: relation "serialtest" does not exist +LINE 1: INSERT INTO serialTest VALUES ('force', 100); + ^ +INSERT INTO serialTest VALUES ('wrong', NULL); +ERROR: relation "serialtest" does not exist +LINE 1: INSERT INTO serialTest VALUES ('wrong', NULL); + ^ + +SELECT * FROM serialTest ORDER BY f1, f2; +ERROR: relation "serialtest" does not exist +LINE 1: SELECT * FROM serialTest ORDER BY f1, f2; + ^ +-- basic sequence operations using both text and oid references +CREATE SEQUENCE sequence_test; + +SELECT nextval('sequence_test'::text); + nextval +--------- + 1 +(1 row) + +SELECT nextval('sequence_test'::regclass); + nextval +--------- + 2 +(1 row) + +SELECT currval('sequence_test'::text); + currval +--------- + 2 +(1 row) + +SELECT currval('sequence_test'::regclass); + currval +--------- + 2 +(1 row) + +SELECT setval('sequence_test'::text, 32); + setval +-------- + 32 +(1 row) + +SELECT nextval('sequence_test'::regclass); + nextval +--------- + 33 +(1 row) + +SELECT setval('sequence_test'::text, 99, false); + setval +-------- + 99 +(1 row) + +SELECT nextval('sequence_test'::regclass); + nextval +--------- + 99 +(1 row) + +SELECT setval('sequence_test'::regclass, 32); + setval +-------- + 32 +(1 row) + +SELECT nextval('sequence_test'::text); + nextval +--------- + 33 +(1 row) + +SELECT setval('sequence_test'::regclass, 99, false); + setval +-------- + 99 +(1 row) + +SELECT nextval('sequence_test'::text); + nextval +--------- + 99 +(1 row) + +DROP SEQUENCE sequence_test; +-- renaming sequences +CREATE SEQUENCE foo_seq; +ALTER TABLE foo_seq RENAME TO foo_seq_new; +SELECT * FROM foo_seq_new; + sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called +---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+----------- + foo_seq | 1 | 1 | 1 | 9223372036854775807 | 1 | 1 | 1 | f | f +(1 row) + +SELECT nextval('foo_seq_new'); + nextval +--------- + 1 +(1 row) + +SELECT nextval('foo_seq_new'); + nextval +--------- + 2 +(1 row) + +SELECT * FROM foo_seq_new; + sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called +---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+----------- + foo_seq | 2 | 1 | 1 | 9223372036854775807 | 1 | 1 | 32 | f | t +(1 row) + +DROP SEQUENCE foo_seq_new; +-- renaming serial sequences +ALTER TABLE serialtest_f2_seq RENAME TO serialtest_f2_foo; +ERROR: relation "serialtest_f2_seq" does not exist +INSERT INTO serialTest VALUES ('more'); +ERROR: relation "serialtest" does not exist +LINE 1: INSERT INTO serialTest VALUES ('more'); + ^ +SELECT * FROM serialTest ORDER BY f1, f2; +ERROR: relation "serialtest" does not exist +LINE 1: SELECT * FROM serialTest ORDER BY f1, f2; + ^ +-- +-- Check dependencies of serial and ordinary sequences +-- +CREATE TEMP SEQUENCE myseq2; +ERROR: Postgres-XC does not support TEMPORARY SEQUENCE yet +DETAIL: The feature is not currently supported +CREATE TEMP SEQUENCE myseq3; +ERROR: Postgres-XC does not support TEMPORARY SEQUENCE yet +DETAIL: The feature is not currently supported +CREATE TEMP TABLE t1 ( + f1 serial, + f2 int DEFAULT nextval('myseq2'), + f3 int DEFAULT nextval('myseq3'::text) +); +ERROR: Postgres-XC does not support SERIAL yet +DETAIL: The feature is not currently supported +-- Both drops should fail, but with different error messages: +DROP SEQUENCE t1_f1_seq; +ERROR: sequence "t1_f1_seq" does not exist +DROP SEQUENCE myseq2; +ERROR: sequence "myseq2" does not exist +-- This however will work: +DROP SEQUENCE myseq3; +ERROR: sequence "myseq3" does not exist +DROP TABLE t1; +ERROR: table "t1" does not exist +-- Fails because no longer existent: +DROP SEQUENCE t1_f1_seq; +ERROR: sequence "t1_f1_seq" does not exist +-- Now OK: +DROP SEQUENCE myseq2; +ERROR: sequence "myseq2" does not exist +-- +-- Alter sequence +-- +CREATE SEQUENCE sequence_test2 START WITH 32; +SELECT nextval('sequence_test2'); + nextval +--------- + 32 +(1 row) + +ALTER SEQUENCE sequence_test2 RESTART WITH 24 + INCREMENT BY 4 MAXVALUE 36 MINVALUE 5 CYCLE; +SELECT nextval('sequence_test2'); + nextval +--------- + 24 +(1 row) + +SELECT nextval('sequence_test2'); + nextval +--------- + 28 +(1 row) + +SELECT nextval('sequence_test2'); + nextval +--------- + 32 +(1 row) + +SELECT nextval('sequence_test2'); + nextval +--------- + 36 +(1 row) + +SELECT nextval('sequence_test2'); + nextval +--------- + 5 +(1 row) + +ALTER SEQUENCE sequence_test2 RESTART; +SELECT nextval('sequence_test2'); + nextval +--------- + 32 +(1 row) + +SELECT nextval('sequence_test2'); + nextval +--------- + 36 +(1 row) + +SELECT nextval('sequence_test2'); + nextval +--------- + 5 +(1 row) + +-- Test comments +COMMENT ON SEQUENCE asdf IS 'won''t work'; +ERROR: relation "asdf" does not exist +COMMENT ON SEQUENCE sequence_test2 IS 'will work'; +COMMENT ON SEQUENCE sequence_test2 IS NULL; +-- Test lastval() +CREATE SEQUENCE seq; +SELECT nextval('seq'); + nextval +--------- + 1 +(1 row) + +SELECT lastval(); + lastval +--------- + 1 +(1 row) + +SELECT setval('seq', 99); + setval +-------- + 99 +(1 row) + +SELECT lastval(); + lastval +--------- + 99 +(1 row) + +CREATE SEQUENCE seq2; +SELECT nextval('seq2'); + nextval +--------- + 1 +(1 row) + +SELECT lastval(); + lastval +--------- + 1 +(1 row) + +DROP SEQUENCE seq2; +-- should fail +SELECT lastval(); +ERROR: lastval is not yet defined in this session +CREATE USER seq_user; +BEGIN; +SET LOCAL SESSION AUTHORIZATION seq_user; +CREATE SEQUENCE seq3; +SELECT nextval('seq3'); + nextval +--------- + 1 +(1 row) + +REVOKE ALL ON seq3 FROM seq_user; +SELECT lastval(); +ERROR: permission denied for sequence seq3 +ROLLBACK; +DROP USER seq_user; +DROP SEQUENCE seq; ----------------------------------------------------------------------- Summary of changes: src/backend/commands/sequence.c | 18 +++++- .../expected/{sequence.out => sequence_2.out} | 59 ++++++++++++-------- 2 files changed, 51 insertions(+), 26 deletions(-) copy src/test/regress/expected/{sequence.out => sequence_2.out} (77%) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-15 04:25:27
|
Project "Postgres-XC". The branch, master has been updated via 8671a6ea9e630d8f4f60126a79f084ada4eb6280 (commit) from 820571e184fb6ae4dd4e63f14724afab283112e2 (commit) - Log ----------------------------------------------------------------- commit 8671a6ea9e630d8f4f60126a79f084ada4eb6280 Author: Michael P <mic...@us...> Date: Fri Apr 15 13:20:48 2011 +0900 Fix for bug 3287052: EXECUTE DIRECT broken on Coordinator There was an issue with type name that could not be sent from a backend Coordinator. diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c index 3458247..a247616 100644 --- a/src/backend/access/common/printtup.c +++ b/src/backend/access/common/printtup.c @@ -194,10 +194,10 @@ SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist, int16 *formats) #ifdef PGXC /* - * Send the type name from a Postgres-XC Datanode backend. + * Send the type name from a Postgres-XC backend node. * This preserves from OID inconsistencies as architecture is shared nothing. */ - if (IS_PGXC_DATANODE && IsConnFromCoord()) + if (IsConnFromCoord()) { char *typename; typename = get_typename(atttypid); ----------------------------------------------------------------------- Summary of changes: src/backend/access/common/printtup.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-15 04:07:19
|
Project "Postgres-XC". The branch, master has been updated via 820571e184fb6ae4dd4e63f14724afab283112e2 (commit) from 5e7b541eb0ae25bc673523fb95c52880337ecd41 (commit) - Log ----------------------------------------------------------------- commit 820571e184fb6ae4dd4e63f14724afab283112e2 Author: Michael P <mic...@us...> Date: Fri Apr 15 13:01:29 2011 +0900 Fix for bug 3231445: COPY TO error when combining data The origin of this bug was round robin table. In the case of COPY TO, connections to all the datanodes of the table are necessary but it happened that only one node was picked up. COPY can be applied on a single node only for COPY TO under a replicated table. Patch written by rahuahua diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 15f97a1..613d5ff 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -3881,15 +3881,22 @@ build_copy_statement(CopyState cstate, List *attnamelist, pPartByCol = GetRelationDistColumn(cstate->rel_loc); if (cstate->rel_loc) { - if (is_from || pPartByCol) - exec_nodes->nodelist = list_copy(cstate->rel_loc->nodeList); + /* + * Pick up one node only + * This case corresponds to a replicated table with COPY TO + * + * PGXCTODO: this is true as long as subset of nodes is not + * supported for tables. In this case, we need one node + * in the node list associated to the table. + */ + if (!is_from && cstate->rel_loc->locatorType == 'R') + exec_nodes->nodelist = GetAnyDataNode(); else { /* - * Pick up one node only - * This case corresponds to a replicated table with COPY TO + * All nodes necessary */ - exec_nodes->nodelist = GetAnyDataNode(); + exec_nodes->nodelist = list_copy(cstate->rel_loc->nodeList); } } ----------------------------------------------------------------------- Summary of changes: src/backend/commands/copy.c | 17 ++++++++++++----- 1 files changed, 12 insertions(+), 5 deletions(-) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-14 06:54:18
|
Project "Postgres-XC". The branch, master has been updated via 5e7b541eb0ae25bc673523fb95c52880337ecd41 (commit) from 5d185a9f610af8043b6b528bc619151fea71ba9b (commit) - Log ----------------------------------------------------------------- commit 5e7b541eb0ae25bc673523fb95c52880337ecd41 Author: Michael P <mic...@us...> Date: Thu Apr 14 15:49:42 2011 +0900 Fix for regression test polymorphism and opr_sanity Aggregates needs a ctype, TEMP tables are not yet supported. So those outputs are OK. An ORDER BY is added in a test case of opr_sanity to have consistent results whatever the cluster configuration. diff --git a/src/test/regress/expected/opr_sanity_1.out b/src/test/regress/expected/opr_sanity_1.out new file mode 100644 index 0000000..885cb13 --- /dev/null +++ b/src/test/regress/expected/opr_sanity_1.out @@ -0,0 +1,1219 @@ +-- +-- OPR_SANITY +-- Sanity checks for common errors in making operator/procedure system tables: +-- pg_operator, pg_proc, pg_cast, pg_aggregate, pg_am, +-- pg_amop, pg_amproc, pg_opclass, pg_opfamily. +-- +-- None of the SELECTs here should ever find any matching entries, +-- so the expected output is easy to maintain ;-). +-- A test failure indicates someone messed up an entry in the system tables. +-- +-- NB: we assume the oidjoins test will have caught any dangling links, +-- that is OID or REGPROC fields that are not zero and do not match some +-- row in the linked-to table. However, if we want to enforce that a link +-- field can't be 0, we have to check it here. +-- +-- NB: run this test earlier than the create_operator test, because +-- that test creates some bogus operators... +-- Helper functions to deal with cases where binary-coercible matches are +-- allowed. +-- This should match IsBinaryCoercible() in parse_coerce.c. +create function binary_coercible(oid, oid) returns bool as $$ +SELECT ($1 = $2) OR + EXISTS(select 1 from pg_catalog.pg_cast where + castsource = $1 and casttarget = $2 and + castmethod = 'b' and castcontext = 'i') OR + ($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND + EXISTS(select 1 from pg_catalog.pg_type where + oid = $1 and typelem != 0 and typlen = -1)) +$$ language sql strict stable; +-- This one ignores castcontext, so it considers only physical equivalence +-- and not whether the coercion can be invoked implicitly. +create function physically_coercible(oid, oid) returns bool as $$ +SELECT ($1 = $2) OR + EXISTS(select 1 from pg_catalog.pg_cast where + castsource = $1 and casttarget = $2 and + castmethod = 'b') OR + ($2 = 'pg_catalog.anyarray'::pg_catalog.regtype AND + EXISTS(select 1 from pg_catalog.pg_type where + oid = $1 and typelem != 0 and typlen = -1)) +$$ language sql strict stable; +-- **************** pg_proc **************** +-- Look for illegal values in pg_proc fields. +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE p1.prolang = 0 OR p1.prorettype = 0 OR + p1.pronargs < 0 OR + p1.pronargdefaults < 0 OR + p1.pronargdefaults > p1.pronargs OR + array_lower(p1.proargtypes, 1) != 0 OR + array_upper(p1.proargtypes, 1) != p1.pronargs-1 OR + 0::oid = ANY (p1.proargtypes) OR + procost <= 0 OR + CASE WHEN proretset THEN prorows <= 0 ELSE prorows != 0 END; + oid | proname +-----+--------- +(0 rows) + +-- prosrc should never be null or empty +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE prosrc IS NULL OR prosrc = '' OR prosrc = '-'; + oid | proname +-----+--------- +(0 rows) + +-- proiswindow shouldn't be set together with proisagg or proretset +SELECT p1.oid, p1.proname +FROM pg_proc AS p1 +WHERE proiswindow AND (proisagg OR proretset); + oid | proname +-----+--------- +(0 rows) + +-- pronargdefaults should be 0 iff proargdefaults is null +SELECT p1.oid, p1.proname +FROM pg_proc AS p1 +WHERE (pronargdefaults <> 0) != (proargdefaults IS NOT NULL); + oid | proname +-----+--------- +(0 rows) + +-- probin should be non-empty for C functions, null everywhere else +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE prolang = 13 AND (probin IS NULL OR probin = '' OR probin = '-'); + oid | proname +-----+--------- +(0 rows) + +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE prolang != 13 AND probin IS NOT NULL; + oid | proname +-----+--------- +(0 rows) + +-- Look for conflicting proc definitions (same names and input datatypes). +-- (This test should be dead code now that we have the unique index +-- pg_proc_proname_args_nsp_index, but I'll leave it in anyway.) +SELECT p1.oid, p1.proname, p2.oid, p2.proname +FROM pg_proc AS p1, pg_proc AS p2 +WHERE p1.oid != p2.oid AND + p1.proname = p2.proname AND + p1.pronargs = p2.pronargs AND + p1.proargtypes = p2.proargtypes; + oid | proname | oid | proname +-----+---------+-----+--------- +(0 rows) + +-- Considering only built-in procs (prolang = 12), look for multiple uses +-- of the same internal function (ie, matching prosrc fields). It's OK to +-- have several entries with different pronames for the same internal function, +-- but conflicts in the number of arguments and other critical items should +-- be complained of. (We don't check data types here; see next query.) +-- Note: ignore aggregate functions here, since they all point to the same +-- dummy built-in function. +SELECT p1.oid, p1.proname, p2.oid, p2.proname +FROM pg_proc AS p1, pg_proc AS p2 +WHERE p1.oid < p2.oid AND + p1.prosrc = p2.prosrc AND + p1.prolang = 12 AND p2.prolang = 12 AND + (p1.proisagg = false OR p2.proisagg = false) AND + (p1.prolang != p2.prolang OR + p1.proisagg != p2.proisagg OR + p1.prosecdef != p2.prosecdef OR + p1.proisstrict != p2.proisstrict OR + p1.proretset != p2.proretset OR + p1.provolatile != p2.provolatile OR + p1.pronargs != p2.pronargs); + oid | proname | oid | proname +-----+---------+-----+--------- +(0 rows) + +-- Look for uses of different type OIDs in the argument/result type fields +-- for different aliases of the same built-in function. +-- This indicates that the types are being presumed to be binary-equivalent, +-- or that the built-in function is prepared to deal with different types. +-- That's not wrong, necessarily, but we make lists of all the types being +-- so treated. Note that the expected output of this part of the test will +-- need to be modified whenever new pairs of types are made binary-equivalent, +-- or when new polymorphic built-in functions are added! +-- Note: ignore aggregate functions here, since they all point to the same +-- dummy built-in function. +SELECT DISTINCT p1.prorettype, p2.prorettype +FROM pg_proc AS p1, pg_proc AS p2 +WHERE p1.oid != p2.oid AND + p1.prosrc = p2.prosrc AND + p1.prolang = 12 AND p2.prolang = 12 AND + NOT p1.proisagg AND NOT p2.proisagg AND + (p1.prorettype < p2.prorettype) +ORDER BY 1, 2; + prorettype | prorettype +------------+------------ + 25 | 1043 + 1114 | 1184 +(2 rows) + +SELECT DISTINCT p1.proargtypes[0], p2.proargtypes[0] +FROM pg_proc AS p1, pg_proc AS p2 +WHERE p1.oid != p2.oid AND + p1.prosrc = p2.prosrc AND + p1.prolang = 12 AND p2.prolang = 12 AND + NOT p1.proisagg AND NOT p2.proisagg AND + (p1.proargtypes[0] < p2.proargtypes[0]) +ORDER BY 1, 2; + proargtypes | proargtypes +-------------+------------- + 25 | 1042 + 25 | 1043 + 1114 | 1184 + 1560 | 1562 + 2277 | 2283 +(5 rows) + +SELECT DISTINCT p1.proargtypes[1], p2.proargtypes[1] +FROM pg_proc AS p1, pg_proc AS p2 +WHERE p1.oid != p2.oid AND + p1.prosrc = p2.prosrc AND + p1.prolang = 12 AND p2.prolang = 12 AND + NOT p1.proisagg AND NOT p2.proisagg AND + (p1.proargtypes[1] < p2.proargtypes[1]) +ORDER BY 1, 2; + proargtypes | proargtypes +-------------+------------- + 23 | 28 + 1114 | 1184 + 1560 | 1562 + 2277 | 2283 +(4 rows) + +SELECT DISTINCT p1.proargtypes[2], p2.proargtypes[2] +FROM pg_proc AS p1, pg_proc AS p2 +WHERE p1.oid != p2.oid AND + p1.prosrc = p2.prosrc AND + p1.prolang = 12 AND p2.prolang = 12 AND + NOT p1.proisagg AND NOT p2.proisagg AND + (p1.proargtypes[2] < p2.proargtypes[2]) +ORDER BY 1, 2; + proargtypes | proargtypes +-------------+------------- + 1114 | 1184 +(1 row) + +SELECT DISTINCT p1.proargtypes[3], p2.proargtypes[3] +FROM pg_proc AS p1, pg_proc AS p2 +WHERE p1.oid != p2.oid AND + p1.prosrc = p2.prosrc AND + p1.prolang = 12 AND p2.prolang = 12 AND + NOT p1.proisagg AND NOT p2.proisagg AND + (p1.proargtypes[3] < p2.proargtypes[3]) +ORDER BY 1, 2; + proargtypes | proargtypes +-------------+------------- + 1114 | 1184 +(1 row) + +SELECT DISTINCT p1.proargtypes[4], p2.proargtypes[4] +FROM pg_proc AS p1, pg_proc AS p2 +WHERE p1.oid != p2.oid AND + p1.prosrc = p2.prosrc AND + p1.prolang = 12 AND p2.prolang = 12 AND + NOT p1.proisagg AND NOT p2.proisagg AND + (p1.proargtypes[4] < p2.proargtypes[4]) +ORDER BY 1, 2; + proargtypes | proargtypes +-------------+------------- +(0 rows) + +SELECT DISTINCT p1.proargtypes[5], p2.proargtypes[5] +FROM pg_proc AS p1, pg_proc AS p2 +WHERE p1.oid != p2.oid AND + p1.prosrc = p2.prosrc AND + p1.prolang = 12 AND p2.prolang = 12 AND + NOT p1.proisagg AND NOT p2.proisagg AND + (p1.proargtypes[5] < p2.proargtypes[5]) +ORDER BY 1, 2; + proargtypes | proargtypes +-------------+------------- +(0 rows) + +SELECT DISTINCT p1.proargtypes[6], p2.proargtypes[6] +FROM pg_proc AS p1, pg_proc AS p2 +WHERE p1.oid != p2.oid AND + p1.prosrc = p2.prosrc AND + p1.prolang = 12 AND p2.prolang = 12 AND + NOT p1.proisagg AND NOT p2.proisagg AND + (p1.proargtypes[6] < p2.proargtypes[6]) +ORDER BY 1, 2; + proargtypes | proargtypes +-------------+------------- +(0 rows) + +SELECT DISTINCT p1.proargtypes[7], p2.proargtypes[7] +FROM pg_proc AS p1, pg_proc AS p2 +WHERE p1.oid != p2.oid AND + p1.prosrc = p2.prosrc AND + p1.prolang = 12 AND p2.prolang = 12 AND + NOT p1.proisagg AND NOT p2.proisagg AND + (p1.proargtypes[7] < p2.proargtypes[7]) +ORDER BY 1, 2; + proargtypes | proargtypes +-------------+------------- +(0 rows) + +-- Look for functions that return type "internal" and do not have any +-- "internal" argument. Such a function would be a security hole since +-- it might be used to call an internal function from an SQL command. +-- As of 7.3 this query should find only internal_in. +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE p1.prorettype = 'internal'::regtype AND NOT + 'internal'::regtype = ANY (p1.proargtypes); + oid | proname +------+------------- + 2304 | internal_in +(1 row) + +-- Check for length inconsistencies between the various argument-info arrays. +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE proallargtypes IS NOT NULL AND + array_length(proallargtypes,1) < array_length(proargtypes,1); + oid | proname +-----+--------- +(0 rows) + +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE proargmodes IS NOT NULL AND + array_length(proargmodes,1) < array_length(proargtypes,1); + oid | proname +-----+--------- +(0 rows) + +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE proargnames IS NOT NULL AND + array_length(proargnames,1) < array_length(proargtypes,1); + oid | proname +-----+--------- +(0 rows) + +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE proallargtypes IS NOT NULL AND proargmodes IS NOT NULL AND + array_length(proallargtypes,1) <> array_length(proargmodes,1); + oid | proname +-----+--------- +(0 rows) + +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE proallargtypes IS NOT NULL AND proargnames IS NOT NULL AND + array_length(proallargtypes,1) <> array_length(proargnames,1); + oid | proname +-----+--------- +(0 rows) + +SELECT p1.oid, p1.proname +FROM pg_proc as p1 +WHERE proargmodes IS NOT NULL AND proargnames IS NOT NULL AND + array_length(proargmodes,1) <> array_length(proargnames,1); + oid | proname +-----+--------- +(0 rows) + +-- **************** pg_cast **************** +-- Catch bogus values in pg_cast columns (other than cases detected by +-- oidjoins test). +SELECT * +FROM pg_cast c +WHERE castsource = 0 OR casttarget = 0 OR castcontext NOT IN ('e', 'a', 'i') + OR castmethod NOT IN ('f', 'b' ,'i'); + castsource | casttarget | castfunc | castcontext | castmethod +------------+------------+----------+-------------+------------ +(0 rows) + +-- Check that castfunc is nonzero only for cast methods that need a function, +-- and zero otherwise +SELECT * +FROM pg_cast c +WHERE (castmethod = 'f' AND castfunc = 0) + OR (castmethod IN ('b', 'i') AND castfunc <> 0); + castsource | casttarget | castfunc | castcontext | castmethod +------------+------------+----------+-------------+------------ +(0 rows) + +-- Look for casts to/from the same type that aren't length coercion functions. +-- (We assume they are length coercions if they take multiple arguments.) +-- Such entries are not necessarily harmful, but they are useless. +SELECT * +FROM pg_cast c +WHERE castsource = casttarget AND castfunc = 0; + castsource | casttarget | castfunc | castcontext | castmethod +------------+------------+----------+-------------+------------ +(0 rows) + +SELECT c.* +FROM pg_cast c, pg_proc p +WHERE c.castfunc = p.oid AND p.pronargs < 2 AND castsource = casttarget; + castsource | casttarget | castfunc | castcontext | castmethod +------------+------------+----------+-------------+------------ +(0 rows) + +-- Look for cast functions that don't have the right signature. The +-- argument and result types in pg_proc must be the same as, or binary +-- compatible with, what it says in pg_cast. +-- As a special case, we allow casts from CHAR(n) that use functions +-- declared to take TEXT. This does not pass the binary-coercibility test +-- because CHAR(n)-to-TEXT normally invokes rtrim(). However, the results +-- are the same, so long as the function is one that ignores trailing blanks. +SELECT c.* +FROM pg_cast c, pg_proc p +WHERE c.castfunc = p.oid AND + (p.pronargs < 1 OR p.pronargs > 3 + OR NOT (binary_coercible(c.castsource, p.proargtypes[0]) + OR (c.castsource = 'character'::regtype AND + p.proargtypes[0] = 'text'::regtype)) + OR NOT binary_coercible(p.prorettype, c.casttarget)); + castsource | casttarget | castfunc | castcontext | castmethod +------------+------------+----------+-------------+------------ +(0 rows) + +SELECT c.* +FROM pg_cast c, pg_proc p +WHERE c.castfunc = p.oid AND + ((p.pronargs > 1 AND p.proargtypes[1] != 'int4'::regtype) OR + (p.pronargs > 2 AND p.proargtypes[2] != 'bool'::regtype)); + castsource | casttarget | castfunc | castcontext | castmethod +------------+------------+----------+-------------+------------ +(0 rows) + +-- Look for binary compatible casts that do not have the reverse +-- direction registered as well, or where the reverse direction is not +-- also binary compatible. This is legal, but usually not intended. +-- As of 7.4, this finds the casts from text and varchar to bpchar, because +-- those are binary-compatible while the reverse way goes through rtrim(). +-- As of 8.2, this finds the cast from cidr to inet, because that is a +-- trivial binary coercion while the other way goes through inet_to_cidr(). +-- As of 8.3, this finds the casts from xml to text, varchar, and bpchar, +-- because those are binary-compatible while the reverse goes through +-- texttoxml(), which does an XML syntax check. +SELECT * +FROM pg_cast c +WHERE c.castmethod = 'b' AND + NOT EXISTS (SELECT 1 FROM pg_cast k + WHERE k.castmethod = 'b' AND + k.castsource = c.casttarget AND + k.casttarget = c.castsource); + castsource | casttarget | castfunc | castcontext | castmethod +------------+------------+----------+-------------+------------ + 25 | 1042 | 0 | i | b + 1043 | 1042 | 0 | i | b + 650 | 869 | 0 | i | b + 142 | 25 | 0 | a | b + 142 | 1043 | 0 | a | b + 142 | 1042 | 0 | a | b +(6 rows) + +-- **************** pg_operator **************** +-- Look for illegal values in pg_operator fields. +SELECT p1.oid, p1.oprname +FROM pg_operator as p1 +WHERE (p1.oprkind != 'b' AND p1.oprkind != 'l' AND p1.oprkind != 'r') OR + p1.oprresult = 0 OR p1.oprcode = 0; + oid | oprname +-----+--------- +(0 rows) + +-- Look for missing or unwanted operand types +SELECT p1.oid, p1.oprname +FROM pg_operator as p1 +WHERE (p1.oprleft = 0 and p1.oprkind != 'l') OR + (p1.oprleft != 0 and p1.oprkind = 'l') OR + (p1.oprright = 0 and p1.oprkind != 'r') OR + (p1.oprright != 0 and p1.oprkind = 'r'); + oid | oprname +-----+--------- +(0 rows) + +-- Look for conflicting operator definitions (same names and input datatypes). +SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode +FROM pg_operator AS p1, pg_operator AS p2 +WHERE p1.oid != p2.oid AND + p1.oprname = p2.oprname AND + p1.oprkind = p2.oprkind AND + p1.oprleft = p2.oprleft AND + p1.oprright = p2.oprright; + oid | oprcode | oid | oprcode +-----+---------+-----+--------- +(0 rows) + +-- Look for commutative operators that don't commute. +-- DEFINITIONAL NOTE: If A.oprcom = B, then x A y has the same result as y B x. +-- We expect that B will always say that B.oprcom = A as well; that's not +-- inherently essential, but it would be inefficient not to mark it so. +SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode +FROM pg_operator AS p1, pg_operator AS p2 +WHERE p1.oprcom = p2.oid AND + (p1.oprkind != 'b' OR + p1.oprleft != p2.oprright OR + p1.oprright != p2.oprleft OR + p1.oprresult != p2.oprresult OR + p1.oid != p2.oprcom); + oid | oprcode | oid | oprcode +-----+---------+-----+--------- +(0 rows) + +-- Look for negatory operators that don't agree. +-- DEFINITIONAL NOTE: If A.oprnegate = B, then both A and B must yield +-- boolean results, and (x A y) == ! (x B y), or the equivalent for +-- single-operand operators. +-- We expect that B will always say that B.oprnegate = A as well; that's not +-- inherently essential, but it would be inefficient not to mark it so. +-- Also, A and B had better not be the same operator. +SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode +FROM pg_operator AS p1, pg_operator AS p2 +WHERE p1.oprnegate = p2.oid AND + (p1.oprkind != p2.oprkind OR + p1.oprleft != p2.oprleft OR + p1.oprright != p2.oprright OR + p1.oprresult != 'bool'::regtype OR + p2.oprresult != 'bool'::regtype OR + p1.oid != p2.oprnegate OR + p1.oid = p2.oid); + oid | oprcode | oid | oprcode +-----+---------+-----+--------- +(0 rows) + +-- A mergejoinable or hashjoinable operator must be binary, must return +-- boolean, and must have a commutator (itself, unless it's a cross-type +-- operator). +SELECT p1.oid, p1.oprname FROM pg_operator AS p1 +WHERE (p1.oprcanmerge OR p1.oprcanhash) AND NOT + (p1.oprkind = 'b' AND p1.oprresult = 'bool'::regtype AND p1.oprcom != 0); + oid | oprname +-----+--------- +(0 rows) + +-- What's more, the commutator had better be mergejoinable/hashjoinable too. +SELECT p1.oid, p1.oprname, p2.oid, p2.oprname +FROM pg_operator AS p1, pg_operator AS p2 +WHERE p1.oprcom = p2.oid AND + (p1.oprcanmerge != p2.oprcanmerge OR + p1.oprcanhash != p2.oprcanhash); + oid | oprname | oid | oprname +-----+---------+-----+--------- +(0 rows) + +-- Mergejoinable operators should appear as equality members of btree index +-- opfamilies. +SELECT p1.oid, p1.oprname +FROM pg_operator AS p1 +WHERE p1.oprcanmerge AND NOT EXISTS + (SELECT 1 FROM pg_amop + WHERE amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') AND + amopopr = p1.oid AND amopstrategy = 3); + oid | oprname +-----+--------- +(0 rows) + +-- And the converse. +SELECT p1.oid, p1.oprname, p.amopfamily +FROM pg_operator AS p1, pg_amop p +WHERE amopopr = p1.oid + AND amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') + AND amopstrategy = 3 + AND NOT p1.oprcanmerge; + oid | oprname | amopfamily +-----+---------+------------ +(0 rows) + +-- Hashable operators should appear as members of hash index opfamilies. +SELECT p1.oid, p1.oprname +FROM pg_operator AS p1 +WHERE p1.oprcanhash AND NOT EXISTS + (SELECT 1 FROM pg_amop + WHERE amopmethod = (SELECT oid FROM pg_am WHERE amname = 'hash') AND + amopopr = p1.oid AND amopstrategy = 1); + oid | oprname +-----+--------- +(0 rows) + +-- And the converse. +SELECT p1.oid, p1.oprname, p.amopfamily +FROM pg_operator AS p1, pg_amop p +WHERE amopopr = p1.oid + AND amopmethod = (SELECT oid FROM pg_am WHERE amname = 'hash') + AND NOT p1.oprcanhash; + oid | oprname | amopfamily +-----+---------+------------ +(0 rows) + +-- Check that each operator defined in pg_operator matches its oprcode entry +-- in pg_proc. Easiest to do this separately for each oprkind. +SELECT p1.oid, p1.oprname, p2.oid, p2.proname +FROM pg_operator AS p1, pg_proc AS p2 +WHERE p1.oprcode = p2.oid AND + p1.oprkind = 'b' AND + (p2.pronargs != 2 + OR NOT binary_coercible(p2.prorettype, p1.oprresult) + OR NOT binary_coercible(p1.oprleft, p2.proargtypes[0]) + OR NOT binary_coercible(p1.oprright, p2.proargtypes[1])); + oid | oprname | oid | proname +-----+---------+-----+--------- +(0 rows) + +SELECT p1.oid, p1.oprname, p2.oid, p2.proname +FROM pg_operator AS p1, pg_proc AS p2 +WHERE p1.oprcode = p2.oid AND + p1.oprkind = 'l' AND + (p2.pronargs != 1 + OR NOT binary_coercible(p2.prorettype, p1.oprresult) + OR NOT binary_coercible(p1.oprright, p2.proargtypes[0]) + OR p1.oprleft != 0); + oid | oprname | oid | proname +-----+---------+-----+--------- +(0 rows) + +SELECT p1.oid, p1.oprname, p2.oid, p2.proname +FROM pg_operator AS p1, pg_proc AS p2 +WHERE p1.oprcode = p2.oid AND + p1.oprkind = 'r' AND + (p2.pronargs != 1 + OR NOT binary_coercible(p2.prorettype, p1.oprresult) + OR NOT binary_coercible(p1.oprleft, p2.proargtypes[0]) + OR p1.oprright != 0); + oid | oprname | oid | proname +-----+---------+-----+--------- +(0 rows) + +-- If the operator is mergejoinable or hashjoinable, its underlying function +-- should not be volatile. +SELECT p1.oid, p1.oprname, p2.oid, p2.proname +FROM pg_operator AS p1, pg_proc AS p2 +WHERE p1.oprcode = p2.oid AND + (p1.oprcanmerge OR p1.oprcanhash) AND + p2.provolatile = 'v'; + oid | oprname | oid | proname +-----+---------+-----+--------- +(0 rows) + +-- If oprrest is set, the operator must return boolean, +-- and it must link to a proc with the right signature +-- to be a restriction selectivity estimator. +-- The proc signature we want is: float8 proc(internal, oid, internal, int4) +SELECT p1.oid, p1.oprname, p2.oid, p2.proname +FROM pg_operator AS p1, pg_proc AS p2 +WHERE p1.oprrest = p2.oid AND + (p1.oprresult != 'bool'::regtype OR + p2.prorettype != 'float8'::regtype OR p2.proretset OR + p2.pronargs != 4 OR + p2.proargtypes[0] != 'internal'::regtype OR + p2.proargtypes[1] != 'oid'::regtype OR + p2.proargtypes[2] != 'internal'::regtype OR + p2.proargtypes[3] != 'int4'::regtype); + oid | oprname | oid | proname +-----+---------+-----+--------- +(0 rows) + +-- If oprjoin is set, the operator must be a binary boolean op, +-- and it must link to a proc with the right signature +-- to be a join selectivity estimator. +-- The proc signature we want is: float8 proc(internal, oid, internal, int2, internal) +-- (Note: the old signature with only 4 args is still allowed, but no core +-- estimator should be using it.) +SELECT p1.oid, p1.oprname, p2.oid, p2.proname +FROM pg_operator AS p1, pg_proc AS p2 +WHERE p1.oprjoin = p2.oid AND + (p1.oprkind != 'b' OR p1.oprresult != 'bool'::regtype OR + p2.prorettype != 'float8'::regtype OR p2.proretset OR + p2.pronargs != 5 OR + p2.proargtypes[0] != 'internal'::regtype OR + p2.proargtypes[1] != 'oid'::regtype OR + p2.proargtypes[2] != 'internal'::regtype OR + p2.proargtypes[3] != 'int2'::regtype OR + p2.proargtypes[4] != 'internal'::regtype); + oid | oprname | oid | proname +-----+---------+-----+--------- +(0 rows) + +-- **************** pg_aggregate **************** +-- Look for illegal values in pg_aggregate fields. +SELECT ctid, aggfnoid::oid +FROM pg_aggregate as p1 +WHERE aggfnoid = 0 OR aggtransfn = 0 OR aggtranstype = 0; + ctid | aggfnoid +------+---------- +(0 rows) + +-- Make sure the matching pg_proc entry is sensible, too. +SELECT a.aggfnoid::oid, p.proname +FROM pg_aggregate as a, pg_proc as p +WHERE a.aggfnoid = p.oid AND + (NOT p.proisagg OR p.proretset); + aggfnoid | proname +----------+--------- +(0 rows) + +-- Make sure there are no proisagg pg_proc entries without matches. +SELECT oid, proname +FROM pg_proc as p +WHERE p.proisagg AND + NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid); + oid | proname +------+------------ + 2335 | array_agg + 3538 | string_agg +(2 rows) + +-- If there is no finalfn then the output type must be the transtype. +SELECT a.aggfnoid::oid, p.proname +FROM pg_aggregate as a, pg_proc as p +WHERE a.aggfnoid = p.oid AND + a.aggfinalfn = 0 AND p.prorettype != a.aggtranstype; + aggfnoid | proname +----------+--------- +(0 rows) + +-- Cross-check transfn against its entry in pg_proc. +-- NOTE: use physically_coercible here, not binary_coercible, because +-- max and min on abstime are implemented using int4larger/int4smaller. +SELECT a.aggfnoid::oid, p.proname, ptr.oid, ptr.proname +FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS ptr +WHERE a.aggfnoid = p.oid AND + a.aggtransfn = ptr.oid AND + (ptr.proretset + OR NOT (ptr.pronargs = p.pronargs + 1) + OR NOT physically_coercible(ptr.prorettype, a.aggtranstype) + OR NOT physically_coercible(a.aggtranstype, ptr.proargtypes[0]) + OR (p.pronargs > 0 AND + NOT physically_coercible(p.proargtypes[0], ptr.proargtypes[1])) + OR (p.pronargs > 1 AND + NOT physically_coercible(p.proargtypes[1], ptr.proargtypes[2])) + OR (p.pronargs > 2 AND + NOT physically_coercible(p.proargtypes[2], ptr.proargtypes[3])) + -- we could carry the check further, but that's enough for now + ); + aggfnoid | proname | oid | proname +----------+---------+-----+--------- +(0 rows) + +-- Cross-check finalfn (if present) against its entry in pg_proc. +SELECT a.aggfnoid::oid, p.proname, pfn.oid, pfn.proname +FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS pfn +WHERE a.aggfnoid = p.oid AND + a.aggfinalfn = pfn.oid AND + (pfn.proretset + OR NOT binary_coercible(pfn.prorettype, p.prorettype) + OR pfn.pronargs != 1 + OR NOT binary_coercible(a.aggtranstype, pfn.proargtypes[0])); + aggfnoid | proname | oid | proname +----------+------------+------+--------- + 2108 | sum | 1779 | int8 + 2109 | sum | 1779 | int8 + 2147 | count | 1779 | int8 + 2803 | count | 1779 | int8 + 2818 | regr_count | 1779 | int8 +(5 rows) + +-- If transfn is strict then either initval should be non-NULL, or +-- input type should match transtype so that the first non-null input +-- can be assigned as the state value. +SELECT a.aggfnoid::oid, p.proname, ptr.oid, ptr.proname +FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS ptr +WHERE a.aggfnoid = p.oid AND + a.aggtransfn = ptr.oid AND ptr.proisstrict AND + a.agginitval IS NULL AND + NOT binary_coercible(p.proargtypes[0], a.aggtranstype); + aggfnoid | proname | oid | proname +----------+---------+-----+--------- +(0 rows) + +-- Cross-check aggsortop (if present) against pg_operator. +-- We expect to find only "<" for "min" and ">" for "max". +SELECT DISTINCT proname, oprname +FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p +WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid +ORDER BY 1; + proname | oprname +---------+--------- + max | > + min | < +(2 rows) + +-- Check datatypes match +SELECT a.aggfnoid::oid, o.oid +FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p +WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND + (oprkind != 'b' OR oprresult != 'boolean'::regtype + OR oprleft != p.proargtypes[0] OR oprright != p.proargtypes[0]); + aggfnoid | oid +----------+----- +(0 rows) + +-- Check operator is a suitable btree opfamily member +SELECT a.aggfnoid::oid, o.oid +FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p +WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND + NOT EXISTS(SELECT 1 FROM pg_amop + WHERE amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') + AND amopopr = o.oid + AND amoplefttype = o.oprleft + AND amoprighttype = o.oprright); + aggfnoid | oid +----------+----- +(0 rows) + +-- Check correspondence of btree strategies and names +SELECT DISTINCT proname, oprname, amopstrategy +FROM pg_operator AS o, pg_aggregate AS a, pg_proc AS p, + pg_amop as ao +WHERE a.aggfnoid = p.oid AND a.aggsortop = o.oid AND + amopopr = o.oid AND + amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') +ORDER BY 1, 2; + proname | oprname | amopstrategy +---------+---------+-------------- + max | > | 5 + min | < | 1 +(2 rows) + +-- Check that there are not aggregates with the same name and different +-- numbers of arguments. While not technically wrong, we have a project policy +-- to avoid this because it opens the door for confusion in connection with +-- ORDER BY: novices frequently put the ORDER BY in the wrong place. +-- See the fate of the single-argument form of string_agg() for history. +-- The only aggregates that should show up here are count(x) and count(*). +SELECT p1.oid::regprocedure, p2.oid::regprocedure +FROM pg_proc AS p1, pg_proc AS p2 +WHERE p1.oid < p2.oid AND p1.proname = p2.proname AND + p1.proisagg AND p2.proisagg AND + array_dims(p1.proargtypes) != array_dims(p2.proargtypes) +ORDER BY 1; + oid | oid +--------------+--------- + count("any") | count() +(1 row) + +-- For the same reason, aggregates with default arguments are no good. +SELECT oid, proname +FROM pg_proc AS p +WHERE proisagg AND proargdefaults IS NOT NULL; + oid | proname +-----+--------- +(0 rows) + +-- **************** pg_opfamily **************** +-- Look for illegal values in pg_opfamily fields +SELECT p1.oid +FROM pg_opfamily as p1 +WHERE p1.opfmethod = 0 OR p1.opfnamespace = 0; + oid +----- +(0 rows) + +-- **************** pg_opclass **************** +-- Look for illegal values in pg_opclass fields +SELECT p1.oid +FROM pg_opclass AS p1 +WHERE p1.opcmethod = 0 OR p1.opcnamespace = 0 OR p1.opcfamily = 0 + OR p1.opcintype = 0; + oid +----- +(0 rows) + +-- opcmethod must match owning opfamily's opfmethod +SELECT p1.oid, p2.oid +FROM pg_opclass AS p1, pg_opfamily AS p2 +WHERE p1.opcfamily = p2.oid AND p1.opcmethod != p2.opfmethod; + oid | oid +-----+----- +(0 rows) + +-- There should not be multiple entries in pg_opclass with opcdefault true +-- and the same opcmethod/opcintype combination. +SELECT p1.oid, p2.oid +FROM pg_opclass AS p1, pg_opclass AS p2 +WHERE p1.oid != p2.oid AND + p1.opcmethod = p2.opcmethod AND p1.opcintype = p2.opcintype AND + p1.opcdefault AND p2.opcdefault; + oid | oid +-----+----- +(0 rows) + +-- **************** pg_amop **************** +-- Look for illegal values in pg_amop fields +SELECT p1.amopfamily, p1.amopstrategy +FROM pg_amop as p1 +WHERE p1.amopfamily = 0 OR p1.amoplefttype = 0 OR p1.amoprighttype = 0 + OR p1.amopopr = 0 OR p1.amopmethod = 0 OR p1.amopstrategy < 1; + amopfamily | amopstrategy +------------+-------------- +(0 rows) + +-- amoplefttype/amoprighttype must match the operator +SELECT p1.oid, p2.oid +FROM pg_amop AS p1, pg_operator AS p2 +WHERE p1.amopopr = p2.oid AND NOT + (p1.amoplefttype = p2.oprleft AND p1.amoprighttype = p2.oprright); + oid | oid +-----+----- +(0 rows) + +-- amopmethod must match owning opfamily's opfmethod +SELECT p1.oid, p2.oid +FROM pg_amop AS p1, pg_opfamily AS p2 +WHERE p1.amopfamily = p2.oid AND p1.amopmethod != p2.opfmethod; + oid | oid +-----+----- +(0 rows) + +-- Cross-check amopstrategy index against parent AM +SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.amname +FROM pg_amop AS p1, pg_am AS p2 +WHERE p1.amopmethod = p2.oid AND + p1.amopstrategy > p2.amstrategies AND p2.amstrategies <> 0; + amopfamily | amopopr | oid | amname +------------+---------+-----+-------- +(0 rows) + +-- Detect missing pg_amop entries: should have as many strategy operators +-- as AM expects for each datatype combination supported by the opfamily. +-- We can't check this for AMs with variable strategy sets. +SELECT p1.amname, p2.amoplefttype, p2.amoprighttype +FROM pg_am AS p1, pg_amop AS p2 +WHERE p2.amopmethod = p1.oid AND + p1.amstrategies <> 0 AND + p1.amstrategies != (SELECT count(*) FROM pg_amop AS p3 + WHERE p3.amopfamily = p2.amopfamily AND + p3.amoplefttype = p2.amoplefttype AND + p3.amoprighttype = p2.amoprighttype); + amname | amoplefttype | amoprighttype +--------+--------------+--------------- +(0 rows) + +-- Check that amopopr points at a reasonable-looking operator, ie a binary +-- operator yielding boolean. +SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname +FROM pg_amop AS p1, pg_operator AS p2 +WHERE p1.amopopr = p2.oid AND + (p2.oprkind != 'b' OR p2.oprresult != 'bool'::regtype); + amopfamily | amopopr | oid | oprname +------------+---------+-----+--------- +(0 rows) + +-- Make a list of all the distinct operator names being used in particular +-- strategy slots. This is a bit hokey, since the list might need to change +-- in future releases, but it's an effective way of spotting mistakes such as +-- swapping two operators within a family. +SELECT DISTINCT amopmethod, amopstrategy, oprname +FROM pg_amop p1 LEFT JOIN pg_operator p2 ON amopopr = p2.oid +ORDER BY 1, 2, 3; + amopmethod | amopstrategy | oprname +------------+--------------+--------- + 403 | 1 | < + 403 | 1 | ~<~ + 403 | 2 | <= + 403 | 2 | ~<=~ + 403 | 3 | = + 403 | 4 | >= + 403 | 4 | ~>=~ + 403 | 5 | > + 403 | 5 | ~>~ + 405 | 1 | = + 783 | 1 | << + 783 | 1 | @@ + 783 | 2 | &< + 783 | 3 | && + 783 | 4 | &> + 783 | 5 | >> + 783 | 6 | ~= + 783 | 7 | @> + 783 | 8 | <@ + 783 | 9 | &<| + 783 | 10 | <<| + 783 | 10 | <^ + 783 | 11 | >^ + 783 | 11 | |>> + 783 | 12 | |&> + 783 | 13 | ~ + 783 | 14 | @ + 783 | 27 | @> + 783 | 28 | <@ + 783 | 47 | @> + 783 | 48 | <@ + 783 | 67 | @> + 783 | 68 | <@ + 2742 | 1 | && + 2742 | 1 | @@ + 2742 | 2 | @> + 2742 | 2 | @@@ + 2742 | 3 | <@ + 2742 | 4 | = +(39 rows) + +-- Check that all operators linked to by opclass entries have selectivity +-- estimators. This is not absolutely required, but it seems a reasonable +-- thing to insist on for all standard datatypes. +SELECT p1.amopfamily, p1.amopopr, p2.oid, p2.oprname +FROM pg_amop AS p1, pg_operator AS p2 +WHERE p1.amopopr = p2.oid AND + (p2.oprrest = 0 OR p2.oprjoin = 0); + amopfamily | amopopr | oid | oprname +------------+---------+-----+--------- +(0 rows) + +-- Check that each opclass in an opfamily has associated operators, that is +-- ones whose oprleft matches opcintype (possibly by coercion). +SELECT p1.opcname, p1.opcfamily +FROM pg_opclass AS p1 +WHERE NOT EXISTS(SELECT 1 FROM pg_amop AS p2 + WHERE p2.amopfamily = p1.opcfamily + AND binary_coercible(p1.opcintype, p2.amoplefttype)); + opcname | opcfamily +---------+----------- +(0 rows) + +-- Operators that are primary members of opclasses must be immutable (else +-- it suggests that the index ordering isn't fixed). Operators that are +-- cross-type members need only be stable, since they are just shorthands +-- for index probe queries. +SELECT p1.amopfamily, p1.amopopr, p2.oprname, p3.prosrc +FROM pg_amop AS p1, pg_operator AS p2, pg_proc AS p3 +WHERE p1.amopopr = p2.oid AND p2.oprcode = p3.oid AND + p1.amoplefttype = p1.amoprighttype AND + p3.provolatile != 'i'; + amopfamily | amopopr | oprname | prosrc +------------+---------+---------+-------- +(0 rows) + +SELECT p1.amopfamily, p1.amopopr, p2.oprname, p3.prosrc +FROM pg_amop AS p1, pg_operator AS p2, pg_proc AS p3 +WHERE p1.amopopr = p2.oid AND p2.oprcode = p3.oid AND + p1.amoplefttype != p1.amoprighttype AND + p3.provolatile = 'v'; + amopfamily | amopopr | oprname | prosrc +------------+---------+---------+-------- +(0 rows) + +-- Multiple-datatype btree opfamilies should provide closed sets of equality +-- operators; that is if you provide int2 = int4 and int4 = int8 then you +-- should also provide int2 = int8 (and commutators of all these). This is +-- important because the planner tries to deduce additional qual clauses from +-- transitivity of mergejoinable operators. If there are clauses +-- int2var = int4var and int4var = int8var, the planner will want to deduce +-- int2var = int8var ... so there should be a way to represent that. While +-- a missing cross-type operator is now only an efficiency loss rather than +-- an error condition, it still seems reasonable to insist that all built-in +-- opfamilies be complete. +-- check commutative closure +SELECT p1.amoplefttype, p1.amoprighttype +FROM pg_amop AS p1 +WHERE p1.amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') AND + p1.amopstrategy = 3 AND + p1.amoplefttype != p1.amoprighttype AND + NOT EXISTS(SELECT 1 FROM pg_amop p2 WHERE + p2.amopfamily = p1.amopfamily AND + p2.amoplefttype = p1.amoprighttype AND + p2.amoprighttype = p1.amoplefttype AND + p2.amopstrategy = 3); + amoplefttype | amoprighttype +--------------+--------------- +(0 rows) + +-- check transitive closure +SELECT p1.amoplefttype, p1.amoprighttype, p2.amoprighttype +FROM pg_amop AS p1, pg_amop AS p2 +WHERE p1.amopfamily = p2.amopfamily AND + p1.amoprighttype = p2.amoplefttype AND + p1.amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') AND + p2.amopmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') AND + p1.amopstrategy = 3 AND p2.amopstrategy = 3 AND + p1.amoplefttype != p1.amoprighttype AND + p2.amoplefttype != p2.amoprighttype AND + NOT EXISTS(SELECT 1 FROM pg_amop p3 WHERE + p3.amopfamily = p1.amopfamily AND + p3.amoplefttype = p1.amoplefttype AND + p3.amoprighttype = p2.amoprighttype AND + p3.amopstrategy = 3); + amoplefttype | amoprighttype | amoprighttype +--------------+---------------+--------------- +(0 rows) + +-- We also expect that built-in multiple-datatype hash opfamilies provide +-- complete sets of cross-type operators. Again, this isn't required, but +-- it is reasonable to expect it for built-in opfamilies. +-- if same family has x=x and y=y, it should have x=y +SELECT p1.amoplefttype, p2.amoplefttype +FROM pg_amop AS p1, pg_amop AS p2 +WHERE p1.amopfamily = p2.amopfamily AND + p1.amoplefttype = p1.amoprighttype AND + p2.amoplefttype = p2.amoprighttype AND + p1.amopmethod = (SELECT oid FROM pg_am WHERE amname = 'hash') AND + p2.amopmethod = (SELECT oid FROM pg_am WHERE amname = 'hash') AND + p1.amopstrategy = 1 AND p2.amopstrategy = 1 AND + p1.amoplefttype != p2.amoplefttype AND + NOT EXISTS(SELECT 1 FROM pg_amop p3 WHERE + p3.amopfamily = p1.amopfamily AND + p3.amoplefttype = p1.amoplefttype AND + p3.amoprighttype = p2.amoplefttype AND + p3.amopstrategy = 1); + amoplefttype | amoplefttype +--------------+-------------- +(0 rows) + +-- **************** pg_amproc **************** +-- Look for illegal values in pg_amproc fields +SELECT p1.amprocfamily, p1.amprocnum +FROM pg_amproc as p1 +WHERE p1.amprocfamily = 0 OR p1.amproclefttype = 0 OR p1.amprocrighttype = 0 + OR p1.amprocnum < 1 OR p1.amproc = 0; + amprocfamily | amprocnum +--------------+----------- +(0 rows) + +-- Cross-check amprocnum index against parent AM +SELECT p1.amprocfamily, p1.amprocnum, p2.oid, p2.amname +FROM pg_amproc AS p1, pg_am AS p2, pg_opfamily AS p3 +WHERE p1.amprocfamily = p3.oid AND p3.opfmethod = p2.oid AND + p1.amprocnum > p2.amsupport; + amprocfamily | amprocnum | oid | amname +--------------+-----------+-----+-------- +(0 rows) + +-- Detect missing pg_amproc entries: should have as many support functions +-- as AM expects for each datatype combination supported by the opfamily. +-- GIN is a special case because it has an optional support function. +SELECT p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype +FROM pg_am AS p1, pg_opfamily AS p2, pg_amproc AS p3 +WHERE p2.opfmethod = p1.oid AND p3.amprocfamily = p2.oid AND + p1.amname <> 'gin' AND + p1.amsupport != (SELECT count(*) FROM pg_amproc AS p4 + WHERE p4.amprocfamily = p2.oid AND + p4.amproclefttype = p3.amproclefttype AND + p4.amprocrighttype = p3.amprocrighttype); + amname | opfname | amproclefttype | amprocrighttype +--------+---------+----------------+----------------- +(0 rows) + +-- Similar check for GIN, allowing one optional proc +SELECT p1.amname, p2.opfname, p3.amproclefttype, p3.amprocrighttype +FROM pg_am AS p1, pg_opfamily AS p2, pg_amproc AS p3 +WHERE p2.opfmethod = p1.oid AND p3.amprocfamily = p2.oid AND + p1.amname = 'gin' AND + p1.amsupport - 1 > (SELECT count(*) FROM pg_amproc AS p4 + WHERE p4.amprocfamily = p2.oid AND + p4.amproclefttype = p3.amproclefttype AND + p4.amprocrighttype = p3.amprocrighttype); + amname | opfname | amproclefttype | amprocrighttype +--------+---------+----------------+----------------- +(0 rows) + +-- Also, check if there are any pg_opclass entries that don't seem to have +-- pg_amproc support. Again, GIN has to be checked separately. +SELECT amname, opcname, count(*) +FROM pg_am am JOIN pg_opclass op ON opcmethod = am.oid + LEFT JOIN pg_amproc p ON amprocfamily = opcfamily AND + amproclefttype = amprocrighttype AND amproclefttype = opcintype +WHERE am.amname <> 'gin' +GROUP BY amname, amsupport, opcname, amprocfamily +HAVING count(*) != amsupport OR amprocfamily IS NULL; +ERROR: GROUP BY clause is not yet supported +SELECT amname, opcname, count(*) +FROM pg_am am JOIN pg_opclass op ON opcmethod = am.oid + LEFT JOIN pg_amproc p ON amprocfamily = opcfamily AND + amproclefttype = amprocrighttype AND amproclefttype = opcintype +WHERE am.amname = 'gin' +GROUP BY amname, amsupport, opcname, amprocfamily +HAVING count(*) < amsupport - 1 OR amprocfamily IS NULL; +ERROR: GROUP BY clause is not yet supported +-- Unfortunately, we can't check the amproc link very well because the +-- signature of the function may be different for different support routines +-- or different base data types. +-- We can check that all the referenced instances of the same support +-- routine number take the same number of parameters, but that's about it +-- for a general check... +SELECT p1.amprocfamily, p1.amprocnum, + p2.oid, p2.proname, + p3.opfname, + p4.amprocfamily, p4.amprocnum, + p5.oid, p5.proname, + p6.opfname +FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3, + pg_amproc AS p4, pg_proc AS p5, pg_opfamily AS p6 +WHERE p1.amprocfamily = p3.oid AND p4.amprocfamily = p6.oid AND + p3.opfmethod = p6.opfmethod AND p1.amprocnum = p4.amprocnum AND + p1.amproc = p2.oid AND p4.amproc = p5.oid AND + (p2.proretset OR p5.proretset OR p2.pronargs != p5.pronargs); + amprocfamily | amprocnum | oid | proname | opfname | amprocfamily | amprocnum | oid | proname | opfname +--------------+-----------+-----+---------+---------+--------------+-----------+-----+---------+--------- +(0 rows) + +-- For btree, though, we can do better since we know the support routines +-- must be of the form cmp(lefttype, righttype) returns int4. +SELECT p1.amprocfamily, p1.amprocnum, + p2.oid, p2.proname, + p3.opfname +FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3 +WHERE p3.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'btree') + AND p1.amprocfamily = p3.oid AND p1.amproc = p2.oid AND + (amprocnum != 1 + OR proretset + OR prorettype != 'int4'::regtype + OR pronargs != 2 + OR proargtypes[0] != amproclefttype + OR proargtypes[1] != amprocrighttype); + amprocfamily | amprocnum | oid | proname | opfname +--------------+-----------+-----+---------+--------- +(0 rows) + +-- For hash we can also do a little better: the support routines must be +-- of the form hash(lefttype) returns int4. There are several cases where +-- we cheat and use a hash function that is physically compatible with the +-- datatype even though there's no cast, so this check does find a small +-- number of entries. +SELECT p1.amprocfamily, p1.amprocnum, p2.proname, p3.opfname +FROM pg_amproc AS p1, pg_proc AS p2, pg_opfamily AS p3 +WHERE p3.opfmethod = (SELECT oid FROM pg_am WHERE amname = 'hash') + AND p1.amprocfamily = p3.oid AND p1.amproc = p2.oid AND + (amprocnum != 1 + OR proretset + OR prorettype != 'int4'::regtype + OR pronargs != 1 + OR NOT physically_coercible(amproclefttype, proargtypes[0]) + OR amproclefttype != amprocrighttype) +ORDER BY 1; + amprocfamily | amprocnum | proname | opfname +--------------+-----------+----------------+----------------- + 435 | 1 | hashint4 | date_ops + 1999 | 1 | timestamp_hash | timestamptz_ops + 2222 | 1 | hashchar | bool_ops + 2223 | 1 | hashvarlena | bytea_ops + 2225 | 1 | hashint4 | xid_ops + 2226 | 1 | hashint4 | cid_ops +(6 rows) + +-- Support routines that are primary members of opfamilies must be immutable +-- (else it suggests that the index ordering isn't fixed). But cross-type +-- members need only be stable, since they are just shorthands +-- for index probe queries. +SELECT p1.amprocfamily, p1.amproc, p2.prosrc +FROM pg_amproc AS p1, pg_proc AS p2 +WHERE p1.amproc = p2.oid AND + p1.amproclefttype = p1.amprocrighttype AND + p2.provolatile != 'i'; + amprocfamily | amproc | prosrc +--------------+--------+-------- +(0 rows) + +SELECT p1.amprocfamily, p1.amproc, p2.prosrc +FROM pg_amproc AS p1, pg_proc AS p2 +WHERE p1.amproc = p2.oid AND + p1.amproclefttype != p1.amprocrighttype AND + p2.provolatile = 'v'; + amprocfamily | amproc | prosrc +--------------+--------+-------- +(0 rows) + diff --git a/src/test/regress/expected/polymorphism_1.out b/src/test/regress/expected/polymorphism_1.out new file mode 100644 index 0000000..008c399 --- /dev/null +++ b/src/test/regress/expected/polymorphism_1.out @@ -0,0 +1,1304 @@ +-- Currently this tests polymorphic aggregates and indirectly does some +-- testing of polymorphic SQL functions. It ought to be extended. +-- Tests for other features related to function-calling have snuck in, too. +-- Legend: +----------- +-- A = type is ANY +-- P = type is polymorphic +-- N = type is non-polymorphic +-- B = aggregate base type +-- S = aggregate state type +-- R = aggregate return type +-- 1 = arg1 of a function +-- 2 = arg2 of a function +-- ag = aggregate +-- tf = trans (state) function +-- ff = final function +-- rt = return type of a function +-- -> = implies +-- => = allowed +-- !> = not allowed +-- E = exists +-- NE = not-exists +-- +-- Possible states: +-- ---------------- +-- B = (A || P || N) +-- when (B = A) -> (tf2 = NE) +-- S = (P || N) +-- ff = (E || NE) +-- tf1 = (P || N) +-- tf2 = (NE || P || N) +-- R = (P || N) +-- create functions for use as tf and ff with the needed combinations of +-- argument polymorphism, but within the constraints of valid aggregate +-- functions, i.e. tf arg1 and tf return type must match +-- polymorphic single arg transfn +CREATE FUNCTION stfp(anyarray) RETURNS anyarray AS +'select $1' LANGUAGE SQL; +-- non-polymorphic single arg transfn +CREATE FUNCTION stfnp(int[]) RETURNS int[] AS +'select $1' LANGUAGE SQL; +-- dual polymorphic transfn +CREATE FUNCTION tfp(anyarray,anyelement) RETURNS anyarray AS +'select $1 || $2' LANGUAGE SQL; +-- dual non-polymorphic transfn +CREATE FUNCTION tfnp(int[],int) RETURNS int[] AS +'select $1 || $2' LANGUAGE SQL; +-- arg1 only polymorphic transfn +CREATE FUNCTION tf1p(anyarray,int) RETURNS anyarray AS +'select $1' LANGUAGE SQL; +-- arg2 only polymorphic transfn +CREATE FUNCTION tf2p(int[],anyelement) RETURNS int[] AS +'select $1' LANGUAGE SQL; +-- multi-arg polymorphic +CREATE FUNCTION sum3(anyelement,anyelement,anyelement) returns anyelement AS +'select $1+$2+$3' language sql strict; +-- finalfn polymorphic +CREATE FUNCTION ffp(anyarray) RETURNS anyarray AS +'select $1' LANGUAGE SQL; +-- finalfn non-polymorphic +CREATE FUNCTION ffnp(int[]) returns int[] as +'select $1' LANGUAGE SQL; +-- Try to cover all the possible states: +-- +-- Note: in Cases 1 & 2, we are trying to return P. Therefore, if the transfn +-- is stfnp, tfnp, or tf2p, we must use ffp as finalfn, because stfnp, tfnp, +-- and tf2p do not return P. Conversely, in Cases 3 & 4, we are trying to +-- return N. Therefore, if the transfn is stfp, tfp, or tf1p, we must use ffnp +-- as finalfn, because stfp, tfp, and tf1p do not return N. +-- +-- Case1 (R = P) && (B = A) +-- ------------------------ +-- S tf1 +-- ------- +-- N N +-- should CREATE +CREATE AGGREGATE myaggp01a(*) (SFUNC = stfnp, STYPE = int4[], + FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- P N +-- should ERROR: stfnp(anyarray) not matched by stfnp(int[]) +CREATE AGGREGATE myaggp02a(*) (SFUNC = stfnp, STYPE = anyarray, + FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- N P +-- should CREATE +CREATE AGGREGATE myaggp03a(*) (SFUNC = stfp, STYPE = int4[], + FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +CREATE AGGREGATE myaggp03b(*) (SFUNC = stfp, STYPE = int4[], + INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- P P +-- should ERROR: we have no way to resolve S +CREATE AGGREGATE myaggp04a(*) (SFUNC = stfp, STYPE = anyarray, + FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +CREATE AGGREGATE myaggp04b(*) (SFUNC = stfp, STYPE = anyarray, + INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- Case2 (R = P) && ((B = P) || (B = N)) +-- ------------------------------------- +-- S tf1 B tf2 +-- ----------------------- +-- N N N N +-- should CREATE +CREATE AGGREGATE myaggp05a(BASETYPE = int, SFUNC = tfnp, STYPE = int[], + FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- N N N P +-- should CREATE +CREATE AGGREGATE myaggp06a(BASETYPE = int, SFUNC = tf2p, STYPE = int[], + FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- N N P N +-- should ERROR: tfnp(int[], anyelement) not matched by tfnp(int[], int) +CREATE AGGREGATE myaggp07a(BASETYPE = anyelement, SFUNC = tfnp, STYPE = int[], + FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- N N P P +-- should CREATE +CREATE AGGREGATE myaggp08a(BASETYPE = anyelement, SFUNC = tf2p, STYPE = int[], + FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- N P N N +-- should CREATE +CREATE AGGREGATE myaggp09a(BASETYPE = int, SFUNC = tf1p, STYPE = int[], + FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +CREATE AGGREGATE myaggp09b(BASETYPE = int, SFUNC = tf1p, STYPE = int[], + INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- N P N P +-- should CREATE +CREATE AGGREGATE myaggp10a(BASETYPE = int, SFUNC = tfp, STYPE = int[], + FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +CREATE AGGREGATE myaggp10b(BASETYPE = int, SFUNC = tfp, STYPE = int[], + INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- N P P N +-- should ERROR: tf1p(int[],anyelement) not matched by tf1p(anyarray,int) +CREATE AGGREGATE myaggp11a(BASETYPE = anyelement, SFUNC = tf1p, STYPE = int[], + FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +CREATE AGGREGATE myaggp11b(BASETYPE = anyelement, SFUNC = tf1p, STYPE = int[], + INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- N P P P +-- should ERROR: tfp(int[],anyelement) not matched by tfp(anyarray,anyelement) +CREATE AGGREGATE myaggp12a(BASETYPE = anyelement, SFUNC = tfp, STYPE = int[], + FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +CREATE AGGREGATE myaggp12b(BASETYPE = anyelement, SFUNC = tfp, STYPE = int[], + INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- P N N N +-- should ERROR: tfnp(anyarray, int) not matched by tfnp(int[],int) +CREATE AGGREGATE myaggp13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray, + FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- P N N P +-- should ERROR: tf2p(anyarray, int) not matched by tf2p(int[],anyelement) +CREATE AGGREGATE myaggp14a(BASETYPE = int, SFUNC = tf2p, STYPE = anyarray, + FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- P N P N +-- should ERROR: tfnp(anyarray, anyelement) not matched by tfnp(int[],int) +CREATE AGGREGATE myaggp15a(BASETYPE = anyelement, SFUNC = tfnp, + STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- P N P P +-- should ERROR: tf2p(anyarray, anyelement) not matched by tf2p(int[],anyelement) +CREATE AGGREGATE myaggp16a(BASETYPE = anyelement, SFUNC = tf2p, + STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- P P N N +-- should ERROR: we have no way to resolve S +CREATE AGGREGATE myaggp17a(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray, + FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +CREATE AGGREGATE myaggp17b(BASETYPE = int, SFUNC = tf1p, STYPE = anyarray, + INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- P P N P +-- should ERROR: tfp(anyarray, int) not matched by tfp(anyarray, anyelement) +CREATE AGGREGATE myaggp18a(BASETYPE = int, SFUNC = tfp, STYPE = anyarray, + FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +CREATE AGGREGATE myaggp18b(BASETYPE = int, SFUNC = tfp, STYPE = anyarray, + INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- P P P N +-- should ERROR: tf1p(anyarray, anyelement) not matched by tf1p(anyarray, int) +CREATE AGGREGATE myaggp19a(BASETYPE = anyelement, SFUNC = tf1p, + STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +CREATE AGGREGATE myaggp19b(BASETYPE = anyelement, SFUNC = tf1p, + STYPE = anyarray, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- P P P P +-- should CREATE +CREATE AGGREGATE myaggp20a(BASETYPE = anyelement, SFUNC = tfp, + STYPE = anyarray, FINALFUNC = ffp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +CREATE AGGREGATE myaggp20b(BASETYPE = anyelement, SFUNC = tfp, + STYPE = anyarray, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- Case3 (R = N) && (B = A) +-- ------------------------ +-- S tf1 +-- ------- +-- N N +-- should CREATE +CREATE AGGREGATE myaggn01a(*) (SFUNC = stfnp, STYPE = int4[], + FINALFUNC = ffnp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +CREATE AGGREGATE myaggn01b(*) (SFUNC = stfnp, STYPE = int4[], + INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- P N +-- should ERROR: stfnp(anyarray) not matched by stfnp(int[]) +CREATE AGGREGATE myaggn02a(*) (SFUNC = stfnp, STYPE = anyarray, + FINALFUNC = ffnp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +CREATE AGGREGATE myaggn02b(*) (SFUNC = stfnp, STYPE = anyarray, + INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- N P +-- should CREATE +CREATE AGGREGATE myaggn03a(*) (SFUNC = stfp, STYPE = int4[], + FINALFUNC = ffnp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- P P +-- should ERROR: ffnp(anyarray) not matched by ffnp(int[]) +CREATE AGGREGATE myaggn04a(*) (SFUNC = stfp, STYPE = anyarray, + FINALFUNC = ffnp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- Case4 (R = N) && ((B = P) || (B = N)) +-- ------------------------------------- +-- S tf1 B tf2 +-- ----------------------- +-- N N N N +-- should CREATE +CREATE AGGREGATE myaggn05a(BASETYPE = int, SFUNC = tfnp, STYPE = int[], + FINALFUNC = ffnp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +CREATE AGGREGATE myaggn05b(BASETYPE = int, SFUNC = tfnp, STYPE = int[], + INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- N N N P +-- should CREATE +CREATE AGGREGATE myaggn06a(BASETYPE = int, SFUNC = tf2p, STYPE = int[], + FINALFUNC = ffnp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +CREATE AGGREGATE myaggn06b(BASETYPE = int, SFUNC = tf2p, STYPE = int[], + INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- N N P N +-- should ERROR: tfnp(int[], anyelement) not matched by tfnp(int[], int) +CREATE AGGREGATE myaggn07a(BASETYPE = anyelement, SFUNC = tfnp, STYPE = int[], + FINALFUNC = ffnp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +CREATE AGGREGATE myaggn07b(BASETYPE = anyelement, SFUNC = tfnp, STYPE = int[], + INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- N N P P +-- should CREATE +CREATE AGGREGATE myaggn08a(BASETYPE = anyelement, SFUNC = tf2p, STYPE = int[], + FINALFUNC = ffnp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +CREATE AGGREGATE myaggn08b(BASETYPE = anyelement, SFUNC = tf2p, STYPE = int[], + INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- N P N N +-- should CREATE +CREATE AGGREGATE myaggn09a(BASETYPE = int, SFUNC = tf1p, STYPE = int[], + FINALFUNC = ffnp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- N P N P +-- should CREATE +CREATE AGGREGATE myaggn10a(BASETYPE = int, SFUNC = tfp, STYPE = int[], + FINALFUNC = ffnp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- N P P N +-- should ERROR: tf1p(int[],anyelement) not matched by tf1p(anyarray,int) +CREATE AGGREGATE myaggn11a(BASETYPE = anyelement, SFUNC = tf1p, STYPE = int[], + FINALFUNC = ffnp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- N P P P +-- should ERROR: tfp(int[],anyelement) not matched by tfp(anyarray,anyelement) +CREATE AGGREGATE myaggn12a(BASETYPE = anyelement, SFUNC = tfp, STYPE = int[], + FINALFUNC = ffnp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- P N N N +-- should ERROR: tfnp(anyarray, int) not matched by tfnp(int[],int) +CREATE AGGREGATE myaggn13a(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray, + FINALFUNC = ffnp, INITCOND = '{}'); +ERROR: aggregate ctype must be specified +CREATE AGGREGATE myaggn13b(BASETYPE = int, SFUNC = tfnp, STYPE = anyarray, + INITCOND = '{}'); +ERROR: aggregate ctype must be specified +-- P N N P +-- should ERR... [truncated message content] |
From: Michael P. <mic...@us...> - 2011-04-14 06:37:25
|
Project "Postgres-XC". The branch, master has been updated via 5d185a9f610af8043b6b528bc619151fea71ba9b (commit) from 8ab933b6a78a3f0eee922a2dd84afacbba342c09 (commit) - Log ----------------------------------------------------------------- commit 5d185a9f610af8043b6b528bc619151fea71ba9b Author: Michael P <mic...@us...> Date: Thu Apr 14 15:33:34 2011 +0900 Correction for output file large_object Output changes depending on system configuration. diff --git a/src/test/regress/output/largeobject_2.source b/src/test/regress/output/largeobject_2.source index 553521e..9a6ea20 100644 --- a/src/test/regress/output/largeobject_2.source +++ b/src/test/regress/output/largeobject_2.source @@ -200,7 +200,7 @@ SELECT lo_unlink(loid) from lotest_stash_values; (1 row) TRUNCATE lotest_stash_values; -INSERT INTO lotest_stash_values (loid) VALUES( lo_import('/home/abbas/pgxc/postgres-xc/src/test/regress/data/tenk.data') ); +INSERT INTO lotest_stash_values (loid) VALUES( lo_import('@abs_srcdir@/data/tenk.data') ); BEGIN; UPDATE lotest_stash_values SET fd=lo_open(loid, CAST(x'20000' | x'40000' AS integer)); -- with the default BLKSZ, LOBLKSZ = 2048, so this positions us for a block ----------------------------------------------------------------------- Summary of changes: src/test/regress/output/largeobject_2.source | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-14 06:25:09
|
Project "Postgres-XC". The branch, master has been updated via 8ab933b6a78a3f0eee922a2dd84afacbba342c09 (commit) from 0fd714273601a16501bb3599c60ad0aa46e1f839 (commit) - Log ----------------------------------------------------------------- commit 8ab933b6a78a3f0eee922a2dd84afacbba342c09 Author: Michael P <mic...@us...> Date: Thu Apr 14 15:21:14 2011 +0900 Fix for bug 2990360: relative path to working directory for gtm Fix an issue with GTM path when its binary is called with a relative path Ex: ./bin/gtm -D data-gtm This was causing gtm to quit with a FATAL error because it was not able to find gtm data repository correctly. Patch written by Benny Wang diff --git a/src/gtm/main/main.c b/src/gtm/main/main.c index 1a98386..1fbec0d 100644 --- a/src/gtm/main/main.c +++ b/src/gtm/main/main.c @@ -26,6 +26,7 @@ #include "gtm/gtm_c.h" #include "gtm/gtm.h" +#include "gtm/path.h" #include "gtm/elog.h" #include "gtm/memutils.h" #include "gtm/gtm_list.h" @@ -84,6 +85,7 @@ static void GTM_UnregisterPGXCNode(Port *myport, GTM_PGXCNodeId pgxc_node_id); static bool CreateOptsFile(int argc, char *argv[]); static void CreateDataDirLockFile(void); static void CreateLockFile(const char *filename, const char *refName); +static void SetDataDir(void); static void ChangeToDataDir(void); static void checkDataDir(void); static void DeleteLockFile(const char *filename); @@ -143,6 +145,7 @@ BaseInit() MemoryContextInit(); checkDataDir(); + SetDataDir(); ChangeToDataDir(); CreateDataDirLockFile(); @@ -1181,6 +1184,29 @@ retry: } /* + * Set data directory, but make sure it's an absolute path. Use this, + * never set DataDir directly. + */ +void +SetDataDir() +{ + char *new; + + /* If presented path is relative, convert to absolute */ + new = make_absolute_path(GTMDataDir); + if (!new) + ereport(FATAL, + (errno, + errmsg("failed to set the data directory \"%s\"", + GTMDataDir))); + + if (GTMDataDir) + free(GTMDataDir); + + GTMDataDir = new; +} + +/* * Change working directory to DataDir. Most of the postmaster and backend * code assumes that we are in DataDir so it can use relative paths to access * stuff in and under the data directory. For convenience during path diff --git a/src/gtm/path/path.c b/src/gtm/path/path.c index b07b5cc..486ce06 100644 --- a/src/gtm/path/path.c +++ b/src/gtm/path/path.c @@ -20,6 +20,7 @@ #include <sys/stat.h> #include <string.h> #include <stdio.h> +#include <unistd.h> #include <gtm/path.h> @@ -175,3 +176,64 @@ trim_trailing_separator(char *path) for (p--; p > path && IS_DIR_SEP(*p); p--) *p = '\0'; } +/* + * If the given pathname isn't already absolute, make it so, interpreting + * it relative to the current working directory. + * + * Also canonicalize the path. The result is always a malloc'd copy. + * + */ +char * +make_absolute_path(const char *path) +{ + char *new; + + /* Returning null for null input is convenient for some callers */ + if (path == NULL) + return NULL; + + if (!is_absolute_path(path)) + { + char *buf; + size_t buflen; + + buflen = MAXPGPATH; + for (;;) + { + buf = malloc(buflen); + if (!buf) + return NULL; + + if (getcwd(buf, buflen)) + break; + else if (errno == ERANGE) + { + free(buf); + buflen *= 2; + continue; + } + else + { + free(buf); + return NULL; + } + } + + new = malloc(strlen(buf) + strlen(path) + 2); + if (!new) + return NULL; + sprintf(new, "%s/%s", buf, path); + free(buf); + } + else + { + new = strdup(path); + if (!new) + return NULL; + } + + /* Make sure punctuation is canonical, too */ + canonicalize_path(new); + + return new; +} diff --git a/src/gtm/proxy/proxy_main.c b/src/gtm/proxy/proxy_main.c index 2135d97..73c6096 100644 --- a/src/gtm/proxy/proxy_main.c +++ b/src/gtm/proxy/proxy_main.c @@ -24,6 +24,7 @@ #include <getopt.h> #include "gtm/gtm_c.h" +#include "gtm/path.h" #include "gtm/gtm_proxy.h" #include "gtm/register.h" #include "gtm/elog.h" @@ -112,6 +113,7 @@ static void GTMProxy_CommandPending(GTMProxy_ConnectionInfo *conninfo, static bool CreateOptsFile(int argc, char *argv[]); static void CreateDataDirLockFile(void); static void CreateLockFile(const char *filename, const char *refName); +static void SetDataDir(void); static void ChangeToDataDir(void); static void checkDataDir(void); static void DeleteLockFile(const char *filename); @@ -174,6 +176,7 @@ BaseInit() MemoryContextInit(); checkDataDir(); + SetDataDir(); ChangeToDataDir(); CreateDataDirLockFile(); @@ -2008,6 +2011,29 @@ retry: } /* + * Set data directory, but make sure it's an absolute path. Use this, + * never set DataDir directly. + */ +void +SetDataDir() +{ + char *new; + + /* If presented path is relative, convert to absolute */ + new = make_absolute_path(GTMProxyDataDir); + if (!new) + ereport(FATAL, + (errno, + errmsg("failed to set the data directory \"%s\"", + GTMProxyDataDir))); + + if (GTMProxyDataDir) + free(GTMProxyDataDir); + + GTMProxyDataDir = new; +} + +/* * Change working directory to DataDir. Most of the postmaster and backend * code assumes that we are in DataDir so it can use relative paths to access * stuff in and under the data directory. For convenience during path diff --git a/src/include/gtm/path.h b/src/include/gtm/path.h index 7ce6602..2cedefb 100644 --- a/src/include/gtm/path.h +++ b/src/include/gtm/path.h @@ -11,6 +11,11 @@ * *------------------------------------------------------------------------- */ +#ifndef _PATH_H +#define _PATH_H + #include "gtm/gtm_c.h" extern void canonicalize_path(char *path); +extern char *make_absolute_path(const char *path); +#endif ----------------------------------------------------------------------- Summary of changes: src/gtm/main/main.c | 26 ++++++++++++++++++ src/gtm/path/path.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ src/gtm/proxy/proxy_main.c | 26 ++++++++++++++++++ src/include/gtm/path.h | 5 +++ 4 files changed, 119 insertions(+), 0 deletions(-) hooks/post-receive -- Postgres-XC |
From: Abbas B. <ga...@us...> - 2011-04-13 16:17:23
|
Project "Postgres-XC". The branch, master has been updated via 0fd714273601a16501bb3599c60ad0aa46e1f839 (commit) from cac1e04b3eeedbe4d6240dbb00c1a326e65f7f97 (commit) - Log ----------------------------------------------------------------- commit 0fd714273601a16501bb3599c60ad0aa46e1f839 Author: Abbas <abb...@en...> Date: Wed Apr 13 21:16:56 2011 +0500 The output is correct as long as we do not add support for INSERT SELECT diff --git a/src/test/regress/expected/vacuum_1.out b/src/test/regress/expected/vacuum_1.out new file mode 100644 index 0000000..776c258 --- /dev/null +++ b/src/test/regress/expected/vacuum_1.out @@ -0,0 +1,73 @@ +-- +-- VACUUM +-- +CREATE TABLE vactst (i INT); +INSERT INTO vactst VALUES (1); +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst VALUES (0); +SELECT count(*) FROM vactst; + count +------- + 2 +(1 row) + +DELETE FROM vactst WHERE i != 0; +SELECT * FROM vactst; + i +--- + 0 +(1 row) + +VACUUM FULL vactst; +UPDATE vactst SET i = i + 1; +ERROR: Partition column can't be updated in current version +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst SELECT * FROM vactst; +INSERT INTO vactst VALUES (0); +SELECT count(*) FROM vactst; + count +------- + 2 +(1 row) + +DELETE FROM vactst WHERE i != 0; +VACUUM (FULL) vactst; +DELETE FROM vactst; +SELECT * FROM vactst; + i +--- +(0 rows) + +VACUUM (FULL, FREEZE) vactst; +VACUUM (ANALYZE, FULL) vactst; +CREATE TABLE vaccluster (i INT PRIMARY KEY); +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "vaccluster_pkey" for table "vaccluster" +ALTER TABLE vaccluster CLUSTER ON vaccluster_pkey; +INSERT INTO vaccluster SELECT * FROM vactst; +CLUSTER vaccluster; +VACUUM FULL pg_am; +VACUUM FULL pg_class; +VACUUM FULL pg_database; +VACUUM FULL vaccluster; +VACUUM FULL vactst; +DROP TABLE vaccluster; +DROP TABLE vactst; ----------------------------------------------------------------------- Summary of changes: .../regress/expected/{vacuum.out => vacuum_1.out} | 5 +++-- 1 files changed, 3 insertions(+), 2 deletions(-) copy src/test/regress/expected/{vacuum.out => vacuum_1.out} (96%) hooks/post-receive -- Postgres-XC |
From: Abbas B. <ga...@us...> - 2011-04-13 15:58:17
|
Project "Postgres-XC". The branch, master has been updated via cac1e04b3eeedbe4d6240dbb00c1a326e65f7f97 (commit) from dfa58f3a944a7b1fe4c3f97281c9b1516f0b69a7 (commit) - Log ----------------------------------------------------------------- commit cac1e04b3eeedbe4d6240dbb00c1a326e65f7f97 Author: Abbas <abb...@en...> Date: Wed Apr 13 20:48:00 2011 +0500 This patch fixes the test case tsearch. Some changes were done in SQL to ensure ORDER etc. The original expected output file was wrong. An alternate expected output file was checked in which is not entirely correct. It contains ZERO row results of count(*) for which the bug ID is 3286054 diff --git a/src/test/regress/expected/tsearch.out b/src/test/regress/expected/tsearch.out index f17c4bb..e1d7646 100644 --- a/src/test/regress/expected/tsearch.out +++ b/src/test/regress/expected/tsearch.out @@ -46,7 +46,7 @@ WHERE mapcfg = 0 OR mapdict = 0; -- Look for pg_ts_config_map entries that aren't one of parser's token types SELECT * FROM ( SELECT oid AS cfgid, (ts_token_type(cfgparser)).tokid AS tokid - FROM pg_ts_config ) AS tt + FROM pg_ts_config ) AS tt RIGHT JOIN pg_ts_config_map AS m ON (tt.cfgid=m.mapcfg AND tt.tokid=m.maptokentype) WHERE @@ -188,7 +188,6 @@ SELECT count(*) FROM test_tsvector WHERE a @@ 'w:*|q:*'; 494 (1 row) - RESET enable_seqscan; INSERT INTO test_tsvector VALUES ('???', 'DFG:1A,2B,6C,10 FGH'); SELECT * FROM ts_stat('SELECT a FROM test_tsvector') ORDER BY ndoc DESC, nentry DESC, word LIMIT 10; @@ -225,7 +224,7 @@ SELECT ts_lexize('english_stem', 'identity'); {ident} (1 row) -SELECT * FROM ts_token_type('default') ORDER BY tokid; +SELECT * FROM ts_token_type('default'); tokid | alias | description -------+-----------------+------------------------------------------ 1 | asciiword | Word, all ASCII @@ -255,143 +254,145 @@ SELECT * FROM ts_token_type('default') ORDER BY tokid; SELECT * FROM ts_parse('default', '345 qwe@efd.r '' http://www.com/ http://aew.werc.ewr/?ad=qwe&dw 1aew.werc.ewr/?ad=qwe&dw 2aew.werc.ewr http://3aew.werc.ewr/?ad=qwe&dw http://4aew.werc.ewr http://5aew.werc.ewr:8100/? ad=qwe&dw 6aew.werc.ewr:8100/?ad=qwe&dw 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 +4.0e-10 qwe qwe qwqwe 234.435 455 5.005 te...@st... qwe-wer asdf <fr>qwer jf sdjk<we hjwer <werrwe> ewr1> ewri2 <a href="qwe<qwe>"> /usr/local/fff /awdf/dwqe/4325 rewt/ewr wefjn /wqe-324/ewr gist.h gist.h.c gist.c. readline 4.2 4.2. 4.2, readline-4.2 readline-4.2. 234 -<i <b> wow < jqw <> qwerty') ORDER BY tokid,token; +<i <b> wow < jqw <> qwerty'); tokid | token -------+-------------------------------------- - 1 | ad - 1 | asdf - 1 | dw - 1 | hjwer - 1 | i - 1 | jf - 1 | jqw - 1 | qwe - 1 | qwe - 1 | qwe + 22 | 345 + 12 | 1 | qwe - 1 | qwer - 1 | qwerty - 1 | qwqwe - 1 | readline - 1 | readline - 1 | readline - 1 | sdjk - 1 | we - 1 | wefjn - 1 | wow - 3 | ewr1 - 3 | ewri2 - 4 | te...@st... - 5 | 1aew.werc.ewr/?ad=qwe&dw - 5 | 3aew.werc.ewr/?ad=qwe&dw - 5 | 6aew.werc.ewr:8100/?ad=qwe&dw - 5 | 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 + 12 | @ + 19 | efd.r + 12 | ' + 14 | http:// + 6 | www.com + 12 | / + 14 | http:// 5 | aew.werc.ewr/?ad=qwe&dw - 6 | 1aew.werc.ewr - 6 | 2aew.werc.ewr - 6 | 3aew.werc.ewr - 6 | 4aew.werc.ewr - 6 | 5aew.werc.ewr:8100 - 6 | 6aew.werc.ewr:8100 - 6 | 7aew.werc.ewr:8100 6 | aew.werc.ewr - 6 | www.com - 7 | +4.0e-10 - 11 | qwe - 11 | wer - 12 | - : - 12 | - : - 12 | - 12 | + 18 | /?ad=qwe&dw 12 | + 5 | 1aew.werc.ewr/?ad=qwe&dw + 6 | 1aew.werc.ewr + 18 | /?ad=qwe&dw 12 | + 6 | 2aew.werc.ewr 12 | + 14 | http:// + 5 | 3aew.werc.ewr/?ad=qwe&dw + 6 | 3aew.werc.ewr + 18 | /?ad=qwe&dw 12 | + 14 | http:// + 6 | 4aew.werc.ewr 12 | + 14 | http:// + 5 | 5aew.werc.ewr:8100/? + 6 | 5aew.werc.ewr:8100 + 18 | /? + 12 | + 1 | ad + 12 | = + 1 | qwe + 12 | & + 1 | dw 12 | + 5 | 6aew.werc.ewr:8100/?ad=qwe&dw + 6 | 6aew.werc.ewr:8100 + 18 | /?ad=qwe&dw 12 | + 5 | 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 + 6 | 7aew.werc.ewr:8100 + 18 | /?ad=qwe&dw=%20%32 12 | + 7 | +4.0e-10 12 | + 1 | qwe 12 | + 1 | qwe 12 | + 1 | qwqwe 12 | + 20 | 234.435 12 | + 22 | 455 12 | + 20 | 5.005 12 | + 4 | te...@st... 12 | + 16 | qwe-wer + 11 | qwe + 12 | - + 11 | wer 12 | + 1 | asdf 12 | + 13 | <fr> + 1 | qwer 12 | + 1 | jf 12 | + 1 | sdjk + 12 | < + 1 | we 12 | + 1 | hjwer 12 | + 13 | <werrwe> 12 | + 3 | ewr1 + 12 | > + 3 | ewri2 12 | + 13 | <a href="qwe<qwe>"> + 12 | + + | + 19 | /usr/local/fff 12 | + 19 | /awdf/dwqe/4325 12 | + 19 | rewt/ewr 12 | + 1 | wefjn 12 | + 19 | /wqe-324/ewr 12 | + 19 | gist.h 12 | + 19 | gist.h.c 12 | + 19 | gist.c + 12 | . + 1 | readline 12 | + 20 | 4.2 12 | + 20 | 4.2 + 12 | . + 20 | 4.2 + 12 | , + 1 | readline + 20 | -4.2 12 | + 1 | readline + 20 | -4.2 + 12 | . + 22 | 234 + 12 | + + | + 12 | < + 1 | i 12 | + 13 | <b> 12 | + 1 | wow 12 | - 12 | ' - 12 | & - 12 | , - 12 | - - 12 | . - 12 | . - 12 | . - 12 | / - 12 | /? - 12 | < - 12 | < 12 | < + 1 | jqw + 12 | 12 | <> - 12 | = - 12 | > - 12 | @ - 13 | <a href="qwe<qwe>"> - 13 | <b> - 13 | <fr> - 13 | <werrwe> - 14 | http:// - 14 | http:// - 14 | http:// - 14 | http:// - 14 | http:// - 16 | qwe-wer - 18 | /?ad=qwe&dw - 18 | /?ad=qwe&dw - 18 | /?ad=qwe&dw - 18 | /?ad=qwe&dw - 18 | /?ad=qwe&dw=%20%32 - 19 | /awdf/dwqe/4325 - 19 | /usr/local/fff - 19 | /wqe-324/ewr - 19 | efd.r - 19 | gist.c - 19 | gist.h - 19 | gist.h.c - 19 | rewt/ewr - 20 | -4.2 - 20 | -4.2 - 20 | 234.435 - 20 | 4.2 - 20 | 4.2 - 20 | 4.2 - 20 | 5.005 - 22 | 234 - 22 | 345 - 22 | 455 -(131 rows) + 1 | qwerty +(133 rows) SELECT to_tsvector('english', '345 qwe@efd.r '' http://www.com/ http://aew.werc.ewr/?ad=qwe&dw 1aew.werc.ewr/?ad=qwe&dw 2aew.werc.ewr http://3aew.werc.ewr/?ad=qwe&dw http://4aew.werc.ewr http://5aew.werc.ewr:8100/? ad=qwe&dw 6aew.werc.ewr:8100/?ad=qwe&dw 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 +4.0e-10 qwe qwe qwqwe 234.435 455 5.005 te...@st... qwe-wer asdf <fr>qwer jf sdjk<we hjwer <werrwe> ewr1> ewri2 <a href="qwe<qwe>"> /usr/local/fff /awdf/dwqe/4325 rewt/ewr wefjn /wqe-324/ewr gist.h gist.h.c gist.c. readline 4.2 4.2. 4.2, readline-4.2 readline-4.2. 234 @@ -670,7 +671,7 @@ to_tsquery('english', 'sea&foo'), 'HighlightAll=true'); </html> (1 row) ---Check if headline fragments work +--Check if headline fragments work SELECT ts_headline('english', ' Day after day, day after day, We stuck, nor breath nor motion, @@ -1082,7 +1083,7 @@ select * from pendtest where 'ipsa:*'::tsquery @@ ts; 'ipsam':2 'lore':1 (1 row) -select * from pendtest where 'ips:*'::tsquery @@ ts ORDER BY 1; +select * from pendtest where 'ips:*'::tsquery @@ ts; ts -------------------- 'ipsam':2 'lore':1 diff --git a/src/test/regress/expected/tsearch.out b/src/test/regress/expected/tsearch_1.out similarity index 98% copy from src/test/regress/expected/tsearch.out copy to src/test/regress/expected/tsearch_1.out index f17c4bb..e8c35d4 100644 --- a/src/test/regress/expected/tsearch.out +++ b/src/test/regress/expected/tsearch_1.out @@ -46,7 +46,7 @@ WHERE mapcfg = 0 OR mapdict = 0; -- Look for pg_ts_config_map entries that aren't one of parser's token types SELECT * FROM ( SELECT oid AS cfgid, (ts_token_type(cfgparser)).tokid AS tokid - FROM pg_ts_config ) AS tt + FROM pg_ts_config ) AS tt RIGHT JOIN pg_ts_config_map AS m ON (tt.cfgid=m.mapcfg AND tt.tokid=m.maptokentype) WHERE @@ -188,7 +188,6 @@ SELECT count(*) FROM test_tsvector WHERE a @@ 'w:*|q:*'; 494 (1 row) - RESET enable_seqscan; INSERT INTO test_tsvector VALUES ('???', 'DFG:1A,2B,6C,10 FGH'); SELECT * FROM ts_stat('SELECT a FROM test_tsvector') ORDER BY ndoc DESC, nentry DESC, word LIMIT 10; @@ -284,6 +283,7 @@ SELECT * FROM ts_parse('default', '345 qwe@efd.r '' http://www.com/ http://aew.w 4 | te...@st... 5 | 1aew.werc.ewr/?ad=qwe&dw 5 | 3aew.werc.ewr/?ad=qwe&dw + 5 | 5aew.werc.ewr:8100/? 5 | 6aew.werc.ewr:8100/?ad=qwe&dw 5 | 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 5 | aew.werc.ewr/?ad=qwe&dw @@ -299,10 +299,12 @@ SELECT * FROM ts_parse('default', '345 qwe@efd.r '' http://www.com/ http://aew.w 7 | +4.0e-10 11 | qwe 11 | wer - 12 | - : - 12 | - : + 12 | < + 12 | < + 12 | <> + 12 | < + 12 | = + 12 | > 12 | 12 | 12 | @@ -342,22 +344,20 @@ SELECT * FROM ts_parse('default', '345 qwe@efd.r '' http://www.com/ http://aew.w 12 | 12 | 12 | + 12 | 12 | ' - 12 | & - 12 | , 12 | - + 12 | , + 12 | / 12 | . 12 | . 12 | . - 12 | / - 12 | /? - 12 | < - 12 | < - 12 | < - 12 | <> - 12 | = - 12 | > 12 | @ + 12 | & + 12 | + + | + 12 | + + | 13 | <a href="qwe<qwe>"> 13 | <b> 13 | <fr> @@ -368,22 +368,23 @@ SELECT * FROM ts_parse('default', '345 qwe@efd.r '' http://www.com/ http://aew.w 14 | http:// 14 | http:// 16 | qwe-wer + 18 | /? 18 | /?ad=qwe&dw 18 | /?ad=qwe&dw 18 | /?ad=qwe&dw 18 | /?ad=qwe&dw 18 | /?ad=qwe&dw=%20%32 19 | /awdf/dwqe/4325 - 19 | /usr/local/fff - 19 | /wqe-324/ewr 19 | efd.r 19 | gist.c 19 | gist.h 19 | gist.h.c 19 | rewt/ewr + 19 | /usr/local/fff + 19 | /wqe-324/ewr + 20 | 234.435 20 | -4.2 20 | -4.2 - 20 | 234.435 20 | 4.2 20 | 4.2 20 | 4.2 @@ -391,7 +392,7 @@ SELECT * FROM ts_parse('default', '345 qwe@efd.r '' http://www.com/ http://aew.w 22 | 234 22 | 345 22 | 455 -(131 rows) +(133 rows) SELECT to_tsvector('english', '345 qwe@efd.r '' http://www.com/ http://aew.werc.ewr/?ad=qwe&dw 1aew.werc.ewr/?ad=qwe&dw 2aew.werc.ewr http://3aew.werc.ewr/?ad=qwe&dw http://4aew.werc.ewr http://5aew.werc.ewr:8100/? ad=qwe&dw 6aew.werc.ewr:8100/?ad=qwe&dw 7aew.werc.ewr:8100/?ad=qwe&dw=%20%32 +4.0e-10 qwe qwe qwqwe 234.435 455 5.005 te...@st... qwe-wer asdf <fr>qwer jf sdjk<we hjwer <werrwe> ewr1> ewri2 <a href="qwe<qwe>"> /usr/local/fff /awdf/dwqe/4325 rewt/ewr wefjn /wqe-324/ewr gist.h gist.h.c gist.c. readline 4.2 4.2. 4.2, readline-4.2 readline-4.2. 234 @@ -410,18 +411,18 @@ SELECT length(to_tsvector('english', '345 qwe@efd.r '' http://www.com/ http://ae (1 row) -- ts_debug -SELECT * from ts_debug('english', '<myns:foo-bar_baz.blurfl>abc&nm1;def©ghiõjkl</myns:foo-bar_baz.blurfl>'); +SELECT * from ts_debug('english', '<myns:foo-bar_baz.blurfl>abc&nm1;def©ghiõjkl</myns:foo-bar_baz.blurfl>') ORDER BY alias, description, token; alias | description | token | dictionaries | dictionary | lexemes -----------+-----------------+----------------------------+----------------+--------------+--------- - tag | XML tag | <myns:foo-bar_baz.blurfl> | {} | | asciiword | Word, all ASCII | abc | {english_stem} | english_stem | {abc} - entity | XML entity | &nm1; | {} | | asciiword | Word, all ASCII | def | {english_stem} | english_stem | {def} - entity | XML entity | © | {} | | asciiword | Word, all ASCII | ghi | {english_stem} | english_stem | {ghi} - entity | XML entity | õ | {} | | asciiword | Word, all ASCII | jkl | {english_stem} | english_stem | {jkl} + entity | XML entity | õ | {} | | + entity | XML entity | &nm1; | {} | | + entity | XML entity | © | {} | | tag | XML tag | </myns:foo-bar_baz.blurfl> | {} | | + tag | XML tag | <myns:foo-bar_baz.blurfl> | {} | | (9 rows) -- check parsing of URLs @@ -670,7 +671,7 @@ to_tsquery('english', 'sea&foo'), 'HighlightAll=true'); </html> (1 row) ---Check if headline fragments work +--Check if headline fragments work SELECT ts_headline('english', ' Day after day, day after day, We stuck, nor breath nor motion, @@ -800,6 +801,7 @@ SELECT COUNT(*) FROM test_tsquery WHERE keyword > 'new & york'; (1 row) CREATE UNIQUE INDEX bt_tsq ON test_tsquery (keyword); +ERROR: Cannot locally enforce a unique index on round robin distributed table. SET enable_seqscan=OFF; SELECT COUNT(*) FROM test_tsquery WHERE keyword < 'new & york'; count @@ -1038,35 +1040,33 @@ SELECT to_tsquery('SKIES & My | booKs'); CREATE TRIGGER tsvectorupdate BEFORE UPDATE OR INSERT ON test_tsvector FOR EACH ROW EXECUTE PROCEDURE tsvector_update_trigger(a, 'pg_catalog.english', t); +ERROR: Postgres-XC does not support TRIGGER yet +DETAIL: The feature is not currently supported SELECT count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty'); count ------- - 0 -(1 row) +(0 rows) INSERT INTO test_tsvector (t) VALUES ('345 qwerty'); SELECT count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty'); count ------- - 1 -(1 row) +(0 rows) UPDATE test_tsvector SET t = null WHERE t = '345 qwerty'; SELECT count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty'); count ------- - 0 -(1 row) +(0 rows) INSERT INTO test_tsvector (t) VALUES ('345 qwerty'); SELECT count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty'); count ------- - 1 -(1 row) +(0 rows) -- test finding items in GIN's pending list -create temp table pendtest (ts tsvector); +create table pendtest (ts tsvector); create index pendtest_idx on pendtest using gin(ts); insert into pendtest values (to_tsvector('Lore ipsam')); insert into pendtest values (to_tsvector('Lore ipsum')); @@ -1099,3 +1099,4 @@ select * from pendtest where 'ipi:*'::tsquery @@ ts; ---- (0 rows) +drop table pendtest; diff --git a/src/test/regress/sql/tsearch.sql b/src/test/regress/sql/tsearch.sql index a9e814b..270bfd2 100644 --- a/src/test/regress/sql/tsearch.sql +++ b/src/test/regress/sql/tsearch.sql @@ -33,7 +33,7 @@ WHERE mapcfg = 0 OR mapdict = 0; -- Look for pg_ts_config_map entries that aren't one of parser's token types SELECT * FROM ( SELECT oid AS cfgid, (ts_token_type(cfgparser)).tokid AS tokid - FROM pg_ts_config ) AS tt + FROM pg_ts_config ) AS tt RIGHT JOIN pg_ts_config_map AS m ON (tt.cfgid=m.mapcfg AND tt.tokid=m.maptokentype) WHERE @@ -76,7 +76,7 @@ SELECT count(*) FROM test_tsvector WHERE a @@ 'eq|yt'; SELECT count(*) FROM test_tsvector WHERE a @@ '(eq&yt)|(wr&qh)'; SELECT count(*) FROM test_tsvector WHERE a @@ '(eq|yt)&(wr|qh)'; SELECT count(*) FROM test_tsvector WHERE a @@ 'w:*|q:*'; - + RESET enable_seqscan; INSERT INTO test_tsvector VALUES ('???', 'DFG:1A,2B,6C,10 FGH'); SELECT * FROM ts_stat('SELECT a FROM test_tsvector') ORDER BY ndoc DESC, nentry DESC, word LIMIT 10; @@ -214,7 +214,7 @@ ff-bg </html>', to_tsquery('english', 'sea&foo'), 'HighlightAll=true'); ---Check if headline fragments work +--Check if headline fragments work SELECT ts_headline('english', ' Day after day, day after day, We stuck, nor breath nor motion, @@ -369,7 +369,7 @@ INSERT INTO test_tsvector (t) VALUES ('345 qwerty'); SELECT count(*) FROM test_tsvector WHERE a @@ to_tsquery('345&qwerty'); -- test finding items in GIN's pending list -create temp table pendtest (ts tsvector); +create table pendtest (ts tsvector); create index pendtest_idx on pendtest using gin(ts); insert into pendtest values (to_tsvector('Lore ipsam')); insert into pendtest values (to_tsvector('Lore ipsum')); @@ -378,3 +378,5 @@ select * from pendtest where 'ipsa:*'::tsquery @@ ts; select * from pendtest where 'ips:*'::tsquery @@ ts ORDER BY 1; select * from pendtest where 'ipt:*'::tsquery @@ ts; select * from pendtest where 'ipi:*'::tsquery @@ ts; +drop table pendtest; + ----------------------------------------------------------------------- Summary of changes: src/test/regress/expected/tsearch.out | 197 ++++++++++---------- .../expected/{tsearch.out => tsearch_1.out} | 71 ++++---- src/test/regress/sql/tsearch.sql | 10 +- 3 files changed, 141 insertions(+), 137 deletions(-) copy src/test/regress/expected/{tsearch.out => tsearch_1.out} (98%) hooks/post-receive -- Postgres-XC |
From: Abbas B. <ga...@us...> - 2011-04-13 12:18:40
|
Project "Postgres-XC". The branch, master has been updated via dfa58f3a944a7b1fe4c3f97281c9b1516f0b69a7 (commit) from 04202cbdd151776cb44eefac7eeecdf05467cca7 (commit) - Log ----------------------------------------------------------------- commit dfa58f3a944a7b1fe4c3f97281c9b1516f0b69a7 Author: Abbas <abb...@en...> Date: Wed Apr 13 17:18:10 2011 +0500 SQL Changes and an alternate expected output file for making largeobject test case pass diff --git a/src/test/regress/input/largeobject.source b/src/test/regress/input/largeobject.source index 807cfd7..e4e38e2 100644 --- a/src/test/regress/input/largeobject.source +++ b/src/test/regress/input/largeobject.source @@ -6,11 +6,11 @@ SET bytea_output TO escape; -- Load a file -CREATE TABLE lotest_stash_values (loid oid, fd integer); +CREATE TABLE lotest_stash_values (loid oid, junk integer, fd integer); -- lo_creat(mode integer) returns oid -- The mode arg to lo_creat is unused, some vestigal holdover from ancient times -- returns the large object id -INSERT INTO lotest_stash_values (loid) SELECT lo_creat(42); +INSERT INTO lotest_stash_values (loid) VALUES( lo_creat(42) ); -- NOTE: large objects require transactions BEGIN; @@ -116,7 +116,7 @@ SELECT lo_unlink(loid) from lotest_stash_values; TRUNCATE lotest_stash_values; -INSERT INTO lotest_stash_values (loid) SELECT lo_import('@abs_srcdir@/data/tenk.data'); +INSERT INTO lotest_stash_values (loid) VALUES( lo_import('@abs_srcdir@/data/tenk.data') ); BEGIN; UPDATE lotest_stash_values SET fd=lo_open(loid, CAST(x'20000' | x'40000' AS integer)); @@ -144,12 +144,12 @@ END; SELECT lo_export(loid, '@abs_builddir@/results/lotest.txt') FROM lotest_stash_values; -\lo_import 'results/lotest.txt' +\lo_import '@abs_builddir@/results/lotest.txt' \set newloid :LASTOID -- just make sure \lo_export does not barf -\lo_export :newloid 'results/lotest2.txt' +\lo_export :newloid '@abs_builddir@/results/lotest2.txt' -- This is a hack to test that export/import are reversible -- This uses knowledge about the inner workings of large object mechanism diff --git a/src/test/regress/input/largeobject.source b/src/test/regress/output/largeobject_2.source similarity index 68% copy from src/test/regress/input/largeobject.source copy to src/test/regress/output/largeobject_2.source index 807cfd7..553521e 100644 --- a/src/test/regress/input/largeobject.source +++ b/src/test/regress/output/largeobject_2.source @@ -1,20 +1,16 @@ -- -- Test large object support -- - -- ensure consistent test output regardless of the default bytea format SET bytea_output TO escape; - -- Load a file -CREATE TABLE lotest_stash_values (loid oid, fd integer); +CREATE TABLE lotest_stash_values (loid oid, junk integer, fd integer); -- lo_creat(mode integer) returns oid -- The mode arg to lo_creat is unused, some vestigal holdover from ancient times -- returns the large object id -INSERT INTO lotest_stash_values (loid) SELECT lo_creat(42); - +INSERT INTO lotest_stash_values (loid) VALUES( lo_creat(42) ); -- NOTE: large objects require transactions BEGIN; - -- lo_open(lobjId oid, mode integer) returns integer -- The mode parameter to lo_open uses two constants: -- INV_READ = 0x20000 @@ -22,7 +18,6 @@ BEGIN; -- The return value is a file descriptor-like value which remains valid for the -- transaction. UPDATE lotest_stash_values SET fd = lo_open(loid, CAST(x'20000' | x'40000' AS integer)); - -- loread/lowrite names are wonky, different from other functions which are lo_* -- lowrite(fd integer, data bytea) returns integer -- the integer is the number of bytes written @@ -49,17 +44,23 @@ And miles to go before I sleep. -- Robert Frost ') FROM lotest_stash_values; + lowrite +--------- + 578 +(1 row) -- lo_close(fd integer) returns integer -- return value is 0 for success, or <0 for error (actually only -1, but...) SELECT lo_close(fd) FROM lotest_stash_values; + lo_close +---------- + 0 +(1 row) END; - -- Read out a portion BEGIN; UPDATE lotest_stash_values SET fd=lo_open(loid, CAST(x'20000' | x'40000' AS integer)); - -- lo_lseek(fd integer, offset integer, whence integer) returns integer -- offset is in bytes, whence is one of three values: -- SEEK_SET (= 0) meaning relative to beginning @@ -67,99 +68,219 @@ UPDATE lotest_stash_values SET fd=lo_open(loid, CAST(x'20000' | x'40000' AS inte -- SEEK_END (= 2) meaning relative to end (offset better be negative) -- returns current position in file SELECT lo_lseek(fd, 422, 0) FROM lotest_stash_values; + lo_lseek +---------- + 422 +(1 row) -- loread/lowrite names are wonky, different from other functions which are lo_* -- loread(fd integer, len integer) returns bytea SELECT loread(fd, 35) FROM lotest_stash_values; + loread +------------------------------------- + The woods are lovely, dark and deep +(1 row) SELECT lo_lseek(fd, -19, 1) FROM lotest_stash_values; + lo_lseek +---------- + 438 +(1 row) SELECT lowrite(fd, 'n') FROM lotest_stash_values; + lowrite +--------- + 1 +(1 row) SELECT lo_tell(fd) FROM lotest_stash_values; + lo_tell +--------- + 439 +(1 row) SELECT lo_lseek(fd, -156, 2) FROM lotest_stash_values; + lo_lseek +---------- + 422 +(1 row) SELECT loread(fd, 35) FROM lotest_stash_values; + loread +------------------------------------- + The woods are lonely, dark and deep +(1 row) SELECT lo_close(fd) FROM lotest_stash_values; + lo_close +---------- + 0 +(1 row) END; - -- Test resource management BEGIN; SELECT lo_open(loid, x'40000'::int) from lotest_stash_values; -ABORT; + lo_open +--------- + 0 +(1 row) +ABORT; -- Test truncation. BEGIN; UPDATE lotest_stash_values SET fd=lo_open(loid, CAST(x'20000' | x'40000' AS integer)); - SELECT lo_truncate(fd, 10) FROM lotest_stash_values; + lo_truncate +------------- + 0 +(1 row) + SELECT loread(fd, 15) FROM lotest_stash_values; + loread +--------------- + \012Whose woo +(1 row) SELECT lo_truncate(fd, 10000) FROM lotest_stash_values; + lo_truncate +------------- + 0 +(1 row) + SELECT loread(fd, 10) FROM lotest_stash_values; + loread +------------------------------------------ + \000\000\000\000\000\000\000\000\000\000 +(1 row) + SELECT lo_lseek(fd, 0, 2) FROM lotest_stash_values; + lo_lseek +---------- + 10000 +(1 row) + SELECT lo_tell(fd) FROM lotest_stash_values; + lo_tell +--------- + 10000 +(1 row) SELECT lo_truncate(fd, 5000) FROM lotest_stash_values; + lo_truncate +------------- + 0 +(1 row) + SELECT lo_lseek(fd, 0, 2) FROM lotest_stash_values; + lo_lseek +---------- + 5000 +(1 row) + SELECT lo_tell(fd) FROM lotest_stash_values; + lo_tell +--------- + 5000 +(1 row) SELECT lo_close(fd) FROM lotest_stash_values; -END; + lo_close +---------- + 0 +(1 row) +END; -- lo_unlink(lobjId oid) returns integer -- return value appears to always be 1 SELECT lo_unlink(loid) from lotest_stash_values; + lo_unlink +----------- + 1 +(1 row) TRUNCATE lotest_stash_values; - -INSERT INTO lotest_stash_values (loid) SELECT lo_import('@abs_srcdir@/data/tenk.data'); - +INSERT INTO lotest_stash_values (loid) VALUES( lo_import('/home/abbas/pgxc/postgres-xc/src/test/regress/data/tenk.data') ); BEGIN; UPDATE lotest_stash_values SET fd=lo_open(loid, CAST(x'20000' | x'40000' AS integer)); - -- with the default BLKSZ, LOBLKSZ = 2048, so this positions us for a block -- edge case SELECT lo_lseek(fd, 2030, 0) FROM lotest_stash_values; + lo_lseek +---------- + 2030 +(1 row) -- this should get half of the value from page 0 and half from page 1 of the -- large object SELECT loread(fd, 36) FROM lotest_stash_values; + loread +----------------------------------------------------------------- + AAA\011FBAAAA\011VVVVxx\0122513\01132\0111\0111\0113\01113\0111 +(1 row) SELECT lo_tell(fd) FROM lotest_stash_values; + lo_tell +--------- + 2066 +(1 row) SELECT lo_lseek(fd, -26, 1) FROM lotest_stash_values; + lo_lseek +---------- + 2040 +(1 row) SELECT lowrite(fd, 'abcdefghijklmnop') FROM lotest_stash_values; + lowrite +--------- + 16 +(1 row) SELECT lo_lseek(fd, 2030, 0) FROM lotest_stash_values; + lo_lseek +---------- + 2030 +(1 row) SELECT loread(fd, 36) FROM lotest_stash_values; + loread +----------------------------------------------------- + AAA\011FBAAAAabcdefghijklmnop1\0111\0113\01113\0111 +(1 row) SELECT lo_close(fd) FROM lotest_stash_values; -END; + lo_close +---------- + 0 +(1 row) +END; SELECT lo_export(loid, '@abs_builddir@/results/lotest.txt') FROM lotest_stash_values; + lo_export +----------- + 1 +(1 row) -\lo_import 'results/lotest.txt' - +\lo_import '@abs_builddir@/results/lotest.txt' \set newloid :LASTOID - -- just make sure \lo_export does not barf -\lo_export :newloid 'results/lotest2.txt' - +\lo_export :newloid '@abs_builddir@/results/lotest2.txt' -- This is a hack to test that export/import are reversible -- This uses knowledge about the inner workings of large object mechanism -- which should not be used outside it. This makes it a HACK SELECT pageno, data FROM pg_largeobject WHERE loid = (SELECT loid from lotest_stash_values) EXCEPT SELECT pageno, data FROM pg_largeobject WHERE loid = :newloid; - + pageno | data +--------+------ +(0 rows) SELECT lo_unlink(loid) FROM lotest_stash_values; -\lo_unlink :newloid + lo_unlink +----------- + 1 +(1 row) +\lo_unlink :newloid TRUNCATE lotest_stash_values; ----------------------------------------------------------------------- Summary of changes: src/test/regress/input/largeobject.source | 10 +++++----- .../{largeobject.source => largeobject_2.source} | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) copy src/test/regress/output/{largeobject.source => largeobject_2.source} (94%) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-13 03:25:41
|
Project "Postgres-XC". The branch, master has been updated via 04202cbdd151776cb44eefac7eeecdf05467cca7 (commit) from 2764f7b5379e3eb66d038a74aa0031e29a0de72c (commit) - Log ----------------------------------------------------------------- commit 04202cbdd151776cb44eefac7eeecdf05467cca7 Author: Michael P <mic...@us...> Date: Wed Apr 13 12:17:38 2011 +0900 Extension of CLEAN CONNECTION for specific users New synopsis of this query becomes: CLEAN CONNECTION TO (COORDINATOR num | DATANODE num | ALL {FORCE}) [ FOR DATABASE dbname ] [ TO USER username ]; This increases cleaning granularity of XC cluster. This query cannot be launched if no database or no user are specified. If only a user name is specified, cleaning is made for all the databases of this user. If only a database name is specified, cleaning is made for all the users of this database. It is also possible to specify both database and user name. This commit also contains modifications for cleaning connections when dropping a database. Now before dropping a database, CLEAN CONNECTION is launched first on all the Coordinators. Then drop query is sent to backend nodes. diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 0c7a3b5..1b43d6e 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -343,7 +343,7 @@ static TypeName *TableFuncTypeName(List *columns); %type <defelt> opt_binary opt_oids copy_delimiter /* PGXC_BEGIN */ %type <list> data_node_list coord_list -%type <str> DirectStmt +%type <str> DirectStmt CleanConnDbName CleanConnUserName /* PGXC_END */ %type <boolean> copy_from @@ -7144,38 +7144,52 @@ data_node_list: * QUERY: * * CLEAN CONNECTION TO (COORDINATOR num | NODE num | ALL {FORCE}) - * FOR DATABASE dbname + * [ FOR DATABASE dbname ] + * [ TO USER username ] * *****************************************************************************/ -CleanConnStmt: CLEAN CONNECTION TO COORDINATOR coord_list FOR DATABASE database_name +CleanConnStmt: CLEAN CONNECTION TO COORDINATOR coord_list CleanConnDbName CleanConnUserName { CleanConnStmt *n = makeNode(CleanConnStmt); n->is_coord = true; n->nodes = $5; n->is_force = false; - n->dbname = $8; + n->dbname = $6; + n->username = $7; $$ = (Node *)n; } - | CLEAN CONNECTION TO NODE data_node_list FOR DATABASE database_name + | CLEAN CONNECTION TO NODE data_node_list CleanConnDbName CleanConnUserName { CleanConnStmt *n = makeNode(CleanConnStmt); n->is_coord = false; n->nodes = $5; n->is_force = false; - n->dbname = $8; + n->dbname = $6; + n->username = $7; $$ = (Node *)n; } - | CLEAN CONNECTION TO ALL opt_force FOR DATABASE database_name + | CLEAN CONNECTION TO ALL opt_force CleanConnDbName CleanConnUserName { CleanConnStmt *n = makeNode(CleanConnStmt); n->is_coord = true; n->nodes = NIL; n->is_force = $5; - n->dbname = $8; + n->dbname = $6; + n->username = $7; $$ = (Node *)n; } ; + +CleanConnDbName: FOR DATABASE database_name { $$ = $3; } + | FOR database_name { $$ = $2; } + | /* EMPTY */ { $$ = NIL; } + ; + +CleanConnUserName: TO USER RoleId { $$ = $3; } + | TO RoleId { $$ = $2; } + | /* EMPTY */ { $$ = NIL; } + ; /* PGXC_END */ /***************************************************************************** diff --git a/src/backend/pgxc/pool/poolmgr.c b/src/backend/pgxc/pool/poolmgr.c index ecd18f9..717e3e3 100644 --- a/src/backend/pgxc/pool/poolmgr.c +++ b/src/backend/pgxc/pool/poolmgr.c @@ -98,7 +98,10 @@ static DatabasePool *create_database_pool(const char *database, const char *user static void insert_database_pool(DatabasePool *pool); static int destroy_database_pool(const char *database, const char *user_name); static DatabasePool *find_database_pool(const char *database, const char *user_name); -static DatabasePool *find_database_pool_to_clean(const char *database, List *dn_list, List *co_list); +static DatabasePool *find_database_pool_to_clean(const char *database, + const char *user_name, + List *dn_list, + List *co_list); static DatabasePool *remove_database_pool(const char *database, const char *user_name); static int *agent_acquire_connections(PoolAgent *agent, List *datanodelist, List *coordlist); static PGXCNodePoolSlot *acquire_connection(DatabasePool *dbPool, int node, char client_conn_type); @@ -110,8 +113,14 @@ static void destroy_slot(PGXCNodePoolSlot *slot); static void grow_pool(DatabasePool *dbPool, int index, char client_conn_type); static void destroy_node_pool(PGXCNodePool *node_pool); static void PoolerLoop(void); -static int clean_connection(List *dn_discard, List *co_discard, const char *database); -static int *abort_pids(int *count, int pid, const char *database); +static int clean_connection(List *dn_discard, + List *co_discard, + const char *database, + const char *user_name); +static int *abort_pids(int *count, + int pid, + const char *database, + const char *user_name); /* Signal handlers */ static void pooler_die(SIGNAL_ARGS); @@ -742,13 +751,39 @@ PoolManagerGetConnections(List *datanodelist, List *coordlist) * Take a lock forbidding access to Pooler for new transactions. */ int -PoolManagerAbortTransactions(char *dbname, int **proc_pids) +PoolManagerAbortTransactions(char *dbname, char *username, int **proc_pids) { - int num_proc_ids = 0; + int num_proc_ids = 0; + int n32, msglen; + char msgtype = 'a'; + int dblen = dbname ? strlen(dbname) + 1 : 0; + int userlen = username ? strlen(username) + 1 : 0; Assert(Handle); - pool_putmessage(&Handle->port, 'a', dbname, strlen(dbname) + 1); + /* Message type */ + pool_putbytes(&Handle->port, &msgtype, 1); + + /* Message length */ + msglen = dblen + userlen + 12; + n32 = htonl(msglen); + pool_putbytes(&Handle->port, (char *) &n32, 4); + + /* Length of Database string */ + n32 = htonl(dblen); + pool_putbytes(&Handle->port, (char *) &n32, 4); + + /* Send database name, followed by \0 terminator if necessary */ + if (dbname) + pool_putbytes(&Handle->port, dbname, dblen); + + /* Length of Username string */ + n32 = htonl(userlen); + pool_putbytes(&Handle->port, (char *) &n32, 4); + + /* Send user name, followed by \0 terminator if necessary */ + if (username) + pool_putbytes(&Handle->port, username, userlen); pool_flush(&Handle->port); @@ -763,13 +798,15 @@ PoolManagerAbortTransactions(char *dbname, int **proc_pids) * Clean up Pooled connections */ void -PoolManagerCleanConnection(List *datanodelist, List *coordlist, char *dbname) +PoolManagerCleanConnection(List *datanodelist, List *coordlist, char *dbname, char *username) { int totlen = list_length(datanodelist) + list_length(coordlist); int nodes[totlen + 2]; ListCell *nodelist_item; - int i, n32; + int i, n32, msglen; char msgtype = 'f'; + int userlen = username ? strlen(username) + 1 : 0; + int dblen = dbname ? strlen(dbname) + 1 : 0; nodes[0] = htonl(list_length(datanodelist)); i = 1; @@ -794,18 +831,29 @@ PoolManagerCleanConnection(List *datanodelist, List *coordlist, char *dbname) pool_putbytes(&Handle->port, &msgtype, 1); /* Message length */ - n32 = htonl(sizeof(int) * (totlen + 2) + strlen(dbname) + 9); + msglen = sizeof(int) * (totlen + 2) + dblen + userlen + 12; + n32 = htonl(msglen); pool_putbytes(&Handle->port, (char *) &n32, 4); /* Send list of nodes */ pool_putbytes(&Handle->port, (char *) nodes, sizeof(int) * (totlen + 2)); /* Length of Database string */ - n32 = htonl(strlen(dbname) + 1); + n32 = htonl(dblen); pool_putbytes(&Handle->port, (char *) &n32, 4); - /* Send database name, followed by \0 terminator */ - pool_putbytes(&Handle->port, dbname, strlen(dbname) + 1); + /* Send database name, followed by \0 terminator if necessary */ + if (dbname) + pool_putbytes(&Handle->port, dbname, dblen); + + /* Length of Username string */ + n32 = htonl(userlen); + pool_putbytes(&Handle->port, (char *) &n32, 4); + + /* Send user name, followed by \0 terminator if necessary */ + if (username) + pool_putbytes(&Handle->port, username, userlen); + pool_flush(&Handle->port); /* Receive result message */ @@ -830,8 +878,8 @@ agent_handle_input(PoolAgent * agent, StringInfo s) */ for (;;) { - const char *database; - const char *user_name; + const char *database = NULL; + const char *user_name = NULL; const char *set_command; bool is_local; int datanodecount; @@ -858,9 +906,17 @@ agent_handle_input(PoolAgent * agent, StringInfo s) { case 'a': /* ABORT */ pool_getmessage(&agent->port, s, 0); - database = pq_getmsgstring(s); + len = pq_getmsgint(s, 4); + if (len > 0) + database = pq_getmsgbytes(s, len); + + len = pq_getmsgint(s, 4); + if (len > 0) + user_name = pq_getmsgbytes(s, len); + pq_getmsgend(s); - pids = abort_pids(&len, agent->pid, database); + + pids = abort_pids(&len, agent->pid, database, user_name); pool_sendpids(&agent->port, pids, len); if (pids) @@ -896,11 +952,16 @@ agent_handle_input(PoolAgent * agent, StringInfo s) for (i = 0; i < coordcount; i++) coordlist = lappend_int(coordlist, pq_getmsgint(s, 4)); len = pq_getmsgint(s, 4); - database = pq_getmsgbytes(s, len); + if (len > 0) + database = pq_getmsgbytes(s, len); + len = pq_getmsgint(s, 4); + if (len > 0) + user_name = pq_getmsgbytes(s, len); + pq_getmsgend(s); /* Clean up connections here */ - res = clean_connection(datanodelist, coordlist, database); + res = clean_connection(datanodelist, coordlist, database, user_name); list_free(datanodelist); list_free(coordlist); @@ -1551,7 +1612,10 @@ find_database_pool(const char *database, const char *user_name) * Find pool to be cleaned for specified database in the list */ static DatabasePool * -find_database_pool_to_clean(const char *database, List *dn_list, List *co_list) +find_database_pool_to_clean(const char *database, + const char *user_name, + List *dn_list, + List *co_list) { DatabasePool *databasePool; @@ -1559,33 +1623,44 @@ find_database_pool_to_clean(const char *database, List *dn_list, List *co_list) databasePool = databasePools; while (databasePool) { - /* Check for given database name */ - if (strcmp(database, databasePool->database) == 0) + ListCell *nodelist_item; + + /* If database name does not correspond, move to next one */ + if (database && strcmp(database, databasePool->database) != 0) { - ListCell *nodelist_item; + databasePool = databasePool->next; + continue; + } - /* Check if this database pool is clean for given coordinator list */ - foreach (nodelist_item, co_list) - { - int nodenum = lfirst_int(nodelist_item); + /* If user name does not correspond, move to next one */ + if (user_name && strcmp(user_name, databasePool->user_name) != 0) + { + databasePool = databasePool->next; + continue; + } - if (databasePool->coordNodePools && - databasePool->coordNodePools[nodenum - 1] && - databasePool->coordNodePools[nodenum - 1]->freeSize != 0) - return databasePool; - } + /* Check if this database pool is clean for given coordinator list */ + foreach (nodelist_item, co_list) + { + int nodenum = lfirst_int(nodelist_item); - /* Check if this database pool is clean for given datanode list */ - foreach (nodelist_item, dn_list) - { - int nodenum = lfirst_int(nodelist_item); + if (databasePool->coordNodePools && + databasePool->coordNodePools[nodenum - 1] && + databasePool->coordNodePools[nodenum - 1]->freeSize != 0) + return databasePool; + } - if (databasePool->dataNodePools && - databasePool->dataNodePools[nodenum - 1] && - databasePool->dataNodePools[nodenum - 1]->freeSize != 0) - return databasePool; - } + /* Check if this database pool is clean for given datanode list */ + foreach (nodelist_item, dn_list) + { + int nodenum = lfirst_int(nodelist_item); + + if (databasePool->dataNodePools && + databasePool->dataNodePools[nodenum - 1] && + databasePool->dataNodePools[nodenum - 1]->freeSize != 0) + return databasePool; } + databasePool = databasePool->next; } return databasePool; @@ -2016,7 +2091,7 @@ PoolerLoop(void) #define TIMEOUT_CLEAN_LOOP 10 int -clean_connection(List *dn_discard, List *co_discard, const char *database) +clean_connection(List *dn_discard, List *co_discard, const char *database, const char *user_name) { DatabasePool *databasePool; int dn_len = list_length(dn_discard); @@ -2038,11 +2113,11 @@ clean_connection(List *dn_discard, List *co_discard, const char *database) co_list[count++] = lfirst_int(nodelist_item); /* Find correct Database pool to clean */ - databasePool = find_database_pool_to_clean(database, dn_discard, co_discard); + databasePool = find_database_pool_to_clean(database, user_name, dn_discard, co_discard); while (databasePool) { - databasePool = find_database_pool_to_clean(database, dn_discard, co_discard); + databasePool = find_database_pool_to_clean(database, user_name, dn_discard, co_discard); /* Database pool has not been found, cleaning is over */ if (!databasePool) @@ -2125,7 +2200,7 @@ clean_connection(List *dn_discard, List *co_discard, const char *database) * Send back to client list of PIDs signaled to watch them. */ int * -abort_pids(int *len, int pid, const char *database) +abort_pids(int *len, int pid, const char *database, const char *user_name) { int *pids = NULL; int i = 0; @@ -2141,15 +2216,20 @@ abort_pids(int *len, int pid, const char *database) /* Send a SIGTERM signal to all processes of Pooler agents except this one */ for (count = 0; count < agentCount; count++) { - if (poolAgents[count]->pid != pid && - strcmp(poolAgents[count]->pool->database, database) == 0) - { - if (kill(poolAgents[count]->pid, SIGTERM) < 0) - elog(ERROR, "kill(%ld,%d) failed: %m", - (long) poolAgents[count]->pid, SIGTERM); + if (poolAgents[count]->pid == pid) + continue; - pids[i++] = poolAgents[count]->pid; - } + if (database && strcmp(poolAgents[count]->pool->database, database) != 0) + continue; + + if (user_name && strcmp(poolAgents[count]->pool->user_name, user_name) != 0) + continue; + + if (kill(poolAgents[count]->pid, SIGTERM) < 0) + elog(ERROR, "kill(%ld,%d) failed: %m", + (long) poolAgents[count]->pid, SIGTERM); + + pids[i++] = poolAgents[count]->pid; } *len = i; diff --git a/src/backend/pgxc/pool/poolutils.c b/src/backend/pgxc/pool/poolutils.c index 24a5c72..cf16c35 100644 --- a/src/backend/pgxc/pool/poolutils.c +++ b/src/backend/pgxc/pool/poolutils.c @@ -23,6 +23,7 @@ #include "pgxc/poolutils.h" #include "access/gtm.h" #include "commands/dbcommands.h" +#include "utils/lsyscache.h" #include "utils/acl.h" #include "nodes/parsenodes.h" @@ -36,30 +37,40 @@ * Use of CLEAN CONNECTION is limited to a super user. * It is advised to clean connections before shutting down a Node or drop a Database. * - * Pool cleaning is done for all the users of a given database. - * * SQL query synopsis is as follows: * CLEAN CONNECTION TO * (COORDINATOR num | DATANODE num | ALL {FORCE}) - * FOR DATABASE dbname + * [ FOR DATABASE dbname ] + * [ TO USER username ] * - * Connection cleaning has to be made on a chosen database called dbname. + * Connection cleaning can be made on a chosen database called dbname + * or/and a chosen user. + * Cleaning is done for all the users of a given database + * if no user name is specified. + * Cleaning is done for all the databases for one user + * if no database name is specified. * * It is also possible to clean connections of several Coordinators or Datanodes * Ex: CLEAN CONNECTION TO DATANODE 1,5,7 FOR DATABASE template1 * CLEAN CONNECTION TO COORDINATOR 2,4,6 FOR DATABASE template1 + * CLEAN CONNECTION TO DATANODE 3,5 TO USER postgres + * CLEAN CONNECTION TO COORDINATOR 6,1 FOR DATABASE template1 TO USER postgres * * Or even to all Coordinators/Datanodes at the same time * Ex: CLEAN CONNECTION TO DATANODE * FOR DATABASE template1 * CLEAN CONNECTION TO COORDINATOR * FOR DATABASE template1 + * CLEAN CONNECTION TO COORDINATOR * TO USER postgres + * CLEAN CONNECTION TO COORDINATOR * FOR DATABASE template1 TO USER postgres * * When FORCE is used, all the transactions using pooler connections are aborted, * and pooler connections are cleaned up. * Ex: CLEAN CONNECTION TO ALL FORCE FOR DATABASE template1; + * CLEAN CONNECTION TO ALL FORCE TO USER postgres; + * CLEAN CONNECTION TO ALL FORCE FOR DATABASE template1 TO USER postgres; * * FORCE can only be used with TO ALL, as it takes a lock on pooler to stop requests * asking for connections, aborts all the connections in the cluster, and cleans up - * pool connections. + * pool connections associated to the given user and/or database. */ void CleanConnection(CleanConnStmt *stmt) @@ -69,10 +80,10 @@ CleanConnection(CleanConnStmt *stmt) List *dn_list = NIL; List *stmt_nodes = NIL; char *dbname = stmt->dbname; + char *username = stmt->username; bool is_coord = stmt->is_coord; bool is_force = stmt->is_force; int max_node_number = 0; - Oid oid; /* Only a DB administrator can clean pooler connections */ if (!superuser()) @@ -80,9 +91,15 @@ CleanConnection(CleanConnStmt *stmt) (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to clean pool connections"))); + /* Database name or user name is mandatory */ + if (!dbname && !username) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("must define Database name or user name"))); + /* Check if the Database exists by getting its Oid */ - oid = get_database_oid(dbname); - if (!OidIsValid(oid)) + if (dbname && + !OidIsValid(get_database_oid(dbname))) { ereport(WARNING, (errcode(ERRCODE_UNDEFINED_DATABASE), @@ -90,6 +107,16 @@ CleanConnection(CleanConnStmt *stmt) return; } + /* Check if role exists */ + if (username && + !OidIsValid(get_roleid(username))) + { + ereport(WARNING, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("role \"%s\" does not exist", username))); + return; + } + /* * FORCE is activated, * Send a SIGTERM signal to all the processes and take a lock on Pooler @@ -102,7 +129,7 @@ CleanConnection(CleanConnStmt *stmt) int *proc_pids = NULL; int num_proc_pids, count; - num_proc_pids = PoolManagerAbortTransactions(dbname, &proc_pids); + num_proc_pids = PoolManagerAbortTransactions(dbname, username, &proc_pids); /* * Watch the processes that received a SIGTERM. @@ -180,7 +207,7 @@ CleanConnection(CleanConnStmt *stmt) */ /* Finish by contacting Pooler Manager */ - PoolManagerCleanConnection(dn_list, co_list, dbname); + PoolManagerCleanConnection(dn_list, co_list, dbname, username); /* Clean up memory */ if (co_list) @@ -200,13 +227,14 @@ DropDBCleanConnection(char *dbname) { List *co_list = GetAllCoordNodes(); List *dn_list = GetAllDataNodes(); + char query[256]; /* Check permissions for this database */ if (!pg_database_ownercheck(get_database_oid(dbname), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, dbname); - PoolManagerCleanConnection(dn_list, co_list, dbname); + PoolManagerCleanConnection(dn_list, co_list, dbname, NULL); /* Clean up memory */ if (co_list) diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 98d19fa..e4f33c5 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -1355,8 +1355,16 @@ standard_ProcessUtility(Node *parsetree, #ifdef PGXC /* Clean connections before dropping a database on local node */ - if (IS_PGXC_COORDINATOR) + if (IS_PGXC_COORDINATOR && !IsConnFromCoord()) + { + char query[256]; DropDBCleanConnection(stmt->dbname); + + /* Clean also remote Coordinators */ + sprintf(query, "CLEAN CONNECTION TO ALL FOR DATABASE %s;", stmt->dbname); + + ExecUtilityStmtOnNodes(query, NULL, true, EXEC_ON_COORDS); + } #endif PreventTransactionChain(isTopLevel, "DROP DATABASE"); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index ebe0c56..c571667 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2521,6 +2521,7 @@ typedef struct CleanConnStmt NodeTag type; List *nodes; /* list of nodes dropped */ char *dbname; /* name of database to drop connections */ + char *username; /* name of user whose connections are dropped */ bool is_coord; /* type of connections dropped */ bool is_force; /* option force */ } CleanConnStmt; diff --git a/src/include/pgxc/poolmgr.h b/src/include/pgxc/poolmgr.h index febf1d4..18569dc 100644 --- a/src/include/pgxc/poolmgr.h +++ b/src/include/pgxc/poolmgr.h @@ -141,10 +141,10 @@ extern int PoolManagerSetCommand(bool is_local, const char *set_command); extern int *PoolManagerGetConnections(List *datanodelist, List *coordlist); /* Clean pool connections */ -extern void PoolManagerCleanConnection(List *datanodelist, List *coordlist, char *dbname); +extern void PoolManagerCleanConnection(List *datanodelist, List *coordlist, char *dbname, char *username); /* Send Abort signal to transactions being run */ -extern int PoolManagerAbortTransactions(char *dbname, int **proc_pids); +extern int PoolManagerAbortTransactions(char *dbname, char *username, int **proc_pids); /* Return connections back to the pool, for both Coordinator and Datanode connections */ extern void PoolManagerReleaseConnections(int dn_ndisc, int* dn_discard, int co_ndisc, int* co_discard); ----------------------------------------------------------------------- Summary of changes: src/backend/parser/gram.y | 30 +++++-- src/backend/pgxc/pool/poolmgr.c | 184 ++++++++++++++++++++++++++----------- src/backend/pgxc/pool/poolutils.c | 50 ++++++++-- src/backend/tcop/utility.c | 10 ++- src/include/nodes/parsenodes.h | 1 + src/include/pgxc/poolmgr.h | 4 +- 6 files changed, 205 insertions(+), 74 deletions(-) hooks/post-receive -- Postgres-XC |
From: Michael P. <mic...@us...> - 2011-04-12 06:22:22
|
Project "website". The branch, master has been updated via 0d458b46802e6e5e9035b37672dffe5a609a81c9 (commit) from 73afa8b8e55f695a042f4449334d839bf1b9ecfe (commit) - Log ----------------------------------------------------------------- commit 0d458b46802e6e5e9035b37672dffe5a609a81c9 Author: Michael P <mic...@us...> Date: Tue Apr 12 15:19:00 2011 +0900 Typo correction diff --git a/roadmap.html b/roadmap.html index 525f005..3ab431d 100755 --- a/roadmap.html +++ b/roadmap.html @@ -85,7 +85,7 @@ subqueries<br> <!-- ==== For Version 1.0 ==== --> <h4> -Version 0.9.5 (March, 2011) +Version 0.9.5 (June, 2011) </h4> <p class="inner"> ----------------------------------------------------------------------- Summary of changes: roadmap.html | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) hooks/post-receive -- website |