Add a bunch of new error location reports to parse-analysis error messages.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 1 Sep 2008 20:42:46 +0000 (20:42 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 1 Sep 2008 20:42:46 +0000 (20:42 +0000)
There are still some weak spots around JOIN USING and relation alias lists,
but most errors reported within backend/parser/ now have locations.

103 files changed:
contrib/cube/expected/cube.out
contrib/cube/expected/cube_1.out
contrib/cube/expected/cube_2.out
contrib/seg/expected/seg.out
contrib/seg/expected/seg_1.out
src/backend/bootstrap/bootparse.y
src/backend/bootstrap/bootstrap.c
src/backend/catalog/namespace.c
src/backend/catalog/toasting.c
src/backend/commands/tablecmds.c
src/backend/commands/trigger.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/makefuncs.c
src/backend/nodes/nodeFuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/util/plancat.c
src/backend/optimizer/util/var.c
src/backend/parser/analyze.c
src/backend/parser/gram.y
src/backend/parser/parse_agg.c
src/backend/parser/parse_clause.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_func.c
src/backend/parser/parse_node.c
src/backend/parser/parse_relation.c
src/backend/parser/parse_target.c
src/backend/parser/parse_type.c
src/backend/parser/parse_utilcmd.c
src/backend/parser/scan.l
src/backend/rewrite/rewriteManip.c
src/backend/tcop/utility.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/error/elog.c
src/include/catalog/catversion.h
src/include/nodes/makefuncs.h
src/include/nodes/parsenodes.h
src/include/nodes/primnodes.h
src/include/optimizer/var.h
src/include/parser/gramparse.h
src/include/parser/parse_node.h
src/include/parser/parse_relation.h
src/include/rewrite/rewriteManip.h
src/include/utils/elog.h
src/pl/plperl/expected/plperl.out
src/pl/plpgsql/src/pl_comp.c
src/test/regress/expected/abstime.out
src/test/regress/expected/aggregates.out
src/test/regress/expected/alter_table.out
src/test/regress/expected/arrays.out
src/test/regress/expected/boolean.out
src/test/regress/expected/box.out
src/test/regress/expected/circle.out
src/test/regress/expected/create_type.out
src/test/regress/expected/date.out
src/test/regress/expected/enum.out
src/test/regress/expected/errors.out
src/test/regress/expected/float4-exp-three-digits.out
src/test/regress/expected/float4.out
src/test/regress/expected/float8-exp-three-digits-win32.out
src/test/regress/expected/float8-small-is-zero.out
src/test/regress/expected/float8-small-is-zero_1.out
src/test/regress/expected/float8.out
src/test/regress/expected/horology.out
src/test/regress/expected/inet.out
src/test/regress/expected/insert.out
src/test/regress/expected/int2.out
src/test/regress/expected/int4.out
src/test/regress/expected/int8-exp-three-digits.out
src/test/regress/expected/int8.out
src/test/regress/expected/interval.out
src/test/regress/expected/lseg.out
src/test/regress/expected/numeric.out
src/test/regress/expected/oid.out
src/test/regress/expected/path.out
src/test/regress/expected/point.out
src/test/regress/expected/polygon.out
src/test/regress/expected/prepared_xacts.out
src/test/regress/expected/rangefuncs.out
src/test/regress/expected/reltime.out
src/test/regress/expected/rowtypes.out
src/test/regress/expected/select_distinct_on.out
src/test/regress/expected/select_having.out
src/test/regress/expected/select_having_1.out
src/test/regress/expected/select_having_2.out
src/test/regress/expected/select_implicit.out
src/test/regress/expected/select_implicit_1.out
src/test/regress/expected/select_implicit_2.out
src/test/regress/expected/temp.out
src/test/regress/expected/time.out
src/test/regress/expected/timestamp.out
src/test/regress/expected/timestamptz.out
src/test/regress/expected/timetz.out
src/test/regress/expected/tinterval.out
src/test/regress/expected/transactions.out
src/test/regress/expected/truncate.out
src/test/regress/expected/txid.out
src/test/regress/expected/uuid.out
src/test/regress/expected/xml.out
src/test/regress/expected/xml_1.out
src/test/regress/output/create_function_1.source

index 86b33483a54f3166635bcc2580a7758aa7af0362..101a63b72362def2ad0fba00ee5640ef2071fd93 100644 (file)
@@ -257,88 +257,144 @@ SELECT '[(0,0,0,0),(1,0,0,0)]'::cube AS cube;
 -- invalid input: parse errors
 SELECT ''::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT ''::cube AS cube;
+               ^
 DETAIL:  syntax error at end of input
 SELECT 'ABC'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT 'ABC'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "A"
 SELECT '()'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '()'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ")"
 SELECT '[]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "]"
 SELECT '[()]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[()]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ")"
 SELECT '[(1)]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1)]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "]"
 SELECT '[(1),]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1),]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "]"
 SELECT '[(1),2]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1),2]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "2"
 SELECT '[(1),(2),(3)]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1),(2),(3)]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ","
 SELECT '1,'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '1,'::cube AS cube;
+               ^
 DETAIL:  syntax error at end of input
 SELECT '1,2,'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '1,2,'::cube AS cube;
+               ^
 DETAIL:  syntax error at end of input
 SELECT '1,,2'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '1,,2'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ","
 SELECT '(1,)'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,)'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ")"
 SELECT '(1,2,)'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2,)'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ")"
 SELECT '(1,,2)'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,,2)'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ","
 -- invalid input: semantic errors and trailing garbage
 SELECT '[(1),(2)],'::cube AS cube; -- 0
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1),(2)],'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ","
 SELECT '[(1,2,3),(2,3)]'::cube AS cube; -- 1
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1,2,3),(2,3)]'::cube AS cube;
+               ^
 DETAIL:  Different point dimensions in (1,2,3) and (2,3).
 SELECT '[(1,2),(1,2,3)]'::cube AS cube; -- 1
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1,2),(1,2,3)]'::cube AS cube;
+               ^
 DETAIL:  Different point dimensions in (1,2) and (1,2,3).
 SELECT '(1),(2),'::cube AS cube; -- 2
 ERROR:  bad cube representation
+LINE 1: SELECT '(1),(2),'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ","
 SELECT '(1,2,3),(2,3)'::cube AS cube; -- 3
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2,3),(2,3)'::cube AS cube;
+               ^
 DETAIL:  Different point dimensions in (1,2,3) and (2,3).
 SELECT '(1,2),(1,2,3)'::cube AS cube; -- 3
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2),(1,2,3)'::cube AS cube;
+               ^
 DETAIL:  Different point dimensions in (1,2) and (1,2,3).
 SELECT '(1,2,3)ab'::cube AS cube; -- 4
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2,3)ab'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "a"
 SELECT '(1,2,3)a'::cube AS cube; -- 5
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2,3)a'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "a"
 SELECT '(1,2)('::cube AS cube; -- 5
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2)('::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "("
 SELECT '1,2ab'::cube AS cube; -- 6
 ERROR:  bad cube representation
+LINE 1: SELECT '1,2ab'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "a"
 SELECT '1 e7'::cube AS cube; -- 6
 ERROR:  bad cube representation
+LINE 1: SELECT '1 e7'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "e"
 SELECT '1,2a'::cube AS cube; -- 7
 ERROR:  bad cube representation
+LINE 1: SELECT '1,2a'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "a"
 SELECT '1..2'::cube AS cube; -- 7
 ERROR:  bad cube representation
+LINE 1: SELECT '1..2'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ".2"
 --
 -- Testing building cubes from float8 values
@@ -430,9 +486,13 @@ ERROR:  Index out of bounds
 --
 select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube;
 ERROR:  bad cube representation
+LINE 1: select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0...
+               ^
 DETAIL:  A cube cannot have more than 100 dimensions.
 select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube;
 ERROR:  bad cube representation
+LINE 1: select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0...
+               ^
 DETAIL:  A cube cannot have more than 100 dimensions.
 --
 -- testing the  operators
index 8609c26106209ad2bc5c534e151ca4ad705c2a3f..55f6861dafb6f438b867a742edb60630ae0f3c8e 100644 (file)
@@ -257,88 +257,144 @@ SELECT '[(0,0,0,0),(1,0,0,0)]'::cube AS cube;
 -- invalid input: parse errors
 SELECT ''::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT ''::cube AS cube;
+               ^
 DETAIL:  syntax error at end of input
 SELECT 'ABC'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT 'ABC'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "A"
 SELECT '()'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '()'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ")"
 SELECT '[]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "]"
 SELECT '[()]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[()]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ")"
 SELECT '[(1)]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1)]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "]"
 SELECT '[(1),]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1),]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "]"
 SELECT '[(1),2]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1),2]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "2"
 SELECT '[(1),(2),(3)]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1),(2),(3)]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ","
 SELECT '1,'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '1,'::cube AS cube;
+               ^
 DETAIL:  syntax error at end of input
 SELECT '1,2,'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '1,2,'::cube AS cube;
+               ^
 DETAIL:  syntax error at end of input
 SELECT '1,,2'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '1,,2'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ","
 SELECT '(1,)'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,)'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ")"
 SELECT '(1,2,)'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2,)'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ")"
 SELECT '(1,,2)'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,,2)'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ","
 -- invalid input: semantic errors and trailing garbage
 SELECT '[(1),(2)],'::cube AS cube; -- 0
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1),(2)],'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ","
 SELECT '[(1,2,3),(2,3)]'::cube AS cube; -- 1
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1,2,3),(2,3)]'::cube AS cube;
+               ^
 DETAIL:  Different point dimensions in (1,2,3) and (2,3).
 SELECT '[(1,2),(1,2,3)]'::cube AS cube; -- 1
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1,2),(1,2,3)]'::cube AS cube;
+               ^
 DETAIL:  Different point dimensions in (1,2) and (1,2,3).
 SELECT '(1),(2),'::cube AS cube; -- 2
 ERROR:  bad cube representation
+LINE 1: SELECT '(1),(2),'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ","
 SELECT '(1,2,3),(2,3)'::cube AS cube; -- 3
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2,3),(2,3)'::cube AS cube;
+               ^
 DETAIL:  Different point dimensions in (1,2,3) and (2,3).
 SELECT '(1,2),(1,2,3)'::cube AS cube; -- 3
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2),(1,2,3)'::cube AS cube;
+               ^
 DETAIL:  Different point dimensions in (1,2) and (1,2,3).
 SELECT '(1,2,3)ab'::cube AS cube; -- 4
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2,3)ab'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "a"
 SELECT '(1,2,3)a'::cube AS cube; -- 5
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2,3)a'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "a"
 SELECT '(1,2)('::cube AS cube; -- 5
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2)('::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "("
 SELECT '1,2ab'::cube AS cube; -- 6
 ERROR:  bad cube representation
+LINE 1: SELECT '1,2ab'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "a"
 SELECT '1 e7'::cube AS cube; -- 6
 ERROR:  bad cube representation
+LINE 1: SELECT '1 e7'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "e"
 SELECT '1,2a'::cube AS cube; -- 7
 ERROR:  bad cube representation
+LINE 1: SELECT '1,2a'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "a"
 SELECT '1..2'::cube AS cube; -- 7
 ERROR:  bad cube representation
+LINE 1: SELECT '1..2'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ".2"
 --
 -- Testing building cubes from float8 values
@@ -430,9 +486,13 @@ ERROR:  Index out of bounds
 --
 select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube;
 ERROR:  bad cube representation
+LINE 1: select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0...
+               ^
 DETAIL:  A cube cannot have more than 100 dimensions.
 select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube;
 ERROR:  bad cube representation
+LINE 1: select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0...
+               ^
 DETAIL:  A cube cannot have more than 100 dimensions.
 --
 -- testing the  operators
index d8737c3cb38473db85a6fa5d6a0543e5b79f1602..c44939581803f093fec2b48e28f10112a72e90a7 100644 (file)
@@ -257,88 +257,144 @@ SELECT '[(0,0,0,0),(1,0,0,0)]'::cube AS cube;
 -- invalid input: parse errors
 SELECT ''::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT ''::cube AS cube;
+               ^
 DETAIL:  syntax error at end of input
 SELECT 'ABC'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT 'ABC'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "A"
 SELECT '()'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '()'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ")"
 SELECT '[]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "]"
 SELECT '[()]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[()]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ")"
 SELECT '[(1)]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1)]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "]"
 SELECT '[(1),]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1),]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "]"
 SELECT '[(1),2]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1),2]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "2"
 SELECT '[(1),(2),(3)]'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1),(2),(3)]'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ","
 SELECT '1,'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '1,'::cube AS cube;
+               ^
 DETAIL:  syntax error at end of input
 SELECT '1,2,'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '1,2,'::cube AS cube;
+               ^
 DETAIL:  syntax error at end of input
 SELECT '1,,2'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '1,,2'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ","
 SELECT '(1,)'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,)'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ")"
 SELECT '(1,2,)'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2,)'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ")"
 SELECT '(1,,2)'::cube AS cube;
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,,2)'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ","
 -- invalid input: semantic errors and trailing garbage
 SELECT '[(1),(2)],'::cube AS cube; -- 0
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1),(2)],'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ","
 SELECT '[(1,2,3),(2,3)]'::cube AS cube; -- 1
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1,2,3),(2,3)]'::cube AS cube;
+               ^
 DETAIL:  Different point dimensions in (1,2,3) and (2,3).
 SELECT '[(1,2),(1,2,3)]'::cube AS cube; -- 1
 ERROR:  bad cube representation
+LINE 1: SELECT '[(1,2),(1,2,3)]'::cube AS cube;
+               ^
 DETAIL:  Different point dimensions in (1,2) and (1,2,3).
 SELECT '(1),(2),'::cube AS cube; -- 2
 ERROR:  bad cube representation
+LINE 1: SELECT '(1),(2),'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ","
 SELECT '(1,2,3),(2,3)'::cube AS cube; -- 3
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2,3),(2,3)'::cube AS cube;
+               ^
 DETAIL:  Different point dimensions in (1,2,3) and (2,3).
 SELECT '(1,2),(1,2,3)'::cube AS cube; -- 3
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2),(1,2,3)'::cube AS cube;
+               ^
 DETAIL:  Different point dimensions in (1,2) and (1,2,3).
 SELECT '(1,2,3)ab'::cube AS cube; -- 4
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2,3)ab'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "a"
 SELECT '(1,2,3)a'::cube AS cube; -- 5
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2,3)a'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "a"
 SELECT '(1,2)('::cube AS cube; -- 5
 ERROR:  bad cube representation
+LINE 1: SELECT '(1,2)('::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "("
 SELECT '1,2ab'::cube AS cube; -- 6
 ERROR:  bad cube representation
+LINE 1: SELECT '1,2ab'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "a"
 SELECT '1 e7'::cube AS cube; -- 6
 ERROR:  bad cube representation
+LINE 1: SELECT '1 e7'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "e"
 SELECT '1,2a'::cube AS cube; -- 7
 ERROR:  bad cube representation
+LINE 1: SELECT '1,2a'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near "a"
 SELECT '1..2'::cube AS cube; -- 7
 ERROR:  bad cube representation
+LINE 1: SELECT '1..2'::cube AS cube;
+               ^
 DETAIL:  syntax error at or near ".2"
 --
 -- Testing building cubes from float8 values
@@ -430,9 +486,13 @@ ERROR:  Index out of bounds
 --
 select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube;
 ERROR:  bad cube representation
