diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index a8a6d4a5c4380a5390613819e4e5843e37cafdea..04354e16b86e525856a720027c1b7c4043dd5e45 100644 --- a/contrib/dblink/dblink.c +++ b/contrib/dblink/dblink.c @@ -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.97 2010/06/15 19:04:15 tgl Exp $ + * $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.98 2010/06/15 20:29:01 tgl Exp $ * Copyright (c) 2001-2010, PostgreSQL Global Development Group * ALL RIGHTS RESERVED; * @@ -2381,11 +2381,13 @@ escape_param_str(const char *str) * Validate the PK-attnums argument for dblink_build_sql_insert() and related * functions, and translate to the internal representation. * - * The user supplies an int2vector of 1-based physical attnums, plus a count + * The user supplies an int2vector of 1-based logical attnums, plus a count * argument (the need for the separate count argument is historical, but we * still check it). We check that each attnum corresponds to a valid, * non-dropped attribute of the rel. We do *not* prevent attnums from being * listed twice, though the actual use-case for such things is dubious. + * Note that before Postgres 9.0, the user's attnums were interpreted as + * physical not logical column numbers; this was changed for future-proofing. * * The internal representation is a palloc'd int array of 0-based physical * attnums. @@ -2416,12 +2418,32 @@ validate_pkattnums(Relation rel, for (i = 0; i < pknumatts_arg; i++) { int pkattnum = pkattnums_arg->values[i]; + int lnum; + int j; - if (pkattnum <= 0 || pkattnum > natts || - tupdesc->attrs[pkattnum - 1]->attisdropped) + /* Can throw error immediately if out of range */ + if (pkattnum <= 0 || pkattnum > natts) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid attribute number %d", pkattnum))); + + /* Identify which physical column has this logical number */ + lnum = 0; + for (j = 0; j < natts; j++) + { + /* dropped columns don't count */ + if (tupdesc->attrs[j]->attisdropped) + continue; + + if (++lnum == pkattnum) + break; + } + + if (j < natts) + (*pkattnums)[i] = j; + else ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid attribute number %d", pkattnum))); - (*pkattnums)[i] = pkattnum - 1; } } diff --git a/contrib/dblink/expected/dblink.out b/contrib/dblink/expected/dblink.out index 454588d94cad3db6d33a9e09be650b3a1533fc23..c59a67c7374041580c42e201506d798e66c25c35 100644 --- a/contrib/dblink/expected/dblink.out +++ b/contrib/dblink/expected/dblink.out @@ -903,21 +903,21 @@ ALTER TABLE test_dropped DROP COLUMN col2, ADD COLUMN col3 VARCHAR(10) NOT NULL DEFAULT 'foo', ADD COLUMN col4 INT NOT NULL DEFAULT 42; -SELECT dblink_build_sql_insert('test_dropped', '2', 1, +SELECT dblink_build_sql_insert('test_dropped', '1', 1, ARRAY['1'::TEXT], ARRAY['2'::TEXT]); dblink_build_sql_insert --------------------------------------------------------------------------- INSERT INTO test_dropped(id,col2b,col3,col4) VALUES('2','113','foo','42') (1 row) -SELECT dblink_build_sql_update('test_dropped', '2', 1, +SELECT dblink_build_sql_update('test_dropped', '1', 1, ARRAY['1'::TEXT], ARRAY['2'::TEXT]); dblink_build_sql_update ------------------------------------------------------------------------------------------- UPDATE test_dropped SET id = '2', col2b = '113', col3 = 'foo', col4 = '42' WHERE id = '2' (1 row) -SELECT dblink_build_sql_delete('test_dropped', '2', 1, +SELECT dblink_build_sql_delete('test_dropped', '1', 1, ARRAY['2'::TEXT]); dblink_build_sql_delete ----------------------------------------- diff --git a/contrib/dblink/sql/dblink.sql b/contrib/dblink/sql/dblink.sql index b15c4ddaf0c8c1a97ade0e7ec62c814d09a7ebd8..a6d7811bfc8b2ff9dc53e2c64d2293deef67a285 100644 --- a/contrib/dblink/sql/dblink.sql +++ b/contrib/dblink/sql/dblink.sql @@ -430,11 +430,11 @@ ALTER TABLE test_dropped ADD COLUMN col3 VARCHAR(10) NOT NULL DEFAULT 'foo', ADD COLUMN col4 INT NOT NULL DEFAULT 42; -SELECT dblink_build_sql_insert('test_dropped', '2', 1, +SELECT dblink_build_sql_insert('test_dropped', '1', 1, ARRAY['1'::TEXT], ARRAY['2'::TEXT]); -SELECT dblink_build_sql_update('test_dropped', '2', 1, +SELECT dblink_build_sql_update('test_dropped', '1', 1, ARRAY['1'::TEXT], ARRAY['2'::TEXT]); -SELECT dblink_build_sql_delete('test_dropped', '2', 1, +SELECT dblink_build_sql_delete('test_dropped', '1', 1, ARRAY['2'::TEXT]); diff --git a/doc/src/sgml/dblink.sgml b/doc/src/sgml/dblink.sgml index 81f23a28f3fd6f24568360cc2552cda0fa66ef10..e894a8cfc739464c983dd5668cffbd917c617409 100644 --- a/doc/src/sgml/dblink.sgml +++ b/doc/src/sgml/dblink.sgml @@ -1,4 +1,4 @@ -<!-- $PostgreSQL: pgsql/doc/src/sgml/dblink.sgml,v 1.12 2010/06/07 02:01:08 itagaki Exp $ --> +<!-- $PostgreSQL: pgsql/doc/src/sgml/dblink.sgml,v 1.13 2010/06/15 20:29:01 tgl Exp $ --> <sect1 id="dblink"> <title>dblink</title> @@ -1294,9 +1294,9 @@ SELECT * <title>Description</title> <para> - <function>dblink_get_notify</> retrieves notifications on either + <function>dblink_get_notify</> retrieves notifications on either the unnamed connection, or on a named connection if specified. - To receive notifications via dblink, <function>LISTEN</> must + To receive notifications via dblink, <function>LISTEN</> must first be issued, using <function>dblink_exec</>. For details see <xref linkend="sql-listen"> and <xref linkend="sql-notify">. </para> @@ -1620,6 +1620,10 @@ SELECT * FROM dblink_get_notify(); <programlisting> CREATE TYPE dblink_pkey_results AS (position int, colname text); </programlisting> + + The <literal>position</> column simply runs from 1 to <replaceable>N</>; + it is the number of the field within the primary key, not the number + within the table's columns. </para> </refsect1> @@ -1659,7 +1663,7 @@ test=# select * from dblink_get_pkey('foobar'); <synopsis> dblink_build_sql_insert(text relname, int2vector primary_key_attnums, - int2 num_primary_key_atts, + integer num_primary_key_atts, text[] src_pk_att_vals_array, text[] tgt_pk_att_vals_array) returns text </synopsis> @@ -1745,6 +1749,20 @@ test=# select * from dblink_get_pkey('foobar'); <para>Returns the requested SQL statement as text.</para> </refsect1> + <refsect1> + <title>Notes</title> + + <para> + As of <productname>PostgreSQL</> 9.0, the attribute numbers in + <parameter>primary_key_attnums</parameter> are interpreted as logical + column numbers, corresponding to the column's position in + <literal>SELECT * FROM relname</>. Previous versions interpreted the + numbers as physical column positions. There is a difference if any + column(s) to the left of the indicated column have been dropped during + the lifetime of the table. + </para> + </refsect1> + <refsect1> <title>Example</title> @@ -1775,7 +1793,7 @@ test=# select * from dblink_get_pkey('foobar'); <synopsis> dblink_build_sql_delete(text relname, int2vector primary_key_attnums, - int2 num_primary_key_atts, + integer num_primary_key_atts, text[] tgt_pk_att_vals_array) returns text </synopsis> </refsynopsisdiv> @@ -1845,6 +1863,20 @@ test=# select * from dblink_get_pkey('foobar'); <para>Returns the requested SQL statement as text.</para> </refsect1> + <refsect1> + <title>Notes</title> + + <para> + As of <productname>PostgreSQL</> 9.0, the attribute numbers in + <parameter>primary_key_attnums</parameter> are interpreted as logical + column numbers, corresponding to the column's position in + <literal>SELECT * FROM relname</>. Previous versions interpreted the + numbers as physical column positions. There is a difference if any + column(s) to the left of the indicated column have been dropped during + the lifetime of the table. + </para> + </refsect1> + <refsect1> <title>Example</title> @@ -1875,7 +1907,7 @@ test=# select * from dblink_get_pkey('foobar'); <synopsis> dblink_build_sql_update(text relname, int2vector primary_key_attnums, - int2 num_primary_key_atts, + integer num_primary_key_atts, text[] src_pk_att_vals_array, text[] tgt_pk_att_vals_array) returns text </synopsis> @@ -1964,6 +1996,20 @@ test=# select * from dblink_get_pkey('foobar'); <para>Returns the requested SQL statement as text.</para> </refsect1> + <refsect1> + <title>Notes</title> + + <para> + As of <productname>PostgreSQL</> 9.0, the attribute numbers in + <parameter>primary_key_attnums</parameter> are interpreted as logical + column numbers, corresponding to the column's position in + <literal>SELECT * FROM relname</>. Previous versions interpreted the + numbers as physical column positions. There is a difference if any + column(s) to the left of the indicated column have been dropped during + the lifetime of the table. + </para> + </refsect1> + <refsect1> <title>Example</title>