On 02/03/2010 10:18 AM, Tom Lane wrote:
> Joe Conway <m...@joeconway.com> 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";

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to