]> granicus.if.org Git - postgresql/commitdiff
Improve parser so that we can show an error cursor position for errors
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 14 Mar 2006 22:48:25 +0000 (22:48 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 14 Mar 2006 22:48:25 +0000 (22:48 +0000)
during parse analysis, not only errors detected in the flex/bison stages.
This is per my earlier proposal.  This commit includes all the basic
infrastructure, but locations are only tracked and reported for errors
involving column references, function calls, and operators.  More could
be done later but this seems like a good set to start with.  I've also
moved the ReportSyntaxErrorPosition logic out of psql and into libpq,
which should make it available to more people --- even within psql this
is an improvement because warnings weren't handled by ReportSyntaxErrorPosition.

80 files changed:
contrib/earthdistance/expected/earthdistance.out
src/backend/access/common/tupdesc.c
src/backend/catalog/pg_aggregate.c
src/backend/catalog/pg_operator.c
src/backend/commands/aggregatecmds.c
src/backend/commands/comment.c
src/backend/commands/define.c
src/backend/commands/functioncmds.c
src/backend/commands/opclasscmds.c
src/backend/commands/operatorcmds.c
src/backend/commands/schemacmds.c
src/backend/commands/sequence.c
src/backend/commands/tablecmds.c
src/backend/commands/typecmds.c
src/backend/commands/view.c
src/backend/executor/spi.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/makefuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/plan/initsplan.c
src/backend/optimizer/util/clauses.c
src/backend/parser/analyze.c
src/backend/parser/gram.y
src/backend/parser/parse_clause.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_func.c
src/backend/parser/parse_node.c
src/backend/parser/parse_oper.c
src/backend/parser/parse_relation.c
src/backend/parser/parse_target.c
src/backend/parser/parse_type.c
src/backend/parser/scan.l
src/backend/tcop/postgres.c
src/backend/utils/adt/ruleutils.c
src/bin/psql/common.c
src/include/nodes/makefuncs.h
src/include/nodes/parsenodes.h
src/include/parser/analyze.h
src/include/parser/gramparse.h
src/include/parser/parse_func.h
src/include/parser/parse_node.h
src/include/parser/parse_oper.h
src/include/parser/parse_relation.h
src/include/parser/parse_type.h
src/include/tcop/tcopprot.h
src/interfaces/libpq/fe-connect.c
src/interfaces/libpq/fe-exec.c
src/interfaces/libpq/fe-protocol3.c
src/interfaces/libpq/libpq-int.h
src/pl/plperl/expected/plperl_elog.out
src/pl/plperl/plperl.c
src/pl/plpgsql/src/pl_comp.c
src/pl/plpython/plpython.c
src/pl/tcl/pltcl.c
src/test/regress/expected/alter_table.out
src/test/regress/expected/arrays.out
src/test/regress/expected/errors.out
src/test/regress/expected/geometry.out
src/test/regress/expected/geometry_1.out
src/test/regress/expected/geometry_2.out
src/test/regress/expected/horology.out
src/test/regress/expected/join.out
src/test/regress/expected/join_1.out
src/test/regress/expected/plpgsql.out
src/test/regress/expected/prepare.out
src/test/regress/expected/rowtypes.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/strings.out
src/test/regress/expected/time.out
src/test/regress/expected/timetz.out
src/test/regress/expected/transactions.out
src/test/regress/expected/union.out
src/test/regress/expected/update.out
src/test/regress/expected/without_oid.out
src/test/regress/output/constraints.source
src/test/regress/output/create_function_1.source

index d7ec06175d0722ad0bfc2fbfed79089227e41669..6857384154b07e70256c14d9011f0b0c88396799 100644 (file)
@@ -881,7 +881,9 @@ SELECT earth_box(ll_to_earth(90,180),
 --
 SELECT is_point(ll_to_earth(0,0));
 ERROR:  function is_point(earth) does not exist
-HINT:  No function matches the given name and argument types. You may need to add explicit typecasts.
+LINE 1: SELECT is_point(ll_to_earth(0,0));
+               ^
+HINT:  No function matches the given name and argument types. You may need to add explicit type casts.
 SELECT cube_dim(ll_to_earth(0,0)) <= 3;
  ?column? 
 ----------
@@ -897,7 +899,9 @@ SELECT abs(cube_distance(ll_to_earth(0,0), '(0)'::cube) / earth() - 1) <
 
 SELECT is_point(ll_to_earth(30,60));
 ERROR:  function is_point(earth) does not exist
-HINT:  No function matches the given name and argument types. You may need to add explicit typecasts.
+LINE 1: SELECT is_point(ll_to_earth(30,60));
+               ^
+HINT:  No function matches the given name and argument types. You may need to add explicit type casts.
 SELECT cube_dim(ll_to_earth(30,60)) <= 3;
  ?column? 
 ----------
@@ -913,7 +917,9 @@ SELECT abs(cube_distance(ll_to_earth(30,60), '(0)'::cube) / earth() - 1) <
 
 SELECT is_point(ll_to_earth(60,90));
 ERROR:  function is_point(earth) does not exist
-HINT:  No function matches the given name and argument types. You may need to add explicit typecasts.
+LINE 1: SELECT is_point(ll_to_earth(60,90));
+               ^
+HINT:  No function matches the given name and argument types. You may need to add explicit type casts.
 SELECT cube_dim(ll_to_earth(60,90)) <= 3;
  ?column? 
 ----------
@@ -929,7 +935,9 @@ SELECT abs(cube_distance(ll_to_earth(60,90), '(0)'::cube) / earth() - 1) <
 
 SELECT is_point(ll_to_earth(-30,-90));
 ERROR:  function is_point(earth) does not exist
-HINT:  No function matches the given name and argument types. You may need to add explicit typecasts.
+LINE 1: SELECT is_point(ll_to_earth(-30,-90));
+               ^
+HINT:  No function matches the given name and argument types. You may need to add explicit type casts.
 SELECT cube_dim(ll_to_earth(-30,-90)) <= 3;
  ?column? 
 ----------
index 4c40ef3c11926655974c405ce237bcd7f3a6aba6..8726797524b12aa25dbb3d193998d53d6356bc34 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.114 2006/03/05 15:58:20 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.115 2006/03/14 22:48:18 tgl Exp $
  *
  * NOTES
  *       some of the executor utility code such as "ExecTypeFromTL" should be
@@ -499,7 +499,7 @@ BuildDescForRelation(List *schema)
                                                        attname)));
 
                TupleDescInitEntry(desc, attnum, attname,
-                                                  typenameTypeId(entry->typename),
+                                                  typenameTypeId(NULL, entry->typename),
                                                   atttypmod, attdim);
 
                /* Fill in additional stuff not handled by TupleDescInitEntry */
index 054c531a9e74291a206f0b1f2fa06a150caf2bac..2f40eca1152c6192768ed0127c217de0f008679d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.78 2006/03/05 15:58:23 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.79 2006/03/14 22:48:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -171,9 +171,9 @@ AggregateCreate(const char *aggName,
 
        /* handle sortop, if supplied */
        if (aggsortopName)
-               sortop = LookupOperName(aggsortopName,
+               sortop = LookupOperName(NULL, aggsortopName,
                                                                aggBaseType, aggBaseType,
-                                                               false);
+                                                               false, -1);
 
        /*
         * Everything looks okay.  Try to create the pg_proc entry for the
index c9c19e4ec32913ff2597715def1d09d543606a67..c51c841800eade68c3de590fdb740eead86e97f1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/catalog/pg_operator.c,v 1.95 2006/03/05 15:58:23 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/catalog/pg_operator.c,v 1.96 2006/03/14 22:48:18 tgl Exp $
  *
  * NOTES
  *       these routines moved here from commands/define.c and somewhat cleaned up.
@@ -175,8 +175,9 @@ OperatorLookup(List *operatorName,
        Oid                     operatorObjectId;
        RegProcedure oprcode;
 
-       operatorObjectId = LookupOperName(operatorName, leftObjectId,
-                                                                         rightObjectId, true);
+       operatorObjectId = LookupOperName(NULL, operatorName,
+                                                                         leftObjectId, rightObjectId,
+                                                                         true, -1);
        if (!OidIsValid(operatorObjectId))
        {
                *defined = false;
index 99c7d531f91702385f0426969274938c19a8da41..3c0855238e25ae31597900385705d9ea45d0972d 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.32 2006/03/05 15:58:23 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.33 2006/03/14 22:48:18 tgl Exp $
  *
  * DESCRIPTION
  *       The "DefineFoo" routines take the parse tree and pick out the
@@ -129,9 +129,9 @@ DefineAggregate(List *names, List *parameters)
        if (pg_strcasecmp(TypeNameToString(baseType), "ANY") == 0)
                baseTypeId = ANYOID;
        else
-               baseTypeId = typenameTypeId(baseType);
+               baseTypeId = typenameTypeId(NULL, baseType);
 
-       transTypeId = typenameTypeId(transType);
+       transTypeId = typenameTypeId(NULL, transType);
        if (get_typtype(transTypeId) == 'p' &&
                transTypeId != ANYARRAYOID &&
                transTypeId != ANYELEMENTOID)
@@ -176,7 +176,7 @@ RemoveAggregate(RemoveAggrStmt *stmt)
         * that the aggregate is to apply to all basetypes (eg, COUNT).
         */
        if (aggType)
-               basetypeID = typenameTypeId(aggType);
+               basetypeID = typenameTypeId(NULL, aggType);
        else
                basetypeID = ANYOID;
 
@@ -231,7 +231,7 @@ RenameAggregate(List *name, TypeName *basetype, const char *newname)
         * COUNT).
         */
        if (basetype)
-               basetypeOid = typenameTypeId(basetype);
+               basetypeOid = typenameTypeId(NULL, basetype);
        else
                basetypeOid = ANYOID;
 
@@ -311,7 +311,7 @@ AlterAggregateOwner(List *name, TypeName *basetype, Oid newOwnerId)
         * COUNT).
         */
        if (basetype)
-               basetypeOid = typenameTypeId(basetype);
+               basetypeOid = typenameTypeId(NULL, basetype);
        else
                basetypeOid = ANYOID;
 
index 8f85dcb8d9429cddb85370f442d20dd35c3ed030..07d82785254094dbf11ecbd619ab2d28cc8066ec 100644 (file)
@@ -7,7 +7,7 @@
  * Copyright (c) 1996-2006, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.87 2006/03/05 15:58:23 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/comment.c,v 1.88 2006/03/14 22:48:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,6 +39,7 @@
 #include "commands/dbcommands.h"
 #include "commands/tablespace.h"
 #include "miscadmin.h"
+#include "nodes/makefuncs.h"
 #include "parser/parse_func.h"
 #include "parser/parse_oper.h"
 #include "parser/parse_type.h"
@@ -846,13 +847,11 @@ CommentType(List *typename, char *comment)
        Oid                     oid;
 
        /* XXX a bit of a crock; should accept TypeName in COMMENT syntax */
-       tname = makeNode(TypeName);
-       tname->names = typename;
-       tname->typmod = -1;
+       tname = makeTypeNameFromNameList(typename);
 
        /* Find the type's oid */
 
-       oid = typenameTypeId(tname);
+       oid = typenameTypeId(NULL, tname);
 
        /* Check object security */
 
@@ -881,7 +880,7 @@ CommentAggregate(List *aggregate, List *arguments, char *comment)
 
        /* First, attempt to determine the base aggregate oid */
        if (aggtype)
-               baseoid = typenameTypeId(aggtype);
+               baseoid = typenameTypeId(NULL, aggtype);
        else
                baseoid = ANYOID;
 
@@ -945,9 +944,11 @@ CommentOperator(List *opername, List *arguments, char *comment)
        Oid                     oid;
 
        /* Look up the operator */
-       oid = LookupOperNameTypeNames(opername, typenode1, typenode2, false);
+       oid = LookupOperNameTypeNames(NULL, opername,
+                                                                 typenode1, typenode2,
+                                                                 false, -1);
 
-       /* Valid user's ability to comment on this operator */
+       /* Check user's privilege to comment on this operator */
        if (!pg_oper_ownercheck(oid, GetUserId()))
                aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
                                           NameListToString(opername));
@@ -1352,19 +1353,8 @@ CommentCast(List *qualname, List *arguments, char *comment)
        targettype = (TypeName *) linitial(arguments);
        Assert(IsA(targettype, TypeName));
 
-       sourcetypeid = typenameTypeId(sourcetype);
-       if (!OidIsValid(sourcetypeid))
-               ereport(ERROR,
-                               (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                errmsg("source data type %s does not exist",
-                                               TypeNameToString(sourcetype))));
-
-       targettypeid = typenameTypeId(targettype);
-       if (!OidIsValid(targettypeid))
-               ereport(ERROR,
-                               (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                errmsg("target data type %s does not exist",
-                                               TypeNameToString(targettype))));
+       sourcetypeid = typenameTypeId(NULL, sourcetype);
+       targettypeid = typenameTypeId(NULL, targettype);
 
        tuple = SearchSysCache(CASTSOURCETARGET,
                                                   ObjectIdGetDatum(sourcetypeid),
index 15ee606c8de2e5817771e92d69a85ff470943387..98cded67cc45a4dd7cd3df3b371426748cc65459 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/define.c,v 1.94 2006/03/05 15:58:24 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/define.c,v 1.95 2006/03/14 22:48:18 tgl Exp $
  *
  * DESCRIPTION
  *       The "DefineFoo" routines take the parse tree and pick out the
@@ -37,6 +37,7 @@
 
 #include "catalog/namespace.h"
 #include "commands/defrem.h"
+#include "nodes/makefuncs.h"
 #include "parser/parse_type.h"
 #include "parser/scansup.h"
 #include "utils/int8.h"
@@ -219,14 +220,8 @@ defGetTypeName(DefElem *def)
                case T_TypeName:
                        return (TypeName *) def->arg;
                case T_String:
-                       {
-                               /* Allow quoted typename for backwards compatibility */
-                               TypeName   *n = makeNode(TypeName);
-
-                               n->names = list_make1(def->arg);
-                               n->typmod = -1;
-                               return n;
-                       }
+                       /* Allow quoted typename for backwards compatibility */
+                       return makeTypeNameFromNameList(list_make1(def->arg));
                default:
                        ereport(ERROR,
                                        (errcode(ERRCODE_SYNTAX_ERROR),
index 4a78db5200ae4e4f4409398fb51022f8df992ece..1da1cf66cb346bcfd9d2ee8e32611a4bb14dc21a 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.72 2006/03/05 15:58:24 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.73 2006/03/14 22:48:18 tgl Exp $
  *
  * DESCRIPTION
  *       These routines take the parse tree and pick out the
@@ -75,7 +75,7 @@ compute_return_type(TypeName *returnType, Oid languageOid,
 {
        Oid                     rettype;
 
-       rettype = LookupTypeName(returnType);
+       rettype = LookupTypeName(NULL, returnType);
 
        if (OidIsValid(rettype))
        {
@@ -174,7 +174,7 @@ examine_parameter_list(List *parameters, Oid languageOid,
                TypeName   *t = fp->argType;
                Oid                     toid;
 
-               toid = LookupTypeName(t);
+               toid = LookupTypeName(NULL, t);
                if (OidIsValid(toid))
                {
                        if (!get_typisdefined(toid))
@@ -1152,33 +1152,10 @@ CreateCast(CreateCastStmt *stmt)
        ObjectAddress myself,
                                referenced;
 
-       sourcetypeid = LookupTypeName(stmt->sourcetype);
-       if (!OidIsValid(sourcetypeid))
-               ereport(ERROR,
-                               (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                errmsg("source data type %s does not exist",
-                                               TypeNameToString(stmt->sourcetype))));
-
-       targettypeid = LookupTypeName(stmt->targettype);
-       if (!OidIsValid(targettypeid))
-               ereport(ERROR,
-                               (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                errmsg("target data type %s does not exist",
-                                               TypeNameToString(stmt->targettype))));
-
-       /* No shells, no pseudo-types allowed */
-       if (!get_typisdefined(sourcetypeid))
-               ereport(ERROR,
-                               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
-                                errmsg("source data type %s is only a shell",
-                                               TypeNameToString(stmt->sourcetype))));
-
-       if (!get_typisdefined(targettypeid))
-               ereport(ERROR,
-                               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
-                                errmsg("target data type %s is only a shell",
-                                               TypeNameToString(stmt->targettype))));
+       sourcetypeid = typenameTypeId(NULL, stmt->sourcetype);
+       targettypeid = typenameTypeId(NULL, stmt->targettype);
 
+       /* No pseudo-types allowed */
        if (get_typtype(sourcetypeid) == 'p')
                ereport(ERROR,
                                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
@@ -1400,19 +1377,8 @@ DropCast(DropCastStmt *stmt)
        HeapTuple       tuple;
        ObjectAddress object;
 
-       sourcetypeid = LookupTypeName(stmt->sourcetype);
-       if (!OidIsValid(sourcetypeid))
-               ereport(ERROR,
-                               (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                errmsg("source data type %s does not exist",
-                                               TypeNameToString(stmt->sourcetype))));
-
-       targettypeid = LookupTypeName(stmt->targettype);
-       if (!OidIsValid(targettypeid))
-               ereport(ERROR,
-                               (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                errmsg("target data type %s does not exist",
-                                               TypeNameToString(stmt->targettype))));
+       sourcetypeid = typenameTypeId(NULL, stmt->sourcetype);
+       targettypeid = typenameTypeId(NULL, stmt->targettype);
 
        tuple = SearchSysCache(CASTSOURCETARGET,
                                                   ObjectIdGetDatum(sourcetypeid),
index 7aa941262bf984a3bd5264907b71347dddaf9994..d66c403e515f4db35e3783745bf0da94588a72f9 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.42 2006/03/05 15:58:24 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.43 2006/03/14 22:48:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -144,7 +144,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
                                 errmsg("must be superuser to create an operator class")));
 
        /* Look up the datatype */
-       typeoid = typenameTypeId(stmt->datatype);
+       typeoid = typenameTypeId(NULL, stmt->datatype);
 
 #ifdef NOT_USED
        /* XXX this is unnecessary given the superuser check above */
@@ -185,16 +185,16 @@ DefineOpClass(CreateOpClassStmt *stmt)
                                        TypeName   *typeName1 = (TypeName *) linitial(item->args);
                                        TypeName   *typeName2 = (TypeName *) lsecond(item->args);
 
-                                       operOid = LookupOperNameTypeNames(item->name,
-                                                                                                         typeName1,
-                                                                                                         typeName2,
-                                                                                                         false);
+                                       operOid = LookupOperNameTypeNames(NULL, item->name,
+                                                                                                         typeName1, typeName2,
+                                                                                                         false, -1);
                                }
                                else
                                {
                                        /* Default to binary op on input datatype */
-                                       operOid = LookupOperName(item->name, typeoid, typeoid,
-                                                                                        false);
+                                       operOid = LookupOperName(NULL, item->name,
+                                                                                        typeoid, typeoid,
+                                                                                        false, -1);
                                }
 
 #ifdef NOT_USED
@@ -246,7 +246,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
                                        ereport(ERROR,
                                                        (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
                                                   errmsg("storage type specified more than once")));
-                               storageoid = typenameTypeId(item->storedtype);
+                               storageoid = typenameTypeId(NULL, item->storedtype);
 
 #ifdef NOT_USED
                                /* XXX this is unnecessary given the superuser check above */
index e835aa94c1bf020d8cea78f2ed09661148f3cc86..c40dbf9d8214c23f9317ea6a489fb271f7c36488 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.28 2006/03/05 15:58:24 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.29 2006/03/14 22:48:18 tgl Exp $
  *
  * DESCRIPTION
  *       The "DefineFoo" routines take the parse tree and pick out the
@@ -152,9 +152,9 @@ DefineOperator(List *names, List *parameters)
 
        /* Transform type names to type OIDs */
        if (typeName1)
-               typeId1 = typenameTypeId(typeName1);
+               typeId1 = typenameTypeId(NULL, typeName1);
        if (typeName2)
-               typeId2 = typenameTypeId(typeName2);
+               typeId2 = typenameTypeId(NULL, typeName2);
 
        /*
         * If any of the mergejoin support operators were given, then canMerge is
@@ -210,8 +210,9 @@ RemoveOperator(RemoveOperStmt *stmt)
        HeapTuple       tup;
        ObjectAddress object;
 
-       operOid = LookupOperNameTypeNames(operatorName, typeName1, typeName2,
-                                                                         false);
+       operOid = LookupOperNameTypeNames(NULL, operatorName,
+                                                                         typeName1, typeName2,
+                                                                         false, -1);
 
        tup = SearchSysCache(OPEROID,
                                                 ObjectIdGetDatum(operOid),
@@ -286,8 +287,9 @@ AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2,
 
        rel = heap_open(OperatorRelationId, RowExclusiveLock);
 
-       operOid = LookupOperNameTypeNames(name, typeName1, typeName2,
-                                                                         false);
+       operOid = LookupOperNameTypeNames(NULL, name,
+                                                                         typeName1, typeName2,
+                                                                         false, -1);
 
        AlterOperatorOwner_internal(rel, operOid, newOwnerId);
 
index c171d8bfdc3b4127480d9319a761ad4d01142487..73d532da4a57bef4ce704d6f0c5454ec660e7101 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.39 2006/03/05 15:58:24 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.40 2006/03/14 22:48:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -121,7 +121,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
                List       *querytree_list;
                ListCell   *querytree_item;
 
-               querytree_list = parse_analyze(parsetree, NULL, 0);
+               querytree_list = parse_analyze(parsetree, NULL, NULL, 0);
 
                foreach(querytree_item, querytree_list)
                {
index 2d6d19286390516b7aa5972c0c9f93a3c5c498a5..5638f4fe9b79d73a7c281fe1207523b5266db2cf 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.128 2006/03/05 15:58:24 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.129 2006/03/14 22:48:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -21,6 +21,7 @@
 #include "commands/tablecmds.h"
 #include "commands/sequence.h"
 #include "miscadmin.h"
+#include "nodes/makefuncs.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/resowner.h"
@@ -112,16 +113,8 @@ DefineSequence(CreateSeqStmt *seq)
        stmt->tableElts = NIL;
        for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
        {
-               ColumnDef  *coldef;
-               TypeName   *typnam;
+               ColumnDef  *coldef = makeNode(ColumnDef);
 
-               typnam = makeNode(TypeName);
-               typnam->setof = FALSE;
-               typnam->arrayBounds = NIL;
-               typnam->typmod = -1;
-
-               coldef = makeNode(ColumnDef);
-               coldef->typename = typnam;
                coldef->inhcount = 0;
                coldef->is_local = true;
                coldef->is_not_null = true;
@@ -135,48 +128,48 @@ DefineSequence(CreateSeqStmt *seq)
                switch (i)
                {
                        case SEQ_COL_NAME:
-                               typnam->typeid = NAMEOID;
+                               coldef->typename = makeTypeNameFromOid(NAMEOID, -1);
                                coldef->colname = "sequence_name";
                                namestrcpy(&name, seq->sequence->relname);
                                value[i - 1] = NameGetDatum(&name);
                                break;
                        case SEQ_COL_LASTVAL:
-                               typnam->typeid = INT8OID;
+                               coldef->typename = makeTypeNameFromOid(INT8OID, -1);
                                coldef->colname = "last_value";
                                value[i - 1] = Int64GetDatumFast(new.last_value);
                                break;
                        case SEQ_COL_INCBY:
-                               typnam->typeid = INT8OID;
+                               coldef->typename = makeTypeNameFromOid(INT8OID, -1);
                                coldef->colname = "increment_by";
                                value[i - 1] = Int64GetDatumFast(new.increment_by);
                                break;
                        case SEQ_COL_MAXVALUE:
-                               typnam->typeid = INT8OID;
+                               coldef->typename = makeTypeNameFromOid(INT8OID, -1);
                                coldef->colname = "max_value";
                                value[i - 1] = Int64GetDatumFast(new.max_value);
                                break;
                        case SEQ_COL_MINVALUE:
-                               typnam->typeid = INT8OID;
+                               coldef->typename = makeTypeNameFromOid(INT8OID, -1);
                                coldef->colname = "min_value";
                                value[i - 1] = Int64GetDatumFast(new.min_value);
                                break;
                        case SEQ_COL_CACHE:
-                               typnam->typeid = INT8OID;
+                               coldef->typename = makeTypeNameFromOid(INT8OID, -1);
                                coldef->colname = "cache_value";
                                value[i - 1] = Int64GetDatumFast(new.cache_value);
                                break;
                        case SEQ_COL_LOG:
-                               typnam->typeid = INT8OID;
+                               coldef->typename = makeTypeNameFromOid(INT8OID, -1);
                                coldef->colname = "log_cnt";
                                value[i - 1] = Int64GetDatum((int64) 1);
                                break;
                        case SEQ_COL_CYCLE:
-                               typnam->typeid = BOOLOID;
+                               coldef->typename = makeTypeNameFromOid(BOOLOID, -1);
                                coldef->colname = "is_cycled";
                                value[i - 1] = BoolGetDatum(new.is_cycled);
                                break;
                        case SEQ_COL_CALLED:
-                               typnam->typeid = BOOLOID;
+                               coldef->typename = makeTypeNameFromOid(BOOLOID, -1);
                                coldef->colname = "is_called";
                                value[i - 1] = BoolGetDatum(false);
                                break;
index c484c148c254acfbde412352687d48b04b9a7fd4..6483578e808c4bd0980668400375ff12932fa824 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.180 2006/03/05 15:58:24 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.181 2006/03/14 22:48:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -867,7 +867,6 @@ MergeAttributes(List *schema, List *supers, bool istemp,
                        char       *attributeName = NameStr(attribute->attname);
                        int                     exist_attno;
                        ColumnDef  *def;
-                       TypeName   *typename;
 
                        /*
                         * Ignore dropped columns in the parent.
@@ -897,7 +896,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
                                                (errmsg("merging multiple inherited definitions of column \"%s\"",
                                                                attributeName)));
                                def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
-                               if (typenameTypeId(def->typename) != attribute->atttypid ||
+                               if (typenameTypeId(NULL, def->typename) != attribute->atttypid ||
                                        def->typename->typmod != attribute->atttypmod)
                                        ereport(ERROR,
                                                        (errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -919,10 +918,8 @@ MergeAttributes(List *schema, List *supers, bool istemp,
                                 */
                                def = makeNode(ColumnDef);
                                def->colname = pstrdup(attributeName);
-                               typename = makeNode(TypeName);
-                               typename->typeid = attribute->atttypid;
-                               typename->typmod = attribute->atttypmod;
-                               def->typename = typename;
+                               def->typename = makeTypeNameFromOid(attribute->atttypid,
+                                                                                                       attribute->atttypmod);
                                def->inhcount = 1;
                                def->is_local = false;
                                def->is_not_null = attribute->attnotnull;
@@ -1041,7 +1038,7 @@ MergeAttributes(List *schema, List *supers, bool istemp,
                                   (errmsg("merging column \"%s\" with inherited definition",
                                                   attributeName)));
                                def = (ColumnDef *) list_nth(inhSchema, exist_attno - 1);
-                               if (typenameTypeId(def->typename) != typenameTypeId(newdef->typename) ||
+                               if (typenameTypeId(NULL, def->typename) != typenameTypeId(NULL, newdef->typename) ||
                                        def->typename->typmod != newdef->typename->typmod)
                                        ereport(ERROR,
                                                        (errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -2955,7 +2952,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
                        Form_pg_attribute childatt = (Form_pg_attribute) GETSTRUCT(tuple);
 
                        /* Okay if child matches by type */
-                       if (typenameTypeId(colDef->typename) != childatt->atttypid ||
+                       if (typenameTypeId(NULL, colDef->typename) != childatt->atttypid ||
                                colDef->typename->typmod != childatt->atttypmod)
                                ereport(ERROR,
                                                (errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -3009,7 +3006,7 @@ ATExecAddColumn(AlteredTableInfo *tab, Relation rel,
                                                MaxHeapAttributeNumber)));
        i = minattnum + 1;
 
-       typeTuple = typenameType(colDef->typename);
+       typeTuple = typenameType(NULL, colDef->typename);
        tform = (Form_pg_type) GETSTRUCT(typeTuple);
        typeOid = HeapTupleGetOid(typeTuple);
 
@@ -3991,8 +3988,9 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
                 * the right answer from the test below on opclass membership unless
                 * we select the proper operator.)
                 */
-               Operator        o = oper(list_make1(makeString("=")),
-                                                        pktypoid[i], fktypoid[i], true);
+               Operator        o = oper(NULL, list_make1(makeString("=")),
+                                                        pktypoid[i], fktypoid[i],
+                                                        true, -1);
 
                if (o == NULL)
                        ereport(ERROR,
@@ -4773,12 +4771,7 @@ ATPrepAlterColumnType(List **wqueue,
                                                colName)));
 
        /* Look up the target type */
-       targettype = LookupTypeName(typename);
-       if (!OidIsValid(targettype))
-               ereport(ERROR,
-                               (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                errmsg("type \"%s\" does not exist",
-                                               TypeNameToString(typename))));
+       targettype = typenameTypeId(NULL, typename);
 
        /* make sure datatype is legal for a column */
        CheckAttributeType(colName, targettype);
@@ -4904,7 +4897,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
                                                colName)));
 
        /* Look up the target type (should not fail, since prep found it) */
-       typeTuple = typenameType(typename);
+       typeTuple = typenameType(NULL, typename);
        tform = (Form_pg_type) GETSTRUCT(typeTuple);
        targettype = HeapTupleGetOid(typeTuple);
 
@@ -5265,7 +5258,7 @@ ATPostAlterTypeParse(char *cmd, List **wqueue)
                Node       *parsetree = (Node *) lfirst(list_item);
 
                querytree_list = list_concat(querytree_list,
-                                                                        parse_analyze(parsetree, NULL, 0));
+                                                                        parse_analyze(parsetree, cmd, NULL, 0));
        }
 
        /*
index 933f76c12d51b788b30fc30af63e9989b2dfa423..83143496dbccbc0927595006be1e11dbb778d08f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.88 2006/03/05 15:58:25 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.89 2006/03/14 22:48:18 tgl Exp $
  *
  * DESCRIPTION
  *       The "DefineFoo" routines take the parse tree and pick out the
@@ -47,7 +47,7 @@
 #include "executor/executor.h"
 #include "miscadmin.h"
 #include "nodes/execnodes.h"
-#include "nodes/nodes.h"
+#include "nodes/makefuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/planmain.h"
 #include "optimizer/var.h"
@@ -80,7 +80,7 @@ static Oid    findTypeReceiveFunction(List *procname, Oid typeOid);
 static Oid     findTypeSendFunction(List *procname, Oid typeOid);
 static Oid     findTypeAnalyzeFunction(List *procname, Oid typeOid);
 static List *get_rels_with_domain(Oid domainOid, LOCKMODE lockmode);
-static void domainOwnerCheck(HeapTuple tup, TypeName *typename);
+static void checkDomainOwner(HeapTuple tup, TypeName *typename);
 static char *domainAddConstraint(Oid domainOid, Oid domainNamespace,
                                        Oid baseTypeOid,
                                        int typMod, Constraint *constr,
@@ -196,7 +196,7 @@ DefineType(List *names, List *parameters)
                }
                else if (pg_strcasecmp(defel->defname, "element") == 0)
                {
-                       elemType = typenameTypeId(defGetTypeName(defel));
+                       elemType = typenameTypeId(NULL, defGetTypeName(defel));
                        /* disallow arrays of pseudotypes */
                        if (get_typtype(elemType) == 'p')
                                ereport(ERROR,
@@ -445,13 +445,10 @@ RemoveType(List *names, DropBehavior behavior, bool missing_ok)
        ObjectAddress object;
 
        /* Make a TypeName so we can use standard type lookup machinery */
-       typename = makeNode(TypeName);
-       typename->names = names;
-       typename->typmod = -1;
-       typename->arrayBounds = NIL;
+       typename = makeTypeNameFromNameList(names);
 
        /* Use LookupTypeName here so that shell types can be removed. */
-       typeoid = LookupTypeName(typename);
+       typeoid = LookupTypeName(NULL, typename);
        if (!OidIsValid(typeoid))
        {
                if (!missing_ok)
@@ -586,7 +583,7 @@ DefineDomain(CreateDomainStmt *stmt)
        /*
         * Look up the base type.
         */
-       typeTup = typenameType(stmt->typename);
+       typeTup = typenameType(NULL, stmt->typename);
 
        baseType = (Form_pg_type) GETSTRUCT(typeTup);
        basetypeoid = HeapTupleGetOid(typeTup);
@@ -840,13 +837,10 @@ RemoveDomain(List *names, DropBehavior behavior, bool missing_ok)
        ObjectAddress object;
 
        /* Make a TypeName so we can use standard type lookup machinery */
-       typename = makeNode(TypeName);
-       typename->names = names;
-       typename->typmod = -1;
-       typename->arrayBounds = NIL;
+       typename = makeTypeNameFromNameList(names);
 
        /* Use LookupTypeName here so that shell types can be removed. */
-       typeoid = LookupTypeName(typename);
+       typeoid = LookupTypeName(NULL, typename);
        if (!OidIsValid(typeoid))
        {
                if (!missing_ok)
@@ -1172,39 +1166,27 @@ AlterDomainDefault(List *names, Node *defaultRaw)
        Form_pg_type typTup;
 
        /* Make a TypeName so we can use standard type lookup machinery */
-       typename = makeNode(TypeName);
-       typename->names = names;
-       typename->typmod = -1;
-       typename->arrayBounds = NIL;
+       typename = makeTypeNameFromNameList(names);
+       domainoid = typenameTypeId(NULL, typename);
 
-       /* Lock the domain in the type table */
+       /* Look up the domain in the type table */
        rel = heap_open(TypeRelationId, RowExclusiveLock);
 
-       /* Use LookupTypeName here so that shell types can be removed. */
-       domainoid = LookupTypeName(typename);
-       if (!OidIsValid(domainoid))
-               ereport(ERROR,
-                               (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                errmsg("type \"%s\" does not exist",
-                                               TypeNameToString(typename))));
-
        tup = SearchSysCacheCopy(TYPEOID,
                                                         ObjectIdGetDatum(domainoid),
                                                         0, 0, 0);
        if (!HeapTupleIsValid(tup))
                elog(ERROR, "cache lookup failed for type %u", domainoid);
+       typTup = (Form_pg_type) GETSTRUCT(tup);
 
-       /* Doesn't return if user isn't allowed to alter the domain */
-       domainOwnerCheck(tup, typename);
+       /* Check it's a domain and check user has permission for ALTER DOMAIN */
+       checkDomainOwner(tup, typename);
 
        /* Setup new tuple */
        MemSet(new_record, (Datum) 0, sizeof(new_record));
        MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));
        MemSet(new_record_repl, ' ', sizeof(new_record_repl));
 
-       /* Useful later */
-       typTup = (Form_pg_type) GETSTRUCT(tup);
-
        /* Store the new default, if null then skip this step */
        if (defaultRaw)
        {
@@ -1295,22 +1277,12 @@ AlterDomainNotNull(List *names, bool notNull)
        Form_pg_type typTup;
 
        /* Make a TypeName so we can use standard type lookup machinery */
-       typename = makeNode(TypeName);
-       typename->names = names;
-       typename->typmod = -1;
-       typename->arrayBounds = NIL;
+       typename = makeTypeNameFromNameList(names);
+       domainoid = typenameTypeId(NULL, typename);
 
-       /* Lock the type table */
+       /* Look up the domain in the type table */
        typrel = heap_open(TypeRelationId, RowExclusiveLock);
 
-       /* Use LookupTypeName here so that shell types can be found (why?). */
-       domainoid = LookupTypeName(typename);
-       if (!OidIsValid(domainoid))
-               ereport(ERROR,
-                               (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                errmsg("type \"%s\" does not exist",
-                                               TypeNameToString(typename))));
-
        tup = SearchSysCacheCopy(TYPEOID,
                                                         ObjectIdGetDatum(domainoid),
                                                         0, 0, 0);
@@ -1318,8 +1290,8 @@ AlterDomainNotNull(List *names, bool notNull)
                elog(ERROR, "cache lookup failed for type %u", domainoid);
        typTup = (Form_pg_type) GETSTRUCT(tup);
 
-       /* Doesn't return if user isn't allowed to alter the domain */
-       domainOwnerCheck(tup, typename);
+       /* Check it's a domain and check user has permission for ALTER DOMAIN */
+       checkDomainOwner(tup, typename);
 
        /* Is the domain already set to the desired constraint? */
        if (typTup->typnotnull == notNull)
@@ -1394,7 +1366,8 @@ AlterDomainNotNull(List *names, bool notNull)
  * Implements the ALTER DOMAIN DROP CONSTRAINT statement
  */
 void
-AlterDomainDropConstraint(List *names, const char *constrName, DropBehavior behavior)
+AlterDomainDropConstraint(List *names, const char *constrName,
+                                                 DropBehavior behavior)
 {
        TypeName   *typename;
        Oid                     domainoid;
@@ -1406,30 +1379,20 @@ AlterDomainDropConstraint(List *names, const char *constrName, DropBehavior beha
        HeapTuple       contup;
 
        /* Make a TypeName so we can use standard type lookup machinery */
-       typename = makeNode(TypeName);
-       typename->names = names;
-       typename->typmod = -1;
-       typename->arrayBounds = NIL;
+       typename = makeTypeNameFromNameList(names);
+       domainoid = typenameTypeId(NULL, typename);
 
-       /* Lock the type table */
+       /* Look up the domain in the type table */
        rel = heap_open(TypeRelationId, RowExclusiveLock);
 
-       /* Use LookupTypeName here so that shell types can be removed. */
-       domainoid = LookupTypeName(typename);
-       if (!OidIsValid(domainoid))
-               ereport(ERROR,
-                               (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                errmsg("type \"%s\" does not exist",
-                                               TypeNameToString(typename))));
-
        tup = SearchSysCacheCopy(TYPEOID,
                                                         ObjectIdGetDatum(domainoid),
                                                         0, 0, 0);
        if (!HeapTupleIsValid(tup))
                elog(ERROR, "cache lookup failed for type %u", domainoid);
 
-       /* Doesn't return if user isn't allowed to alter the domain */
-       domainOwnerCheck(tup, typename);
+       /* Check it's a domain and check user has permission for ALTER DOMAIN */
+       checkDomainOwner(tup, typename);
 
        /* Grab an appropriate lock on the pg_constraint relation */
        conrel = heap_open(ConstraintRelationId, RowExclusiveLock);
@@ -1491,22 +1454,12 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
        Constraint *constr;
 
        /* Make a TypeName so we can use standard type lookup machinery */
-       typename = makeNode(TypeName);
-       typename->names = names;
-       typename->typmod = -1;
-       typename->arrayBounds = NIL;
+       typename = makeTypeNameFromNameList(names);
+       domainoid = typenameTypeId(NULL, typename);
 
-       /* Lock the type table */
+       /* Look up the domain in the type table */
        typrel = heap_open(TypeRelationId, RowExclusiveLock);
 
-       /* Use LookupTypeName here so that shell types can be found (why?). */
-       domainoid = LookupTypeName(typename);
-       if (!OidIsValid(domainoid))
-               ereport(ERROR,
-                               (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                errmsg("type \"%s\" does not exist",
-                                               TypeNameToString(typename))));
-
        tup = SearchSysCacheCopy(TYPEOID,
                                                         ObjectIdGetDatum(domainoid),
                                                         0, 0, 0);
@@ -1514,8 +1467,8 @@ AlterDomainAddConstraint(List *names, Node *newConstraint)
                elog(ERROR, "cache lookup failed for type %u", domainoid);
        typTup = (Form_pg_type) GETSTRUCT(tup);
 
-       /* Doesn't return if user isn't allowed to alter the domain */
-       domainOwnerCheck(tup, typename);
+       /* Check it's a domain and check user has permission for ALTER DOMAIN */
+       checkDomainOwner(tup, typename);
 
        /* Check for unsupported constraint types */
        if (IsA(newConstraint, FkConstraint))
@@ -1782,14 +1735,13 @@ get_rels_with_domain(Oid domainOid, LOCKMODE lockmode)
 }
 
 /*
- * domainOwnerCheck
+ * checkDomainOwner
  *
- * Throw an error if the current user doesn't have permission to modify
- * the domain in an ALTER DOMAIN statement, or if the type isn't actually
- * a domain.
+ * Check that the type is actually a domain and that the current user
+ * has permission to do ALTER DOMAIN on it.  Throw an error if not.
  */
 static void
-domainOwnerCheck(HeapTuple tup, TypeName *typename)
+checkDomainOwner(HeapTuple tup, TypeName *typename)
 {
        Form_pg_type typTup = (Form_pg_type) GETSTRUCT(tup);
 
@@ -2079,22 +2031,19 @@ AlterTypeOwner(List *names, Oid newOwnerId)
        AclResult       aclresult;
 
        /* Make a TypeName so we can use standard type lookup machinery */
-       typename = makeNode(TypeName);
-       typename->names = names;
-       typename->typmod = -1;
-       typename->arrayBounds = NIL;
-
-       /* Lock the type table */
-       rel = heap_open(TypeRelationId, RowExclusiveLock);
+       typename = makeTypeNameFromNameList(names);
 
-       /* Use LookupTypeName here so that shell types can be processed (why?) */
-       typeOid = LookupTypeName(typename);
+       /* Use LookupTypeName here so that shell types can be processed */
+       typeOid = LookupTypeName(NULL, typename);
        if (!OidIsValid(typeOid))
                ereport(ERROR,
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
                                 errmsg("type \"%s\" does not exist",
                                                TypeNameToString(typename))));
 
+       /* Look up the type in the type table */
+       rel = heap_open(TypeRelationId, RowExclusiveLock);
+
        tup = SearchSysCacheCopy(TYPEOID,
                                                         ObjectIdGetDatum(typeOid),
                                                         0, 0, 0);
@@ -2206,19 +2155,9 @@ AlterTypeNamespace(List *names, const char *newschema)
        Oid                     typeOid;
        Oid                     nspOid;
 
-       /* get type OID */
-       typename = makeNode(TypeName);
-       typename->names = names;
-       typename->typmod = -1;
-       typename->arrayBounds = NIL;
-
-       typeOid = LookupTypeName(typename);
-
-       if (!OidIsValid(typeOid))
-               ereport(ERROR,
-                               (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                errmsg("type \"%s\" does not exist",
-                                               TypeNameToString(typename))));
+       /* Make a TypeName so we can use standard type lookup machinery */
+       typename = makeTypeNameFromNameList(names);
+       typeOid = typenameTypeId(NULL, typename);
 
        /* check permissions on type */
        if (!pg_type_ownercheck(typeOid, GetUserId()))
index bdecdad247bbeec7d0809cf35d01f9434fa7d528..490e0aa351966e47dfb4bd8d8e09a6582b50ed9c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.93 2006/03/05 15:58:25 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.94 2006/03/14 22:48:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -114,14 +114,10 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
                if (!tle->resjunk)
                {
                        ColumnDef  *def = makeNode(ColumnDef);
-                       TypeName   *typename = makeNode(TypeName);
 
                        def->colname = pstrdup(tle->resname);
-
-                       typename->typeid = exprType((Node *) tle->expr);
-                       typename->typmod = exprTypmod((Node *) tle->expr);
-                       def->typename = typename;
-
+                       def->typename = makeTypeNameFromOid(exprType((Node *) tle->expr),
+                                                                                       exprTypmod((Node *) tle->expr));
                        def->inhcount = 0;
                        def->is_local = true;
                        def->is_not_null = false;
index 2f0d73caf78501255d6c5ab511ab3f0ad6891190..183bc89b020843c195332c3037bd1a495b735bb5 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.148 2006/03/05 15:58:26 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.149 2006/03/14 22:48:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1282,7 +1282,7 @@ _SPI_prepare_plan(const char *src, _SPI_plan *plan)
                Node       *parsetree = (Node *) lfirst(list_item);
                List       *query_list;
 
-               query_list = pg_analyze_and_rewrite(parsetree, argtypes, nargs);
+               query_list = pg_analyze_and_rewrite(parsetree, src, argtypes, nargs);
 
                query_list_list = lappend(query_list_list, query_list);
 
index f37daaf3a6f0a53b4ed70b0af31dcfcf7e458785..b38efcdec8b581c7f60e3bd6a5ff7b8008d06061 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.329 2006/03/05 15:58:27 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.330 2006/03/14 22:48:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1418,6 +1418,7 @@ _copyAExpr(A_Expr *from)
        COPY_NODE_FIELD(name);
        COPY_NODE_FIELD(lexpr);
        COPY_NODE_FIELD(rexpr);
+       COPY_SCALAR_FIELD(location);
 
        return newnode;
 }
@@ -1428,6 +1429,7 @@ _copyColumnRef(ColumnRef *from)
        ColumnRef  *newnode = makeNode(ColumnRef);
 
        COPY_NODE_FIELD(fields);
+       COPY_SCALAR_FIELD(location);
 
        return newnode;
 }
@@ -1482,6 +1484,7 @@ _copyFuncCall(FuncCall *from)
        COPY_NODE_FIELD(args);
        COPY_SCALAR_FIELD(agg_star);
        COPY_SCALAR_FIELD(agg_distinct);
+       COPY_SCALAR_FIELD(location);
 
        return newnode;
 }
@@ -1532,6 +1535,7 @@ _copyTypeName(TypeName *from)
        COPY_SCALAR_FIELD(pct_type);
        COPY_SCALAR_FIELD(typmod);
        COPY_NODE_FIELD(arrayBounds);
+       COPY_SCALAR_FIELD(location);
 
        return newnode;
 }
index 757acd9fb91525c0f680e0584d7199ea4ba06d9b..0275b01c28e5f99a6f8903bddae9d2f676fae71f 100644 (file)
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.265 2006/03/05 15:58:27 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.266 2006/03/14 22:48:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1540,6 +1540,7 @@ _equalAExpr(A_Expr *a, A_Expr *b)
        COMPARE_NODE_FIELD(name);
        COMPARE_NODE_FIELD(lexpr);
        COMPARE_NODE_FIELD(rexpr);
+       COMPARE_SCALAR_FIELD(location);
 
        return true;
 }
@@ -1548,6 +1549,7 @@ static bool
 _equalColumnRef(ColumnRef *a, ColumnRef *b)
 {
        COMPARE_NODE_FIELD(fields);
+       COMPARE_SCALAR_FIELD(location);
 
        return true;
 }
@@ -1577,6 +1579,7 @@ _equalFuncCall(FuncCall *a, FuncCall *b)
        COMPARE_NODE_FIELD(args);
        COMPARE_SCALAR_FIELD(agg_star);
        COMPARE_SCALAR_FIELD(agg_distinct);
+       COMPARE_SCALAR_FIELD(location);
 
        return true;
 }
@@ -1619,6 +1622,7 @@ _equalTypeName(TypeName *a, TypeName *b)
        COMPARE_SCALAR_FIELD(pct_type);
        COMPARE_SCALAR_FIELD(typmod);
        COMPARE_NODE_FIELD(arrayBounds);
+       COMPARE_SCALAR_FIELD(location);
 
        return true;
 }
index f69b6e6244bf490701c90d79d03fd92dab5522bf..784dd57831d6102c26537ec2abadc2a604db218d 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.49 2006/03/05 15:58:27 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.50 2006/03/14 22:48:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -25,7 +25,8 @@
  *             makes an A_Expr node
  */
 A_Expr *
-makeA_Expr(A_Expr_Kind kind, List *name, Node *lexpr, Node *rexpr)
+makeA_Expr(A_Expr_Kind kind, List *name,
+                  Node *lexpr, Node *rexpr, int location)
 {
        A_Expr     *a = makeNode(A_Expr);
 
@@ -33,6 +34,7 @@ makeA_Expr(A_Expr_Kind kind, List *name, Node *lexpr, Node *rexpr)
        a->name = name;
        a->lexpr = lexpr;
        a->rexpr = rexpr;
+       a->location = location;
        return a;
 }
 
@@ -42,7 +44,7 @@ makeA_Expr(A_Expr_Kind kind, List *name, Node *lexpr, Node *rexpr)
  */
 A_Expr *
 makeSimpleA_Expr(A_Expr_Kind kind, const char *name,
-                                Node *lexpr, Node *rexpr)
+                                Node *lexpr, Node *rexpr, int location)
 {
        A_Expr     *a = makeNode(A_Expr);
 
@@ -50,6 +52,7 @@ makeSimpleA_Expr(A_Expr_Kind kind, const char *name,
        a->name = list_make1(makeString((char *) name));
        a->lexpr = lexpr;
        a->rexpr = rexpr;
+       a->location = location;
        return a;
 }
 
@@ -253,6 +256,8 @@ makeRangeVar(char *schemaname, char *relname)
 /*
  * makeTypeName -
  *     build a TypeName node for an unqualified name.
+ *
+ * typmod is defaulted, but can be changed later by caller.
  */
 TypeName *
 makeTypeName(char *typnam)
@@ -261,6 +266,39 @@ makeTypeName(char *typnam)
 
        n->names = list_make1(makeString(typnam));
        n->typmod = -1;
+       n->location = -1;
+       return n;
+}
+
+/*
+ * makeTypeNameFromNameList -
+ *     build a TypeName node for a String list representing a qualified name.
+ *
+ * typmod is defaulted, but can be changed later by caller.
+ */
+TypeName *
+makeTypeNameFromNameList(List *names)
+{
+       TypeName   *n = makeNode(TypeName);
+
+       n->names = names;
+       n->typmod = -1;
+       n->location = -1;
+       return n;
+}
+
+/*
+ * makeTypeNameFromOid -
+ *     build a TypeName node to represent a type already known by OID.
+ */
+TypeName *
+makeTypeNameFromOid(Oid typeid, int32 typmod)
+{
+       TypeName   *n = makeNode(TypeName);
+
+       n->typeid = typeid;
+       n->typmod = typmod;
+       n->location = -1;
        return n;
 }
 
index 7bb20628c6029f2fd819b453e575650fc37f22a4..ef87fedbc216ab9c376693ba0769d029635d3ff3 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.269 2006/03/05 15:58:27 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.270 2006/03/14 22:48:19 tgl Exp $
  *
  * NOTES
  *       Every node type that can appear in stored rules' parsetrees *must*
@@ -1400,6 +1400,7 @@ _outFuncCall(StringInfo str, FuncCall *node)
        WRITE_NODE_FIELD(args);
        WRITE_BOOL_FIELD(agg_star);
        WRITE_BOOL_FIELD(agg_distinct);
+       WRITE_INT_FIELD(location);
 }
 
 static void
@@ -1449,6 +1450,7 @@ _outTypeName(StringInfo str, TypeName *node)
        WRITE_BOOL_FIELD(pct_type);
        WRITE_INT_FIELD(typmod);
        WRITE_NODE_FIELD(arrayBounds);
+       /* location is deliberately not stored */
 }
 
 static void
@@ -1648,6 +1650,7 @@ _outAExpr(StringInfo str, A_Expr *node)
 
        WRITE_NODE_FIELD(lexpr);
        WRITE_NODE_FIELD(rexpr);
+       WRITE_INT_FIELD(location);
 }
 
 static void
@@ -1687,6 +1690,7 @@ _outColumnRef(StringInfo str, ColumnRef *node)
        WRITE_NODE_TYPE("COLUMNREF");
 
        WRITE_NODE_FIELD(fields);
+       WRITE_INT_FIELD(location);
 }
 
 static void
index 2733db62b3acf33968828f75c4fd38467a7d3487..c7490a9567ccc59e8df2f8be6f6713a3c03052fb 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.185 2006/03/05 15:58:28 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.186 2006/03/14 22:48:19 tgl Exp $
  *
  * NOTES
  *       Path and Plan nodes do not have any readfuncs support, because we
@@ -893,6 +893,8 @@ _readTypeName(void)
        READ_BOOL_FIELD(pct_type);
        READ_INT_FIELD(typmod);
        READ_NODE_FIELD(arrayBounds);
+       /* location is deliberately not stored */
+       local_node->location = -1;
 
        READ_DONE();
 }
index d980cde06bca9c1741f52985955c17960c94de30..1c04a8784d296eed421059f0592e9c6ec922bdf4 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.116 2006/03/07 01:00:15 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.117 2006/03/14 22:48:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -992,8 +992,9 @@ process_implied_equality(PlannerInfo *root,
         */
        ltype = exprType(item1);
        rtype = exprType(item2);
-       eq_operator = compatible_oper(list_make1(makeString("=")),
-                                                                 ltype, rtype, true);
+       eq_operator = compatible_oper(NULL, list_make1(makeString("=")),
+                                                                 ltype, rtype,
+                                                                 true, -1);
        if (!HeapTupleIsValid(eq_operator))
        {
                /*
index 37d693b9950f52ee55c743039f4e105256b8fac5..aa21dfdac95406318b4829010c7a028997cf65d5 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.209 2006/03/05 15:58:31 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.210 2006/03/14 22:48:19 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -2637,7 +2637,7 @@ inline_function(Oid funcid, Oid result_type, List *args,
        if (list_length(raw_parsetree_list) != 1)
                goto fail;
 
-       querytree_list = parse_analyze(linitial(raw_parsetree_list),
+       querytree_list = parse_analyze(linitial(raw_parsetree_list), src,
                                                                   argtypes, funcform->pronargs);
 
        if (list_length(querytree_list) != 1)
index 645a740be0e2bf0b7fbb729c9d8482a1f90de459..1c4dc363034873751bcf54bd748e890bca010217 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.330 2006/03/05 15:58:32 momjian Exp $
+ *     $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.331 2006/03/14 22:48:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -146,6 +146,9 @@ static bool check_parameter_resolution_walker(Node *node,
  * parse_analyze
  *             Analyze a raw parse tree and transform it to Query form.
  *
+ * If available, pass the source text from which the raw parse tree was
+ * generated; it's OK to pass NULL if this is not available.
+ *
  * Optionally, information about $n parameter types can be supplied.
  * References to $n indexes not defined by paramTypes[] are disallowed.
  *
@@ -155,11 +158,13 @@ static bool check_parameter_resolution_walker(Node *node,
  * a dummy CMD_UTILITY Query node.
  */
 List *
-parse_analyze(Node *parseTree, Oid *paramTypes, int numParams)
+parse_analyze(Node *parseTree, const char *sourceText,
+                         Oid *paramTypes, int numParams)
 {
        ParseState *pstate = make_parsestate(NULL);
        List       *result;
 
+       pstate->p_sourcetext = sourceText;
        pstate->p_paramtypes = paramTypes;
        pstate->p_numparams = numParams;
        pstate->p_variableparams = false;
@@ -179,11 +184,13 @@ parse_analyze(Node *parseTree, Oid *paramTypes, int numParams)
  * be modified or enlarged (via repalloc).
  */
 List *
-parse_analyze_varparams(Node *parseTree, Oid **paramTypes, int *numParams)
+parse_analyze_varparams(Node *parseTree, const char *sourceText,
+                                               Oid **paramTypes, int *numParams)
 {
        ParseState *pstate = make_parsestate(NULL);
        List       *result;
 
+       pstate->p_sourcetext = sourceText;
        pstate->p_paramtypes = *paramTypes;
        pstate->p_numparams = *numParams;
        pstate->p_variableparams = true;
@@ -921,6 +928,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
                funccallnode->args = list_make1(snamenode);
                funccallnode->agg_star = false;
                funccallnode->agg_distinct = false;
+               funccallnode->location = -1;
 
                constraint = makeNode(Constraint);
                constraint->contype = CONSTR_DEFAULT;
@@ -1097,7 +1105,6 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
                Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1];
                char       *attributeName = NameStr(attribute->attname);
                ColumnDef  *def;
-               TypeName   *typename;
 
                /*
                 * Ignore dropped columns in the parent.
@@ -1113,10 +1120,8 @@ transformInhRelation(ParseState *pstate, CreateStmtContext *cxt,
                 */
                def = makeNode(ColumnDef);
                def->colname = pstrdup(attributeName);
-               typename = makeNode(TypeName);
-               typename->typeid = attribute->atttypid;
-               typename->typmod = attribute->atttypmod;
-               def->typename = typename;
+               def->typename = makeTypeNameFromOid(attribute->atttypid,
+                                                                                       attribute->atttypmod);
                def->inhcount = 0;
                def->is_local = false;
                def->is_not_null = attribute->attnotnull;
@@ -2608,7 +2613,7 @@ transformPrepareStmt(ParseState *pstate, PrepareStmt *stmt)
                foreach(l, stmt->argtypes)
                {
                        TypeName   *tn = lfirst(l);
-                       Oid                     toid = typenameTypeId(tn);
+                       Oid                     toid = typenameTypeId(pstate, tn);
 
                        argtoids[i++] = toid;
                }
@@ -2621,6 +2626,7 @@ transformPrepareStmt(ParseState *pstate, PrepareStmt *stmt)
         * from context.
         */
        queries = parse_analyze_varparams((Node *) stmt->query,
+                                                                         pstate->p_sourcetext,
                                                                          &argtoids, &nargs);
 
        /*
@@ -3029,7 +3035,7 @@ transformColumnType(ParseState *pstate, ColumnDef *column)
        /*
         * All we really need to do here is verify that the type is valid.
         */
-       Type            ctype = typenameType(column->typename);
+       Type            ctype = typenameType(pstate, column->typename);
 
        ReleaseSysCache(ctype);
 }
index c86a6888f205a960d65c9f1be549d8b8f7c8ecdc..acaddb13651ade62caac4d33beccd92035aa34de 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.534 2006/03/07 01:00:16 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.535 2006/03/14 22:48:20 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
 #include "utils/numeric.h"
 
 
+/* Location tracking support --- simpler than bison's default */
+#define YYLLOC_DEFAULT(Current, Rhs, N) \
+       Current = Rhs[1];
+
 extern List *parsetree;                        /* final parse result is delivered here */
 
 static bool QueryIsRule = FALSE;
@@ -72,7 +76,7 @@ static bool QueryIsRule = FALSE;
  */
 /*#define __YYSCLASS*/
 
-static Node *makeColumnRef(char *relname, List *indirection);
+static Node *makeColumnRef(char *relname, List *indirection, int location);
 static Node *makeTypeCast(Node *arg, TypeName *typename);
 static Node *makeStringConst(char *str, TypeName *typename);
 static Node *makeIntConst(int val);
@@ -81,7 +85,7 @@ static Node *makeAConst(Value *v);
 static Node *makeRowNullTest(NullTestType test, RowExpr *row);
 static DefElem *makeDefElem(char *name, Node *arg);
 static A_Const *makeBoolAConst(bool state);
-static FuncCall *makeOverlaps(List *largs, List *rargs);
+static FuncCall *makeOverlaps(List *largs, List *rargs, int location);
 static void check_qualified_name(List *names);
 static List *check_func_name(List *names);
 static List *extractArgTypes(List *parameters);
@@ -90,12 +94,13 @@ static void insertSelectOptions(SelectStmt *stmt,
                                                                List *sortClause, Node *lockingClause,
                                                                Node *limitOffset, Node *limitCount);
 static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
-static Node *doNegate(Node *n);
+static Node *doNegate(Node *n, int location);
 static void doNegateFloat(Value *v);
 
 %}
 
 %name-prefix="base_yy"
+%locations
 
 %union
 {
@@ -3705,6 +3710,7 @@ func_type:        Typename                                                                { $$ = $1; }
                                        $$->names = lcons(makeString($1), $2);
                                        $$->pct_type = true;
                                        $$->typmod = -1;
+                                       $$->location = @1;
                                }
                        | SETOF type_name attrs '%' TYPE_P
                                {
@@ -3713,6 +3719,7 @@ func_type:        Typename                                                                { $$ = $1; }
                                        $$->pct_type = true;
                                        $$->typmod = -1;
                                        $$->setof = TRUE;
+                                       $$->location = @2;
                                }
                ;
 
@@ -6053,6 +6060,7 @@ SimpleTypename:
                                        $$ = makeNode(TypeName);
                                        $$->names = lcons(makeString($1), $2);
                                        $$->typmod = -1;
+                                       $$->location = @1;
                                }
                ;
 
@@ -6077,6 +6085,7 @@ GenericType:
                        type_name
                                {
                                        $$ = makeTypeName($1);
+                                       $$->location = @1;
                                }
                ;
 
@@ -6540,6 +6549,7 @@ a_expr:           c_expr                                                                  { $$ = $1; }
                                        n->args = list_make2($5, $1);
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @2;
                                        $$ = (Node *) n;
                                }
                /*
@@ -6552,44 +6562,44 @@ a_expr:         c_expr                                                                  { $$ = $1; }
                 * also to b_expr and to the MathOp list above.
                 */
                        | '+' a_expr                                    %prec UMINUS
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
                        | '-' a_expr                                    %prec UMINUS
-                               { $$ = doNegate($2); }
+                               { $$ = doNegate($2, @1); }
                        | a_expr '+' a_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2); }
                        | a_expr '-' a_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2); }
                        | a_expr '*' a_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3, @2); }
                        | a_expr '/' a_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3, @2); }
                        | a_expr '%' a_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3, @2); }
                        | a_expr '^' a_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3, @2); }
                        | a_expr '<' a_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3, @2); }
                        | a_expr '>' a_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2); }
                        | a_expr '=' a_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); }
 
                        | a_expr qual_Op a_expr                         %prec Op
-                               { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3); }
+                               { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
                        | qual_Op a_expr                                        %prec Op
-                               { $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2); }
+                               { $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
                        | a_expr qual_Op                                        %prec POSTFIXOP
-                               { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL); }
+                               { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
 
                        | a_expr AND a_expr
-                               { $$ = (Node *) makeA_Expr(AEXPR_AND, NIL, $1, $3); }
+                               { $$ = (Node *) makeA_Expr(AEXPR_AND, NIL, $1, $3, @2); }
                        | a_expr OR a_expr
-                               { $$ = (Node *) makeA_Expr(AEXPR_OR, NIL, $1, $3); }
+                               { $$ = (Node *) makeA_Expr(AEXPR_OR, NIL, $1, $3, @2); }
                        | NOT a_expr
-                               { $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, $2); }
+                               { $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, $2, @1); }
 
                        | a_expr LIKE a_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, $3, @2); }
                        | a_expr LIKE a_expr ESCAPE a_expr
                                {
                                        FuncCall *n = makeNode(FuncCall);
@@ -6597,10 +6607,11 @@ a_expr:         c_expr                                                                  { $$ = $1; }
                                        n->args = list_make2($3, $5);
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, (Node *) n);
+                                       n->location = @4;
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, (Node *) n, @2);
                                }
                        | a_expr NOT LIKE a_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, $4); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, $4, @2); }
                        | a_expr NOT LIKE a_expr ESCAPE a_expr
                                {
                                        FuncCall *n = makeNode(FuncCall);
@@ -6608,10 +6619,11 @@ a_expr:         c_expr                                                                  { $$ = $1; }
                                        n->args = list_make2($4, $6);
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, (Node *) n);
+                                       n->location = @5;
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, (Node *) n, @2);
                                }
                        | a_expr ILIKE a_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, $3, @2); }
                        | a_expr ILIKE a_expr ESCAPE a_expr
                                {
                                        FuncCall *n = makeNode(FuncCall);
@@ -6619,10 +6631,11 @@ a_expr:         c_expr                                                                  { $$ = $1; }
                                        n->args = list_make2($3, $5);
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, (Node *) n);
+                                       n->location = @4;
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, (Node *) n, @2);
                                }
                        | a_expr NOT ILIKE a_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, $4); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, $4, @2); }
                        | a_expr NOT ILIKE a_expr ESCAPE a_expr
                                {
                                        FuncCall *n = makeNode(FuncCall);
@@ -6630,7 +6643,8 @@ a_expr:           c_expr                                                                  { $$ = $1; }
                                        n->args = list_make2($4, $6);
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, (Node *) n);
+                                       n->location = @5;
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, (Node *) n, @2);
                                }
 
                        | a_expr SIMILAR TO a_expr                              %prec SIMILAR
@@ -6642,7 +6656,8 @@ a_expr:           c_expr                                                                  { $$ = $1; }
                                        n->args = list_make2($4, (Node *) c);
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n);
+                                       n->location = @2;
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2);
                                }
                        | a_expr SIMILAR TO a_expr ESCAPE a_expr
                                {
@@ -6651,7 +6666,8 @@ a_expr:           c_expr                                                                  { $$ = $1; }
                                        n->args = list_make2($4, $6);
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n);
+                                       n->location = @5;
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2);
                                }
                        | a_expr NOT SIMILAR TO a_expr                  %prec SIMILAR
                                {
@@ -6662,7 +6678,8 @@ a_expr:           c_expr                                                                  { $$ = $1; }
                                        n->args = list_make2($5, (Node *) c);
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n);
+                                       n->location = @5;
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2);
                                }
                        | a_expr NOT SIMILAR TO a_expr ESCAPE a_expr
                                {
@@ -6671,7 +6688,8 @@ a_expr:           c_expr                                                                  { $$ = $1; }
                                        n->args = list_make2($5, $7);
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n);
+                                       n->location = @6;
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2);
                                }
 
                        /* NullTest clause
@@ -6733,7 +6751,7 @@ a_expr:           c_expr                                                                  { $$ = $1; }
                                }
                        | row OVERLAPS row
                                {
-                                       $$ = (Node *)makeOverlaps($1, $3);
+                                       $$ = (Node *)makeOverlaps($1, $3, @2);
                                }
                        | a_expr IS TRUE_P
                                {
@@ -6779,54 +6797,63 @@ a_expr:         c_expr                                                                  { $$ = $1; }
                                }
                        | a_expr IS DISTINCT FROM a_expr                        %prec IS
                                {
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5);
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
                                }
                        | a_expr IS NOT DISTINCT FROM a_expr            %prec IS
                                {
                                        $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
                                                                        (Node *) makeSimpleA_Expr(AEXPR_DISTINCT,
-                                                                                                                         "=", $1, $6));
+                                                                                                                         "=", $1, $6, @2),
+                                                                                        @2);
 
                                }
                        | a_expr IS OF '(' type_list ')'                        %prec IS
                                {
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5);
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2);
                                }
                        | a_expr IS NOT OF '(' type_list ')'            %prec IS
                                {
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6);
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2);
                                }
                        | a_expr BETWEEN opt_asymmetric b_expr AND b_expr               %prec BETWEEN
                                {
                                        $$ = (Node *) makeA_Expr(AEXPR_AND, NIL,
-                                               (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4),
-                                               (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6));
+                                               (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4, @2),
+                                               (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6, @2),
+                                                                                        @2);
                                }
                        | a_expr NOT BETWEEN opt_asymmetric b_expr AND b_expr   %prec BETWEEN
                                {
                                        $$ = (Node *) makeA_Expr(AEXPR_OR, NIL,
-                                               (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5),
-                                               (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7));
+                                               (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5, @2),
+                                               (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7, @2),
+                                                                                        @2);
                                }
                        | a_expr BETWEEN SYMMETRIC b_expr AND b_expr                    %prec BETWEEN
                                {
                                        $$ = (Node *) makeA_Expr(AEXPR_OR, NIL,
                                                (Node *) makeA_Expr(AEXPR_AND, NIL,
-                                                   (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4),
-                                                   (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6)),
+                                                   (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4, @2),
+                                                   (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6, @2),
+                                                                                       @2),
                                                (Node *) makeA_Expr(AEXPR_AND, NIL,
-                                                   (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $6),
-                                                   (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $4)));
+                                                   (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $6, @2),
+                                                   (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $4, @2),
+                                                                                       @2),
+                                                                                        @2);
                                }
                        | a_expr NOT BETWEEN SYMMETRIC b_expr AND b_expr                %prec BETWEEN
                                {
                                        $$ = (Node *) makeA_Expr(AEXPR_AND, NIL,
                                                (Node *) makeA_Expr(AEXPR_OR, NIL,
-                                                   (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5),
-                                                   (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7)),
+                                                   (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5, @2),
+                                                   (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7, @2),
+                                                                                       @2),
                                                (Node *) makeA_Expr(AEXPR_OR, NIL,
-                                                   (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $7),
-                                                   (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $5)));
+                                                   (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $7, @2),
+                                                   (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $5, @2),
+                                                                                       @2),
+                                                                                        @2);
                                }
                        | a_expr IN_P in_expr
                                {
@@ -6843,7 +6870,7 @@ a_expr:           c_expr                                                                  { $$ = $1; }
                                        else
                                        {
                                                /* generate scalar IN expression */
-                                               $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "=", $1, $3);
+                                               $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "=", $1, $3, @2);
                                        }
                                }
                        | a_expr NOT IN_P in_expr
@@ -6858,12 +6885,12 @@ a_expr:         c_expr                                                                  { $$ = $1; }
                                                n->testexpr = $1;
                                                n->operName = list_make1(makeString("="));
                                                /* Stick a NOT on top */
-                                               $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, (Node *) n);
+                                               $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, (Node *) n, @2);
                                        }
                                        else
                                        {
                                                /* generate scalar NOT IN expression */
-                                               $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "<>", $1, $4);
+                                               $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "<>", $1, $4, @2);
                                        }
                                }
                        | a_expr subquery_Op sub_type select_with_parens        %prec Op
@@ -6878,9 +6905,9 @@ a_expr:           c_expr                                                                  { $$ = $1; }
                        | a_expr subquery_Op sub_type '(' a_expr ')'            %prec Op
                                {
                                        if ($3 == ANY_SUBLINK)
-                                               $$ = (Node *) makeA_Expr(AEXPR_OP_ANY, $2, $1, $5);
+                                               $$ = (Node *) makeA_Expr(AEXPR_OP_ANY, $2, $1, $5, @2);
                                        else
-                                               $$ = (Node *) makeA_Expr(AEXPR_OP_ALL, $2, $1, $5);
+                                               $$ = (Node *) makeA_Expr(AEXPR_OP_ALL, $2, $1, $5, @2);
                                }
                        | UNIQUE select_with_parens
                                {
@@ -6913,49 +6940,49 @@ b_expr:         c_expr
                        | b_expr TYPECAST Typename
                                { $$ = makeTypeCast($1, $3); }
                        | '+' b_expr                                    %prec UMINUS
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
                        | '-' b_expr                                    %prec UMINUS
-                               { $$ = doNegate($2); }
+                               { $$ = doNegate($2, @1); }
                        | b_expr '+' b_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2); }
                        | b_expr '-' b_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2); }
                        | b_expr '*' b_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3, @2); }
                        | b_expr '/' b_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3, @2); }
                        | b_expr '%' b_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3, @2); }
                        | b_expr '^' b_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3, @2); }
                        | b_expr '<' b_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3, @2); }
                        | b_expr '>' b_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2); }
                        | b_expr '=' b_expr
-                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3); }
+                               { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); }
                        | b_expr qual_Op b_expr                         %prec Op
-                               { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3); }
+                               { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
                        | qual_Op b_expr                                        %prec Op
-                               { $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2); }
+                               { $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
                        | b_expr qual_Op                                        %prec POSTFIXOP
-                               { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL); }
+                               { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
                        | b_expr IS DISTINCT FROM b_expr                %prec IS
                                {
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5);
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
                                }
                        | b_expr IS NOT DISTINCT FROM b_expr    %prec IS
                                {
                                        $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL,
-                                               NULL, (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $6));
+                                               NULL, (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $6, @2), @2);
                                }
                        | b_expr IS OF '(' type_list ')'                %prec IS
                                {
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5);
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2);
                                }
                        | b_expr IS NOT OF '(' type_list ')'    %prec IS
                                {
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6);
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2);
                                }
                ;
 
@@ -7052,6 +7079,7 @@ func_expr:        func_name '(' ')'
                                        n->args = NIL;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | func_name '(' expr_list ')'
@@ -7061,6 +7089,7 @@ func_expr:        func_name '(' ')'
                                        n->args = $3;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | func_name '(' ALL expr_list ')'
@@ -7074,6 +7103,7 @@ func_expr:        func_name '(' ')'
                                         * "must be an aggregate", but there's no provision
                                         * for that in FuncCall at the moment.
                                         */
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | func_name '(' DISTINCT expr_list ')'
@@ -7083,6 +7113,7 @@ func_expr:        func_name '(' ')'
                                        n->args = $4;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = TRUE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | func_name '(' '*' ')'
@@ -7108,6 +7139,7 @@ func_expr:        func_name '(' ')'
                                        n->args = list_make1(star);
                                        n->agg_star = TRUE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | CURRENT_DATE
@@ -7196,6 +7228,7 @@ func_expr:        func_name '(' ')'
                                        n->args = NIL;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | CURRENT_TIMESTAMP '(' Iconst ')'
@@ -7331,6 +7364,7 @@ func_expr:        func_name '(' ')'
                                        n->args = NIL;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | CURRENT_USER
@@ -7340,6 +7374,7 @@ func_expr:        func_name '(' ')'
                                        n->args = NIL;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | SESSION_USER
@@ -7349,6 +7384,7 @@ func_expr:        func_name '(' ')'
                                        n->args = NIL;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | USER
@@ -7358,6 +7394,7 @@ func_expr:        func_name '(' ')'
                                        n->args = NIL;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | CAST '(' a_expr AS Typename ')'
@@ -7369,6 +7406,7 @@ func_expr:        func_name '(' ')'
                                        n->args = $3;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | OVERLAY '(' overlay_list ')'
@@ -7383,6 +7421,7 @@ func_expr:        func_name '(' ')'
                                        n->args = $3;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | POSITION '(' position_list ')'
@@ -7393,6 +7432,7 @@ func_expr:        func_name '(' ')'
                                        n->args = $3;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | SUBSTRING '(' substr_list ')'
@@ -7405,6 +7445,7 @@ func_expr:        func_name '(' ')'
                                        n->args = $3;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | TREAT '(' a_expr AS Typename ')'
@@ -7413,7 +7454,7 @@ func_expr:        func_name '(' ')'
                                         * which is defined to be a subtype of the original expression.
                                         * In SQL99, this is intended for use with structured UDTs,
                                         * but let's make this a generally useful form allowing stronger
-                                        * coersions than are handled by implicit casting.
+                                        * coercions than are handled by implicit casting.
                                         */
                                        FuncCall *n = makeNode(FuncCall);
                                        /* Convert SystemTypeName() to SystemFuncName() even though
@@ -7421,6 +7462,9 @@ func_expr:        func_name '(' ')'
                                         */
                                        n->funcname = SystemFuncName(((Value *)llast($5->names))->val.str);
                                        n->args = list_make1($3);
+                                       n->agg_star = FALSE;
+                                       n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | TRIM '(' BOTH trim_list ')'
@@ -7433,6 +7477,7 @@ func_expr:        func_name '(' ')'
                                        n->args = $4;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | TRIM '(' LEADING trim_list ')'
@@ -7442,6 +7487,7 @@ func_expr:        func_name '(' ')'
                                        n->args = $4;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | TRIM '(' TRAILING trim_list ')'
@@ -7451,6 +7497,7 @@ func_expr:        func_name '(' ')'
                                        n->args = $4;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | TRIM '(' trim_list ')'
@@ -7460,6 +7507,7 @@ func_expr:        func_name '(' ')'
                                        n->args = $3;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | CONVERT '(' a_expr USING any_name ')'
@@ -7474,6 +7522,7 @@ func_expr:        func_name '(' ')'
                                        n->args = list_make2($3, c);
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | CONVERT '(' expr_list ')'
@@ -7483,11 +7532,12 @@ func_expr:      func_name '(' ')'
                                        n->args = $3;
                                        n->agg_star = FALSE;
                                        n->agg_distinct = FALSE;
+                                       n->location = @1;
                                        $$ = (Node *)n;
                                }
                        | NULLIF '(' a_expr ',' a_expr ')'
                                {
-                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_NULLIF, "=", $3, $5);
+                                       $$ = (Node *) makeSimpleA_Expr(AEXPR_NULLIF, "=", $3, $5, @1);
                                }
                        | COALESCE '(' expr_list ')'
                                {
@@ -7797,11 +7847,11 @@ case_arg:       a_expr                                                                  { $$ = $1; }
  */
 columnref:     relation_name
                                {
-                                       $$ = makeColumnRef($1, NIL);
+                                       $$ = makeColumnRef($1, NIL, @1);
                                }
                        | relation_name indirection
                                {
-                                       $$ = makeColumnRef($1, $2);
+                                       $$ = makeColumnRef($1, $2, @1);
                                }
                ;
 
@@ -7875,6 +7925,7 @@ target_el:        a_expr AS ColLabel
                                {
                                        ColumnRef *n = makeNode(ColumnRef);
                                        n->fields = list_make1(makeString("*"));
+                                       n->location = @1;
 
                                        $$ = makeNode(ResTarget);
                                        $$->name = NULL;
@@ -8585,7 +8636,7 @@ SpecialRuleRelation:
 %%
 
 static Node *
-makeColumnRef(char *relname, List *indirection)
+makeColumnRef(char *relname, List *indirection, int location)
 {
        /*
         * Generate a ColumnRef node, with an A_Indirection node added if there
@@ -8597,6 +8648,7 @@ makeColumnRef(char *relname, List *indirection)
        int             nfields = 0;
        ListCell *l;
 
+       c->location = location;
        foreach(l, indirection)
        {
                if (IsA(lfirst(l), A_Indices))
@@ -8750,9 +8802,9 @@ makeRowNullTest(NullTestType test, RowExpr *row)
                if (result == NULL)
                        result = (Node *) n;
                else if (test == IS_NOT_NULL)
-                       result = (Node *) makeA_Expr(AEXPR_OR, NIL, result, (Node *)n);
+                       result = (Node *) makeA_Expr(AEXPR_OR, NIL, result, (Node *)n, -1);
                else
-                       result = (Node *) makeA_Expr(AEXPR_AND, NIL, result, (Node *)n);
+                       result = (Node *) makeA_Expr(AEXPR_AND, NIL, result, (Node *)n, -1);
        }
 
        if (result == NULL)
@@ -8768,9 +8820,10 @@ makeRowNullTest(NullTestType test, RowExpr *row)
  * Create and populate a FuncCall node to support the OVERLAPS operator.
  */
 static FuncCall *
-makeOverlaps(List *largs, List *rargs)
+makeOverlaps(List *largs, List *rargs, int location)
 {
        FuncCall *n = makeNode(FuncCall);
+
        n->funcname = SystemFuncName("overlaps");
        if (list_length(largs) == 1)
                largs = lappend(largs, largs);
@@ -8787,6 +8840,7 @@ makeOverlaps(List *largs, List *rargs)
        n->args = list_concat(largs, rargs);
        n->agg_star = FALSE;
        n->agg_distinct = FALSE;
+       n->location = location;
        return n;
 }
 
@@ -8944,6 +8998,7 @@ SystemTypeName(char *name)
 
        n->names = list_make2(makeString("pg_catalog"), makeString(name));
        n->typmod = -1;
+       n->location = -1;
        return n;
 }
 
@@ -8987,7 +9042,7 @@ exprIsNullConstant(Node *arg)
  * until we know what the desired type is.
  */
 static Node *
-doNegate(Node *n)
+doNegate(Node *n, int location)
 {
        if (IsA(n, A_Const))
        {
@@ -9005,7 +9060,7 @@ doNegate(Node *n)
                }
        }
 
-       return (Node *) makeSimpleA_Expr(AEXPR_OP, "-", NULL, n);
+       return (Node *) makeSimpleA_Expr(AEXPR_OP, "-", NULL, n, location);
 }
 
 static void
index fdc2e41b3aaf03a5f0e604d83baf3e857be06392..4384a4eaab83fce99cd21736fc8e62f293a4cf0d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.147 2006/03/05 21:34:34 neilc Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.148 2006/03/14 22:48:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -303,7 +303,9 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
                Node       *rvar = (Node *) lfirst(rvars);
                A_Expr     *e;
 
-               e = makeSimpleA_Expr(AEXPR_OP, "=", copyObject(lvar), copyObject(rvar));
+               e = makeSimpleA_Expr(AEXPR_OP, "=",
+                                                        copyObject(lvar), copyObject(rvar),
+                                                        -1);
 
                if (result == NULL)
                        result = (Node *) e;
@@ -311,7 +313,7 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
                {
                        A_Expr     *a;
 
-                       a = makeA_Expr(AEXPR_AND, NIL, result, (Node *) e);
+                       a = makeA_Expr(AEXPR_AND, NIL, result, (Node *) e, -1);
                        result = (Node *) a;
                }
        }
@@ -1182,6 +1184,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
                list_length(((ColumnRef *) node)->fields) == 1)
        {
                char       *name = strVal(linitial(((ColumnRef *) node)->fields));
+               int                     location = ((ColumnRef *) node)->location;
 
                if (clause == GROUP_CLAUSE)
                {
@@ -1201,7 +1204,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
                         * breaks no cases that are legal per spec, and it seems a more
                         * self-consistent behavior.
                         */
-                       if (colNameToVar(pstate, name, true) != NULL)
+                       if (colNameToVar(pstate, name, true, location) != NULL)
                                name = NULL;
                }
 
@@ -1225,7 +1228,8 @@ findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause)
                                                         * construct, eg ORDER BY
                                                         */
                                                                         errmsg("%s \"%s\" is ambiguous",
-                                                                                       clauseText[clause], name)));
+                                                                                       clauseText[clause], name),
+                                                                        parser_errposition(pstate, location)));
                                        }
                                        else
                                                target_result = tle;
index ab4d681fdfd66ce625f1e8c85961d18e4345dc98..cae682c9e775ea271255a1205ff8052fa902df14 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.190 2006/03/05 15:58:33 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.191 2006/03/14 22:48:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -57,18 +57,18 @@ static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m);
 static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
 static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
 static Node *transformWholeRowRef(ParseState *pstate, char *schemaname,
-                                        char *relname);
+                                        char *relname, int location);
 static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b);
 static Node *transformIndirection(ParseState *pstate, Node *basenode,
                                         List *indirection);
 static Node *typecast_expression(ParseState *pstate, Node *expr,
                                        TypeName *typename);
 static Node *make_row_comparison_op(ParseState *pstate, List *opname,
-                                                                       List *largs, List *rargs);
+                                                                       List *largs, List *rargs, int location);
 static Node *make_row_distinct_op(ParseState *pstate, List *opname,
-                                        RowExpr *lrow, RowExpr *rrow);
+                                        RowExpr *lrow, RowExpr *rrow, int location);
 static Expr *make_distinct_op(ParseState *pstate, List *opname,
-                                Node *ltree, Node *rtree);
+                                Node *ltree, Node *rtree, int location);
 
 
 /*
@@ -308,7 +308,8 @@ transformIndirection(ParseState *pstate, Node *basenode, List *indirection)
                        result = ParseFuncOrColumn(pstate,
                                                                           list_make1(n),
                                                                           list_make1(result),
-                                                                          false, false, true);
+                                                                          false, false, true,
+                                                                          -1);
                }
        }
        /* process trailing subscripts, if any */
@@ -361,7 +362,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
                                char       *name = strVal(linitial(cref->fields));
 
                                /* Try to identify as an unqualified column */
-                               node = colNameToVar(pstate, name, false);
+                               node = colNameToVar(pstate, name, false, cref->location);
 
                                if (node == NULL)
                                {
@@ -391,12 +392,14 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
                                         */
                                        if (refnameRangeTblEntry(pstate, NULL, name,
                                                                                         &levels_up) != NULL)
-                                               node = transformWholeRowRef(pstate, NULL, name);
+                                               node = transformWholeRowRef(pstate, NULL, name,
+                                                                                                       cref->location);
                                        else
                                                ereport(ERROR,
                                                                (errcode(ERRCODE_UNDEFINED_COLUMN),
                                                                 errmsg("column \"%s\" does not exist",
-                                                                               name)));
+                                                                               name),
+                                                                parser_errposition(pstate, cref->location)));
                                }
                                break;
                        }
@@ -408,12 +411,14 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
                                /* Whole-row reference? */
                                if (strcmp(name2, "*") == 0)
                                {
-                                       node = transformWholeRowRef(pstate, NULL, name1);
+                                       node = transformWholeRowRef(pstate, NULL, name1,
+                                                                                               cref->location);
                                        break;
                                }
 
                                /* Try to identify as a once-qualified column */
-                               node = qualifiedNameToVar(pstate, NULL, name1, name2, true);
+                               node = qualifiedNameToVar(pstate, NULL, name1, name2, true,
+                                                                                 cref->location);
                                if (node == NULL)
                                {
                                        /*
@@ -421,11 +426,13 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
                                         * it as a function call.  Here, we will create an
                                         * implicit RTE for tables not already entered.
                                         */
-                                       node = transformWholeRowRef(pstate, NULL, name1);
+                                       node = transformWholeRowRef(pstate, NULL, name1,
+                                                                                               cref->location);
                                        node = ParseFuncOrColumn(pstate,
                                                                                         list_make1(makeString(name2)),
                                                                                         list_make1(node),
-                                                                                        false, false, true);
+                                                                                        false, false, true,
+                                                                                        cref->location);
                                }
                                break;
                        }
@@ -438,20 +445,24 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
                                /* Whole-row reference? */
                                if (strcmp(name3, "*") == 0)
                                {
-                                       node = transformWholeRowRef(pstate, name1, name2);
+                                       node = transformWholeRowRef(pstate, name1, name2,
+                                                                                               cref->location);
                                        break;
                                }
 
                                /* Try to identify as a twice-qualified column */
-                               node = qualifiedNameToVar(pstate, name1, name2, name3, true);
+                               node = qualifiedNameToVar(pstate, name1, name2, name3, true,
+                                                                                 cref->location);
                                if (node == NULL)
                                {
                                        /* Try it as a function call */
-                                       node = transformWholeRowRef(pstate, name1, name2);
+                                       node = transformWholeRowRef(pstate, name1, name2,
+                                                                                               cref->location);
                                        node = ParseFuncOrColumn(pstate,
                                                                                         list_make1(makeString(name3)),
                                                                                         list_make1(node),
-                                                                                        false, false, true);
+                                                                                        false, false, true,
+                                                                                        cref->location);
                                }
                                break;
                        }
@@ -469,25 +480,30 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
                                        ereport(ERROR,
                                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                                         errmsg("cross-database references are not implemented: %s",
-                                                                       NameListToString(cref->fields))));
+                                                                       NameListToString(cref->fields)),
+                                                        parser_errposition(pstate, cref->location)));
 
                                /* Whole-row reference? */
                                if (strcmp(name4, "*") == 0)
                                {
-                                       node = transformWholeRowRef(pstate, name2, name3);
+                                       node = transformWholeRowRef(pstate, name2, name3,
+                                                                                               cref->location);
                                        break;
                                }
 
                                /* Try to identify as a twice-qualified column */
-                               node = qualifiedNameToVar(pstate, name2, name3, name4, true);
+                               node = qualifiedNameToVar(pstate, name2, name3, name4, true,
+                                                                                 cref->location);
                                if (node == NULL)
                                {
                                        /* Try it as a function call */
-                                       node = transformWholeRowRef(pstate, name2, name3);
+                                       node = transformWholeRowRef(pstate, name2, name3,
+                                                                                               cref->location);
                                        node = ParseFuncOrColumn(pstate,
                                                                                         list_make1(makeString(name4)),
                                                                                         list_make1(node),
-                                                                                        false, false, true);
+                                                                                        false, false, true,
+                                                                                        cref->location);
                                }
                                break;
                        }
@@ -495,7 +511,8 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
                        ereport(ERROR,
                                        (errcode(ERRCODE_SYNTAX_ERROR),
                                errmsg("improper qualified name (too many dotted names): %s",
-                                          NameListToString(cref->fields))));
+                                          NameListToString(cref->fields)),
+                                        parser_errposition(pstate, cref->location)));
                        node = NULL;            /* keep compiler quiet */
                        break;
        }