+LINE 1: select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0...
+               ^
 DETAIL:  A cube cannot have more than 100 dimensions.
 select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)'::cube;
 ERROR:  bad cube representation
+LINE 1: select '(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0...
+               ^
 DETAIL:  A cube cannot have more than 100 dimensions.
 --
 -- testing the  operators
index 69bcfa144197aec32dbebd4042f1d6eeb27ae1de..bd099a222ca2af5ac142e5de1f07e2df839cf6db 100644 (file)
@@ -394,30 +394,48 @@ SELECT '100(+-)1'::seg AS seg;
 -- invalid input
 SELECT ''::seg AS seg;
 ERROR:  bad seg representation
+LINE 1: SELECT ''::seg AS seg;
+               ^
 DETAIL:  syntax error at end of input
 SELECT 'ABC'::seg AS seg;
 ERROR:  bad seg representation
+LINE 1: SELECT 'ABC'::seg AS seg;
+               ^
 DETAIL:  syntax error at or near "A"
 SELECT '1ABC'::seg AS seg;
 ERROR:  bad seg representation
+LINE 1: SELECT '1ABC'::seg AS seg;
+               ^
 DETAIL:  syntax error at or near "A"
 SELECT '1.'::seg AS seg;
 ERROR:  bad seg representation
+LINE 1: SELECT '1.'::seg AS seg;
+               ^
 DETAIL:  syntax error at or near "."
 SELECT '1.....'::seg AS seg;
 ERROR:  bad seg representation
+LINE 1: SELECT '1.....'::seg AS seg;
+               ^
 DETAIL:  syntax error at or near ".."
 SELECT '.1'::seg AS seg;
 ERROR:  bad seg representation
+LINE 1: SELECT '.1'::seg AS seg;
+               ^
 DETAIL:  syntax error at or near "."
 SELECT '1..2.'::seg AS seg;
 ERROR:  bad seg representation
+LINE 1: SELECT '1..2.'::seg AS seg;
+               ^
 DETAIL:  syntax error at or near "."
 SELECT '1 e7'::seg AS seg;
 ERROR:  bad seg representation
+LINE 1: SELECT '1 e7'::seg AS seg;
+               ^
 DETAIL:  syntax error at or near "e"
 SELECT '1e700'::seg AS seg;
 ERROR:  "1e700" is out of range for type real
+LINE 1: SELECT '1e700'::seg AS seg;
+               ^
 --
 -- testing the  operators
 --
index aef3df8aea1c5fab77dc3da223de6c4f49caf5a2..c92cd835100e3ada0ecc4933a599e50aae99062c 100644 (file)
@@ -394,30 +394,48 @@ SELECT '100(+-)1'::seg AS seg;
 -- invalid input
 SELECT ''::seg AS seg;
 ERROR:  bad seg representation
+LINE 1: SELECT ''::seg AS seg;
+               ^
 DETAIL:  syntax error at end of input
 SELECT 'ABC'::seg AS seg;
 ERROR:  bad seg representation
+LINE 1: SELECT 'ABC'::seg AS seg;
+               ^
 DETAIL:  syntax error at or near "A"
 SELECT '1ABC'::seg AS seg;
 ERROR:  bad seg representation
+LINE 1: SELECT '1ABC'::seg AS seg;
+               ^
 DETAIL:  syntax error at or near "A"
 SELECT '1.'::seg AS seg;
 ERROR:  bad seg representation
+LINE 1: SELECT '1.'::seg AS seg;
+               ^
 DETAIL:  syntax error at or near "."
 SELECT '1.....'::seg AS seg;
 ERROR:  bad seg representation
+LINE 1: SELECT '1.....'::seg AS seg;
+               ^
 DETAIL:  syntax error at or near ".."
 SELECT '.1'::seg AS seg;
 ERROR:  bad seg representation
+LINE 1: SELECT '.1'::seg AS seg;
+               ^
 DETAIL:  syntax error at or near "."
 SELECT '1..2.'::seg AS seg;
 ERROR:  bad seg representation
+LINE 1: SELECT '1..2.'::seg AS seg;
+               ^
 DETAIL:  syntax error at or near "."
 SELECT '1 e7'::seg AS seg;
 ERROR:  bad seg representation
+LINE 1: SELECT '1 e7'::seg AS seg;
+               ^
 DETAIL:  syntax error at or near "e"
 SELECT '1e700'::seg AS seg;
 ERROR:  "1e700" is out of range for type real
+LINE 1: SELECT '1e700'::seg AS seg;
+               ^
 --
 -- testing the  operators
 --
