diff --git a/doc/src/sgml/ref/delete.sgml b/doc/src/sgml/ref/delete.sgml index 8369d9913725bd0bcd652ff3be3845449e9aa48f..b61e6cacd2132d3544eaef490a168a9209dcaa45 100644 --- a/doc/src/sgml/ref/delete.sgml +++ b/doc/src/sgml/ref/delete.sgml @@ -1,5 +1,5 @@ <!-- -$PostgreSQL: pgsql/doc/src/sgml/ref/delete.sgml,v 1.25 2005/11/01 21:09:50 tgl Exp $ +$PostgreSQL: pgsql/doc/src/sgml/ref/delete.sgml,v 1.26 2006/01/22 05:20:33 neilc Exp $ PostgreSQL documentation --> @@ -20,7 +20,7 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> -DELETE FROM [ ONLY ] <replaceable class="PARAMETER">table</replaceable> +DELETE FROM [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ [ AS ] <replaceable class="parameter">alias</replaceable> ] [ USING <replaceable class="PARAMETER">usinglist</replaceable> ] [ WHERE <replaceable class="PARAMETER">condition</replaceable> ] </synopsis> @@ -91,6 +91,19 @@ DELETE FROM [ ONLY ] <replaceable class="PARAMETER">table</replaceable> </listitem> </varlistentry> + <varlistentry> + <term><replaceable class="parameter">alias</replaceable></term> + <listitem> + <para> + A substitute name for the target table. When an alias is + provided, it completely hides the actual name of the table. For + example, given <literal>DELETE FROM foo AS f</>, the remainder + of the <command>DELETE</command> statement must refer to this + table as <literal>f</> not <literal>foo</>. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><replaceable class="PARAMETER">usinglist</replaceable></term> <listitem> diff --git a/doc/src/sgml/ref/update.sgml b/doc/src/sgml/ref/update.sgml index 503f41de12bcc6e7141126751158cf5eac0de013..95e4310ab424657a2c175b62a38d1d3b96c95ea4 100644 --- a/doc/src/sgml/ref/update.sgml +++ b/doc/src/sgml/ref/update.sgml @@ -1,5 +1,5 @@ <!-- -$PostgreSQL: pgsql/doc/src/sgml/ref/update.sgml,v 1.34 2006/01/19 23:09:42 momjian Exp $ +$PostgreSQL: pgsql/doc/src/sgml/ref/update.sgml,v 1.35 2006/01/22 05:20:33 neilc Exp $ PostgreSQL documentation --> @@ -20,7 +20,8 @@ PostgreSQL documentation <refsynopsisdiv> <synopsis> -UPDATE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> SET <replaceable class="PARAMETER">column</replaceable> = { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] +UPDATE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> [ [ AS ] <replaceable class="parameter">alias</replaceable> ] + SET <replaceable class="PARAMETER">column</replaceable> = { <replaceable class="PARAMETER">expression</replaceable> | DEFAULT } [, ...] [ FROM <replaceable class="PARAMETER">fromlist</replaceable> ] [ WHERE <replaceable class="PARAMETER">condition</replaceable> ] </synopsis> @@ -73,6 +74,21 @@ UPDATE [ ONLY ] <replaceable class="PARAMETER">table</replaceable> SET <replacea </listitem> </varlistentry> + <varlistentry> + <term><replaceable class="parameter">alias</replaceable></term> + <listitem> + <para> + A substitute name for the target table. When an alias is + provided, it completely hides the actual name of the table. For + example, given <literal>UPDATE foo AS f</>, the remainder of the + <command>UPDATE</command> statement must refer to this table as + <literal>f</> not <literal>foo</>. You cannot use the alias in + the <literal>SET</literal> clause. For example, <literal>SET + f.col = 1</> is invalid. + </para> + </listitem> + </varlistentry> + <varlistentry> <term><replaceable class="PARAMETER">column</replaceable></term> <listitem> diff --git a/doc/src/sgml/regress.sgml b/doc/src/sgml/regress.sgml index 05749a3157bcc8cba87e3b334b9d9a88b3c59cf7..11f9468860fbaaa08cec328cd945c454b10adb40 100644 --- a/doc/src/sgml/regress.sgml +++ b/doc/src/sgml/regress.sgml @@ -1,4 +1,4 @@ -<!-- $PostgreSQL: pgsql/doc/src/sgml/regress.sgml,v 1.49 2005/10/18 21:43:33 tgl Exp $ --> +<!-- $PostgreSQL: pgsql/doc/src/sgml/regress.sgml,v 1.50 2006/01/22 05:20:32 neilc Exp $ --> <chapter id="regress"> <title id="regress-title">Regression Tests</title> @@ -49,7 +49,7 @@ gmake check <screen> <computeroutput> ====================== - All 98 tests passed. + All 100 tests passed. ====================== </computeroutput> </screen> diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 41b22d811c9868c457ee855209b021f9315191e3..22e20165b96aec1d3e3e71b4c9aff2c55ab62a49 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.522 2006/01/21 02:16:19 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.523 2006/01/22 05:20:33 neilc Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -291,6 +291,7 @@ static void doNegateFloat(Value *v); %type <node> table_ref %type <jexpr> joined_table %type <range> relation_expr +%type <range> relation_expr_opt_alias %type <target> target_el insert_target_el update_target_el insert_column_item %type <typnam> Typename SimpleTypename ConstTypename @@ -5148,7 +5149,8 @@ insert_column_item: * *****************************************************************************/ -DeleteStmt: DELETE_P FROM relation_expr using_clause where_clause +DeleteStmt: DELETE_P FROM relation_expr_opt_alias + using_clause where_clause { DeleteStmt *n = makeNode(DeleteStmt); n->relation = $3; @@ -5200,7 +5202,7 @@ opt_nowait: NOWAIT { $$ = TRUE; } * *****************************************************************************/ -UpdateStmt: UPDATE relation_expr +UpdateStmt: UPDATE relation_expr_opt_alias SET update_target_list from_clause where_clause @@ -5878,6 +5880,20 @@ relation_expr: ; +relation_expr_opt_alias: relation_expr + { + $$ = $1; + } + | relation_expr opt_as IDENT + { + Alias *alias = makeNode(Alias); + alias->aliasname = $3; + $1->alias = alias; + $$ = $1; + } + ; + + func_table: func_expr { $$ = $1; } ; diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index aee45f3d2050ee447297f48dc786149e1c466ba1..934802e16ec7986844c553b4d92b4e61c18833d6 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.144 2005/11/22 18:17:16 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.145 2006/01/22 05:20:34 neilc Exp $ * *------------------------------------------------------------------------- */ @@ -160,7 +160,7 @@ setTargetTable(ParseState *pstate, RangeVar *relation, * Now build an RTE. */ rte = addRangeTableEntryForRelation(pstate, pstate->p_target_relation, - NULL, inh, false); + relation->alias, inh, false); pstate->p_target_rangetblentry = rte; /* assume new rte is at end */ diff --git a/src/test/regress/expected/delete.out b/src/test/regress/expected/delete.out new file mode 100644 index 0000000000000000000000000000000000000000..68128f69d099dea131948cfe530c1bb96c97eede --- /dev/null +++ b/src/test/regress/expected/delete.out @@ -0,0 +1,27 @@ +CREATE TABLE delete_test ( + id SERIAL PRIMARY KEY, + a INT +); +NOTICE: CREATE TABLE will create implicit sequence "delete_test_id_seq" for serial column "delete_test.id" +NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "delete_test_pkey" for table "delete_test" +INSERT INTO delete_test (a) VALUES (10); +INSERT INTO delete_test (a) VALUES (50); +INSERT INTO delete_test (a) VALUES (100); +-- allow an alias to be specified for DELETE's target table +DELETE FROM delete_test AS dt WHERE dt.a > 75; +-- if an alias is specified, don't allow the original table name +-- to be referenced +BEGIN; +SET LOCAL add_missing_from = false; +DELETE FROM delete_test dt WHERE delete_test.a > 25; +ERROR: invalid reference to FROM-clause entry for table "delete_test" +HINT: Perhaps you meant to reference the table alias "dt". +ROLLBACK; +SELECT * FROM delete_test; + id | a +----+---- + 1 | 10 + 2 | 50 +(2 rows) + +DROP TABLE delete_test; diff --git a/src/test/regress/expected/rowtypes.out b/src/test/regress/expected/rowtypes.out index fc46dd14e19007b6acf7d027eade73c80fc2b807..c6b1bfac3982e1276ff9f6ba66cf305ddef8b5fe 100644 --- a/src/test/regress/expected/rowtypes.out +++ b/src/test/regress/expected/rowtypes.out @@ -59,8 +59,11 @@ select * from quadtable; 2 | ("(,4.4)","(5.5,6.6)") (2 rows) +begin; +set local add_missing_from = false; select f1, q.c1 from quadtable; -- fails, q is a table reference ERROR: missing FROM-clause entry for table "q" +rollback; select f1, (q).c1, (qq.q).c1.i from quadtable qq; f1 | c1 | i ----+-----------+----- diff --git a/src/test/regress/expected/update.out b/src/test/regress/expected/update.out index 3fca2fb41ac71c0cea4ddbf35d13026fa46a34ff..1ff7c8918f5184e6c7154ac2ec49a7f9055ecaa3 100644 --- a/src/test/regress/expected/update.out +++ b/src/test/regress/expected/update.out @@ -22,4 +22,29 @@ SELECT * FROM update_test; 10 | (2 rows) +-- aliases for the UPDATE target table +UPDATE update_test AS t SET b = 10 WHERE t.a = 10; +SELECT * FROM update_test; + a | b +----+---- + 10 | 10 + 10 | 10 +(2 rows) + +UPDATE update_test t SET b = t.b + 10 WHERE t.a = 10; +SELECT * FROM update_test; + a | b +----+---- + 10 | 20 + 10 | 20 +(2 rows) + +-- if an alias for the target table is specified, don't allow references +-- to the original table name +BEGIN; +SET LOCAL add_missing_from = false; +UPDATE update_test AS t SET b = update_test.b + 10 WHERE t.a = 10; +ERROR: invalid reference to FROM-clause entry for table "update_test" +HINT: Perhaps you meant to reference the table alias "t". +ROLLBACK; DROP TABLE update_test; diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule index d5777794bfbc047f89db676829a5f69ba11e02bf..fef609711b2df346269e3f56286733eeca3a99b2 100644 --- a/src/test/regress/parallel_schedule +++ b/src/test/regress/parallel_schedule @@ -60,7 +60,7 @@ ignore: random # ---------- # The fourth group of parallel test # ---------- -test: select_into select_distinct select_distinct_on select_implicit select_having subselect union case join aggregates transactions random portals arrays btree_index hash_index update namespace prepared_xacts +test: select_into select_distinct select_distinct_on select_implicit select_having subselect union case join aggregates transactions random portals arrays btree_index hash_index update namespace prepared_xacts delete test: privileges test: misc diff --git a/src/test/regress/serial_schedule b/src/test/regress/serial_schedule index dd60070433c9b1f3fb75d9bc2f273602bb2fc9ee..3342dc2ba1fe03c4336333609b9c78cbcaa94001 100644 --- a/src/test/regress/serial_schedule +++ b/src/test/regress/serial_schedule @@ -1,4 +1,4 @@ -# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.29 2005/11/19 17:39:45 adunstan Exp $ +# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.30 2006/01/22 05:20:34 neilc Exp $ # This should probably be in an order similar to parallel_schedule. test: boolean test: char @@ -74,6 +74,7 @@ test: arrays test: btree_index test: hash_index test: update +test: delete test: namespace test: prepared_xacts test: privileges diff --git a/src/test/regress/sql/delete.sql b/src/test/regress/sql/delete.sql new file mode 100644 index 0000000000000000000000000000000000000000..86cabfcf6489aa74bc2da514d60b81e925727768 --- /dev/null +++ b/src/test/regress/sql/delete.sql @@ -0,0 +1,22 @@ +CREATE TABLE delete_test ( + id SERIAL PRIMARY KEY, + a INT +); + +INSERT INTO delete_test (a) VALUES (10); +INSERT INTO delete_test (a) VALUES (50); +INSERT INTO delete_test (a) VALUES (100); + +-- allow an alias to be specified for DELETE's target table +DELETE FROM delete_test AS dt WHERE dt.a > 75; + +-- if an alias is specified, don't allow the original table name +-- to be referenced +BEGIN; +SET LOCAL add_missing_from = false; +DELETE FROM delete_test dt WHERE delete_test.a > 25; +ROLLBACK; + +SELECT * FROM delete_test; + +DROP TABLE delete_test; \ No newline at end of file diff --git a/src/test/regress/sql/rowtypes.sql b/src/test/regress/sql/rowtypes.sql index 613c4e91f9180c84f516bab122ca3661e462647e..43d57bc60355b2af68ed0c611a14fc814e33a84f 100644 --- a/src/test/regress/sql/rowtypes.sql +++ b/src/test/regress/sql/rowtypes.sql @@ -35,7 +35,10 @@ insert into quadtable values (2, ((null,4.4),(5.5,6.6))); select * from quadtable; +begin; +set local add_missing_from = false; select f1, q.c1 from quadtable; -- fails, q is a table reference +rollback; select f1, (q).c1, (qq.q).c1.i from quadtable qq; diff --git a/src/test/regress/sql/update.sql b/src/test/regress/sql/update.sql index 577596abb1b75432247f6d3d1c2bcdc54c776d34..99fd74bca79d2569fd86d11adc5c0a84763cbef2 100644 --- a/src/test/regress/sql/update.sql +++ b/src/test/regress/sql/update.sql @@ -16,4 +16,20 @@ UPDATE update_test SET a = DEFAULT, b = DEFAULT; SELECT * FROM update_test; +-- aliases for the UPDATE target table +UPDATE update_test AS t SET b = 10 WHERE t.a = 10; + +SELECT * FROM update_test; + +UPDATE update_test t SET b = t.b + 10 WHERE t.a = 10; + +SELECT * FROM update_test; + +-- if an alias for the target table is specified, don't allow references +-- to the original table name +BEGIN; +SET LOCAL add_missing_from = false; +UPDATE update_test AS t SET b = update_test.b + 10 WHERE t.a = 10; +ROLLBACK; + DROP TABLE update_test;