On 02/03/2010 10:18 AM, Tom Lane wrote: > Joe Conway <[email protected]> writes: >> The problem exists with all three dblink_build_sql_* functions. Here is >> a more complete patch. If there are no objections I'll apply this to >> HEAD and look at back-patching -- these functions have hardly been >> touched since inception. > > Do you really need to copy the relation tupdesc when you only are going > to make a one-time check of the number of attributes? This coding would > make some sense if you intended to use the tupdesc again later in the > functions, but it appears you don't. > > Also, what about cases where the relation contains dropped columns --- > it's not obvious whether this test is correct in that case.
Good input, as always. Here's another whack at it. Thanks, Joe
Index: dblink.c
===================================================================
RCS file: /opt/src/cvs/pgsql/contrib/dblink/dblink.c,v
retrieving revision 1.87
diff -c -r1.87 dblink.c
*** dblink.c 24 Jan 2010 22:19:38 -0000 1.87
--- dblink.c 3 Feb 2010 19:23:51 -0000
***************
*** 101,106 ****
--- 101,107 ----
static void dblink_res_error(const char *conname, PGresult *res, const char *dblink_context_msg, bool fail);
static char *get_connect_string(const char *servername);
static char *escape_param_str(const char *from);
+ static int get_nondropped_natts(Oid relid);
/* Global */
static remoteConn *pconn = NULL;
***************
*** 1262,1267 ****
--- 1263,1269 ----
int src_nitems;
int tgt_nitems;
char *sql;
+ int nondropped_natts;
/*
* Convert relname to rel OID.
***************
*** 1290,1295 ****
--- 1292,1306 ----
"attributes too large")));
/*
+ * ensure we don't ask for more pk attributes than we have
+ * non-dropped columns
+ */
+ nondropped_natts = get_nondropped_natts(relid);
+ if (pknumatts > nondropped_natts)
+ ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("number of primary key fields exceeds number of specified relation attributes")));
+
+ /*
* Source array is made up of key values that will be used to locate the
* tuple of interest from the local system.
*/
***************
*** 1354,1359 ****
--- 1365,1371 ----
int2vector *pkattnums = (int2vector *) PG_GETARG_POINTER(1);
int32 pknumatts_tmp = PG_GETARG_INT32(2);
ArrayType *tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
+ int nondropped_natts;
Oid relid;
int16 pknumatts = 0;
char **tgt_pkattvals;
***************
*** 1387,1392 ****
--- 1399,1413 ----
"attributes too large")));
/*
+ * ensure we don't ask for more pk attributes than we have
+ * non-dropped columns
+ */
+ nondropped_natts = get_nondropped_natts(relid);
+ if (pknumatts > nondropped_natts)
+ ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("number of primary key fields exceeds number of specified relation attributes")));
+
+ /*
* Target array is made up of key values that will be used to build the
* SQL string for use on the remote system.
*/
***************
*** 1441,1446 ****
--- 1462,1468 ----
int32 pknumatts_tmp = PG_GETARG_INT32(2);
ArrayType *src_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
ArrayType *tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4);
+ int nondropped_natts;
Oid relid;
int16 pknumatts = 0;
char **src_pkattvals;
***************
*** 1476,1481 ****
--- 1498,1512 ----
"attributes too large")));
/*
+ * ensure we don't ask for more pk attributes than we have
+ * non-dropped columns
+ */
+ nondropped_natts = get_nondropped_natts(relid);
+ if (pknumatts > nondropped_natts)
+ ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("number of primary key fields exceeds number of specified relation attributes")));
+
+ /*
* Source array is made up of key values that will be used to locate the
* tuple of interest from the local system.
*/
***************
*** 2442,2444 ****
--- 2473,2500 ----
return buf->data;
}
+
+ static int
+ get_nondropped_natts(Oid relid)
+ {
+ int nondropped_natts = 0;
+ TupleDesc tupdesc;
+ Relation rel;
+ int natts;
+ int i;
+
+ rel = relation_open(relid, AccessShareLock);
+ tupdesc = rel->rd_att;
+ natts = tupdesc->natts;
+
+ for (i = 0; i < natts; i++)
+ {
+ if (tupdesc->attrs[i]->attisdropped)
+ continue;
+ nondropped_natts++;
+ }
+
+ relation_close(rel, AccessShareLock);
+ return nondropped_natts;
+ }
+
Index: expected/dblink.out
===================================================================
RCS file: /opt/src/cvs/pgsql/contrib/dblink/expected/dblink.out,v
retrieving revision 1.27
diff -c -r1.27 dblink.out
*** expected/dblink.out 22 Nov 2009 05:20:38 -0000 1.27
--- expected/dblink.out 3 Feb 2010 18:01:25 -0000
***************
*** 39,44 ****
--- 39,47 ----
INSERT INTO foo(f1,f2,f3) VALUES('99','xyz','{a0,b0,c0}')
(1 row)
+ -- too many pk fields, should fail
+ SELECT dblink_build_sql_insert('foo','1 2 3 4',4,'{"0", "a", "{a0,b0,c0}"}','{"99", "xyz", "{za0,zb0,zc0}"}');
+ ERROR: number of primary key fields exceeds number of specified relation attributes
-- build an update statement based on a local tuple,
-- replacing the primary key values with new ones
SELECT dblink_build_sql_update('foo','1 2',2,'{"0", "a"}','{"99", "xyz"}');
***************
*** 47,52 ****
--- 50,58 ----
UPDATE foo SET f1 = '99', f2 = 'xyz', f3 = '{a0,b0,c0}' WHERE f1 = '99' AND f2 = 'xyz'
(1 row)
+ -- too many pk fields, should fail
+ SELECT dblink_build_sql_update('foo','1 2 3 4',4,'{"0", "a", "{a0,b0,c0}"}','{"99", "xyz", "{za0,zb0,zc0}"}');
+ ERROR: number of primary key fields exceeds number of specified relation attributes
-- build a delete statement based on a local tuple,
SELECT dblink_build_sql_delete('foo','1 2',2,'{"0", "a"}');
dblink_build_sql_delete
***************
*** 54,59 ****
--- 60,68 ----
DELETE FROM foo WHERE f1 = '0' AND f2 = 'a'
(1 row)
+ -- too many pk fields, should fail
+ SELECT dblink_build_sql_delete('foo','1 2 3 4',4,'{"0", "a", "{a0,b0,c0}"}');
+ ERROR: number of primary key fields exceeds number of specified relation attributes
-- retest using a quoted and schema qualified table
CREATE SCHEMA "MySchema";
CREATE TABLE "MySchema"."Foo"(f1 int, f2 text, f3 text[], primary key (f1,f2));
Index: sql/dblink.sql
===================================================================
RCS file: /opt/src/cvs/pgsql/contrib/dblink/sql/dblink.sql,v
retrieving revision 1.22
diff -c -r1.22 dblink.sql
*** sql/dblink.sql 5 Aug 2009 16:11:07 -0000 1.22
--- sql/dblink.sql 3 Feb 2010 17:59:11 -0000
***************
*** 34,46 ****
--- 34,52 ----
-- build an insert statement based on a local tuple,
-- replacing the primary key values with new ones
SELECT dblink_build_sql_insert('foo','1 2',2,'{"0", "a"}','{"99", "xyz"}');
+ -- too many pk fields, should fail
+ SELECT dblink_build_sql_insert('foo','1 2 3 4',4,'{"0", "a", "{a0,b0,c0}"}','{"99", "xyz", "{za0,zb0,zc0}"}');
-- build an update statement based on a local tuple,
-- replacing the primary key values with new ones
SELECT dblink_build_sql_update('foo','1 2',2,'{"0", "a"}','{"99", "xyz"}');
+ -- too many pk fields, should fail
+ SELECT dblink_build_sql_update('foo','1 2 3 4',4,'{"0", "a", "{a0,b0,c0}"}','{"99", "xyz", "{za0,zb0,zc0}"}');
-- build a delete statement based on a local tuple,
SELECT dblink_build_sql_delete('foo','1 2',2,'{"0", "a"}');
+ -- too many pk fields, should fail
+ SELECT dblink_build_sql_delete('foo','1 2 3 4',4,'{"0", "a", "{a0,b0,c0}"}');
-- retest using a quoted and schema qualified table
CREATE SCHEMA "MySchema";
signature.asc
Description: OpenPGP digital signature