index da76d76d9d2ccf88dbbb10db043b6c0605a2dcb5..8019b244ae8cb2e1200a86445a4a1df95b81158b 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.92 2008/05/09 23:32:04 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.93 2008/09/01 20:42:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -247,7 +247,7 @@ Boot_DeclareIndexStmt:
                {
                    do_start();
 
-                   DefineIndex(makeRangeVar(NULL, LexIDStr($6)),
+                   DefineIndex(makeRangeVar(NULL, LexIDStr($6), -1),
                                LexIDStr($3),
                                $4,
                                LexIDStr($8),
@@ -265,7 +265,7 @@ Boot_DeclareUniqueIndexStmt:
                {
                    do_start();
 
-                   DefineIndex(makeRangeVar(NULL, LexIDStr($7)),
+                   DefineIndex(makeRangeVar(NULL, LexIDStr($7), -1),
                                LexIDStr($4),
                                $5,
                                LexIDStr($9),
index 25eba1406fb7b8f16fc71415212d1d2bf6680fc9..0689fb1f1aaa670966755f1bcc48825a02b3edb8 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.244 2008/06/24 17:58:27 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.245 2008/09/01 20:42:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -637,7 +637,7 @@ boot_openrel(char *relname)
    elog(DEBUG4, "open relation %s, attrsize %d",
         relname, (int) ATTRIBUTE_TUPLE_SIZE);
 
-   boot_reldesc = heap_openrv(makeRangeVar(NULL, relname), NoLock);
+   boot_reldesc = heap_openrv(makeRangeVar(NULL, relname, -1), NoLock);
    numattr = boot_reldesc->rd_rel->relnatts;
    for (i = 0; i < numattr; i++)
    {
index 7f0ea88c4383f1a214f0cf1b110cf41dec3d0232..de827f74b2fc492a205ad0f72310cab153d64d8c 100644 (file)
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.110 2008/08/30 01:39:13 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.111 2008/09/01 20:42:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2156,7 +2156,7 @@ QualifiedNameGetCreationNamespace(List *names, char **objname_p)
 RangeVar *
 makeRangeVarFromNameList(List *names)
 {
-   RangeVar   *rel = makeRangeVar(NULL, NULL);
+   RangeVar   *rel = makeRangeVar(NULL, NULL, -1);
 
    switch (list_length(names))
    {
index 0171d1f73386269fbdc786aff1afd595db8ca825..d4f04346c94f4d7751a88dfcad7c90c6e5ac8883 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/catalog/toasting.c,v 1.10 2008/05/09 23:32:04 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/catalog/toasting.c,v 1.11 2008/09/01 20:42:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -73,7 +73,7 @@ BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid)
 {
    Relation    rel;
 
-   rel = heap_openrv(makeRangeVar(NULL, relName), AccessExclusiveLock);
+   rel = heap_openrv(makeRangeVar(NULL, relName, -1), AccessExclusiveLock);
 
    /* Note: during bootstrap may see uncataloged relation */
    if (rel->rd_rel->relkind != RELKIND_RELATION &&
index 6f2303f62cebf0fe27736a26100fbd0d0200193d..8b7b10159556c5b15cc17c204ef913b1d42aad4f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.264 2008/08/28 23:09:45 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.265 2008/09/01 20:42:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -5112,7 +5112,8 @@ createForeignKeyTriggers(Relation rel, FkConstraint *fkconstraint,
     * Reconstruct a RangeVar for my relation (not passed in, unfortunately).
     */
    myRel = makeRangeVar(get_namespace_name(RelationGetNamespace(rel)),
-                        pstrdup(RelationGetRelationName(rel)));
+                        pstrdup(RelationGetRelationName(rel)),
+                        -1);
 
    /* Make changes-so-far visible */
    CommandCounterIncrement();
index 44f13df36148112ae5b6b0bfc1eacaad072ede97..3461056c576ff3b2fc3035c02a72ab6fb2e1e95b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.236 2008/07/18 20:26:06 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.237 2008/09/01 20:42:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -655,7 +655,7 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
            else
            {
                /* Work around ancient pg_dump bug that omitted constrrel */
-               fkcon->pktable = makeRangeVar(NULL, pk_table_name);
+               fkcon->pktable = makeRangeVar(NULL, pk_table_name, -1);
            }
        }
        else
@@ -667,7 +667,7 @@ ConvertTriggerToFK(CreateTrigStmt *stmt, Oid funcoid)
            else
            {
                /* Work around ancient pg_dump bug that omitted constrrel */
-               atstmt->relation = makeRangeVar(NULL, fk_table_name);
+               atstmt->relation = makeRangeVar(NULL, fk_table_name, -1);
            }
        }
        atstmt->cmds = list_make1(atcmd);
index 67a25500dac9a1464ac06ac844d90ed234be60f3..6e2028142b9514270ccfd38856ab1e2c6e87c280 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.403 2008/08/30 01:39:13 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.404 2008/09/01 20:42:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -722,6 +722,7 @@ _copyRangeVar(RangeVar *from)
    COPY_SCALAR_FIELD(inhOpt);
    COPY_SCALAR_FIELD(istemp);
    COPY_NODE_FIELD(alias);
+   COPY_LOCATION_FIELD(location);
 
    return newnode;
 }
@@ -1773,10 +1774,11 @@ _copySortBy(SortBy *from)
 {
    SortBy     *newnode = makeNode(SortBy);
 
+   COPY_NODE_FIELD(node);
    COPY_SCALAR_FIELD(sortby_dir);
    COPY_SCALAR_FIELD(sortby_nulls);
    COPY_NODE_FIELD(useOp);
-   COPY_NODE_FIELD(node);
+   COPY_LOCATION_FIELD(location);
 
    return newnode;
 }
@@ -2406,7 +2408,7 @@ _copyNotifyStmt(NotifyStmt *from)
 {
    NotifyStmt *newnode = makeNode(NotifyStmt);
 
-   COPY_NODE_FIELD(relation);
+   COPY_STRING_FIELD(conditionname);
 
    return newnode;
 }
@@ -2416,7 +2418,7 @@ _copyListenStmt(ListenStmt *from)
 {
    ListenStmt *newnode = makeNode(ListenStmt);
 
-   COPY_NODE_FIELD(relation);
+   COPY_STRING_FIELD(conditionname);
 
    return newnode;
 }
@@ -2426,7 +2428,7 @@ _copyUnlistenStmt(UnlistenStmt *from)
 {
    UnlistenStmt *newnode = makeNode(UnlistenStmt);
 
-   COPY_NODE_FIELD(relation);
+   COPY_STRING_FIELD(conditionname);
 
    return newnode;
 }
index 298d03aa9bab2776966ed041ea34a4876b5d33ba..f0939b4777df9d3000666b1788bdf5a905eb536a 100644 (file)
@@ -22,7 +22,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.330 2008/08/30 01:39:13 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.331 2008/09/01 20:42:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -106,6 +106,7 @@ _equalRangeVar(RangeVar *a, RangeVar *b)
    COMPARE_SCALAR_FIELD(inhOpt);
    COMPARE_SCALAR_FIELD(istemp);
    COMPARE_NODE_FIELD(alias);
+   COMPARE_LOCATION_FIELD(location);
 
    return true;
 }
@@ -1230,7 +1231,7 @@ _equalRuleStmt(RuleStmt *a, RuleStmt *b)
 static bool
 _equalNotifyStmt(NotifyStmt *a, NotifyStmt *b)
 {
-   COMPARE_NODE_FIELD(relation);
+   COMPARE_STRING_FIELD(conditionname);
 
    return true;
 }
@@ -1238,7 +1239,7 @@ _equalNotifyStmt(NotifyStmt *a, NotifyStmt *b)
 static bool
 _equalListenStmt(ListenStmt *a, ListenStmt *b)
 {
-   COMPARE_NODE_FIELD(relation);
+   COMPARE_STRING_FIELD(conditionname);
 
    return true;
 }
@@ -1246,7 +1247,7 @@ _equalListenStmt(ListenStmt *a, ListenStmt *b)
 static bool
 _equalUnlistenStmt(UnlistenStmt *a, UnlistenStmt *b)
 {
-   COMPARE_NODE_FIELD(relation);
+   COMPARE_STRING_FIELD(conditionname);
 
    return true;
 }
@@ -1837,10 +1838,11 @@ _equalTypeCast(TypeCast *a, TypeCast *b)
 static bool
 _equalSortBy(SortBy *a, SortBy *b)
 {
+   COMPARE_NODE_FIELD(node);
    COMPARE_SCALAR_FIELD(sortby_dir);
    COMPARE_SCALAR_FIELD(sortby_nulls);
    COMPARE_NODE_FIELD(useOp);
-   COMPARE_NODE_FIELD(node);
+   COMPARE_LOCATION_FIELD(location);
 
    return true;
 }
index 5ab853c37bf62f897bba977a399e842e2ccc2f76..42539f6f97bfe0c023315c3c23ebc4ae6f598d96 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.59 2008/08/28 23:09:46 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.60 2008/09/01 20:42:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -266,7 +266,7 @@ makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod, CoercionForm rformat)
  *   creates a RangeVar node (rather oversimplified case)
  */
 RangeVar *
-makeRangeVar(char *schemaname, char *relname)
+makeRangeVar(char *schemaname, char *relname, int location)
 {
    RangeVar   *r = makeNode(RangeVar);
 
@@ -276,6 +276,7 @@ makeRangeVar(char *schemaname, char *relname)
    r->inhOpt = INH_DEFAULT;
    r->istemp = false;
    r->alias = NULL;
+   r->location = location;
 
    return r;
 }
index fa1bb347b903bcbfd7c9d0296d9ab55320c02474..a06164156665b827059db2f89d54910549fc8f0b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.31 2008/08/28 23:09:46 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/nodes/nodeFuncs.c,v 1.32 2008/09/01 20:42:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -613,6 +613,9 @@ exprLocation(Node *expr)
        return -1;
    switch (nodeTag(expr))
    {
+       case T_RangeVar:
+           loc = ((RangeVar *) expr)->location;
+           break;
        case T_Var:
            loc = ((Var *) expr)->location;
            break;
@@ -789,6 +792,10 @@ exprLocation(Node *expr)
            /* just use argument's location */
            loc = exprLocation((Node *) ((TargetEntry *) expr)->expr);
            break;
+       case T_IntoClause:
+           /* use the contained RangeVar's location --- close enough */
+           loc = exprLocation((Node *) ((IntoClause *) expr)->rel);
+           break;
        case T_List:
            {
                /* report location of first list member that has a location */
@@ -852,6 +859,10 @@ exprLocation(Node *expr)
                loc = leftmostLoc(loc, tc->location);
            }
            break;
+       case T_SortBy:
+           /* just use argument's location (ignore operator, if any) */
+           loc = exprLocation(((SortBy *) expr)->node);
+           break;
        case T_TypeName:
            loc = ((TypeName *) expr)->location;
            break;
index 882dd0f9f14494fae28492551e277969795fa269..15ced48445af995cf4cd7990148de09d0a5fe9eb 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.337 2008/08/30 01:39:14 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.338 2008/09/01 20:42:44 tgl Exp $
  *
  * NOTES
  *   Every node type that can appear in stored rules' parsetrees *must*
@@ -667,6 +667,7 @@ _outRangeVar(StringInfo str, RangeVar *node)
    WRITE_ENUM_FIELD(inhOpt, InhOption);
    WRITE_BOOL_FIELD(istemp);
    WRITE_NODE_FIELD(alias);
+   WRITE_LOCATION_FIELD(location);
 }
 
 static void
@@ -1609,7 +1610,7 @@ _outNotifyStmt(StringInfo str, NotifyStmt *node)
 {
    WRITE_NODE_TYPE("NOTIFY");
 
-   WRITE_NODE_FIELD(relation);
+   WRITE_STRING_FIELD(conditionname);
 }
 
 static void
@@ -2038,10 +2039,11 @@ _outSortBy(StringInfo str, SortBy *node)
 {
    WRITE_NODE_TYPE("SORTBY");
 
+   WRITE_NODE_FIELD(node);
    WRITE_ENUM_FIELD(sortby_dir, SortByDir);
    WRITE_ENUM_FIELD(sortby_nulls, SortByNulls);
    WRITE_NODE_FIELD(useOp);
-   WRITE_NODE_FIELD(node);
+   WRITE_LOCATION_FIELD(location);
 }
 
 static void
index ee363502f69c71ebed50c0e88da19a36ee519490..1eca85d0b60b91f8d8df6c9e9dabd6a05692116f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.213 2008/08/28 23:09:46 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.214 2008/09/01 20:42:44 tgl Exp $
  *
  * NOTES
  *   Path and Plan nodes do not have any readfuncs support, because we
@@ -179,7 +179,7 @@ _readNotifyStmt(void)
 {
    READ_LOCALS(NotifyStmt);
 
-   READ_NODE_FIELD(relation);
+   READ_STRING_FIELD(conditionname);
 
    READ_DONE();
 }
@@ -278,6 +278,7 @@ _readRangeVar(void)
    READ_ENUM_FIELD(inhOpt, InhOption);
    READ_BOOL_FIELD(istemp);
    READ_NODE_FIELD(alias);
+   READ_LOCATION_FIELD(location);
 
    READ_DONE();
 }
index 8f025ac3a425e6254cae5c8d09fd948481c72f40..e6cd2f26b959053334885482f7d00de6ce8a78d0 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.150 2008/08/25 22:42:33 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.151 2008/09/01 20:42:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -733,7 +733,7 @@ build_physical_tlist(PlannerInfo *root, RelOptInfo *rel)
            break;
 
        case RTE_FUNCTION:
-           expandRTE(rte, varno, 0, true /* include dropped */ ,
+           expandRTE(rte, varno, 0, -1, true /* include dropped */ ,
                      NULL, &colvars);
            foreach(l, colvars)
            {
@@ -758,7 +758,7 @@ build_physical_tlist(PlannerInfo *root, RelOptInfo *rel)
            break;
 
        case RTE_VALUES:
-           expandRTE(rte, varno, 0, false /* dropped not applicable */ ,
+           expandRTE(rte, varno, 0, -1, false /* dropped not applicable */ ,
                      NULL, &colvars);
            foreach(l, colvars)
            {
index e9fd15e6f3fda5eeec92492781442289649f9d34..748a3cb93ac567e9e1a9e99d57ff3b4663d660b0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.78 2008/08/28 23:09:46 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.79 2008/09/01 20:42:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -30,10 +30,16 @@ typedef struct
 
 typedef struct
 {
-   int         varno;
-   int         varattno;
+   int         var_location;
    int         sublevels_up;
-} contain_var_reference_context;
+} locate_var_of_level_context;
+
+typedef struct
+{
+   int         var_location;
+   int         relid;
+   int         sublevels_up;
+} locate_var_of_relation_context;
 
 typedef struct
 {
@@ -56,11 +62,12 @@ typedef struct
 static bool pull_varnos_walker(Node *node,
                   pull_varnos_context *context);
 static bool pull_varattnos_walker(Node *node, Bitmapset **varattnos);
-static bool contain_var_reference_walker(Node *node,
-                            contain_var_reference_context *context);
 static bool contain_var_clause_walker(Node *node, void *context);
 static bool contain_vars_of_level_walker(Node *node, int *sublevels_up);
-static bool contain_vars_above_level_walker(Node *node, int *sublevels_up);
+static bool locate_var_of_level_walker(Node *node,
+                                      locate_var_of_level_context *context);
+static bool locate_var_of_relation_walker(Node *node,
+                                   locate_var_of_relation_context *context);
 static bool find_minimum_var_level_walker(Node *node,
                              find_minimum_var_level_context *context);
 static bool pull_var_clause_walker(Node *node,
@@ -136,6 +143,7 @@ pull_varnos_walker(Node *node, pull_varnos_context *context)
                                  (void *) context);
 }
 
+
 /*
  * pull_varattnos
  *     Find all the distinct attribute numbers present in an expression tree,
@@ -178,69 +186,6 @@ pull_varattnos_walker(Node *node, Bitmapset **varattnos)
 }
 
 
-/*
- *     contain_var_reference
- *
- *     Detect whether a parsetree contains any references to a specified
- *     attribute of a specified rtable entry.
- *
- * NOTE: this is used on not-yet-planned expressions.  It may therefore find
- * bare SubLinks, and if so it needs to recurse into them to look for uplevel
- * references to the desired rtable entry! But when we find a completed
- * SubPlan, we only need to look at the parameters passed to the subplan.
- */
-bool
-contain_var_reference(Node *node, int varno, int varattno, int levelsup)
-{
-   contain_var_reference_context context;
-
-   context.varno = varno;
-   context.varattno = varattno;
-   context.sublevels_up = levelsup;
-
-   /*
-    * Must be prepared to start with a Query or a bare expression tree; if
-    * it's a Query, we don't want to increment sublevels_up.
-    */
-   return query_or_expression_tree_walker(node,
-                                          contain_var_reference_walker,
-                                          (void *) &context,
-                                          0);
-}
-
-static bool
-contain_var_reference_walker(Node *node,
-                            contain_var_reference_context *context)
-{
-   if (node == NULL)
-       return false;
-   if (IsA(node, Var))
-   {
-       Var        *var = (Var *) node;
-
-       if (var->varno == context->varno &&
-           var->varattno == context->varattno &&
-           var->varlevelsup == context->sublevels_up)
-           return true;
-       return false;
-   }
-   if (IsA(node, Query))
-   {
-       /* Recurse into RTE subquery or not-yet-planned sublink subquery */
-       bool        result;
-
-       context->sublevels_up++;
-       result = query_tree_walker((Query *) node,
-                                  contain_var_reference_walker,
-                                  (void *) context, 0);
-       context->sublevels_up--;
-       return result;
-   }
-   return expression_tree_walker(node, contain_var_reference_walker,
-                                 (void *) context);
-}
-
-
 /*
  * contain_var_clause
  *   Recursively scan a clause to discover whether it contains any Var nodes
@@ -273,6 +218,7 @@ contain_var_clause_walker(Node *node, void *context)
    return expression_tree_walker(node, contain_var_clause_walker, context);
 }
 
+
 /*
  * contain_vars_of_level
  *   Recursively scan a clause to discover whether it contains any Var nodes
@@ -328,53 +274,146 @@ contain_vars_of_level_walker(Node *node, int *sublevels_up)
                                  (void *) sublevels_up);
 }
 
+
 /*
- * contain_vars_above_level
- *   Recursively scan a clause to discover whether it contains any Var nodes
- *   above the specified query level.  (For example, pass zero to detect
- *   all nonlocal Vars.)
+ * locate_var_of_level
+ *   Find the parse location of any Var of the specified query level.
  *
- *   Returns true if any such Var found.
+ * Returns -1 if no such Var is in the querytree, or if they all have
+ * unknown parse location.  (The former case is probably caller error,
+ * but we don't bother to distinguish it from the latter case.)
  *
  * Will recurse into sublinks. Also, may be invoked directly on a Query.
+ *
+ * Note: it might seem appropriate to merge this functionality into
+ * contain_vars_of_level, but that would complicate that function's API.
+ * Currently, the only uses of this function are for error reporting,
+ * and so shaving cycles probably isn't very important.
  */
-bool
-contain_vars_above_level(Node *node, int levelsup)
+int
+locate_var_of_level(Node *node, int levelsup)
 {
-   int         sublevels_up = levelsup;
+   locate_var_of_level_context context;
 
-   return query_or_expression_tree_walker(node,
-                                          contain_vars_above_level_walker,
-                                          (void *) &sublevels_up,
+   context.var_location = -1;      /* in case we find nothing */
+   context.sublevels_up = levelsup;
+
+   (void) query_or_expression_tree_walker(node,
+                                          locate_var_of_level_walker,
+                                          (void *) &context,
                                           0);
+
+   return context.var_location;
 }
 
 static bool
-contain_vars_above_level_walker(Node *node, int *sublevels_up)
+locate_var_of_level_walker(Node *node,
+                          locate_var_of_level_context *context)
 {
    if (node == NULL)
        return false;
    if (IsA(node, Var))
    {
-       if (((Var *) node)->varlevelsup > *sublevels_up)
+       Var    *var = (Var *) node;
+
+       if (var->varlevelsup == context->sublevels_up &&
+           var->location >= 0)
+       {
+           context->var_location = var->location;
            return true;        /* abort tree traversal and return true */
+       }
+       return false;
+   }
+   if (IsA(node, CurrentOfExpr))
+   {
+       /* since CurrentOfExpr doesn't carry location, nothing we can do */
+       return false;
    }
    if (IsA(node, Query))
    {
        /* Recurse into subselects */
        bool        result;
 
-       (*sublevels_up)++;
+       context->sublevels_up++;
        result = query_tree_walker((Query *) node,
-                                  contain_vars_above_level_walker,
-                                  (void *) sublevels_up,
+                                  locate_var_of_level_walker,
+                                  (void *) context,
                                   0);
-       (*sublevels_up)--;
+       context->sublevels_up--;
        return result;
    }
    return expression_tree_walker(node,
-                                 contain_vars_above_level_walker,
-                                 (void *) sublevels_up);
+                                 locate_var_of_level_walker,
+                                 (void *) context);
+}
+
+
+/*
+ * locate_var_of_relation
+ *   Find the parse location of any Var of the specified relation.
+ *
+ * Returns -1 if no such Var is in the querytree, or if they all have
+ * unknown parse location.
+ *
+ * Will recurse into sublinks. Also, may be invoked directly on a Query.
+ */
+int
+locate_var_of_relation(Node *node, int relid, int levelsup)
+{
+   locate_var_of_relation_context context;
+
+   context.var_location = -1;      /* in case we find nothing */
+   context.relid = relid;
+   context.sublevels_up = levelsup;
+
+   (void) query_or_expression_tree_walker(node,
+                                          locate_var_of_relation_walker,
+                                          (void *) &context,
+                                          0);
+
+   return context.var_location;
+}
+
+static bool
+locate_var_of_relation_walker(Node *node,
+                             locate_var_of_relation_context *context)
+{
+   if (node == NULL)
+       return false;
+   if (IsA(node, Var))
+   {
+       Var    *var = (Var *) node;
+
+       if (var->varno == context->relid &&
+           var->varlevelsup == context->sublevels_up &&
+           var->location >= 0)
+       {
+           context->var_location = var->location;
+           return true;        /* abort tree traversal and return true */
+       }
+       return false;
+   }
+   if (IsA(node, CurrentOfExpr))
+   {
+       /* since CurrentOfExpr doesn't carry location, nothing we can do */
+       return false;
+   }
+   if (IsA(node, Query))
+   {
+       /* Recurse into subselects */
+       bool        result;
+
+       context->sublevels_up++;
+       result = query_tree_walker((Query *) node,
+                                  locate_var_of_relation_walker,
+                                  (void *) context,
+                                  0);
+       context->sublevels_up--;
+       return result;
+   }
+   return expression_tree_walker(node,
+                                 locate_var_of_relation_walker,
+                                 (void *) context);
 }
 
 
index b513d61c071691c4833cb99f96666bd8ea872483..18585b860b4335aa96ea6bf795d646b11e9b2dbe 100644 (file)
@@ -17,7 +17,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.378 2008/08/28 23:09:47 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.379 2008/09/01 20:42:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "parser/parse_relation.h"
 #include "parser/parse_target.h"
 #include "parser/parsetree.h"
+#include "rewrite/rewriteManip.h"
 #include "utils/rel.h"
 
 
-typedef struct
-{
-   Oid        *paramTypes;
-   int         numParams;
-} check_parameter_resolution_context;
-
-
 static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
 static Query *transformInsertStmt(ParseState *pstate, InsertStmt *stmt);
 static List *transformInsertRow(ParseState *pstate, List *exprlist,
@@ -62,9 +56,9 @@ static Query *transformDeclareCursorStmt(ParseState *pstate,
                           DeclareCursorStmt *stmt);
 static Query *transformExplainStmt(ParseState *pstate,
                     ExplainStmt *stmt);
-static void transformLockingClause(Query *qry, LockingClause *lc);
-static bool check_parameter_resolution_walker(Node *node,
-                               check_parameter_resolution_context *context);
+static void transformLockingClause(ParseState *pstate,
+                                  Query *qry, LockingClause *lc);
+static bool check_parameter_resolution_walker(Node *node, ParseState *pstate);
 
 
 /*
@@ -122,21 +116,15 @@ parse_analyze_varparams(Node *parseTree, const char *sourceText,
 
    query = transformStmt(pstate, parseTree);
 
+   /* make sure all is well with parameter types */
+   if (pstate->p_numparams > 0)
+       check_parameter_resolution_walker((Node *) query, pstate);
+
    *paramTypes = pstate->p_paramtypes;
    *numParams = pstate->p_numparams;
 
    free_parsestate(pstate);
 
-   /* make sure all is well with parameter types */
-   if (*numParams > 0)
-   {
-       check_parameter_resolution_context context;
-
-       context.paramTypes = *paramTypes;
-       context.numParams = *numParams;
-       check_parameter_resolution_walker((Node *) query, &context);
-   }
-
    return query;
 }
 
@@ -383,13 +371,16 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
        free_parsestate(sub_pstate);
 
        /* The grammar should have produced a SELECT, but it might have INTO */
-       Assert(IsA(selectQuery, Query));
-       Assert(selectQuery->commandType == CMD_SELECT);
-       Assert(selectQuery->utilityStmt == NULL);
+       if (!IsA(selectQuery, Query) ||
+           selectQuery->commandType != CMD_SELECT ||
+           selectQuery->utilityStmt != NULL)
+           elog(ERROR, "unexpected non-SELECT command in INSERT ... SELECT");
        if (selectQuery->intoClause)
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
-                    errmsg("INSERT ... SELECT cannot specify INTO")));
+                    errmsg("INSERT ... SELECT cannot specify INTO"),
+                    parser_errposition(pstate,
+                                       exprLocation((Node *) selectQuery->intoClause))));
 
        /*
         * Make the source be a subquery in the INSERT's rangetable, and add
@@ -477,7 +468,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
            {
                ereport(ERROR,
                        (errcode(ERRCODE_SYNTAX_ERROR),
-                        errmsg("VALUES lists must all be the same length")));
+                        errmsg("VALUES lists must all be the same length"),
+                        parser_errposition(pstate,
+                                           exprLocation((Node *) sublist))));
            }
 
            /* Prepare row for assignment to target table */
@@ -496,7 +489,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
        if (pstate->p_joinlist != NIL)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                    errmsg("VALUES must not contain table references")));
+                    errmsg("VALUES must not contain table references"),
+                    parser_errposition(pstate,
+                                       locate_var_of_level((Node *) exprsLists, 0))));
 
        /*
         * Another thing we can't currently support is NEW/OLD references in
@@ -509,7 +504,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("VALUES must not contain OLD or NEW references"),
-                    errhint("Use SELECT ... UNION ALL ... instead.")));
+                    errhint("Use SELECT ... UNION ALL ... instead."),
+                    parser_errposition(pstate,
+                                       locate_var_of_level((Node *) exprsLists, 0))));
 
        /*
         * Generate the VALUES RTE
@@ -524,7 +521,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
        /*
         * Generate list of Vars referencing the RTE
         */
