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 @@
*
*
* 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
......
......@@ -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);
}
/*------------------------------------------------------------------
......
This diff is collapsed.
......@@ -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;
}
}
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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;
}
}
......@@ -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
......
......@@ -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;
......
......@@ -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;
}
/*-------------------------------------------------------------------------
*
* 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
This diff is collapsed.
This diff is collapsed.
......@@ -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;
}
......@@ -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);
......
......@@ -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;
/* ----------------------
......
......@@ -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 */
......@@ -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 */
......@@ -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 */
......
......@@ -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
......
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