Commit fbd26d69 authored by Tom Lane's avatar Tom Lane

Arrange that no database accesses are attempted during parser() --- this

took some rejiggering of typename and ACL parsing, as well as moving
parse_analyze call out of parser().  Restructure postgres.c processing
so that parse analysis and rewrite are skipped when in abort-transaction
state.  Only COMMIT and ABORT statements will be processed beyond the raw
parser() phase.  This addresses problem of parser failing with database access
errors while in aborted state (see pghackers discussions around 7/28/00).
Also fix some bugs with COMMIT/ABORT statements appearing in the middle of
a single query input string.
Function, operator, and aggregate arguments/results can now use full
TypeName production, in particular foo[] for array types.
DROP OPERATOR and COMMENT ON OPERATOR were broken for unary operators.
Allow CREATE AGGREGATE to accept unquoted numeric constants for initcond.
parent 4837270b
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.48 2000/08/21 20:55:31 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.49 2000/10/07 00:58:15 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -93,35 +93,34 @@ ProcedureCreate(char *procedureName, ...@@ -93,35 +93,34 @@ ProcedureCreate(char *procedureName,
MemSet(typev, 0, FUNC_MAX_ARGS * sizeof(Oid)); MemSet(typev, 0, FUNC_MAX_ARGS * sizeof(Oid));
foreach(x, argList) foreach(x, argList)
{ {
Value *t = lfirst(x); TypeName *t = (TypeName *) lfirst(x);
char *typnam = TypeNameToInternalName(t);
if (parameterCount >= FUNC_MAX_ARGS) if (parameterCount >= FUNC_MAX_ARGS)
elog(ERROR, "Procedures cannot take more than %d arguments", elog(ERROR, "Procedures cannot take more than %d arguments",
FUNC_MAX_ARGS); FUNC_MAX_ARGS);
if (strcmp(strVal(t), "opaque") == 0) if (strcmp(typnam, "opaque") == 0)
{ {
if (languageObjectId == SQLlanguageId) if (languageObjectId == SQLlanguageId)
elog(ERROR, "ProcedureCreate: sql functions cannot take type \"opaque\""); elog(ERROR, "ProcedureCreate: sql functions cannot take type \"opaque\"");
toid = 0; toid = InvalidOid;
} }
else else
{ {
toid = TypeGet(strVal(t), &defined); toid = TypeGet(typnam, &defined);
if (!OidIsValid(toid)) if (!OidIsValid(toid))
{
elog(ERROR, "ProcedureCreate: arg type '%s' is not defined", elog(ERROR, "ProcedureCreate: arg type '%s' is not defined",
strVal(t)); typnam);
}
if (!defined) if (!defined)
{
elog(NOTICE, "ProcedureCreate: arg type '%s' is only a shell", elog(NOTICE, "ProcedureCreate: arg type '%s' is only a shell",
strVal(t)); typnam);
}
} }
if (t->setof)
elog(ERROR, "ProcedureCreate: functions cannot accept set arguments");
typev[parameterCount++] = toid; typev[parameterCount++] = toid;
} }
...@@ -178,7 +177,7 @@ ProcedureCreate(char *procedureName, ...@@ -178,7 +177,7 @@ ProcedureCreate(char *procedureName,
{ {
if (languageObjectId == SQLlanguageId) if (languageObjectId == SQLlanguageId)
elog(ERROR, "ProcedureCreate: sql functions cannot return type \"opaque\""); elog(ERROR, "ProcedureCreate: sql functions cannot return type \"opaque\"");
typeObjectId = 0; typeObjectId = InvalidOid;
} }
else else
{ {
...@@ -194,10 +193,8 @@ ProcedureCreate(char *procedureName, ...@@ -194,10 +193,8 @@ ProcedureCreate(char *procedureName,
returnTypeName); returnTypeName);
} }
else if (!defined) else if (!defined)
{
elog(NOTICE, "ProcedureCreate: return type '%s' is only a shell", elog(NOTICE, "ProcedureCreate: return type '%s' is only a shell",
returnTypeName); returnTypeName);
}
} }
/* /*
...@@ -212,7 +209,6 @@ ProcedureCreate(char *procedureName, ...@@ -212,7 +209,6 @@ ProcedureCreate(char *procedureName,
elog(ERROR, "method %s already an attribute of type %s", elog(ERROR, "method %s already an attribute of type %s",
procedureName, strVal(lfirst(argList))); procedureName, strVal(lfirst(argList)));
/* /*
* If this is a postquel procedure, we parse it here in order to be * If this is a postquel procedure, we parse it here in order to be
* sure that it contains no syntax errors. We should store the plan * sure that it contains no syntax errors. We should store the plan
......
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include "commands/comment.h" #include "commands/comment.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "parser/parse.h" #include "parser/parse.h"
#include "parser/parse_expr.h"
#include "parser/parse_func.h"
#include "rewrite/rewriteRemove.h" #include "rewrite/rewriteRemove.h"
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
...@@ -46,7 +48,7 @@ static void CommentAttribute(char *relation, char *attrib, char *comment); ...@@ -46,7 +48,7 @@ static void CommentAttribute(char *relation, char *attrib, char *comment);
static void CommentDatabase(char *database, char *comment); static void CommentDatabase(char *database, char *comment);
static void CommentRewrite(char *rule, char *comment); static void CommentRewrite(char *rule, char *comment);
static void CommentType(char *type, char *comment); static void CommentType(char *type, char *comment);
static void CommentAggregate(char *aggregate, char *aggtype, char *comment); static void CommentAggregate(char *aggregate, List *arguments, char *comment);
static void CommentProc(char *function, List *arguments, char *comment); static void CommentProc(char *function, List *arguments, char *comment);
static void CommentOperator(char *opname, List *arguments, char *comment); static void CommentOperator(char *opname, List *arguments, char *comment);
static void CommentTrigger(char *trigger, char *relation, char *comments); static void CommentTrigger(char *trigger, char *relation, char *comments);
...@@ -92,7 +94,7 @@ CommentObject(int objtype, char *objname, char *objproperty, ...@@ -92,7 +94,7 @@ CommentObject(int objtype, char *objname, char *objproperty,
CommentType(objname, comment); CommentType(objname, comment);
break; break;
case (AGGREGATE): case (AGGREGATE):
CommentAggregate(objname, objproperty, comment); CommentAggregate(objname, objlist, comment);
break; break;
case (FUNCTION): case (FUNCTION):
CommentProc(objname, objlist, comment); CommentProc(objname, objlist, comment);
...@@ -544,9 +546,10 @@ CommentType(char *type, char *comment) ...@@ -544,9 +546,10 @@ CommentType(char *type, char *comment)
*/ */
static void static void
CommentAggregate(char *aggregate, char *argument, char *comment) CommentAggregate(char *aggregate, List *arguments, char *comment)
{ {
TypeName *aggtype = (TypeName *) lfirst(arguments);
char *aggtypename = NULL;
HeapTuple aggtuple; HeapTuple aggtuple;
Oid baseoid, Oid baseoid,
oid; oid;
...@@ -554,11 +557,12 @@ CommentAggregate(char *aggregate, char *argument, char *comment) ...@@ -554,11 +557,12 @@ CommentAggregate(char *aggregate, char *argument, char *comment)
/*** First, attempt to determine the base aggregate oid ***/ /*** First, attempt to determine the base aggregate oid ***/
if (argument) if (aggtype)
{ {
baseoid = TypeGet(argument, &defined); aggtypename = TypeNameToInternalName(aggtype);
baseoid = TypeGet(aggtypename, &defined);
if (!OidIsValid(baseoid)) if (!OidIsValid(baseoid))
elog(ERROR, "aggregate type '%s' does not exist", argument); elog(ERROR, "type '%s' does not exist", aggtypename);
} }
else else
baseoid = 0; baseoid = 0;
...@@ -568,10 +572,10 @@ CommentAggregate(char *aggregate, char *argument, char *comment) ...@@ -568,10 +572,10 @@ CommentAggregate(char *aggregate, char *argument, char *comment)
#ifndef NO_SECURITY #ifndef NO_SECURITY
if (!pg_aggr_ownercheck(GetUserId(), aggregate, baseoid)) if (!pg_aggr_ownercheck(GetUserId(), aggregate, baseoid))
{ {
if (argument) if (aggtypename)
{ {
elog(ERROR, "you are not permitted to comment on aggregate '%s' %s '%s'", elog(ERROR, "you are not permitted to comment on aggregate '%s' %s '%s'",
aggregate, "with type", argument); aggregate, "with type", aggtypename);
} }
else else
{ {
...@@ -587,10 +591,10 @@ CommentAggregate(char *aggregate, char *argument, char *comment) ...@@ -587,10 +591,10 @@ CommentAggregate(char *aggregate, char *argument, char *comment)
ObjectIdGetDatum(baseoid), 0, 0); ObjectIdGetDatum(baseoid), 0, 0);
if (!HeapTupleIsValid(aggtuple)) if (!HeapTupleIsValid(aggtuple))
{ {
if (argument) if (aggtypename)
{ {
elog(ERROR, "aggregate type '%s' does not exist for aggregate '%s'", elog(ERROR, "aggregate type '%s' does not exist for aggregate '%s'",
argument, aggregate); aggtypename, aggregate);
} }
else else
elog(ERROR, "aggregate '%s' does not exist", aggregate); elog(ERROR, "aggregate '%s' does not exist", aggregate);
...@@ -622,7 +626,6 @@ CommentProc(char *function, List *arguments, char *comment) ...@@ -622,7 +626,6 @@ CommentProc(char *function, List *arguments, char *comment)
functuple; functuple;
Oid oid, Oid oid,
argoids[FUNC_MAX_ARGS]; argoids[FUNC_MAX_ARGS];
char *argument;
int i, int i,
argcount; argcount;
...@@ -635,18 +638,20 @@ CommentProc(char *function, List *arguments, char *comment) ...@@ -635,18 +638,20 @@ CommentProc(char *function, List *arguments, char *comment)
FUNC_MAX_ARGS); FUNC_MAX_ARGS);
for (i = 0; i < argcount; i++) for (i = 0; i < argcount; i++)
{ {
argument = strVal(lfirst(arguments)); TypeName *t = (TypeName *) lfirst(arguments);
char *typnam = TypeNameToInternalName(t);
arguments = lnext(arguments); arguments = lnext(arguments);
if (strcmp(argument, "opaque") == 0)
argoids[i] = 0; if (strcmp(typnam, "opaque") == 0)
argoids[i] = InvalidOid;
else else
{ {
argtuple = SearchSysCacheTuple(TYPENAME, argtuple = SearchSysCacheTuple(TYPENAME,
PointerGetDatum(argument), PointerGetDatum(typnam),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(argtuple)) if (!HeapTupleIsValid(argtuple))
elog(ERROR, "function argument type '%s' does not exist", elog(ERROR, "CommentProc: type '%s' not found", typnam);
argument);
argoids[i] = argtuple->t_data->t_oid; argoids[i] = argtuple->t_data->t_oid;
} }
} }
...@@ -664,10 +669,9 @@ CommentProc(char *function, List *arguments, char *comment) ...@@ -664,10 +669,9 @@ CommentProc(char *function, List *arguments, char *comment)
functuple = SearchSysCacheTuple(PROCNAME, PointerGetDatum(function), functuple = SearchSysCacheTuple(PROCNAME, PointerGetDatum(function),
Int32GetDatum(argcount), Int32GetDatum(argcount),
PointerGetDatum(argoids), 0); PointerGetDatum(argoids), 0);
if (!HeapTupleIsValid(functuple)) if (!HeapTupleIsValid(functuple))
elog(ERROR, "function '%s' with the supplied %s does not exist", func_error("CommentProc", function, argcount, argoids, NULL);
function, "argument list");
oid = functuple->t_data->t_oid; oid = functuple->t_data->t_oid;
/*** Call CreateComments() to create/drop the comments ***/ /*** Call CreateComments() to create/drop the comments ***/
...@@ -691,23 +695,24 @@ CommentProc(char *function, List *arguments, char *comment) ...@@ -691,23 +695,24 @@ CommentProc(char *function, List *arguments, char *comment)
static void static void
CommentOperator(char *opername, List *arguments, char *comment) CommentOperator(char *opername, List *arguments, char *comment)
{ {
TypeName *typenode1 = (TypeName *) lfirst(arguments);
TypeName *typenode2 = (TypeName *) lsecond(arguments);
char oprtype = 0,
*lefttype = NULL,
*righttype = NULL;
Form_pg_operator data; Form_pg_operator data;
HeapTuple optuple; HeapTuple optuple;
Oid oid, Oid oid,
leftoid = InvalidOid, leftoid = InvalidOid,
rightoid = InvalidOid; rightoid = InvalidOid;
bool defined; bool defined;
char oprtype = 0,
*lefttype = NULL,
*righttype = NULL;
/*** Initialize our left and right argument types ***/ /*** Initialize our left and right argument types ***/
if (lfirst(arguments) != NULL) if (typenode1 != NULL)
lefttype = strVal(lfirst(arguments)); lefttype = TypeNameToInternalName(typenode1);
if (lsecond(arguments) != NULL) if (typenode2 != NULL)
righttype = strVal(lsecond(arguments)); righttype = TypeNameToInternalName(typenode2);
/*** Attempt to fetch the left oid, if specified ***/ /*** Attempt to fetch the left oid, if specified ***/
...@@ -732,9 +737,9 @@ CommentOperator(char *opername, List *arguments, char *comment) ...@@ -732,9 +737,9 @@ CommentOperator(char *opername, List *arguments, char *comment)
if (OidIsValid(leftoid) && (OidIsValid(rightoid))) if (OidIsValid(leftoid) && (OidIsValid(rightoid)))
oprtype = 'b'; oprtype = 'b';
else if (OidIsValid(leftoid)) else if (OidIsValid(leftoid))
oprtype = 'l';
else if (OidIsValid(rightoid))
oprtype = 'r'; oprtype = 'r';
else if (OidIsValid(rightoid))
oprtype = 'l';
else else
elog(ERROR, "operator '%s' is of an illegal type'", opername); elog(ERROR, "operator '%s' is of an illegal type'", opername);
...@@ -769,7 +774,6 @@ CommentOperator(char *opername, List *arguments, char *comment) ...@@ -769,7 +774,6 @@ CommentOperator(char *opername, List *arguments, char *comment)
/*** Call CreateComments() to create/drop the comments ***/ /*** Call CreateComments() to create/drop the comments ***/
CreateComments(oid, comment); CreateComments(oid, comment);
} }
/*------------------------------------------------------------------ /*------------------------------------------------------------------
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.46 2000/07/22 03:34:26 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.47 2000/10/07 00:58:16 tgl Exp $
* *
* DESCRIPTION * DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the * The "DefineFoo" routines take the parse tree and pick out the
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#include "commands/defrem.h" #include "commands/defrem.h"
#include "fmgr.h" #include "fmgr.h"
#include "optimizer/cost.h" #include "optimizer/cost.h"
#include "parser/parse_expr.h"
#include "tcop/dest.h" #include "tcop/dest.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/syscache.h" #include "utils/syscache.h"
...@@ -83,27 +84,15 @@ case_translate_language_name(const char *input, char *output) ...@@ -83,27 +84,15 @@ case_translate_language_name(const char *input, char *output)
static void static void
compute_return_type(const Node *returnType, compute_return_type(TypeName *returnType,
char **prorettype_p, bool *returnsSet_p) char **prorettype_p, bool *returnsSet_p)
{ {
/*--------------------------------------------------------------------------- /*---------------------------------------------------------------------------
Examine the "returns" clause returnType of the CREATE FUNCTION statement Examine the "returns" clause returnType of the CREATE FUNCTION statement
and return information about it as **prorettype_p and **returnsSet. and return information about it as *prorettype_p and *returnsSet.
----------------------------------------------------------------------------*/ ----------------------------------------------------------------------------*/
if (nodeTag(returnType) == T_TypeName) *prorettype_p = TypeNameToInternalName(returnType);
{ *returnsSet_p = returnType->setof;
/* a set of values */
TypeName *setType = (TypeName *) returnType;
*prorettype_p = setType->name;
*returnsSet_p = setType->setof;
}
else
{
/* singleton */
*prorettype_p = strVal(returnType);
*returnsSet_p = false;
}
} }
...@@ -214,7 +203,7 @@ interpret_AS_clause(const char *languageName, const List *as, ...@@ -214,7 +203,7 @@ interpret_AS_clause(const char *languageName, const List *as,
*prosrc_str_p = strVal(lfirst(as)); *prosrc_str_p = strVal(lfirst(as));
*probin_str_p = "-"; *probin_str_p = "-";
if (lnext(as) != NULL) if (lnext(as) != NIL)
elog(ERROR, "CREATE FUNCTION: only one AS item needed for %s language", elog(ERROR, "CREATE FUNCTION: only one AS item needed for %s language",
languageName); languageName);
} }
...@@ -231,27 +220,23 @@ void ...@@ -231,27 +220,23 @@ void
CreateFunction(ProcedureStmt *stmt, CommandDest dest) CreateFunction(ProcedureStmt *stmt, CommandDest dest)
{ {
char *probin_str; char *probin_str;
/* pathname of executable file that executes this function, if any */ /* pathname of executable file that executes this function, if any */
char *prosrc_str;
char *prosrc_str;
/* SQL that executes this function, if any */ /* SQL that executes this function, if any */
char *prorettype;
char *prorettype;
/* Type of return value (or member of set of values) from function */ /* Type of return value (or member of set of values) from function */
char languageName[NAMEDATALEN];
char languageName[NAMEDATALEN];
/* /*
* name of language of function, with case adjusted: "C", "newC", * name of language of function, with case adjusted: "C", "newC",
* "internal", "newinternal", "sql", etc. * "internal", "newinternal", "sql", etc.
*/ */
bool returnsSet; bool returnsSet;
/* The function returns a set of values, as opposed to a singleton. */ /* The function returns a set of values, as opposed to a singleton. */
bool lanisPL = false;
/* /*
* The following are optional user-supplied attributes of the * The following are optional user-supplied attributes of the
* function. * function.
...@@ -263,8 +248,12 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) ...@@ -263,8 +248,12 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
bool canCache, bool canCache,
isStrict; isStrict;
/* Convert language name to canonical case */
case_translate_language_name(stmt->language, languageName); case_translate_language_name(stmt->language, languageName);
/*
* Apply appropriate security checks depending on language.
*/
if (strcmp(languageName, "C") == 0 || if (strcmp(languageName, "C") == 0 ||
strcmp(languageName, "newC") == 0 || strcmp(languageName, "newC") == 0 ||
strcmp(languageName, "internal") == 0 || strcmp(languageName, "internal") == 0 ||
...@@ -301,7 +290,7 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) ...@@ -301,7 +290,7 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
/* Check that this language is a PL */ /* Check that this language is a PL */
languageStruct = (Form_pg_language) GETSTRUCT(languageTuple); languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
if (!(languageStruct->lanispl)) if (!languageStruct->lanispl)
elog(ERROR, elog(ERROR,
"Language '%s' isn't defined as PL", languageName); "Language '%s' isn't defined as PL", languageName);
...@@ -316,11 +305,15 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) ...@@ -316,11 +305,15 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
"language.", "language.",
languageName); languageName);
} }
lanisPL = true;
} }
compute_return_type(stmt->returnType, &prorettype, &returnsSet); /*
* Convert remaining parameters of CREATE to form wanted by
* ProcedureCreate.
*/
Assert(IsA(stmt->returnType, TypeName));
compute_return_type((TypeName *) stmt->returnType,
&prorettype, &returnsSet);
compute_full_attributes(stmt->withClause, compute_full_attributes(stmt->withClause,
&byte_pct, &perbyte_cpu, &percall_cpu, &byte_pct, &perbyte_cpu, &percall_cpu,
...@@ -345,7 +338,7 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) ...@@ -345,7 +338,7 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
perbyte_cpu, perbyte_cpu,
percall_cpu, percall_cpu,
outin_ratio, outin_ratio,
stmt->defArgs, stmt->argTypes,
dest); dest);
} }
...@@ -389,49 +382,43 @@ DefineOperator(char *oprName, ...@@ -389,49 +382,43 @@ DefineOperator(char *oprName,
{ {
DefElem *defel = (DefElem *) lfirst(pl); DefElem *defel = (DefElem *) lfirst(pl);
if (!strcasecmp(defel->defname, "leftarg")) if (strcasecmp(defel->defname, "leftarg") == 0)
{ {
if ((nodeTag(defel->arg) == T_TypeName)
&& (((TypeName *) defel->arg)->setof))
elog(ERROR, "setof type not implemented for leftarg");
typeName1 = defGetString(defel); typeName1 = defGetString(defel);
if (typeName1 == NULL) if (IsA(defel->arg, TypeName)
elog(ERROR, "type for leftarg is malformed."); && ((TypeName *) defel->arg)->setof)
elog(ERROR, "setof type not implemented for leftarg");
} }
else if (!strcasecmp(defel->defname, "rightarg")) else if (strcasecmp(defel->defname, "rightarg") == 0)
{ {
if ((nodeTag(defel->arg) == T_TypeName)
&& (((TypeName *) defel->arg)->setof))
elog(ERROR, "setof type not implemented for rightarg");
typeName2 = defGetString(defel); typeName2 = defGetString(defel);
if (typeName2 == NULL) if (IsA(defel->arg, TypeName)
elog(ERROR, "type for rightarg is malformed."); && ((TypeName *) defel->arg)->setof)
elog(ERROR, "setof type not implemented for rightarg");
} }
else if (!strcasecmp(defel->defname, "procedure")) else if (strcasecmp(defel->defname, "procedure") == 0)
functionName = defGetString(defel); functionName = defGetString(defel);
else if (!strcasecmp(defel->defname, "precedence")) else if (strcasecmp(defel->defname, "precedence") == 0)
{ {
/* NOT IMPLEMENTED (never worked in v4.2) */ /* NOT IMPLEMENTED (never worked in v4.2) */
elog(NOTICE, "CREATE OPERATOR: precedence not implemented"); elog(NOTICE, "CREATE OPERATOR: precedence not implemented");
} }
else if (!strcasecmp(defel->defname, "associativity")) else if (strcasecmp(defel->defname, "associativity") == 0)
{ {
/* NOT IMPLEMENTED (never worked in v4.2) */ /* NOT IMPLEMENTED (never worked in v4.2) */
elog(NOTICE, "CREATE OPERATOR: associativity not implemented"); elog(NOTICE, "CREATE OPERATOR: associativity not implemented");
} }
else if (!strcasecmp(defel->defname, "commutator")) else if (strcasecmp(defel->defname, "commutator") == 0)
commutatorName = defGetString(defel); commutatorName = defGetString(defel);
else if (!strcasecmp(defel->defname, "negator")) else if (strcasecmp(defel->defname, "negator") == 0)
negatorName = defGetString(defel); negatorName = defGetString(defel);
else if (!strcasecmp(defel->defname, "restrict")) else if (strcasecmp(defel->defname, "restrict") == 0)
restrictionName = defGetString(defel); restrictionName = defGetString(defel);
else if (!strcasecmp(defel->defname, "join")) else if (strcasecmp(defel->defname, "join") == 0)
joinName = defGetString(defel); joinName = defGetString(defel);
else if (!strcasecmp(defel->defname, "hashes")) else if (strcasecmp(defel->defname, "hashes") == 0)
canHash = TRUE; canHash = TRUE;
else if (!strcasecmp(defel->defname, "sort1")) else if (strcasecmp(defel->defname, "sort1") == 0)
{ {
/* ---------------- /* ----------------
* XXX ( ... [ , sort1 = oprname ] [ , sort2 = oprname ] ... ) * XXX ( ... [ , sort1 = oprname ] [ , sort2 = oprname ] ... )
...@@ -441,7 +428,7 @@ DefineOperator(char *oprName, ...@@ -441,7 +428,7 @@ DefineOperator(char *oprName,
*/ */
sortName1 = defGetString(defel); sortName1 = defGetString(defel);
} }
else if (!strcasecmp(defel->defname, "sort2")) else if (strcasecmp(defel->defname, "sort2") == 0)
sortName2 = defGetString(defel); sortName2 = defGetString(defel);
else else
{ {
...@@ -562,72 +549,73 @@ DefineType(char *typeName, List *parameters) ...@@ -562,72 +549,73 @@ DefineType(char *typeName, List *parameters)
char delimiter = DEFAULT_TYPDELIM; char delimiter = DEFAULT_TYPDELIM;
char *shadow_type; char *shadow_type;
List *pl; List *pl;
char alignment = 'i';/* default alignment */ char alignment = 'i'; /* default alignment */
char storage = 'p'; /* default storage in TOAST */ char storage = 'p'; /* default storage in TOAST */
/* /*
* Type names can only be 15 characters long, so that the shadow type * Type names must be one character shorter than other names,
* can be created using the 16th character as necessary. * allowing room to create the corresponding array type name with
* prepended "_".
*/ */
if (strlen(typeName) >= (NAMEDATALEN - 1)) if (strlen(typeName) > (NAMEDATALEN - 2))
{ {
elog(ERROR, "DefineType: type names must be %d characters or less", elog(ERROR, "DefineType: type names must be %d characters or less",
NAMEDATALEN - 1); NAMEDATALEN - 2);
} }
foreach(pl, parameters) foreach(pl, parameters)
{ {
DefElem *defel = (DefElem *) lfirst(pl); DefElem *defel = (DefElem *) lfirst(pl);
if (!strcasecmp(defel->defname, "internallength")) if (strcasecmp(defel->defname, "internallength") == 0)
internalLength = defGetTypeLength(defel); internalLength = defGetTypeLength(defel);
else if (!strcasecmp(defel->defname, "externallength")) else if (strcasecmp(defel->defname, "externallength") == 0)
externalLength = defGetTypeLength(defel); externalLength = defGetTypeLength(defel);
else if (!strcasecmp(defel->defname, "input")) else if (strcasecmp(defel->defname, "input") == 0)
inputName = defGetString(defel); inputName = defGetString(defel);
else if (!strcasecmp(defel->defname, "output")) else if (strcasecmp(defel->defname, "output") == 0)
outputName = defGetString(defel); outputName = defGetString(defel);
else if (!strcasecmp(defel->defname, "send")) else if (strcasecmp(defel->defname, "send") == 0)
sendName = defGetString(defel); sendName = defGetString(defel);
else if (!strcasecmp(defel->defname, "delimiter")) else if (strcasecmp(defel->defname, "delimiter") == 0)
{ {
char *p = defGetString(defel); char *p = defGetString(defel);
delimiter = p[0]; delimiter = p[0];
} }
else if (!strcasecmp(defel->defname, "receive")) else if (strcasecmp(defel->defname, "receive") == 0)
receiveName = defGetString(defel); receiveName = defGetString(defel);
else if (!strcasecmp(defel->defname, "element")) else if (strcasecmp(defel->defname, "element") == 0)
elemName = defGetString(defel); elemName = defGetString(defel);
else if (!strcasecmp(defel->defname, "default")) else if (strcasecmp(defel->defname, "default") == 0)
defaultValue = defGetString(defel); defaultValue = defGetString(defel);
else if (!strcasecmp(defel->defname, "passedbyvalue")) else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
byValue = true; byValue = true;
else if (!strcasecmp(defel->defname, "alignment")) else if (strcasecmp(defel->defname, "alignment") == 0)
{ {
char *a = defGetString(defel); char *a = defGetString(defel);
if (!strcasecmp(a, "double")) if (strcasecmp(a, "double") == 0)
alignment = 'd'; alignment = 'd';
else if (!strcasecmp(a, "int4")) else if (strcasecmp(a, "int4") == 0)
alignment = 'i'; alignment = 'i';
else else
{ {
elog(ERROR, "DefineType: \"%s\" alignment not recognized", elog(ERROR, "DefineType: \"%s\" alignment not recognized",
a); a);
} }
} }
else if (!strcasecmp(defel->defname, "storage")) else if (strcasecmp(defel->defname, "storage") == 0)
{ {
char *a = defGetString(defel); char *a = defGetString(defel);
if (!strcasecmp(a, "plain")) if (strcasecmp(a, "plain") == 0)
storage = 'p'; storage = 'p';
else if (!strcasecmp(a, "external")) else if (strcasecmp(a, "external") == 0)
storage = 'e'; storage = 'e';
else if (!strcasecmp(a, "extended")) else if (strcasecmp(a, "extended") == 0)
storage = 'x'; storage = 'x';
else if (!strcasecmp(a, "main")) else if (strcasecmp(a, "main") == 0)
storage = 'm'; storage = 'm';
else else
{ {
...@@ -674,8 +662,8 @@ DefineType(char *typeName, List *parameters) ...@@ -674,8 +662,8 @@ DefineType(char *typeName, List *parameters)
storage); /* TOAST strategy */ storage); /* TOAST strategy */
/* ---------------- /* ----------------
* When we create a true type (as opposed to a complex type) * When we create a base type (as opposed to a complex type)
* we need to have an shadow array entry for it in pg_type as well. * we need to have an array entry for it in pg_type as well.
* ---------------- * ----------------
*/ */
shadow_type = makeArrayTypeName(typeName); shadow_type = makeArrayTypeName(typeName);
...@@ -702,19 +690,32 @@ DefineType(char *typeName, List *parameters) ...@@ -702,19 +690,32 @@ DefineType(char *typeName, List *parameters)
static char * static char *
defGetString(DefElem *def) defGetString(DefElem *def)
{ {
char *string; if (def->arg == NULL)
elog(ERROR, "Define: \"%s\" requires a parameter",
if (nodeTag(def->arg) == T_String) def->defname);
string = strVal(def->arg); switch (nodeTag(def->arg))
else if (nodeTag(def->arg) == T_TypeName) {
string = ((TypeName *) def->arg)->name; case T_Integer:
else {
string = NULL; char *str = palloc(32);
#if 0
elog(ERROR, "Define: \"%s\" = what?", def->defname);
#endif
return string; snprintf(str, 32, "%ld", (long) intVal(def->arg));
return str;
}
case T_Float:
/* T_Float values are kept in string form, so this type cheat
* works (and doesn't risk losing precision)
*/
return strVal(def->arg);
case T_String:
return strVal(def->arg);
case T_TypeName:
return TypeNameToInternalName((TypeName *) def->arg);
default:
elog(ERROR, "Define: cannot interpret argument of \"%s\"",
def->defname);
}
return NULL; /* keep compiler quiet */
} }
static double static double
...@@ -739,15 +740,32 @@ defGetNumeric(DefElem *def) ...@@ -739,15 +740,32 @@ defGetNumeric(DefElem *def)
static int static int
defGetTypeLength(DefElem *def) defGetTypeLength(DefElem *def)
{ {
if (nodeTag(def->arg) == T_Integer) if (def->arg == NULL)
return intVal(def->arg); elog(ERROR, "Define: \"%s\" requires a parameter",
else if (nodeTag(def->arg) == T_String && def->defname);
!strcasecmp(strVal(def->arg), "variable")) switch (nodeTag(def->arg))
return -1; /* variable length */ {
else if (nodeTag(def->arg) == T_TypeName && case T_Integer:
!strcasecmp(((TypeName *)(def->arg))->name, "variable")) return intVal(def->arg);
return -1; case T_Float:
elog(ERROR, "Define: \"%s\" requires an integral value",
elog(ERROR, "Define: \"%s\" = what?", def->defname); def->defname);
return -1; break;
case T_String:
if (strcasecmp(strVal(def->arg), "variable") == 0)
return -1; /* variable length */
break;
case T_TypeName:
/* cope if grammar chooses to believe "variable" is a typename */
if (strcasecmp(TypeNameToInternalName((TypeName *) def->arg),
"variable") == 0)
return -1; /* variable length */
break;
default:
elog(ERROR, "Define: cannot interpret argument of \"%s\"",
def->defname);
}
elog(ERROR, "Define: invalid argument for \"%s\"",
def->defname);
return 0; /* keep compiler quiet */
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.52 2000/09/12 16:48:55 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.53 2000/10/07 00:58:16 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "commands/comment.h" #include "commands/comment.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "parser/parse_expr.h"
#include "parser/parse_func.h" #include "parser/parse_func.h"
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/syscache.h" #include "utils/syscache.h"
...@@ -39,8 +40,8 @@ ...@@ -39,8 +40,8 @@
*/ */
void void
RemoveOperator(char *operatorName, /* operator name */ RemoveOperator(char *operatorName, /* operator name */
char *typeName1, /* first type name */ char *typeName1, /* left argument type name */
char *typeName2) /* optional second type name */ char *typeName2) /* right argument type name */
{ {
Relation relation; Relation relation;
HeapTuple tup; HeapTuple tup;
...@@ -53,28 +54,22 @@ RemoveOperator(char *operatorName, /* operator name */ ...@@ -53,28 +54,22 @@ RemoveOperator(char *operatorName, /* operator name */
{ {
typeId1 = TypeGet(typeName1, &defined); typeId1 = TypeGet(typeName1, &defined);
if (!OidIsValid(typeId1)) if (!OidIsValid(typeId1))
{
elog(ERROR, "RemoveOperator: type '%s' does not exist", typeName1); elog(ERROR, "RemoveOperator: type '%s' does not exist", typeName1);
return;
}
} }
if (typeName2) if (typeName2)
{ {
typeId2 = TypeGet(typeName2, &defined); typeId2 = TypeGet(typeName2, &defined);
if (!OidIsValid(typeId2)) if (!OidIsValid(typeId2))
{
elog(ERROR, "RemoveOperator: type '%s' does not exist", typeName2); elog(ERROR, "RemoveOperator: type '%s' does not exist", typeName2);
return;
}
} }
if (OidIsValid(typeId1) && OidIsValid(typeId2)) if (OidIsValid(typeId1) && OidIsValid(typeId2))
oprtype = 'b'; oprtype = 'b';
else if (OidIsValid(typeId1)) else if (OidIsValid(typeId1))
oprtype = 'l';
else
oprtype = 'r'; oprtype = 'r';
else
oprtype = 'l';
relation = heap_openr(OperatorRelationName, RowExclusiveLock); relation = heap_openr(OperatorRelationName, RowExclusiveLock);
...@@ -94,7 +89,6 @@ RemoveOperator(char *operatorName, /* operator name */ ...@@ -94,7 +89,6 @@ RemoveOperator(char *operatorName, /* operator name */
operatorName); operatorName);
#endif #endif
/*** Delete any comments associated with this operator ***/ /*** Delete any comments associated with this operator ***/
DeleteComments(tup->t_data->t_oid); DeleteComments(tup->t_data->t_oid);
...@@ -308,13 +302,12 @@ RemoveType(char *typeName) /* type name to be removed */ ...@@ -308,13 +302,12 @@ RemoveType(char *typeName) /* type name to be removed */
*/ */
void void
RemoveFunction(char *functionName, /* function name to be removed */ RemoveFunction(char *functionName, /* function name to be removed */
int nargs, List *argTypes) /* list of TypeName nodes */
List *argNameList /* list of TypeNames */ )
{ {
int nargs = length(argTypes);
Relation relation; Relation relation;
HeapTuple tup; HeapTuple tup;
Oid argList[FUNC_MAX_ARGS]; Oid argList[FUNC_MAX_ARGS];
char *typename;
int i; int i;
if (nargs > FUNC_MAX_ARGS) if (nargs > FUNC_MAX_ARGS)
...@@ -323,19 +316,20 @@ RemoveFunction(char *functionName, /* function name to be removed */ ...@@ -323,19 +316,20 @@ RemoveFunction(char *functionName, /* function name to be removed */
MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid)); MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
for (i = 0; i < nargs; i++) for (i = 0; i < nargs; i++)
{ {
typename = strVal(lfirst(argNameList)); TypeName *t = (TypeName *) lfirst(argTypes);
argNameList = lnext(argNameList); char *typnam = TypeNameToInternalName(t);
if (strcmp(typename, "opaque") == 0) argTypes = lnext(argTypes);
argList[i] = 0;
if (strcmp(typnam, "opaque") == 0)
argList[i] = InvalidOid;
else else
{ {
tup = SearchSysCacheTuple(TYPENAME, tup = SearchSysCacheTuple(TYPENAME,
PointerGetDatum(typename), PointerGetDatum(typnam),
0, 0, 0); 0, 0, 0);
if (!HeapTupleIsValid(tup)) if (!HeapTupleIsValid(tup))
elog(ERROR, "RemoveFunction: type '%s' not found", typename); elog(ERROR, "RemoveFunction: type '%s' not found", typnam);
argList[i] = tup->t_data->t_oid; argList[i] = tup->t_data->t_oid;
} }
} }
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.124 2000/10/05 19:11:27 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.125 2000/10/07 00:58:16 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1854,13 +1854,9 @@ _copyChangeACLStmt(ChangeACLStmt *from) ...@@ -1854,13 +1854,9 @@ _copyChangeACLStmt(ChangeACLStmt *from)
{ {
ChangeACLStmt *newnode = makeNode(ChangeACLStmt); ChangeACLStmt *newnode = makeNode(ChangeACLStmt);
if (from->aclitem)
{
newnode->aclitem = (struct AclItem *) palloc(sizeof(struct AclItem));
memcpy(newnode->aclitem, from->aclitem, sizeof(struct AclItem));
}
newnode->modechg = from->modechg;
Node_Copy(from, newnode, relNames); Node_Copy(from, newnode, relNames);
if (from->aclString)
newnode->aclString = pstrdup(from->aclString);
return newnode; return newnode;
} }
...@@ -2033,7 +2029,7 @@ _copyProcedureStmt(ProcedureStmt *from) ...@@ -2033,7 +2029,7 @@ _copyProcedureStmt(ProcedureStmt *from)
ProcedureStmt *newnode = makeNode(ProcedureStmt); ProcedureStmt *newnode = makeNode(ProcedureStmt);
newnode->funcname = pstrdup(from->funcname); newnode->funcname = pstrdup(from->funcname);
Node_Copy(from, newnode, defArgs); Node_Copy(from, newnode, argTypes);
Node_Copy(from, newnode, returnType); Node_Copy(from, newnode, returnType);
Node_Copy(from, newnode, withClause); Node_Copy(from, newnode, withClause);
Node_Copy(from, newnode, as); Node_Copy(from, newnode, as);
...@@ -2048,7 +2044,7 @@ _copyRemoveAggrStmt(RemoveAggrStmt *from) ...@@ -2048,7 +2044,7 @@ _copyRemoveAggrStmt(RemoveAggrStmt *from)
RemoveAggrStmt *newnode = makeNode(RemoveAggrStmt); RemoveAggrStmt *newnode = makeNode(RemoveAggrStmt);
newnode->aggname = pstrdup(from->aggname); newnode->aggname = pstrdup(from->aggname);
newnode->aggtype = pstrdup(from->aggtype); Node_Copy(from, newnode, aggtype);
return newnode; return newnode;
} }
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.75 2000/10/05 19:11:27 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.76 2000/10/07 00:58:16 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -753,24 +753,10 @@ _equalAlterTableStmt(AlterTableStmt *a, AlterTableStmt *b) ...@@ -753,24 +753,10 @@ _equalAlterTableStmt(AlterTableStmt *a, AlterTableStmt *b)
static bool static bool
_equalChangeACLStmt(ChangeACLStmt *a, ChangeACLStmt *b) _equalChangeACLStmt(ChangeACLStmt *a, ChangeACLStmt *b)
{ {
if (a->aclitem && b->aclitem)
{
if (a->aclitem->ai_id != b->aclitem->ai_id)
return false;
if (a->aclitem->ai_idtype != b->aclitem->ai_idtype)
return false;
if (a->aclitem->ai_mode != b->aclitem->ai_mode)
return false;
}
else
{
if (a->aclitem != b->aclitem)
return false; /* one NULL, one not */
}
if (a->modechg != b->modechg)
return false;
if (!equal(a->relNames, b->relNames)) if (!equal(a->relNames, b->relNames))
return false; return false;
if (!equalstr(a->aclString, b->aclString))
return false;
return true; return true;
} }
...@@ -956,7 +942,7 @@ _equalProcedureStmt(ProcedureStmt *a, ProcedureStmt *b) ...@@ -956,7 +942,7 @@ _equalProcedureStmt(ProcedureStmt *a, ProcedureStmt *b)
{ {
if (!equalstr(a->funcname, b->funcname)) if (!equalstr(a->funcname, b->funcname))
return false; return false;
if (!equal(a->defArgs, b->defArgs)) if (!equal(a->argTypes, b->argTypes))
return false; return false;
if (!equal(a->returnType, b->returnType)) if (!equal(a->returnType, b->returnType))
return false; return false;
...@@ -975,7 +961,7 @@ _equalRemoveAggrStmt(RemoveAggrStmt *a, RemoveAggrStmt *b) ...@@ -975,7 +961,7 @@ _equalRemoveAggrStmt(RemoveAggrStmt *a, RemoveAggrStmt *b)
{ {
if (!equalstr(a->aggname, b->aggname)) if (!equalstr(a->aggname, b->aggname))
return false; return false;
if (!equalstr(a->aggtype, b->aggtype)) if (!equal(a->aggtype, b->aggtype))
return false; return false;
return true; return true;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: analyze.c,v 1.160 2000/10/05 19:11:33 tgl Exp $ * $Id: analyze.c,v 1.161 2000/10/07 00:58:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -69,49 +69,45 @@ static List *extras_after; ...@@ -69,49 +69,45 @@ static List *extras_after;
/* /*
* parse_analyze - * parse_analyze -
* analyze a list of parse trees and transform them if necessary. * analyze a raw parse tree and transform it to Query form.
*
* Returns a list of transformed parse trees. Optimizable statements are
* all transformed to Query while the rest stays the same.
* *
* The result is a List of Query nodes (we need a list since some commands
* produce multiple Queries). Optimizable statements require considerable
* transformation, while many utility-type statements are simply hung off
* a dummy CMD_UTILITY Query node.
*/ */
List * List *
parse_analyze(List *pl, ParseState *parentParseState) parse_analyze(Node *parseTree, ParseState *parentParseState)
{ {
List *result = NIL; List *result = NIL;
ParseState *pstate = make_parsestate(parentParseState);
Query *query;
while (pl != NIL) extras_before = extras_after = NIL;
{
ParseState *pstate = make_parsestate(parentParseState);
Query *parsetree;
extras_before = extras_after = NIL; query = transformStmt(pstate, parseTree);
release_pstate_resources(pstate);
parsetree = transformStmt(pstate, lfirst(pl)); while (extras_before != NIL)
{
result = lappend(result,
transformStmt(pstate, lfirst(extras_before)));
release_pstate_resources(pstate); release_pstate_resources(pstate);
extras_before = lnext(extras_before);
}
while (extras_before != NIL) result = lappend(result, query);
{
result = lappend(result,
transformStmt(pstate, lfirst(extras_before)));
release_pstate_resources(pstate);
extras_before = lnext(extras_before);
}
result = lappend(result, parsetree);
while (extras_after != NIL) while (extras_after != NIL)
{ {
result = lappend(result, result = lappend(result,
transformStmt(pstate, lfirst(extras_after))); transformStmt(pstate, lfirst(extras_after)));
release_pstate_resources(pstate); release_pstate_resources(pstate);
extras_after = lnext(extras_after); extras_after = lnext(extras_after);
}
pfree(pstate);
pl = lnext(pl);
} }
pfree(pstate);
return result; return result;
} }
...@@ -126,8 +122,7 @@ release_pstate_resources(ParseState *pstate) ...@@ -126,8 +122,7 @@ release_pstate_resources(ParseState *pstate)
/* /*
* transformStmt - * transformStmt -
* transform a Parse tree. If it is an optimizable statement, turn it * transform a Parse tree into a Query tree.
* into a Query tree.
*/ */
static Query * static Query *
transformStmt(ParseState *pstate, Node *parseTree) transformStmt(ParseState *pstate, Node *parseTree)
...@@ -353,7 +348,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) ...@@ -353,7 +348,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
* from a stand-alone SELECT. (Indeed, Postgres up through 6.5 had * from a stand-alone SELECT. (Indeed, Postgres up through 6.5 had
* bugs of just that nature...) * bugs of just that nature...)
*/ */
selectList = parse_analyze(makeList1(stmt->selectStmt), pstate); selectList = parse_analyze(stmt->selectStmt, pstate);
Assert(length(selectList) == 1); Assert(length(selectList) == 1);
selectQuery = (Query *) lfirst(selectList); selectQuery = (Query *) lfirst(selectList);
...@@ -1933,7 +1928,7 @@ transformSetOperationTree(ParseState *pstate, Node *node) ...@@ -1933,7 +1928,7 @@ transformSetOperationTree(ParseState *pstate, Node *node)
*/ */
save_rtable = pstate->p_rtable; save_rtable = pstate->p_rtable;
pstate->p_rtable = NIL; pstate->p_rtable = NIL;
selectList = parse_analyze(makeList1(stmt), pstate); selectList = parse_analyze((Node *) stmt, pstate);
pstate->p_rtable = save_rtable; pstate->p_rtable = save_rtable;
Assert(length(selectList) == 1); Assert(length(selectList) == 1);
...@@ -2752,6 +2747,7 @@ makeFromExpr(List *fromlist, Node *quals) ...@@ -2752,6 +2747,7 @@ makeFromExpr(List *fromlist, Node *quals)
static void static void
transformColumnType(ParseState *pstate, ColumnDef *column) transformColumnType(ParseState *pstate, ColumnDef *column)
{ {
TypeName *typename = column->typename;
/* /*
* If the column doesn't have an explicitly specified typmod, check to * If the column doesn't have an explicitly specified typmod, check to
...@@ -2760,18 +2756,33 @@ transformColumnType(ParseState *pstate, ColumnDef *column) ...@@ -2760,18 +2756,33 @@ transformColumnType(ParseState *pstate, ColumnDef *column)
* Note that we deliberately do NOT look at array or set information * Note that we deliberately do NOT look at array or set information
* here; "numeric[]" needs the same default typmod as "numeric". * here; "numeric[]" needs the same default typmod as "numeric".
*/ */
if (column->typename->typmod == -1) if (typename->typmod == -1)
{ {
switch (typeTypeId(typenameType(column->typename->name))) switch (typeTypeId(typenameType(typename->name)))
{ {
case BPCHAROID: case BPCHAROID:
/* "char" -> "char(1)" */ /* "char" -> "char(1)" */
column->typename->typmod = VARHDRSZ + 1; typename->typmod = VARHDRSZ + 1;
break; break;
case NUMERICOID: case NUMERICOID:
column->typename->typmod = VARHDRSZ + typename->typmod = VARHDRSZ +
((NUMERIC_DEFAULT_PRECISION << 16) | NUMERIC_DEFAULT_SCALE); ((NUMERIC_DEFAULT_PRECISION << 16) | NUMERIC_DEFAULT_SCALE);
break; break;
} }
} }
/*
* Is this the name of a complex type? If so, implement
* it as a set.
*
* XXX this is a hangover from ancient Berkeley code that probably
* doesn't work anymore anyway.
*/
if (typeTypeRelid(typenameType(typename->name)) != InvalidOid)
{
/* (Eventually add in here that the set can only
* contain one element.)
*/
typename->setof = true;
}
} }
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.194 2000/10/05 19:11:33 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.195 2000/10/07 00:58:17 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -59,7 +59,6 @@ ...@@ -59,7 +59,6 @@
extern List *parsetree; /* final parse result is delivered here */ extern List *parsetree; /* final parse result is delivered here */
static char saved_relname[NAMEDATALEN]; /* need this for complex attributes */
static bool QueryIsRule = FALSE; static bool QueryIsRule = FALSE;
static Oid *param_type_info; static Oid *param_type_info;
static int pfunc_num_args; static int pfunc_num_args;
...@@ -161,7 +160,7 @@ static void doNegateFloat(Value *v); ...@@ -161,7 +160,7 @@ static void doNegateFloat(Value *v);
%type <str> relation_name, copy_file_name, copy_delimiter, copy_null, def_name, %type <str> relation_name, copy_file_name, copy_delimiter, copy_null, def_name,
database_name, access_method_clause, access_method, attr_name, database_name, access_method_clause, access_method, attr_name,
class, index_name, name, func_name, file_name, aggr_argtype class, index_name, name, func_name, file_name
%type <str> opt_id, %type <str> opt_id,
all_Op, MathOp, opt_name, all_Op, MathOp, opt_name,
...@@ -183,7 +182,7 @@ static void doNegateFloat(Value *v); ...@@ -183,7 +182,7 @@ static void doNegateFloat(Value *v);
def_list, opt_indirection, group_clause, TriggerFuncArgs, def_list, opt_indirection, group_clause, TriggerFuncArgs,
opt_select_limit opt_select_limit
%type <typnam> func_arg, func_return %type <typnam> func_arg, func_return, aggr_argtype
%type <boolean> opt_arg, TriggerForOpt, TriggerForType, OptTemp %type <boolean> opt_arg, TriggerForOpt, TriggerForType, OptTemp
...@@ -1541,7 +1540,7 @@ CreateAsStmt: CREATE OptTemp TABLE relation_name OptUnder OptCreateAs AS Select ...@@ -1541,7 +1540,7 @@ CreateAsStmt: CREATE OptTemp TABLE relation_name OptUnder OptCreateAs AS Select
n->istemp = $2; n->istemp = $2;
n->into = $4; n->into = $4;
if ($5 != NIL) if ($5 != NIL)
yyerror("CREATE TABLE/AS SELECT does not support UNDER"); elog(ERROR,"CREATE TABLE/AS SELECT does not support UNDER");
if ($6 != NIL) if ($6 != NIL)
mapTargetColumns($6, n->targetList); mapTargetColumns($6, n->targetList);
$$ = $8; $$ = $8;
...@@ -2009,8 +2008,8 @@ CommentStmt: COMMENT ON comment_type name IS comment_text ...@@ -2009,8 +2008,8 @@ CommentStmt: COMMENT ON comment_type name IS comment_text
CommentStmt *n = makeNode(CommentStmt); CommentStmt *n = makeNode(CommentStmt);
n->objtype = $3; n->objtype = $3;
n->objname = $4; n->objname = $4;
n->objproperty = $5; n->objproperty = NULL;
n->objlist = NULL; n->objlist = makeList1($5);
n->comment = $7; n->comment = $7;
$$ = (Node *) n; $$ = (Node *) n;
} }
...@@ -2309,7 +2308,7 @@ grantee: PUBLIC ...@@ -2309,7 +2308,7 @@ grantee: PUBLIC
opt_with_grant: WITH GRANT OPTION opt_with_grant: WITH GRANT OPTION
{ {
yyerror("WITH GRANT OPTION is not supported. Only relation owners can set privileges"); elog(ERROR,"WITH GRANT OPTION is not supported. Only relation owners can set privileges");
} }
| /*EMPTY*/ | /*EMPTY*/
; ;
...@@ -2471,7 +2470,7 @@ ProcedureStmt: CREATE FUNCTION func_name func_args ...@@ -2471,7 +2470,7 @@ ProcedureStmt: CREATE FUNCTION func_name func_args
{ {
ProcedureStmt *n = makeNode(ProcedureStmt); ProcedureStmt *n = makeNode(ProcedureStmt);
n->funcname = $3; n->funcname = $3;
n->defArgs = $4; n->argTypes = $4;
n->returnType = (Node *)$6; n->returnType = (Node *)$6;
n->withClause = $11; n->withClause = $11;
n->as = $8; n->as = $8;
...@@ -2488,29 +2487,12 @@ func_args: '(' func_args_list ')' { $$ = $2; } ...@@ -2488,29 +2487,12 @@ func_args: '(' func_args_list ')' { $$ = $2; }
; ;
func_args_list: func_arg func_args_list: func_arg
{ $$ = makeList1(makeString($1->name)); } { $$ = makeList1($1); }
| func_args_list ',' func_arg | func_args_list ',' func_arg
{ $$ = lappend($1, makeString($3->name)); } { $$ = lappend($1, $3); }
; ;
/* Would be nice to use the full Typename production for these fields, func_arg: opt_arg Typename
* but that one sometimes dives into the catalogs looking for valid types.
* Arguments like "opaque" are valid when defining functions,
* so that won't work here. The only thing we give up is array notation,
* which isn't meaningful in this context anyway.
* - thomas 2000-03-25
* The following productions are difficult, since it is difficult to
* distinguish between TokenId and SimpleTypename:
opt_arg TokenId SimpleTypename
{
$$ = $3;
}
| TokenId SimpleTypename
{
$$ = $2;
}
*/
func_arg: opt_arg SimpleTypename
{ {
/* We can catch over-specified arguments here if we want to, /* We can catch over-specified arguments here if we want to,
* but for now better to silently swallow typmod, etc. * but for now better to silently swallow typmod, etc.
...@@ -2518,7 +2500,7 @@ func_arg: opt_arg SimpleTypename ...@@ -2518,7 +2500,7 @@ func_arg: opt_arg SimpleTypename
*/ */
$$ = $2; $$ = $2;
} }
| SimpleTypename | Typename
{ {
$$ = $1; $$ = $1;
} }
...@@ -2546,7 +2528,7 @@ func_as: Sconst ...@@ -2546,7 +2528,7 @@ func_as: Sconst
{ $$ = makeList2(makeString($1), makeString($3)); } { $$ = makeList2(makeString($1), makeString($3)); }
; ;
func_return: SimpleTypename func_return: Typename
{ {
/* We can catch over-specified arguments here if we want to, /* We can catch over-specified arguments here if we want to,
* but for now better to silently swallow typmod, etc. * but for now better to silently swallow typmod, etc.
...@@ -2554,11 +2536,6 @@ func_return: SimpleTypename ...@@ -2554,11 +2536,6 @@ func_return: SimpleTypename
*/ */
$$ = $1; $$ = $1;
} }
| SETOF SimpleTypename
{
$$ = $2;
$$->setof = TRUE;
}
; ;
...@@ -2599,12 +2576,12 @@ RemoveAggrStmt: DROP AGGREGATE name aggr_argtype ...@@ -2599,12 +2576,12 @@ RemoveAggrStmt: DROP AGGREGATE name aggr_argtype
{ {
RemoveAggrStmt *n = makeNode(RemoveAggrStmt); RemoveAggrStmt *n = makeNode(RemoveAggrStmt);
n->aggname = $3; n->aggname = $3;
n->aggtype = $4; n->aggtype = (Node *) $4;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
aggr_argtype: name { $$ = $1; } aggr_argtype: Typename { $$ = $1; }
| '*' { $$ = NULL; } | '*' { $$ = NULL; }
; ;
...@@ -2628,16 +2605,16 @@ RemoveOperStmt: DROP OPERATOR all_Op '(' oper_argtypes ')' ...@@ -2628,16 +2605,16 @@ RemoveOperStmt: DROP OPERATOR all_Op '(' oper_argtypes ')'
} }
; ;
oper_argtypes: name oper_argtypes: Typename
{ {
elog(ERROR,"parser: argument type missing (use NONE for unary operators)"); elog(ERROR,"parser: argument type missing (use NONE for unary operators)");
} }
| name ',' name | Typename ',' Typename
{ $$ = makeList2(makeString($1), makeString($3)); } { $$ = makeList2($1, $3); }
| NONE ',' name /* left unary */ | NONE ',' Typename /* left unary */
{ $$ = makeList2(NULL, makeString($3)); } { $$ = makeList2(NULL, $3); }
| name ',' NONE /* right unary */ | Typename ',' NONE /* right unary */
{ $$ = makeList2(makeString($1), NULL); } { $$ = makeList2($1, NULL); }
; ;
...@@ -3832,23 +3809,6 @@ Typename: SimpleTypename opt_array_bounds ...@@ -3832,23 +3809,6 @@ Typename: SimpleTypename opt_array_bounds
{ {
$$ = $1; $$ = $1;
$$->arrayBounds = $2; $$->arrayBounds = $2;
/* Is this the name of a complex type? If so, implement
* it as a set.
*/
if (strcmp(saved_relname, $$->name) == 0)
/* This attr is the same type as the relation
* being defined. The classic example: create
* emp(name=text,mgr=emp)
*/
$$->setof = TRUE;
else if (typeTypeRelid(typenameType($$->name)) != InvalidOid)
/* (Eventually add in here that the set can only
* contain one element.)
*/
$$->setof = TRUE;
else
$$->setof = FALSE;
} }
| SETOF SimpleTypename | SETOF SimpleTypename
{ {
...@@ -3909,7 +3869,7 @@ Numeric: FLOAT opt_float ...@@ -3909,7 +3869,7 @@ Numeric: FLOAT opt_float
| DECIMAL opt_decimal | DECIMAL opt_decimal
{ {
$$ = makeNode(TypeName); $$ = makeNode(TypeName);
$$->name = xlateSqlType("numeric"); $$->name = xlateSqlType("decimal");
$$->typmod = $2; $$->typmod = $2;
} }
| DEC opt_decimal | DEC opt_decimal
...@@ -5245,17 +5205,15 @@ update_target_el: ColId opt_indirection '=' a_expr ...@@ -5245,17 +5205,15 @@ update_target_el: ColId opt_indirection '=' a_expr
relation_name: SpecialRuleRelation relation_name: SpecialRuleRelation
{ {
$$ = $1; $$ = $1;
StrNCpy(saved_relname, $1, NAMEDATALEN);
} }
| ColId | ColId
{ {
/* disallow refs to variable system tables */ /* disallow refs to variable system tables */
if (strcmp(LogRelationName, $1) == 0 if (strcmp(LogRelationName, $1) == 0
|| strcmp(VariableRelationName, $1) == 0) || strcmp(VariableRelationName, $1) == 0)
elog(ERROR,"%s cannot be accessed by users",$1); elog(ERROR,"%s cannot be accessed by users",$1);
else else
$$ = $1; $$ = $1;
StrNCpy(saved_relname, $1, NAMEDATALEN);
} }
; ;
...@@ -5298,7 +5256,7 @@ AexprConst: Iconst ...@@ -5298,7 +5256,7 @@ AexprConst: Iconst
n->val.val.str = $1; n->val.val.str = $1;
$$ = (Node *)n; $$ = (Node *)n;
} }
/* The SimpleTypename rule formerly used Typename, /* This rule formerly used Typename,
* but that causes reduce conflicts with subscripted column names. * but that causes reduce conflicts with subscripted column names.
* Now, separate into ConstTypename and ConstInterval, * Now, separate into ConstTypename and ConstInterval,
* to allow implementing the SQL92 syntax for INTERVAL literals. * to allow implementing the SQL92 syntax for INTERVAL literals.
...@@ -5383,6 +5341,7 @@ ColId: generic { $$ = $1; } ...@@ -5383,6 +5341,7 @@ ColId: generic { $$ = $1; }
| TokenId { $$ = $1; } | TokenId { $$ = $1; }
| INTERVAL { $$ = "interval"; } | INTERVAL { $$ = "interval"; }
| NATIONAL { $$ = "national"; } | NATIONAL { $$ = "national"; }
| NONE { $$ = "none"; }
| PATH_P { $$ = "path"; } | PATH_P { $$ = "path"; }
| SERIAL { $$ = "serial"; } | SERIAL { $$ = "serial"; }
| TIME { $$ = "time"; } | TIME { $$ = "time"; }
...@@ -5595,7 +5554,6 @@ ColLabel: ColId { $$ = $1; } ...@@ -5595,7 +5554,6 @@ ColLabel: ColId { $$ = $1; }
| NATURAL { $$ = "natural"; } | NATURAL { $$ = "natural"; }
| NCHAR { $$ = "nchar"; } | NCHAR { $$ = "nchar"; }
| NEW { $$ = "new"; } | NEW { $$ = "new"; }
| NONE { $$ = "none"; }
| NOT { $$ = "not"; } | NOT { $$ = "not"; }
| NOTNULL { $$ = "notnull"; } | NOTNULL { $$ = "notnull"; }
| NULLIF { $$ = "nullif"; } | NULLIF { $$ = "nullif"; }
...@@ -5851,7 +5809,6 @@ xlateSqlType(char *name) ...@@ -5851,7 +5809,6 @@ xlateSqlType(char *name)
void parser_init(Oid *typev, int nargs) void parser_init(Oid *typev, int nargs)
{ {
saved_relname[0] = '\0';
QueryIsRule = FALSE; QueryIsRule = FALSE;
/* /*
* Keep enough information around to fill out the type of param nodes * Keep enough information around to fill out the type of param nodes
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.69 2000/10/05 19:11:33 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.70 2000/10/07 00:58:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -375,7 +375,7 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r) ...@@ -375,7 +375,7 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
save_joinlist = pstate->p_joinlist; save_joinlist = pstate->p_joinlist;
pstate->p_rtable = NIL; pstate->p_rtable = NIL;
pstate->p_joinlist = NIL; pstate->p_joinlist = NIL;
parsetrees = parse_analyze(makeList1(r->subquery), pstate); parsetrees = parse_analyze(r->subquery, pstate);
pstate->p_rtable = save_rtable; pstate->p_rtable = save_rtable;
pstate->p_joinlist = save_joinlist; pstate->p_joinlist = save_joinlist;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.85 2000/10/05 19:11:33 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.86 2000/10/07 00:58:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -294,8 +294,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -294,8 +294,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
break; break;
} }
pstate->p_hasSubLinks = true; pstate->p_hasSubLinks = true;
qtrees = parse_analyze(makeList1(sublink->subselect), qtrees = parse_analyze(sublink->subselect, pstate);
pstate);
if (length(qtrees) != 1) if (length(qtrees) != 1)
elog(ERROR, "Bad query in subselect"); elog(ERROR, "Bad query in subselect");
qtree = (Query *) lfirst(qtrees); qtree = (Query *) lfirst(qtrees);
...@@ -821,19 +820,21 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod) ...@@ -821,19 +820,21 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
static Node * static Node *
parser_typecast_constant(Value *expr, TypeName *typename) parser_typecast_constant(Value *expr, TypeName *typename)
{ {
Const *con;
Type tp; Type tp;
Datum datum; Datum datum;
Const *con;
char *const_string = NULL; char *const_string = NULL;
bool string_palloced = false; bool string_palloced = false;
bool isNull = false; bool isNull = false;
tp = typenameType(TypeNameToInternalName(typename));
switch (nodeTag(expr)) switch (nodeTag(expr))
{ {
case T_Integer: case T_Integer:
string_palloced = true;
const_string = DatumGetCString(DirectFunctionCall1(int4out, const_string = DatumGetCString(DirectFunctionCall1(int4out,
Int32GetDatum(expr->val.ival))); Int32GetDatum(expr->val.ival)));
string_palloced = true;
break; break;
case T_Float: case T_Float:
case T_String: case T_String:
...@@ -844,19 +845,9 @@ parser_typecast_constant(Value *expr, TypeName *typename) ...@@ -844,19 +845,9 @@ parser_typecast_constant(Value *expr, TypeName *typename)
break; break;
default: default:
elog(ERROR, "Cannot cast this expression to type '%s'", elog(ERROR, "Cannot cast this expression to type '%s'",
typename->name); typeTypeName(tp));
} }
if (typename->arrayBounds != NIL)
{
char type_string[NAMEDATALEN + 2];
sprintf(type_string, "_%s", typename->name);
tp = (Type) typenameType(type_string);
}
else
tp = (Type) typenameType(typename->name);
if (isNull) if (isNull)
datum = (Datum) NULL; datum = (Datum) NULL;
else else
...@@ -892,15 +883,7 @@ parser_typecast_expression(ParseState *pstate, ...@@ -892,15 +883,7 @@ parser_typecast_expression(ParseState *pstate,
Type tp; Type tp;
Oid targetType; Oid targetType;
if (typename->arrayBounds != NIL) tp = typenameType(TypeNameToInternalName(typename));
{
char type_string[NAMEDATALEN + 2];
sprintf(type_string, "_%s", typename->name);
tp = (Type) typenameType(type_string);
}
else
tp = (Type) typenameType(typename->name);
targetType = typeTypeId(tp); targetType = typeTypeId(tp);
if (inputType == InvalidOid) if (inputType == InvalidOid)
...@@ -925,3 +908,26 @@ parser_typecast_expression(ParseState *pstate, ...@@ -925,3 +908,26 @@ parser_typecast_expression(ParseState *pstate,
return expr; return expr;
} }
/*
* Given a TypeName node as returned by the grammar, generate the internal
* name of the corresponding type. Note this does NOT check if the type
* exists or not.
*/
char *
TypeNameToInternalName(TypeName *typename)
{
if (typename->arrayBounds != NIL)
{
/*
* By convention, the name of an array type is the name of its
* element type with "_" prepended.
*/
char *arrayname = palloc(strlen(typename->name) + 2);
sprintf(arrayname, "_%s", typename->name);
return arrayname;
}
else
return typename->name;
}
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* parser.c * parser.c
* Main entry point/driver for PostgreSQL parser * Main entry point/driver for PostgreSQL grammar
*
* Note that the grammar is not allowed to perform any table access
* (since we need to be able to do basic parsing even while inside an
* aborted transaction). Therefore, the data structures returned by
* the grammar are "raw" parsetrees that still need to be analyzed by
* parse_analyze.
* *
* *
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.46 2000/09/12 21:07:02 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.47 2000/10/07 00:58:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -16,8 +22,6 @@ ...@@ -16,8 +22,6 @@
#include "postgres.h" #include "postgres.h"
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
#include "nodes/pg_list.h"
#include "parser/analyze.h"
#include "parser/gramparse.h" #include "parser/gramparse.h"
#include "parser/parse.h" #include "parser/parse.h"
#include "parser/parser.h" #include "parser/parser.h"
...@@ -35,19 +39,17 @@ List *parsetree; /* result of parsing is left here */ ...@@ -35,19 +39,17 @@ List *parsetree; /* result of parsing is left here */
static int lookahead_token; /* one-token lookahead */ static int lookahead_token; /* one-token lookahead */
static bool have_lookahead; /* lookahead_token set? */ static bool have_lookahead; /* lookahead_token set? */
#ifdef SETS_FIXED
static void fixupsets();
static void define_sets();
#endif
/* /*
* parser-- returns a list of parse trees * parser
* Given a query in string form, and optionally info about
* parameter types, do lexical and syntactic analysis.
*
* Returns a list of raw (un-analyzed) parse trees.
*/ */
List * List *
parser(char *str, Oid *typev, int nargs) parser(char *str, Oid *typev, int nargs)
{ {
List *queryList;
int yyresult; int yyresult;
parseString = str; parseString = str;
...@@ -67,28 +69,9 @@ parser(char *str, Oid *typev, int nargs) ...@@ -67,28 +69,9 @@ parser(char *str, Oid *typev, int nargs)
clearerr(stdin); clearerr(stdin);
if (yyresult) /* error */ if (yyresult) /* error */
return (List *) NULL; return NIL;
queryList = parse_analyze(parsetree, NULL);
#ifdef SETS_FIXED return parsetree;
/*
* Fixing up sets calls the parser, so it reassigns the global
* variable parsetree. So save the real parsetree.
*/
savetree = parsetree;
foreach(parse, savetree)
{ /* savetree is really a list of parses */
/* find set definitions embedded in query */
fixupsets((Query *) lfirst(parse));
}
return savetree;
#endif
return queryList;
} }
...@@ -135,83 +118,3 @@ yylex(void) ...@@ -135,83 +118,3 @@ yylex(void)
return cur_token; return cur_token;
} }
#ifdef SETS_FIXED
static void
fixupsets(Query *parse)
{
if (parse == NULL)
return;
if (parse->commandType == CMD_UTILITY) /* utility */
return;
if (parse->commandType != CMD_INSERT)
return;
define_sets(parse);
}
/* Recursively find all of the Consts in the parsetree. Some of
* these may represent a set. The value of the Const will be the
* query (a string) which defines the set. Call SetDefine to define
* the set, and store the OID of the new set in the Const instead.
*/
static void
define_sets(Node *clause)
{
Oid setoid;
Type t = typeidType(OIDOID);
Oid typeoid = typeTypeId(t);
Size oidsize = typeLen(t);
bool oidbyval = typeByVal(t);
if (clause == NULL)
return;
else if (IsA(clause, LispList))
{
define_sets(lfirst(clause));
define_sets(lnext(clause));
}
else if (IsA(clause, Const))
{
if (get_constisnull((Const) clause) ||
!get_constisset((Const) clause))
return;
setoid = SetDefine(((Const *) clause)->constvalue,
typeidTypeName(((Const *) clause)->consttype));
set_constvalue((Const) clause, setoid);
set_consttype((Const) clause, typeoid);
set_constlen((Const) clause, oidsize);
set_constypeByVal((Const) clause, oidbyval);
}
else if (IsA(clause, Iter))
define_sets(((Iter *) clause)->iterexpr);
else if (single_node(clause))
return;
else if (or_clause(clause) || and_clause(clause))
{
List *temp;
/* mapcan */
foreach(temp, ((Expr *) clause)->args)
define_sets(lfirst(temp));
}
else if (is_funcclause(clause))
{
List *temp;
/* mapcan */
foreach(temp, ((Expr *) clause)->args)
define_sets(lfirst(temp));
}
else if (IsA(clause, ArrayRef))
define_sets(((ArrayRef *) clause)->refassgnexpr);
else if (not_clause(clause))
define_sets(get_notclausearg(clause));
else if (is_opclause(clause))
{
define_sets(get_leftop(clause));
define_sets(get_rightop(clause));
}
}
#endif
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.177 2000/10/03 03:11:19 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.178 2000/10/07 00:58:18 tgl Exp $
* *
* NOTES * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
...@@ -47,6 +47,8 @@ ...@@ -47,6 +47,8 @@
#include "nodes/print.h" #include "nodes/print.h"
#include "optimizer/cost.h" #include "optimizer/cost.h"
#include "optimizer/planner.h" #include "optimizer/planner.h"
#include "parser/analyze.h"
#include "parser/parse.h"
#include "parser/parser.h" #include "parser/parser.h"
#include "rewrite/rewriteHandler.h" #include "rewrite/rewriteHandler.h"
#include "tcop/fastpath.h" #include "tcop/fastpath.h"
...@@ -90,8 +92,6 @@ extern char ControlFilePath[]; ...@@ -90,8 +92,6 @@ extern char ControlFilePath[];
static bool dontExecute = false; static bool dontExecute = false;
static bool IsEmptyQuery = false;
/* note: these declarations had better match tcopprot.h */ /* note: these declarations had better match tcopprot.h */
DLLIMPORT sigjmp_buf Warn_restart; DLLIMPORT sigjmp_buf Warn_restart;
...@@ -129,6 +129,10 @@ int XfuncMode = 0; ...@@ -129,6 +129,10 @@ int XfuncMode = 0;
static int InteractiveBackend(StringInfo inBuf); static int InteractiveBackend(StringInfo inBuf);
static int SocketBackend(StringInfo inBuf); static int SocketBackend(StringInfo inBuf);
static int ReadCommand(StringInfo inBuf); static int ReadCommand(StringInfo inBuf);
static List *pg_parse_query(char *query_string, Oid *typev, int nargs);
static List *pg_analyze_and_rewrite(Node *parsetree);
static void start_xact_command(void);
static void finish_xact_command(void);
static void SigHupHandler(SIGNAL_ARGS); static void SigHupHandler(SIGNAL_ARGS);
static void FloatExceptionHandler(SIGNAL_ARGS); static void FloatExceptionHandler(SIGNAL_ARGS);
static void quickdie(SIGNAL_ARGS); static void quickdie(SIGNAL_ARGS);
...@@ -341,46 +345,120 @@ ReadCommand(StringInfo inBuf) ...@@ -341,46 +345,120 @@ ReadCommand(StringInfo inBuf)
* *
* A list of Query nodes is returned, since the string might contain * A list of Query nodes is returned, since the string might contain
* multiple queries and/or the rewriter might expand one query to several. * multiple queries and/or the rewriter might expand one query to several.
*
* NOTE: this routine is no longer used for processing interactive queries,
* but it is still needed for parsing of SQL function bodies.
*/ */
List * List *
pg_parse_and_rewrite(char *query_string, /* string to execute */ pg_parse_and_rewrite(char *query_string, /* string to execute */
Oid *typev, /* parameter types */ Oid *typev, /* parameter types */
int nargs) /* number of parameters */ int nargs) /* number of parameters */
{ {
List *raw_parsetree_list;
List *querytree_list; List *querytree_list;
List *querytree_list_item; List *list_item;
Query *querytree;
List *new_list; /* ----------------
* (1) parse the request string into a list of raw parse trees.
* ----------------
*/
raw_parsetree_list = pg_parse_query(query_string, typev, nargs);
/* ----------------
* (2) Do parse analysis and rule rewrite.
* ----------------
*/
querytree_list = NIL;
foreach(list_item, raw_parsetree_list)
{
Node *parsetree = (Node *) lfirst(list_item);
querytree_list = nconc(querytree_list,
pg_analyze_and_rewrite(parsetree));
}
return querytree_list;
}
/*
* Do raw parsing (only).
*
* A list of parsetrees is returned, since there might be multiple
* commands in the given string.
*
* NOTE: for interactive queries, it is important to keep this routine
* separate from the analysis & rewrite stages. Analysis and rewriting
* cannot be done in an aborted transaction, since they require access to
* database tables. So, we rely on the raw parser to determine whether
* we've seen a COMMIT or ABORT command; when we are in abort state, other
* commands are not processed any further than the raw parse stage.
*/
static List *
pg_parse_query(char *query_string, Oid *typev, int nargs)
{
List *raw_parsetree_list;
if (Debug_print_query) if (Debug_print_query)
elog(DEBUG, "query: %s", query_string); elog(DEBUG, "query: %s", query_string);
if (Show_parser_stats)
ResetUsage();
raw_parsetree_list = parser(query_string, typev, nargs);
if (Show_parser_stats)
{
fprintf(StatFp, "PARSER STATISTICS\n");
ShowUsage();
}
return raw_parsetree_list;
}
/*
* Given a raw parsetree (gram.y output), perform parse analysis and
* rule rewriting.
*
* A list of Query nodes is returned, since either the analyzer or the
* rewriter might expand one query to several.
*
* NOTE: for reasons mentioned above, this must be separate from raw parsing.
*/
static List *
pg_analyze_and_rewrite(Node *parsetree)
{
List *querytree_list;
List *list_item;
Query *querytree;
List *new_list;
/* ---------------- /* ----------------
* (1) parse the request string into a list of parse trees * (1) Perform parse analysis.
* ---------------- * ----------------
*/ */
if (Show_parser_stats) if (Show_parser_stats)
ResetUsage(); ResetUsage();
querytree_list = parser(query_string, typev, nargs); querytree_list = parse_analyze(parsetree, NULL);
if (Show_parser_stats) if (Show_parser_stats)
{ {
fprintf(StatFp, "PARSER STATISTICS\n"); fprintf(StatFp, "PARSE ANALYSIS STATISTICS\n");
ShowUsage(); ShowUsage();
ResetUsage();
} }
/* ---------------- /* ----------------
* (2) rewrite the queries, as necessary * (2) Rewrite the queries, as necessary
* *
* rewritten queries are collected in new_list. Note there may be * rewritten queries are collected in new_list. Note there may be
* more or fewer than in the original list. * more or fewer than in the original list.
* ---------------- * ----------------
*/ */
new_list = NIL; new_list = NIL;
foreach(querytree_list_item, querytree_list) foreach(list_item, querytree_list)
{ {
querytree = (Query *) lfirst(querytree_list_item); querytree = (Query *) lfirst(list_item);
if (Debug_print_parse) if (Debug_print_parse)
{ {
...@@ -409,19 +487,18 @@ pg_parse_and_rewrite(char *query_string, /* string to execute */ ...@@ -409,19 +487,18 @@ pg_parse_and_rewrite(char *query_string, /* string to execute */
querytree_list = new_list; querytree_list = new_list;
if (Show_parser_stats)
{
fprintf(StatFp, "REWRITER STATISTICS\n");
ShowUsage();
}
#ifdef COPY_PARSE_PLAN_TREES #ifdef COPY_PARSE_PLAN_TREES
/* Optional debugging check: pass parsetree output through copyObject() */ /* Optional debugging check: pass querytree output through copyObject() */
/*
* Note: we run this test after rewrite, not before, because copyObject()
* does not handle most kinds of nodes that are used only in raw parse
* trees. The present (bizarre) implementation of UNION/INTERSECT/EXCEPT
* doesn't run analysis of the second and later subqueries until rewrite,
* so we'd get false failures on these queries if we did it beforehand.
*/
new_list = (List *) copyObject(querytree_list); new_list = (List *) copyObject(querytree_list);
/* This checks both copyObject() and the equal() routines... */ /* This checks both copyObject() and the equal() routines... */
if (! equal(new_list, querytree_list)) if (! equal(new_list, querytree_list))
elog(NOTICE, "pg_parse_and_rewrite: copyObject failed on parse tree"); elog(NOTICE, "pg_analyze_and_rewrite: copyObject failed on parse tree");
else else
querytree_list = new_list; querytree_list = new_list;
#endif #endif
...@@ -431,9 +508,9 @@ pg_parse_and_rewrite(char *query_string, /* string to execute */ ...@@ -431,9 +508,9 @@ pg_parse_and_rewrite(char *query_string, /* string to execute */
if (Debug_pretty_print) if (Debug_pretty_print)
{ {
elog(DEBUG, "rewritten parse tree:"); elog(DEBUG, "rewritten parse tree:");
foreach(querytree_list_item, querytree_list) foreach(list_item, querytree_list)
{ {
querytree = (Query *) lfirst(querytree_list_item); querytree = (Query *) lfirst(list_item);
nodeDisplay(querytree); nodeDisplay(querytree);
printf("\n"); printf("\n");
} }
...@@ -441,10 +518,9 @@ pg_parse_and_rewrite(char *query_string, /* string to execute */ ...@@ -441,10 +518,9 @@ pg_parse_and_rewrite(char *query_string, /* string to execute */
else else
{ {
elog(DEBUG, "rewritten parse tree:"); elog(DEBUG, "rewritten parse tree:");
foreach(list_item, querytree_list)
foreach(querytree_list_item, querytree_list)
{ {
querytree = (Query *) lfirst(querytree_list_item); querytree = (Query *) lfirst(list_item);
elog(DEBUG, "%s", nodeToString(querytree)); elog(DEBUG, "%s", nodeToString(querytree));
} }
} }
...@@ -514,7 +590,7 @@ pg_plan_query(Query *querytree) ...@@ -514,7 +590,7 @@ pg_plan_query(Query *querytree)
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* pg_exec_query_dest() * pg_exec_query_string()
* *
* Takes a querystring, runs the parser/utilities or * Takes a querystring, runs the parser/utilities or
* parser/planner/executor over it as necessary. * parser/planner/executor over it as necessary.
...@@ -545,21 +621,31 @@ pg_plan_query(Query *querytree) ...@@ -545,21 +621,31 @@ pg_plan_query(Query *querytree)
*/ */
void void
pg_exec_query_dest(char *query_string, /* string to execute */ pg_exec_query_string(char *query_string, /* string to execute */
CommandDest dest, /* where results should go */ CommandDest dest, /* where results should go */
MemoryContext parse_context) /* context for parsetrees */ MemoryContext parse_context) /* context for parsetrees */
{ {
bool xact_started;
MemoryContext oldcontext; MemoryContext oldcontext;
List *querytree_list, List *parsetree_list,
*querytree_item; *parsetree_item;
/* /*
* If you called this routine with parse_context = CurrentMemoryContext, * Start up a transaction command. All queries generated by the
* you blew it. They *must* be different, else the context reset * query_string will be in this same command block, *unless* we find
* at the bottom of the loop will destroy the querytree list. * a BEGIN/COMMIT/ABORT statement; we have to force a new xact command
* (We really ought to check that parse_context isn't a child of * after one of those, else bad things will happen in xact.c.
* CurrentMemoryContext either, but that would take more cycles than * (Note that this will possibly change execution memory context.)
* it's likely to be worth.) */
start_xact_command();
xact_started = true;
/*
* parse_context *must* be different from the execution memory context,
* else the context reset at the bottom of the loop will destroy the
* parsetree list. (We really ought to check that parse_context isn't a
* child of CurrentMemoryContext either, but that would take more cycles
* than it's likely to be worth.)
*/ */
Assert(parse_context != CurrentMemoryContext); Assert(parse_context != CurrentMemoryContext);
...@@ -569,48 +655,57 @@ pg_exec_query_dest(char *query_string, /* string to execute */ ...@@ -569,48 +655,57 @@ pg_exec_query_dest(char *query_string, /* string to execute */
oldcontext = MemoryContextSwitchTo(parse_context); oldcontext = MemoryContextSwitchTo(parse_context);
/* /*
* Parse and rewrite the query or queries. * Do basic parsing of the query or queries (this should be safe
* even if we are in aborted transaction state!)
*/ */
querytree_list = pg_parse_and_rewrite(query_string, NULL, 0); parsetree_list = pg_parse_query(query_string, NULL, 0);
/* /*
* Switch back to execution context for planning and execution. * Switch back to execution context to enter the loop.
*/ */
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
/* /*
* Run through the query or queries and execute each one. * Run through the parsetree(s) and process each one.
*/ */
foreach(querytree_item, querytree_list) foreach(parsetree_item, parsetree_list)
{ {
Query *querytree = (Query *) lfirst(querytree_item); Node *parsetree = (Node *) lfirst(parsetree_item);
bool isTransactionStmt;
List *querytree_list,
*querytree_item;
/* if we got a cancel signal in parsing or prior command, quit */ /* Transaction control statements need some special handling */
if (QueryCancel) isTransactionStmt = IsA(parsetree, TransactionStmt);
CancelQuery();
if (querytree->commandType == CMD_UTILITY) /*
* If we are in an aborted transaction, ignore all commands except
* COMMIT/ABORT. It is important that this test occur before we
* try to do parse analysis, rewrite, or planning, since all those
* phases try to do database accesses, which may fail in abort state.
* (It might be safe to allow some additional utility commands in
* this state, but not many...)
*/
if (IsAbortedTransactionBlockState())
{ {
/* ---------------- bool allowit = false;
* process utility functions (create, destroy, etc..)
*
* Note: we do not check for the transaction aborted state
* because that is done in ProcessUtility.
* ----------------
*/
if (Debug_print_query)
elog(DEBUG, "ProcessUtility: %s", query_string);
else if (DebugLvl > 1)
elog(DEBUG, "ProcessUtility");
ProcessUtility(querytree->utilityStmt, dest); if (isTransactionStmt)
} {
else TransactionStmt *stmt = (TransactionStmt *) parsetree;
{
Plan *plan; switch (stmt->command)
{
case COMMIT:
case ROLLBACK:
allowit = true;
break;
default:
break;
}
}
/* If aborted transaction, skip planning and execution */ if (! allowit)
if (IsAbortedTransactionBlockState())
{ {
/* ---------------- /* ----------------
* the EndCommand() stuff is to tell the frontend * the EndCommand() stuff is to tell the frontend
...@@ -631,58 +726,180 @@ pg_exec_query_dest(char *query_string, /* string to execute */ ...@@ -631,58 +726,180 @@ pg_exec_query_dest(char *query_string, /* string to execute */
*/ */
continue; continue;
} }
}
plan = pg_plan_query(querytree); /* Make sure we are in a transaction command */
if (! xact_started)
{
start_xact_command();
xact_started = true;
}
/* if we got a cancel signal whilst planning, quit */ /* If we got a cancel signal in parsing or prior command, quit */
if (QueryCancel) if (QueryCancel)
CancelQuery(); CancelQuery();
/*
* OK to analyze and rewrite this query.
*
* Switch to appropriate context for constructing querytrees
* (again, these must outlive the execution context).
*/
oldcontext = MemoryContextSwitchTo(parse_context);
/* Initialize snapshot state for query */ querytree_list = pg_analyze_and_rewrite(parsetree);
SetQuerySnapshot();
/* /*
* execute the plan * Switch back to execution context for planning and execution.
*/ */
if (Show_executor_stats) MemoryContextSwitchTo(oldcontext);
ResetUsage();
/*
* Inner loop handles the individual queries generated from a
* single parsetree by analysis and rewrite.
*/
foreach(querytree_item, querytree_list)
{
Query *querytree = (Query *) lfirst(querytree_item);
if (dontExecute) /* Make sure we are in a transaction command */
if (! xact_started)
{ {
/* don't execute it, just show the query plan */ start_xact_command();
print_plan(plan, querytree); xact_started = true;
}
/* If we got a cancel signal in analysis or prior command, quit */
if (QueryCancel)
CancelQuery();
if (querytree->commandType == CMD_UTILITY)
{
/* ----------------
* process utility functions (create, destroy, etc..)
* ----------------
*/
if (Debug_print_query)
elog(DEBUG, "ProcessUtility: %s", query_string);
else if (DebugLvl > 1)
elog(DEBUG, "ProcessUtility");
ProcessUtility(querytree->utilityStmt, dest);
} }
else else
{ {
if (DebugLvl > 1) /* ----------------
elog(DEBUG, "ProcessQuery"); * process a plannable query.
ProcessQuery(querytree, plan, dest); * ----------------
*/
Plan *plan;
plan = pg_plan_query(querytree);
/* if we got a cancel signal whilst planning, quit */
if (QueryCancel)
CancelQuery();
/* Initialize snapshot state for query */
SetQuerySnapshot();
/*
* execute the plan
*/
if (Show_executor_stats)
ResetUsage();
if (dontExecute)
{
/* don't execute it, just show the query plan */
print_plan(plan, querytree);
}
else
{
if (DebugLvl > 1)
elog(DEBUG, "ProcessQuery");
ProcessQuery(querytree, plan, dest);
}
if (Show_executor_stats)
{
fprintf(stderr, "EXECUTOR STATISTICS\n");
ShowUsage();
}
} }
if (Show_executor_stats) /*
* In a query block, we want to increment the command counter
* between queries so that the effects of early queries are
* visible to subsequent ones. In particular we'd better
* do so before checking constraints.
*/
if (!isTransactionStmt)
CommandCounterIncrement();
/*
* Invoke IMMEDIATE constraint triggers
*/
DeferredTriggerEndQuery();
/*
* Clear the execution context to recover temporary
* memory used by the query. NOTE: if query string contains
* BEGIN/COMMIT transaction commands, execution context may
* now be different from what we were originally passed;
* so be careful to clear current context not "oldcontext".
*/
Assert(parse_context != CurrentMemoryContext);
MemoryContextResetAndDeleteChildren(CurrentMemoryContext);
/*
* If this was a transaction control statement, commit it
* and arrange to start a new xact command for the next
* command (if any).
*/
if (isTransactionStmt)
{ {
fprintf(stderr, "EXECUTOR STATISTICS\n"); finish_xact_command();
ShowUsage(); xact_started = false;
} }
}
/* } /* end loop over queries generated from a parsetree */
* In a query block, we want to increment the command counter } /* end loop over parsetrees */
* between queries so that the effects of early queries are
* visible to subsequent ones. /*
*/ * Close down transaction statement, if one is open.
CommandCounterIncrement(); */
/* if (xact_started)
* Also, clear the execution context to recover temporary finish_xact_command();
* memory used by the query. NOTE: if query string contains
* BEGIN/COMMIT transaction commands, execution context may
* now be different from what we were originally passed;
* so be careful to clear current context not "oldcontext".
*/
MemoryContextResetAndDeleteChildren(CurrentMemoryContext);
}
} }
/*
* Convenience routines for starting/committing a single command.
*/
static void
start_xact_command(void)
{
if (DebugLvl >= 1)
elog(DEBUG, "StartTransactionCommand");
StartTransactionCommand();
}
static void
finish_xact_command(void)
{
if (DebugLvl >= 1)
elog(DEBUG, "CommitTransactionCommand");
set_ps_display("commit"); /* XXX probably the wrong place to do this */
CommitTransactionCommand();
#ifdef SHOW_MEMORY_STATS
/* print mem stats at each commit for leak tracking */
if (ShowStats)
MemoryContextStats(TopMemoryContext);
#endif
}
/* -------------------------------- /* --------------------------------
* signal handler routines used in PostgresMain() * signal handler routines used in PostgresMain()
* *
...@@ -1397,7 +1614,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1397,7 +1614,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
puts("\nPOSTGRES backend interactive interface "); puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.177 $ $Date: 2000/10/03 03:11:19 $\n"); puts("$Revision: 1.178 $ $Date: 2000/10/07 00:58:18 $\n");
} }
/* /*
...@@ -1524,22 +1741,20 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1524,22 +1741,20 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
{ {
/* ---------------- /* ----------------
* 'F' indicates a fastpath call. * 'F' indicates a fastpath call.
* XXX HandleFunctionRequest
* ---------------- * ----------------
*/ */
case 'F': case 'F':
IsEmptyQuery = false;
/* start an xact for this function invocation */ /* start an xact for this function invocation */
if (DebugLvl >= 1) start_xact_command();
elog(DEBUG, "StartTransactionCommand");
StartTransactionCommand();
if (HandleFunctionRequest() == EOF) if (HandleFunctionRequest() == EOF)
{ {
/* lost frontend connection during F message input */ /* lost frontend connection during F message input */
goto normalexit; goto normalexit;
} }
/* commit the function-invocation transaction */
finish_xact_command();
break; break;
/* ---------------- /* ----------------
...@@ -1551,35 +1766,28 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1551,35 +1766,28 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
{ {
/* ---------------- /* ----------------
* if there is nothing in the input buffer, don't bother * if there is nothing in the input buffer, don't bother
* trying to parse and execute anything.. * trying to parse and execute anything; just send
* back a quick NullCommand response.
* ---------------- * ----------------
*/ */
IsEmptyQuery = true; if (IsUnderPostmaster)
NullCommand(Remote);
} }
else else
{ {
/* ---------------- /* ----------------
* otherwise, process the input string. * otherwise, process the input string.
*
* Note: transaction command start/end is now done
* within pg_exec_query_string(), not here.
* ---------------- * ----------------
*/ */
IsEmptyQuery = false;
if (Show_query_stats) if (Show_query_stats)
ResetUsage(); ResetUsage();
/* start an xact for this query */ pg_exec_query_string(parser_input->data,
if (DebugLvl >= 1) whereToSendOutput,
elog(DEBUG, "StartTransactionCommand"); QueryContext);
StartTransactionCommand();
pg_exec_query_dest(parser_input->data,
whereToSendOutput,
QueryContext);
/*
* Invoke IMMEDIATE constraint triggers
*
*/
DeferredTriggerEndQuery();
if (Show_query_stats) if (Show_query_stats)
{ {
...@@ -1603,39 +1811,14 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha ...@@ -1603,39 +1811,14 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
elog(ERROR, "unknown frontend message was received"); elog(ERROR, "unknown frontend message was received");
} }
/* ----------------
* (6) commit the current transaction
*
* Note: if we had an empty input buffer, then we didn't
* call pg_exec_query_dest, so we don't bother to commit
* this transaction.
* ----------------
*/
if (!IsEmptyQuery)
{
if (DebugLvl >= 1)
elog(DEBUG, "CommitTransactionCommand");
set_ps_display("commit");
CommitTransactionCommand();
#ifdef SHOW_MEMORY_STATS
/* print global-context stats at each commit for leak tracking */
if (ShowStats)
MemoryContextStats(TopMemoryContext);
#endif
}
else
{
if (IsUnderPostmaster)
NullCommand(Remote);
}
#ifdef MEMORY_CONTEXT_CHECKING #ifdef MEMORY_CONTEXT_CHECKING
/* /*
* Check all memory after each backend loop * Check all memory after each backend loop. This is a rather
* weird place to do it, perhaps.
*/ */
MemoryContextCheck(TopMemoryContext); MemoryContextCheck(TopMemoryContext);
#endif #endif
} /* end of main loop */ } /* end of input-reading loop */
normalexit: normalexit:
ExitAfterAbort = true; /* ensure we will exit if elog during abort */ ExitAfterAbort = true; /* ensure we will exit if elog during abort */
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.94 2000/09/12 05:09:45 momjian Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.95 2000/10/07 00:58:18 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "commands/view.h" #include "commands/view.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "parser/parse.h" #include "parser/parse.h"
#include "parser/parse_expr.h"
#include "rewrite/rewriteDefine.h" #include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteRemove.h" #include "rewrite/rewriteRemove.h"
#include "tcop/utility.h" #include "tcop/utility.h"
...@@ -45,24 +46,6 @@ ...@@ -45,24 +46,6 @@
#include "utils/syscache.h" #include "utils/syscache.h"
/* ----------------
* CHECK_IF_ABORTED() is used to avoid doing unnecessary
* processing within an aborted transaction block.
* ----------------
*/
/* we have to use IF because of the 'break' */
#define CHECK_IF_ABORTED() \
if (1) \
{ \
if (IsAbortedTransactionBlockState()) \
{ \
elog(NOTICE, "current transaction is aborted, " \
"queries ignored until end of transaction block"); \
commandTag = "*ABORT STATE*"; \
break; \
} \
} else
/* ---------------- /* ----------------
* general utility function invoker * general utility function invoker
* ---------------- * ----------------
...@@ -90,7 +73,6 @@ ProcessUtility(Node *parsetree, ...@@ -90,7 +73,6 @@ ProcessUtility(Node *parsetree,
{ {
case BEGIN_TRANS: case BEGIN_TRANS:
set_ps_display(commandTag = "BEGIN"); set_ps_display(commandTag = "BEGIN");
CHECK_IF_ABORTED();
BeginTransactionBlock(); BeginTransactionBlock();
break; break;
...@@ -116,7 +98,6 @@ ProcessUtility(Node *parsetree, ...@@ -116,7 +98,6 @@ ProcessUtility(Node *parsetree,
ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree; ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
set_ps_display(commandTag = "CLOSE"); set_ps_display(commandTag = "CLOSE");
CHECK_IF_ABORTED();
PerformPortalClose(stmt->portalname, dest); PerformPortalClose(stmt->portalname, dest);
} }
...@@ -130,7 +111,6 @@ ProcessUtility(Node *parsetree, ...@@ -130,7 +111,6 @@ ProcessUtility(Node *parsetree,
int count; int count;
set_ps_display(commandTag = (stmt->ismove) ? "MOVE" : "FETCH"); set_ps_display(commandTag = (stmt->ismove) ? "MOVE" : "FETCH");
CHECK_IF_ABORTED();
SetQuerySnapshot(); SetQuerySnapshot();
...@@ -153,7 +133,6 @@ ProcessUtility(Node *parsetree, ...@@ -153,7 +133,6 @@ ProcessUtility(Node *parsetree,
*/ */
case T_CreateStmt: case T_CreateStmt:
set_ps_display(commandTag = "CREATE"); set_ps_display(commandTag = "CREATE");
CHECK_IF_ABORTED();
DefineRelation((CreateStmt *) parsetree, RELKIND_RELATION); DefineRelation((CreateStmt *) parsetree, RELKIND_RELATION);
...@@ -174,7 +153,6 @@ ProcessUtility(Node *parsetree, ...@@ -174,7 +153,6 @@ ProcessUtility(Node *parsetree,
List *arg; List *arg;
set_ps_display(commandTag = "DROP"); set_ps_display(commandTag = "DROP");
CHECK_IF_ABORTED();
/* check as much as we can before we start dropping ... */ /* check as much as we can before we start dropping ... */
foreach(arg, args) foreach(arg, args)
...@@ -216,7 +194,6 @@ ProcessUtility(Node *parsetree, ...@@ -216,7 +194,6 @@ ProcessUtility(Node *parsetree,
Relation rel; Relation rel;
set_ps_display(commandTag = "TRUNCATE"); set_ps_display(commandTag = "TRUNCATE");
CHECK_IF_ABORTED();
relname = ((TruncateStmt *) parsetree)->relName; relname = ((TruncateStmt *) parsetree)->relName;
if (!allowSystemTableMods && IsSystemRelationName(relname)) if (!allowSystemTableMods && IsSystemRelationName(relname))
...@@ -243,27 +220,23 @@ ProcessUtility(Node *parsetree, ...@@ -243,27 +220,23 @@ ProcessUtility(Node *parsetree,
case T_CommentStmt: case T_CommentStmt:
{ {
CommentStmt *statement; CommentStmt *statement;
statement = ((CommentStmt *) parsetree); statement = ((CommentStmt *) parsetree);
set_ps_display(commandTag = "COMMENT"); set_ps_display(commandTag = "COMMENT");
CHECK_IF_ABORTED();
CommentObject(statement->objtype, statement->objname, CommentObject(statement->objtype, statement->objname,
statement->objproperty, statement->objlist, statement->objproperty, statement->objlist,
statement->comment); statement->comment);
} }
break; break;
case T_CopyStmt: case T_CopyStmt:
{ {
CopyStmt *stmt = (CopyStmt *) parsetree; CopyStmt *stmt = (CopyStmt *) parsetree;
set_ps_display(commandTag = "COPY"); set_ps_display(commandTag = "COPY");
CHECK_IF_ABORTED();
if (stmt->direction != FROM) if (stmt->direction != FROM)
SetQuerySnapshot(); SetQuerySnapshot();
...@@ -292,7 +265,6 @@ ProcessUtility(Node *parsetree, ...@@ -292,7 +265,6 @@ ProcessUtility(Node *parsetree,
RenameStmt *stmt = (RenameStmt *) parsetree; RenameStmt *stmt = (RenameStmt *) parsetree;
set_ps_display(commandTag = "ALTER"); set_ps_display(commandTag = "ALTER");
CHECK_IF_ABORTED();
relname = stmt->relname; relname = stmt->relname;
if (!allowSystemTableMods && IsSystemRelationName(relname)) if (!allowSystemTableMods && IsSystemRelationName(relname))
...@@ -345,7 +317,6 @@ ProcessUtility(Node *parsetree, ...@@ -345,7 +317,6 @@ ProcessUtility(Node *parsetree,
AlterTableStmt *stmt = (AlterTableStmt *) parsetree; AlterTableStmt *stmt = (AlterTableStmt *) parsetree;
set_ps_display(commandTag = "ALTER"); set_ps_display(commandTag = "ALTER");
CHECK_IF_ABORTED();
/* /*
* Some or all of these functions are recursive to cover * Some or all of these functions are recursive to cover
...@@ -385,34 +356,10 @@ ProcessUtility(Node *parsetree, ...@@ -385,34 +356,10 @@ ProcessUtility(Node *parsetree,
case T_ChangeACLStmt: case T_ChangeACLStmt:
{ {
ChangeACLStmt *stmt = (ChangeACLStmt *) parsetree; ChangeACLStmt *stmt = (ChangeACLStmt *) parsetree;
List *i;
AclItem *aip;
unsigned modechg;
set_ps_display(commandTag = "CHANGE"); set_ps_display(commandTag = "CHANGE");
CHECK_IF_ABORTED();
aip = stmt->aclitem;
modechg = stmt->modechg; ExecuteChangeACLStmt(stmt);
foreach(i, stmt->relNames)
{
Relation rel;
relname = strVal(lfirst(i));
rel = heap_openr(relname, AccessExclusiveLock);
if (rel && rel->rd_rel->relkind == RELKIND_INDEX)
elog(ERROR, "\"%s\" is an index relation",
relname);
/* close rel, but keep lock until end of xact */
heap_close(rel, NoLock);
#ifndef NO_SECURITY
if (!pg_ownercheck(GetUserId(), relname, RELNAME))
elog(ERROR, "you do not own class \"%s\"",
relname);
#endif
ChangeAcl(relname, aip, modechg);
}
} }
break; break;
...@@ -426,7 +373,6 @@ ProcessUtility(Node *parsetree, ...@@ -426,7 +373,6 @@ ProcessUtility(Node *parsetree,
DefineStmt *stmt = (DefineStmt *) parsetree; DefineStmt *stmt = (DefineStmt *) parsetree;
set_ps_display(commandTag = "CREATE"); set_ps_display(commandTag = "CREATE");
CHECK_IF_ABORTED();
switch (stmt->defType) switch (stmt->defType)
{ {
...@@ -450,14 +396,14 @@ ProcessUtility(Node *parsetree, ...@@ -450,14 +396,14 @@ ProcessUtility(Node *parsetree,
ViewStmt *stmt = (ViewStmt *) parsetree; ViewStmt *stmt = (ViewStmt *) parsetree;
set_ps_display(commandTag = "CREATE"); set_ps_display(commandTag = "CREATE");
CHECK_IF_ABORTED();
DefineView(stmt->viewname, stmt->query); /* retrieve parsetree */ DefineView(stmt->viewname, stmt->query); /* retrieve parsetree */
} }
break; break;
case T_ProcedureStmt: /* CREATE FUNCTION */ case T_ProcedureStmt: /* CREATE FUNCTION */
set_ps_display(commandTag = "CREATE"); set_ps_display(commandTag = "CREATE");
CHECK_IF_ABORTED();
CreateFunction((ProcedureStmt *) parsetree, dest); /* everything */ CreateFunction((ProcedureStmt *) parsetree, dest); /* everything */
break; break;
...@@ -466,7 +412,7 @@ ProcessUtility(Node *parsetree, ...@@ -466,7 +412,7 @@ ProcessUtility(Node *parsetree,
IndexStmt *stmt = (IndexStmt *) parsetree; IndexStmt *stmt = (IndexStmt *) parsetree;
set_ps_display(commandTag = "CREATE"); set_ps_display(commandTag = "CREATE");
CHECK_IF_ABORTED();
DefineIndex(stmt->relname, /* relation name */ DefineIndex(stmt->relname, /* relation name */
stmt->idxname, /* index name */ stmt->idxname, /* index name */
stmt->accessMethod, /* am name */ stmt->accessMethod, /* am name */
...@@ -491,14 +437,13 @@ ProcessUtility(Node *parsetree, ...@@ -491,14 +437,13 @@ ProcessUtility(Node *parsetree,
elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]); elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
#endif #endif
set_ps_display(commandTag = "CREATE"); set_ps_display(commandTag = "CREATE");
CHECK_IF_ABORTED();
DefineQueryRewrite(stmt); DefineQueryRewrite(stmt);
} }
break; break;
case T_CreateSeqStmt: case T_CreateSeqStmt:
set_ps_display(commandTag = "CREATE"); set_ps_display(commandTag = "CREATE");
CHECK_IF_ABORTED();
DefineSequence((CreateSeqStmt *) parsetree); DefineSequence((CreateSeqStmt *) parsetree);
break; break;
...@@ -508,7 +453,6 @@ ProcessUtility(Node *parsetree, ...@@ -508,7 +453,6 @@ ProcessUtility(Node *parsetree,
ExtendStmt *stmt = (ExtendStmt *) parsetree; ExtendStmt *stmt = (ExtendStmt *) parsetree;
set_ps_display(commandTag = "EXTEND"); set_ps_display(commandTag = "EXTEND");
CHECK_IF_ABORTED();
ExtendIndex(stmt->idxname, /* index name */ ExtendIndex(stmt->idxname, /* index name */
(Expr *) stmt->whereClause, /* where */ (Expr *) stmt->whereClause, /* where */
...@@ -521,7 +465,6 @@ ProcessUtility(Node *parsetree, ...@@ -521,7 +465,6 @@ ProcessUtility(Node *parsetree,
RemoveStmt *stmt = (RemoveStmt *) parsetree; RemoveStmt *stmt = (RemoveStmt *) parsetree;
set_ps_display(commandTag = "DROP"); set_ps_display(commandTag = "DROP");
CHECK_IF_ABORTED();
switch (stmt->removeType) switch (stmt->removeType)
{ {
...@@ -581,10 +524,14 @@ ProcessUtility(Node *parsetree, ...@@ -581,10 +524,14 @@ ProcessUtility(Node *parsetree,
case T_RemoveAggrStmt: case T_RemoveAggrStmt:
{ {
RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree; RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
char *typename = (char *) NULL;
set_ps_display(commandTag = "DROP"); set_ps_display(commandTag = "DROP");
CHECK_IF_ABORTED();
RemoveAggregate(stmt->aggname, stmt->aggtype); if (stmt->aggtype != NULL)
typename = TypeNameToInternalName((TypeName *) stmt->aggtype);
RemoveAggregate(stmt->aggname, typename);
} }
break; break;
...@@ -593,27 +540,27 @@ ProcessUtility(Node *parsetree, ...@@ -593,27 +540,27 @@ ProcessUtility(Node *parsetree,
RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree; RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
set_ps_display(commandTag = "DROP"); set_ps_display(commandTag = "DROP");
CHECK_IF_ABORTED();
RemoveFunction(stmt->funcname, RemoveFunction(stmt->funcname, stmt->args);
length(stmt->args),
stmt->args);
} }
break; break;
case T_RemoveOperStmt: case T_RemoveOperStmt:
{ {
RemoveOperStmt *stmt = (RemoveOperStmt *) parsetree; RemoveOperStmt *stmt = (RemoveOperStmt *) parsetree;
char *type1 = (char *) NULL; TypeName *typenode1 = (TypeName *) lfirst(stmt->args);
char *type2 = (char *) NULL; TypeName *typenode2 = (TypeName *) lsecond(stmt->args);
char *typename1 = (char *) NULL;
char *typename2 = (char *) NULL;
set_ps_display(commandTag = "DROP"); set_ps_display(commandTag = "DROP");
CHECK_IF_ABORTED();
if (lfirst(stmt->args) != NULL) if (typenode1 != NULL)
type1 = strVal(lfirst(stmt->args)); typename1 = TypeNameToInternalName(typenode1);
if (lsecond(stmt->args) != NULL) if (typenode2 != NULL)
type2 = strVal(lsecond(stmt->args)); typename2 = TypeNameToInternalName(typenode2);
RemoveOperator(stmt->opname, type1, type2);
RemoveOperator(stmt->opname, typename1, typename2);
} }
break; break;
...@@ -626,7 +573,7 @@ ProcessUtility(Node *parsetree, ...@@ -626,7 +573,7 @@ ProcessUtility(Node *parsetree,
CreatedbStmt *stmt = (CreatedbStmt *) parsetree; CreatedbStmt *stmt = (CreatedbStmt *) parsetree;
set_ps_display(commandTag = "CREATE DATABASE"); set_ps_display(commandTag = "CREATE DATABASE");
CHECK_IF_ABORTED();
createdb(stmt->dbname, stmt->dbpath, stmt->encoding); createdb(stmt->dbname, stmt->dbpath, stmt->encoding);
} }
break; break;
...@@ -636,7 +583,7 @@ ProcessUtility(Node *parsetree, ...@@ -636,7 +583,7 @@ ProcessUtility(Node *parsetree,
DropdbStmt *stmt = (DropdbStmt *) parsetree; DropdbStmt *stmt = (DropdbStmt *) parsetree;
set_ps_display(commandTag = "DROP DATABASE"); set_ps_display(commandTag = "DROP DATABASE");
CHECK_IF_ABORTED();
dropdb(stmt->dbname); dropdb(stmt->dbname);
} }
break; break;
...@@ -647,7 +594,6 @@ ProcessUtility(Node *parsetree, ...@@ -647,7 +594,6 @@ ProcessUtility(Node *parsetree,
NotifyStmt *stmt = (NotifyStmt *) parsetree; NotifyStmt *stmt = (NotifyStmt *) parsetree;
set_ps_display(commandTag = "NOTIFY"); set_ps_display(commandTag = "NOTIFY");
CHECK_IF_ABORTED();
Async_Notify(stmt->relname); Async_Notify(stmt->relname);
} }
...@@ -658,7 +604,6 @@ ProcessUtility(Node *parsetree, ...@@ -658,7 +604,6 @@ ProcessUtility(Node *parsetree,
ListenStmt *stmt = (ListenStmt *) parsetree; ListenStmt *stmt = (ListenStmt *) parsetree;
set_ps_display(commandTag = "LISTEN"); set_ps_display(commandTag = "LISTEN");
CHECK_IF_ABORTED();
Async_Listen(stmt->relname, MyProcPid); Async_Listen(stmt->relname, MyProcPid);
} }
...@@ -669,7 +614,6 @@ ProcessUtility(Node *parsetree, ...@@ -669,7 +614,6 @@ ProcessUtility(Node *parsetree,
UnlistenStmt *stmt = (UnlistenStmt *) parsetree; UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
set_ps_display(commandTag = "UNLISTEN"); set_ps_display(commandTag = "UNLISTEN");
CHECK_IF_ABORTED();
Async_Unlisten(stmt->relname, MyProcPid); Async_Unlisten(stmt->relname, MyProcPid);
} }
...@@ -684,7 +628,6 @@ ProcessUtility(Node *parsetree, ...@@ -684,7 +628,6 @@ ProcessUtility(Node *parsetree,
LoadStmt *stmt = (LoadStmt *) parsetree; LoadStmt *stmt = (LoadStmt *) parsetree;
set_ps_display(commandTag = "LOAD"); set_ps_display(commandTag = "LOAD");
CHECK_IF_ABORTED();
closeAllVfds(); /* probably not necessary... */ closeAllVfds(); /* probably not necessary... */
load_file(stmt->filename); load_file(stmt->filename);
...@@ -696,7 +639,6 @@ ProcessUtility(Node *parsetree, ...@@ -696,7 +639,6 @@ ProcessUtility(Node *parsetree,
ClusterStmt *stmt = (ClusterStmt *) parsetree; ClusterStmt *stmt = (ClusterStmt *) parsetree;
set_ps_display(commandTag = "CLUSTER"); set_ps_display(commandTag = "CLUSTER");
CHECK_IF_ABORTED();
cluster(stmt->relname, stmt->indexname); cluster(stmt->relname, stmt->indexname);
} }
...@@ -704,7 +646,7 @@ ProcessUtility(Node *parsetree, ...@@ -704,7 +646,7 @@ ProcessUtility(Node *parsetree,
case T_VacuumStmt: case T_VacuumStmt:
set_ps_display(commandTag = "VACUUM"); set_ps_display(commandTag = "VACUUM");
CHECK_IF_ABORTED();
vacuum(((VacuumStmt *) parsetree)->vacrel, vacuum(((VacuumStmt *) parsetree)->vacrel,
((VacuumStmt *) parsetree)->verbose, ((VacuumStmt *) parsetree)->verbose,
((VacuumStmt *) parsetree)->analyze, ((VacuumStmt *) parsetree)->analyze,
...@@ -716,7 +658,6 @@ ProcessUtility(Node *parsetree, ...@@ -716,7 +658,6 @@ ProcessUtility(Node *parsetree,
ExplainStmt *stmt = (ExplainStmt *) parsetree; ExplainStmt *stmt = (ExplainStmt *) parsetree;
set_ps_display(commandTag = "EXPLAIN"); set_ps_display(commandTag = "EXPLAIN");
CHECK_IF_ABORTED();
ExplainQuery(stmt->query, stmt->verbose, dest); ExplainQuery(stmt->query, stmt->verbose, dest);
} }
...@@ -732,7 +673,7 @@ ProcessUtility(Node *parsetree, ...@@ -732,7 +673,7 @@ ProcessUtility(Node *parsetree,
RecipeStmt *stmt = (RecipeStmt *) parsetree; RecipeStmt *stmt = (RecipeStmt *) parsetree;
set_ps_display(commandTag = "EXECUTE RECIPE"); set_ps_display(commandTag = "EXECUTE RECIPE");
CHECK_IF_ABORTED();
beginRecipe(stmt); beginRecipe(stmt);
} }
break; break;
...@@ -773,14 +714,12 @@ ProcessUtility(Node *parsetree, ...@@ -773,14 +714,12 @@ ProcessUtility(Node *parsetree,
*/ */
case T_CreateTrigStmt: case T_CreateTrigStmt:
set_ps_display(commandTag = "CREATE"); set_ps_display(commandTag = "CREATE");
CHECK_IF_ABORTED();
CreateTrigger((CreateTrigStmt *) parsetree); CreateTrigger((CreateTrigStmt *) parsetree);
break; break;
case T_DropTrigStmt: case T_DropTrigStmt:
set_ps_display(commandTag = "DROP"); set_ps_display(commandTag = "DROP");
CHECK_IF_ABORTED();
DropTrigger((DropTrigStmt *) parsetree); DropTrigger((DropTrigStmt *) parsetree);
break; break;
...@@ -790,14 +729,12 @@ ProcessUtility(Node *parsetree, ...@@ -790,14 +729,12 @@ ProcessUtility(Node *parsetree,
*/ */
case T_CreatePLangStmt: case T_CreatePLangStmt:
set_ps_display(commandTag = "CREATE"); set_ps_display(commandTag = "CREATE");
CHECK_IF_ABORTED();
CreateProceduralLanguage((CreatePLangStmt *) parsetree); CreateProceduralLanguage((CreatePLangStmt *) parsetree);
break; break;
case T_DropPLangStmt: case T_DropPLangStmt:
set_ps_display(commandTag = "DROP"); set_ps_display(commandTag = "DROP");
CHECK_IF_ABORTED();
DropProceduralLanguage((DropPLangStmt *) parsetree); DropProceduralLanguage((DropPLangStmt *) parsetree);
break; break;
...@@ -808,56 +745,48 @@ ProcessUtility(Node *parsetree, ...@@ -808,56 +745,48 @@ ProcessUtility(Node *parsetree,
*/ */
case T_CreateUserStmt: case T_CreateUserStmt:
set_ps_display(commandTag = "CREATE USER"); set_ps_display(commandTag = "CREATE USER");
CHECK_IF_ABORTED();
CreateUser((CreateUserStmt *) parsetree); CreateUser((CreateUserStmt *) parsetree);
break; break;
case T_AlterUserStmt: case T_AlterUserStmt:
set_ps_display(commandTag = "ALTER USER"); set_ps_display(commandTag = "ALTER USER");
CHECK_IF_ABORTED();
AlterUser((AlterUserStmt *) parsetree); AlterUser((AlterUserStmt *) parsetree);
break; break;
case T_DropUserStmt: case T_DropUserStmt:
set_ps_display(commandTag = "DROP USER"); set_ps_display(commandTag = "DROP USER");
CHECK_IF_ABORTED();
DropUser((DropUserStmt *) parsetree); DropUser((DropUserStmt *) parsetree);
break; break;
case T_LockStmt: case T_LockStmt:
set_ps_display(commandTag = "LOCK TABLE"); set_ps_display(commandTag = "LOCK TABLE");
CHECK_IF_ABORTED();
LockTableCommand((LockStmt *) parsetree); LockTableCommand((LockStmt *) parsetree);
break; break;
case T_ConstraintsSetStmt: case T_ConstraintsSetStmt:
set_ps_display(commandTag = "SET CONSTRAINTS"); set_ps_display(commandTag = "SET CONSTRAINTS");
CHECK_IF_ABORTED();
DeferredTriggerSetState((ConstraintsSetStmt *) parsetree); DeferredTriggerSetState((ConstraintsSetStmt *) parsetree);
break; break;
case T_CreateGroupStmt: case T_CreateGroupStmt:
set_ps_display(commandTag = "CREATE GROUP"); set_ps_display(commandTag = "CREATE GROUP");
CHECK_IF_ABORTED();
CreateGroup((CreateGroupStmt *) parsetree); CreateGroup((CreateGroupStmt *) parsetree);
break; break;
case T_AlterGroupStmt: case T_AlterGroupStmt:
set_ps_display(commandTag = "ALTER GROUP"); set_ps_display(commandTag = "ALTER GROUP");
CHECK_IF_ABORTED();
AlterGroup((AlterGroupStmt *) parsetree, "ALTER GROUP"); AlterGroup((AlterGroupStmt *) parsetree, "ALTER GROUP");
break; break;
case T_DropGroupStmt: case T_DropGroupStmt:
set_ps_display(commandTag = "DROP GROUP"); set_ps_display(commandTag = "DROP GROUP");
CHECK_IF_ABORTED();
DropGroup((DropGroupStmt *) parsetree); DropGroup((DropGroupStmt *) parsetree);
break; break;
...@@ -867,7 +796,6 @@ ProcessUtility(Node *parsetree, ...@@ -867,7 +796,6 @@ ProcessUtility(Node *parsetree,
ReindexStmt *stmt = (ReindexStmt *) parsetree; ReindexStmt *stmt = (ReindexStmt *) parsetree;
set_ps_display(commandTag = "REINDEX"); set_ps_display(commandTag = "REINDEX");
CHECK_IF_ABORTED();
switch (stmt->reindexType) switch (stmt->reindexType)
{ {
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.49 2000/10/02 04:49:27 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.50 2000/10/07 00:58:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -16,10 +16,12 @@ ...@@ -16,10 +16,12 @@
#include "postgres.h" #include "postgres.h"
#include "access/heapam.h"
#include "catalog/catalog.h" #include "catalog/catalog.h"
#include "catalog/pg_shadow.h" #include "catalog/pg_shadow.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "lib/stringinfo.h" #include "lib/stringinfo.h"
#include "miscadmin.h"
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/memutils.h" #include "utils/memutils.h"
...@@ -561,7 +563,52 @@ aclcontains(PG_FUNCTION_ARGS) ...@@ -561,7 +563,52 @@ aclcontains(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(false); PG_RETURN_BOOL(false);
} }
/* parser support routines */ /*
* ExecuteChangeACLStmt
* Called to execute the utility command type ChangeACLStmt
*/
void
ExecuteChangeACLStmt(ChangeACLStmt *stmt)
{
AclItem aclitem;
unsigned modechg;
List *i;
/* see comment in pg_type.h */
Assert(ACLITEMSIZE == sizeof(AclItem));
/* Convert string ACL spec into internal form */
aclparse(stmt->aclString, &aclitem, &modechg);
foreach(i, stmt->relNames)
{
char *relname = strVal(lfirst(i));
Relation rel;
rel = heap_openr(relname, AccessExclusiveLock);
if (rel && rel->rd_rel->relkind == RELKIND_INDEX)
elog(ERROR, "\"%s\" is an index relation",
relname);
#ifndef NO_SECURITY
if (!pg_ownercheck(GetUserId(), relname, RELNAME))
elog(ERROR, "you do not own class \"%s\"",
relname);
#endif
ChangeAcl(relname, &aclitem, modechg);
/* close rel, but keep lock until end of xact */
heap_close(rel, NoLock);
}
}
/*
* Parser support routines for ACL-related statements.
*
* XXX CAUTION: these are called from gram.y, which is not allowed to
* do any table accesses. Therefore, it is not kosher to do things
* like trying to translate usernames to user IDs here. Keep it all
* in string form until statement execution time.
*/
/* /*
* aclmakepriv * aclmakepriv
...@@ -569,9 +616,7 @@ aclcontains(PG_FUNCTION_ARGS) ...@@ -569,9 +616,7 @@ aclcontains(PG_FUNCTION_ARGS)
* and a new privilege * and a new privilege
* *
* does not add duplicate privileges * does not add duplicate privileges
*
*/ */
char * char *
aclmakepriv(char *old_privlist, char new_priv) aclmakepriv(char *old_privlist, char new_priv)
{ {
...@@ -619,12 +664,9 @@ aclmakepriv(char *old_privlist, char new_priv) ...@@ -619,12 +664,9 @@ aclmakepriv(char *old_privlist, char new_priv)
* "G" - group * "G" - group
* "U" - user * "U" - user
* *
* concatenates the two strings together with a space in between * Just concatenates the two strings together with a space in between.
* * Per above comments, we can't try to resolve a user or group name here.
* this routine is used in the parser
*
*/ */
char * char *
aclmakeuser(char *user_type, char *user) aclmakeuser(char *user_type, char *user)
{ {
...@@ -635,20 +677,16 @@ aclmakeuser(char *user_type, char *user) ...@@ -635,20 +677,16 @@ aclmakeuser(char *user_type, char *user)
return user_list; return user_list;
} }
/* /*
* makeAclStmt: * makeAclStmt:
* this is a helper routine called by the parser * create a ChangeACLStmt at parse time.
* create a ChangeAclStmt * we take in the privileges, relation_name_list, and grantee
* we take in the privilegs, relation_name_list, and grantee * as well as a single character '+' or '-' to indicate grant or revoke
* as well as a single character '+' or '-' to indicate grant or revoke
* *
* returns a new ChangeACLStmt* * We convert the information to the same external form recognized by
* * aclitemin (see aclparse), and save that string in the ChangeACLStmt.
* this routines works by creating a old-style changle acl string and * Conversion to internal form happens when the statement is executed.
* then calling aclparse;
*/ */
ChangeACLStmt * ChangeACLStmt *
makeAclStmt(char *privileges, List *rel_list, char *grantee, makeAclStmt(char *privileges, List *rel_list, char *grantee,
char grant_or_revoke) char grant_or_revoke)
...@@ -658,11 +696,6 @@ makeAclStmt(char *privileges, List *rel_list, char *grantee, ...@@ -658,11 +696,6 @@ makeAclStmt(char *privileges, List *rel_list, char *grantee,
initStringInfo(&str); initStringInfo(&str);
/* see comment in pg_type.h */
Assert(ACLITEMSIZE == sizeof(AclItem));
n->aclitem = (AclItem *) palloc(sizeof(AclItem));
/* the grantee string is "G <group_name>", "U <user_name>", or "ALL" */ /* the grantee string is "G <group_name>", "U <user_name>", or "ALL" */
if (grantee[0] == 'G') /* group permissions */ if (grantee[0] == 'G') /* group permissions */
{ {
...@@ -683,7 +716,8 @@ makeAclStmt(char *privileges, List *rel_list, char *grantee, ...@@ -683,7 +716,8 @@ makeAclStmt(char *privileges, List *rel_list, char *grantee,
grant_or_revoke, privileges); grant_or_revoke, privileges);
} }
n->relNames = rel_list; n->relNames = rel_list;
aclparse(str.data, n->aclitem, (unsigned *) &n->modechg); n->aclString = pstrdup(str.data);
pfree(str.data); pfree(str.data);
return n; return n;
} }
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: defrem.h,v 1.20 2000/08/24 03:29:09 tgl Exp $ * $Id: defrem.h,v 1.21 2000/10/07 00:58:20 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -48,7 +48,7 @@ extern void DefineType(char *name, List *parameters); ...@@ -48,7 +48,7 @@ extern void DefineType(char *name, List *parameters);
/* /*
* prototypes in remove.c * prototypes in remove.c
*/ */
extern void RemoveFunction(char *functionName, int nargs, List *argNameList); extern void RemoveFunction(char *functionName, List *argTypes);
extern void RemoveOperator(char *operatorName, extern void RemoveOperator(char *operatorName,
char *typeName1, char *typeName2); char *typeName1, char *typeName2);
extern void RemoveType(char *typeName); extern void RemoveType(char *typeName);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: parsenodes.h,v 1.115 2000/10/05 19:11:36 tgl Exp $ * $Id: parsenodes.h,v 1.116 2000/10/07 00:58:21 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -114,9 +114,8 @@ typedef struct AlterTableStmt ...@@ -114,9 +114,8 @@ typedef struct AlterTableStmt
typedef struct ChangeACLStmt typedef struct ChangeACLStmt
{ {
NodeTag type; NodeTag type;
struct AclItem *aclitem;
unsigned modechg;
List *relNames; List *relNames;
char *aclString;
} ChangeACLStmt; } ChangeACLStmt;
/* ---------------------- /* ----------------------
...@@ -488,10 +487,8 @@ typedef struct ProcedureStmt ...@@ -488,10 +487,8 @@ typedef struct ProcedureStmt
{ {
NodeTag type; NodeTag type;
char *funcname; /* name of function to create */ char *funcname; /* name of function to create */
List *defArgs; /* list of definitions a list of strings List *argTypes; /* list of argument types (TypeName nodes) */
* (as Value *) */ Node *returnType; /* the return type (a TypeName node) */
Node *returnType; /* the return type (as a string or a
* TypeName (ie.setof) */
List *withClause; /* a list of DefElem */ List *withClause; /* a list of DefElem */
List *as; /* definition of function body */ List *as; /* definition of function body */
char *language; /* C, SQL, etc */ char *language; /* C, SQL, etc */
...@@ -505,7 +502,7 @@ typedef struct RemoveAggrStmt ...@@ -505,7 +502,7 @@ typedef struct RemoveAggrStmt
{ {
NodeTag type; NodeTag type;
char *aggname; /* aggregate to drop */ char *aggname; /* aggregate to drop */
char *aggtype; /* for this type */ Node *aggtype; /* TypeName for input datatype, or NULL */
} RemoveAggrStmt; } RemoveAggrStmt;
/* ---------------------- /* ----------------------
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: analyze.h,v 1.11 2000/10/05 19:11:38 tgl Exp $ * $Id: analyze.h,v 1.12 2000/10/07 00:58:21 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -15,6 +15,6 @@ ...@@ -15,6 +15,6 @@
#include "parser/parse_node.h" #include "parser/parse_node.h"
extern List *parse_analyze(List *pl, ParseState *parentParseState); extern List *parse_analyze(Node *parseTree, ParseState *parentParseState);
#endif /* ANALYZE_H */ #endif /* ANALYZE_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: parse_expr.h,v 1.19 2000/06/15 03:32:55 momjian Exp $ * $Id: parse_expr.h,v 1.20 2000/10/07 00:58:21 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -26,5 +26,6 @@ extern Oid exprType(Node *expr); ...@@ -26,5 +26,6 @@ extern Oid exprType(Node *expr);
extern int32 exprTypmod(Node *expr); extern int32 exprTypmod(Node *expr);
extern bool exprIsLengthCoercion(Node *expr, int32 *coercedTypmod); extern bool exprIsLengthCoercion(Node *expr, int32 *coercedTypmod);
extern void parse_expr_init(void); extern void parse_expr_init(void);
extern char *TypeNameToInternalName(TypeName *typename);
#endif /* PARSE_EXPR_H */ #endif /* PARSE_EXPR_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: tcopprot.h,v 1.34 2000/09/06 14:15:28 petere Exp $ * $Id: tcopprot.h,v 1.35 2000/10/07 00:58:23 tgl Exp $
* *
* OLD COMMENTS * OLD COMMENTS
* This file was created so that other c files could get the two * This file was created so that other c files could get the two
...@@ -35,9 +35,9 @@ extern bool ShowPortNumber; ...@@ -35,9 +35,9 @@ extern bool ShowPortNumber;
extern List *pg_parse_and_rewrite(char *query_string, extern List *pg_parse_and_rewrite(char *query_string,
Oid *typev, int nargs); Oid *typev, int nargs);
extern Plan *pg_plan_query(Query *querytree); extern Plan *pg_plan_query(Query *querytree);
extern void pg_exec_query_dest(char *query_string, extern void pg_exec_query_string(char *query_string,
CommandDest dest, CommandDest dest,
MemoryContext parse_context); MemoryContext parse_context);
#endif /* BOOTSTRAP_INCLUDE */ #endif /* BOOTSTRAP_INCLUDE */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: acl.h,v 1.28 2000/10/02 04:49:27 tgl Exp $ * $Id: acl.h,v 1.29 2000/10/07 00:58:23 tgl Exp $
* *
* NOTES * NOTES
* For backward-compatibility purposes we have to allow there * For backward-compatibility purposes we have to allow there
...@@ -167,12 +167,15 @@ extern char *aclcheck_error_strings[]; ...@@ -167,12 +167,15 @@ extern char *aclcheck_error_strings[];
/*#define ACLDEBUG_TRACE*/ /*#define ACLDEBUG_TRACE*/
/* /*
* routines used internally (parser, etc.) * routines used internally
*/ */
extern Acl *acldefault(char *relname, AclId ownerid); extern Acl *acldefault(char *relname, AclId ownerid);
extern Acl *aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg); extern Acl *aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg);
/*
* routines used by the parser
*/
extern char *aclmakepriv(char *old_privlist, char new_priv); extern char *aclmakepriv(char *old_privlist, char new_priv);
extern char *aclmakeuser(char *user_type, char *user); extern char *aclmakeuser(char *user_type, char *user);
extern ChangeACLStmt *makeAclStmt(char *privs, List *rel_list, char *grantee, extern ChangeACLStmt *makeAclStmt(char *privs, List *rel_list, char *grantee,
...@@ -187,6 +190,7 @@ extern Datum aclitemout(PG_FUNCTION_ARGS); ...@@ -187,6 +190,7 @@ extern Datum aclitemout(PG_FUNCTION_ARGS);
extern Datum aclinsert(PG_FUNCTION_ARGS); extern Datum aclinsert(PG_FUNCTION_ARGS);
extern Datum aclremove(PG_FUNCTION_ARGS); extern Datum aclremove(PG_FUNCTION_ARGS);
extern Datum aclcontains(PG_FUNCTION_ARGS); extern Datum aclcontains(PG_FUNCTION_ARGS);
extern void ExecuteChangeACLStmt(ChangeACLStmt *stmt);
/* /*
* prototypes for functions in aclchk.c * prototypes for functions in aclchk.c
......
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