@@ -614,7 +631,8 @@ transformAExprOp(ParseState *pstate, A_Expr *a)
                result = make_row_comparison_op(pstate,
                                                                                a->name,
                                                                                ((RowExpr *) lexpr)->args,
-                                                                               ((RowExpr *) rexpr)->args);
+                                                                               ((RowExpr *) rexpr)->args,
+                                                                               a->location);
        }
        else
        {
@@ -625,7 +643,8 @@ transformAExprOp(ParseState *pstate, A_Expr *a)
                result = (Node *) make_op(pstate,
                                                                  a->name,
                                                                  lexpr,
-                                                                 rexpr);
+                                                                 rexpr,
+                                                                 a->location);
        }
 
        return result;
@@ -678,7 +697,8 @@ transformAExprOpAny(ParseState *pstate, A_Expr *a)
                                                                                 a->name,
                                                                                 true,
                                                                                 lexpr,
-                                                                                rexpr);
+                                                                                rexpr,
+                                                                                a->location);
 }
 
 static Node *
@@ -691,7 +711,8 @@ transformAExprOpAll(ParseState *pstate, A_Expr *a)
                                                                                 a->name,
                                                                                 false,
                                                                                 lexpr,
-                                                                                rexpr);
+                                                                                rexpr,
+                                                                                a->location);
 }
 
 static Node *
@@ -706,7 +727,8 @@ transformAExprDistinct(ParseState *pstate, A_Expr *a)
                /* "row op row" */
                return make_row_distinct_op(pstate, a->name,
                                                                        (RowExpr *) lexpr,
-                                                                       (RowExpr *) rexpr);
+                                                                       (RowExpr *) rexpr,
+                                                                       a->location);
        }
        else
        {
@@ -714,7 +736,8 @@ transformAExprDistinct(ParseState *pstate, A_Expr *a)
                return (Node *) make_distinct_op(pstate,
                                                                                 a->name,
                                                                                 lexpr,
-                                                                                rexpr);
+                                                                                rexpr,
+                                                                                a->location);
        }
 }
 
@@ -728,11 +751,13 @@ transformAExprNullIf(ParseState *pstate, A_Expr *a)
        result = (Node *) make_op(pstate,
                                                          a->name,
                                                          lexpr,
-                                                         rexpr);
+                                                         rexpr,
+                                                         a->location);
        if (((OpExpr *) result)->opresulttype != BOOLOID)
                ereport(ERROR,
                                (errcode(ERRCODE_DATATYPE_MISMATCH),
-                                errmsg("NULLIF requires = operator to yield boolean")));
+                                errmsg("NULLIF requires = operator to yield boolean"),
+                                parser_errposition(pstate, a->location)));
 
        /*
         * We rely on NullIfExpr and OpExpr being the same struct
@@ -758,7 +783,7 @@ transformAExprOf(ParseState *pstate, A_Expr *a)
        ltype = exprType(lexpr);
        foreach(telem, (List *) a->rexpr)
        {
-               rtype = LookupTypeName(lfirst(telem));
+               rtype = typenameTypeId(pstate, lfirst(telem));
                matched = (rtype == ltype);
                if (matched)
                        break;
@@ -864,7 +889,8 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
                                                                                                 a->name,
                                                                                                 useOr,
                                                                                                 lexpr,
-                                                                                                (Node *) newa);
+                                                                                                (Node *) newa,
+                                                                                                a->location);
                }
        }
 
@@ -883,17 +909,20 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
                                !IsA(rexpr, RowExpr))
                                ereport(ERROR,
                                                (errcode(ERRCODE_SYNTAX_ERROR),
-                                                errmsg("arguments of row IN must all be row expressions")));
+                                                errmsg("arguments of row IN must all be row expressions"),
+                                                parser_errposition(pstate, a->location)));
                        cmp = make_row_comparison_op(pstate,
                                                                                 a->name,
                                                                                 (List *) copyObject(((RowExpr *) lexpr)->args),
-                                                                                ((RowExpr *) rexpr)->args);
+                                                                                ((RowExpr *) rexpr)->args,
+                                                                                a->location);
                }
                else
                        cmp = (Node *) make_op(pstate,
                                                                   a->name,
                                                                   copyObject(lexpr),
-                                                                  rexpr);
+                                                                  rexpr,
+                                                                  a->location);
 
                cmp = coerce_to_boolean(pstate, cmp, "IN");
                if (result == NULL)
@@ -931,7 +960,8 @@ transformFuncCall(ParseState *pstate, FuncCall *fn)
                                                         targs,
                                                         fn->agg_star,
                                                         fn->agg_distinct,
-                                                        false);
+                                                        false,
+                                                        fn->location);
 }
 
 static Node *
@@ -994,7 +1024,8 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
                        /* shorthand form was specified, so expand... */
                        warg = (Node *) makeSimpleA_Expr(AEXPR_OP, "=",
                                                                                         (Node *) placeholder,
-                                                                                        warg);
+                                                                                        warg,
+                                                                                        -1);
                }
                neww->expr = (Expr *) transformExpr(pstate, warg);
 
@@ -1173,7 +1204,8 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
                sublink->testexpr = make_row_comparison_op(pstate,
                                                                                                   sublink->operName,
                                                                                                   left_list,
-                                                                                                  right_list);
+                                                                                                  right_list,
+                                                                                                  -1);
        }
 
        return result;
@@ -1394,7 +1426,8 @@ transformBooleanTest(ParseState *pstate, BooleanTest *b)
  * a rowtype; either a named composite type, or RECORD.
  */
 static Node *
-transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname)
+transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
+                                        int location)
 {
        Node       *result;
        RangeTblEntry *rte;
@@ -1408,7 +1441,8 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname)
                                                           &sublevels_up);
 
        if (rte == NULL)
-               rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname));
+               rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname),
+                                                        location);
 
        vnum = RTERangeTablePosn(pstate, rte, &sublevels_up);
 
@@ -1877,7 +1911,7 @@ typecast_expression(ParseState *pstate, Node *expr, TypeName *typename)
        Oid                     inputType = exprType(expr);
        Oid                     targetType;
 
-       targetType = typenameTypeId(typename);
+       targetType = typenameTypeId(pstate, typename);
 
        if (inputType == InvalidOid)
                return expr;                    /* do nothing if NULL input */
@@ -1891,7 +1925,8 @@ typecast_expression(ParseState *pstate, Node *expr, TypeName *typename)
                                (errcode(ERRCODE_CANNOT_COERCE),
                                 errmsg("cannot cast type %s to %s",
                                                format_type_be(inputType),
-                                               format_type_be(targetType))));
+                                               format_type_be(targetType)),
+                                parser_errposition(pstate, typename->location)));
 
        return expr;
 }
@@ -1910,7 +1945,7 @@ typecast_expression(ParseState *pstate, Node *expr, TypeName *typename)
  */
 static Node *
 make_row_comparison_op(ParseState *pstate, List *opname,
-                                          List *largs, List *rargs)
+                                          List *largs, List *rargs, int location)
 {
        RowCompareExpr *rcexpr;
        RowCompareType rctype;
@@ -1929,7 +1964,8 @@ make_row_comparison_op(ParseState *pstate, List *opname,
        if (nopers != list_length(rargs))
                ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("unequal number of entries in row expressions")));
+                                errmsg("unequal number of entries in row expressions"),
+                                parser_errposition(pstate, location)));
 
        /*
         * We can't compare zero-length rows because there is no principled
@@ -1938,7 +1974,8 @@ make_row_comparison_op(ParseState *pstate, List *opname,
        if (nopers == 0)
                ereport(ERROR,
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                errmsg("cannot compare rows of zero length")));
+                                errmsg("cannot compare rows of zero length"),
+                                parser_errposition(pstate, location)));
 
        /*
         * Identify all the pairwise operators, using make_op so that
@@ -1951,7 +1988,7 @@ make_row_comparison_op(ParseState *pstate, List *opname,
                Node       *rarg = (Node *) lfirst(r);
                OpExpr     *cmp;
 
-               cmp = (OpExpr *) make_op(pstate, opname, larg, rarg);
+               cmp = (OpExpr *) make_op(pstate, opname, larg, rarg, location);
                Assert(IsA(cmp, OpExpr));
 
                /*
@@ -1964,11 +2001,13 @@ make_row_comparison_op(ParseState *pstate, List *opname,
                                        (errcode(ERRCODE_DATATYPE_MISMATCH),
                                         errmsg("row comparison operator must yield type boolean, "
                                                        "not type %s",
-                                                       format_type_be(cmp->opresulttype))));
+                                                       format_type_be(cmp->opresulttype)),
+                                        parser_errposition(pstate, location)));
                if (expression_returns_set((Node *) cmp))
                        ereport(ERROR,
                                        (errcode(ERRCODE_DATATYPE_MISMATCH),
-                                        errmsg("row comparison operator must not return a set")));
+                                        errmsg("row comparison operator must not return a set"),
+                                        parser_errposition(pstate, location)));
                opexprs = lappend(opexprs, cmp);
        }
 
@@ -2021,7 +2060,8 @@ make_row_comparison_op(ParseState *pstate, List *opname,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                         errmsg("could not determine interpretation of row comparison operator %s",
                                                        strVal(llast(opname))),
-                                        errhint("Row comparison operators must be associated with btree operator classes.")));
+                                        errhint("Row comparison operators must be associated with btree operator classes."),
+                                        parser_errposition(pstate, location)));
                        rctype = 0;                     /* keep compiler quiet */
                        break;
                case BMS_SINGLETON:
@@ -2069,7 +2109,8 @@ make_row_comparison_op(ParseState *pstate, List *opname,
                                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                                         errmsg("could not determine interpretation of row comparison operator %s",
                                                                        strVal(llast(opname))),
-                                                        errdetail("There are multiple equally-plausible candidates.")));
+                                                        errdetail("There are multiple equally-plausible candidates."),
+                                                        parser_errposition(pstate, location)));
                                break;
                        }
        }
@@ -2120,7 +2161,8 @@ make_row_comparison_op(ParseState *pstate, List *opname,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                         errmsg("could not determine interpretation of row comparison operator %s",
                                                        strVal(llast(opname))),
-                                        errdetail("There are multiple equally-plausible candidates.")));
+                                        errdetail("There are multiple equally-plausible candidates."),
+                                        parser_errposition(pstate, location)));
        }
 
        /*
@@ -2158,7 +2200,8 @@ make_row_comparison_op(ParseState *pstate, List *opname,
  */
 static Node *
 make_row_distinct_op(ParseState *pstate, List *opname,
-                                        RowExpr *lrow, RowExpr *rrow)
+                                        RowExpr *lrow, RowExpr *rrow,
+                                        int location)
 {
        Node       *result = NULL;
        List       *largs = lrow->args;
@@ -2169,7 +2212,8 @@ make_row_distinct_op(ParseState *pstate, List *opname,
        if (list_length(largs) != list_length(rargs))
                ereport(ERROR,
                                (errcode(ERRCODE_SYNTAX_ERROR),
-                                errmsg("unequal number of entries in row expressions")));
+                                errmsg("unequal number of entries in row expressions"),
+                                parser_errposition(pstate, location)));
 
        forboth(l, largs, r, rargs)
        {
@@ -2177,7 +2221,7 @@ make_row_distinct_op(ParseState *pstate, List *opname,
                Node       *rarg = (Node *) lfirst(r);
                Node       *cmp;
 
-               cmp = (Node *) make_distinct_op(pstate, opname, larg, rarg);
+               cmp = (Node *) make_distinct_op(pstate, opname, larg, rarg, location);
                if (result == NULL)
                        result = cmp;
                else
@@ -2198,15 +2242,17 @@ make_row_distinct_op(ParseState *pstate, List *opname,
  * make the node for an IS DISTINCT FROM operator
  */
 static Expr *
-make_distinct_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree)
+make_distinct_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
+                                int location)
 {
        Expr       *result;
 
-       result = make_op(pstate, opname, ltree, rtree);
+       result = make_op(pstate, opname, ltree, rtree, location);
        if (((OpExpr *) result)->opresulttype != BOOLOID)
                ereport(ERROR,
                                (errcode(ERRCODE_DATATYPE_MISMATCH),
-                  errmsg("IS DISTINCT FROM requires = operator to yield boolean")));
+                                errmsg("IS DISTINCT FROM requires = operator to yield boolean"),
+                                parser_errposition(pstate, location)));
 
        /*
         * We rely on DistinctExpr and OpExpr being same struct
index d6b4307a61a7989a932e06101dbc4df01856f683..35e826881fd1534a2a46ba214904c81811ee8099 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.184 2006/03/05 15:58:33 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.185 2006/03/14 22:48:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,8 +34,9 @@
 
 
 static Node *ParseComplexProjection(ParseState *pstate, char *funcname,
-                                          Node *first_arg);
-static void unknown_attribute(ParseState *pstate, Node *relref, char *attname);
+                                          Node *first_arg, int location);
+static void unknown_attribute(ParseState *pstate, Node *relref, char *attname,
+                                                         int location);
 
 
 /*
@@ -59,7 +60,8 @@ static void unknown_attribute(ParseState *pstate, Node *relref, char *attname);
  */
 Node *
 ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
-                                 bool agg_star, bool agg_distinct, bool is_column)
+                                 bool agg_star, bool agg_distinct, bool is_column,
+                                 int location)
 {
        Oid                     rettype;
        Oid                     funcid;
@@ -83,7 +85,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
                ereport(ERROR,
                                (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
                                 errmsg("cannot pass more than %d arguments to a function",
-                                               FUNC_MAX_ARGS)));
+                                               FUNC_MAX_ARGS),
+                                parser_errposition(pstate, location)));
 
        /*
         * Extract arg type info in preparation for function lookup.
@@ -131,7 +134,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
                {
                        retval = ParseComplexProjection(pstate,
                                                                                        strVal(linitial(funcname)),
-                                                                                       first_arg);
+                                                                                       first_arg,
+                                                                                       location);
                        if (retval)
                                return retval;
 
@@ -174,12 +178,14 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
                                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                           errmsg("%s(*) specified, but %s is not an aggregate function",
                                          NameListToString(funcname),
-                                         NameListToString(funcname))));
+                                         NameListToString(funcname)),
+                                        parser_errposition(pstate, location)));
                if (agg_distinct)
                        ereport(ERROR,
                                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                        errmsg("DISTINCT specified, but %s is not an aggregate function",
-                                  NameListToString(funcname))));
+                                  NameListToString(funcname)),
+                                        parser_errposition(pstate, location)));
        }
        else if (fdresult != FUNCDETAIL_AGGREGATE)
        {
@@ -193,7 +199,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
                {
                        Assert(nargs == 1);
                        Assert(list_length(funcname) == 1);
-                       unknown_attribute(pstate, first_arg, strVal(linitial(funcname)));
+                       unknown_attribute(pstate, first_arg, strVal(linitial(funcname)),
+                                                         location);
                }
 
                /*
@@ -206,7 +213,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
                                                        func_signature_string(funcname, nargs,
                                                                                                  actual_arg_types)),
                                         errhint("Could not choose a best candidate function. "
-                                                        "You may need to add explicit type casts.")));
+                                                        "You may need to add explicit type casts."),
+                                        parser_errposition(pstate, location)));
                else
                        ereport(ERROR,
                                        (errcode(ERRCODE_UNDEFINED_FUNCTION),
@@ -214,7 +222,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
                                                        func_signature_string(funcname, nargs,
                                                                                                  actual_arg_types)),
                        errhint("No function matches the given name and argument types. "
-                                       "You may need to add explicit type casts.")));
+                                       "You may need to add explicit type casts."),
+                                        parser_errposition(pstate, location)));
        }
 
        /*
@@ -262,7 +271,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
                if (retset)
                        ereport(ERROR,
                                        (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
-                                        errmsg("aggregates may not return sets")));
+                                        errmsg("aggregates may not return sets"),
+                                        parser_errposition(pstate, location)));
        }
 
        return retval;
@@ -726,11 +736,9 @@ func_get_detail(List *funcname,
                if (nargs == 1 && fargs != NIL)
                {
                        Oid                     targetType;
-                       TypeName   *tn = makeNode(TypeName);
 
-                       tn->names = funcname;
-                       tn->typmod = -1;
-                       targetType = LookupTypeName(tn);
+                       targetType = LookupTypeName(NULL,
+                                                                               makeTypeNameFromNameList(funcname));
                        if (OidIsValid(targetType) &&
                                !ISCOMPLEX(targetType))
                        {
@@ -953,7 +961,8 @@ make_fn_arguments(ParseState *pstate,
  *       transformed expression tree.  If not, return NULL.
  */
 static Node *
-ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg)
+ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg,
+                                          int location)
 {
        TupleDesc       tupdesc;
        int                     i;
@@ -977,7 +986,7 @@ ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg)
                                                                         ((Var *) first_arg)->varno,
                                                                         ((Var *) first_arg)->varlevelsup);
                /* Return a Var if funcname matches a column, else NULL */
-               return scanRTEForColumn(pstate, rte, funcname);
+               return scanRTEForColumn(pstate, rte, funcname, location);
        }
 
        /*
@@ -1019,7 +1028,8 @@ ParseComplexProjection(ParseState *pstate, char *funcname, Node *first_arg)
  * helper routine for delivering "column does not exist" error message
  */
 static void
-unknown_attribute(ParseState *pstate, Node *relref, char *attname)
+unknown_attribute(ParseState *pstate, Node *relref, char *attname,
+                                 int location)
 {
        RangeTblEntry *rte;
 
@@ -1033,7 +1043,8 @@ unknown_attribute(ParseState *pstate, Node *relref, char *attname)
                ereport(ERROR,
                                (errcode(ERRCODE_UNDEFINED_COLUMN),
                                 errmsg("column %s.%s does not exist",
-                                               rte->eref->aliasname, attname)));
+                                               rte->eref->aliasname, attname),
+                                parser_errposition(pstate, location)));
        }
        else
        {
@@ -1044,18 +1055,21 @@ unknown_attribute(ParseState *pstate, Node *relref, char *attname)
                        ereport(ERROR,
                                        (errcode(ERRCODE_UNDEFINED_COLUMN),
                                         errmsg("column \"%s\" not found in data type %s",
-                                                       attname, format_type_be(relTypeId))));
+                                                       attname, format_type_be(relTypeId)),
+                                        parser_errposition(pstate, location)));
                else if (relTypeId == RECORDOID)
                        ereport(ERROR,
                                        (errcode(ERRCODE_UNDEFINED_COLUMN),
                           errmsg("could not identify column \"%s\" in record data type",
-                                         attname)));
+                                         attname),
+                                        parser_errposition(pstate, location)));
                else
                        ereport(ERROR,
                                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                         errmsg("column notation .%s applied to type %s, "
                                                        "which is not a composite type",
-                                                       attname, format_type_be(relTypeId))));
+                                                       attname, format_type_be(relTypeId)),
+                                        parser_errposition(pstate, location)));
        }
 }
 
@@ -1219,7 +1233,7 @@ LookupFuncNameTypeNames(List *funcname, List *argtypes, bool noError)
        {
                TypeName   *t = (TypeName *) lfirst(args_item);
 
-               argoids[i] = LookupTypeName(t);
+               argoids[i] = LookupTypeName(NULL, t);
 
                if (!OidIsValid(argoids[i]))
                        ereport(ERROR,
index 2ac869c9fcde597fc6abbd6e383ce52625123e92..23d73a13f251387cea93f6c4aafec7945abb10b7 100644 (file)
@@ -8,13 +8,14 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.91 2006/03/05 15:58:34 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_node.c,v 1.92 2006/03/14 22:48:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "catalog/pg_type.h"
+#include "mb/pg_wchar.h"
 #include "nodes/makefuncs.h"
 #include "parser/parsetree.h"
 #include "parser/parse_coerce.h"
@@ -44,12 +45,46 @@ make_parsestate(ParseState *parentParseState)
        pstate->p_next_resno = 1;
 
        if (parentParseState)
+       {
+               pstate->p_sourcetext = parentParseState->p_sourcetext;
                pstate->p_variableparams = parentParseState->p_variableparams;
+       }
 
        return pstate;
 }
 
 
+/*
+ * parser_errposition
+ *             Report a parse-analysis-time cursor position, if possible.
+ *
+ * This is expected to be used within an ereport() call.  The return value
+ * is a dummy (always 0, in fact).
+ *
+ * The locations stored in raw parsetrees are byte offsets into the source
+ * string.  We have to convert them to 1-based character indexes for reporting
+ * to clients.  (We do things this way to avoid unnecessary overhead in the
+ * normal non-error case: computing character indexes would be much more
+ * expensive than storing token offsets.)
+ */
+int
+parser_errposition(ParseState *pstate, int location)
+{
+       int             pos;
+
+       /* No-op if location was not provided */
+       if (location < 0)
+               return 0;
+       /* Can't do anything if source text is not available */
+       if (pstate == NULL || pstate->p_sourcetext == NULL)
+               return 0;
+       /* Convert offset to character number */
+       pos = pg_mbstrlen_with_len(pstate->p_sourcetext, location) + 1;
+       /* And pass it to the ereport mechanism */
+       return errposition(pos);
+}
+
+
 /*
  * make_var
  *             Build a Var node for an attribute identified by RTE and attrno
index 2bd65b2e126d24a69e5890d27affdb3f68df9d5a..e483372e8520a92c2d438cb4efe9c41f6fd62ad3 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.85 2006/03/05 15:58:34 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_oper.c,v 1.86 2006/03/14 22:48:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -37,8 +37,9 @@ static FuncDetailCode oper_select_candidate(int nargs,
                                          Oid *operOid);
 static const char *op_signature_string(List *op, char oprkind,
                                        Oid arg1, Oid arg2);
-static void op_error(List *op, char oprkind, Oid arg1, Oid arg2,
-                FuncDetailCode fdresult);
+static void op_error(ParseState *pstate, List *op, char oprkind,
+                                        Oid arg1, Oid arg2,
+                                        FuncDetailCode fdresult, int location);
 static Expr *make_op_expr(ParseState *pstate, Operator op,
                         Node *ltree, Node *rtree,
                         Oid ltypeId, Oid rtypeId);
@@ -56,10 +57,12 @@ static Expr *make_op_expr(ParseState *pstate, Operator op,
  * namespace search path.
  *
  * If the operator is not found, we return InvalidOid if noError is true,
- * else raise an error.
+ * else raise an error.  pstate and location are used only to report the
+ * error position; pass NULL/-1 if not available.
  */
 Oid
-LookupOperName(List *opername, Oid oprleft, Oid oprright, bool noError)
+LookupOperName(ParseState *pstate, List *opername, Oid oprleft, Oid oprright,
+                          bool noError, int location)
 {
        FuncCandidateList clist;
        char            oprkind;
@@ -86,7 +89,8 @@ LookupOperName(List *opername, Oid oprleft, Oid oprright, bool noError)
                                (errcode(ERRCODE_UNDEFINED_FUNCTION),
                                 errmsg("operator does not exist: %s",
                                                op_signature_string(opername, oprkind,
-                                                                                       oprleft, oprright))));
+                                                                                       oprleft, oprright)),
+                                parser_errposition(pstate, location)));
 
        return InvalidOid;
 }
@@ -99,8 +103,9 @@ LookupOperName(List *opername, Oid oprleft, Oid oprright, bool noError)
  * Pass oprleft = NULL for a prefix op, oprright = NULL for a postfix op.
  */
 Oid
-LookupOperNameTypeNames(List *opername, TypeName *oprleft,
-                                               TypeName *oprright, bool noError)
+LookupOperNameTypeNames(ParseState *pstate, List *opername,
+                                               TypeName *oprleft, TypeName *oprright,
+                                               bool noError, int location)
 {
        Oid                     leftoid,
                                rightoid;
@@ -108,27 +113,15 @@ LookupOperNameTypeNames(List *opername, TypeName *oprleft,
        if (oprleft == NULL)
                leftoid = InvalidOid;
        else
-       {
-               leftoid = LookupTypeName(oprleft);
-               if (!OidIsValid(leftoid))
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                        errmsg("type %s does not exist",
-                                                       TypeNameToString(oprleft))));
-       }
+               leftoid = typenameTypeId(pstate, oprleft);
+
        if (oprright == NULL)
                rightoid = InvalidOid;
        else
-       {
-               rightoid = LookupTypeName(oprright);
-               if (!OidIsValid(rightoid))
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_UNDEFINED_OBJECT),
-                                        errmsg("type %s does not exist",
-                                                       TypeNameToString(oprright))));
-       }
+               rightoid = typenameTypeId(pstate, oprright);
 
-       return LookupOperName(opername, leftoid, rightoid, noError);
+       return LookupOperName(pstate, opername, leftoid, rightoid,
+                                                 noError, location);
 }
 
 /*
@@ -500,13 +493,15 @@ oper_select_candidate(int nargs,
  * you need an exact- or binary-compatible match; see compatible_oper.
  *
  * If no matching operator found, return NULL if noError is true,
- * raise an error if it is false.
+ * raise an error if it is false.  pstate and location are used only to report
+ * the error position; pass NULL/-1 if not available.
  *
  * NOTE: on success, the returned object is a syscache entry.  The caller
  * must ReleaseSysCache() the entry when done with it.
  */
 Operator
-oper(List *opname, Oid ltypeId, Oid rtypeId, bool noError)
+oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId,
+        bool noError, int location)
 {
        FuncCandidateList clist;
        Oid                     inputOids[2];
@@ -549,7 +544,7 @@ oper(List *opname, Oid ltypeId, Oid rtypeId, bool noError)
        }
 
        if (!HeapTupleIsValid(tup) && !noError)
-               op_error(opname, 'b', ltypeId, rtypeId, fdresult);
+               op_error(pstate, opname, 'b', ltypeId, rtypeId, fdresult, location);
 
        return (Operator) tup;
 }
@@ -562,13 +557,14 @@ oper(List *opname, Oid ltypeId, Oid rtypeId, bool noError)
  *     are accepted).  Otherwise, the semantics are the same.
  */
 Operator
-compatible_oper(List *op, Oid arg1, Oid arg2, bool noError)
+compatible_oper(ParseState *pstate, List *op, Oid arg1, Oid arg2,
+                               bool noError, int location)
 {
        Operator        optup;
        Form_pg_operator opform;
 
        /* oper() will find the best available match */
-       optup = oper(op, arg1, arg2, noError);
+       optup = oper(pstate, op, arg1, arg2, noError, location);
        if (optup == (Operator) NULL)
                return (Operator) NULL; /* must be noError case */
 
@@ -585,7 +581,8 @@ compatible_oper(List *op, Oid arg1, Oid arg2, bool noError)
                ereport(ERROR,
                                (errcode(ERRCODE_UNDEFINED_FUNCTION),
                                 errmsg("operator requires run-time type coercion: %s",
-                                               op_signature_string(op, 'b', arg1, arg2))));
+                                               op_signature_string(op, 'b', arg1, arg2)),
+                                parser_errposition(pstate, location)));
 
        return (Operator) NULL;
 }
@@ -602,7 +599,7 @@ compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
        Operator        optup;
        Oid                     result;
 
-       optup = compatible_oper(op, arg1, arg2, noError);
+       optup = compatible_oper(NULL, op, arg1, arg2, noError, -1);
        if (optup != NULL)
        {
                result = oprid(optup);
@@ -621,13 +618,14 @@ compatible_oper_opid(List *op, Oid arg1, Oid arg2, bool noError)
  * you need an exact- or binary-compatible match.
  *
  * If no matching operator found, return NULL if noError is true,
- * raise an error if it is false.
+ * raise an error if it is false.  pstate and location are used only to report
+ * the error position; pass NULL/-1 if not available.
  *
  * NOTE: on success, the returned object is a syscache entry.  The caller
  * must ReleaseSysCache() the entry when done with it.
  */
 Operator
-right_oper(List *op, Oid arg, bool noError)
+right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
 {
        FuncCandidateList clist;
        Oid                     operOid = InvalidOid;
@@ -669,7 +667,7 @@ right_oper(List *op, Oid arg, bool noError)
        }
 
        if (!HeapTupleIsValid(tup) && !noError)
-               op_error(op, 'r', arg, InvalidOid, fdresult);
+               op_error(pstate, op, 'r', arg, InvalidOid, fdresult, location);
 
        return (Operator) tup;
 }
@@ -683,13 +681,14 @@ right_oper(List *op, Oid arg, bool noError)
  * you need an exact- or binary-compatible match.
  *
  * If no matching operator found, return NULL if noError is true,
- * raise an error if it is false.
+ * raise an error if it is false.  pstate and location are used only to report
+ * the error position; pass NULL/-1 if not available.
  *
  * NOTE: on success, the returned object is a syscache entry.  The caller
  * must ReleaseSysCache() the entry when done with it.
  */
 Operator
-left_oper(List *op, Oid arg, bool noError)
+left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
 {
        FuncCandidateList clist;
        Oid                     operOid = InvalidOid;
@@ -736,7 +735,7 @@ left_oper(List *op, Oid arg, bool noError)
        }
 
        if (!HeapTupleIsValid(tup) && !noError)
-               op_error(op, 'l', InvalidOid, arg, fdresult);
+               op_error(pstate, op, 'l', InvalidOid, arg, fdresult, location);
 
        return (Operator) tup;
 }
@@ -771,7 +770,9 @@ op_signature_string(List *op, char oprkind, Oid arg1, Oid arg2)
  * op_error - utility routine to complain about an unresolvable operator
  */
 static void