-       expandRTE(rte, rtr->rtindex, 0, false, NULL, &exprList);
+       expandRTE(rte, rtr->rtindex, 0, -1, false, NULL, &exprList);
    }
    else
    {
@@ -603,7 +600,9 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
    if (pstate->p_hasAggs)
        ereport(ERROR,
                (errcode(ERRCODE_GROUPING_ERROR),
-                errmsg("cannot use aggregate function in VALUES")));
+                errmsg("cannot use aggregate function in VALUES"),
+                parser_errposition(pstate,
+                                   locate_agg_of_level((Node *) qry, 0))));
 
    return qry;
 }
@@ -633,12 +632,18 @@ transformInsertRow(ParseState *pstate, List *exprlist,
    if (list_length(exprlist) > list_length(icolumns))
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
-                errmsg("INSERT has more expressions than target columns")));
+                errmsg("INSERT has more expressions than target columns"),
+                parser_errposition(pstate,
+                                   exprLocation(list_nth(exprlist,
+                                                         list_length(icolumns))))));
    if (stmtcols != NIL &&
        list_length(exprlist) < list_length(icolumns))
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
-                errmsg("INSERT has more target columns than expressions")));
+                errmsg("INSERT has more target columns than expressions"),
+                parser_errposition(pstate,
+                                   exprLocation(list_nth(icolumns,
+                                                         list_length(exprlist))))));
 
    /*
     * Prepare columns for assignment to target table.
@@ -770,7 +775,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
 
    foreach(l, stmt->lockingClause)
    {
-       transformLockingClause(qry, (LockingClause *) lfirst(l));
+       transformLockingClause(pstate, qry, (LockingClause *) lfirst(l));
    }
 
    return qry;
@@ -838,7 +843,9 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
        {
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
-                    errmsg("VALUES lists must all be the same length")));
+                    errmsg("VALUES lists must all be the same length"),
+                    parser_errposition(pstate,
+                                       exprLocation((Node *) sublist))));
        }
 
        exprsLists = lappend(exprsLists, sublist);
@@ -902,7 +909,7 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
     * Generate a targetlist as though expanding "*"
     */
    Assert(pstate->p_next_resno == 1);
-   qry->targetList = expandRelAttrs(pstate, rte, rtr->rtindex, 0);
+   qry->targetList = expandRelAttrs(pstate, rte, rtr->rtindex, 0, -1);
 
    /*
     * The grammar allows attaching ORDER BY, LIMIT, and FOR UPDATE to a
@@ -940,7 +947,9 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
    if (list_length(pstate->p_joinlist) != 1)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                errmsg("VALUES must not contain table references")));
+                errmsg("VALUES must not contain table references"),
+                parser_errposition(pstate,
+                                   locate_var_of_level((Node *) newExprsLists, 0))));
 
    /*
     * Another thing we can't currently support is NEW/OLD references in rules
@@ -953,7 +962,9 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("VALUES must not contain OLD or NEW references"),
-                errhint("Use SELECT ... UNION ALL ... instead.")));
+                errhint("Use SELECT ... UNION ALL ... instead."),
+                parser_errposition(pstate,
+                                   locate_var_of_level((Node *) newExprsLists, 0))));
 
    qry->rtable = pstate->p_rtable;
    qry->jointree = makeFromExpr(pstate->p_joinlist, NULL);
@@ -963,7 +974,9 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
    if (pstate->p_hasAggs)
        ereport(ERROR,
                (errcode(ERRCODE_GROUPING_ERROR),
-                errmsg("cannot use aggregate function in VALUES")));
+                errmsg("cannot use aggregate function in VALUES"),
+                parser_errposition(pstate,
+                                   locate_agg_of_level((Node *) newExprsLists, 0))));
 
    return qry;
 }
@@ -1155,7 +1168,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                 errmsg("invalid UNION/INTERSECT/EXCEPT ORDER BY clause"),
                 errdetail("Only result column names can be used, not expressions or functions."),
-                errhint("Add the expression/function to every SELECT, or move the UNION into a FROM clause.")));
+                errhint("Add the expression/function to every SELECT, or move the UNION into a FROM clause."),
+                parser_errposition(pstate,
+                                   exprLocation(list_nth(qry->targetList, tllen)))));
 
    qry->limitOffset = transformLimitClause(pstate, limitOffset,
                                            "OFFSET");
@@ -1185,7 +1200,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
 
    foreach(l, lockingClause)
    {
-       transformLockingClause(qry, (LockingClause *) lfirst(l));
+       transformLockingClause(pstate, qry, (LockingClause *) lfirst(l));
    }
 
    return qry;
@@ -1198,9 +1213,9 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
  * In addition to returning the transformed node, we return a list of
  * expression nodes showing the type, typmod, and location (for error messages)
  * of each output column of the set-op node.  This is used only during the
- * internal recursion of this function.  We use SetToDefault nodes for
- * this purpose, since they carry exactly the fields needed, but any other
- * expression node type would do as well.
+ * internal recursion of this function.  At the upper levels we use
+ * SetToDefault nodes for this purpose, since they carry exactly the fields
+ * needed, but any other expression node type would do as well.
  */
 static Node *
 transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
@@ -1216,7 +1231,10 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
    if (stmt->intoClause)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
-                errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT")));
+                errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT"),
+                parser_errposition(pstate,
+                                   exprLocation((Node *) stmt->intoClause))));
+
    /* We don't support FOR UPDATE/SHARE with set ops at the moment. */
    if (stmt->lockingClause)
        ereport(ERROR,
@@ -1273,25 +1291,21 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
            if (contain_vars_of_level((Node *) selectQuery, 1))
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
-                        errmsg("UNION/INTERSECT/EXCEPT member statement cannot refer to other relations of same query level")));
+                        errmsg("UNION/INTERSECT/EXCEPT member statement cannot refer to other relations of same query level"),
+                        parser_errposition(pstate,
+                                           locate_var_of_level((Node *) selectQuery, 1))));
        }
 
        /*
-        * Extract information about the result columns.
+        * Extract a list of the result expressions for upper-level checking.
         */
        *colInfo = NIL;
        foreach(tl, selectQuery->targetList)
        {
            TargetEntry *tle = (TargetEntry *) lfirst(tl);
-           SetToDefault   *cinfo;
 
-           if (tle->resjunk)
-               continue;
-           cinfo = makeNode(SetToDefault);
-           cinfo->typeId = exprType((Node *) tle->expr);
-           cinfo->typeMod = exprTypmod((Node *) tle->expr);
-           cinfo->location = exprLocation((Node *) tle->expr);
-           *colInfo = lappend(*colInfo, cinfo);
+           if (!tle->resjunk)
+               *colInfo = lappend(*colInfo, tle->expr);
        }
 
        /*
@@ -1356,12 +1370,12 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
        op->groupClauses = NIL;
        forboth(lci, lcolinfo, rci, rcolinfo)
        {
-           SetToDefault *lcolinfo = (SetToDefault *) lfirst(lci);
-           SetToDefault *rcolinfo = (SetToDefault *) lfirst(rci);
-           Oid         lcoltype = lcolinfo->typeId;
-           Oid         rcoltype = rcolinfo->typeId;
-           int32       lcoltypmod = lcolinfo->typeMod;
-           int32       rcoltypmod = rcolinfo->typeMod;
+           Node       *lcolinfo = (Node *) lfirst(lci);
+           Node       *rcolinfo = (Node *) lfirst(rci);
+           Oid         lcoltype = exprType(lcolinfo);
+           Oid         rcoltype = exprType(rcolinfo);
+           int32       lcoltypmod = exprTypmod(lcolinfo);
+           int32       rcoltypmod = exprTypmod(rcolinfo);
            Node       *bestexpr;
            SetToDefault *rescolinfo;
            Oid         rescoltype;
@@ -1379,18 +1393,16 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
                rescoltypmod = -1;
 
            /* verify the coercions are actually possible */
-           if (lcoltype != UNKNOWNOID)
-               (void) coerce_to_common_type(pstate, (Node *) lcolinfo,
-                                            rescoltype, context);
-           if (rcoltype != UNKNOWNOID)
-               (void) coerce_to_common_type(pstate, (Node *) rcolinfo,
-                                            rescoltype, context);
+           (void) coerce_to_common_type(pstate, lcolinfo,
+                                        rescoltype, context);
+           (void) coerce_to_common_type(pstate, rcolinfo,
+                                        rescoltype, context);
 
            /* emit results */
            rescolinfo = makeNode(SetToDefault);
            rescolinfo->typeId = rescoltype;
            rescolinfo->typeMod = rescoltypmod;
-           rescolinfo->location = ((SetToDefault *) bestexpr)->location;
+           rescolinfo->location = exprLocation(bestexpr);
            *colInfo = lappend(*colInfo, rescolinfo);
 
            op->colTypes = lappend_oid(op->colTypes, rescoltype);
@@ -1406,12 +1418,18 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
                SortGroupClause *grpcl = makeNode(SortGroupClause);
                Oid         sortop;
                Oid         eqop;
+               ParseCallbackState pcbstate;
+
+               setup_parser_errposition_callback(&pcbstate, pstate,
+                                                 rescolinfo->location);
 
                /* determine the eqop and optional sortop */
                get_sort_group_operators(rescoltype,
                                         false, true, false,
                                         &sortop, &eqop, NULL);
 
+               cancel_parser_errposition_callback(&pcbstate);
+
                /* we don't have a tlist yet, so can't assign sortgrouprefs */
                grpcl->tleSortGroupRef = 0;
                grpcl->eqop = eqop;
@@ -1510,7 +1528,9 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
    if (pstate->p_hasAggs)
        ereport(ERROR,
                (errcode(ERRCODE_GROUPING_ERROR),
-                errmsg("cannot use aggregate function in UPDATE")));
+                errmsg("cannot use aggregate function in UPDATE"),
+                parser_errposition(pstate,
+                                   locate_agg_of_level((Node *) qry, 0))));
 
    /*
     * Now we are done with SELECT-like processing, and can get on with
@@ -1607,13 +1627,28 @@ transformReturningList(ParseState *pstate, List *returningList)
    if (pstate->p_hasAggs)
        ereport(ERROR,
                (errcode(ERRCODE_GROUPING_ERROR),
-                errmsg("cannot use aggregate function in RETURNING")));
+                errmsg("cannot use aggregate function in RETURNING"),
+                parser_errposition(pstate,
+                                   locate_agg_of_level((Node *) rlist, 0))));
 
    /* no new relation references please */
    if (list_length(pstate->p_rtable) != length_rtable)
+   {
+       int     vlocation = -1;
+       int     relid;
+
+       /* try to locate such a reference to point to */
+       for (relid = length_rtable + 1; relid <= list_length(pstate->p_rtable); relid++)
+       {
+           vlocation = locate_var_of_relation((Node *) rlist, relid, 0);
+           if (vlocation >= 0)
+               break;
+       }
        ereport(ERROR,
                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-         errmsg("RETURNING cannot contain references to other relations")));
+         errmsg("RETURNING cannot contain references to other relations"),
+                parser_errposition(pstate, vlocation)));
+   }
 
    /* mark column origins */
    markTargetListOrigins(pstate, rlist);
@@ -1653,16 +1688,19 @@ transformDeclareCursorStmt(ParseState *pstate, DeclareCursorStmt *stmt)
 
    result = transformStmt(pstate, stmt->query);
 
+   /* Grammar should not have allowed anything but SELECT */
    if (!IsA(result, Query) ||
        result->commandType != CMD_SELECT ||
        result->utilityStmt != NULL)
-       elog(ERROR, "unexpected non-SELECT command in cursor statement");
+       elog(ERROR, "unexpected non-SELECT command in DECLARE CURSOR");
 
    /* But we must explicitly disallow DECLARE CURSOR ... SELECT INTO */
    if (result->intoClause)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
-                errmsg("DECLARE CURSOR cannot specify INTO")));
+                errmsg("DECLARE CURSOR cannot specify INTO"),
+                parser_errposition(pstate,
+                                   exprLocation((Node *) result->intoClause))));
 
    /* FOR UPDATE and WITH HOLD are not compatible */
    if (result->rowMarks != NIL && (stmt->options & CURSOR_OPT_HOLD))
@@ -1761,10 +1799,10 @@ CheckSelectLocking(Query *qry)
  * This basically involves replacing names by integer relids.
  *
  * NB: if you need to change this, see also markQueryForLocking()
- * in rewriteHandler.c.
+ * in rewriteHandler.c, and isLockedRel() in parse_relation.c.
  */
 static void
-transformLockingClause(Query *qry, LockingClause *lc)
+transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc)
 {
    List       *lockedRels = lc->lockedRels;
    ListCell   *l;
@@ -1801,7 +1839,7 @@ transformLockingClause(Query *qry, LockingClause *lc)
                     * FOR UPDATE/SHARE of subquery is propagated to all of
                     * subquery's rels
                     */
-                   transformLockingClause(rte->subquery, allrels);
+                   transformLockingClause(pstate, rte->subquery, allrels);
                    break;
                default:
                    /* ignore JOIN, SPECIAL, FUNCTION RTEs */
@@ -1814,7 +1852,14 @@ transformLockingClause(Query *qry, LockingClause *lc)
        /* just the named tables */
        foreach(l, lockedRels)
        {
-           char       *relname = strVal(lfirst(l));
+           RangeVar   *thisrel = (RangeVar *) lfirst(l);
+
+           /* For simplicity we insist on unqualified alias names here */
+           if (thisrel->catalogname || thisrel->schemaname)
+               ereport(ERROR,
+                       (errcode(ERRCODE_SYNTAX_ERROR),
+                        errmsg("SELECT FOR UPDATE/SHARE must specify unqualified relation names"),
+                        parser_errposition(pstate, thisrel->location)));
 
            i = 0;
            foreach(rt, qry->rtable)
@@ -1822,7 +1867,7 @@ transformLockingClause(Query *qry, LockingClause *lc)
                RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
 
                ++i;
-               if (strcmp(rte->eref->aliasname, relname) == 0)
+               if (strcmp(rte->eref->aliasname, thisrel->relname) == 0)
                {
                    switch (rte->rtekind)
                    {
@@ -1837,27 +1882,31 @@ transformLockingClause(Query *qry, LockingClause *lc)
                             * FOR UPDATE/SHARE of subquery is propagated to
                             * all of subquery's rels
                             */
-                           transformLockingClause(rte->subquery, allrels);
+                           transformLockingClause(pstate, rte->subquery, allrels);
                            break;
                        case RTE_JOIN:
                            ereport(ERROR,
                                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                    errmsg("SELECT FOR UPDATE/SHARE cannot be applied to a join")));
+                                    errmsg("SELECT FOR UPDATE/SHARE cannot be applied to a join"),
+                                    parser_errposition(pstate, thisrel->location)));
                            break;
                        case RTE_SPECIAL:
                            ereport(ERROR,
                                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                    errmsg("SELECT FOR UPDATE/SHARE cannot be applied to NEW or OLD")));
