diff options
Diffstat (limited to 'src/backend/parser')
| -rw-r--r-- | src/backend/parser/analyze.c | 10 | ||||
| -rw-r--r-- | src/backend/parser/gram.y | 80 | ||||
| -rw-r--r-- | src/backend/parser/parse_clause.c | 279 |
3 files changed, 328 insertions, 41 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 8b9b9eab53..9e66ca1ab6 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.336 2006/06/27 03:43:20 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.337 2006/07/02 02:23:20 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -757,7 +757,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt, cxt.blist = NIL; cxt.alist = NIL; cxt.pkey = NULL; - cxt.hasoids = interpretOidsOption(stmt->hasoids); + cxt.hasoids = interpretOidsOption(stmt->options); /* * Run through each primary element in the table creation clause. Separate @@ -1282,6 +1282,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt) index->relation = cxt->relation; index->accessMethod = DEFAULT_INDEX_TYPE; + index->options = constraint->options; index->tableSpace = constraint->indexspace; index->indexParams = NIL; index->whereClause = NULL; @@ -1881,7 +1882,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt) if (stmt->intoColNames) applyColumnNames(qry->targetList, stmt->intoColNames); - qry->intoHasOids = interpretOidsOption(stmt->intoHasOids); + qry->intoHasOids = interpretOidsOption(stmt->intoOptions); + qry->intoOptions = copyObject(stmt->intoOptions); qry->intoOnCommit = stmt->intoOnCommit; qry->intoTableSpaceName = stmt->intoTableSpaceName; @@ -2752,7 +2754,7 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt) paramtypes = FetchPreparedStatementParams(stmt->name); - stmt->into_has_oids = interpretOidsOption(stmt->into_contains_oids); + stmt->into_has_oids = interpretOidsOption(stmt->intoOptions); if (stmt->params || paramtypes) { diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 9ad722528e..f09a7a6b2d 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.549 2006/07/02 01:58:36 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.550 2006/07/02 02:23:21 momjian Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -53,6 +53,7 @@ #include "catalog/index.h" #include "catalog/namespace.h" +#include "commands/defrem.h" #include "nodes/makefuncs.h" #include "parser/gramparse.h" #include "storage/lmgr.h" @@ -123,7 +124,6 @@ static void doNegateFloat(Value *v); JoinType jtype; DropBehavior dbehavior; OnCommitAction oncommit; - ContainsOids withoids; List *list; Node *node; Value *value; @@ -228,11 +228,11 @@ static void doNegateFloat(Value *v); %type <list> stmtblock stmtmulti OptTableElementList TableElementList OptInherit definition - opt_distinct opt_definition func_args func_args_list + OptWith opt_distinct opt_definition func_args func_args_list func_as createfunc_opt_list alterfunc_opt_list aggr_args aggr_args_list old_aggr_definition old_aggr_list oper_argtypes RuleActionList RuleActionMulti - opt_column_list columnList opt_name_list + opt_column_list columnList opt_name_list sort_clause opt_sort_clause sortby_list index_params name_list from_clause from_list opt_array_bounds qualified_name_list any_name any_name_list @@ -255,7 +255,6 @@ static void doNegateFloat(Value *v); %type <boolean> TriggerForType OptTemp %type <oncommit> OnCommitOption -%type <withoids> OptWithOids %type <node> for_locking_item %type <list> for_locking_clause opt_for_locking_clause for_locking_items @@ -1559,6 +1558,32 @@ alter_rel_cmd: n->name = $3; $$ = (Node *)n; } + /* ALTER [TABLE|INDEX] <name> SET (...) */ + | SET definition + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_SetOptions; + n->def = (Node *)$2; + $$ = (Node *)n; + } + | RESET definition + { + AlterTableCmd *n; + ListCell *cell; + + foreach(cell, $2) + { + if (((DefElem *) lfirst(cell))->arg != NULL) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("parameters for RESET should not take values"))); + } + + n = makeNode(AlterTableCmd); + n->subtype = AT_SetOptions; + n->def = (Node *)$2; + $$ = (Node *)n; + } ; alter_column_default: @@ -1744,7 +1769,7 @@ opt_using: *****************************************************************************/ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' - OptInherit OptWithOids OnCommitOption OptTableSpace + OptInherit OptWith OnCommitOption OptTableSpace { CreateStmt *n = makeNode(CreateStmt); $4->istemp = $2; @@ -1752,13 +1777,13 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->tableElts = $6; n->inhRelations = $8; n->constraints = NIL; - n->hasoids = $9; + n->options = $9; n->oncommit = $10; n->tablespacename = $11; $$ = (Node *)n; } | CREATE OptTemp TABLE qualified_name OF qualified_name - '(' OptTableElementList ')' OptWithOids OnCommitOption OptTableSpace + '(' OptTableElementList ')' OptWith OnCommitOption OptTableSpace { /* SQL99 CREATE TABLE OF <UDT> (cols) seems to be satisfied * by our inheritance capabilities. Let's try it... @@ -1769,7 +1794,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' n->tableElts = $8; n->inhRelations = list_make1($6); n->constraints = NIL; - n->hasoids = $10; + n->options = $10; n->oncommit = $11; n->tablespacename = $12; $$ = (Node *)n; @@ -1905,7 +1930,7 @@ ColConstraintElem: n->indexspace = $2; $$ = (Node *)n; } - | PRIMARY KEY OptConsTableSpace + | PRIMARY KEY opt_definition OptConsTableSpace { Constraint *n = makeNode(Constraint); n->contype = CONSTR_PRIMARY; @@ -1913,7 +1938,8 @@ ColConstraintElem: n->raw_expr = NULL; n->cooked_expr = NULL; n->keys = NULL; - n->indexspace = $3; + n->options = $3; + n->indexspace = $4; $$ = (Node *)n; } | CHECK '(' a_expr ')' @@ -2085,7 +2111,7 @@ ConstraintElem: n->indexspace = $5; $$ = (Node *)n; } - | PRIMARY KEY '(' columnList ')' OptConsTableSpace + | PRIMARY KEY '(' columnList ')' opt_definition OptConsTableSpace { Constraint *n = makeNode(Constraint); n->contype = CONSTR_PRIMARY; @@ -2093,7 +2119,8 @@ ConstraintElem: n->raw_expr = NULL; n->cooked_expr = NULL; n->keys = $4; - n->indexspace = $6; + n->options = $6; + n->indexspace = $7; $$ = (Node *)n; } | FOREIGN KEY '(' columnList ')' REFERENCES qualified_name @@ -2187,10 +2214,13 @@ OptInherit: INHERITS '(' qualified_name_list ')' { $$ = $3; } | /*EMPTY*/ { $$ = NIL; } ; -OptWithOids: - WITH OIDS { $$ = MUST_HAVE_OIDS; } - | WITHOUT OIDS { $$ = MUST_NOT_HAVE_OIDS; } - | /*EMPTY*/ { $$ = DEFAULT_OIDS; } +OptWith: + WITH OIDS { $$ = list_make1(defWithOids(true)); } + | WITHOUT OIDS { $$ = list_make1(defWithOids(false)); } + | WITH definition { $$ = $2; } + | WITH OIDS WITH definition { $$ = lappend($4, defWithOids(true)); } + | WITHOUT OIDS WITH definition { $$ = lappend($4, defWithOids(false)); } + | /*EMPTY*/ { $$ = NIL; } ; OnCommitOption: ON COMMIT DROP { $$ = ONCOMMIT_DROP; } @@ -2215,7 +2245,7 @@ OptConsTableSpace: USING INDEX TABLESPACE name { $$ = $4; } CreateAsStmt: CREATE OptTemp TABLE qualified_name OptCreateAs - OptWithOids OnCommitOption OptTableSpace AS SelectStmt + OptWith OnCommitOption OptTableSpace AS SelectStmt { /* * When the SelectStmt is a set-operation tree, we must @@ -2232,7 +2262,7 @@ CreateAsStmt: $4->istemp = $2; n->into = $4; n->intoColNames = $5; - n->intoHasOids = $6; + n->intoOptions = $6; n->intoOnCommit = $7; n->intoTableSpaceName = $8; $$ = $10; @@ -3630,7 +3660,7 @@ opt_granted_by: GRANTED BY RoleId { $$ = $3; } *****************************************************************************/ IndexStmt: CREATE index_opt_unique INDEX index_name ON qualified_name - access_method_clause '(' index_params ')' OptTableSpace where_clause + access_method_clause '(' index_params ')' opt_definition OptTableSpace where_clause { IndexStmt *n = makeNode(IndexStmt); n->unique = $2; @@ -3638,8 +3668,9 @@ IndexStmt: CREATE index_opt_unique INDEX index_name ON qualified_name n->relation = $6; n->accessMethod = $7; n->indexParams = $9; - n->tableSpace = $11; - n->whereClause = $12; + n->options = $11; + n->tableSpace = $12; + n->whereClause = $13; $$ = (Node *)n; } ; @@ -5264,7 +5295,7 @@ ExecuteStmt: EXECUTE name execute_param_clause $$ = (Node *) n; } | CREATE OptTemp TABLE qualified_name OptCreateAs - OptWithOids OnCommitOption OptTableSpace AS + OptWith OnCommitOption OptTableSpace AS EXECUTE name execute_param_clause { ExecuteStmt *n = makeNode(ExecuteStmt); @@ -5272,7 +5303,7 @@ ExecuteStmt: EXECUTE name execute_param_clause n->params = $12; $4->istemp = $2; n->into = $4; - n->into_contains_oids = $6; + n->intoOptions = $6; n->into_on_commit = $7; n->into_tbl_space = $8; if ($5) @@ -5606,7 +5637,6 @@ simple_select: n->targetList = $3; n->into = $4; n->intoColNames = NIL; - n->intoHasOids = DEFAULT_OIDS; n->fromClause = $5; n->whereClause = $6; n->groupClause = $7; diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 9bdb91b474..a4fe1999fe 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.149 2006/03/16 00:31:55 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.150 2006/07/02 02:23:21 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -17,6 +17,7 @@ #include "access/heapam.h" #include "catalog/heap.h" +#include "commands/defrem.h" #include "nodes/makefuncs.h" #include "optimizer/clauses.h" #include "optimizer/tlist.h" @@ -33,6 +34,7 @@ #include "rewrite/rewriteManip.h" #include "utils/builtins.h" #include "utils/guc.h" +#include "utils/memutils.h" #define ORDER_CLAUSE 0 @@ -64,6 +66,8 @@ static Node *buildMergedJoinVar(ParseState *pstate, JoinType jointype, Var *l_colvar, Var *r_colvar); static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node, List **tlist, int clause); +static bool OptionMatches(text *t, const char* kw, char **str, Size *len); +static Datum OptionToText(DefElem *def); /* @@ -212,29 +216,280 @@ interpretInhOption(InhOption inhOpt) } /* - * Given an enum that indicates whether WITH / WITHOUT OIDS was + * Given a List that indicates whether WITH / WITHOUT OIDS was * specified by the user, return true iff the specified table/result * set should be created with OIDs. This needs to be done after * parsing the query string because the return value can depend upon * the default_with_oids GUC var. */ bool -interpretOidsOption(ContainsOids opt) +interpretOidsOption(List *options) { - switch (opt) + ListCell *cell; + + foreach(cell, options) { - case MUST_HAVE_OIDS: - return true; + DefElem *def = (DefElem *) lfirst(cell); - case MUST_NOT_HAVE_OIDS: - return false; + if (pg_strcasecmp(def->defname, "oids") == 0) + return defGetBoolean(def); + } + + /* oids option is not specified. */ + return default_with_oids; +} - case DEFAULT_OIDS: - return default_with_oids; +/* + * Test if t is start with 'kw='. + */ +static bool +OptionMatches(text *t, const char* kw, char **str, Size *len) +{ + char *text_str = (char *) VARATT_DATA(t); + int text_len = VARATT_SIZE(t) - VARHDRSZ; + Size kwlen = strlen(kw); + + if (text_len > kwlen && text_str[kwlen] == '=' && + pg_strncasecmp(text_str, kw, kwlen) == 0) + { + *str = text_str + kwlen + 1; + *len = text_len - kwlen - 1; + return true; } - elog(ERROR, "bogus ContainsOids value: %d", opt); - return false; /* keep compiler quiet */ + return false; +} + +/* + * Flatten a DefElem to a text like as 'defname=arg'. + */ +static Datum +OptionToText(DefElem *def) +{ + text *t; + char *value = defGetString(def); + Size len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value); + + t = palloc(len + 1); + VARATT_SIZEP(t) = len; + sprintf((char *) VARATT_DATA(t), "%s=%s", def->defname, value); + + return PointerGetDatum(t); +} + +/* + * Merge option array and option list. + * + * array Existing option, or NULL if new option. + * list List of DefElems to be added to array. + */ +ArrayType * +OptionBuild(ArrayType *array, List *list) +{ + ListCell *cell; + bool *used; + int index; + int o; + ArrayType *result; + ArrayBuildState *astate; + MemoryContext myContext; + MemoryContext oldContext; + + if (list_length(list) == 0) + { + /* no additinal elements, so just clone. */ + if (array == NULL) + return NULL; + result = palloc(VARATT_SIZE(array)); + memcpy(result, array, VARATT_SIZE(array)); + return result; + } + + /* Make a temporary context to hold all the junk */ + myContext = AllocSetContextCreate(CurrentMemoryContext, + "OptionBuild", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + ALLOCSET_DEFAULT_MAXSIZE); + oldContext = MemoryContextSwitchTo(myContext); + + astate = NULL; + used = (bool *) palloc0(sizeof(bool) * list_length(list)); + + if (array) + { + Assert(ARR_ELEMTYPE(array) == TEXTOID); + Assert(ARR_NDIM(array) == 1); + Assert(ARR_LBOUND(array)[0] == 1); + + for (o = 1; o <= ARR_DIMS(array)[0]; o++) + { + bool isnull; + Datum datum; + + datum = array_ref(array, 1, &o, + -1 /* varlenarray */ , + -1 /* TEXT's typlen */ , + false /* TEXT's typbyval */ , + 'i' /* TEXT's typalign */ , + &isnull); + if (isnull) + continue; + + index = 0; + foreach(cell, list) + { + DefElem *def = lfirst(cell); + + /* + * We ignore 'oids' item because it is stored + * in pg_class.relhasoids. + */ + if (!used[index] && + pg_strcasecmp(def->defname, "oids") != 0) + { + char *value_str; + Size value_len; + if (OptionMatches(DatumGetTextP(datum), + def->defname, &value_str, &value_len)) + { + used[index] = true; + if (def->arg) + { + /* Replace an existing option. */ + datum = OptionToText(def); + goto next; /* skip remain items in list */ + } + else + { + /* Remove the option from array. */ + goto skip; + } + } + } + + index++; + } + + /* + * The datum is an existing parameter and is not modified. + * Fall down. + */ + +next: + astate = accumArrayResult(astate, datum, false, TEXTOID, myContext); +skip: + ; + } + } + + /* + * add options not in array + */ + index = 0; + foreach(cell, list) + { + DefElem *def = lfirst(cell); + + if (!used[index] && def->arg && + pg_strcasecmp(def->defname, "oids") != 0) + { + astate = accumArrayResult(astate, OptionToText(def), + false, TEXTOID, myContext); + } + + index++; + } + + if (astate) + result = DatumGetArrayTypeP(makeArrayResult(astate, oldContext)); + else + result = NULL; + + MemoryContextSwitchTo(oldContext); + MemoryContextDelete(myContext); + return result; +} + +/* + * Support routine to parse options. + * + * options List of DefElems + * num length of kwds + * kwds supported keywords + * strict Throw error if unsupported option is found. + * + * FIXME: memory is leaked in kwds[].arg. + */ +void +OptionParse(ArrayType *options, Size num, DefElem kwds[], bool strict) +{ + Size k; + int o; + + for (k = 0; k < num; k++) + { + Assert(kwds[k].defname); + kwds[k].arg = NULL; + } + + if (options == NULL) + return; /* use default for all */ + + Assert(ARR_ELEMTYPE(options) == TEXTOID); + Assert(ARR_NDIM(options) == 1); + Assert(ARR_LBOUND(options)[0] == 1); + + for (o = 1; o <= ARR_DIMS(options)[0]; o++) + { + bool isnull; + Datum datum; + + datum = array_ref(options, 1, &o, + -1 /* varlenarray */ , + -1 /* TEXT's typlen */ , + false /* TEXT's typbyval */ , + 'i' /* TEXT's typalign */ , + &isnull); + if (isnull) + continue; + + for (k = 0; k < num; k++) + { + char *value_str; + Size value_len; + + if (OptionMatches(DatumGetTextP(datum), + kwds[k].defname, &value_str, &value_len)) + { + char *value; + + if (kwds[k].arg != NULL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("duplicated parameter %s", + kwds[k].defname))); + + /* copy value as Value node */ + value = (char *) palloc(value_len + 1); + strncpy(value, value_str, value_len); + value[value_len] = '\0'; + kwds[k].arg = (Node *) makeString(value); + goto next; /* skip remain keywords */ + } + } + + /* parameter is not in kwds */ + if (strict) + { + char *c = DatumGetCString(DirectFunctionCall1(textout, datum)); + + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unsupported parameter %s", c))); + } +next:; + } } /* |