-op_error(List *op, char oprkind, Oid arg1, Oid arg2, FuncDetailCode fdresult)
+op_error(ParseState *pstate, List *op, char oprkind,
+                Oid arg1, Oid arg2,
+                FuncDetailCode fdresult, int location)
 {
        if (fdresult == FUNCDETAIL_MULTIPLE)
                ereport(ERROR,
@@ -779,14 +780,16 @@ op_error(List *op, char oprkind, Oid arg1, Oid arg2, FuncDetailCode fdresult)
                                 errmsg("operator is not unique: %s",
                                                op_signature_string(op, oprkind, arg1, arg2)),
                                 errhint("Could not choose a best candidate operator. "
-                                                "You may need to add explicit type casts.")));
+                                                "You may need to add explicit type casts."),
+                                parser_errposition(pstate, location)));
        else
                ereport(ERROR,
                                (errcode(ERRCODE_UNDEFINED_FUNCTION),
                                 errmsg("operator does not exist: %s",
                                                op_signature_string(op, oprkind, arg1, arg2)),
                  errhint("No operator matches the given name and argument type(s). "
-                                 "You may need to add explicit type casts.")));
+                                 "You may need to add explicit type casts."),
+                                parser_errposition(pstate, location)));
 }
 
 /*
@@ -800,7 +803,8 @@ op_error(List *op, char oprkind, Oid arg1, Oid arg2, FuncDetailCode fdresult)
  * processing is wanted.
  */
 Expr *
-make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree)
+make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree,
+               int location)
 {
        Oid                     ltypeId,
                                rtypeId;
@@ -813,21 +817,21 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree)
                /* right operator */
                ltypeId = exprType(ltree);
                rtypeId = InvalidOid;
-               tup = right_oper(opname, ltypeId, false);
+               tup = right_oper(pstate, opname, ltypeId, false, location);
        }
        else if (ltree == NULL)
        {
                /* left operator */
                rtypeId = exprType(rtree);
                ltypeId = InvalidOid;
-               tup = left_oper(opname, rtypeId, false);
+               tup = left_oper(pstate, opname, rtypeId, false, location);
        }
        else
        {
                /* otherwise, binary operator */
                ltypeId = exprType(ltree);
                rtypeId = exprType(rtree);
-               tup = oper(opname, ltypeId, rtypeId, false);
+               tup = oper(pstate, opname, ltypeId, rtypeId, false, location);
        }
 
        /* Do typecasting and build the expression tree */
@@ -845,7 +849,8 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree)
 Expr *
 make_scalar_array_op(ParseState *pstate, List *opname,
                                         bool useOr,
-                                        Node *ltree, Node *rtree)
+                                        Node *ltree, Node *rtree,
+                                        int location)
 {
        Oid                     ltypeId,
                                rtypeId,
@@ -875,11 +880,12 @@ make_scalar_array_op(ParseState *pstate, List *opname,
                if (!OidIsValid(rtypeId))
                        ereport(ERROR,
                                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
-                                errmsg("op ANY/ALL (array) requires array on right side")));
+                                        errmsg("op ANY/ALL (array) requires array on right side"),
+                                        parser_errposition(pstate, location)));
        }
 
        /* Now resolve the operator */
-       tup = oper(opname, ltypeId, rtypeId, false);
+       tup = oper(pstate, opname, ltypeId, rtypeId, false, location);
        opform = (Form_pg_operator) GETSTRUCT(tup);
 
        args = list_make2(ltree, rtree);
@@ -904,11 +910,13 @@ make_scalar_array_op(ParseState *pstate, List *opname,
        if (rettype != BOOLOID)
                ereport(ERROR,
                                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
-                  errmsg("op ANY/ALL (array) requires operator to yield boolean")));
+                                errmsg("op ANY/ALL (array) requires operator to yield boolean"),
+                                parser_errposition(pstate, location)));
        if (get_func_retset(opform->oprcode))
                ereport(ERROR,
                                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
-               errmsg("op ANY/ALL (array) requires operator not to return a set")));
+                                errmsg("op ANY/ALL (array) requires operator not to return a set"),
+                                parser_errposition(pstate, location)));
 
        /*
         * Now switch back to the array type on the right, arranging for any
@@ -919,7 +927,8 @@ make_scalar_array_op(ParseState *pstate, List *opname,
                ereport(ERROR,
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
                                 errmsg("could not find array type for data type %s",
-                                               format_type_be(declared_arg_types[1]))));
+                                               format_type_be(declared_arg_types[1])),
+                                parser_errposition(pstate, location)));
        actual_arg_types[1] = atypeId;
        declared_arg_types[1] = res_atypeId;
 
index af8086a81a830e49268906f8c7dc504ddbc9bf4d..d0f78b119cdf0e65b88b5b494a3f024e854233ae 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.119 2006/03/05 15:58:34 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.120 2006/03/14 22:48:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,7 +47,8 @@ static void expandTupleDesc(TupleDesc tupdesc, Alias *eref,
                                bool include_dropped,
                                List **colnames, List **colvars);
 static int     specialAttNum(const char *attname);
-static void warnAutoRange(ParseState *pstate, RangeVar *relation);
+static void warnAutoRange(ParseState *pstate, RangeVar *relation,
+                                                 int location);
 
 
 /*
@@ -329,7 +330,8 @@ GetRTEByRangeTablePosn(ParseState *pstate,
  * FROM will be marked as requiring read access from the beginning.
  */
 Node *
-scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
+scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname,
+                                int location)
 {
        Node       *result = NULL;
        int                     attnum = 0;
@@ -357,7 +359,8 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
                                ereport(ERROR,
                                                (errcode(ERRCODE_AMBIGUOUS_COLUMN),
                                                 errmsg("column reference \"%s\" is ambiguous",
-                                                               colname)));
+                                                               colname),
+                                                parser_errposition(pstate, location)));
                        result = (Node *) make_var(pstate, rte, attnum);
                        /* Require read access */
                        rte->requiredPerms |= ACL_SELECT;
@@ -404,7 +407,8 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
  *       If localonly is true, only names in the innermost query are considered.
  */
 Node *
-colNameToVar(ParseState *pstate, char *colname, bool localonly)
+colNameToVar(ParseState *pstate, char *colname, bool localonly,
+                        int location)
 {
        Node       *result = NULL;
        ParseState *orig_pstate = pstate;
@@ -419,7 +423,7 @@ colNameToVar(ParseState *pstate, char *colname, bool localonly)
                        Node       *newresult;
 
                        /* use orig_pstate here to get the right sublevels_up */
-                       newresult = scanRTEForColumn(orig_pstate, rte, colname);
+                       newresult = scanRTEForColumn(orig_pstate, rte, colname, location);
 
                        if (newresult)
                        {
@@ -427,7 +431,8 @@ colNameToVar(ParseState *pstate, char *colname, bool localonly)
                                        ereport(ERROR,
                                                        (errcode(ERRCODE_AMBIGUOUS_COLUMN),
                                                         errmsg("column reference \"%s\" is ambiguous",
-                                                                       colname)));
+                                                                       colname),
+                                                        parser_errposition(orig_pstate, location)));
                                result = newresult;
                        }
                }
@@ -454,7 +459,8 @@ qualifiedNameToVar(ParseState *pstate,
                                   char *schemaname,
                                   char *refname,
                                   char *colname,
-                                  bool implicitRTEOK)
+                                  bool implicitRTEOK,
+                                  int location)
 {
        RangeTblEntry *rte;
        int                     sublevels_up;
@@ -465,10 +471,11 @@ qualifiedNameToVar(ParseState *pstate,
        {
                if (!implicitRTEOK)
                        return NULL;
-               rte = addImplicitRTE(pstate, makeRangeVar(schemaname, refname));
+               rte = addImplicitRTE(pstate, makeRangeVar(schemaname, refname),
+                                                        location);
        }
 
-       return scanRTEForColumn(pstate, rte, colname);
+       return scanRTEForColumn(pstate, rte, colname, location);
 }
 
 /*
@@ -1043,12 +1050,12 @@ addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
  * a conflicting name.
  */
 RangeTblEntry *
-addImplicitRTE(ParseState *pstate, RangeVar *relation)
+addImplicitRTE(ParseState *pstate, RangeVar *relation, int location)
 {
        RangeTblEntry *rte;
 
        /* issue warning or error as needed */
-       warnAutoRange(pstate, relation);
+       warnAutoRange(pstate, relation, location);
        /*
         * Note that we set inFromCl true, so that the RTE will be listed
         * explicitly if the parsetree is ever decompiled by ruleutils.c. This
@@ -1196,7 +1203,7 @@ expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
                                                        Var                *varnode;
                                                        Oid                     atttypid;
 
-                                                       atttypid = typenameTypeId(colDef->typename);
+                                                       atttypid = typenameTypeId(NULL, colDef->typename);
 
                                                        varnode = makeVar(rtindex,
                                                                                          attnum,
@@ -1543,7 +1550,7 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
                                {
                                        ColumnDef  *colDef = list_nth(rte->coldeflist, attnum - 1);
 
-                                       *vartype = typenameTypeId(colDef->typename);
+                                       *vartype = typenameTypeId(NULL, colDef->typename);
                                        *vartypmod = colDef->typename->typmod;
                                }
                                else
@@ -1802,7 +1809,7 @@ attnumTypeId(Relation rd, int attid)
  * a warning.
  */
 static void
-warnAutoRange(ParseState *pstate, RangeVar *relation)
+warnAutoRange(ParseState *pstate, RangeVar *relation, int location)
 {
        RangeTblEntry *rte;
        int                     sublevels_up;
@@ -1841,7 +1848,8 @@ warnAutoRange(ParseState *pstate, RangeVar *relation)
                                          errhint("Perhaps you meant to reference the table alias \"%s\".",
                                                          badAlias) :
                                          errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
-                                                         rte->eref->aliasname))));
+                                                         rte->eref->aliasname)),
+                                        parser_errposition(pstate, location)));
                else
                        ereport(ERROR,
                                        (errcode(ERRCODE_UNDEFINED_TABLE),
@@ -1849,7 +1857,8 @@ warnAutoRange(ParseState *pstate, RangeVar *relation)
                                          errmsg("missing FROM-clause entry in subquery for table \"%s\"",
                                                         relation->relname) :
                                          errmsg("missing FROM-clause entry for table \"%s\"",
-                                                        relation->relname))));
+                                                        relation->relname)),
+                                        parser_errposition(pstate, location)));
        }
        else
        {
@@ -1866,6 +1875,7 @@ warnAutoRange(ParseState *pstate, RangeVar *relation)
                                                  badAlias) :
                                  (rte ?
                                   errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
-                                                  rte->eref->aliasname) : 0))));
+                                                  rte->eref->aliasname) : 0)),
+                                parser_errposition(pstate, location)));
        }
 }
index 63ce087e71c5c7400e561bca0591fea0f0f6a9ca..300e02d90b9d3485cde2ddb2c18cf2bc888a9e62 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.140 2006/03/05 15:58:34 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.141 2006/03/14 22:48:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -718,7 +718,8 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref)
                                                ereport(ERROR,
                                                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                                                 errmsg("cross-database references are not implemented: %s",
-                                                                               NameListToString(fields))));
+                                                                               NameListToString(fields)),
+                                                                parser_errposition(pstate, cref->location)));
                                        schemaname = strVal(lsecond(fields));
                                        relname = strVal(lthird(fields));
                                        break;
@@ -727,7 +728,8 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref)
                                ereport(ERROR,
                                                (errcode(ERRCODE_SYNTAX_ERROR),
                                errmsg("improper qualified name (too many dotted names): %s",
-                                          NameListToString(fields))));
+                                          NameListToString(fields)),
+                                                parser_errposition(pstate, cref->location)));
                                schemaname = NULL;              /* keep compiler quiet */
                                relname = NULL;
                                break;
@@ -736,8 +738,8 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref)
                rte = refnameRangeTblEntry(pstate, schemaname, relname,
                                                                   &sublevels_up);
                if (rte == NULL)
-                       rte = addImplicitRTE(pstate, makeRangeVar(schemaname,
-                                                                                                         relname));
+                       rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname),
+                                                                cref->location);
 
                rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up);
 
index 41143540576cb16e2b7df0c4be9894f5e7dbcc50..e88e6c37c1e1276d0364c8c9045a0bd12409a7a2 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.78 2006/03/05 15:58:34 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.79 2006/03/14 22:48:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
  *
  * NB: even if the returned OID is not InvalidOid, the type might be
  * just a shell.  Caller should check typisdefined before using the type.
+ *
+ * pstate is only used for error location info, and may be NULL.
  */
 Oid
-LookupTypeName(const TypeName *typename)
+LookupTypeName(ParseState *pstate, const TypeName *typename)
 {
        Oid                     restype;
 
@@ -60,7 +62,8 @@ LookupTypeName(const TypeName *typename)
                                ereport(ERROR,
                                                (errcode(ERRCODE_SYNTAX_ERROR),
                                errmsg("improper %%TYPE reference (too few dotted names): %s",
-                                          NameListToString(typename->names))));
+                                          NameListToString(typename->names)),
+                                                parser_errposition(pstate, typename->location)));
                                break;
                        case 2:
                                rel->relname = strVal(linitial(typename->names));
@@ -81,7 +84,8 @@ LookupTypeName(const TypeName *typename)
                                ereport(ERROR,
                                                (errcode(ERRCODE_SYNTAX_ERROR),
                                                 errmsg("improper %%TYPE reference (too many dotted names): %s",
-                                                               NameListToString(typename->names))));
+                                                               NameListToString(typename->names)),
+                                                parser_errposition(pstate, typename->location)));
                                break;
                }
 
@@ -92,7 +96,8 @@ LookupTypeName(const TypeName *typename)
                        ereport(ERROR,
                                        (errcode(ERRCODE_UNDEFINED_COLUMN),
                                         errmsg("column \"%s\" of relation \"%s\" does not exist",
-                                                       field, rel->relname)));
+                                                       field, rel->relname),
+                                        parser_errposition(pstate, typename->location)));
                restype = get_atttype(relid, attnum);
 
                /* this construct should never have an array indicator */
@@ -190,21 +195,24 @@ TypeNameToString(const TypeName *typename)
  * a suitable error message if the type cannot be found or is not defined.
  */
 Oid
-typenameTypeId(const TypeName *typename)
+typenameTypeId(ParseState *pstate, const TypeName *typename)
 {
        Oid                     typoid;
 
-       typoid = LookupTypeName(typename);
+       typoid = LookupTypeName(pstate, typename);
        if (!OidIsValid(typoid))
                ereport(ERROR,
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
                                 errmsg("type \"%s\" does not exist",
-                                               TypeNameToString(typename))));
+                                               TypeNameToString(typename)),
+                                parser_errposition(pstate, typename->location)));
+
        if (!get_typisdefined(typoid))
                ereport(ERROR,
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
                                 errmsg("type \"%s\" is only a shell",
-                                               TypeNameToString(typename))));
+                                               TypeNameToString(typename)),
+                                parser_errposition(pstate, typename->location)));
        return typoid;
 }
 
@@ -215,17 +223,18 @@ typenameTypeId(const TypeName *typename)
  * NB: caller must ReleaseSysCache the type tuple when done with it.
  */
 Type
-typenameType(const TypeName *typename)
+typenameType(ParseState *pstate, const TypeName *typename)
 {
        Oid                     typoid;
        HeapTuple       tup;
 
-       typoid = LookupTypeName(typename);
+       typoid = LookupTypeName(pstate, typename);
        if (!OidIsValid(typoid))
                ereport(ERROR,
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
                                 errmsg("type \"%s\" does not exist",
-                                               TypeNameToString(typename))));
+                                               TypeNameToString(typename)),
+                                parser_errposition(pstate, typename->location)));
        tup = SearchSysCache(TYPEOID,
                                                 ObjectIdGetDatum(typoid),
                                                 0, 0, 0);
@@ -235,7 +244,8 @@ typenameType(const TypeName *typename)
                ereport(ERROR,
                                (errcode(ERRCODE_UNDEFINED_OBJECT),
                                 errmsg("type \"%s\" is only a shell",
-                                               TypeNameToString(typename))));
+                                               TypeNameToString(typename)),
+                                parser_errposition(pstate, typename->location)));
        return (Type) tup;
 }
 
@@ -447,7 +457,7 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod)
        if (typename->setof)
                goto fail;
 
-       *type_id = typenameTypeId(typename);
+       *type_id = typenameTypeId(NULL, typename);
        *typmod = typename->typmod;
 
        pfree(buf.data);
index 3d63cb73c8aabb9db77907c23d0095c4bcd543b2..0ac8d346a7bd13194a81c0e3b59d7ff6b68fc8e2 100644 (file)
@@ -24,7 +24,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/scan.l,v 1.132 2006/03/07 01:00:17 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/scan.l,v 1.133 2006/03/14 22:48:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -74,20 +74,19 @@ static int          literalalloc;   /* current allocated buffer size */
 static void addlit(char *ytext, int yleng);
 static void addlitchar(unsigned char ychar);
 static char *litbufdup(void);
-static int     pg_err_position(void);
+
+static int     lexer_errposition(void);
 static void check_escape_warning(void);
 static void check_string_escape_warning(unsigned char ychar);
 
 /*
+ * Each call to yylex must set yylloc to the location of the found token
+ * (expressed as a byte offset from the start of the input text).
  * When we parse a token that requires multiple lexer rules to process,
- * we set token_start to point at the true start of the token, for use
- * by yyerror().  yytext will point at just the text consumed by the last
- * rule, so it's not very helpful (e.g., it might contain just the last
- * quote mark of a quoted identifier).  But to avoid cluttering every rule
- * with setting token_start, we allow token_start = NULL to denote that
- * it's okay to use yytext.
+ * this should be done in the first such rule, else yylloc will point
+ * into the middle of the token.
  */
-static char       *token_start;
+#define SET_YYLLOC()  (yylloc = yytext - scanbuf)
 
 /* Handles to the buffer that the lexer uses internally */
 static YY_BUFFER_STATE scanbufhandle;
@@ -316,17 +315,13 @@ other                     .
 
 %%
 
-%{
-                                       /* code to execute during start of each call of yylex() */
-                                       token_start = NULL;
-%}
-
 {whitespace}   {
                                        /* ignore */
                                }
 
 {xcstart}              {
-                                       token_start = yytext;
+                                       /* Set location in case of syntax error in comment */
+                                       SET_YYLLOC();
                                        xcdepth = 0;
                                        BEGIN(xc);
                                        /* Put back any characters past slash-star; see above */
@@ -341,11 +336,7 @@ other                      .
 
 <xc>{xcstop}   {
                                        if (xcdepth <= 0)
-                                       {
                                                BEGIN(INITIAL);
-                                               /* reset token_start for next token */
-                                               token_start = NULL;
-                                       }
                                        else
                                                xcdepth--;
                                }
@@ -371,7 +362,7 @@ other                       .
                                         * In the meantime, place a leading "b" on the string
                                         * to mark it for the input routine as a binary string.
                                         */
-                                       token_start = yytext;
+                                       SET_YYLLOC();
                                        BEGIN(xb);
                                        startlit();
                                        addlitchar('b');
@@ -400,7 +391,7 @@ other                       .
                                         * In the meantime, place a leading "x" on the string
                                         * to mark it for the input routine as a hex string.
                                         */
-                                       token_start = yytext;
+                                       SET_YYLLOC();
                                        BEGIN(xh);
                                        startlit();
                                        addlitchar('x');
@@ -421,6 +412,7 @@ other                       .
                                         */
                                        const ScanKeyword *keyword;
 
+                                       SET_YYLLOC();
                                        yyless(1);                              /* eat only 'n' this time */
                                        /* nchar had better be a keyword! */
                                        keyword = ScanKeywordLookup("nchar");
@@ -431,7 +423,7 @@ other                       .
 
 {xqstart}              {
                                        warn_on_first_escape = true;
-                                       token_start = yytext;
+                                       SET_YYLLOC();
                                        if (standard_conforming_strings)
                                                BEGIN(xq);
                                        else
@@ -440,7 +432,7 @@ other                       .
                                }
 {xestart}              {
                                        warn_on_first_escape = false;
-                                       token_start = yytext;
+                                       SET_YYLLOC();
                                        BEGIN(xe);
                                        startlit();
                                }
@@ -490,7 +482,7 @@ other                       .
 <xq,xe><<EOF>>         { yyerror("unterminated quoted string"); }
 
 {dolqdelim}            {
-                                       token_start = yytext;
+                                       SET_YYLLOC();
                                        dolqstart = pstrdup(yytext);
                                        BEGIN(xdolq);
                                        startlit();
@@ -533,7 +525,7 @@ other                       .
 <xdolq><<EOF>> { yyerror("unterminated dollar-quoted string"); }
 
 {xdstart}              {
-                                       token_start = yytext;
+                                       SET_YYLLOC();
                                        BEGIN(xd);
                                        startlit();
                                }
@@ -558,10 +550,12 @@ other                     .
 <xd><<EOF>>            { yyerror("unterminated quoted identifier"); }
 
 {typecast}             {
+                                       SET_YYLLOC();
                                        return TYPECAST;
                                }
 
 {self}                 {
+                                       SET_YYLLOC();
                                        return yytext[0];
                                }
 
@@ -611,6 +605,8 @@ other                       .
                                                nchars--; /* else remove the +/-, and check again */
                                        }
 
+                                       SET_YYLLOC();
+
                                        if (nchars < yyleng)
                                        {
                                                /* Strip the unwanted chars from the token */
@@ -644,6 +640,7 @@ other                       .
                                }
 
 {param}                        {
+                                       SET_YYLLOC();
                                        yylval.ival = atol(yytext + 1);
                                        return PARAM;
                                }
@@ -652,6 +649,7 @@ other                       .
                                        long val;
                                        char* endptr;
 
+                                       SET_YYLLOC();
                                        errno = 0;
                                        val = strtol(yytext, &endptr, 10);
                                        if (*endptr != '\0' || errno == ERANGE
@@ -669,10 +667,12 @@ other                     .
                                        return ICONST;
                                }
 {decimal}              {
+                                       SET_YYLLOC();
                                        yylval.str = pstrdup(yytext);
                                        return FCONST;
                                }
 {real}                 {
+                                       SET_YYLLOC();
                                        yylval.str = pstrdup(yytext);
                                        return FCONST;
                                }
@@ -684,12 +684,14 @@ other                     .
                                         * syntax error anyway, we don't bother to distinguish.
                                         */
                                        yyless(yyleng-1);
+                                       SET_YYLLOC();
                                        yylval.str = pstrdup(yytext);
                                        return FCONST;
                                }
 {realfail2}            {
                                        /* throw back the [Ee][+-], and proceed as above */
                                        yyless(yyleng-2);
+                                       SET_YYLLOC();
                                        yylval.str = pstrdup(yytext);
                                        return FCONST;
                                }
@@ -699,6 +701,8 @@ other                       .
                                        const ScanKeyword *keyword;
                                        char               *ident;
 
+                                       SET_YYLLOC();
+
                                        /* Is it a keyword? */
                                        keyword = ScanKeywordLookup(yytext);
                                        if (keyword != NULL)
@@ -717,25 +721,52 @@ other                     .
                                }
 
 {other}                        {
+                                       SET_YYLLOC();
                                        return yytext[0];
                                }
 
+<<EOF>>                        {
+                                       SET_YYLLOC();
+                                       yyterminate();
+                               }
+
 %%
 
+/*
+ * lexer_errposition
+ *             Report a lexical-analysis-time cursor position, if possible.
+ *
+ * This is expected to be used within an ereport() call.  The return value
+ * is a dummy (always 0, in fact).
+ *
+ * Note that this can only be used for messages from the lexer itself,
+ * since it depends on scanbuf to still be valid.
+ */
 static int
-pg_err_position(void)
+lexer_errposition(void)
 {
-       const char *loc = token_start ? token_start : yytext;
+       int             pos;
 
-       /* in multibyte encodings, return index in characters not bytes */
-       return pg_mbstrlen_with_len(scanbuf, loc - scanbuf) + 1;
+       /* Convert byte offset to character number */
+       pos = pg_mbstrlen_with_len(scanbuf, yylloc) + 1;
+       /* And pass it to the ereport mechanism */
+       return errposition(pos);
 }
 
+/*
+ * yyerror
+ *             Report a lexer or grammar error.
+ *
+ * The message's cursor position identifies the most recently lexed token.
+ * This is OK for syntax error messages from the Bison parser, because Bison
+ * parsers report error as soon as the first unparsable token is reached.
+ * Beware of using yyerror for other purposes, as the cursor position might
+ * be misleading!
+ */
 void
 yyerror(const char *message)
 {
-       const char *loc = token_start ? token_start : yytext;
-       int                     cursorpos = pg_err_position();
+       const char *loc = scanbuf + yylloc;
 
        if (*loc == YY_END_OF_BUFFER_CHAR)
        {
@@ -743,7 +774,7 @@ yyerror(const char *message)
                                (errcode(ERRCODE_SYNTAX_ERROR),
                                 /* translator: %s is typically "syntax error" */
                                 errmsg("%s at end of input", _(message)),
-                                errposition(cursorpos)));
+                                lexer_errposition()));
        }
        else
        {
@@ -751,7 +782,7 @@ yyerror(const char *message)
                                (errcode(ERRCODE_SYNTAX_ERROR),
                                 /* translator: first %s is typically "syntax error" */
                                 errmsg("%s at or near \"%s\"", _(message), loc),
-                                errposition(cursorpos)));
+                                lexer_errposition()));
        }
 }
 
@@ -878,7 +909,7 @@ check_string_escape_warning(unsigned char ychar)
                                        (errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
                                         errmsg("nonstandard use of \\' in a string literal"),
                                         errhint("Use '' to write quotes in strings, or use the escape string syntax (E'...')."),
-                                        errposition(pg_err_position())));
+                                        lexer_errposition()));
                warn_on_first_escape = false;   /* warn only once per string */
        }
        else if (ychar == '\\')
@@ -888,7 +919,7 @@ check_string_escape_warning(unsigned char ychar)
                                        (errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
                                         errmsg("nonstandard use of \\\\ in a string literal"),
                                         errhint("Use the escape string syntax for backslashes, e.g., E'\\\\'."),
-                                        errposition(pg_err_position())));
+                                        lexer_errposition()));
                warn_on_first_escape = false;   /* warn only once per string */
        }
        else
@@ -903,6 +934,6 @@ check_escape_warning(void)
                                (errcode(ERRCODE_NONSTANDARD_USE_OF_ESCAPE_CHARACTER),
                                 errmsg("nonstandard use of escape in a string literal"),
                                 errhint("Use the escape string syntax for escapes, e.g., E'\\r\\n'."),
-                                errposition(pg_err_position())));
+                                lexer_errposition()));
        warn_on_first_escape = false;   /* warn only once per string */
 }
index a94d2691e885f5b88bfcb8106bedd6b32022102d..78cb8c3f811be947ea00f1ca78438ad0e1ec6820 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.481 2006/03/05 15:58:40 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.482 2006/03/14 22:48:21 tgl Exp $
  *
  * NOTES
  *       this is the "main" module of the postgres backend and
@@ -501,6 +501,7 @@ pg_parse_and_rewrite(const char *query_string,      /* string to execute */
 
                querytree_list = list_concat(querytree_list,
                                                                         pg_analyze_and_rewrite(parsetree,
+                                                                                                                       query_string,
                                                                                                                        paramTypes,
                                                                                                                        numParams));
        }
