aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/pg_proc.c28
-rw-r--r--src/backend/commands/comment.c68
-rw-r--r--src/backend/commands/define.c226
-rw-r--r--src/backend/commands/remove.c38
-rw-r--r--src/backend/nodes/copyfuncs.c14
-rw-r--r--src/backend/nodes/equalfuncs.c24
-rw-r--r--src/backend/parser/analyze.c91
-rw-r--r--src/backend/parser/gram.y95
-rw-r--r--src/backend/parser/parse_clause.c4
-rw-r--r--src/backend/parser/parse_expr.c56
-rw-r--r--src/backend/parser/parser.c127
-rw-r--r--src/backend/tcop/postgres.c491
-rw-r--r--src/backend/tcop/utility.c132
-rw-r--r--src/backend/utils/adt/acl.c84
-rw-r--r--src/include/commands/defrem.h4
-rw-r--r--src/include/nodes/parsenodes.h13
-rw-r--r--src/include/parser/analyze.h4
-rw-r--r--src/include/parser/parse_expr.h3
-rw-r--r--src/include/tcop/tcopprot.h8
-rw-r--r--src/include/utils/acl.h8
20 files changed, 768 insertions, 750 deletions
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 98d0cdca0c4..26861047b24 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
*
*
* 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,
MemSet(typev, 0, FUNC_MAX_ARGS * sizeof(Oid));
foreach(x, argList)
{
- Value *t = lfirst(x);
+ TypeName *t = (TypeName *) lfirst(x);
+ char *typnam = TypeNameToInternalName(t);
if (parameterCount >= FUNC_MAX_ARGS)
elog(ERROR, "Procedures cannot take more than %d arguments",
FUNC_MAX_ARGS);
- if (strcmp(strVal(t), "opaque") == 0)
+ if (strcmp(typnam, "opaque") == 0)
{
if (languageObjectId == SQLlanguageId)
elog(ERROR, "ProcedureCreate: sql functions cannot take type \"opaque\"");
- toid = 0;
+ toid = InvalidOid;
}
else
{
- toid = TypeGet(strVal(t), &defined);
+ toid = TypeGet(typnam, &defined);
if (!OidIsValid(toid))
- {
elog(ERROR, "ProcedureCreate: arg type '%s' is not defined",
- strVal(t));
- }
-
+ typnam);
if (!defined)
- {
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;
}
@@ -178,7 +177,7 @@ ProcedureCreate(char *procedureName,
{
if (languageObjectId == SQLlanguageId)
elog(ERROR, "ProcedureCreate: sql functions cannot return type \"opaque\"");
- typeObjectId = 0;
+ typeObjectId = InvalidOid;
}
else
{
@@ -194,10 +193,8 @@ ProcedureCreate(char *procedureName,
returnTypeName);
}
else if (!defined)
- {
elog(NOTICE, "ProcedureCreate: return type '%s' is only a shell",
returnTypeName);
- }
}
/*
@@ -212,7 +209,6 @@ ProcedureCreate(char *procedureName,
elog(ERROR, "method %s already an attribute of type %s",
procedureName, strVal(lfirst(argList)));
-
/*
* 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
diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c
index 51832bc2c7b..e7b13a80788 100644
--- a/src/backend/commands/comment.c
+++ b/src/backend/commands/comment.c
@@ -25,6 +25,8 @@
#include "commands/comment.h"
#include "miscadmin.h"
#include "parser/parse.h"
+#include "parser/parse_expr.h"
+#include "parser/parse_func.h"
#include "rewrite/rewriteRemove.h"
#include "utils/acl.h"
#include "utils/fmgroids.h"
@@ -46,7 +48,7 @@ static void CommentAttribute(char *relation, char *attrib, char *comment);
static void CommentDatabase(char *database, char *comment);
static void CommentRewrite(char *rule, 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 CommentOperator(char *opname, List *arguments, char *comment);
static void CommentTrigger(char *trigger, char *relation, char *comments);
@@ -92,7 +94,7 @@ CommentObject(int objtype, char *objname, char *objproperty,
CommentType(objname, comment);
break;
case (AGGREGATE):
- CommentAggregate(objname, objproperty, comment);
+ CommentAggregate(objname, objlist, comment);
break;
case (FUNCTION):
CommentProc(objname, objlist, comment);
@@ -544,9 +546,10 @@ CommentType(char *type, char *comment)
*/
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;
Oid baseoid,
oid;
@@ -554,11 +557,12 @@ CommentAggregate(char *aggregate, char *argument, char *comment)
/*** 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))
- elog(ERROR, "aggregate type '%s' does not exist", argument);
+ elog(ERROR, "type '%s' does not exist", aggtypename);
}
else
baseoid = 0;
@@ -568,10 +572,10 @@ CommentAggregate(char *aggregate, char *argument, char *comment)
#ifndef NO_SECURITY
if (!pg_aggr_ownercheck(GetUserId(), aggregate, baseoid))
{
- if (argument)
+ if (aggtypename)
{
elog(ERROR, "you are not permitted to comment on aggregate '%s' %s '%s'",
- aggregate, "with type", argument);
+ aggregate, "with type", aggtypename);
}
else
{
@@ -587,10 +591,10 @@ CommentAggregate(char *aggregate, char *argument, char *comment)
ObjectIdGetDatum(baseoid), 0, 0);
if (!HeapTupleIsValid(aggtuple))
{
- if (argument)
+ if (aggtypename)
{
elog(ERROR, "aggregate type '%s' does not exist for aggregate '%s'",
- argument, aggregate);
+ aggtypename, aggregate);
}
else
elog(ERROR, "aggregate '%s' does not exist", aggregate);
@@ -622,7 +626,6 @@ CommentProc(char *function, List *arguments, char *comment)
functuple;
Oid oid,
argoids[FUNC_MAX_ARGS];
- char *argument;
int i,
argcount;
@@ -635,18 +638,20 @@ CommentProc(char *function, List *arguments, char *comment)
FUNC_MAX_ARGS);
for (i = 0; i < argcount; i++)
{
- argument = strVal(lfirst(arguments));
+ TypeName *t = (TypeName *) lfirst(arguments);
+ char *typnam = TypeNameToInternalName(t);
+
arguments = lnext(arguments);
- if (strcmp(argument, "opaque") == 0)
- argoids[i] = 0;
+
+ if (strcmp(typnam, "opaque") == 0)
+ argoids[i] = InvalidOid;
else
{
argtuple = SearchSysCacheTuple(TYPENAME,
- PointerGetDatum(argument),
+ PointerGetDatum(typnam),
0, 0, 0);
if (!HeapTupleIsValid(argtuple))
- elog(ERROR, "function argument type '%s' does not exist",
- argument);
+ elog(ERROR, "CommentProc: type '%s' not found", typnam);
argoids[i] = argtuple->t_data->t_oid;
}
}
@@ -664,10 +669,9 @@ CommentProc(char *function, List *arguments, char *comment)
functuple = SearchSysCacheTuple(PROCNAME, PointerGetDatum(function),
Int32GetDatum(argcount),
PointerGetDatum(argoids), 0);
-
if (!HeapTupleIsValid(functuple))
- elog(ERROR, "function '%s' with the supplied %s does not exist",
- function, "argument list");
+ func_error("CommentProc", function, argcount, argoids, NULL);
+
oid = functuple->t_data->t_oid;
/*** Call CreateComments() to create/drop the comments ***/
@@ -691,23 +695,24 @@ CommentProc(char *function, List *arguments, char *comment)
static void
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;
HeapTuple optuple;
Oid oid,
leftoid = InvalidOid,
rightoid = InvalidOid;
bool defined;
- char oprtype = 0,
- *lefttype = NULL,
- *righttype = NULL;
/*** Initialize our left and right argument types ***/
- if (lfirst(arguments) != NULL)
- lefttype = strVal(lfirst(arguments));
- if (lsecond(arguments) != NULL)
- righttype = strVal(lsecond(arguments));
+ if (typenode1 != NULL)
+ lefttype = TypeNameToInternalName(typenode1);
+ if (typenode2 != NULL)
+ righttype = TypeNameToInternalName(typenode2);
/*** Attempt to fetch the left oid, if specified ***/
@@ -732,9 +737,9 @@ CommentOperator(char *opername, List *arguments, char *comment)
if (OidIsValid(leftoid) && (OidIsValid(rightoid)))
oprtype = 'b';
else if (OidIsValid(leftoid))
- oprtype = 'l';
- else if (OidIsValid(rightoid))
oprtype = 'r';
+ else if (OidIsValid(rightoid))
+ oprtype = 'l';
else
elog(ERROR, "operator '%s' is of an illegal type'", opername);
@@ -769,7 +774,6 @@ CommentOperator(char *opername, List *arguments, char *comment)
/*** Call CreateComments() to create/drop the comments ***/
CreateComments(oid, comment);
-
}
/*------------------------------------------------------------------
diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c
index cf31e5edb1f..a33d155db9f 100644
--- a/src/backend/commands/define.c
+++ b/src/backend/commands/define.c
@@ -10,7 +10,7 @@
*
*
* 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
* The "DefineFoo" routines take the parse tree and pick out the
@@ -49,6 +49,7 @@
#include "commands/defrem.h"
#include "fmgr.h"
#include "optimizer/cost.h"
+#include "parser/parse_expr.h"
#include "tcop/dest.h"
#include "utils/builtins.h"
#include "utils/syscache.h"
@@ -83,27 +84,15 @@ case_translate_language_name(const char *input, char *output)
static void
-compute_return_type(const Node *returnType,
+compute_return_type(TypeName *returnType,
char **prorettype_p, bool *returnsSet_p)
{
/*---------------------------------------------------------------------------
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)
- {
- /* 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;
- }
+ *prorettype_p = TypeNameToInternalName(returnType);
+ *returnsSet_p = returnType->setof;
}
@@ -214,7 +203,7 @@ interpret_AS_clause(const char *languageName, const List *as,
*prosrc_str_p = strVal(lfirst(as));
*probin_str_p = "-";
- if (lnext(as) != NULL)
+ if (lnext(as) != NIL)
elog(ERROR, "CREATE FUNCTION: only one AS item needed for %s language",
languageName);
}
@@ -231,27 +220,23 @@ void
CreateFunction(ProcedureStmt *stmt, CommandDest dest)
{
char *probin_str;
-
/* pathname of executable file that executes this function, if any */
- char *prosrc_str;
+ char *prosrc_str;
/* SQL that executes this function, if any */
- char *prorettype;
+ char *prorettype;
/* 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",
* "internal", "newinternal", "sql", etc.
*/
bool returnsSet;
-
/* The function returns a set of values, as opposed to a singleton. */
- bool lanisPL = false;
-
/*
* The following are optional user-supplied attributes of the
* function.
@@ -263,8 +248,12 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
bool canCache,
isStrict;
+ /* Convert language name to canonical case */
case_translate_language_name(stmt->language, languageName);
+ /*
+ * Apply appropriate security checks depending on language.
+ */
if (strcmp(languageName, "C") == 0 ||
strcmp(languageName, "newC") == 0 ||
strcmp(languageName, "internal") == 0 ||
@@ -301,7 +290,7 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
/* Check that this language is a PL */
languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
- if (!(languageStruct->lanispl))
+ if (!languageStruct->lanispl)
elog(ERROR,
"Language '%s' isn't defined as PL", languageName);
@@ -316,11 +305,15 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
"language.",
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,
&byte_pct, &perbyte_cpu, &percall_cpu,
@@ -345,7 +338,7 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
perbyte_cpu,
percall_cpu,
outin_ratio,
- stmt->defArgs,
+ stmt->argTypes,
dest);
}
@@ -389,49 +382,43 @@ DefineOperator(char *oprName,
{
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);
- if (typeName1 == NULL)
- elog(ERROR, "type for leftarg is malformed.");
+ if (IsA(defel->arg, TypeName)
+ && ((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);
- if (typeName2 == NULL)
- elog(ERROR, "type for rightarg is malformed.");
+ if (IsA(defel->arg, TypeName)
+ && ((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);
- else if (!strcasecmp(defel->defname, "precedence"))
+ else if (strcasecmp(defel->defname, "precedence") == 0)
{
/* NOT IMPLEMENTED (never worked in v4.2) */
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) */
elog(NOTICE, "CREATE OPERATOR: associativity not implemented");
}
- else if (!strcasecmp(defel->defname, "commutator"))
+ else if (strcasecmp(defel->defname, "commutator") == 0)
commutatorName = defGetString(defel);
- else if (!strcasecmp(defel->defname, "negator"))
+ else if (strcasecmp(defel->defname, "negator") == 0)
negatorName = defGetString(defel);
- else if (!strcasecmp(defel->defname, "restrict"))
+ else if (strcasecmp(defel->defname, "restrict") == 0)
restrictionName = defGetString(defel);
- else if (!strcasecmp(defel->defname, "join"))
+ else if (strcasecmp(defel->defname, "join") == 0)
joinName = defGetString(defel);
- else if (!strcasecmp(defel->defname, "hashes"))
+ else if (strcasecmp(defel->defname, "hashes") == 0)
canHash = TRUE;
- else if (!strcasecmp(defel->defname, "sort1"))
+ else if (strcasecmp(defel->defname, "sort1") == 0)
{
/* ----------------
* XXX ( ... [ , sort1 = oprname ] [ , sort2 = oprname ] ... )
@@ -441,7 +428,7 @@ DefineOperator(char *oprName,
*/
sortName1 = defGetString(defel);
}
- else if (!strcasecmp(defel->defname, "sort2"))
+ else if (strcasecmp(defel->defname, "sort2") == 0)
sortName2 = defGetString(defel);
else
{
@@ -562,72 +549,73 @@ DefineType(char *typeName, List *parameters)
char delimiter = DEFAULT_TYPDELIM;
char *shadow_type;
List *pl;
- char alignment = 'i';/* default alignment */
- char storage = 'p'; /* default storage in TOAST */
+ char alignment = 'i'; /* default alignment */
+ char storage = 'p'; /* default storage in TOAST */
/*
- * Type names can only be 15 characters long, so that the shadow type
- * can be created using the 16th character as necessary.
+ * Type names must be one character shorter than other names,
+ * 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",
- NAMEDATALEN - 1);
+ NAMEDATALEN - 2);
}
foreach(pl, parameters)
{
DefElem *defel = (DefElem *) lfirst(pl);
- if (!strcasecmp(defel->defname, "internallength"))
+ if (strcasecmp(defel->defname, "internallength") == 0)
internalLength = defGetTypeLength(defel);
- else if (!strcasecmp(defel->defname, "externallength"))
+ else if (strcasecmp(defel->defname, "externallength") == 0)
externalLength = defGetTypeLength(defel);
- else if (!strcasecmp(defel->defname, "input"))
+ else if (strcasecmp(defel->defname, "input") == 0)
inputName = defGetString(defel);
- else if (!strcasecmp(defel->defname, "output"))
+ else if (strcasecmp(defel->defname, "output") == 0)
outputName = defGetString(defel);
- else if (!strcasecmp(defel->defname, "send"))
+ else if (strcasecmp(defel->defname, "send") == 0)
sendName = defGetString(defel);
- else if (!strcasecmp(defel->defname, "delimiter"))
+ else if (strcasecmp(defel->defname, "delimiter") == 0)
{
char *p = defGetString(defel);
delimiter = p[0];
}
- else if (!strcasecmp(defel->defname, "receive"))
+ else if (strcasecmp(defel->defname, "receive") == 0)
receiveName = defGetString(defel);
- else if (!strcasecmp(defel->defname, "element"))
+ else if (strcasecmp(defel->defname, "element") == 0)
elemName = defGetString(defel);
- else if (!strcasecmp(defel->defname, "default"))
+ else if (strcasecmp(defel->defname, "default") == 0)
defaultValue = defGetString(defel);
- else if (!strcasecmp(defel->defname, "passedbyvalue"))
+ else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
byValue = true;
- else if (!strcasecmp(defel->defname, "alignment"))
+ else if (strcasecmp(defel->defname, "alignment") == 0)
{
char *a = defGetString(defel);
- if (!strcasecmp(a, "double"))
+ if (strcasecmp(a, "double") == 0)
alignment = 'd';
- else if (!strcasecmp(a, "int4"))
+ else if (strcasecmp(a, "int4") == 0)
alignment = 'i';
else
{
- elog(ERROR, "DefineType: \"%s\" alignment not recognized",
+ elog(ERROR, "DefineType: \"%s\" alignment not recognized",
a);
}
}
- else if (!strcasecmp(defel->defname, "storage"))
+ else if (strcasecmp(defel->defname, "storage") == 0)
{
char *a = defGetString(defel);
- if (!strcasecmp(a, "plain"))
+ if (strcasecmp(a, "plain") == 0)
storage = 'p';
- else if (!strcasecmp(a, "external"))
+ else if (strcasecmp(a, "external") == 0)
storage = 'e';
- else if (!strcasecmp(a, "extended"))
+ else if (strcasecmp(a, "extended") == 0)
storage = 'x';
- else if (!strcasecmp(a, "main"))
+ else if (strcasecmp(a, "main") == 0)
storage = 'm';
else
{
@@ -674,8 +662,8 @@ DefineType(char *typeName, List *parameters)
storage); /* TOAST strategy */
/* ----------------
- * When we create a true type (as opposed to a complex type)
- * we need to have an shadow array entry for it in pg_type as well.
+ * When we create a base type (as opposed to a complex type)
+ * we need to have an array entry for it in pg_type as well.
* ----------------
*/
shadow_type = makeArrayTypeName(typeName);
@@ -702,19 +690,32 @@ DefineType(char *typeName, List *parameters)
static char *
defGetString(DefElem *def)
{
- char *string;
-
- if (nodeTag(def->arg) == T_String)
- string = strVal(def->arg);
- else if (nodeTag(def->arg) == T_TypeName)
- string = ((TypeName *) def->arg)->name;
- else
- string = NULL;
-#if 0
- elog(ERROR, "Define: \"%s\" = what?", def->defname);
-#endif
+ if (def->arg == NULL)
+ elog(ERROR, "Define: \"%s\" requires a parameter",
+ def->defname);
+ switch (nodeTag(def->arg))
+ {
+ case T_Integer:
+ {
+ char *str = palloc(32);
- 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
@@ -739,15 +740,32 @@ defGetNumeric(DefElem *def)
static int
defGetTypeLength(DefElem *def)
{
- if (nodeTag(def->arg) == T_Integer)
- return intVal(def->arg);
- else if (nodeTag(def->arg) == T_String &&
- !strcasecmp(strVal(def->arg), "variable"))
- return -1; /* variable length */
- else if (nodeTag(def->arg) == T_TypeName &&
- !strcasecmp(((TypeName *)(def->arg))->name, "variable"))
- return -1;
-
- elog(ERROR, "Define: \"%s\" = what?", def->defname);
- return -1;
+ if (def->arg == NULL)
+ elog(ERROR, "Define: \"%s\" requires a parameter",
+ def->defname);
+ switch (nodeTag(def->arg))
+ {
+ case T_Integer:
+ return intVal(def->arg);
+ case T_Float:
+ elog(ERROR, "Define: \"%s\" requires an integral value",
+ def->defname);
+ 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 */
}
diff --git a/src/backend/commands/remove.c b/src/backend/commands/remove.c
index c5b7968e5fd..6da32297f61 100644
--- a/src/backend/commands/remove.c
+++ b/src/backend/commands/remove.c
@@ -8,7 +8,7 @@
*
*
* 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 @@
#include "commands/comment.h"
#include "commands/defrem.h"
#include "miscadmin.h"
+#include "parser/parse_expr.h"
#include "parser/parse_func.h"
#include "utils/acl.h"
#include "utils/syscache.h"
@@ -39,8 +40,8 @@
*/
void
RemoveOperator(char *operatorName, /* operator name */
- char *typeName1, /* first type name */
- char *typeName2) /* optional second type name */
+ char *typeName1, /* left argument type name */
+ char *typeName2) /* right argument type name */
{
Relation relation;
HeapTuple tup;
@@ -53,28 +54,22 @@ RemoveOperator(char *operatorName, /* operator name */
{
typeId1 = TypeGet(typeName1, &defined);
if (!OidIsValid(typeId1))
- {
elog(ERROR, "RemoveOperator: type '%s' does not exist", typeName1);
- return;
- }
}
if (typeName2)
{
typeId2 = TypeGet(typeName2, &defined);
if (!OidIsValid(typeId2))
- {
elog(ERROR, "RemoveOperator: type '%s' does not exist", typeName2);
- return;
- }
}
if (OidIsValid(typeId1) && OidIsValid(typeId2))
oprtype = 'b';
else if (OidIsValid(typeId1))
- oprtype = 'l';
- else
oprtype = 'r';
+ else
+ oprtype = 'l';
relation = heap_openr(OperatorRelationName, RowExclusiveLock);
@@ -94,7 +89,6 @@ RemoveOperator(char *operatorName, /* operator name */
operatorName);
#endif
-
/*** Delete any comments associated with this operator ***/
DeleteComments(tup->t_data->t_oid);
@@ -308,13 +302,12 @@ RemoveType(char *typeName) /* type name to be removed */
*/
void
RemoveFunction(char *functionName, /* function name to be removed */
- int nargs,
- List *argNameList /* list of TypeNames */ )
+ List *argTypes) /* list of TypeName nodes */
{
+ int nargs = length(argTypes);
Relation relation;
HeapTuple tup;
Oid argList[FUNC_MAX_ARGS];
- char *typename;
int i;
if (nargs > FUNC_MAX_ARGS)
@@ -323,19 +316,20 @@ RemoveFunction(char *functionName, /* function name to be removed */
MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
for (i = 0; i < nargs; i++)
{
- typename = strVal(lfirst(argNameList));
- argNameList = lnext(argNameList);
+ TypeName *t = (TypeName *) lfirst(argTypes);
+ char *typnam = TypeNameToInternalName(t);
- if (strcmp(typename, "opaque") == 0)
- argList[i] = 0;
+ argTypes = lnext(argTypes);
+
+ if (strcmp(typnam, "opaque") == 0)
+ argList[i] = InvalidOid;
else
{
tup = SearchSysCacheTuple(TYPENAME,
- PointerGetDatum(typename),
+ PointerGetDatum(typnam),
0, 0, 0);
-
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;
}
}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 1a0f4623978..e768d0bd796 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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)
{
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);
+ if (from->aclString)
+ newnode->aclString = pstrdup(from->aclString);
return newnode;
}
@@ -2033,7 +2029,7 @@ _copyProcedureStmt(ProcedureStmt *from)
ProcedureStmt *newnode = makeNode(ProcedureStmt);
newnode->funcname = pstrdup(from->funcname);
- Node_Copy(from, newnode, defArgs);
+ Node_Copy(from, newnode, argTypes);
Node_Copy(from, newnode, returnType);
Node_Copy(from, newnode, withClause);
Node_Copy(from, newnode, as);
@@ -2048,7 +2044,7 @@ _copyRemoveAggrStmt(RemoveAggrStmt *from)
RemoveAggrStmt *newnode = makeNode(RemoveAggrStmt);
newnode->aggname = pstrdup(from->aggname);
- newnode->aggtype = pstrdup(from->aggtype);
+ Node_Copy(from, newnode, aggtype);
return newnode;
}
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index ab8779cb375..d5b2ff4607e 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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)
static bool
_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))
return false;
+ if (!equalstr(a->aclString, b->aclString))
+ return false;
return true;
}
@@ -956,7 +942,7 @@ _equalProcedureStmt(ProcedureStmt *a, ProcedureStmt *b)
{
if (!equalstr(a->funcname, b->funcname))
return false;
- if (!equal(a->defArgs, b->defArgs))
+ if (!equal(a->argTypes, b->argTypes))
return false;
if (!equal(a->returnType, b->returnType))
return false;
@@ -975,7 +961,7 @@ _equalRemoveAggrStmt(RemoveAggrStmt *a, RemoveAggrStmt *b)
{
if (!equalstr(a->aggname, b->aggname))
return false;
- if (!equalstr(a->aggtype, b->aggtype))
+ if (!equal(a->aggtype, b->aggtype))
return false;
return true;
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index ffedca05ed9..ae1f027e47c 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* 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;
/*
* parse_analyze -
- * analyze a list of parse trees and transform them if necessary.
- *
- * Returns a list of transformed parse trees. Optimizable statements are
- * all transformed to Query while the rest stays the same.
+ * analyze a raw parse tree and transform it to Query form.
*
+ * 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 *
-parse_analyze(List *pl, ParseState *parentParseState)
+parse_analyze(Node *parseTree, ParseState *parentParseState)
{
List *result = NIL;
+ ParseState *pstate = make_parsestate(parentParseState);
+ Query *query;
- while (pl != NIL)
- {
- ParseState *pstate = make_parsestate(parentParseState);
- Query *parsetree;
+ extras_before = extras_after = NIL;
- 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);
+ extras_before = lnext(extras_before);
+ }
- while (extras_before != NIL)
- {
- result = lappend(result,
- transformStmt(pstate, lfirst(extras_before)));
- release_pstate_resources(pstate);
- extras_before = lnext(extras_before);
- }
-
- result = lappend(result, parsetree);
+ result = lappend(result, query);
- while (extras_after != NIL)
- {
- result = lappend(result,
- transformStmt(pstate, lfirst(extras_after)));
- release_pstate_resources(pstate);
- extras_after = lnext(extras_after);
- }
-
- pfree(pstate);
- pl = lnext(pl);
+ while (extras_after != NIL)
+ {
+ result = lappend(result,
+ transformStmt(pstate, lfirst(extras_after)));
+ release_pstate_resources(pstate);
+ extras_after = lnext(extras_after);
}
+ pfree(pstate);
+
return result;
}
@@ -126,8 +122,7 @@ release_pstate_resources(ParseState *pstate)
/*
* transformStmt -
- * transform a Parse tree. If it is an optimizable statement, turn it
- * into a Query tree.
+ * transform a Parse tree into a Query tree.
*/
static Query *
transformStmt(ParseState *pstate, Node *parseTree)
@@ -353,7 +348,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
* from a stand-alone SELECT. (Indeed, Postgres up through 6.5 had
* bugs of just that nature...)
*/
- selectList = parse_analyze(makeList1(stmt->selectStmt), pstate);
+ selectList = parse_analyze(stmt->selectStmt, pstate);
Assert(length(selectList) == 1);
selectQuery = (Query *) lfirst(selectList);
@@ -1933,7 +1928,7 @@ transformSetOperationTree(ParseState *pstate, Node *node)
*/
save_rtable = pstate->p_rtable;
pstate->p_rtable = NIL;
- selectList = parse_analyze(makeList1(stmt), pstate);
+ selectList = parse_analyze((Node *) stmt, pstate);
pstate->p_rtable = save_rtable;
Assert(length(selectList) == 1);
@@ -2752,6 +2747,7 @@ makeFromExpr(List *fromlist, Node *quals)
static void
transformColumnType(ParseState *pstate, ColumnDef *column)
{
+ TypeName *typename = column->typename;
/*
* If the column doesn't have an explicitly specified typmod, check to
@@ -2760,18 +2756,33 @@ transformColumnType(ParseState *pstate, ColumnDef *column)
* Note that we deliberately do NOT look at array or set information
* 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)" */
- column->typename->typmod = VARHDRSZ + 1;
+ typename->typmod = VARHDRSZ + 1;
break;
case NUMERICOID:
- column->typename->typmod = VARHDRSZ +
+ typename->typmod = VARHDRSZ +
((NUMERIC_DEFAULT_PRECISION << 16) | NUMERIC_DEFAULT_SCALE);
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;
+ }
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index f13b942abd8..a596bd6aba1 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* 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
* AUTHOR DATE MAJOR EVENT
@@ -59,7 +59,6 @@
extern List *parsetree; /* final parse result is delivered here */
-static char saved_relname[NAMEDATALEN]; /* need this for complex attributes */
static bool QueryIsRule = FALSE;
static Oid *param_type_info;
static int pfunc_num_args;
@@ -161,7 +160,7 @@ static void doNegateFloat(Value *v);
%type <str> relation_name, copy_file_name, copy_delimiter, copy_null, def_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,
all_Op, MathOp, opt_name,
@@ -183,7 +182,7 @@ static void doNegateFloat(Value *v);
def_list, opt_indirection, group_clause, TriggerFuncArgs,
opt_select_limit
-%type <typnam> func_arg, func_return
+%type <typnam> func_arg, func_return, aggr_argtype
%type <boolean> opt_arg, TriggerForOpt, TriggerForType, OptTemp
@@ -1541,7 +1540,7 @@ CreateAsStmt: CREATE OptTemp TABLE relation_name OptUnder OptCreateAs AS Select
n->istemp = $2;
n->into = $4;
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)
mapTargetColumns($6, n->targetList);
$$ = $8;
@@ -2009,8 +2008,8 @@ CommentStmt: COMMENT ON comment_type name IS comment_text
CommentStmt *n = makeNode(CommentStmt);
n->objtype = $3;
n->objname = $4;
- n->objproperty = $5;
- n->objlist = NULL;
+ n->objproperty = NULL;
+ n->objlist = makeList1($5);
n->comment = $7;
$$ = (Node *) n;
}
@@ -2309,7 +2308,7 @@ grantee: PUBLIC
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*/
;
@@ -2471,7 +2470,7 @@ ProcedureStmt: CREATE FUNCTION func_name func_args
{
ProcedureStmt *n = makeNode(ProcedureStmt);
n->funcname = $3;
- n->defArgs = $4;
+ n->argTypes = $4;
n->returnType = (Node *)$6;
n->withClause = $11;
n->as = $8;
@@ -2488,29 +2487,12 @@ func_args: '(' func_args_list ')' { $$ = $2; }
;
func_args_list: func_arg
- { $$ = makeList1(makeString($1->name)); }
+ { $$ = makeList1($1); }
| 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,
- * 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
+func_arg: opt_arg Typename
{
/* We can catch over-specified arguments here if we want to,
* but for now better to silently swallow typmod, etc.
@@ -2518,7 +2500,7 @@ func_arg: opt_arg SimpleTypename
*/
$$ = $2;
}
- | SimpleTypename
+ | Typename
{
$$ = $1;
}
@@ -2546,7 +2528,7 @@ func_as: Sconst
{ $$ = makeList2(makeString($1), makeString($3)); }
;
-func_return: SimpleTypename
+func_return: Typename
{
/* We can catch over-specified arguments here if we want to,
* but for now better to silently swallow typmod, etc.
@@ -2554,11 +2536,6 @@ func_return: SimpleTypename
*/
$$ = $1;
}
- | SETOF SimpleTypename
- {
- $$ = $2;
- $$->setof = TRUE;
- }
;
@@ -2599,12 +2576,12 @@ RemoveAggrStmt: DROP AGGREGATE name aggr_argtype
{
RemoveAggrStmt *n = makeNode(RemoveAggrStmt);
n->aggname = $3;
- n->aggtype = $4;
+ n->aggtype = (Node *) $4;
$$ = (Node *)n;
}
;
-aggr_argtype: name { $$ = $1; }
+aggr_argtype: Typename { $$ = $1; }
| '*' { $$ = NULL; }
;
@@ -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)");
}
- | name ',' name
- { $$ = makeList2(makeString($1), makeString($3)); }
- | NONE ',' name /* left unary */
- { $$ = makeList2(NULL, makeString($3)); }
- | name ',' NONE /* right unary */
- { $$ = makeList2(makeString($1), NULL); }
+ | Typename ',' Typename
+ { $$ = makeList2($1, $3); }
+ | NONE ',' Typename /* left unary */
+ { $$ = makeList2(NULL, $3); }
+ | Typename ',' NONE /* right unary */
+ { $$ = makeList2($1, NULL); }
;
@@ -3832,23 +3809,6 @@ Typename: SimpleTypename opt_array_bounds
{
$$ = $1;
$$->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
{
@@ -3909,7 +3869,7 @@ Numeric: FLOAT opt_float
| DECIMAL opt_decimal
{
$$ = makeNode(TypeName);
- $$->name = xlateSqlType("numeric");
+ $$->name = xlateSqlType("decimal");
$$->typmod = $2;
}
| DEC opt_decimal
@@ -5245,17 +5205,15 @@ update_target_el: ColId opt_indirection '=' a_expr
relation_name: SpecialRuleRelation
{
$$ = $1;
- StrNCpy(saved_relname, $1, NAMEDATALEN);
}
| ColId
{
/* disallow refs to variable system tables */
if (strcmp(LogRelationName, $1) == 0
- || strcmp(VariableRelationName, $1) == 0)
+ || strcmp(VariableRelationName, $1) == 0)
elog(ERROR,"%s cannot be accessed by users",$1);
else
$$ = $1;
- StrNCpy(saved_relname, $1, NAMEDATALEN);
}
;
@@ -5298,7 +5256,7 @@ AexprConst: Iconst
n->val.val.str = $1;
$$ = (Node *)n;
}
- /* The SimpleTypename rule formerly used Typename,
+ /* This rule formerly used Typename,
* but that causes reduce conflicts with subscripted column names.
* Now, separate into ConstTypename and ConstInterval,
* to allow implementing the SQL92 syntax for INTERVAL literals.
@@ -5383,6 +5341,7 @@ ColId: generic { $$ = $1; }
| TokenId { $$ = $1; }
| INTERVAL { $$ = "interval"; }
| NATIONAL { $$ = "national"; }
+ | NONE { $$ = "none"; }
| PATH_P { $$ = "path"; }
| SERIAL { $$ = "serial"; }
| TIME { $$ = "time"; }
@@ -5595,7 +5554,6 @@ ColLabel: ColId { $$ = $1; }
| NATURAL { $$ = "natural"; }
| NCHAR { $$ = "nchar"; }
| NEW { $$ = "new"; }
- | NONE { $$ = "none"; }
| NOT { $$ = "not"; }
| NOTNULL { $$ = "notnull"; }
| NULLIF { $$ = "nullif"; }
@@ -5851,7 +5809,6 @@ xlateSqlType(char *name)
void parser_init(Oid *typev, int nargs)
{
- saved_relname[0] = '\0';
QueryIsRule = FALSE;
/*
* Keep enough information around to fill out the type of param nodes
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index 20233ed1950..38dc3ea0976 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -8,7 +8,7 @@
*
*
* 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)
save_joinlist = pstate->p_joinlist;
pstate->p_rtable = 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_joinlist = save_joinlist;
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 7b647124d1f..94ccaa5f69f 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -8,7 +8,7 @@
*
*
* 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)
break;
}
pstate->p_hasSubLinks = true;
- qtrees = parse_analyze(makeList1(sublink->subselect),
- pstate);
+ qtrees = parse_analyze(sublink->subselect, pstate);
if (length(qtrees) != 1)
elog(ERROR, "Bad query in subselect");
qtree = (Query *) lfirst(qtrees);
@@ -821,19 +820,21 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
static Node *
parser_typecast_constant(Value *expr, TypeName *typename)
{
- Const *con;
Type tp;
Datum datum;
+ Const *con;
char *const_string = NULL;
bool string_palloced = false;
bool isNull = false;
+ tp = typenameType(TypeNameToInternalName(typename));
+
switch (nodeTag(expr))
{
case T_Integer:
- string_palloced = true;
const_string = DatumGetCString(DirectFunctionCall1(int4out,
Int32GetDatum(expr->val.ival)));
+ string_palloced = true;
break;
case T_Float:
case T_String:
@@ -844,19 +845,9 @@ parser_typecast_constant(Value *expr, TypeName *typename)
break;
default:
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)
datum = (Datum) NULL;
else
@@ -892,15 +883,7 @@ parser_typecast_expression(ParseState *pstate,
Type tp;
Oid targetType;
- 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);
+ tp = typenameType(TypeNameToInternalName(typename));
targetType = typeTypeId(tp);
if (inputType == InvalidOid)
@@ -925,3 +908,26 @@ parser_typecast_expression(ParseState *pstate,
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;
+}
diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c
index 4a6c825498a..84b27549d36 100644
--- a/src/backend/parser/parser.c
+++ b/src/backend/parser/parser.c
@@ -1,14 +1,20 @@
/*-------------------------------------------------------------------------
*
* 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) 1994, Regents of the University of California
*
* 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 @@
#include "postgres.h"
#include "nodes/parsenodes.h"
-#include "nodes/pg_list.h"
-#include "parser/analyze.h"
#include "parser/gramparse.h"
#include "parser/parse.h"
#include "parser/parser.h"
@@ -35,19 +39,17 @@ List *parsetree; /* result of parsing is left here */
static int lookahead_token; /* one-token lookahead */
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 *
parser(char *str, Oid *typev, int nargs)
{
- List *queryList;
int yyresult;
parseString = str;
@@ -67,28 +69,9 @@ parser(char *str, Oid *typev, int nargs)
clearerr(stdin);
if (yyresult) /* error */
- return (List *) NULL;
-
- queryList = parse_analyze(parsetree, NULL);
+ return NIL;
-#ifdef SETS_FIXED
-
- /*
- * 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;
+ return parsetree;
}
@@ -135,83 +118,3 @@ yylex(void)
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
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index bddad9e4f6e..3eaa3a1562d 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
*
*
* 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
* this is the "main" module of the postgres backend and
@@ -47,6 +47,8 @@
#include "nodes/print.h"
#include "optimizer/cost.h"
#include "optimizer/planner.h"
+#include "parser/analyze.h"
+#include "parser/parse.h"
#include "parser/parser.h"
#include "rewrite/rewriteHandler.h"
#include "tcop/fastpath.h"
@@ -90,8 +92,6 @@ extern char ControlFilePath[];
static bool dontExecute = false;
-static bool IsEmptyQuery = false;
-
/* note: these declarations had better match tcopprot.h */
DLLIMPORT sigjmp_buf Warn_restart;
@@ -129,6 +129,10 @@ int XfuncMode = 0;
static int InteractiveBackend(StringInfo inBuf);
static int SocketBackend(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 FloatExceptionHandler(SIGNAL_ARGS);
static void quickdie(SIGNAL_ARGS);
@@ -341,46 +345,120 @@ ReadCommand(StringInfo inBuf)
*
* A list of Query nodes is returned, since the string might contain
* 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 *
pg_parse_and_rewrite(char *query_string, /* string to execute */
Oid *typev, /* parameter types */
int nargs) /* number of parameters */
{
+ List *raw_parsetree_list;
List *querytree_list;
- List *querytree_list_item;
- Query *querytree;
- List *new_list;
+ List *list_item;
+
+ /* ----------------
+ * (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)
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)
ResetUsage();
- querytree_list = parser(query_string, typev, nargs);
+ querytree_list = parse_analyze(parsetree, NULL);
if (Show_parser_stats)
{
- fprintf(StatFp, "PARSER STATISTICS\n");
+ fprintf(StatFp, "PARSE ANALYSIS STATISTICS\n");
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
* more or fewer than in the original list.
* ----------------
*/
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)
{
@@ -409,19 +487,18 @@ pg_parse_and_rewrite(char *query_string, /* string to execute */
querytree_list = new_list;
+ if (Show_parser_stats)
+ {
+ fprintf(StatFp, "REWRITER STATISTICS\n");
+ ShowUsage();
+ }
+
#ifdef COPY_PARSE_PLAN_TREES
- /* Optional debugging check: pass parsetree 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.
- */
+ /* Optional debugging check: pass querytree output through copyObject() */
new_list = (List *) copyObject(querytree_list);
/* This checks both copyObject() and the equal() routines... */
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
querytree_list = new_list;
#endif
@@ -431,9 +508,9 @@ pg_parse_and_rewrite(char *query_string, /* string to execute */
if (Debug_pretty_print)
{
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);
printf("\n");
}
@@ -441,10 +518,9 @@ pg_parse_and_rewrite(char *query_string, /* string to execute */
else
{
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);
elog(DEBUG, "%s", nodeToString(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
* parser/planner/executor over it as necessary.
@@ -545,21 +621,31 @@ pg_plan_query(Query *querytree)
*/
void
-pg_exec_query_dest(char *query_string, /* string to execute */
- CommandDest dest, /* where results should go */
- MemoryContext parse_context) /* context for parsetrees */
+pg_exec_query_string(char *query_string, /* string to execute */
+ CommandDest dest, /* where results should go */
+ MemoryContext parse_context) /* context for parsetrees */
{
+ bool xact_started;
MemoryContext oldcontext;
- List *querytree_list,
- *querytree_item;
+ List *parsetree_list,
+ *parsetree_item;
/*
- * If you called this routine with parse_context = CurrentMemoryContext,
- * you blew it. They *must* be different, else the context reset
- * at the bottom of the loop will destroy the querytree 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.)
+ * Start up a transaction command. All queries generated by the
+ * query_string will be in this same command block, *unless* we find
+ * a BEGIN/COMMIT/ABORT statement; we have to force a new xact command
+ * after one of those, else bad things will happen in xact.c.
+ * (Note that this will possibly change execution memory context.)
+ */
+ 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);
@@ -569,48 +655,57 @@ pg_exec_query_dest(char *query_string, /* string to execute */
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);
/*
- * 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 */
- if (QueryCancel)
- CancelQuery();
+ /* Transaction control statements need some special handling */
+ isTransactionStmt = IsA(parsetree, TransactionStmt);
- 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())
{
- /* ----------------
- * 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");
+ bool allowit = false;
- ProcessUtility(querytree->utilityStmt, dest);
- }
- else
- {
- Plan *plan;
+ if (isTransactionStmt)
+ {
+ TransactionStmt *stmt = (TransactionStmt *) parsetree;
+
+ switch (stmt->command)
+ {
+ case COMMIT:
+ case ROLLBACK:
+ allowit = true;
+ break;
+ default:
+ break;
+ }
+ }
- /* If aborted transaction, skip planning and execution */
- if (IsAbortedTransactionBlockState())
+ if (! allowit)
{
/* ----------------
* the EndCommand() stuff is to tell the frontend
@@ -631,58 +726,180 @@ pg_exec_query_dest(char *query_string, /* string to execute */
*/
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 (QueryCancel)
- CancelQuery();
+ /* If we got a cancel signal in parsing or prior command, quit */
+ if (QueryCancel)
+ 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 */
- SetQuerySnapshot();
+ querytree_list = pg_analyze_and_rewrite(parsetree);
- /*
- * execute the plan
- */
- if (Show_executor_stats)
- ResetUsage();
+ /*
+ * Switch back to execution context for planning and execution.
+ */
+ MemoryContextSwitchTo(oldcontext);
+
+ /*
+ * 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 */
- print_plan(plan, querytree);
+ start_xact_command();
+ 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
{
- if (DebugLvl > 1)
- elog(DEBUG, "ProcessQuery");
- ProcessQuery(querytree, plan, dest);
+ /* ----------------
+ * process a plannable query.
+ * ----------------
+ */
+ 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");
- ShowUsage();
+ finish_xact_command();
+ xact_started = false;
}
- }
- /*
- * 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.
- */
- CommandCounterIncrement();
- /*
- * Also, 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".
- */
- MemoryContextResetAndDeleteChildren(CurrentMemoryContext);
- }
+ } /* end loop over queries generated from a parsetree */
+ } /* end loop over parsetrees */
+
+ /*
+ * Close down transaction statement, if one is open.
+ */
+ if (xact_started)
+ finish_xact_command();
}
+/*
+ * 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()
*
@@ -1397,7 +1614,7 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
if (!IsUnderPostmaster)
{
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
{
/* ----------------
* 'F' indicates a fastpath call.
- * XXX HandleFunctionRequest
* ----------------
*/
case 'F':
- IsEmptyQuery = false;
-
/* start an xact for this function invocation */
- if (DebugLvl >= 1)
- elog(DEBUG, "StartTransactionCommand");
- StartTransactionCommand();
+ start_xact_command();
if (HandleFunctionRequest() == EOF)
{
/* lost frontend connection during F message input */
goto normalexit;
}
+
+ /* commit the function-invocation transaction */
+ finish_xact_command();
break;
/* ----------------
@@ -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
- * 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
{
/* ----------------
* 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)
ResetUsage();
- /* start an xact for this query */
- if (DebugLvl >= 1)
- elog(DEBUG, "StartTransactionCommand");
- StartTransactionCommand();
-
- pg_exec_query_dest(parser_input->data,
- whereToSendOutput,
- QueryContext);
-
- /*
- * Invoke IMMEDIATE constraint triggers
- *
- */
- DeferredTriggerEndQuery();
+ pg_exec_query_string(parser_input->data,
+ whereToSendOutput,
+ QueryContext);
if (Show_query_stats)
{
@@ -1603,39 +1811,14 @@ PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[], const cha
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
/*
- * 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);
#endif
- } /* end of main loop */
+ } /* end of input-reading loop */
normalexit:
ExitAfterAbort = true; /* ensure we will exit if elog during abort */
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 9edb092e62d..9b52e9b66cd 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
*
*
* 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 @@
#include "commands/view.h"
#include "miscadmin.h"
#include "parser/parse.h"
+#include "parser/parse_expr.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteRemove.h"
#include "tcop/utility.h"
@@ -46,24 +47,6 @@
/* ----------------
- * 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
* ----------------
*/
@@ -90,7 +73,6 @@ ProcessUtility(Node *parsetree,
{
case BEGIN_TRANS:
set_ps_display(commandTag = "BEGIN");
- CHECK_IF_ABORTED();
BeginTransactionBlock();
break;
@@ -116,7 +98,6 @@ ProcessUtility(Node *parsetree,
ClosePortalStmt *stmt = (ClosePortalStmt *) parsetree;
set_ps_display(commandTag = "CLOSE");
- CHECK_IF_ABORTED();
PerformPortalClose(stmt->portalname, dest);
}
@@ -130,7 +111,6 @@ ProcessUtility(Node *parsetree,
int count;
set_ps_display(commandTag = (stmt->ismove) ? "MOVE" : "FETCH");
- CHECK_IF_ABORTED();
SetQuerySnapshot();
@@ -153,7 +133,6 @@ ProcessUtility(Node *parsetree,
*/
case T_CreateStmt:
set_ps_display(commandTag = "CREATE");
- CHECK_IF_ABORTED();
DefineRelation((CreateStmt *) parsetree, RELKIND_RELATION);
@@ -174,7 +153,6 @@ ProcessUtility(Node *parsetree,
List *arg;
set_ps_display(commandTag = "DROP");
- CHECK_IF_ABORTED();
/* check as much as we can before we start dropping ... */
foreach(arg, args)
@@ -216,7 +194,6 @@ ProcessUtility(Node *parsetree,
Relation rel;
set_ps_display(commandTag = "TRUNCATE");
- CHECK_IF_ABORTED();
relname = ((TruncateStmt *) parsetree)->relName;
if (!allowSystemTableMods && IsSystemRelationName(relname))
@@ -243,27 +220,23 @@ ProcessUtility(Node *parsetree,
case T_CommentStmt:
{
-
CommentStmt *statement;
statement = ((CommentStmt *) parsetree);
set_ps_display(commandTag = "COMMENT");
- CHECK_IF_ABORTED();
+
CommentObject(statement->objtype, statement->objname,
statement->objproperty, statement->objlist,
statement->comment);
}
break;
-
-
case T_CopyStmt:
{
CopyStmt *stmt = (CopyStmt *) parsetree;
set_ps_display(commandTag = "COPY");
- CHECK_IF_ABORTED();
if (stmt->direction != FROM)
SetQuerySnapshot();
@@ -292,7 +265,6 @@ ProcessUtility(Node *parsetree,
RenameStmt *stmt = (RenameStmt *) parsetree;
set_ps_display(commandTag = "ALTER");
- CHECK_IF_ABORTED();
relname = stmt->relname;
if (!allowSystemTableMods && IsSystemRelationName(relname))
@@ -345,7 +317,6 @@ ProcessUtility(Node *parsetree,
AlterTableStmt *stmt = (AlterTableStmt *) parsetree;
set_ps_display(commandTag = "ALTER");
- CHECK_IF_ABORTED();
/*
* Some or all of these functions are recursive to cover
@@ -385,34 +356,10 @@ ProcessUtility(Node *parsetree,
case T_ChangeACLStmt:
{
ChangeACLStmt *stmt = (ChangeACLStmt *) parsetree;
- List *i;
- AclItem *aip;
- unsigned modechg;
set_ps_display(commandTag = "CHANGE");
- CHECK_IF_ABORTED();
-
- aip = stmt->aclitem;
- modechg = stmt->modechg;
- 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);
- }
+ ExecuteChangeACLStmt(stmt);
}
break;
@@ -426,7 +373,6 @@ ProcessUtility(Node *parsetree,
DefineStmt *stmt = (DefineStmt *) parsetree;
set_ps_display(commandTag = "CREATE");
- CHECK_IF_ABORTED();
switch (stmt->defType)
{
@@ -450,14 +396,14 @@ ProcessUtility(Node *parsetree,
ViewStmt *stmt = (ViewStmt *) parsetree;
set_ps_display(commandTag = "CREATE");
- CHECK_IF_ABORTED();
+
DefineView(stmt->viewname, stmt->query); /* retrieve parsetree */
}
break;
case T_ProcedureStmt: /* CREATE FUNCTION */
set_ps_display(commandTag = "CREATE");
- CHECK_IF_ABORTED();
+
CreateFunction((ProcedureStmt *) parsetree, dest); /* everything */
break;
@@ -466,7 +412,7 @@ ProcessUtility(Node *parsetree,
IndexStmt *stmt = (IndexStmt *) parsetree;
set_ps_display(commandTag = "CREATE");
- CHECK_IF_ABORTED();
+
DefineIndex(stmt->relname, /* relation name */
stmt->idxname, /* index name */
stmt->accessMethod, /* am name */
@@ -491,14 +437,13 @@ ProcessUtility(Node *parsetree,
elog(ERROR, "%s: %s", relname, aclcheck_error_strings[aclcheck_result]);
#endif
set_ps_display(commandTag = "CREATE");
- CHECK_IF_ABORTED();
+
DefineQueryRewrite(stmt);
}
break;
case T_CreateSeqStmt:
set_ps_display(commandTag = "CREATE");
- CHECK_IF_ABORTED();
DefineSequence((CreateSeqStmt *) parsetree);
break;
@@ -508,7 +453,6 @@ ProcessUtility(Node *parsetree,
ExtendStmt *stmt = (ExtendStmt *) parsetree;
set_ps_display(commandTag = "EXTEND");
- CHECK_IF_ABORTED();
ExtendIndex(stmt->idxname, /* index name */
(Expr *) stmt->whereClause, /* where */
@@ -521,7 +465,6 @@ ProcessUtility(Node *parsetree,
RemoveStmt *stmt = (RemoveStmt *) parsetree;
set_ps_display(commandTag = "DROP");
- CHECK_IF_ABORTED();
switch (stmt->removeType)
{
@@ -581,10 +524,14 @@ ProcessUtility(Node *parsetree,
case T_RemoveAggrStmt:
{
RemoveAggrStmt *stmt = (RemoveAggrStmt *) parsetree;
+ char *typename = (char *) NULL;
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;
@@ -593,27 +540,27 @@ ProcessUtility(Node *parsetree,
RemoveFuncStmt *stmt = (RemoveFuncStmt *) parsetree;
set_ps_display(commandTag = "DROP");
- CHECK_IF_ABORTED();
- RemoveFunction(stmt->funcname,
- length(stmt->args),
- stmt->args);
+
+ RemoveFunction(stmt->funcname, stmt->args);
}
break;
case T_RemoveOperStmt:
{
RemoveOperStmt *stmt = (RemoveOperStmt *) parsetree;
- char *type1 = (char *) NULL;
- char *type2 = (char *) NULL;
+ TypeName *typenode1 = (TypeName *) lfirst(stmt->args);
+ TypeName *typenode2 = (TypeName *) lsecond(stmt->args);
+ char *typename1 = (char *) NULL;
+ char *typename2 = (char *) NULL;
set_ps_display(commandTag = "DROP");
- CHECK_IF_ABORTED();
- if (lfirst(stmt->args) != NULL)
- type1 = strVal(lfirst(stmt->args));
- if (lsecond(stmt->args) != NULL)
- type2 = strVal(lsecond(stmt->args));
- RemoveOperator(stmt->opname, type1, type2);
+ if (typenode1 != NULL)
+ typename1 = TypeNameToInternalName(typenode1);
+ if (typenode2 != NULL)
+ typename2 = TypeNameToInternalName(typenode2);
+
+ RemoveOperator(stmt->opname, typename1, typename2);
}
break;
@@ -626,7 +573,7 @@ ProcessUtility(Node *parsetree,
CreatedbStmt *stmt = (CreatedbStmt *) parsetree;
set_ps_display(commandTag = "CREATE DATABASE");
- CHECK_IF_ABORTED();
+
createdb(stmt->dbname, stmt->dbpath, stmt->encoding);
}
break;
@@ -636,7 +583,7 @@ ProcessUtility(Node *parsetree,
DropdbStmt *stmt = (DropdbStmt *) parsetree;
set_ps_display(commandTag = "DROP DATABASE");
- CHECK_IF_ABORTED();
+
dropdb(stmt->dbname);
}
break;
@@ -647,7 +594,6 @@ ProcessUtility(Node *parsetree,
NotifyStmt *stmt = (NotifyStmt *) parsetree;
set_ps_display(commandTag = "NOTIFY");
- CHECK_IF_ABORTED();
Async_Notify(stmt->relname);
}
@@ -658,7 +604,6 @@ ProcessUtility(Node *parsetree,
ListenStmt *stmt = (ListenStmt *) parsetree;
set_ps_display(commandTag = "LISTEN");
- CHECK_IF_ABORTED();
Async_Listen(stmt->relname, MyProcPid);
}
@@ -669,7 +614,6 @@ ProcessUtility(Node *parsetree,
UnlistenStmt *stmt = (UnlistenStmt *) parsetree;
set_ps_display(commandTag = "UNLISTEN");
- CHECK_IF_ABORTED();
Async_Unlisten(stmt->relname, MyProcPid);
}
@@ -684,7 +628,6 @@ ProcessUtility(Node *parsetree,
LoadStmt *stmt = (LoadStmt *) parsetree;
set_ps_display(commandTag = "LOAD");
- CHECK_IF_ABORTED();
closeAllVfds(); /* probably not necessary... */
load_file(stmt->filename);
@@ -696,7 +639,6 @@ ProcessUtility(Node *parsetree,
ClusterStmt *stmt = (ClusterStmt *) parsetree;
set_ps_display(commandTag = "CLUSTER");
- CHECK_IF_ABORTED();
cluster(stmt->relname, stmt->indexname);
}
@@ -704,7 +646,7 @@ ProcessUtility(Node *parsetree,
case T_VacuumStmt:
set_ps_display(commandTag = "VACUUM");
- CHECK_IF_ABORTED();
+
vacuum(((VacuumStmt *) parsetree)->vacrel,
((VacuumStmt *) parsetree)->verbose,
((VacuumStmt *) parsetree)->analyze,
@@ -716,7 +658,6 @@ ProcessUtility(Node *parsetree,
ExplainStmt *stmt = (ExplainStmt *) parsetree;
set_ps_display(commandTag = "EXPLAIN");
- CHECK_IF_ABORTED();
ExplainQuery(stmt->query, stmt->verbose, dest);
}
@@ -732,7 +673,7 @@ ProcessUtility(Node *parsetree,
RecipeStmt *stmt = (RecipeStmt *) parsetree;
set_ps_display(commandTag = "EXECUTE RECIPE");
- CHECK_IF_ABORTED();
+
beginRecipe(stmt);
}
break;
@@ -773,14 +714,12 @@ ProcessUtility(Node *parsetree,
*/
case T_CreateTrigStmt:
set_ps_display(commandTag = "CREATE");
- CHECK_IF_ABORTED();
CreateTrigger((CreateTrigStmt *) parsetree);
break;
case T_DropTrigStmt:
set_ps_display(commandTag = "DROP");
- CHECK_IF_ABORTED();
DropTrigger((DropTrigStmt *) parsetree);
break;
@@ -790,14 +729,12 @@ ProcessUtility(Node *parsetree,
*/
case T_CreatePLangStmt:
set_ps_display(commandTag = "CREATE");
- CHECK_IF_ABORTED();
CreateProceduralLanguage((CreatePLangStmt *) parsetree);
break;
case T_DropPLangStmt:
set_ps_display(commandTag = "DROP");
- CHECK_IF_ABORTED();
DropProceduralLanguage((DropPLangStmt *) parsetree);
break;
@@ -808,56 +745,48 @@ ProcessUtility(Node *parsetree,
*/
case T_CreateUserStmt:
set_ps_display(commandTag = "CREATE USER");
- CHECK_IF_ABORTED();
CreateUser((CreateUserStmt *) parsetree);
break;
case T_AlterUserStmt:
set_ps_display(commandTag = "ALTER USER");
- CHECK_IF_ABORTED();
AlterUser((AlterUserStmt *) parsetree);
break;
case T_DropUserStmt:
set_ps_display(commandTag = "DROP USER");
- CHECK_IF_ABORTED();
DropUser((DropUserStmt *) parsetree);
break;
case T_LockStmt:
set_ps_display(commandTag = "LOCK TABLE");
- CHECK_IF_ABORTED();
LockTableCommand((LockStmt *) parsetree);
break;
case T_ConstraintsSetStmt:
set_ps_display(commandTag = "SET CONSTRAINTS");
- CHECK_IF_ABORTED();
DeferredTriggerSetState((ConstraintsSetStmt *) parsetree);
break;
case T_CreateGroupStmt:
set_ps_display(commandTag = "CREATE GROUP");
- CHECK_IF_ABORTED();
CreateGroup((CreateGroupStmt *) parsetree);
break;
case T_AlterGroupStmt:
set_ps_display(commandTag = "ALTER GROUP");
- CHECK_IF_ABORTED();
AlterGroup((AlterGroupStmt *) parsetree, "ALTER GROUP");
break;
case T_DropGroupStmt:
set_ps_display(commandTag = "DROP GROUP");
- CHECK_IF_ABORTED();
DropGroup((DropGroupStmt *) parsetree);
break;
@@ -867,7 +796,6 @@ ProcessUtility(Node *parsetree,
ReindexStmt *stmt = (ReindexStmt *) parsetree;
set_ps_display(commandTag = "REINDEX");
- CHECK_IF_ABORTED();
switch (stmt->reindexType)
{
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 3d43a45cd1e..401ed1a9375 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -8,7 +8,7 @@
*
*
* 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 @@
#include "postgres.h"
+#include "access/heapam.h"
#include "catalog/catalog.h"
#include "catalog/pg_shadow.h"
#include "catalog/pg_type.h"
#include "lib/stringinfo.h"
+#include "miscadmin.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
@@ -561,7 +563,52 @@ aclcontains(PG_FUNCTION_ARGS)
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
@@ -569,9 +616,7 @@ aclcontains(PG_FUNCTION_ARGS)
* and a new privilege
*
* does not add duplicate privileges
- *
*/
-
char *
aclmakepriv(char *old_privlist, char new_priv)
{
@@ -619,12 +664,9 @@ aclmakepriv(char *old_privlist, char new_priv)
* "G" - group
* "U" - user
*
- * concatenates the two strings together with a space in between
- *
- * this routine is used in the parser
- *
+ * 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.
*/
-
char *
aclmakeuser(char *user_type, char *user)
{
@@ -635,20 +677,16 @@ aclmakeuser(char *user_type, char *user)
return user_list;
}
-
/*
* makeAclStmt:
- * this is a helper routine called by the parser
- * create a ChangeAclStmt
- * we take in the privilegs, relation_name_list, and grantee
- * as well as a single character '+' or '-' to indicate grant or revoke
+ * create a ChangeACLStmt at parse time.
+ * we take in the privileges, relation_name_list, and grantee
+ * as well as a single character '+' or '-' to indicate grant or revoke
*
- * returns a new ChangeACLStmt*
- *
- * this routines works by creating a old-style changle acl string and
- * then calling aclparse;
+ * We convert the information to the same external form recognized by
+ * aclitemin (see aclparse), and save that string in the ChangeACLStmt.
+ * Conversion to internal form happens when the statement is executed.
*/
-
ChangeACLStmt *
makeAclStmt(char *privileges, List *rel_list, char *grantee,
char grant_or_revoke)
@@ -658,11 +696,6 @@ makeAclStmt(char *privileges, List *rel_list, char *grantee,
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" */
if (grantee[0] == 'G') /* group permissions */
{
@@ -683,7 +716,8 @@ makeAclStmt(char *privileges, List *rel_list, char *grantee,
grant_or_revoke, privileges);
}
n->relNames = rel_list;
- aclparse(str.data, n->aclitem, (unsigned *) &n->modechg);
+ n->aclString = pstrdup(str.data);
+
pfree(str.data);
return n;
}
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 2a7a4bdcfa8..dce401d7d9b 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* 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);
/*
* 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,
char *typeName1, char *typeName2);
extern void RemoveType(char *typeName);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 41309426e8b..b50990fe299 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* 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
typedef struct ChangeACLStmt
{
NodeTag type;
- struct AclItem *aclitem;
- unsigned modechg;
List *relNames;
+ char *aclString;
} ChangeACLStmt;
/* ----------------------
@@ -488,10 +487,8 @@ typedef struct ProcedureStmt
{
NodeTag type;
char *funcname; /* name of function to create */
- List *defArgs; /* list of definitions a list of strings
- * (as Value *) */
- Node *returnType; /* the return type (as a string or a
- * TypeName (ie.setof) */
+ List *argTypes; /* list of argument types (TypeName nodes) */
+ Node *returnType; /* the return type (a TypeName node) */
List *withClause; /* a list of DefElem */
List *as; /* definition of function body */
char *language; /* C, SQL, etc */
@@ -505,7 +502,7 @@ typedef struct RemoveAggrStmt
{
NodeTag type;
char *aggname; /* aggregate to drop */
- char *aggtype; /* for this type */
+ Node *aggtype; /* TypeName for input datatype, or NULL */
} RemoveAggrStmt;
/* ----------------------
diff --git a/src/include/parser/analyze.h b/src/include/parser/analyze.h
index afd8a34fb3e..9d60e0f64c8 100644
--- a/src/include/parser/analyze.h
+++ b/src/include/parser/analyze.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* 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 @@
#include "parser/parse_node.h"
-extern List *parse_analyze(List *pl, ParseState *parentParseState);
+extern List *parse_analyze(Node *parseTree, ParseState *parentParseState);
#endif /* ANALYZE_H */
diff --git a/src/include/parser/parse_expr.h b/src/include/parser/parse_expr.h
index 7f1b5d5122d..410a24bc455 100644
--- a/src/include/parser/parse_expr.h
+++ b/src/include/parser/parse_expr.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* 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);
extern int32 exprTypmod(Node *expr);
extern bool exprIsLengthCoercion(Node *expr, int32 *coercedTypmod);
extern void parse_expr_init(void);
+extern char *TypeNameToInternalName(TypeName *typename);
#endif /* PARSE_EXPR_H */
diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h
index 562efca25cc..062a5818407 100644
--- a/src/include/tcop/tcopprot.h
+++ b/src/include/tcop/tcopprot.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* 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
* This file was created so that other c files could get the two
@@ -35,9 +35,9 @@ extern bool ShowPortNumber;
extern List *pg_parse_and_rewrite(char *query_string,
Oid *typev, int nargs);
extern Plan *pg_plan_query(Query *querytree);
-extern void pg_exec_query_dest(char *query_string,
- CommandDest dest,
- MemoryContext parse_context);
+extern void pg_exec_query_string(char *query_string,
+ CommandDest dest,
+ MemoryContext parse_context);
#endif /* BOOTSTRAP_INCLUDE */
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index 4add4202fcb..8836bd1733e 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* 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
* For backward-compatibility purposes we have to allow there
@@ -167,12 +167,15 @@ extern char *aclcheck_error_strings[];
/*#define ACLDEBUG_TRACE*/
/*
- * routines used internally (parser, etc.)
+ * routines used internally
*/
extern Acl *acldefault(char *relname, AclId ownerid);
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 *aclmakeuser(char *user_type, char *user);
extern ChangeACLStmt *makeAclStmt(char *privs, List *rel_list, char *grantee,
@@ -187,6 +190,7 @@ extern Datum aclitemout(PG_FUNCTION_ARGS);
extern Datum aclinsert(PG_FUNCTION_ARGS);
extern Datum aclremove(PG_FUNCTION_ARGS);
extern Datum aclcontains(PG_FUNCTION_ARGS);
+extern void ExecuteChangeACLStmt(ChangeACLStmt *stmt);
/*
* prototypes for functions in aclchk.c