+                                    errmsg("SELECT FOR UPDATE/SHARE cannot be applied to NEW or OLD"),
+                                    parser_errposition(pstate, thisrel->location)));
                            break;
                        case RTE_FUNCTION:
                            ereport(ERROR,
                                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                    errmsg("SELECT FOR UPDATE/SHARE cannot be applied to a function")));
+                                    errmsg("SELECT FOR UPDATE/SHARE cannot be applied to a function"),
+                                    parser_errposition(pstate, thisrel->location)));
                            break;
                        case RTE_VALUES:
                            ereport(ERROR,
                                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                    errmsg("SELECT FOR UPDATE/SHARE cannot be applied to VALUES")));
+                                    errmsg("SELECT FOR UPDATE/SHARE cannot be applied to VALUES"),
+                                    parser_errposition(pstate, thisrel->location)));
                            break;
                        default:
                            elog(ERROR, "unrecognized RTE type: %d",
@@ -1871,7 +1920,8 @@ transformLockingClause(Query *qry, LockingClause *lc)
                ereport(ERROR,
                        (errcode(ERRCODE_UNDEFINED_TABLE),
                         errmsg("relation \"%s\" in FOR UPDATE/SHARE clause not found in FROM clause",
-                               relname)));
+                               thisrel->relname),
+                        parser_errposition(pstate, thisrel->location)));
        }
    }
 }
@@ -1919,8 +1969,7 @@ applyLockingClause(Query *qry, Index rtindex, bool forUpdate, bool noWait)
  * and yet other instances seen later might have gotten coerced.
  */
 static bool
-check_parameter_resolution_walker(Node *node,
-                                 check_parameter_resolution_context *context)
+check_parameter_resolution_walker(Node *node, ParseState *pstate)
 {
    if (node == NULL)
        return false;
@@ -1933,16 +1982,18 @@ check_parameter_resolution_walker(Node *node,
            int         paramno = param->paramid;
 
            if (paramno <= 0 || /* shouldn't happen, but... */
-               paramno > context->numParams)
+               paramno > pstate->p_numparams)
                ereport(ERROR,
                        (errcode(ERRCODE_UNDEFINED_PARAMETER),
-                        errmsg("there is no parameter $%d", paramno)));
+                        errmsg("there is no parameter $%d", paramno),
+                        parser_errposition(pstate, param->location)));
 
-           if (param->paramtype != context->paramTypes[paramno - 1])
+           if (param->paramtype != pstate->p_paramtypes[paramno - 1])
                ereport(ERROR,
                        (errcode(ERRCODE_AMBIGUOUS_PARAMETER),
                     errmsg("could not determine data type of parameter $%d",
-                           paramno)));
+                           paramno),
+                        parser_errposition(pstate, param->location)));
        }
        return false;
    }
@@ -1951,8 +2002,8 @@ check_parameter_resolution_walker(Node *node,
        /* Recurse into RTE subquery or not-yet-planned sublink subquery */
        return query_tree_walker((Query *) node,
                                 check_parameter_resolution_walker,
-                                (void *) context, 0);
+                                (void *) pstate, 0);
    }
    return expression_tree_walker(node, check_parameter_resolution_walker,
-                                 (void *) context);
+                                 (void *) pstate);
 }
index 78e81fbf562f82e5999f1beacd8d628ac76ac11c..26a3198d37b960f1a94791c4e75cbb9016f3f059 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.620 2008/08/30 01:39:14 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.621 2008/09/01 20:42:44 tgl Exp $
  *
  * HISTORY
  *   AUTHOR            DATE            MAJOR EVENT
@@ -55,6 +55,7 @@
 #include "catalog/namespace.h"
 #include "commands/defrem.h"
 #include "nodes/makefuncs.h"
+#include "nodes/nodeFuncs.h"
 #include "parser/gramparse.h"
 #include "storage/lmgr.h"
 #include "utils/date.h"
@@ -1215,7 +1216,8 @@ zone_value:
                        if (($3 & ~(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) != 0)
                            ereport(ERROR,
                                    (errcode(ERRCODE_SYNTAX_ERROR),
-                                    errmsg("time zone interval must be HOUR or HOUR TO MINUTE")));
+                                    errmsg("time zone interval must be HOUR or HOUR TO MINUTE"),
+                                    scanner_errposition(@3)));
                        t->typmods = list_make1(makeIntConst($3, @3));
                    }
                    $$ = makeStringConstCast($2, @2, t);
@@ -1227,7 +1229,8 @@ zone_value:
                        && (($6 & ~(INTERVAL_MASK(HOUR) | INTERVAL_MASK(MINUTE))) != 0))
                        ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("time zone interval must be HOUR or HOUR TO MINUTE")));
+                                errmsg("time zone interval must be HOUR or HOUR TO MINUTE"),
+                                scanner_errposition(@6)));
                    t->typmods = list_make2(makeIntConst($6, @6),
                                            makeIntConst($3, @3));
                    $$ = makeStringConstCast($5, @5, t);
@@ -2286,7 +2289,8 @@ key_match:  MATCH FULL
            {
                ereport(ERROR,
                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                        errmsg("MATCH PARTIAL not yet implemented")));
+                        errmsg("MATCH PARTIAL not yet implemented"),
+                        scanner_errposition(@1)));
                $$ = FKCONSTR_MATCH_PARTIAL;
            }
        | MATCH SIMPLE
@@ -2378,7 +2382,8 @@ CreateAsStmt:
                    if (n->intoClause != NULL)
                        ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("CREATE TABLE AS cannot specify INTO")));
+                                errmsg("CREATE TABLE AS cannot specify INTO"),
+                                scanner_errposition(exprLocation((Node *) n->intoClause))));
                    $4->rel->istemp = $2;
                    n->intoClause = $4;
                    $$ = $6;
@@ -2799,7 +2804,8 @@ ConstraintAttributeSpec:
                    if ($1 == 0 && $2 != 0)
                        ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE")));
+                                errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
+                                scanner_errposition(@1)));
                    $$ = $1 | $2;
                }
            | ConstraintTimeSpec
@@ -2814,7 +2820,8 @@ ConstraintAttributeSpec:
                    if ($2 == 0 && $1 != 0)
                        ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE")));
+                                errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
+                                scanner_errposition(@1)));
                    $$ = $1 | $2;
                }
            | /*EMPTY*/
@@ -2986,9 +2993,11 @@ DefineStmt:
                            ereport(ERROR,
                                    (errcode(ERRCODE_SYNTAX_ERROR),
                                     errmsg("improper qualified name (too many dotted names): %s",
-                                           NameListToString($3))));
+                                           NameListToString($3)),
+                                           scanner_errposition(@3)));
                            break;
                    }
+                   r->location = @3;
                    n->typevar = r;
                    n->coldeflist = $6;
                    $$ = (Node *)n;
@@ -3128,12 +3137,12 @@ opclass_item:
                    n->number = $2;
                    $$ = (Node *) n;
                }
-           | OPERATOR Iconst any_operator '(' oper_argtypes ')' opt_recheck
+           | OPERATOR Iconst any_operator oper_argtypes opt_recheck
                {
                    CreateOpClassItem *n = makeNode(CreateOpClassItem);
                    n->itemtype = OPCLASS_ITEM_OPERATOR;
                    n->name = $3;
-                   n->args = $5;
+                   n->args = $4;
                    n->number = $2;
                    $$ = (Node *) n;
                }
@@ -3178,7 +3187,8 @@ opt_recheck:  RECHECK
                    ereport(ERROR,
                            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                             errmsg("RECHECK is no longer supported"),
-                            errhint("Update your data type.")));
+                            errhint("Update your data type."),
+                            scanner_errposition(@1)));
                    $$ = TRUE;
                }
            | /*EMPTY*/                     { $$ = FALSE; }
@@ -3445,14 +3455,13 @@ CommentStmt:
                    n->comment = $7;
                    $$ = (Node *) n;
                }
-           | COMMENT ON OPERATOR any_operator '(' oper_argtypes ')'
-           IS comment_text
+           | COMMENT ON OPERATOR any_operator oper_argtypes IS comment_text
                {
                    CommentStmt *n = makeNode(CommentStmt);
                    n->objtype = OBJECT_OPERATOR;
                    n->objname = $4;
-                   n->objargs = $6;
-                   n->comment = $9;
+                   n->objargs = $5;
+                   n->comment = $7;
                    $$ = (Node *) n;
                }
            | COMMENT ON CONSTRAINT name ON any_name IS comment_text
@@ -4088,8 +4097,8 @@ opt_class:    any_name                                { $$ = $1; }
        ;
 
 opt_asc_desc: ASC                          { $$ = SORTBY_ASC; }
-           | DESC                      { $$ = SORTBY_DESC; }
-           | /*EMPTY*/                 { $$ = SORTBY_DEFAULT; }
+           | DESC                          { $$ = SORTBY_DESC; }
+           | /*EMPTY*/                     { $$ = SORTBY_DEFAULT; }
        ;
 
 opt_nulls_order: NULLS_FIRST               { $$ = SORTBY_NULLS_FIRST; }
@@ -4464,42 +4473,43 @@ RemoveAggrStmt:
        ;
 
 RemoveOperStmt:
-           DROP OPERATOR any_operator '(' oper_argtypes ')' opt_drop_behavior
+           DROP OPERATOR any_operator oper_argtypes opt_drop_behavior
                {
                    RemoveFuncStmt *n = makeNode(RemoveFuncStmt);
                    n->kind = OBJECT_OPERATOR;
                    n->name = $3;
-                   n->args = $5;
-                   n->behavior = $7;
+                   n->args = $4;
+                   n->behavior = $5;
                    n->missing_ok = false;
                    $$ = (Node *)n;
                }
-           | DROP OPERATOR IF_P EXISTS any_operator '(' oper_argtypes ')' opt_drop_behavior
+           | DROP OPERATOR IF_P EXISTS any_operator oper_argtypes opt_drop_behavior
                {
                    RemoveFuncStmt *n = makeNode(RemoveFuncStmt);
                    n->kind = OBJECT_OPERATOR;
                    n->name = $5;
-                   n->args = $7;
-                   n->behavior = $9;
+                   n->args = $6;
+                   n->behavior = $7;
                    n->missing_ok = true;
                    $$ = (Node *)n;
                }
        ;
 
 oper_argtypes:
-           Typename
+           '(' Typename ')'
                {
                   ereport(ERROR,
                           (errcode(ERRCODE_SYNTAX_ERROR),
                            errmsg("missing argument"),
-                           errhint("Use NONE to denote the missing argument of a unary operator.")));
+                           errhint("Use NONE to denote the missing argument of a unary operator."),
+                           scanner_errposition(@3)));
                }
-           | Typename ',' Typename
-                   { $$ = list_make2($1, $3); }
-           | NONE ',' Typename                         /* left unary */
-                   { $$ = list_make2(NULL, $3); }
-           | Typename ',' NONE                         /* right unary */
-                   { $$ = list_make2($1, NULL); }
+           | '(' Typename ',' Typename ')'
+                   { $$ = list_make2($2, $4); }
+           | '(' NONE ',' Typename ')'                 /* left unary */
+                   { $$ = list_make2(NULL, $4); }
+           | '(' Typename ',' NONE ')'                 /* right unary */
+                   { $$ = list_make2($2, NULL); }
        ;
 
 any_operator:
@@ -4939,13 +4949,13 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
                    n->newowner = $7;
                    $$ = (Node *)n;
                }
-           | ALTER OPERATOR any_operator '(' oper_argtypes ')' OWNER TO RoleId
+           | ALTER OPERATOR any_operator oper_argtypes OWNER TO RoleId
                {
                    AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
                    n->objectType = OBJECT_OPERATOR;
                    n->object = $3;
-                   n->objarg = $5;
-                   n->newowner = $9;
+                   n->objarg = $4;
+                   n->newowner = $7;
                    $$ = (Node *)n;
                }
            | ALTER OPERATOR CLASS any_name USING access_method OWNER TO RoleId
@@ -5108,7 +5118,7 @@ DropRuleStmt:
 /*****************************************************************************
  *
  *     QUERY:
- *             NOTIFY <qualified_name> can appear both in rule bodies and
+ *             NOTIFY <identifier> can appear both in rule bodies and
  *             as a query-level command
  *
  *****************************************************************************/
@@ -5116,9 +5126,7 @@ DropRuleStmt:
 NotifyStmt: NOTIFY ColId
                {
                    NotifyStmt *n = makeNode(NotifyStmt);
-                   n->relation = makeNode(RangeVar);
-                   n->relation->relname = $2;
-                   n->relation->schemaname = NULL;
+                   n->conditionname = $2;
                    $$ = (Node *)n;
                }
        ;
@@ -5126,9 +5134,7 @@ NotifyStmt: NOTIFY ColId
 ListenStmt: LISTEN ColId
                {
                    ListenStmt *n = makeNode(ListenStmt);
-                   n->relation = makeNode(RangeVar);
-                   n->relation->relname = $2;
-                   n->relation->schemaname = NULL;
+                   n->conditionname = $2;
                    $$ = (Node *)n;
                }
        ;
@@ -5137,15 +5143,13 @@ UnlistenStmt:
            UNLISTEN ColId
                {
                    UnlistenStmt *n = makeNode(UnlistenStmt);
-                   n->relation = makeNode(RangeVar);
-                   n->relation->relname = $2;
-                   n->relation->schemaname = NULL;
+                   n->conditionname = $2;
                    $$ = (Node *)n;
                }
            | UNLISTEN '*'
                {
                    UnlistenStmt *n = makeNode(UnlistenStmt);
-                   n->relation = NULL;
+                   n->conditionname = NULL;
                    $$ = (Node *)n;
                }
        ;
@@ -6119,7 +6123,8 @@ multiple_set_clause:
                    if (list_length($2) != list_length($5))
                        ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("number of columns does not match number of values")));
+                                errmsg("number of columns does not match number of values"),
+                                scanner_errposition(@1)));
                    forboth(col_cell, $2, val_cell, $5)
                    {
                        ResTarget *res_col = (ResTarget *) lfirst(col_cell);
@@ -6419,6 +6424,7 @@ sortby:       a_expr USING qual_all_Op opt_nulls_order
                    $$->sortby_dir = SORTBY_USING;
                    $$->sortby_nulls = $4;
                    $$->useOp = $3;
+                   $$->location = @3;
                }
            | a_expr opt_asc_desc opt_nulls_order
                {
@@ -6427,6 +6433,7 @@ sortby:       a_expr USING qual_all_Op opt_nulls_order
                    $$->sortby_dir = $2;
                    $$->sortby_nulls = $3;
                    $$->useOp = NIL;
+                   $$->location = -1;      /* no operator */
                }
        ;
 
@@ -6446,7 +6453,8 @@ select_limit:
                    ereport(ERROR,
                            (errcode(ERRCODE_SYNTAX_ERROR),
                             errmsg("LIMIT #,# syntax is not supported"),
-                            errhint("Use separate LIMIT and OFFSET clauses.")));
+                            errhint("Use separate LIMIT and OFFSET clauses."),
+                            scanner_errposition(@1)));
                }
        ;
 
@@ -6514,7 +6522,7 @@ for_locking_item:
        ;
 
 locked_rels_list:
-           OF name_list                            { $$ = $2; }
+           OF qualified_name_list                  { $$ = $2; }
            | /* EMPTY */                           { $$ = NIL; }
        ;
 
@@ -6629,12 +6637,14 @@ table_ref:  relation_expr
                        ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR),
                                 errmsg("VALUES in FROM must have an alias"),
-                                errhint("For example, FROM (VALUES ...) [AS] foo.")));
+                                errhint("For example, FROM (VALUES ...) [AS] foo."),
+                                scanner_errposition(@1)));
                    else
                        ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR),
                                 errmsg("subquery in FROM must have an alias"),
-                                errhint("For example, FROM (SELECT ...) [AS] foo.")));
+                                errhint("For example, FROM (SELECT ...) [AS] foo."),
+                                scanner_errposition(@1)));
                    $$ = NULL;
                }
            | select_with_parens alias_clause
@@ -7089,7 +7099,8 @@ opt_float:    '(' Iconst ')'
                    if ($2 < 1)
                        ereport(ERROR,
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                                errmsg("precision for type float must be at least 1 bit")));
+                                errmsg("precision for type float must be at least 1 bit"),
+                                scanner_errposition(@2)));
                    else if ($2 <= 24)
                        $$ = SystemTypeName("float4");
                    else if ($2 <= 53)
@@ -7097,7 +7108,8 @@ opt_float:    '(' Iconst ')'
                    else
                        ereport(ERROR,
                                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-                                errmsg("precision for type float must be less than 54 bits")));
+                                errmsg("precision for type float must be less than 54 bits"),
+                                scanner_errposition(@2)));
                }
            | /*EMPTY*/
                {
@@ -7734,7 +7746,8 @@ a_expr:       c_expr                                  { $$ = $1; }
                     */
                    ereport(ERROR,
                            (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                            errmsg("UNIQUE predicate is not yet implemented")));
+                            errmsg("UNIQUE predicate is not yet implemented"),
+                            scanner_errposition(@1)));
                }
            | a_expr IS DOCUMENT_P                  %prec IS
                {
@@ -8874,6 +8887,7 @@ qualified_name:
                    $$->catalogname = NULL;
                    $$->schemaname = NULL;
                    $$->relname = $1;
+                   $$->location = @1;
                }
            | relation_name indirection
                {
@@ -8895,9 +8909,11 @@ qualified_name:
                            ereport(ERROR,
                                    (errcode(ERRCODE_SYNTAX_ERROR),
                                     errmsg("improper qualified name (too many dotted names): %s",
-                                           NameListToString(lcons(makeString($1), $2)))));
+                                           NameListToString(lcons(makeString($1), $2))),
+                                    scanner_errposition(@1)));
                            break;
                    }
+                   $$->location = @1;
                }
        ;
 
@@ -9494,7 +9510,8 @@ SpecialRuleRelation:
                    else
                        ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("OLD used in query that is not in a rule")));
+                                errmsg("OLD used in query that is not in a rule"),
+                                scanner_errposition(@1)));
                }
            | NEW
                {
@@ -9503,7 +9520,8 @@ SpecialRuleRelation:
                    else
                        ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("NEW used in query that is not in a rule")));
+                                errmsg("NEW used in query that is not in a rule"),
+                                scanner_errposition(@1)));
                }
        ;
 
@@ -9689,13 +9707,15 @@ makeOverlaps(List *largs, List *rargs, int location)
    else if (list_length(largs) != 2)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
-                errmsg("wrong number of parameters on left side of OVERLAPS expression")));
+                errmsg("wrong number of parameters on left side of OVERLAPS expression"),
+                scanner_errposition(location)));
    if (list_length(rargs) == 1)
        rargs = lappend(rargs, rargs);
    else if (list_length(rargs) != 2)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
-                errmsg("wrong number of parameters on right side of OVERLAPS expression")));
+                errmsg("wrong number of parameters on right side of OVERLAPS expression"),
+                scanner_errposition(location)));
    n->args = list_concat(largs, rargs);
    n->agg_star = FALSE;
    n->agg_distinct = FALSE;
@@ -9813,7 +9833,8 @@ insertSelectOptions(SelectStmt *stmt,
        if (stmt->sortClause)
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
-                    errmsg("multiple ORDER BY clauses not allowed")));
+                    errmsg("multiple ORDER BY clauses not allowed"),
+                    scanner_errposition(exprLocation((Node *) sortClause))));
        stmt->sortClause = sortClause;
    }
    /* We can handle multiple locking clauses, though */
@@ -9823,7 +9844,8 @@ insertSelectOptions(SelectStmt *stmt,
        if (stmt->limitOffset)
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
-                    errmsg("multiple OFFSET clauses not allowed")));
+                    errmsg("multiple OFFSET clauses not allowed"),
+                    scanner_errposition(exprLocation(limitOffset))));
        stmt->limitOffset = limitOffset;
    }
    if (limitCount)
@@ -9831,7 +9853,8 @@ insertSelectOptions(SelectStmt *stmt,
        if (stmt->limitCount)
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
-                    errmsg("multiple LIMIT clauses not allowed")));
+                    errmsg("multiple LIMIT clauses not allowed"),
+                    scanner_errposition(exprLocation(limitCount))));
        stmt->limitCount = limitCount;
    }
 }
index 215557396f911dd441cc4f4cddf0dbd4869de5aa..d85f64c7abc5dc0b4e32d846a5878f18c15a81aa 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.82 2008/08/28 23:09:47 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.83 2008/09/01 20:42:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -70,7 +70,9 @@ transformAggregateCall(ParseState *pstate, Aggref *agg)
        if (checkExprHasAggs((Node *) agg->args))
            ereport(ERROR,
                    (errcode(ERRCODE_GROUPING_ERROR),
-                    errmsg("aggregate function calls cannot be nested")));
+                    errmsg("aggregate function calls cannot be nested"),
+                    parser_errposition(pstate,
+                                       locate_agg_of_level((Node *) agg->args, 0))));
    }
 
    if (min_varlevel < 0)
@@ -117,11 +119,15 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
    if (checkExprHasAggs(qry->jointree->quals))
        ereport(ERROR,
                (errcode(ERRCODE_GROUPING_ERROR),
-                errmsg("aggregates not allowed in WHERE clause")));
+                errmsg("aggregates not allowed in WHERE clause"),
+                parser_errposition(pstate,
+                                   locate_agg_of_level(qry->jointree->quals, 0))));
    if (checkExprHasAggs((Node *) qry->jointree->fromlist))
        ereport(ERROR,
                (errcode(ERRCODE_GROUPING_ERROR),
-                errmsg("aggregates not allowed in JOIN conditions")));
+                errmsg("aggregates not allowed in JOIN conditions"),
+                parser_errposition(pstate,
+                                   locate_agg_of_level((Node *) qry->jointree->fromlist, 0))));
 
    /*
     * No aggregates allowed in GROUP BY clauses, either.
@@ -140,7 +146,9 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
        if (checkExprHasAggs(expr))
            ereport(ERROR,
                    (errcode(ERRCODE_GROUPING_ERROR),
-                    errmsg("aggregates not allowed in GROUP BY clause")));
+                    errmsg("aggregates not allowed in GROUP BY clause"),
+                    parser_errposition(pstate,
+                                       locate_agg_of_level(expr, 0))));
        groupClauses = lcons(expr, groupClauses);
    }
 
@@ -327,13 +335,14 @@ check_ungrouped_columns_walker(Node *node,
            ereport(ERROR,
                    (errcode(ERRCODE_GROUPING_ERROR),
                     errmsg("column \"%s.%s\" must appear in the GROUP BY clause or be used in an aggregate function",
-                           rte->eref->aliasname, attname)));
+                           rte->eref->aliasname, attname),
+                    parser_errposition(context->pstate, var->location)));
        else
            ereport(ERROR,
                    (errcode(ERRCODE_GROUPING_ERROR),
                     errmsg("subquery uses ungrouped column \"%s.%s\" from outer query",
-                           rte->eref->aliasname, attname)));
-
+                           rte->eref->aliasname, attname),
+                    parser_errposition(context->pstate, var->location)));
    }
 
    if (IsA(node, Query))
index 5285f0ba3d9f2fdbda320ae1b67d17fcc9ae5133..2f547f29be66ed2662af11a67fb51d093add3d53 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.178 2008/08/30 01:39:14 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.179 2008/09/01 20:42:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -66,12 +66,13 @@ static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype,
                   Var *l_colvar, Var *r_colvar);
 static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node,
                    List **tlist, int clause);
+static int get_matching_location(int sortgroupref,
+                                 List *sortgrouprefs, List *exprs);
 static List *addTargetToSortList(ParseState *pstate, TargetEntry *tle,
-                   List *sortlist, List *targetlist,
-                   SortByDir sortby_dir, SortByNulls sortby_nulls,
-                   List *sortby_opname, bool resolveUnknown);
+                   List *sortlist, List *targetlist, SortBy *sortby,
+                   bool resolveUnknown);
 static List *addTargetToGroupList(ParseState *pstate, TargetEntry *tle,
-                    List *grouplist, List *targetlist,
+                    List *grouplist, List *targetlist, int location,
                     bool resolveUnknown);
 
 
@@ -163,7 +164,8 @@ setTargetTable(ParseState *pstate, RangeVar *relation,
     * free_parsestate() will eventually do the corresponding heap_close(),
     * but *not* release the lock.
     */
-   pstate->p_target_relation = heap_openrv(relation, RowExclusiveLock);
+   pstate->p_target_relation = parserOpenTable(pstate, relation,
+                                               RowExclusiveLock);
 
    /*
     * Now build an RTE.
@@ -390,7 +392,9 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j,
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
         errmsg("JOIN/ON clause refers to \"%s\", which is not part of JOIN",
-               rt_fetch(varno, pstate->p_rtable)->eref->aliasname)));
+               rt_fetch(varno, pstate->p_rtable)->eref->aliasname),
+                parser_errposition(pstate,
+                                   locate_var_of_relation(result, varno, 0))));
    }
    bms_free(clause_varnos);
 
@@ -431,12 +435,11 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
    /*
     * We require user to supply an alias for a subselect, per SQL92. To relax
     * this, we'd have to be prepared to gin up a unique alias for an
-    * unlabeled subselect.
+    * unlabeled subselect.  (This is just elog, not ereport, because the
+    * grammar should have enforced it already.)
     */
    if (r->alias == NULL)
-       ereport(ERROR,
-               (errcode(ERRCODE_SYNTAX_ERROR),
-                errmsg("subquery in FROM must have an alias")));
+       elog(ERROR, "subquery in FROM must have an alias");
 
    /*
     * Analyze and transform the subquery.
@@ -447,13 +450,16 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
     * Check that we got something reasonable.  Many of these conditions are
     * impossible given restrictions of the grammar, but check 'em anyway.
     */
-   if (query->commandType != CMD_SELECT ||
+   if (!IsA(query, Query) ||
+       query->commandType != CMD_SELECT ||
        query->utilityStmt != NULL)
-       elog(ERROR, "expected SELECT query from subquery in FROM");
-   if (query->intoClause != NULL)
+       elog(ERROR, "unexpected non-SELECT command in subquery in FROM");
+   if (query->intoClause)
        ereport(ERROR,
                (errcode(ERRCODE_SYNTAX_ERROR),
-                errmsg("subquery in FROM cannot have SELECT INTO")));
+                errmsg("subquery in FROM cannot have SELECT INTO"),
+                parser_errposition(pstate,
+                                   exprLocation((Node *) query->intoClause))));
 
    /*
     * The subquery cannot make use of any variables from FROM items created
@@ -473,7 +479,9 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
        if (contain_vars_of_level((Node *) query, 1))
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
-                    errmsg("subquery in FROM cannot refer to other relations of same query level")));
+                    errmsg("subquery in FROM cannot refer to other relations of same query level"),
+                    parser_errposition(pstate,
+                                       locate_var_of_level((Node *) query, 1))));
    }
 
    /*
@@ -522,7 +530,9 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
        if (contain_vars_of_level(funcexpr, 0))
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
-                    errmsg("function expression in FROM cannot refer to other relations of same query level")));
+                    errmsg("function expression in FROM cannot refer to other relations of same query level"),
+                    parser_errposition(pstate,
+                                       locate_var_of_level(funcexpr, 0))));
    }
 
    /*
@@ -534,7 +544,9 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r)
        if (checkExprHasAggs(funcexpr))
            ereport(ERROR,
                    (errcode(ERRCODE_GROUPING_ERROR),
-                    errmsg("cannot use aggregate function in function expression in FROM")));
+                    errmsg("cannot use aggregate function in function expression in FROM"),
+                    parser_errposition(pstate,
+                                       locate_agg_of_level(funcexpr, 0))));
    }
 
    /*
@@ -709,9 +721,9 @@ transformFromClauseItem(ParseState *pstate, Node *n,
         *
         * Note: expandRTE returns new lists, safe for me to modify
         */
-       expandRTE(l_rte, l_rtindex, 0, false,
+       expandRTE(l_rte, l_rtindex, 0, -1, false,
                  &l_colnames, &l_colvars);
-       expandRTE(r_rte, r_rtindex, 0, false,
+       expandRTE(r_rte, r_rtindex, 0, -1, false,
                  &r_colnames, &r_colvars);
 
        /*
@@ -1109,7 +1121,9 @@ transformLimitClause(ParseState *pstate, Node *clause,
                (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
        /* translator: %s is name of a SQL construct, eg LIMIT */
                 errmsg("argument of %s must not contain variables",
-                       constructName)));
+                       constructName),
+                parser_errposition(pstate,
+                                   locate_var_of_level(qual, 0))));
    }
    if (checkExprHasAggs(qual))
    {
@@ -1117,7 +1131,9 @@ transformLimitClause(ParseState *pstate, Node *clause,
                (errcode(ERRCODE_GROUPING_ERROR),
        /* translator: %s is name of a SQL construct, eg LIMIT */
                 errmsg("argument of %s must not contain aggregates",
-                       constructName)));
+                       constructName),
+                parser_errposition(pstate,
+                                   locate_agg_of_level(qual, 0))));
    }
 
    return qual;
@@ -1365,6 +1381,7 @@ transformGroupClause(ParseState *pstate, List *grouplist,
        if (!found)
            result = addTargetToGroupList(pstate, tle,
                                          result, *targetlist,
+                                         exprLocation(gexpr),
                                          true);
    }
 
@@ -1396,10 +1413,7 @@ transformSortClause(ParseState *pstate,
                                  targetlist, ORDER_CLAUSE);
 
        sortlist = addTargetToSortList(pstate, tle,
-                                      sortlist, *targetlist,
-                                      sortby->sortby_dir,
-                                      sortby->sortby_nulls,
-                                      sortby->useOp,
+                                      sortlist, *targetlist, sortby,
                                       resolveUnknown);
    }
 
