diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index 0a2d70e6b69..18271b24f76 100644 --- a/contrib/dblink/dblink.c +++ b/contrib/dblink/dblink.c @@ -88,6 +88,7 @@ static Oid get_relid_from_relname(text *relname_text); static char *generate_relation_name(Oid relid); static char *connstr_strip_password(const char *connstr); static void dblink_security_check(PGconn *conn, remoteConn *rcon, const char *connstr); +static int get_nondropped_natts(Oid relid); /* Global */ List *res_id = NIL; @@ -985,6 +986,7 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS) int16 typlen; bool typbyval; char typalign; + int nondropped_natts; relname_text = PG_GETARG_TEXT_P(0); @@ -1016,6 +1018,15 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("number of key attributes must be > 0"))); + /* + * 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"))); + src_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3); tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4); @@ -1132,6 +1143,7 @@ dblink_build_sql_delete(PG_FUNCTION_ARGS) int16 typlen; bool typbyval; char typalign; + int nondropped_natts; relname_text = PG_GETARG_TEXT_P(0); @@ -1163,6 +1175,15 @@ dblink_build_sql_delete(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("number of key attributes must be > 0"))); + /* + * 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"))); + tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3); /* @@ -1254,6 +1275,7 @@ dblink_build_sql_update(PG_FUNCTION_ARGS) int16 typlen; bool typbyval; char typalign; + int nondropped_natts; relname_text = PG_GETARG_TEXT_P(0); @@ -1285,6 +1307,15 @@ dblink_build_sql_update(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("number of key attributes must be > 0"))); + /* + * 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"))); + src_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3); tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4); @@ -2134,3 +2165,27 @@ dblink_security_check(PGconn *conn, remoteConn *rcon, const char *connstr) PQfinish(conn); } } + +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; +} diff --git a/contrib/dblink/expected/dblink.out b/contrib/dblink/expected/dblink.out index 7ef40b06d79..4c27ad23651 100644 --- a/contrib/dblink/expected/dblink.out +++ b/contrib/dblink/expected/dblink.out @@ -44,6 +44,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"}'); @@ -52,6 +55,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 @@ -59,6 +65,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)); diff --git a/contrib/dblink/sql/dblink.sql b/contrib/dblink/sql/dblink.sql index d0e448fc0b0..15e33144e13 100644 --- a/contrib/dblink/sql/dblink.sql +++ b/contrib/dblink/sql/dblink.sql @@ -35,13 +35,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";