]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Check to ensure the number of primary key fields supplied does not
authorJoe Conway <mail@joeconway.com>
Wed, 3 Feb 2010 23:01:34 +0000 (23:01 +0000)
committerJoe Conway <mail@joeconway.com>
Wed, 3 Feb 2010 23:01:34 +0000 (23:01 +0000)
exceed the total number of non-dropped source table fields for
dblink_build_sql_*(). Addresses bug report from Rushabh Lathia.

Backpatch all the way to the 7.3 branch.

contrib/dblink/dblink.c
contrib/dblink/expected/dblink.out
contrib/dblink/sql/dblink.sql

index 234d84cf831d7c5059cb9e16946c53c7e1db3072..1360c7a00dc0f4540b35ec85f16ae29ee4ae73cb 100644 (file)
@@ -8,7 +8,7 @@
  * Darko Prenosil <Darko.Prenosil@finteh.hr>
  * Shridhar Daithankar <shridhar_daithankar@persistent.co.in>
  *
- * $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.69.2.2 2009/01/03 19:57:54 joe Exp $
+ * $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.69.2.3 2010/02/03 23:01:34 joe Exp $
  * Copyright (c) 2001-2008, PostgreSQL Global Development Group
  * ALL RIGHTS RESERVED;
  *
@@ -94,6 +94,7 @@ static HeapTuple get_tuple_of_interest(Oid relid, int2vector *pkattnums, int16 p
 static Oid     get_relid_from_relname(text *relname_text);
 static char *generate_relation_name(Oid relid);
 static void dblink_security_check(PGconn *conn, remoteConn *rconn);
+static int get_nondropped_natts(Oid relid);
 
 /* Global */
 static remoteConn *pconn = NULL;
@@ -1391,6 +1392,7 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS)
        int                     src_nitems;
        int                     tgt_nitems;
        char       *sql;
+       int                     nondropped_natts;
 
        /*
         * Convert relname to rel OID.
@@ -1418,6 +1420,15 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS)
                                 errmsg("input for number of primary key " \
                                                "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.
@@ -1483,6 +1494,7 @@ dblink_build_sql_delete(PG_FUNCTION_ARGS)
        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;
@@ -1515,6 +1527,15 @@ dblink_build_sql_delete(PG_FUNCTION_ARGS)
                                 errmsg("input for number of primary key " \
                                                "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.
@@ -1570,6 +1591,7 @@ dblink_build_sql_update(PG_FUNCTION_ARGS)
        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;
@@ -1604,6 +1626,15 @@ dblink_build_sql_update(PG_FUNCTION_ARGS)
                                 errmsg("input for number of primary key " \
                                                "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.
@@ -2319,3 +2350,28 @@ dblink_security_check(PGconn *conn, remoteConn *rconn)
                }
        }
 }
+
+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 fd35d76af9672cf22db450c34e551064d6b8b109..c8a855f58fe6aeb53aac2685aac301c054772017 100644 (file)
@@ -46,6 +46,9 @@ SELECT dblink_build_sql_insert('foo','1 2',2,'{"0", "a"}','{"99", "xyz"}');
  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"}');
@@ -54,6 +57,9 @@ SELECT dblink_build_sql_update('foo','1 2',2,'{"0", "a"}','{"99", "xyz"}');
  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           
@@ -61,6 +67,9 @@ SELECT dblink_build_sql_delete('foo','1 2',2,'{"0", "a"}');
  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 48e1daca54d2b800ba97dd8dbc637319b89b9d6d..c3984ae54c65838f7f7fcdb2aa619a4a33b1f2e0 100644 (file)
@@ -37,13 +37,19 @@ FROM dblink_get_pkey('foo');
 -- 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";