@@ -1450,7 +1464,9 @@ transformDistinctClause(ParseState *pstate,
        if (tle->resjunk)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
-                    errmsg("for SELECT DISTINCT, ORDER BY expressions must appear in select list")));
+                    errmsg("for SELECT DISTINCT, ORDER BY expressions must appear in select list"),
+                    parser_errposition(pstate,
+                                       exprLocation((Node *) tle->expr))));
        result = lappend(result, copyObject(scl));
    }
 
@@ -1466,6 +1482,7 @@ transformDistinctClause(ParseState *pstate,
            continue;           /* ignore junk */
        result = addTargetToGroupList(pstate, tle,
                                      result, *targetlist,
+                                     exprLocation((Node *) tle->expr),
                                      true);
    }
 
@@ -1490,28 +1507,29 @@ transformDistinctOnClause(ParseState *pstate, List *distinctlist,
                          List **targetlist, List *sortClause)
 {
    List       *result = NIL;
-   ListCell   *slitem;
-   ListCell   *dlitem;
-   Bitmapset  *refnos = NULL;
-   int         sortgroupref;
+   List       *sortgrouprefs = NIL;
    bool        skipped_sortitem;
+   ListCell   *lc;
+   ListCell   *lc2;
 
    /*
     * Add all the DISTINCT ON expressions to the tlist (if not already
     * present, they are added as resjunk items).  Assign sortgroupref
-    * numbers to them, and form a bitmapset of these numbers.  (A
-    * bitmapset is convenient here because we don't care about order
-    * and we can discard duplicates.)
+    * numbers to them, and make a list of these numbers.  (NB: we rely
+    * below on the sortgrouprefs list being one-for-one with the original
+    * distinctlist.  Also notice that we could have duplicate DISTINCT ON
+    * expressions and hence duplicate entries in sortgrouprefs.)
     */
-   foreach(dlitem, distinctlist)
+   foreach(lc, distinctlist)
    {
-       Node       *dexpr = (Node *) lfirst(dlitem);
+       Node       *dexpr = (Node *) lfirst(lc);
+       int         sortgroupref;
        TargetEntry *tle;
 
        tle = findTargetlistEntry(pstate, dexpr,
                                  targetlist, DISTINCT_ON_CLAUSE);
        sortgroupref = assignSortGroupRef(tle, *targetlist);
-       refnos = bms_add_member(refnos, sortgroupref);
+       sortgrouprefs = lappend_int(sortgrouprefs, sortgroupref);
    }
 
    /*
@@ -1523,16 +1541,20 @@ transformDistinctOnClause(ParseState *pstate, List *distinctlist,
     * skipped an ORDER BY item that wasn't in DISTINCT ON.
     */
    skipped_sortitem = false;
-   foreach(slitem, sortClause)
+   foreach(lc, sortClause)
    {
-       SortGroupClause *scl = (SortGroupClause *) lfirst(slitem);
+       SortGroupClause *scl = (SortGroupClause *) lfirst(lc);
 
-       if (bms_is_member(scl->tleSortGroupRef, refnos))
+       if (list_member_int(sortgrouprefs, scl->tleSortGroupRef))
        {
            if (skipped_sortitem)
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
-                        errmsg("SELECT DISTINCT ON expressions must match initial ORDER BY expressions")));
+                        errmsg("SELECT DISTINCT ON expressions must match initial ORDER BY expressions"),
+                        parser_errposition(pstate,
+                                           get_matching_location(scl->tleSortGroupRef,
+                                                                 sortgrouprefs,
+                                                                 distinctlist))));
            else
                result = lappend(result, copyObject(scl));
        }
@@ -1549,8 +1571,10 @@ transformDistinctOnClause(ParseState *pstate, List *distinctlist,
     * better to throw an error or warning here.  But historically we've
     * allowed it, so keep doing so.)
     */
-   while ((sortgroupref = bms_first_member(refnos)) >= 0)
+   forboth(lc, distinctlist, lc2, sortgrouprefs)
    {
+       Node       *dexpr = (Node *) lfirst(lc);
+       int         sortgroupref = lfirst_int(lc2);
        TargetEntry *tle = get_sortgroupref_tle(sortgroupref, *targetlist);
 
        if (targetIsInSortList(tle, InvalidOid, result))
@@ -1558,15 +1582,44 @@ transformDistinctOnClause(ParseState *pstate, List *distinctlist,
        if (skipped_sortitem)
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
-                    errmsg("SELECT DISTINCT ON expressions must match initial ORDER BY expressions")));
+                    errmsg("SELECT DISTINCT ON expressions must match initial ORDER BY expressions"),
+                    parser_errposition(pstate, exprLocation(dexpr))));
        result = addTargetToGroupList(pstate, tle,
                                      result, *targetlist,
+                                     exprLocation(dexpr),
                                      true);
    }
 
    return result;
 }
 
+/*
+ * get_matching_location
+ *     Get the exprLocation of the exprs member corresponding to the
+ *     (first) member of sortgrouprefs that equals sortgroupref.
+ *
+ * This is used so that we can point at a troublesome DISTINCT ON entry.
+ * (Note that we need to use the original untransformed DISTINCT ON list
+ * item, as whatever TLE it corresponds to will very possibly have a
+ * parse location pointing to some matching entry in the SELECT list
+ * or ORDER BY list.)
+ */
+static int
+get_matching_location(int sortgroupref, List *sortgrouprefs, List *exprs)
+{
+   ListCell   *lcs;
+   ListCell   *lce;
+
+   forboth(lcs, sortgrouprefs, lce, exprs)
+   {
+       if (lfirst_int(lcs) == sortgroupref)
+           return exprLocation((Node *) lfirst(lce));
+   }
+   /* if no match, caller blew it */
+   elog(ERROR, "get_matching_location: no matching sortgroupref");
+   return -1;                  /* keep compiler quiet */
+}
+
 /*
  * addTargetToSortList
  *     If the given targetlist entry isn't already in the SortGroupClause
@@ -1582,14 +1635,15 @@ transformDistinctOnClause(ParseState *pstate, List *distinctlist,
  */
 static List *
 addTargetToSortList(ParseState *pstate, TargetEntry *tle,
-                   List *sortlist, List *targetlist,
-                   SortByDir sortby_dir, SortByNulls sortby_nulls,
-                   List *sortby_opname, bool resolveUnknown)
+                   List *sortlist, List *targetlist, SortBy *sortby,
+                   bool resolveUnknown)
 {
    Oid         restype = exprType((Node *) tle->expr);
    Oid         sortop;
    Oid         eqop;
    bool        reverse;
+   int         location;
+   ParseCallbackState pcbstate;
 
    /* if tlist item is an UNKNOWN literal, change it to TEXT */
    if (restype == UNKNOWNOID && resolveUnknown)
@@ -1602,8 +1656,21 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
        restype = TEXTOID;
    }
 
+   /*
+    * Rather than clutter the API of get_sort_group_operators and the other
+    * functions we're about to use, make use of error context callback to
+    * mark any error reports with a parse position.  We point to the operator
+    * location if present, else to the expression being sorted.  (NB: use
+    * the original untransformed expression here; the TLE entry might well
+    * point at a duplicate expression in the regular SELECT list.)
+    */
+   location = sortby->location;
+   if (location < 0)
+       location = exprLocation(sortby->node);
+   setup_parser_errposition_callback(&pcbstate, pstate, location);
+
    /* determine the sortop, eqop, and directionality */
-   switch (sortby_dir)
+   switch (sortby->sortby_dir)
    {
        case SORTBY_DEFAULT:
        case SORTBY_ASC:
@@ -1619,8 +1686,8 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
            reverse = true;
            break;
        case SORTBY_USING:
-           Assert(sortby_opname != NIL);
-           sortop = compatible_oper_opid(sortby_opname,
+           Assert(sortby->useOp != NIL);
+           sortop = compatible_oper_opid(sortby->useOp,
                                          restype,
                                          restype,
                                          false);
@@ -1635,17 +1702,19 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
                ereport(ERROR,
                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                       errmsg("operator %s is not a valid ordering operator",
-                             strVal(llast(sortby_opname))),
+                             strVal(llast(sortby->useOp))),
                         errhint("Ordering operators must be \"<\" or \">\" members of btree operator families.")));
            break;
        default:
-           elog(ERROR, "unrecognized sortby_dir: %d", sortby_dir);
+           elog(ERROR, "unrecognized sortby_dir: %d", sortby->sortby_dir);
            sortop = InvalidOid;    /* keep compiler quiet */
            eqop = InvalidOid;
            reverse = false;
            break;
    }
 
+   cancel_parser_errposition_callback(&pcbstate);
+
    /* avoid making duplicate sortlist entries */
    if (!targetIsInSortList(tle, sortop, sortlist))
    {
@@ -1656,7 +1725,7 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
        sortcl->eqop = eqop;
        sortcl->sortop = sortop;
 
-       switch (sortby_nulls)
+       switch (sortby->sortby_nulls)
        {
            case SORTBY_NULLS_DEFAULT:
                /* NULLS FIRST is default for DESC; other way for ASC */
@@ -1669,7 +1738,8 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
                sortcl->nulls_first = false;
                break;
            default:
-               elog(ERROR, "unrecognized sortby_nulls: %d", sortby_nulls);
+               elog(ERROR, "unrecognized sortby_nulls: %d",
+                    sortby->sortby_nulls);
                break;
        }
 
@@ -1690,6 +1760,11 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
  * the TLE is considered "already in the list" if it appears there with any
  * sorting semantics.
  *
+ * location is the parse location to be fingered in event of trouble.  Note
+ * that we can't rely on exprLocation(tle->expr), because that might point
+ * to a SELECT item that matches the GROUP BY item; it'd be pretty confusing
+ * to report such a location.
+ *
  * If resolveUnknown is TRUE, convert TLEs of type UNKNOWN to TEXT.  If not,
  * do nothing (which implies the search for an equality operator will fail).
  * pstate should be provided if resolveUnknown is TRUE, but can be NULL
@@ -1699,7 +1774,7 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
  */
 static List *
 addTargetToGroupList(ParseState *pstate, TargetEntry *tle,
-                    List *grouplist, List *targetlist,
+                    List *grouplist, List *targetlist, int location,
                     bool resolveUnknown)
 {
    Oid         restype = exprType((Node *) tle->expr);
@@ -1721,12 +1796,17 @@ addTargetToGroupList(ParseState *pstate, TargetEntry *tle,
    if (!targetIsInSortList(tle, InvalidOid, grouplist))
    {
        SortGroupClause *grpcl = makeNode(SortGroupClause);
+       ParseCallbackState pcbstate;
+
+       setup_parser_errposition_callback(&pcbstate, pstate, location);
 
        /* determine the eqop and optional sortop */
        get_sort_group_operators(restype,
                                 false, true, false,
                                 &sortop, &eqop, NULL);
 
+       cancel_parser_errposition_callback(&pcbstate);
+
        grpcl->tleSortGroupRef = assignSortGroupRef(tle, targetlist);
        grpcl->eqop = eqop;
        grpcl->sortop = sortop;
index cd9b7b0cfbed03ec74f2cf295e4a7113627d7f72..efe45974c35e9b03ec6c990df9bb2ad09cc21577 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.165 2008/08/28 23:09:47 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.166 2008/09/01 20:42:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -180,6 +180,7 @@ coerce_type(ParseState *pstate, Node *node,
        Oid         baseTypeId;
        int32       baseTypeMod;
        Type        targetType;
+       ParseCallbackState pcbstate;
 
        /*
         * If the target type is a domain, we want to call its base type's
@@ -207,6 +208,12 @@ coerce_type(ParseState *pstate, Node *node,
        else
            newcon->location = location;
 
+       /*
+        * Set up to point at the constant's text if the input routine
+        * throws an error.
+        */
+       setup_parser_errposition_callback(&pcbstate, pstate, con->location);
+
        /*
         * We pass typmod -1 to the input routine, primarily because existing
         * input routines follow implicit-coercion semantics for length
@@ -223,6 +230,8 @@ coerce_type(ParseState *pstate, Node *node,
        else
            newcon->constvalue = stringTypeDatum(targetType, NULL, -1);
 
+       cancel_parser_errposition_callback(&pcbstate);
+
        result = (Node *) newcon;
 
        /* If target is a domain, apply constraints. */
@@ -257,7 +266,8 @@ coerce_type(ParseState *pstate, Node *node,
            paramno > toppstate->p_numparams)
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_PARAMETER),
-                    errmsg("there is no parameter $%d", paramno)));
+                    errmsg("there is no parameter $%d", paramno),
+                    parser_errposition(pstate, param->location)));
 
        if (toppstate->p_paramtypes[paramno - 1] == UNKNOWNOID)
        {
@@ -277,7 +287,8 @@ coerce_type(ParseState *pstate, Node *node,
                            paramno),
                     errdetail("%s versus %s",
                        format_type_be(toppstate->p_paramtypes[paramno - 1]),
-                              format_type_be(targetTypeId))));
+                              format_type_be(targetTypeId)),
+                    parser_errposition(pstate, param->location)));
        }
 
        param->paramtype = targetTypeId;
@@ -819,10 +830,11 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
    {
        int         rtindex = ((Var *) node)->varno;
        int         sublevels_up = ((Var *) node)->varlevelsup;
+       int         vlocation = ((Var *) node)->location;
        RangeTblEntry *rte;
 
        rte = GetRTEByRangeTablePosn(pstate, rtindex, sublevels_up);
-       expandRTE(rte, rtindex, sublevels_up, false,
+       expandRTE(rte, rtindex, sublevels_up, vlocation, false,
                  NULL, &args);
    }
    else
index 8496e7291c1768861450b06c317a11c86fb72936..1091d87473ddb444d1dc6f5b66d32e47dc8aef36 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.233 2008/08/30 01:39:14 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.234 2008/09/01 20:42:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -122,7 +122,7 @@ transformExpr(ParseState *pstate, Node *expr)
                A_Const    *con = (A_Const *) expr;
                Value      *val = &con->val;
 
-               result = (Node *) make_const(val, con->location);
+               result = (Node *) make_const(pstate, val, con->location);
                break;
            }
 
@@ -454,6 +454,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
                     * "rel.*".
                     */
                    if (refnameRangeTblEntry(pstate, NULL, name1,
+                                            cref->location,
                                             &levels_up) != NULL)
                        node = transformWholeRowRef(pstate, NULL, name1,
                                                    cref->location);
@@ -621,7 +622,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
  * return a pointer to it.
  */
 static Oid *
