Commit 20ab467d authored by Tom Lane's avatar Tom Lane

Improve parser so that we can show an error cursor position for errors

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.
parent 48fb6967
......@@ -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?
----------
......
......@@ -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 */
......
......@@ -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
......
......@@ -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;
......
......@@ -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;
......
......@@ -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),
......
......@@ -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;
}
return makeTypeNameFromNameList(list_make1(def->arg));
default:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
......
......@@ -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),
......
......@@ -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 */
......
......@@ -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);
......
......@@ -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)
{
......
......@@ -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;
......
......@@ -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));
}
/*
......
This diff is collapsed.
......@@ -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;
......
......@@ -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);
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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;
}
......
......@@ -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
......
......@@ -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();
}
......
......@@ -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))
{
/*
......
......@@ -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)
......
......@@ -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);
}
......
This diff is collapsed.
......@@ -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;
......
This diff is collapsed.
......@@ -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,
......
......@@ -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
......
This diff is collapsed.
......@@ -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)));
}
}
......@@ -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);
......
......@@ -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 $
*
*-------------------------------------------------------------------------
*/
......@@ -35,9 +35,11 @@
*
* 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);
......
......@@ -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 */
}
......@@ -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);
......
......@@ -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);
......
......@@ -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();
}
......
......@@ -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 $
*
*-------------------------------------------------------------------------
*/
......@@ -18,10 +18,10 @@
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);
......
......@@ -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;
/*
......
......@@ -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 $
*
*-------------------------------------------------------------------------
*/
......@@ -16,9 +16,10 @@
#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);
......
......@@ -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 $
*
*-------------------------------------------------------------------------
*/
......@@ -17,6 +17,15 @@
#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);
......
......@@ -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,
......
......@@ -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 $
*
*-------------------------------------------------------------------------
*/
......@@ -20,6 +20,15 @@
/*
* 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,
......
......@@ -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 $
*
*-------------------------------------------------------------------------
*/
......@@ -21,20 +21,27 @@
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 */
......@@ -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);
......
......@@ -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 $
*
*-------------------------------------------------------------------------
*/
......@@ -20,10 +20,10 @@
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);
......
......@@ -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,
......
......@@ -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)
......
......@@ -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.
......
......@@ -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)
{
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);
appendPQExpBuffer(&workBuf, libpq_gettext(" at character %s"),
val);
}
}
else
{
val = PQresultErrorField(res, PG_DIAG_INTERNAL_POSITION);
if (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.
......
......@@ -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 */
......
......@@ -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 $$
......
/**********************************************************************
* 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 $
*
**********************************************************************/
......@@ -19,12 +19,13 @@
#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)));
List *names;
HeapTuple typeTup;
typeTup = typenameType(typename);
/* 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);
}
/************************************************************
......
......@@ -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;
......
/**********************************************************************
* 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 */
......
......@@ -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);
}
/************************************************************
......
......@@ -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
-----
......
......@@ -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?
......
This diff is collapsed.
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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;
......
......@@ -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;
......
This diff is collapsed.
......@@ -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;
......
......@@ -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
......
This diff is collapsed.
......@@ -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.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment