summaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/analyze.c10
-rw-r--r--src/backend/parser/gram.y80
-rw-r--r--src/backend/parser/parse_clause.c279
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:;
+ }
}
/*