-find_param_type(ParseState *pstate, int paramno)
+find_param_type(ParseState *pstate, int paramno, int location)
 {
    Oid        *result;
 
@@ -635,14 +636,15 @@ find_param_type(ParseState *pstate, int paramno)
    if (paramno <= 0)           /* probably can't happen? */
        ereport(ERROR,
                (errcode(ERRCODE_UNDEFINED_PARAMETER),
-                errmsg("there is no parameter $%d", paramno)));
+                errmsg("there is no parameter $%d", paramno),
+                parser_errposition(pstate, location)));
    if (paramno > pstate->p_numparams)
    {
        if (!pstate->p_variableparams)
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_PARAMETER),
-                    errmsg("there is no parameter $%d",
-                           paramno)));
+                    errmsg("there is no parameter $%d", paramno),
+                    parser_errposition(pstate, location)));
        /* Okay to enlarge param array */
        if (pstate->p_paramtypes)
            pstate->p_paramtypes = (Oid *) repalloc(pstate->p_paramtypes,
@@ -672,7 +674,7 @@ static Node *
 transformParamRef(ParseState *pstate, ParamRef *pref)
 {
    int         paramno = pref->number;
-   Oid        *pptype = find_param_type(pstate, paramno);
+   Oid        *pptype = find_param_type(pstate, paramno, pref->location);
    Param      *param;
 
    param = makeNode(Param);
@@ -1235,10 +1237,22 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
 
    pstate->p_hasSubLinks = true;
    qtree = parse_sub_analyze(sublink->subselect, pstate);
-   if (qtree->commandType != CMD_SELECT ||
-       qtree->utilityStmt != NULL ||
-       qtree->intoClause != NULL)
-       elog(ERROR, "bad query in sub-select");
+
+   /*
+    * Check that we got something reasonable.  Many of these conditions are
+    * impossible given restrictions of the grammar, but check 'em anyway.
+    */
+   if (!IsA(qtree, Query) ||
+       qtree->commandType != CMD_SELECT ||
+       qtree->utilityStmt != NULL)
+       elog(ERROR, "unexpected non-SELECT command in SubLink");
+   if (qtree->intoClause)
+       ereport(ERROR,
+               (errcode(ERRCODE_SYNTAX_ERROR),
+                errmsg("subquery cannot have SELECT INTO"),
+                parser_errposition(pstate,
+                                   exprLocation((Node *) qtree->intoClause))));
+
    sublink->subselect = (Node *) qtree;
 
    if (sublink->subLinkType == EXISTS_SUBLINK)
@@ -1445,7 +1459,8 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
                ereport(ERROR,
                        (errcode(ERRCODE_UNDEFINED_OBJECT),
                         errmsg("could not find element type for data type %s",
-                               format_type_be(array_type))));
+                               format_type_be(array_type)),
+                        parser_errposition(pstate, a->location)));
        }
        else
        {
@@ -1455,7 +1470,8 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
                ereport(ERROR,
                        (errcode(ERRCODE_UNDEFINED_OBJECT),
                         errmsg("could not find array type for data type %s",
-                               format_type_be(element_type))));
+                               format_type_be(element_type)),
+                        parser_errposition(pstate, a->location)));
        }
        coerce_hard = false;
    }
@@ -1823,7 +1839,7 @@ transformCurrentOfExpr(ParseState *pstate, CurrentOfExpr *cexpr)
    /* If a parameter is used, it must be of type REFCURSOR */
    if (cexpr->cursor_name == NULL)
    {
-       Oid        *pptype = find_param_type(pstate, cexpr->cursor_param);
+       Oid        *pptype = find_param_type(pstate, cexpr->cursor_param, -1);
 
        if (pstate->p_variableparams && *pptype == UNKNOWNOID)
        {
@@ -1866,12 +1882,12 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
 
    /* Look up the referenced RTE, creating it if needed */
 
-   rte = refnameRangeTblEntry(pstate, schemaname, relname,
+   rte = refnameRangeTblEntry(pstate, schemaname, relname, location,
                               &sublevels_up);
 
    if (rte == NULL)
-       rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname),
-                            location);
+       rte = addImplicitRTE(pstate,
+                            makeRangeVar(schemaname, relname, location));
 
    vnum = RTERangeTablePosn(pstate, rte, &sublevels_up);
 
index 31317800c1e8f29438b61d15fe8be988fe73ec73..bbbc5fe7a94d7deedcd31ae03fb6358e9c4045d4 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.206 2008/08/28 23:09:47 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.207 2008/09/01 20:42:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -270,7 +270,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
            ereport(ERROR,
                    (errcode(ERRCODE_UNDEFINED_OBJECT),
                     errmsg("could not find array type for data type %s",
-                           format_type_be(newa->element_typeid))));
+                           format_type_be(newa->element_typeid)),
+                    parser_errposition(pstate, exprLocation((Node *) vargs))));
        newa->multidims = false;
        newa->location = exprLocation((Node *) vargs);
 
index 1760e492854bbdee3f67d6948ad7eac153ae3372..532dbe319dde282e22db0a49b71093c46bae0842 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.102 2008/08/28 23:09:47 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.103 2008/09/01 20:42:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,6 +29,9 @@
 #include "utils/varbit.h"
 
 
+static void pcb_error_callback(void *arg);
+
+
 /*
  * make_parsestate
  *     Allocate and initialize a new ParseState.
@@ -112,6 +115,62 @@ parser_errposition(ParseState *pstate, int location)
 }
 
 
+/*
+ * setup_parser_errposition_callback
+ *     Arrange for non-parser errors to report an error position
+ *
+ * Sometimes the parser calls functions that aren't part of the parser
+ * subsystem and can't reasonably be passed a ParseState; yet we would
+ * like any errors thrown in those functions to be tagged with a parse
+ * error location.  Use this function to set up an error context stack
+ * entry that will accomplish that.  Usage pattern:
+ *
+ *     declare a local variable "ParseCallbackState pcbstate"
+ *     ...
+ *     setup_parser_errposition_callback(&pcbstate, pstate, location);
+ *     call function that might throw error;
+ *     cancel_parser_errposition_callback(&pcbstate);
+ */
+void
+setup_parser_errposition_callback(ParseCallbackState *pcbstate,
+                                 ParseState *pstate, int location)
+{
+   /* Setup error traceback support for ereport() */
+   pcbstate->pstate = pstate;
+   pcbstate->location = location;
+   pcbstate->errcontext.callback = pcb_error_callback;
+   pcbstate->errcontext.arg = (void *) pcbstate;
+   pcbstate->errcontext.previous = error_context_stack;
+   error_context_stack = &pcbstate->errcontext;
+}
+
+/*
+ * Cancel a previously-set-up errposition callback.
+ */
+void
+cancel_parser_errposition_callback(ParseCallbackState *pcbstate)
+{
+   /* Pop the error context stack */
+   error_context_stack = pcbstate->errcontext.previous;
+}
+
+/*
+ * Error context callback for inserting parser error location.
+ *
+ * Note that this will be called for *any* error occurring while the
+ * callback is installed.  We avoid inserting an irrelevant error location
+ * if the error is a query cancel --- are there any other important cases?
+ */
+static void
+pcb_error_callback(void *arg)
+{
+   ParseCallbackState *pcbstate = (ParseCallbackState *) arg;
+
+   if (geterrcode() != ERRCODE_QUERY_CANCELED)
+       (void) parser_errposition(pcbstate->pstate, pcbstate->location);
+}
+
+
 /*
  * make_var
  *     Build a Var node for an attribute identified by RTE and attrno
@@ -344,14 +403,15 @@ transformArraySubscripts(ParseState *pstate,
  * too many examples that fail if we try.
  */
 Const *
-make_const(Value *value, int location)
+make_const(ParseState *pstate, Value *value, int location)
 {
+   Const      *con;
    Datum       val;
    int64       val64;
    Oid         typeid;
    int         typelen;
    bool        typebyval;
-   Const      *con;
+   ParseCallbackState pcbstate;
 
    switch (nodeTag(value))
    {
@@ -392,10 +452,13 @@ make_const(Value *value, int location)
            }
            else
            {
+               /* arrange to report location if numeric_in() fails */
+               setup_parser_errposition_callback(&pcbstate, pstate, location);
                val = DirectFunctionCall3(numeric_in,
                                          CStringGetDatum(strVal(value)),
                                          ObjectIdGetDatum(InvalidOid),
                                          Int32GetDatum(-1));
+               cancel_parser_errposition_callback(&pcbstate);
 
                typeid = NUMERICOID;
                typelen = -1;   /* variable len */
@@ -417,10 +480,13 @@ make_const(Value *value, int location)
            break;
 
        case T_BitString:
+           /* arrange to report location if bit_in() fails */
+           setup_parser_errposition_callback(&pcbstate, pstate, location);
            val = DirectFunctionCall3(bit_in,
                                      CStringGetDatum(strVal(value)),
                                      ObjectIdGetDatum(InvalidOid),
                                      Int32GetDatum(-1));
+           cancel_parser_errposition_callback(&pcbstate);
            typeid = BITOID;
            typelen = -1;
            typebyval = false;
index f7eb825f5d0cefee342cc3e2d52324556878dd9c..6accd96f0dad1165b1c80ae2578d817b54037b75 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.134 2008/08/28 23:09:48 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.135 2008/09/01 20:42:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 bool       add_missing_from;
 
 static RangeTblEntry *scanNameSpaceForRefname(ParseState *pstate,
-                       const char *refname);
-static RangeTblEntry *scanNameSpaceForRelid(ParseState *pstate, Oid relid);
+                       const char *refname, int location);
+static RangeTblEntry *scanNameSpaceForRelid(ParseState *pstate, Oid relid,
+                                           int location);
 static bool isLockedRel(ParseState *pstate, char *refname);
 static void expandRelation(Oid relid, Alias *eref,
               int rtindex, int sublevels_up,
-              bool include_dropped,
+              int location, bool include_dropped,
               List **colnames, List **colvars);
 static void expandTupleDesc(TupleDesc tupdesc, Alias *eref,
                int rtindex, int sublevels_up,
-               bool include_dropped,
+               int location, bool include_dropped,
                List **colnames, List **colvars);
 static int specialAttNum(const char *attname);
-static void warnAutoRange(ParseState *pstate, RangeVar *relation,
-             int location);
+static void warnAutoRange(ParseState *pstate, RangeVar *relation);
 
 
 /*
@@ -77,6 +77,7 @@ RangeTblEntry *
 refnameRangeTblEntry(ParseState *pstate,
                     const char *schemaname,
                     const char *refname,
+                    int location,
                     int *sublevels_up)
 {
    Oid         relId = InvalidOid;
@@ -99,9 +100,9 @@ refnameRangeTblEntry(ParseState *pstate,
        RangeTblEntry *result;
 
        if (OidIsValid(relId))
-           result = scanNameSpaceForRelid(pstate, relId);
+           result = scanNameSpaceForRelid(pstate, relId, location);
        else
-           result = scanNameSpaceForRefname(pstate, refname);
+           result = scanNameSpaceForRefname(pstate, refname, location);
 
        if (result)
            return result;
@@ -122,7 +123,7 @@ refnameRangeTblEntry(ParseState *pstate,
  * if no match.  Raise error if multiple matches.
  */
 static RangeTblEntry *
-scanNameSpaceForRefname(ParseState *pstate, const char *refname)
+scanNameSpaceForRefname(ParseState *pstate, const char *refname, int location)
 {
    RangeTblEntry *result = NULL;
    ListCell   *l;
@@ -137,7 +138,8 @@ scanNameSpaceForRefname(ParseState *pstate, const char *refname)
                ereport(ERROR,
                        (errcode(ERRCODE_AMBIGUOUS_ALIAS),
                         errmsg("table reference \"%s\" is ambiguous",
-                               refname)));
+                               refname),
+                        parser_errposition(pstate, location)));
            result = rte;
        }
    }
@@ -154,7 +156,7 @@ scanNameSpaceForRefname(ParseState *pstate, const char *refname)
  * acts the way it does.
  */
 static RangeTblEntry *
-scanNameSpaceForRelid(ParseState *pstate, Oid relid)
+scanNameSpaceForRelid(ParseState *pstate, Oid relid, int location)
 {
    RangeTblEntry *result = NULL;
    ListCell   *l;
@@ -172,7 +174,8 @@ scanNameSpaceForRelid(ParseState *pstate, Oid relid)
                ereport(ERROR,
                        (errcode(ERRCODE_AMBIGUOUS_ALIAS),
                         errmsg("table reference %u is ambiguous",
-                               relid)));
+                               relid),
+                        parser_errposition(pstate, location)));
            result = rte;
        }
    }
@@ -466,14 +469,15 @@ qualifiedNameToVar(ParseState *pstate,
    RangeTblEntry *rte;
    int         sublevels_up;
 
-   rte = refnameRangeTblEntry(pstate, schemaname, refname, &sublevels_up);
+   rte = refnameRangeTblEntry(pstate, schemaname, refname, location,
+                              &sublevels_up);
 
    if (rte == NULL)
    {
        if (!implicitRTEOK)
            return NULL;
-       rte = addImplicitRTE(pstate, makeRangeVar(schemaname, refname),
-                            location);
+       rte = addImplicitRTE(pstate,
+                            makeRangeVar(schemaname, refname, location));
    }
 
    return scanRTEForColumn(pstate, rte, colname, location);
@@ -607,6 +611,28 @@ buildScalarFunctionAlias(Node *funcexpr, char *funcname,
    eref->colnames = list_make1(makeString(eref->aliasname));
 }
 
+/*
+ * Open a table during parse analysis
+ *
+ * This is essentially just the same as heap_openrv(), except that it
+ * arranges to include the RangeVar's parse location in any resulting error.
+ *
+ * Note: properly, lockmode should be declared LOCKMODE not int, but that
+ * would require importing storage/lock.h into parse_relation.h.  Since
+ * LOCKMODE is typedef'd as int anyway, that seems like overkill.
+ */
+Relation
+parserOpenTable(ParseState *pstate, const RangeVar *relation, int lockmode)
+{
+   Relation    rel;
+   ParseCallbackState pcbstate;
+
+   setup_parser_errposition_callback(&pcbstate, pstate, relation->location);
+   rel = heap_openrv(relation, lockmode);
+   cancel_parser_errposition_callback(&pcbstate);
+   return rel;
+}
+
 /*
  * Add an entry for a relation to the pstate's range table (p_rtable).
  *
@@ -638,7 +664,7 @@ addRangeTableEntry(ParseState *pstate,
     * depending on whether we're doing SELECT FOR UPDATE/SHARE.
     */
    lockmode = isLockedRel(pstate, refname) ? RowShareLock : AccessShareLock;
-   rel = heap_openrv(relation, lockmode);
+   rel = parserOpenTable(pstate, relation, lockmode);
    rte->relid = RelationGetRelid(rel);
 
    /*
@@ -859,14 +885,16 @@ addRangeTableEntryForFunction(ParseState *pstate,
        if (functypclass != TYPEFUNC_RECORD)
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
-                    errmsg("a column definition list is only allowed for functions returning \"record\"")));
+                    errmsg("a column definition list is only allowed for functions returning \"record\""),
+                    parser_errposition(pstate, exprLocation(funcexpr))));
    }
    else
    {
        if (functypclass == TYPEFUNC_RECORD)
            ereport(ERROR,
                    (errcode(ERRCODE_SYNTAX_ERROR),
-                    errmsg("a column definition list is required for functions returning \"record\"")));
+                    errmsg("a column definition list is required for functions returning \"record\""),
+                    parser_errposition(pstate, exprLocation(funcexpr))));
    }
 
    if (functypclass == TYPEFUNC_COMPOSITE)
@@ -901,7 +929,8 @@ addRangeTableEntryForFunction(ParseState *pstate,
                ereport(ERROR,
                        (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                         errmsg("column \"%s\" cannot be declared SETOF",
-                               attrname)));
+                               attrname),
+                        parser_errposition(pstate, n->typename->location)));
            attrtype = typenameTypeId(pstate, n->typename, &attrtypmod);
            eref->colnames = lappend(eref->colnames, makeString(attrname));
            rte->funccoltypes = lappend_oid(rte->funccoltypes, attrtype);
@@ -912,7