@@ -625,7 +626,8 @@ log_after_parse(List *raw_parsetree_list, const char *query_string,
  * NOTE: for reasons mentioned above, this must be separate from raw parsing.
  */
 List *
-pg_analyze_and_rewrite(Node *parsetree, Oid *paramTypes, int numParams)
+pg_analyze_and_rewrite(Node *parsetree, const char *query_string,
+                                          Oid *paramTypes, int numParams)
 {
        List       *querytree_list;
 
@@ -635,7 +637,8 @@ pg_analyze_and_rewrite(Node *parsetree, Oid *paramTypes, int numParams)
        if (log_parser_stats)
                ResetUsage();
 
-       querytree_list = parse_analyze(parsetree, paramTypes, numParams);
+       querytree_list = parse_analyze(parsetree, query_string,
+                                                                  paramTypes, numParams);
 
        if (log_parser_stats)
                ShowUsage("PARSE ANALYSIS STATISTICS");
@@ -946,7 +949,8 @@ exec_simple_query(const char *query_string)
                 */
                oldcontext = MemoryContextSwitchTo(MessageContext);
 
-               querytree_list = pg_analyze_and_rewrite(parsetree, NULL, 0);
+               querytree_list = pg_analyze_and_rewrite(parsetree, query_string,
+                                                                                               NULL, 0);
 
                plantree_list = pg_plan_queries(querytree_list, NULL, true);
 
@@ -1257,6 +1261,7 @@ exec_parse_message(const char *query_string,      /* string to execute */
                        ResetUsage();
 
                querytree_list = parse_analyze_varparams(parsetree,
+                                                                                                query_string,
                                                                                                 &paramTypes,
                                                                                                 &numParams);
 
index 030f8c52b2f7d4aefe07747046a0683a96adf975..9942bcc291b86989f658e4d74d641d7af9d96671 100644 (file)
@@ -2,7 +2,7 @@
  * ruleutils.c - Functions to convert stored expressions/querytrees
  *                             back to source text
  *
- *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.215 2006/03/11 16:43:21 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.216 2006/03/14 22:48:22 tgl Exp $
  **********************************************************************/
 
 #include "postgres.h"
@@ -4479,7 +4479,7 @@ get_from_clause_coldeflist(List *coldeflist, deparse_context *context)
                int32           atttypmod;
 
                attname = n->colname;
-               atttypeid = typenameTypeId(n->typename);
+               atttypeid = typenameTypeId(NULL, n->typename);
                atttypmod = n->typename->typmod;
 
                if (i > 0)
@@ -4868,13 +4868,16 @@ generate_operator_name(Oid operid, Oid arg1, Oid arg2)
        switch (operform->oprkind)
        {
                case 'b':
-                       p_result = oper(list_make1(makeString(oprname)), arg1, arg2, true);
+                       p_result = oper(NULL, list_make1(makeString(oprname)), arg1, arg2,
+                                                       true, -1);
                        break;
                case 'l':
-                       p_result = left_oper(list_make1(makeString(oprname)), arg2, true);
+                       p_result = left_oper(NULL, list_make1(makeString(oprname)), arg2,
+                                                                true, -1);
                        break;
                case 'r':
-                       p_result = right_oper(list_make1(makeString(oprname)), arg1, true);
+                       p_result = right_oper(NULL, list_make1(makeString(oprname)), arg1,
+                                                                 true, -1);
                        break;
                default:
                        elog(ERROR, "unrecognized oprkind: %d", operform->oprkind);
index 07f4d22c07087d19904c0227c0e56b6e5ea75a0e..ec0acc156e7f80356ead2c719c25f0ea9db750f1 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2006, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.115 2006/03/06 19:49:20 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/common.c,v 1.116 2006/03/14 22:48:22 tgl Exp $
  */
 #include "postgres_fe.h"
 #include "common.h"
@@ -428,234 +428,6 @@ ResetCancelConn(void)
 }
 
 
-/*
- * on errors, print syntax error position if available.
- *
- * the query is expected to be in the client encoding.
- */
-static void
-ReportSyntaxErrorPosition(const PGresult *result, const char *query)
-{
-#define DISPLAY_SIZE   60              /* screen width limit, in screen cols */
-#define MIN_RIGHT_CUT  10              /* try to keep this far away from EOL */
-
-       int                     loc = 0;
-       const char *sp;
-       int                     clen,
-                               slen,
-                               i,
-                               w,
-                          *qidx,
-                          *scridx,
-                               qoffset,
-                               scroffset,
-                               ibeg,
-                               iend,
-                               loc_line;
-       char       *wquery;
-       bool            beg_trunc,
-                               end_trunc;
-       PQExpBufferData msg;
-
-       if (pset.verbosity == PQERRORS_TERSE)
-               return;
-
-       sp = PQresultErrorField(result, PG_DIAG_STATEMENT_POSITION);
-       if (sp == NULL)
-       {
-               sp = PQresultErrorField(result, PG_DIAG_INTERNAL_POSITION);
-               if (sp == NULL)
-                       return;                         /* no syntax error */
-               query = PQresultErrorField(result, PG_DIAG_INTERNAL_QUERY);
-       }
-       if (query == NULL)
-               return;                                 /* nothing to reference location to */
-
-       if (sscanf(sp, "%d", &loc) != 1)
-       {
-               psql_error("INTERNAL ERROR: unexpected statement position \"%s\"\n",
-                                  sp);
-               return;
-       }
-
-       /* Make a writable copy of the query, and a buffer for messages. */
-       wquery = pg_strdup(query);
-
-       initPQExpBuffer(&msg);
-
-       /*
-        * The returned cursor position is measured in logical characters. Each
-        * character might occupy multiple physical bytes in the string, and in
-        * some Far Eastern character sets it might take more than one screen
-        * column as well.      We compute the starting byte offset and starting
-        * screen column of each logical character, and store these in qidx[] and
-        * scridx[] respectively.
-        */
-
-       /* we need a safe allocation size... */
-       slen = strlen(query) + 1;
-
-       qidx = (int *) pg_malloc(slen * sizeof(int));
-       scridx = (int *) pg_malloc(slen * sizeof(int));
-
-       qoffset = 0;
-       scroffset = 0;
-       for (i = 0; query[qoffset] != '\0'; i++)
-       {
-               qidx[i] = qoffset;
-               scridx[i] = scroffset;
-               w = PQdsplen(&query[qoffset], pset.encoding);
-               /* treat control chars as width 1; see tab hack below */
-               if (w <= 0)
-                       w = 1;
-               scroffset += w;
-               qoffset += PQmblen(&query[qoffset], pset.encoding);
-       }
-       qidx[i] = qoffset;
-       scridx[i] = scroffset;
-       clen = i;
-       psql_assert(clen < slen);
-
-       /* convert loc to zero-based offset in qidx/scridx arrays */
-       loc--;
-
-       /* do we have something to show? */
-       if (loc >= 0 && loc <= clen)
-       {
-               /* input line number of our syntax error. */
-               loc_line = 1;
-               /* first included char of extract. */
-               ibeg = 0;
-               /* last-plus-1 included char of extract. */
-               iend = clen;
-
-               /*
-                * Replace tabs with spaces in the writable copy.  (Later we might
-                * want to think about coping with their variable screen width, but
-                * not today.)
-                *
-                * Extract line number and begin and end indexes of line containing
-                * error location.      There will not be any newlines or carriage returns
-                * in the selected extract.
-                */
-               for (i = 0; i < clen; i++)
-               {
-                       /* character length must be 1 or it's not ASCII */
-                       if ((qidx[i + 1] - qidx[i]) == 1)
-                       {
-                               if (wquery[qidx[i]] == '\t')
-                                       wquery[qidx[i]] = ' ';
-                               else if (wquery[qidx[i]] == '\r' || wquery[qidx[i]] == '\n')
-                               {
-                                       if (i < loc)
-                                       {
-                                               /*
-                                                * count lines before loc.      Each \r or \n counts as a
-                                                * line except when \r \n appear together.
-                                                */
-                                               if (wquery[qidx[i]] == '\r' ||
-                                                       i == 0 ||
-                                                       (qidx[i] - qidx[i - 1]) != 1 ||
-                                                       wquery[qidx[i - 1]] != '\r')
-                                                       loc_line++;
-                                               /* extract beginning = last line start before loc. */
-                                               ibeg = i + 1;
-                                       }
-                                       else
-                                       {
-                                               /* set extract end. */
-                                               iend = i;
-                                               /* done scanning. */
-                                               break;
-                                       }
-                               }
-                       }
-               }
-
-               /* If the line extracted is too long, we truncate it. */
-               beg_trunc = false;
-               end_trunc = false;
-               if (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
-               {
-                       /*
-                        * We first truncate right if it is enough.  This code might be
-                        * off a space or so on enforcing MIN_RIGHT_CUT if there's a wide
-                        * character right there, but that should be okay.
-                        */
-                       if (scridx[ibeg] + DISPLAY_SIZE >= scridx[loc] + MIN_RIGHT_CUT)
-                       {
-                               while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
-                                       iend--;
-                               end_trunc = true;
-                       }
-                       else
-                       {
-                               /* Truncate right if not too close to loc. */
-                               while (scridx[loc] + MIN_RIGHT_CUT < scridx[iend])
-                               {
-                                       iend--;
-                                       end_trunc = true;
-                               }
-
-                               /* Truncate left if still too long. */
-                               while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
-                               {
-                                       ibeg++;
-                                       beg_trunc = true;
-                               }
-                       }
-               }
-
-               /* the extract MUST contain the target position! */
-               psql_assert(ibeg <= loc && loc <= iend);
-
-               /* truncate working copy at desired endpoint */
-               wquery[qidx[iend]] = '\0';
-
-               /* Begin building the finished message. */
-               printfPQExpBuffer(&msg, _("LINE %d: "), loc_line);
-               if (beg_trunc)
-                       appendPQExpBufferStr(&msg, "...");
-
-               /*
-                * While we have the prefix in the msg buffer, compute its screen
-                * width.
-                */
-               scroffset = 0;
-               for (i = 0; i < msg.len; i += PQmblen(&msg.data[i], pset.encoding))
-               {
-                       w = PQdsplen(&msg.data[i], pset.encoding);
-                       if (w <= 0)
-                               w = 1;
-                       scroffset += w;
-               }
-
-               /* Finish and emit the message. */
-               appendPQExpBufferStr(&msg, &wquery[qidx[ibeg]]);
-               if (end_trunc)
-                       appendPQExpBufferStr(&msg, "...");
-
-               psql_error("%s\n", msg.data);
-
-               /* Now emit the cursor marker line. */
-               scroffset += scridx[loc] - scridx[ibeg];
-               resetPQExpBuffer(&msg);
-               for (i = 0; i < scroffset; i++)
-                       appendPQExpBufferChar(&msg, ' ');
-               appendPQExpBufferChar(&msg, '^');
-
-               psql_error("%s\n", msg.data);
-       }
-
-       /* Clean up. */
-       termPQExpBuffer(&msg);
-
-       free(wquery);
-       free(qidx);
-       free(scridx);
-}
-
-
 /*
  * AcceptResult
  *
@@ -704,8 +476,6 @@ AcceptResult(const PGresult *result, const char *query)
                if (strlen(error))
                        psql_error("%s", error);
 
-               ReportSyntaxErrorPosition(result, query);
-
                CheckConnection();
        }
 
index ad8607cf6bff30f53d8ee020d795d2af58ba90e1..23cb0029c0da47716869ff840c4acc2dd293406b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.54 2006/03/05 15:58:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.55 2006/03/14 22:48:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 
 extern A_Expr *makeA_Expr(A_Expr_Kind kind, List *name,
-                  Node *lexpr, Node *rexpr);
+                  Node *lexpr, Node *rexpr, int location);
 
 extern A_Expr *makeSimpleA_Expr(A_Expr_Kind kind, const char *name,
-                                Node *lexpr, Node *rexpr);
+                                Node *lexpr, Node *rexpr, int location);
 
 extern Var *makeVar(Index varno,
                AttrNumber varattno,
@@ -56,6 +56,8 @@ extern RelabelType *makeRelabelType(Expr *arg, Oid rtype, int32 rtypmod,
 extern RangeVar *makeRangeVar(char *schemaname, char *relname);
 
 extern TypeName *makeTypeName(char *typnam);
+extern TypeName *makeTypeNameFromNameList(List *names);
+extern TypeName *makeTypeNameFromOid(Oid typeid, int32 typmod);
 
 extern FuncExpr *makeFuncExpr(Oid funcid, Oid rettype,
                         List *args, CoercionForm fformat);
index 30652a56dfadcb61fcbe018c84290d2385a272eb..0e7d5bf9f51859e87503dc8102dd5f0e6cfa2621 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.303 2006/03/05 15:58:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.304 2006/03/14 22:48:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -142,6 +142,11 @@ typedef struct Query
  *     Most of these node types appear in raw parsetrees output by the grammar,
  *     and get transformed to something else by the analyzer.  A few of them
  *     are used as-is in transformed querytrees.
+ *
+ *     Many of the node types used in raw parsetrees include a "location" field.
+ *     This is a byte (not character) offset in the original source text, to be
+ *     used for positioning an error cursor when there is an analysis-time
+ *     error related to the node.
  ****************************************************************************/
 
 /*
@@ -165,6 +170,7 @@ typedef struct TypeName
        bool            pct_type;               /* %TYPE specified? */
        int32           typmod;                 /* type modifier */
        List       *arrayBounds;        /* array bounds */
+       int                     location;               /* token location, or -1 if unknown */
 } TypeName;
 
 /*
@@ -182,6 +188,7 @@ typedef struct ColumnRef
 {
        NodeTag         type;
        List       *fields;                     /* field names (list of Value strings) */
+       int                     location;               /* token location, or -1 if unknown */
 } ColumnRef;
 
 /*
@@ -217,6 +224,7 @@ typedef struct A_Expr
        List       *name;                       /* possibly-qualified name of operator */
        Node       *lexpr;                      /* left argument, or NULL if none */
        Node       *rexpr;                      /* right argument, or NULL if none */
+       int                     location;               /* token location, or -1 if unknown */
 } A_Expr;
 
 /*
@@ -226,7 +234,7 @@ typedef struct A_Const
 {
        NodeTag         type;
        Value           val;                    /* the value (with the tag) */
-       TypeName   *typename;           /* typecast */
+       TypeName   *typename;           /* typecast, or NULL if none */
 } A_Const;
 
 /*
@@ -235,8 +243,8 @@ typedef struct A_Const
  * NOTE: for mostly historical reasons, A_Const parsenodes contain
  * room for a TypeName; we only generate a separate TypeCast node if the
  * argument to be casted is not a constant.  In theory either representation
- * would work, but it is convenient to have the target type immediately
- * available while resolving a constant's datatype.
+ * would work, but the combined representation saves a bit of code in many
+ * productions in gram.y.
  */
 typedef struct TypeCast
 {
@@ -260,6 +268,7 @@ typedef struct FuncCall
        List       *args;                       /* the arguments (list of exprs) */
        bool            agg_star;               /* argument was really '*' */
        bool            agg_distinct;   /* arguments were labeled DISTINCT */
+       int                     location;               /* token location, or -1 if unknown */
 } FuncCall;
 
 /*
index 38e501875fe6da7ef8731c279b34436cc41ed4f6..57188b9fce96976da4c97a7ba364d617a3435e93 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/parser/analyze.h,v 1.31 2006/03/05 15:58:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/parser/analyze.h,v 1.32 2006/03/14 22:48:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "parser/parse_node.h"
 
 
-extern List *parse_analyze(Node *parseTree, Oid *paramTypes, int numParams);
-extern List *parse_analyze_varparams(Node *parseTree, Oid **paramTypes,
-                                               int *numParams);
+extern List *parse_analyze(Node *parseTree, const char *sourceText,
+                                                  Oid *paramTypes, int numParams);
+extern List *parse_analyze_varparams(Node *parseTree, const char *sourceText,
+                                                                        Oid **paramTypes, int *numParams);
 extern List *parse_sub_analyze(Node *parseTree, ParseState *parentParseState);
 extern List *analyzeCreateSchemaStmt(CreateSchemaStmt *stmt);
 extern void CheckSelectLocking(Query *qry, bool forUpdate);
index 054604521bc754d128888f829bd720a415222fe3..13af69116cd3bc34a0b8bacf7eed2cda0084dcbb 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/parser/gramparse.h,v 1.33 2006/03/07 01:00:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/parser/gramparse.h,v 1.34 2006/03/14 22:48:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "nodes/parsenodes.h"
 
+/*
+ * We track token locations in terms of byte offsets from the start of the
+ * source string, not the column number/line number representation that
+ * bison uses by default.  Also, to minimize overhead we track only one
+ * location (usually the first token location) for each construct, not
+ * the beginning and ending locations as bison does by default.  It's
+ * therefore sufficient to make YYLTYPE an int.
+ */
+#define YYLTYPE  int
 
 /* from scan.l */
 extern void scanner_init(const char *str);
index 82e114f6c80eb43a04ed7e2e1cd3df45fa7a2c0c..13aa706a044ab8ca096b0b4f013e114f229461bc 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/parser/parse_func.h,v 1.54 2006/03/05 15:58:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_func.h,v 1.55 2006/03/14 22:48:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -43,7 +43,8 @@ typedef enum
 
 extern Node *ParseFuncOrColumn(ParseState *pstate,
                                  List *funcname, List *fargs,
-                                 bool agg_star, bool agg_distinct, bool is_column);
+                                 bool agg_star, bool agg_distinct, bool is_column,
+                                 int location);
 
 extern FuncDetailCode func_get_detail(List *funcname, List *fargs,
                                int nargs, Oid *argtypes,
index 5262c804aba337325c6f1110689c9d55fd557dca..2c23cf78946600cb32fc331c4fc78d692aa58bb7 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.47 2006/03/05 15:58:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.48 2006/03/14 22:48:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * State information used during parse analysis
  *
+ * parentParseState: NULL in a top-level ParseState.  When parsing a subquery,
+ * links to current parse state of outer query.
+ *
+ * p_sourcetext: source string that generated the raw parsetree being
+ * analyzed, or NULL if not available.  (The string is used only to
+ * generate cursor positions in error messages: we need it to convert
+ * byte-wise locations in parse structures to character-wise cursor
+ * positions.)
+ *
  * p_rtable: list of RTEs that will become the rangetable of the query.
  * Note that neither relname nor refname of these entries are necessarily
  * unique; searching the rtable by name is a bad idea.
@@ -53,6 +62,7 @@
 typedef struct ParseState
 {
        struct ParseState *parentParseState;            /* stack link */
+       const char *p_sourcetext;       /* source text, or NULL if not available */
        List       *p_rtable;           /* range table so far */
        List       *p_joinlist;         /* join items so far (will become FromExpr
                                                                 * node's fromlist) */
@@ -73,6 +83,8 @@ typedef struct ParseState
 } ParseState;
 
 extern ParseState *make_parsestate(ParseState *parentParseState);
+extern int     parser_errposition(ParseState *pstate, int location);
+
 extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno);
 extern Oid     transformArrayType(Oid arrayType);
 extern ArrayRef *transformArraySubscripts(ParseState *pstate,
index f3c2ee543ec2f74d52b645e4c8cd2212af5f1736..33e54ef01e07950ca22604b267e3c53bc7276a08 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/parser/parse_oper.h,v 1.38 2006/03/05 15:58:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_oper.h,v 1.39 2006/03/14 22:48:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 typedef HeapTuple Operator;
 
 /* Routines to look up an operator given name and exact input type(s) */
-extern Oid LookupOperName(List *opername, Oid oprleft, Oid oprright,
-                          bool noError);
-extern Oid LookupOperNameTypeNames(List *opername, TypeName *oprleft,
-                                               TypeName *oprright, bool noError);
+extern Oid LookupOperName(ParseState *pstate, List *opername,
+                                                 Oid oprleft, Oid oprright,
+                                                 bool noError, int location);
+extern Oid LookupOperNameTypeNames(ParseState *pstate, List *opername,
+                                                                  TypeName *oprleft, TypeName *oprright,
+                                                                  bool noError, int location);
 
 /* Routines to find operators matching a name and given input types */
 /* NB: the selected operator may require coercion of the input types! */
-extern Operator oper(List *op, Oid arg1, Oid arg2, bool noError);
-extern Operator right_oper(List *op, Oid arg, bool noError);
-extern Operator left_oper(List *op, Oid arg, bool noError);
+extern Operator oper(ParseState *pstate, List *op, Oid arg1, Oid arg2,
+                                        bool noError, int location);
+extern Operator right_oper(ParseState *pstate, List *op, Oid arg,
+                                                  bool noError, int location);
+extern Operator left_oper(ParseState *pstate, List *op, Oid arg,
+                                                 bool noError, int location);
 
 /* Routines to find operators that DO NOT require coercion --- ie, their */
 /* input types are either exactly as given, or binary-compatible */
-extern Operator compatible_oper(List *op, Oid arg1, Oid arg2, bool noError);
+extern Operator compatible_oper(ParseState *pstate, List *op,
+                                                               Oid arg1, Oid arg2,
+                                                               bool noError, int location);
 
 /* currently no need for compatible_left_oper/compatible_right_oper */
 
@@ -55,9 +62,9 @@ extern Oid    oprfuncid(Operator op);
 
 /* Build expression tree for an operator invocation */
 extern Expr *make_op(ParseState *pstate, List *opname,
-               Node *ltree, Node *rtree);
+               Node *ltree, Node *rtree, int location);
 extern Expr *make_scalar_array_op(ParseState *pstate, List *opname,
                                         bool useOr,
-                                        Node *ltree, Node *rtree);
+                                        Node *ltree, Node *rtree, int location);
 
 #endif   /* PARSE_OPER_H */
index 4faa3351a5fef7877a6121d36a7c674a2a0bf9a5..33ebad8abce21a5f1760d97047b4764e7ad12d57 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/parser/parse_relation.h,v 1.52 2006/03/05 15:58:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_relation.h,v 1.53 2006/03/14 22:48:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -31,13 +31,15 @@ extern RangeTblEntry *GetRTEByRangeTablePosn(ParseState *pstate,
                                           int varno,
                                           int sublevels_up);
 extern Node *scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte,
-                                char *colname);
-extern Node *colNameToVar(ParseState *pstate, char *colname, bool localonly);
+                                char *colname, int location);
+extern Node *colNameToVar(ParseState *pstate, char *colname, bool localonly,
+                                                 int location);
 extern Node *qualifiedNameToVar(ParseState *pstate,
                                   char *schemaname,
                                   char *refname,
                                   char *colname,
-                                  bool implicitRTEOK);
+                                  bool implicitRTEOK,
+                                  int location);
 extern RangeTblEntry *addRangeTableEntry(ParseState *pstate,
                                   RangeVar *relation,
                                   Alias *alias,
@@ -66,7 +68,8 @@ extern RangeTblEntry *addRangeTableEntryForJoin(ParseState *pstate,
 extern void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
                          bool addToJoinList,
                          bool addToRelNameSpace, bool addToVarNameSpace);
-extern RangeTblEntry *addImplicitRTE(ParseState *pstate, RangeVar *relation);
+extern RangeTblEntry *addImplicitRTE(ParseState *pstate, RangeVar *relation,
+                                                                        int location);
 extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
                  bool include_dropped,
                  List **colnames, List **colvars);
index a7069ada9105c7d15ebeff5e723be4cd186b7eb4..62c02370deb29f64a06fe1b07b9787acc8ef168a 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/parser/parse_type.h,v 1.31 2006/03/05 15:58:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/parser/parse_type.h,v 1.32 2006/03/14 22:48:22 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 typedef HeapTuple Type;
 
-extern Oid     LookupTypeName(const TypeName *typename);
+extern Oid     LookupTypeName(ParseState *pstate, const TypeName *typename);
 extern char *TypeNameToString(const TypeName *typename);
-extern Oid     typenameTypeId(const TypeName *typename);
-extern Type typenameType(const TypeName *typename);
+extern Oid     typenameTypeId(ParseState *pstate, const TypeName *typename);
+extern Type typenameType(ParseState *pstate, const TypeName *typename);
 
 extern Type typeidType(Oid id);
 
index 09a24d5d279ad37b12819ea4f1d19c586460aca0..4509d8f7f1808cda3cec83850500c8fb83ef9522 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.80 2006/03/05 15:59:00 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.81 2006/03/14 22:48:23 tgl Exp $
  *
  * OLD COMMENTS
  *       This file was created so that other c files could get the two
@@ -47,7 +47,7 @@ extern LogStmtLevel log_statement;
 extern List *pg_parse_and_rewrite(const char *query_string,
                                         Oid *paramTypes, int numParams);
 extern List *pg_parse_query(const char *query_string);
-extern List *pg_analyze_and_rewrite(Node *parsetree,
+extern List *pg_analyze_and_rewrite(Node *parsetree, const char *query_string,
                                           Oid *paramTypes, int numParams);
 extern Plan *pg_plan_query(Query *querytree, ParamListInfo boundParams);
 extern List *pg_plan_queries(List *querytrees, ParamListInfo boundParams,
index ef708658d738548db544c19adb8713f6497500ea..98d834b5954b377b56fd579b0216be2cf6a7dc15 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.327 2006/03/05 15:59:08 momjian Exp $
+ *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-connect.c,v 1.328 2006/03/14 22:48:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1918,6 +1918,8 @@ freePGconn(PGconn *conn)
                free(conn->krbsrvname);
 #endif
        /* Note that conn->Pfdebug is not ours to close or free */
+       if (conn->last_query)
+               free(conn->last_query);
        pg_freeaddrinfo_all(conn->addrlist_family, conn->addrlist);
        notify = conn->notifyHead;
        while (notify != NULL)
index 26d2b58fd97ef75db6ae17ce273c9e36b54b5381..7f09ff6dd22842621201038742947053cbd62534 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.181 2006/03/05 15:59:09 momjian Exp $
+ *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-exec.c,v 1.182 2006/03/14 22:48:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -667,6 +667,12 @@ PQsendQuery(PGconn *conn, const char *query)
        /* remember we are using simple query protocol */
        conn->queryclass = PGQUERY_SIMPLE;
 
+       /* and remember the query text too, if possible */
+       /* if insufficient memory, last_query just winds up NULL */
+       if (conn->last_query)
+               free(conn->last_query);
+       conn->last_query = strdup(query);
+
        /*
         * Give the data a push.  In nonblock mode, don't complain if we're unable
         * to send it all; PQgetResult() will do any additional flushing needed.
@@ -788,6 +794,12 @@ PQsendPrepare(PGconn *conn,
        /* remember we are doing just a Parse */
        conn->queryclass = PGQUERY_PREPARE;
 
+       /* and remember the query text too, if possible */
+       /* if insufficient memory, last_query just winds up NULL */
+       if (conn->last_query)
+               free(conn->last_query);
+       conn->last_query = strdup(query);
+
        /*
         * Give the data a push.  In nonblock mode, don't complain if we're unable
         * to send it all; PQgetResult() will do any additional flushing needed.
@@ -1017,6 +1029,15 @@ PQsendQueryGuts(PGconn *conn,
        /* remember we are using extended query protocol */
        conn->queryclass = PGQUERY_EXTENDED;
 
+       /* and remember the query text too, if possible */
+       /* if insufficient memory, last_query just winds up NULL */
+       if (conn->last_query)
+               free(conn->last_query);
+       if (command)
+               conn->last_query = strdup(command);
+       else
+               conn->last_query = NULL;
+
        /*
         * Give the data a push.  In nonblock mode, don't complain if we're unable
         * to send it all; PQgetResult() will do any additional flushing needed.
index 0fbb3738adf3f2483b29c2dcf0b9f923ab8f50ff..35f015ecce60f2b484f45d22c749340aafec7daa 100644 (file)
@@ -8,13 +8,12 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-protocol3.c,v 1.25 2006/03/05 15:59:09 momjian Exp $
+ *       $PostgreSQL: pgsql/src/interfaces/libpq/fe-protocol3.c,v 1.26 2006/03/14 22:48:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres_fe.h"
 
-#include <errno.h>
 #include <ctype.h>
 #include <fcntl.h>
 
@@ -51,6 +50,8 @@ static int    getParameterStatus(PGconn *conn);
 static int     getNotify(PGconn *conn);
 static int     getCopyStart(PGconn *conn, ExecStatusType copytype);
 static int     getReadyForQuery(PGconn *conn);
+static void reportErrorPosition(PQExpBuffer msg, const char *query,
+                                                               int loc, int encoding);
 static int build_startup_packet(const PGconn *conn, char *packet,
                                         const PQEnvironmentOption *options);
 
@@ -614,6 +615,8 @@ pqGetErrorNotice3(PGconn *conn, bool isError)
        PQExpBufferData workBuf;
        char            id;
        const char *val;
+       const char *querytext = NULL;
+       int                     querypos = 0;
 
        /*
         * Since the fields might be pretty long, we create a temporary
@@ -666,22 +669,46 @@ pqGetErrorNotice3(PGconn *conn, bool isError)
        val = PQresultErrorField(res, PG_DIAG_STATEMENT_POSITION);
        if (val)
        {
-               /* translator: %s represents a digit string */
-               appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"), val);
+               if (conn->verbosity != PQERRORS_TERSE && conn->last_query != NULL)
+               {
+                       /* emit position as a syntax cursor display */
+                       querytext = conn->last_query;
+                       querypos = atoi(val);
+               }
+               else
+               {
+                       /* emit position as text addition to primary message */
+                       /* translator: %s represents a digit string */
+                       appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"),
+                                                         val);
+               }
        }
        else
        {
                val = PQresultErrorField(res, PG_DIAG_INTERNAL_POSITION);
                if (val)
                {
-                       /* translator: %s represents a digit string */
-                       appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"),
-                                                         val);
+                       querytext = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY);
+                       if (conn->verbosity != PQERRORS_TERSE && querytext != NULL)
+                       {
+                               /* emit position as a syntax cursor display */
+                               querypos = atoi(val);
+                       }
+                       else
+                       {
+                               /* emit position as text addition to primary message */
+                               /* translator: %s represents a digit string */
+                               appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"),
+                                                                 val);
+                       }
                }
        }
        appendPQExpBufferChar(&workBuf, '\n');
        if (conn->verbosity != PQERRORS_TERSE)
        {
+               if (querytext && querypos > 0)
+                       reportErrorPosition(&workBuf, querytext, querypos,
+                                                               conn->client_encoding);
                val = PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL);
                if (val)
                        appendPQExpBuffer(&workBuf, libpq_gettext("DETAIL:  %s\n"), val);
@@ -746,6 +773,212 @@ fail:
        return EOF;
 }
 
