mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +03:00
Add FILLFACTOR to CREATE INDEX.
ITAGAKI Takahiro
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
case DEFAULT_OIDS:
|
||||
return default_with_oids;
|
||||
if (pg_strcasecmp(def->defname, "oids") == 0)
|
||||
return defGetBoolean(def);
|
||||
}
|
||||
|
||||
elog(ERROR, "bogus ContainsOids value: %d", opt);
|
||||
return false; /* keep compiler quiet */
|
||||
/* oids option is not specified. */
|
||||
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;
|
||||
}
|
||||
|
||||
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:;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user