+/*
+ * Add an error-location display to the error message under construction.
+ *
+ * The cursor location is measured in logical characters; the query string
+ * is presumed to be in the specified encoding.
+ */
+static void
+reportErrorPosition(PQExpBuffer msg, const char *query, int loc, int encoding)
+{
+#define DISPLAY_SIZE   60              /* screen width limit, in screen cols */
+#define MIN_RIGHT_CUT  10              /* try to keep this far away from EOL */
+
+       char       *wquery;
+       int                     clen,
+                               slen,
+                               i,
+                               w,
+                          *qidx,
+                          *scridx,
+                               qoffset,
+                               scroffset,
+                               ibeg,
+                               iend,
+                               loc_line;
+       bool            beg_trunc,
+                               end_trunc;
+
+       /* Need a writable copy of the query */
+       wquery = strdup(query);
+       if (wquery == NULL)
+               return;                                 /* fail silently if out of memory */
+
+       /*
+        * Each character might occupy multiple physical bytes in the string, and
+        * in some Far Eastern character sets it might take more than one screen
+        * column as well.      We compute the starting byte offset and starting
+        * screen column of each logical character, and store these in qidx[] and
+        * scridx[] respectively.
+        */
+
+       /* we need a safe allocation size... */
+       slen = strlen(query) + 1;
+
+       qidx = (int *) malloc(slen * sizeof(int));
+       if (qidx == NULL)
+       {
+               free(wquery);
+               return;
+       }
+       scridx = (int *) malloc(slen * sizeof(int));
+       if (scridx == NULL)
+       {
+               free(qidx);
+               free(wquery);
+               return;
+       }
+
+       qoffset = 0;
+       scroffset = 0;
+       for (i = 0; query[qoffset] != '\0'; i++)
+       {
+               qidx[i] = qoffset;
+               scridx[i] = scroffset;
+               w = pg_encoding_dsplen(encoding, &query[qoffset]);
+               /* treat control chars as width 1; see tab hack below */
+               if (w <= 0)
+                       w = 1;
+               scroffset += w;
+               qoffset += pg_encoding_mblen(encoding, &query[qoffset]);
+       }
+       qidx[i] = qoffset;
+       scridx[i] = scroffset;
+       clen = i;
+
+       /* convert loc to zero-based offset in qidx/scridx arrays */
+       loc--;
+
+       /* do we have something to show? */
+       if (loc >= 0 && loc <= clen)
+       {
+               /* input line number of our syntax error. */
+               loc_line = 1;
+               /* first included char of extract. */
+               ibeg = 0;
+               /* last-plus-1 included char of extract. */
+               iend = clen;
+
+               /*
+                * Replace tabs with spaces in the writable copy.  (Later we might
+                * want to think about coping with their variable screen width, but
+                * not today.)
+                *
+                * Extract line number and begin and end indexes of line containing
+                * error location.      There will not be any newlines or carriage returns
+                * in the selected extract.
+                */
+               for (i = 0; i < clen; i++)
+               {
+                       /* character length must be 1 or it's not ASCII */
+                       if ((qidx[i + 1] - qidx[i]) == 1)
+                       {
+                               if (wquery[qidx[i]] == '\t')
+                                       wquery[qidx[i]] = ' ';
+                               else if (wquery[qidx[i]] == '\r' || wquery[qidx[i]] == '\n')
+                               {
+                                       if (i < loc)
+                                       {
+                                               /*
+                                                * count lines before loc. Each \r or \n counts
+                                                * as a line except when \r \n appear together.
+                                                */
+                                               if (wquery[qidx[i]] == '\r' ||
+                                                       i == 0 ||
+                                                       (qidx[i] - qidx[i - 1]) != 1 ||
+                                                       wquery[qidx[i - 1]] != '\r')
+                                                       loc_line++;
+                                               /* extract beginning = last line start before loc. */
+                                               ibeg = i + 1;
+                                       }
+                                       else
+                                       {
+                                               /* set extract end. */
+                                               iend = i;
+                                               /* done scanning. */
+                                               break;
+                                       }
+                               }
+                       }
+               }
+
+               /* If the line extracted is too long, we truncate it. */
+               beg_trunc = false;
+               end_trunc = false;
+               if (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
+               {
+                       /*
+                        * We first truncate right if it is enough.  This code might be
+                        * off a space or so on enforcing MIN_RIGHT_CUT if there's a wide
+                        * character right there, but that should be okay.
+                        */
+                       if (scridx[ibeg] + DISPLAY_SIZE >= scridx[loc] + MIN_RIGHT_CUT)
+                       {
+                               while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
+                                       iend--;
+                               end_trunc = true;
+                       }
+                       else
+                       {
+                               /* Truncate right if not too close to loc. */
+                               while (scridx[loc] + MIN_RIGHT_CUT < scridx[iend])
+                               {
+                                       iend--;
+                                       end_trunc = true;
+                               }
+
+                               /* Truncate left if still too long. */
+                               while (scridx[iend] - scridx[ibeg] > DISPLAY_SIZE)
+                               {
+                                       ibeg++;
+                                       beg_trunc = true;
+                               }
+                       }
+               }
+
+               /* truncate working copy at desired endpoint */
+               wquery[qidx[iend]] = '\0';
+
+               /* Begin building the finished message. */
+               i = msg->len;
+               appendPQExpBuffer(msg, libpq_gettext("LINE %d: "), loc_line);
+               if (beg_trunc)
+                       appendPQExpBufferStr(msg, "...");
+
+               /*
+                * While we have the prefix in the msg buffer, compute its screen
+                * width.
+                */
+               scroffset = 0;
+               for (; i < msg->len; i += pg_encoding_mblen(encoding, &msg->data[i]))
+               {
+                       w = pg_encoding_dsplen(encoding, &msg->data[i]);
+                       if (w <= 0)
+                               w = 1;
+                       scroffset += w;
+               }
+
+               /* Finish up the LINE message line. */
+               appendPQExpBufferStr(msg, &wquery[qidx[ibeg]]);
+               if (end_trunc)
+                       appendPQExpBufferStr(msg, "...");
+               appendPQExpBufferChar(msg, '\n');
+
+               /* Now emit the cursor marker line. */
+               scroffset += scridx[loc] - scridx[ibeg];
+               for (i = 0; i < scroffset; i++)
+                       appendPQExpBufferChar(msg, ' ');
+               appendPQExpBufferChar(msg, '^');
+               appendPQExpBufferChar(msg, '\n');
+       }
+
+       /* Clean up. */
+       free(scridx);
+       free(qidx);
+       free(wquery);
+}
+
 
 /*
  * Attempt to read a ParameterStatus message.
index 4ae59c9e9a5ffe9526417642f2735fd9f022767d..39533452ec822282e79e1204ea821aae4e74f731 100644 (file)
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.111 2006/03/05 15:59:10 momjian Exp $
+ * $PostgreSQL: pgsql/src/interfaces/libpq/libpq-int.h,v 1.112 2006/03/14 22:48:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -278,6 +278,7 @@ struct pg_conn
        PGAsyncStatusType asyncStatus;
        PGTransactionStatusType xactStatus;             /* never changes to ACTIVE */
        PGQueryClass queryclass;
+       char       *last_query;         /* last SQL command, or NULL if unknown */
        bool            options_valid;  /* true if OK to attempt connection */
        bool            nonblocking;    /* whether this connection is using nonblock
                                                                 * sending semantics */
index 61325138d7e0ebed9977d32345dac191c9d8ea1c..e04140c5805363328893b0351238453c96161a1f 100644 (file)
@@ -39,6 +39,8 @@ ERROR:  creation of Perl function failed: Global symbol "$global" requires expli
 Global symbol "$other_global" requires explicit package name at line 4.
 select uses_global();
 ERROR:  function uses_global() does not exist
+LINE 1: select uses_global();
+               ^
 HINT:  No function matches the given name and argument types. You may need to add explicit type casts.
 SET plperl.use_strict = false;
 create or replace function uses_global() returns text language plperl as $$
index fc8af5634bf260cfeeba2246cd698154c88303b8..362bf77472551fe4602a8e9fbd8929386262cb3a 100644 (file)
@@ -1,7 +1,7 @@
 /**********************************************************************
  * plperl.c - perl as a procedural language for PostgreSQL
  *
- *       $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.105 2006/03/11 16:43:22 momjian Exp $
+ *       $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.106 2006/03/14 22:48:23 tgl Exp $
  *
  **********************************************************************/
 
 #include "commands/trigger.h"
 #include "executor/spi.h"
 #include "funcapi.h"
+#include "mb/pg_wchar.h"
+#include "miscadmin.h"
+#include "nodes/makefuncs.h"
+#include "parser/parse_type.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/typcache.h"
-#include "miscadmin.h"
-#include "mb/pg_wchar.h"
-#include "parser/parse_type.h"
 
 /* define this before the perl headers get a chance to mangle DLLIMPORT */
 extern DLLIMPORT bool check_function_bodies;
@@ -1950,7 +1951,6 @@ plperl_spi_prepare(char* query, int argc, SV ** argv)
        plperl_query_desc *qdesc;
        void       *plan;
        int                     i;
-       HeapTuple       typeTup;
 
        MemoryContext oldcontext = CurrentMemoryContext;
        ResourceOwner oldowner = CurrentResourceOwner;
@@ -1977,33 +1977,18 @@ plperl_spi_prepare(char* query, int argc, SV ** argv)
                 ************************************************************/
                for (i = 0; i < argc; i++)
                {
-                       char       *argcopy;
-                       List       *names = NIL;
-                       ListCell   *l;
-                       TypeName   *typename;
-
-                       /************************************************************
-                        * Use SplitIdentifierString() on a copy of the type name,
-                        * turn the resulting pointer list into a TypeName node
-                        * and call typenameType() to get the pg_type tuple.
-                        ************************************************************/
-                       argcopy = pstrdup(SvPV(argv[i],PL_na));
-                       SplitIdentifierString(argcopy, '.', &names);
-                       typename = makeNode(TypeName);
-                       foreach(l, names)
-                               typename->names = lappend(typename->names, makeString(lfirst(l)));
-
-                       typeTup = typenameType(typename);
+                       List       *names;
+                       HeapTuple       typeTup;
+
+                       /* Parse possibly-qualified type name and look it up in pg_type */
+                       names = stringToQualifiedNameList(SvPV(argv[i], PL_na),
+                                                                                         "plperl_spi_prepare");
+                       typeTup = typenameType(NULL, makeTypeNameFromNameList(names));
                        qdesc->argtypes[i] = HeapTupleGetOid(typeTup);
                        perm_fmgr_info(((Form_pg_type) GETSTRUCT(typeTup))->typinput,
                                                   &(qdesc->arginfuncs[i]));
                        qdesc->argtypioparams[i] = getTypeIOParam(typeTup);
                        ReleaseSysCache(typeTup);
-
-                       list_free(typename->names);
-                       pfree(typename);
-                       list_free(names);
-                       pfree(argcopy);
                }
 
                /************************************************************
index 0362bccbbc474221b01fb5c51de45aa345570035..93814db1665c619f486ffd05cf2e80ab1501e089 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.100 2006/03/09 21:29:36 momjian Exp $
+ *       $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.101 2006/03/14 22:48:23 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1082,7 +1082,7 @@ plpgsql_parse_wordtype(char *word)
         * Word wasn't found on the namestack. Try to find a data type with that
         * name, but ignore pg_type entries that are in fact class types.
         */
-       typeOid = LookupTypeName(makeTypeName(cp[0]));
+       typeOid = LookupTypeName(NULL, makeTypeName(cp[0]));
        if (OidIsValid(typeOid))
        {
                HeapTuple       typeTup;
index b8a516731f35fe2fed5c6444e3e962826562e27f..d20a5f72f1301954324ff53377294a1da6d67e5e 100644 (file)
@@ -1,7 +1,7 @@
 /**********************************************************************
  * plpython.c - python as a procedural language for PostgreSQL
  *
- *     $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.75 2006/03/11 16:43:22 momjian Exp $
+ *     $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.76 2006/03/14 22:48:24 tgl Exp $
  *
  *********************************************************************
  */
@@ -23,6 +23,7 @@
 #include "nodes/makefuncs.h"
 #include "parser/parse_type.h"
 #include "tcop/tcopprot.h"
+#include "utils/builtins.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
 #include "utils/syscache.h"
@@ -1873,6 +1874,7 @@ PLy_spi_prepare(PyObject * self, PyObject * args)
                                for (i = 0; i < nargs; i++)
                                {
                                        char       *sptr;
+                                       List       *names;
                                        HeapTuple       typeTup;
                                        Form_pg_type typeStruct;
 
@@ -1882,9 +1884,13 @@ PLy_spi_prepare(PyObject * self, PyObject * args)
                                        sptr = PyString_AsString(optr);
 
                                        /*
-                                        * XXX should extend this to allow qualified type names
+                                        * Parse possibly-qualified type name and look it up in
+                                        * pg_type
                                         */
-                                       typeTup = typenameType(makeTypeName(sptr));
+                                       names = stringToQualifiedNameList(sptr,
+                                                                                                         "PLy_spi_prepare");
+                                       typeTup = typenameType(NULL,
+                                                                                  makeTypeNameFromNameList(names));
                                        Py_DECREF(optr);
                                        optr = NULL;    /* this is important */
 
index fba628960ec2046687d84d7e9a501086a4db9f22..e1f21109bc5ef259c406b51507a71dbae4ed4bfe 100644 (file)
@@ -2,7 +2,7 @@
  * pltcl.c             - PostgreSQL support for Tcl as
  *                               procedural language (PL)
  *
- *       $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.100 2006/03/11 16:43:22 momjian Exp $
+ *       $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.101 2006/03/14 22:48:24 tgl Exp $
  *
  **********************************************************************/
 
@@ -1754,7 +1754,6 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
        pltcl_query_desc *qdesc;
        void       *plan;
        int                     i;
-       HeapTuple       typeTup;
        Tcl_HashEntry *hashent;
        int                     hashnew;
        Tcl_HashTable *query_hash;
@@ -1802,33 +1801,18 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
                 ************************************************************/
                for (i = 0; i < nargs; i++)
                {
-                       char       *argcopy;
-                       List       *names = NIL;
-                       ListCell   *l;
-                       TypeName   *typename;
-
-                       /************************************************************
-                        * Use SplitIdentifierString() on a copy of the type name,
-                        * turn the resulting pointer list into a TypeName node
-                        * and call typenameType() to get the pg_type tuple.
-                        ************************************************************/
-                       argcopy = pstrdup(args[i]);
-                       SplitIdentifierString(argcopy, '.', &names);
-                       typename = makeNode(TypeName);
-                       foreach(l, names)
-                               typename->names = lappend(typename->names, makeString(lfirst(l)));
+                       List       *names;
+                       HeapTuple       typeTup;
 
-                       typeTup = typenameType(typename);
+                       /* Parse possibly-qualified type name and look it up in pg_type */
+                       names = stringToQualifiedNameList(args[i],
+                                                                                         "pltcl_SPI_prepare");
+                       typeTup = typenameType(NULL, makeTypeNameFromNameList(names));
                        qdesc->argtypes[i] = HeapTupleGetOid(typeTup);
                        perm_fmgr_info(((Form_pg_type) GETSTRUCT(typeTup))->typinput,
                                                   &(qdesc->arginfuncs[i]));
                        qdesc->argtypioparams[i] = getTypeIOParam(typeTup);
                        ReleaseSysCache(typeTup);
-
-                       list_free(typename->names);
-                       pfree(typename);
-                       list_free(names);
-                       pfree(argcopy);
                }
 
                /************************************************************
index 02723d62ecc7153ac411cc5a5c0841309e44dc66..6655e8b6d11299dc7f66324de6488ef820561b69 100644 (file)
@@ -616,12 +616,20 @@ select * from atacc1;
 
 select * from atacc1 order by a;
 ERROR:  column "a" does not exist
+LINE 1: select * from atacc1 order by a;
+                                      ^
 select * from atacc1 order by "........pg.dropped.1........";
 ERROR:  column "........pg.dropped.1........" does not exist
+LINE 1: select * from atacc1 order by "........pg.dropped.1........"...
+                                      ^
 select * from atacc1 group by a;
 ERROR:  column "a" does not exist
+LINE 1: select * from atacc1 group by a;
+                                      ^
 select * from atacc1 group by "........pg.dropped.1........";
 ERROR:  column "........pg.dropped.1........" does not exist
+LINE 1: select * from atacc1 group by "........pg.dropped.1........"...
+                                      ^
 select atacc1.* from atacc1;
  b | c | d 
 ---+---+---
@@ -630,8 +638,12 @@ select atacc1.* from atacc1;
 
 select a from atacc1;
 ERROR:  column "a" does not exist
+LINE 1: select a from atacc1;
+               ^
 select atacc1.a from atacc1;
 ERROR:  column atacc1.a does not exist
+LINE 1: select atacc1.a from atacc1;
+               ^
 select b,c,d from atacc1;
  b | c | d 
 ---+---+---
@@ -640,25 +652,41 @@ select b,c,d from atacc1;
 
 select a,b,c,d from atacc1;
 ERROR:  column "a" does not exist
+LINE 1: select a,b,c,d from atacc1;
+               ^
 select * from atacc1 where a = 1;
 ERROR:  column "a" does not exist
+LINE 1: select * from atacc1 where a = 1;
+                                   ^
 select "........pg.dropped.1........" from atacc1;
 ERROR:  column "........pg.dropped.1........" does not exist
+LINE 1: select "........pg.dropped.1........" from atacc1;
+               ^
 select atacc1."........pg.dropped.1........" from atacc1;
 ERROR:  column atacc1.........pg.dropped.1........ does not exist
+LINE 1: select atacc1."........pg.dropped.1........" from atacc1;
+               ^
 select "........pg.dropped.1........",b,c,d from atacc1;
 ERROR:  column "........pg.dropped.1........" does not exist
+LINE 1: select "........pg.dropped.1........",b,c,d from atacc1;
+               ^
 select * from atacc1 where "........pg.dropped.1........" = 1;
 ERROR:  column "........pg.dropped.1........" does not exist
+LINE 1: select * from atacc1 where "........pg.dropped.1........" = ...
+                                   ^
 -- UPDATEs
 update atacc1 set a = 3;
 ERROR:  column "a" of relation "atacc1" does not exist
 update atacc1 set b = 2 where a = 3;
 ERROR:  column "a" does not exist
+LINE 1: update atacc1 set b = 2 where a = 3;
+                                      ^
 update atacc1 set "........pg.dropped.1........" = 3;
 ERROR:  column "........pg.dropped.1........" of relation "atacc1" does not exist
 update atacc1 set b = 2 where "........pg.dropped.1........" = 3;
 ERROR:  column "........pg.dropped.1........" does not exist
+LINE 1: update atacc1 set b = 2 where "........pg.dropped.1........"...
+                                      ^
 -- INSERTs
 insert into atacc1 values (10, 11, 12, 13);
 ERROR:  INSERT has more expressions than target columns
@@ -685,8 +713,12 @@ ERROR:  column "........pg.dropped.1........" of relation "atacc1" does not exis
 -- DELETEs
 delete from atacc1 where a = 3;
 ERROR:  column "a" does not exist
+LINE 1: delete from atacc1 where a = 3;
+                                 ^
 delete from atacc1 where "........pg.dropped.1........" = 3;
 ERROR:  column "........pg.dropped.1........" does not exist
+LINE 1: delete from atacc1 where "........pg.dropped.1........" = 3;
+                                 ^
 delete from atacc1;
 -- try dropping a non-existent column, should fail
 alter table atacc1 drop bar;
@@ -926,6 +958,8 @@ select f1 from c1;
 alter table c1 drop column f1;
 select f1 from c1;
 ERROR:  column "f1" does not exist
+LINE 1: select f1 from c1;
+               ^
 drop table p1 cascade;
 NOTICE:  drop cascades to table c1
 create table p1 (f1 int, f2 int);
@@ -937,6 +971,8 @@ alter table p1 drop column f1;
 -- c1.f1 is dropped now, since there is no local definition for it
 select f1 from c1;
 ERROR:  column "f1" does not exist
+LINE 1: select f1 from c1;
+               ^
 drop table p1 cascade;
 NOTICE:  drop cascades to table c1
 create table p1 (f1 int, f2 int);
@@ -1035,6 +1071,8 @@ select oid > 0, * from altstartwith;
 alter table altstartwith set without oids;
 select oid > 0, * from altstartwith; -- fails
 ERROR:  column "oid" does not exist
+LINE 1: select oid > 0, * from altstartwith;
+               ^
 select * from altstartwith;
  col 
 -----
@@ -1062,8 +1100,12 @@ alter table altwithoid set without oids;
 alter table altinhoid set without oids;
 select oid > 0, * from altwithoid; -- fails
 ERROR:  column "oid" does not exist
+LINE 1: select oid > 0, * from altwithoid;
+               ^
 select oid > 0, * from altinhoid; -- fails
 ERROR:  column "oid" does not exist
+LINE 1: select oid > 0, * from altinhoid;
+               ^
 select * from altwithoid;
  col 
 -----
index 11b83ea993618f80c30b77c8871ac3368af6d5d0..17d073d37c7356f40942b28b65c6536fe7a24f89 100644 (file)
@@ -393,8 +393,12 @@ select 33.4 > all (array[1,2,3]);
 -- errors
 select 33 * any ('{1,2,3}');
 ERROR:  op ANY/ALL (array) requires operator to yield boolean
+LINE 1: select 33 * any ('{1,2,3}');
+                  ^
 select 33 * any (44);
 ERROR:  op ANY/ALL (array) requires array on right side
+LINE 1: select 33 * any (44);
+                  ^
 -- nulls
 select 33 = any (null::int[]);
  ?column? 
index 5e323c7e2cd58887eeccee50e531d1fd76c0dee5..8c97e4106b1343492497d166cf135bd9f3025f0b 100644 (file)
@@ -19,7 +19,7 @@ select 1;
  
 -- missing relation name 
 select;
-ERROR:  syntax error at or near ";" at character 7
+ERROR:  syntax error at or near ";"
 LINE 1: select;
               ^
 -- no such relation 
@@ -27,32 +27,40 @@ select * from nonesuch;
 ERROR:  relation "nonesuch" does not exist
 -- missing target list
 select from pg_database;
-ERROR:  syntax error at or near "from" at character 8
+ERROR:  syntax error at or near "from"
 LINE 1: select from pg_database;
                ^
 -- bad name in target list
 select nonesuch from pg_database;
 ERROR:  column "nonesuch" does not exist
+LINE 1: select nonesuch from pg_database;
+               ^
 -- bad attribute name on lhs of operator
 select * from pg_database where nonesuch = pg_database.datname;
 ERROR:  column "nonesuch" does not exist
+LINE 1: select * from pg_database where nonesuch = pg_database.datna...
+                                        ^
 -- bad attribute name on rhs of operator
 select * from pg_database where pg_database.datname = nonesuch;
 ERROR:  column "nonesuch" does not exist
+LINE 1: ...ect * from pg_database where pg_database.datname = nonesuch;
+                                                              ^
 -- bad select distinct on syntax, distinct attribute missing
 select distinct on (foobar) from pg_database;
-ERROR:  syntax error at or near "from" at character 29
+ERROR:  syntax error at or near "from"
 LINE 1: select distinct on (foobar) from pg_database;
                                     ^
 -- bad select distinct on syntax, distinct attribute not in target list
 select distinct on (foobar) * from pg_database;
 ERROR:  column "foobar" does not exist
+LINE 1: select distinct on (foobar) * from pg_database;
+                            ^
 --
 -- DELETE
  
 -- missing relation name (this had better not wildcard!) 
 delete from;
-ERROR:  syntax error at or near ";" at character 12
+ERROR:  syntax error at or near ";"
 LINE 1: delete from;
                    ^
 -- no such relation 
@@ -63,7 +71,7 @@ ERROR:  relation "nonesuch" does not exist
  
 -- missing relation name (this had better not wildcard!) 
 drop table;
-ERROR:  syntax error at or near ";" at character 11
+ERROR:  syntax error at or near ";"
 LINE 1: drop table;
                   ^
 -- no such relation 
@@ -75,7 +83,7 @@ ERROR:  table "nonesuch" does not exist
 -- relation renaming 
 -- missing relation name 
 alter table rename;
-ERROR:  syntax error at or near ";" at character 19
+ERROR:  syntax error at or near ";"
 LINE 1: alter table rename;
                           ^
 -- no such relation 
@@ -131,12 +139,12 @@ ERROR:  aggregate basetype must be specified
  
 -- missing index name 
 drop index;
-ERROR:  syntax error at or near ";" at character 11
+ERROR:  syntax error at or near ";"
 LINE 1: drop index;
                   ^
 -- bad index name 
 drop index 314159;
-ERROR:  syntax error at or near "314159" at character 12
+ERROR:  syntax error at or near "314159"
 LINE 1: drop index 314159;
                    ^
 -- no such index 
@@ -147,17 +155,17 @@ ERROR:  index "nonesuch" does not exist
  
 -- missing aggregate name 
 drop aggregate;
-ERROR:  syntax error at or near ";" at character 15
+ERROR:  syntax error at or near ";"
 LINE 1: drop aggregate;
                       ^
 -- missing aggregate type
 drop aggregate newcnt1;
-ERROR:  syntax error at or near ";" at character 23
+ERROR:  syntax error at or near ";"
 LINE 1: drop aggregate newcnt1;
                               ^
 -- bad aggregate name 
 drop aggregate 314159 (int);
-ERROR:  syntax error at or near "314159" at character 16
+ERROR:  syntax error at or near "314159"
 LINE 1: drop aggregate 314159 (int);
                        ^
 -- bad aggregate type
@@ -174,12 +182,12 @@ ERROR:  aggregate newcnt(real) does not exist
  
 -- missing function name 
 drop function ();
-ERROR:  syntax error at or near "(" at character 15
+ERROR:  syntax error at or near "("
 LINE 1: drop function ();
                       ^
 -- bad function name 
 drop function 314159();
-ERROR:  syntax error at or near "314159" at character 15
+ERROR:  syntax error at or near "314159"
 LINE 1: drop function 314159();
                       ^
 -- no such function 
@@ -190,12 +198,12 @@ ERROR:  function nonesuch() does not exist
  
 -- missing type name 
 drop type;
-ERROR:  syntax error at or near ";" at character 10
+ERROR:  syntax error at or near ";"
 LINE 1: drop type;
                  ^
 -- bad type name 
 drop type 314159;
-ERROR:  syntax error at or near "314159" at character 11
+ERROR:  syntax error at or near "314159"
 LINE 1: drop type 314159;
                   ^
 -- no such type 
@@ -206,32 +214,32 @@ ERROR:  type "nonesuch" does not exist
  
 -- missing everything 
 drop operator;
-ERROR:  syntax error at or near ";" at character 14
+ERROR:  syntax error at or near ";"
 LINE 1: drop operator;
                      ^
 -- bad operator name 
 drop operator equals;
-ERROR:  syntax error at or near ";" at character 21
+ERROR:  syntax error at or near ";"
 LINE 1: drop operator equals;
                             ^
 -- missing type list 
 drop operator ===;
-ERROR:  syntax error at or near ";" at character 18
+ERROR:  syntax error at or near ";"
 LINE 1: drop operator ===;
                          ^
 -- missing parentheses 
 drop operator int4, int4;
-ERROR:  syntax error at or near "," at character 19
+ERROR:  syntax error at or near ","
 LINE 1: drop operator int4, int4;
                           ^
 -- missing operator name 
 drop operator (int4, int4);
-ERROR:  syntax error at or near "(" at character 15
+ERROR:  syntax error at or near "("
 LINE 1: drop operator (int4, int4);
                       ^
 -- missing type list contents 
 drop operator === ();
-ERROR:  syntax error at or near ")" at character 20
+ERROR:  syntax error at or near ")"
 LINE 1: drop operator === ();
                            ^
 -- no such operator 
@@ -247,18 +255,18 @@ ERROR:  missing argument
 HINT:  Use NONE to denote the missing argument of a unary operator.
 -- no such type1 
 drop operator = ( , int4);
-ERROR:  syntax error at or near "," at character 19
+ERROR:  syntax error at or near ","
 LINE 1: drop operator = ( , int4);
                           ^
 -- no such type1 
 drop operator = (nonesuch, int4);
-ERROR:  type nonesuch does not exist
+ERROR:  type "nonesuch" does not exist
 -- no such type2 
 drop operator = (int4, nonesuch);
-ERROR:  type nonesuch does not exist
+ERROR:  type "nonesuch" does not exist
 -- no such type2 
 drop operator = (int4, );
-ERROR:  syntax error at or near ")" at character 24
+ERROR:  syntax error at or near ")"
 LINE 1: drop operator = (int4, );
                                ^
 --
@@ -266,12 +274,12 @@ LINE 1: drop operator = (int4, );
  
 -- missing rule name 
 drop rule;
-ERROR:  syntax error at or near ";" at character 10
+ERROR:  syntax error at or near ";"
 LINE 1: drop rule;
                  ^
 -- bad rule name 
 drop rule 314159;
-ERROR:  syntax error at or near "314159" at character 11
+ERROR:  syntax error at or near "314159"
 LINE 1: drop rule 314159;
                   ^
 -- no such rule 
@@ -279,15 +287,15 @@ drop rule nonesuch on noplace;
 ERROR:  relation "noplace" does not exist
 -- these postquel variants are no longer supported
 drop tuple rule nonesuch;
-ERROR:  syntax error at or near "tuple" at character 6
+ERROR:  syntax error at or near "tuple"
 LINE 1: drop tuple rule nonesuch;
              ^
 drop instance rule nonesuch on noplace;
-ERROR:  syntax error at or near "instance" at character 6
+ERROR:  syntax error at or near "instance"
 LINE 1: drop instance rule nonesuch on noplace;
              ^
 drop rewrite rule nonesuch;
-ERROR:  syntax error at or near "rewrite" at character 6
+ERROR:  syntax error at or near "rewrite"
 LINE 1: drop rewrite rule nonesuch;
              ^
 --
@@ -319,35 +327,35 @@ ERROR:  division by zero
 -- Test psql's reporting of syntax error location
 --
 xxx;
-ERROR:  syntax error at or near "xxx" at character 1
+ERROR:  syntax error at or near "xxx"
 LINE 1: xxx;
         ^
 CREATE foo;
-ERROR:  syntax error at or near "foo" at character 8
+ERROR:  syntax error at or near "foo"
 LINE 1: CREATE foo;
                ^
 CREATE TABLE ;
-ERROR:  syntax error at or near ";" at character 14
+ERROR:  syntax error at or near ";"
 LINE 1: CREATE TABLE ;
                      ^
 CREATE TABLE
 \g
-ERROR:  syntax error at end of input at character 13
+ERROR:  syntax error at end of input
 LINE 1: CREATE TABLE
                     ^
 INSERT INTO foo VALUES(123) foo;
-ERROR:  syntax error at or near "foo" at character 29
+ERROR:  syntax error at or near "foo"
 LINE 1: INSERT INTO foo VALUES(123) foo;
                                     ^
 INSERT INTO 123
 VALUES(123);
-ERROR:  syntax error at or near "123" at character 13
+ERROR:  syntax error at or near "123"
 LINE 1: INSERT INTO 123
                     ^
 INSERT INTO foo 
 VALUES(123) 123
 ;
-ERROR:  syntax error at or near "123" at character 30
+ERROR:  syntax error at or near "123"
 LINE 2: VALUES(123) 123
                     ^
 -- with a tab
@@ -355,24 +363,24 @@ CREATE TABLE foo
   (id INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY,
        id3 INTEGER NOT NUL,
    id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL);
-ERROR:  syntax error at or near "NUL" at character 94
+ERROR:  syntax error at or near "NUL"
 LINE 3:  id3 INTEGER NOT NUL,
                          ^
 -- long line to be truncated on the left
 CREATE TABLE foo(id INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, 
 id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL);
-ERROR:  syntax error at or near "NUL" at character 90
+ERROR:  syntax error at or near "NUL"
 LINE 1: ...T NULL, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, 
                                                                   ^
 -- long line to be truncated on the right
 CREATE TABLE foo(
 id3 INTEGER NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL, id INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY);
-ERROR:  syntax error at or near "NUL" at character 35
+ERROR:  syntax error at or near "NUL"
 LINE 2: id3 INTEGER NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQ...
                         ^
 -- long line to be truncated both ways
 CREATE TABLE foo(id INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL);
-ERROR:  syntax error at or near "NUL" at character 90
+ERROR:  syntax error at or near "NUL"
 LINE 1: ...L, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, id4 I...
                                                              ^
 -- long line to be truncated on the left, many lines
@@ -389,7 +397,7 @@ UNIQUE
 NOT 
 NULL)
 ;
-ERROR:  syntax error at or near "NUL" at character 101
+ERROR:  syntax error at or near "NUL"
 LINE 4: ...T NULL, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, 
                                                                   ^
 -- long line to be truncated on the right, many lines
@@ -399,7 +407,7 @@ TABLE
 foo(
 id3 INTEGER NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL, id INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY)
 ;
-ERROR:  syntax error at or near "NUL" at character 47
+ERROR:  syntax error at or near "NUL"
 LINE 5: id3 INTEGER NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQ...
                         ^
 -- long line to be truncated both ways, many lines
@@ -412,7 +420,7 @@ INT4
 UNIQUE NOT NULL, idx INT4 UNIQUE NOT NULL, idy INT4 UNIQUE NOT NULL, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, id4 INT4 UNIQUE NOT NULL, id5 TEXT UNIQUE NOT NULL, 
 idz INT4 UNIQUE NOT NULL, 
 idv INT4 UNIQUE NOT NULL);
-ERROR:  syntax error at or near "NUL" at character 157
+ERROR:  syntax error at or near "NUL"
 LINE 7: ...L, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, id4 I...
                                                              ^
 -- more than 10 lines...
@@ -438,7 +446,7 @@ INT4
 UNIQUE 
 NOT 
 NULL);
-ERROR:  syntax error at or near "NUL" at character 190
+ERROR:  syntax error at or near "NUL"
 LINE 16: ...L, id2 TEXT NOT NULL PRIMARY KEY, id3 INTEGER NOT NUL, id4 I...
                                                               ^
 -- Check that stack depth detection mechanism works and
index bdb4aa54778d0f26c7e06aa01ab875c9a704491e..ef8f4ec7932c77f119ecd22285c90e0491234035 100644 (file)
@@ -105,6 +105,8 @@ SELECT '' AS one, p1.f1
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 ERROR:  operator does not exist: lseg # point
+LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
+                                           ^
 HINT:  No operator matches the given name and argument type(s). You may need to add explicit type casts.
 -- closest point
 SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
index 2a61b34a7ada5ccb94829086722fc64940f80227..a60b91301a7ccc15f2a3c82e019ee0d9749d9fdb 100644 (file)
@@ -105,6 +105,8 @@ SELECT '' AS one, p1.f1
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 ERROR:  operator does not exist: lseg # point
+LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
+                                           ^
 HINT:  No operator matches the given name and argument type(s). You may need to add explicit type casts.
 -- closest point
 SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
index af3ee4084049d06010da00a8ff44a9dd0dccc06d..3b864ffe779585d524aa8cfcf572ee3b28884cbd 100644 (file)
@@ -105,6 +105,8 @@ SELECT '' AS one, p1.f1
 SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
    FROM LSEG_TBL l, POINT_TBL p;
 ERROR:  operator does not exist: lseg # point
+LINE 1: SELECT '' AS count, p.f1, l.s, l.s # p.f1 AS intersection
+                                           ^
 HINT:  No operator matches the given name and argument type(s). You may need to add explicit type casts.
 -- closest point
 SELECT '' AS thirty, p.f1, l.s, p.f1 ## l.s AS closest
index 392d1feedd671b65b819bddd5c87416cad2cb863..ea22c443861e50c742858a37153fe59295bbb531 100644 (file)
@@ -306,6 +306,8 @@ SELECT date '1991-02-03' - time '04:05:06' AS "Subtract Time";
 
 SELECT date '1991-02-03' - time with time zone '04:05:06 UTC' AS "Subtract Time UTC";
 ERROR:  operator does not exist: date - time with time zone
+LINE 1: SELECT date '1991-02-03' - time with time zone '04:05:06 UTC...
+                                 ^
 HINT:  No operator matches the given name and argument type(s). You may need to add explicit type casts.
 --
 -- timestamp, interval arithmetic
index 0a7c5605cd255a611bd97b2b924ae194316ed3d2..b110f08130010e1fc34e59ee49c2eff37e5c4cdb 100644 (file)
@@ -337,6 +337,8 @@ SELECT '' AS "xxx", *
 SELECT '' AS "xxx", i, k, t
   FROM J1_TBL CROSS JOIN J2_TBL;
 ERROR:  column reference "i" is ambiguous
+LINE 1: SELECT '' AS "xxx", i, k, t
+                            ^
 -- resolve previous ambiguity by specifying the table name
 SELECT '' AS "xxx", t1.i, k, t
   FROM J1_TBL t1 CROSS JOIN J2_TBL t2;
index 289ccb6c9f7940abc972c457aef0d97c4493eb53..172d6d6fe8ab3fc1285ae1848d76aa2c1491239f 100644 (file)
@@ -337,6 +337,8 @@ SELECT '' AS "xxx", *
 SELECT '' AS "xxx", i, k, t
   FROM J1_TBL CROSS JOIN J2_TBL;
 ERROR:  column reference "i" is ambiguous
+LINE 1: SELECT '' AS "xxx", i, k, t
+                            ^
 -- resolve previous ambiguity by specifying the table name
 SELECT '' AS "xxx", t1.i, k, t
   FROM J1_TBL t1 CROSS JOIN J2_TBL t2;
index 5617b6ef0103db9f6a23c190bfdeb4a644f71f1b..e72383bbb72c27b9e5a471cb44ce23ffd718613b 100644 (file)
@@ -1747,7 +1747,7 @@ create function f1(in i int, out j int) returns int as $$
 begin
   return i+1;
 end$$ language plpgsql;
-ERROR:  RETURN cannot have a parameter in function with OUT parameters at or near "i" at character 74
+ERROR:  RETURN cannot have a parameter in function with OUT parameters at or near "i"
 LINE 3:   return i+1;
                  ^
 create function f1(in i int, out j int) as $$
@@ -2323,11 +2323,11 @@ begin
     a := 10;
     return a;
 end$$ language plpgsql;
-ERROR:  syntax error at or near "Johnny" at character 1
-QUERY:  Johnny Yuma
-CONTEXT:  SQL statement in PL/PgSQL function "bad_sql1" near line 4
+ERROR:  syntax error at or near "Johnny"
 LINE 1: Johnny Yuma
         ^
+QUERY:  Johnny Yuma
+CONTEXT:  SQL statement in PL/PgSQL function "bad_sql1" near line 4
 create function bad_sql2() returns int as $$
 declare r record;
 begin
@@ -2336,27 +2336,27 @@ begin
     end loop;
     return 5;
 end;$$ language plpgsql;
-ERROR:  syntax error at or near "fought" at character 11
-QUERY:   select I fought the law, the law won
-CONTEXT:  SQL statement in PL/PgSQL function "bad_sql2" near line 3
+ERROR:  syntax error at or near "fought"
 LINE 1:  select I fought the law, the law won
                   ^
+QUERY:   select I fought the law, the law won
+CONTEXT:  SQL statement in PL/PgSQL function "bad_sql2" near line 3
 -- a RETURN expression is mandatory, except for void-returning
 -- functions, where it is not allowed
 create function missing_return_expr() returns int as $$
 begin
     return ;
 end;$$ language plpgsql;
-ERROR:  syntax error at end of input at character 8
-QUERY:  SELECT 
-CONTEXT:  SQL statement in PL/PgSQL function "missing_return_expr" near line 2
+ERROR:  syntax error at end of input
 LINE 1: SELECT 
                ^
+QUERY:  SELECT 
+CONTEXT:  SQL statement in PL/PgSQL function "missing_return_expr" near line 2
 create function void_return_expr() returns void as $$
 begin
     return 5;
 end;$$ language plpgsql;
-ERROR:  RETURN cannot have a parameter in function returning void at or near "5" at character 72
+ERROR:  RETURN cannot have a parameter in function returning void at or near "5"
 LINE 3:     return 5;
                    ^
 -- VOID functions are allowed to omit RETURN
@@ -2426,8 +2426,10 @@ end; $$ language plpgsql;
 -- blocks
 select excpt_test1();
 ERROR:  column "sqlstate" does not exist
-CONTEXT:  SQL statement "SELECT  sqlstate"
-PL/pgSQL function "excpt_test1" line 2 at raise
+LINE 1: SELECT  sqlstate
+                ^
+QUERY:  SELECT  sqlstate
+CONTEXT:  PL/pgSQL function "excpt_test1" line 2 at raise
 create function excpt_test2() returns void as $$
 begin
     begin
@@ -2439,8 +2441,10 @@ end; $$ language plpgsql;
 -- should fail
 select excpt_test2();
 ERROR:  column "sqlstate" does not exist
-CONTEXT:  SQL statement "SELECT  sqlstate"
-PL/pgSQL function "excpt_test2" line 4 at raise
+LINE 1: SELECT  sqlstate
+                ^
+QUERY:  SELECT  sqlstate
+CONTEXT:  PL/pgSQL function "excpt_test2" line 4 at raise
 create function excpt_test3() returns void as $$
 begin
     begin
@@ -2695,7 +2699,7 @@ begin
   end loop flbl1;
 end;
 $$ language plpgsql;
-ERROR:  no such label at or near "flbl1" at character 101
+ERROR:  no such label at or near "flbl1"
 LINE 5:   end loop flbl1;
                    ^
 -- should fail: end label does not match start label
index b2cb3c2f9a0bc9f54d543be5315bb45af4500a81..902acba4c2679ff72d01e01121c6e148b5ed0d2f 100644 (file)
@@ -116,6 +116,8 @@ HINT:  You will need to rewrite or cast the expression.
 -- invalid type
 PREPARE q4(nonexistenttype) AS SELECT $1;
 ERROR:  type "nonexistenttype" does not exist
+LINE 1: PREPARE q4(nonexistenttype) AS SELECT $1;
+                   ^
 -- create table as execute
 PREPARE q5(int, text) AS
        SELECT * FROM tenk1 WHERE unique1 = $1 OR stringu1 = $2;
index c6b1bfac3982e1276ff9f6ba66cf305ddef8b5fe..5b4d9555aed9a45aeadee9d505a7286dd2494f26 100644 (file)
@@ -63,6 +63,8 @@ begin;
 set local add_missing_from = false;
 select f1, q.c1 from quadtable;                -- fails, q is a table reference
 ERROR:  missing FROM-clause entry for table "q"
+LINE 1: select f1, q.c1 from quadtable;
+                   ^
 rollback;
 select f1, (q).c1, (qq.q).c1.i from quadtable qq;
  f1 |    c1     |  i  
@@ -199,6 +201,8 @@ select ROW('ABC','DEF') ~>=~ ROW('DEF','ABC') as false;
 
 select ROW('ABC','DEF') ~~ ROW('DEF','ABC') as fail;
 ERROR:  could not determine interpretation of row comparison operator ~~
+LINE 1: select ROW('ABC','DEF') ~~ ROW('DEF','ABC') as fail;
+                                ^
 HINT:  Row comparison operators must be associated with btree operator classes.
 -- Check row comparison with a subselect
 select unique1, unique2 from tenk1
index 4c8022d04021da337af93b152d26c9ac8dacfc59..1ee7f9b7358d2e6b540a4028c400a7ce65ed848e 100644 (file)
@@ -121,6 +121,8 @@ SELECT count(*) FROM test_missing_target x, test_missing_target y
        WHERE x.a = y.a
        GROUP BY b ORDER BY b;
 ERROR:  column reference "b" is ambiguous
+LINE 3:  GROUP BY b ORDER BY b;
+                             ^
 --   order w/ target under ambiguous condition
 --   failure NOT expected
 SELECT a, a FROM test_missing_target
@@ -287,6 +289,8 @@ SELECT count(x.a) FROM test_missing_target x, test_missing_target y
        WHERE x.a = y.a
        GROUP BY b/2 ORDER BY b/2;
 ERROR:  column reference "b" is ambiguous
+LINE 3:  GROUP BY b/2 ORDER BY b/2;
+                               ^
 --   group w/ existing GROUP BY target under ambiguous condition
 SELECT x.b/2, count(x.b) FROM test_missing_target x, test_missing_target y 
        WHERE x.a = y.a
@@ -304,6 +308,8 @@ SELECT count(b) FROM test_missing_target x, test_missing_target y
        WHERE x.a = y.a
        GROUP BY x.b/2;
 ERROR:  column reference "b" is ambiguous
+LINE 1: SELECT count(b) FROM test_missing_target x, test_missing_tar...
+                     ^
 --   group w/o existing GROUP BY target under ambiguous condition
 --   into a table
 SELECT count(x.b) INTO TABLE test_missing_target3 
index 7e316ddbb710004157f15a3a9ad1980a72fb6d50..85092ef046cf23b37aa475c347a5cbfd94b250ac 100644 (file)
@@ -121,6 +121,8 @@ SELECT count(*) FROM test_missing_target x, test_missing_target y
        WHERE x.a = y.a
        GROUP BY b ORDER BY b;
 ERROR:  column reference "b" is ambiguous
+LINE 3:  GROUP BY b ORDER BY b;
+                             ^
 --   order w/ target under ambiguous condition
 --   failure NOT expected
 SELECT a, a FROM test_missing_target
@@ -287,6 +289,8 @@ SELECT count(x.a) FROM test_missing_target x, test_missing_target y
        WHERE x.a = y.a
        GROUP BY b/2 ORDER BY b/2;
 ERROR:  column reference "b" is ambiguous
+LINE 3:  GROUP BY b/2 ORDER BY b/2;
+                               ^
 --   group w/ existing GROUP BY target under ambiguous condition
 SELECT x.b/2, count(x.b) FROM test_missing_target x, test_missing_target y 
        WHERE x.a = y.a
@@ -304,6 +308,8 @@ SELECT count(b) FROM test_missing_target x, test_missing_target y
        WHERE x.a = y.a
        GROUP BY x.b/2;
 ERROR:  column reference "b" is ambiguous
+LINE 1: SELECT count(b) FROM test_missing_target x, test_missing_tar...
+                     ^
 --   group w/o existing GROUP BY target under ambiguous condition
 --   into a table
 SELECT count(x.b) INTO TABLE test_missing_target3 
index b45197f2de45e2cb74de17e70153ec0e4d3fe1ce..718eb09f058101127db6e7db55157445ed7a9c10 100644 (file)
@@ -121,6 +121,8 @@ SELECT count(*) FROM test_missing_target x, test_missing_target y
        WHERE x.a = y.a
        GROUP BY b ORDER BY b;
 ERROR:  column reference "b" is ambiguous
+LINE 3:  GROUP BY b ORDER BY b;
+                             ^
 --   order w/ target under ambiguous condition
 --   failure NOT expected
 SELECT a, a FROM test_missing_target
@@ -287,6 +289,8 @@ SELECT count(x.a) FROM test_missing_target x, test_missing_target y
        WHERE x.a = y.a
        GROUP BY b/2 ORDER BY b/2;
 ERROR:  column reference "b" is ambiguous
+LINE 3:  GROUP BY b/2 ORDER BY b/2;
+                               ^
 --   group w/ existing GROUP BY target under ambiguous condition
 SELECT x.b/2, count(x.b) FROM test_missing_target x, test_missing_target y 
        WHERE x.a = y.a
@@ -304,6 +308,8 @@ SELECT count(b) FROM test_missing_target x, test_missing_target y
        WHERE x.a = y.a
        GROUP BY x.b/2;
 ERROR:  column reference "b" is ambiguous
+LINE 1: SELECT count(b) FROM test_missing_target x, test_missing_tar...
+                     ^
 --   group w/o existing GROUP BY target under ambiguous condition
 --   into a table
 SELECT count(x.b) INTO TABLE test_missing_target3 
index 6faf3c69ad542b0fc35df7adc31d4050e9c94afe..0c9b88ee8f0ee6d62b1a94ed2fee30cbac5ba014 100644 (file)
@@ -18,7 +18,7 @@ SELECT 'first line'
 ' - next line' /* this comment is not allowed here */
 ' - third line'
        AS "Illegal comment within continuation";
-ERROR:  syntax error at or near "' - third line'" at character 75
+ERROR:  syntax error at or near "' - third line'"
 LINE 3: ' - third line'
         ^
 --
@@ -927,17 +927,29 @@ show standard_conforming_strings;
 (1 row)
 
 select 'a\bcd' as f1, 'a\b''cd' as f2, 'a\b''''cd' as f3, 'abcd\'   as f4, 'ab\''cd' as f5, '\\' as f6;
-WARNING:  nonstandard use of escape in a string literal at character 8
+WARNING:  nonstandard use of escape in a string literal
+LINE 1: select 'a\bcd' as f1, 'a\b''cd' as f2, 'a\b''''cd' as f3, 'a...
+               ^
 HINT:  Use the escape string syntax for escapes, e.g., E'\r\n'.
-WARNING:  nonstandard use of escape in a string literal at character 23
+WARNING:  nonstandard use of escape in a string literal
+LINE 1: select 'a\bcd' as f1, 'a\b''cd' as f2, 'a\b''''cd' as f3, 'a...
+                              ^
 HINT:  Use the escape string syntax for escapes, e.g., E'\r\n'.
-WARNING:  nonstandard use of escape in a string literal at character 40
+WARNING:  nonstandard use of escape in a string literal
+LINE 1: select 'a\bcd' as f1, 'a\b''cd' as f2, 'a\b''''cd' as f3, 'a...
+                                               ^
 HINT:  Use the escape string syntax for escapes, e.g., E'\r\n'.
-WARNING:  nonstandard use of escape in a string literal at character 59
+WARNING:  nonstandard use of escape in a string literal
+LINE 1: ...a\bcd' as f1, 'a\b''cd' as f2, 'a\b''''cd' as f3, 'abcd\'   ...
+                                                             ^
 HINT:  Use the escape string syntax for escapes, e.g., E'\r\n'.
-WARNING:  nonstandard use of escape in a string literal at character 76
+WARNING:  nonstandard use of escape in a string literal
+LINE 1: ...b''cd' as f2, 'a\b''''cd' as f3, 'abcd\'   as f4, 'ab\''cd' ...
+                                                             ^
 HINT:  Use the escape string syntax for escapes, e.g., E'\r\n'.
-WARNING:  nonstandard use of escape in a string literal at character 93
+WARNING:  nonstandard use of escape in a string literal
+LINE 1: ...b''''cd' as f3, 'abcd\'   as f4, 'ab\''cd' as f5, '\\' as f6...
+                                                             ^
 HINT:  Use the escape string syntax for escapes, e.g., E'\r\n'.
   f1   |   f2   |   f3    |  f4   |   f5   | f6 
 -------+--------+---------+-------+--------+----
@@ -946,17 +958,29 @@ HINT:  Use the escape string syntax for escapes, e.g., E'\r\n'.
 
 set standard_conforming_strings = off;
 select 'a\\bcd' as f1, 'a\\b\'cd' as f2, 'a\\b\'''cd' as f3, 'abcd\\'   as f4, 'ab\\\'cd' as f5, '\\\\' as f6;
-WARNING:  nonstandard use of \\ in a string literal at character 8
+WARNING:  nonstandard use of \\ in a string literal
+LINE 1: select 'a\\bcd' as f1, 'a\\b\'cd' as f2, 'a\\b\'''cd' as f3,...
+               ^
 HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
-WARNING:  nonstandard use of \\ in a string literal at character 24
+WARNING:  nonstandard use of \\ in a string literal
+LINE 1: select 'a\\bcd' as f1, 'a\\b\'cd' as f2, 'a\\b\'''cd' as f3,...
+                               ^
 HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
-WARNING:  nonstandard use of \\ in a string literal at character 42
+WARNING:  nonstandard use of \\ in a string literal
+LINE 1: select 'a\\bcd' as f1, 'a\\b\'cd' as f2, 'a\\b\'''cd' as f3,...
+                                                 ^
 HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
-WARNING:  nonstandard use of \\ in a string literal at character 62
+WARNING:  nonstandard use of \\ in a string literal
+LINE 1: ...bcd' as f1, 'a\\b\'cd' as f2, 'a\\b\'''cd' as f3, 'abcd\\'  ...
+                                                             ^
 HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
-WARNING:  nonstandard use of \\ in a string literal at character 80
+WARNING:  nonstandard use of \\ in a string literal
+LINE 1: ...'cd' as f2, 'a\\b\'''cd' as f3, 'abcd\\'   as f4, 'ab\\\'cd'...
+                                                             ^
 HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
-WARNING:  nonstandard use of \\ in a string literal at character 98
+WARNING:  nonstandard use of \\ in a string literal
+LINE 1: ...'''cd' as f3, 'abcd\\'   as f4, 'ab\\\'cd' as f5, '\\\\' as ...
+                                                             ^
 HINT:  Use the escape string syntax for backslashes, e.g., E'\\'.
   f1   |   f2   |   f3    |  f4   |   f5   | f6 
 -------+--------+---------+-------+--------+----
index a562c29691e9e832d5b9ff44312588f6897ce893..f85dcdbd7ab3f31b91c1486a16c6642165bce854 100644 (file)
@@ -70,4 +70,6 @@ SELECT f1 AS "Eight" FROM TIME_TBL WHERE f1 >= '00:00';
 -- where we do mixed-type arithmetic. - thomas 2000-12-02
 SELECT f1 + time '00:01' AS "Illegal" FROM TIME_TBL;
 ERROR:  operator is not unique: time without time zone + time without time zone
+LINE 1: SELECT f1 + time '00:01' AS "Illegal" FROM TIME_TBL;
+                  ^
 HINT:  Could not choose a best candidate operator. You may need to add explicit type casts.
index 20a394a79a048b85701a143ff3a462da8955dd51..cd330635afe0833375a9d3e79cc1c01c2e39db50 100644 (file)
@@ -77,4 +77,6 @@ SELECT f1 AS "Ten" FROM TIMETZ_TBL WHERE f1 >= '00:00-07';
 -- where we do mixed-type arithmetic. - thomas 2000-12-02
 SELECT f1 + time with time zone '00:01' AS "Illegal" FROM TIMETZ_TBL;
 ERROR:  operator does not exist: time with time zone + time with time zone
+LINE 1: SELECT f1 + time with time zone '00:01' AS "Illegal" FROM TI...
+                  ^
 HINT:  No operator matches the given name and argument type(s). You may need to add explicit type casts.
index 047bba8f70a6ae8698cd9ce540da085a72f4e2f6..8d3be84d63d6bff46c73f4e47f9665ed0c678e87 100644 (file)
@@ -140,6 +140,8 @@ BEGIN;
        SAVEPOINT one;
                SELECT foo;
 ERROR:  column "foo" does not exist
+LINE 1: SELECT foo;
+               ^
        ROLLBACK TO SAVEPOINT one;
        RELEASE SAVEPOINT one;
        SAVEPOINT two;
@@ -188,6 +190,8 @@ BEGIN;
                INSERT INTO savepoints VALUES (5);
                SELECT foo;
 ERROR:  column "foo" does not exist
+LINE 1: SELECT foo;
+               ^
 COMMIT;
 SELECT * FROM savepoints;
  a 
index d09d9a81647c837f63d1e44ae2e10a68f97cd76e..abcbc9503a8bbebbb4be6115fb7c9a0d36bbc466 100644 (file)
@@ -405,6 +405,8 @@ ORDER BY q2,q1;
 -- This should fail, because q2 isn't a name of an EXCEPT output column
 SELECT q1 FROM int8_tbl EXCEPT SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1;
 ERROR:  column "q2" does not exist
+LINE 1: ... int8_tbl EXCEPT SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1...
+                                                             ^
 -- But this should work:
 SELECT q1 FROM int8_tbl EXCEPT (((SELECT q2 FROM int8_tbl ORDER BY q2 LIMIT 1)));
         q1        
index 1ff7c8918f5184e6c7154ac2ec49a7f9055ecaa3..9849e9053920df53d1c61b6b48217e8aa1b9de5b 100644 (file)
@@ -45,6 +45,8 @@ BEGIN;
 SET LOCAL add_missing_from = false;
 UPDATE update_test AS t SET b = update_test.b + 10 WHERE t.a = 10;
 ERROR:  invalid reference to FROM-clause entry for table "update_test"
+LINE 1: UPDATE update_test AS t SET b = update_test.b + 10 WHERE t.a...
+                                        ^
 HINT:  Perhaps you meant to reference the table alias "t".
 ROLLBACK;
 DROP TABLE update_test;
index 5e46aa8ebee80557b7ee2145beee1610006cbc08..c32daf815d6251e3eed4bd5098c81778d0be1fb9 100644 (file)
@@ -43,6 +43,8 @@ SELECT count(oid) FROM wi;
 -- should fail
 SELECT count(oid) FROM wo;
 ERROR:  column "oid" does not exist
+LINE 1: SELECT count(oid) FROM wo;
+                     ^
 VACUUM ANALYZE wi;
 VACUUM ANALYZE wo;
 SELECT min(relpages) < max(relpages), min(reltuples) - max(reltuples)
@@ -76,6 +78,8 @@ SELECT count(oid) FROM create_table_test2;
 -- should fail
 SELECT count(oid) FROM create_table_test3;
 ERROR:  column "oid" does not exist
+LINE 1: SELECT count(oid) FROM create_table_test3;
+                     ^
 PREPARE table_source(int) AS
     SELECT a + b AS c1, a - b AS c2, $1 AS c3 FROM create_table_test;
 CREATE TABLE execute_with WITH OIDS AS EXECUTE table_source(1);
@@ -89,6 +93,8 @@ SELECT count(oid) FROM execute_with;
 -- should fail
 SELECT count(oid) FROM execute_without;
 ERROR:  column "oid" does not exist
+LINE 1: SELECT count(oid) FROM execute_without;
+                     ^
 DROP TABLE create_table_test;
 DROP TABLE create_table_test2;
 DROP TABLE create_table_test3;
index 5ba46c062fc77cdbb3c74cd70a8c29a3c5e73c44..e40c445014e68537a253f2da4063091b2d313d7c 100644 (file)
@@ -45,14 +45,14 @@ SELECT '' AS four, * FROM DEFAULTEXPR_TBL;
 -- syntax errors
 --  test for extraneous comma
 CREATE TABLE error_tbl (i int DEFAULT (100, ));
-ERROR:  syntax error at or near ")" at character 45
+ERROR:  syntax error at or near ")"
 LINE 1: CREATE TABLE error_tbl (i int DEFAULT (100, ));
                                                     ^
 --  this will fail because gram.y uses b_expr not a_expr for defaults,
 --  to avoid a shift/reduce conflict that arises from NOT NULL being
 --  part of the column definition syntax:
 CREATE TABLE error_tbl (b1 bool DEFAULT 1 IN (1, 2));
-ERROR:  syntax error at or near "IN" at character 43
+ERROR:  syntax error at or near "IN"
 LINE 1: CREATE TABLE error_tbl (b1 bool DEFAULT 1 IN (1, 2));
                                                   ^
 --  this should work, however:
index a3c506598f6701ad7da0464bfc7b3aa22150c632..e7fd46130f0d96e86d2da8e8985a21438e53c17e 100644 (file)
@@ -55,7 +55,7 @@ DETAIL:  Actual return type is "unknown".
 CONTEXT:  SQL function "test1"
 CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL
     AS 'not even SQL';
-ERROR:  syntax error at or near "not" at character 62
+ERROR:  syntax error at or near "not"
 LINE 2:     AS 'not even SQL';
                 ^
 CREATE FUNCTION test1 (int) RETURNS int LANGUAGE SQL