/* State shared by transformCreateStmt and its subroutines */ typedefstruct
{
ParseState *pstate; /* overall parser state */ constchar *stmtType; /* "CREATE [FOREIGN] TABLE" or "ALTER TABLE" */
RangeVar *relation; /* relation to create */
Relation rel; /* opened/locked rel, if ALTER */
List *inhRelations; /* relations to inherit from */ bool isforeign; /* true if CREATE/ALTER FOREIGN TABLE */ bool isalter; /* true if altering existing table */
List *columns; /* ColumnDef items */
List *ckconstraints; /* CHECK constraints */
List *nnconstraints; /* NOT NULL constraints */
List *fkconstraints; /* FOREIGN KEY constraints */
List *ixconstraints; /* index-creating constraints */
List *likeclauses; /* LIKE clauses that need post-processing */
List *blist; /* "before list" of things to do before
* creating the table */
List *alist; /* "after list" of things to do after creating
* the table */
IndexStmt *pkey; /* PRIMARY KEY index, if any */ bool ispartitioned; /* true if table is partitioned */
PartitionBoundSpec *partbound; /* transformed FOR VALUES */ bool ofType; /* true if statement contains OF typename */
} CreateStmtContext;
/* State shared by transformCreateSchemaStmtElements and its subroutines */ typedefstruct
{ constchar *schemaname; /* name of schema */
List *sequences; /* CREATE SEQUENCE items */
List *tables; /* CREATE TABLE items */
List *views; /* CREATE VIEW items */
List *indexes; /* CREATE INDEX items */
List *triggers; /* CREATE TRIGGER items */
List *grants; /* GRANT items */
} CreateSchemaStmtContext;
staticvoid transformColumnDefinition(CreateStmtContext *cxt,
ColumnDef *column); staticvoid transformTableConstraint(CreateStmtContext *cxt,
Constraint *constraint); staticvoid transformTableLikeClause(CreateStmtContext *cxt,
TableLikeClause *table_like_clause); staticvoid transformOfType(CreateStmtContext *cxt, TypeName *ofTypename); static CreateStatsStmt *generateClonedExtStatsStmt(RangeVar *heapRel,
Oid heapRelid,
Oid source_statsid, const AttrMap *attmap); static List *get_collation(Oid collation, Oid actual_datatype); static List *get_opclass(Oid opclass, Oid actual_datatype); staticvoid transformIndexConstraints(CreateStmtContext *cxt); static IndexStmt *transformIndexConstraint(Constraint *constraint,
CreateStmtContext *cxt); staticvoid transformFKConstraints(CreateStmtContext *cxt, bool skipValidation, bool isAddConstraint); staticvoid transformCheckConstraints(CreateStmtContext *cxt, bool skipValidation); staticvoid transformConstraintAttrs(CreateStmtContext *cxt,
List *constraintList); staticvoid transformColumnType(CreateStmtContext *cxt, ColumnDef *column); staticvoid setSchemaName(constchar *context_schema, char **stmt_schema_name); staticvoid transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd); static List *transformPartitionRangeBounds(ParseState *pstate, List *blist,
Relation parent); staticvoid validateInfiniteBounds(ParseState *pstate, List *blist); staticConst *transformPartitionBoundValue(ParseState *pstate, Node *val, constchar *colName, Oid colType, int32 colTypmod,
Oid partCollation);
/* *transformCreateStmt- *parseanalysisforCREATETABLE * *ReturnsaListofutilitycommandstobedoneinsequence.Oneofthese *willbethetransformedCreateStmt,buttheremaybeadditionalactions *tobedonebeforeandaftertheactualDefineRelation()call. *InadditiontonormalutilitycommandssuchasAlterTableStmtand *IndexStmt,theresultlistmaycontainTableLikeClause(s),representing *theneedtoperformadditionalparseanalysisafterDefineRelation(). * *SQLallowsconstraintstobescatteredallover,sothumbthrough *thecolumnsandcollectallconstraintsintooneplace. *Ifthereareanyimpliedindices(e.g.UNIQUEorPRIMARYKEY) *thenexpandthoseintomultipleIndexStmtblocks. *-thomas1997-12-02
*/
List *
transformCreateStmt(CreateStmt *stmt, constchar *queryString)
{
ParseState *pstate;
CreateStmtContext cxt;
List *result;
List *save_alist;
ListCell *elements;
Oid namespaceid;
Oid existing_relid;
ParseCallbackState pcbstate;
/* Set up pstate */
pstate = make_parsestate(NULL);
pstate->p_sourcetext = queryString;
ereport(DEBUG1,
(errmsg_internal("%s will create implicit sequence \"%s\" for serial column \"%s.%s\"",
cxt->stmtType, sname,
cxt->relation->relname, column->colname)));
/* *Determinethepersistenceofthesequence.Bydefaultwecopythe *persistenceofthetable,butifLOGGEDorUNLOGGEDwasspecified,use *that(aslongasthetableisn'tTEMP). * *ForCREATETABLE,wegetthepersistencefromcxt->relation,which *comesfromtheCreateStmtinprogress.ForALTERTABLE,theparser *won'tsetcxt->relation->relpersistence,butwehavecxt->relasthe *existingtable,sowecopythepersistencefromthere.
*/
seqpersistence = cxt->rel ? cxt->rel->rd_rel->relpersistence : cxt->relation->relpersistence; if (loggedEl)
{ if (seqpersistence == RELPERSISTENCE_TEMP)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("cannot set logged status of a temporary sequence"),
parser_errposition(cxt->pstate, loggedEl->location))); elseif (strcmp(loggedEl->defname, "logged") == 0)
seqpersistence = RELPERSISTENCE_PERMANENT; else
seqpersistence = RELPERSISTENCE_UNLOGGED;
}
/* *Wehavetoreject"serial[]"explicitly,becauseoncewe'veset *typeid,LookupTypeNamewon'tnoticearrayBounds.Wedon'tneedany *specialcodingforserial(typmod)though.
*/ if (is_serial && column->typeName->arrayBounds != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("array of serial is not implemented"),
parser_errposition(cxt->pstate,
column->typeName->location)));
}
/* Do necessary work on the column type declaration */ if (column->typeName)
transformColumnType(cxt, column);
/* Special actions for SERIAL pseudo-types */ if (is_serial)
{ char *snamespace; char *sname; char *qstring;
A_Const *snamenode;
TypeCast *castnode;
FuncCall *funccallnode;
Constraint *constraint;
/* Now scan them again to do full processing */
saw_nullable = false;
saw_default = false;
saw_identity = false;
saw_generated = false;
foreach_node(Constraint, constraint, column->constraints)
{ switch (constraint->contype)
{ case CONSTR_NULL: if ((saw_nullable && column->is_not_null) || need_notnull)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
column->colname, cxt->relation->relname),
parser_errposition(cxt->pstate,
constraint->location)));
column->is_not_null = false;
saw_nullable = true; break;
case CONSTR_NOTNULL: if (cxt->ispartitioned && constraint->is_no_inherit)
ereport(ERROR,
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("not-null constraints on partitioned tables cannot be NO INHERIT"));
/* Disallow conflicting [NOT] NULL markings */ if (saw_nullable && !column->is_not_null)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
column->colname, cxt->relation->relname),
parser_errposition(cxt->pstate,
constraint->location)));
if (disallow_noinherit_notnull && constraint->is_no_inherit)
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting NO INHERIT declarations for not-null constraints on column \"%s\"",
column->colname));
if (notnull_constraint->is_no_inherit != constraint->is_no_inherit)
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting NO INHERIT declarations for not-null constraints on column \"%s\"",
column->colname));
if (!notnull_constraint->conname && constraint->conname)
notnull_constraint->conname = constraint->conname;
}
break;
case CONSTR_DEFAULT: if (saw_default)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("multiple default values specified for column \"%s\" of table \"%s\"",
column->colname, cxt->relation->relname),
parser_errposition(cxt->pstate,
constraint->location)));
column->raw_default = constraint->raw_expr;
Assert(constraint->cooked_expr == NULL);
saw_default = true; break;
case CONSTR_IDENTITY:
{
Type ctype;
Oid typeOid;
if (cxt->ofType)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("identity columns are not supported on typed tables"))); if (cxt->partbound)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("identity columns are not supported on partitions")));
/* *IdentitycolumnsarealwaysNOTNULL,butwemayhavea *constraintalready.
*/ if (!saw_nullable)
need_notnull = true; elseif (!column->is_not_null)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
column->colname, cxt->relation->relname),
parser_errposition(cxt->pstate,
constraint->location))); break;
}
case CONSTR_GENERATED: if (cxt->ofType)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("generated columns are not supported on typed tables"))); if (saw_generated)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("multiple generation clauses specified for column \"%s\" of table \"%s\"",
column->colname, cxt->relation->relname),
parser_errposition(cxt->pstate,
constraint->location)));
column->generated = constraint->generated_kind;
column->raw_default = constraint->raw_expr;
Assert(constraint->cooked_expr == NULL);
saw_generated = true; break;
case CONSTR_CHECK:
cxt->ckconstraints = lappend(cxt->ckconstraints, constraint); break;
case CONSTR_PRIMARY: if (saw_nullable && !column->is_not_null)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
column->colname, cxt->relation->relname),
parser_errposition(cxt->pstate,
constraint->location)));
need_notnull = true;
if (cxt->isforeign)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("primary key constraints are not supported on foreign tables"),
parser_errposition(cxt->pstate,
constraint->location))); /* FALL THRU */
case CONSTR_UNIQUE: if (cxt->isforeign)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unique constraints are not supported on foreign tables"),
parser_errposition(cxt->pstate,
constraint->location))); if (constraint->keys == NIL)
constraint->keys = list_make1(makeString(column->colname));
cxt->ixconstraints = lappend(cxt->ixconstraints, constraint); break;
case CONSTR_EXCLUSION: /* grammar does not allow EXCLUDE as a column constraint */
elog(ERROR, "column exclusion constraints are not supported"); break;
case CONSTR_FOREIGN: if (cxt->isforeign)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("foreign key constraints are not supported on foreign tables"),
parser_errposition(cxt->pstate,
constraint->location)));
case CONSTR_ATTR_DEFERRABLE: case CONSTR_ATTR_NOT_DEFERRABLE: case CONSTR_ATTR_DEFERRED: case CONSTR_ATTR_IMMEDIATE: case CONSTR_ATTR_ENFORCED: case CONSTR_ATTR_NOT_ENFORCED: /* transformConstraintAttrs took care of these */ break;
/* *transformTableConstraint *transformaConstraintnodewithinCREATETABLEorALTERTABLE
*/ staticvoid
transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
{ switch (constraint->contype)
{ case CONSTR_PRIMARY: if (cxt->isforeign)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("primary key constraints are not supported on foreign tables"),
parser_errposition(cxt->pstate,
constraint->location)));
cxt->ixconstraints = lappend(cxt->ixconstraints, constraint); break;
case CONSTR_UNIQUE: if (cxt->isforeign)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("unique constraints are not supported on foreign tables"),
parser_errposition(cxt->pstate,
constraint->location)));
cxt->ixconstraints = lappend(cxt->ixconstraints, constraint); break;
case CONSTR_EXCLUSION: if (cxt->isforeign)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("exclusion constraints are not supported on foreign tables"),
parser_errposition(cxt->pstate,
constraint->location)));
cxt->ixconstraints = lappend(cxt->ixconstraints, constraint); break;
case CONSTR_CHECK:
cxt->ckconstraints = lappend(cxt->ckconstraints, constraint); break;
case CONSTR_NOTNULL: if (cxt->ispartitioned && constraint->is_no_inherit)
ereport(ERROR,
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("not-null constraints on partitioned tables cannot be NO INHERIT"));
case CONSTR_FOREIGN: if (cxt->isforeign)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("foreign key constraints are not supported on foreign tables"),
parser_errposition(cxt->pstate,
constraint->location)));
cxt->fkconstraints = lappend(cxt->fkconstraints, constraint); break;
case CONSTR_NULL: case CONSTR_DEFAULT: case CONSTR_ATTR_DEFERRABLE: case CONSTR_ATTR_NOT_DEFERRABLE: case CONSTR_ATTR_DEFERRED: case CONSTR_ATTR_IMMEDIATE: case CONSTR_ATTR_ENFORCED: case CONSTR_ATTR_NOT_ENFORCED:
elog(ERROR, "invalid context for constraint type %d",
constraint->contype); break;
/* *OpentherelationreferencedbytheLIKEclause.Weshouldstillhave *thetablelockobtainedbytransformTableLikeClause(andthis'llthrow *anassertionfailureifnot).Hence,noneedtorecheckprivileges *etc.WemustopentherelbyOIDnotname,tobesurewegetthesame *table.
*/ if (!OidIsValid(table_like_clause->relationOid))
elog(ERROR, "expandTableLikeClause called on untransformed LIKE clause");
this_default = TupleDescGetDefault(tupleDesc, parent_attno); if (this_default == NULL)
elog(ERROR, "default expression not found for attribute %d of relation \"%s\"",
parent_attno, RelationGetRelationName(relation));
for (i = 0; i < nElems; i++)
{
Oid operid = DatumGetObjectId(elems[i]);
HeapTuple opertup;
Form_pg_operator operform; char *oprname; char *nspname;
List *namelist;
opertup = SearchSysCache1(OPEROID,
ObjectIdGetDatum(operid)); if (!HeapTupleIsValid(opertup))
elog(ERROR, "cache lookup failed for operator %u",
operid);
operform = (Form_pg_operator) GETSTRUCT(opertup);
oprname = pstrdup(NameStr(operform->oprname)); /* For simplicity we always schema-qualify the op name */
nspname = get_namespace_name(operform->oprnamespace);
namelist = list_make2(makeString(nspname),
makeString(oprname));
index->excludeOpNames = lappend(index->excludeOpNames,
namelist);
ReleaseSysCache(opertup);
}
}
/* Get the index expressions, if any */
datum = SysCacheGetAttr(INDEXRELID, ht_idx,
Anum_pg_index_indexprs, &isnull); if (!isnull)
{ char *exprsString;
if (AttributeNumberIsValid(attnum))
{ /* Simple index column */ char *attname;
attname = get_attname(indrelid, attnum, false);
iparam->name = attname;
iparam->expr = NULL;
} else
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("expressions are not supported in included columns")));
/* Copy the original index column name */
iparam->indexcolname = pstrdup(NameStr(attr->attname));
index->indexIncludingParams = lappend(index->indexIncludingParams, iparam);
} /* Copy reloptions if any */
datum = SysCacheGetAttr(RELOID, ht_idxrel,
Anum_pg_class_reloptions, &isnull); if (!isnull)
index->options = untransformRelOptions(datum);
/* If it's a partial index, decompile and append the predicate */
datum = SysCacheGetAttr(INDEXRELID, ht_idx,
Anum_pg_index_indpred, &isnull); if (!isnull)
{ char *pred_str;
Node *pred_tree; bool found_whole_row;
/* Convert text string to node tree */
pred_str = TextDatumGetCString(datum);
pred_tree = (Node *) stringToNode(pred_str);
/* Adjust Vars to match new table's column numbering */
pred_tree = map_variable_attnos(pred_tree, 1, 0,
attmap,
InvalidOid, &found_whole_row);
/* As in expandTableLikeClause, reject whole-row variables */ if (found_whole_row)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot convert whole-row table reference"),
errdetail("Index \"%s\" contains a whole-row table reference.",
RelationGetRelationName(source_idx))));
index->whereClause = pred_tree;
}
/* Clean up */
ReleaseSysCache(ht_idxrel);
ReleaseSysCache(ht_am);
return index;
}
/* *GenerateaCreateStatsStmtnodeusinginformationfromanalreadyexisting *extendedstatistic"source_statsid",fortherelidentifiedbyheapReland *heapRelid. * *stxkeysinthesourcestatisticholdsattributenumbersfromtheparent *relation.Thoseattnums,alongwiththeattributenumbersreferencedby *Varsinsidetheexpressiontree,areremappedtothenewrelation's *numberingaccordingtoattmap.
*/ static CreateStatsStmt *
generateClonedExtStatsStmt(RangeVar *heapRel, Oid heapRelid,
Oid source_statsid, const AttrMap *attmap)
{
HeapTuple ht_stats;
Form_pg_statistic_ext statsrec;
CreateStatsStmt *stats;
List *stat_types = NIL;
List *def_names = NIL; bool isnull;
Datum datum;
ArrayType *arr; char *enabled; int i;
/* Determine which statistics types exist */
datum = SysCacheGetAttrNotNull(STATEXTOID, ht_stats,
Anum_pg_statistic_ext_stxkind);
arr = DatumGetArrayTypeP(datum); if (ARR_NDIM(arr) != 1 ||
ARR_HASNULL(arr) ||
ARR_ELEMTYPE(arr) != CHAROID)
elog(ERROR, "stxkind is not a 1-D char array");
enabled = (char *) ARR_DATA_PTR(arr); for (i = 0; i < ARR_DIMS(arr)[0]; i++)
{ if (enabled[i] == STATS_EXT_NDISTINCT)
stat_types = lappend(stat_types, makeString("ndistinct")); elseif (enabled[i] == STATS_EXT_DEPENDENCIES)
stat_types = lappend(stat_types, makeString("dependencies")); elseif (enabled[i] == STATS_EXT_MCV)
stat_types = lappend(stat_types, makeString("mcv")); elseif (enabled[i] == STATS_EXT_EXPRESSIONS) /* expression stats are not exposed to users */ continue; else
elog(ERROR, "unrecognized statistics kind %c", enabled[i]);
}
/* Determine which columns the statistics are on */ for (i = 0; i < statsrec->stxkeys.dim1; i++)
{
StatsElem *selem = makeNode(StatsElem);
AttrNumber attnum = statsrec->stxkeys.values[i];
/* *get_collation-fetchqualifiednameofacollation * *IfcollationisInvalidOidoristhedefaultforthegivenactual_datatype, *thenthereturnvalueisNIL.
*/ static List *
get_collation(Oid collation, Oid actual_datatype)
{
List *result;
HeapTuple ht_coll;
Form_pg_collation coll_rec; char *nsp_name; char *coll_name;
if (!OidIsValid(collation)) return NIL; /* easy case */ if (collation == get_typcollation(actual_datatype)) return NIL; /* just let it default */
ht_coll = SearchSysCache1(COLLOID, ObjectIdGetDatum(collation)); if (!HeapTupleIsValid(ht_coll))
elog(ERROR, "cache lookup failed for collation %u", collation);
coll_rec = (Form_pg_collation) GETSTRUCT(ht_coll);
/* For simplicity, we always schema-qualify the name */
nsp_name = get_namespace_name(coll_rec->collnamespace);
coll_name = pstrdup(NameStr(coll_rec->collname));
result = list_make2(makeString(nsp_name), makeString(coll_name));
ReleaseSysCache(ht_coll); return result;
}
/* *get_opclass-fetchqualifiednameofanindexoperatorclass * *Iftheopclassisthedefaultforthegivenactual_datatype,then *thereturnvalueisNIL.
*/ static List *
get_opclass(Oid opclass, Oid actual_datatype)
{
List *result = NIL;
HeapTuple ht_opc;
Form_pg_opclass opc_rec;
ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass)); if (!HeapTupleIsValid(ht_opc))
elog(ERROR, "cache lookup failed for opclass %u", opclass);
opc_rec = (Form_pg_opclass) GETSTRUCT(ht_opc);
if (GetDefaultOpClass(actual_datatype, opc_rec->opcmethod) != opclass)
{ /* For simplicity, we always schema-qualify the name */ char *nsp_name = get_namespace_name(opc_rec->opcnamespace); char *opc_name = pstrdup(NameStr(opc_rec->opcname));
result = list_make2(makeString(nsp_name), makeString(opc_name));
}
index = transformIndexConstraint(constraint, cxt);
indexlist = lappend(indexlist, index);
}
/* *Scantheindexlistandremoveanyredundantindexspecifications.This *canhappenif,forinstance,theuserwritesUNIQUEPRIMARYKEY.A *strictreadingofSQLwouldsuggestraisinganerrorinstead,butthat *strikesmeastooanal-retentive.-tgl2001-02-14 * *XXXinALTERTABLEcase,it'dbenicetolookforduplicate *pre-existingindexes,too.
*/ if (cxt->pkey != NULL)
{ /* Make sure we keep the PKEY index in preference to others... */
finalindexlist = list_make1(cxt->pkey);
}
/* *Ifit'sALTERTABLEADDCONSTRAINTUSINGINDEX,lookuptheindexand *verifyit'susable,thenextracttheimpliedcolumnnamelist.(We *willnotactuallyneedthecolumnnamelistatruntime,butweneedit *nowtocheckforduplicatecolumnentriesbelow.)
*/ if (constraint->indexname != NULL)
{ char *index_name = constraint->indexname;
Relation heap_rel = cxt->rel;
Oid index_oid;
Relation index_rel;
Form_pg_index index_form;
oidvector *indclass;
Datum indclassDatum; int i;
/* Grammar should not allow this with explicit column list */
Assert(constraint->keys == NIL);
/* Grammar should only allow PRIMARY and UNIQUE constraints */
Assert(constraint->contype == CONSTR_PRIMARY ||
constraint->contype == CONSTR_UNIQUE);
/* Must be ALTER, not CREATE, but grammar doesn't enforce that */ if (!cxt->isalter)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot use an existing index in CREATE TABLE"),
parser_errposition(cxt->pstate, constraint->location)));
/* Look for the index in the same schema as the table */
index_oid = get_relname_relid(index_name, RelationGetNamespace(heap_rel));
if (!OidIsValid(index_oid))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("index \"%s\" does not exist", index_name),
parser_errposition(cxt->pstate, constraint->location)));
/* Open the index (this will throw an error if it is not an index) */
index_rel = index_open(index_oid, AccessShareLock);
index_form = index_rel->rd_index;
/* Check that it does not have an associated constraint already */ if (OidIsValid(get_index_constraint(index_oid)))
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("index \"%s\" is already associated with a constraint",
index_name),
parser_errposition(cxt->pstate, constraint->location)));
/* Perform validity checks on the index */ if (index_form->indrelid != RelationGetRelid(heap_rel))
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("index \"%s\" does not belong to table \"%s\"",
index_name, RelationGetRelationName(heap_rel)),
parser_errposition(cxt->pstate, constraint->location)));
if (!index_form->indisvalid)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("index \"%s\" is not valid", index_name),
parser_errposition(cxt->pstate, constraint->location)));
/* *Todayweforbidnon-uniqueindexes,butwecouldpermitGiST *indexeswhoselastentryisarangetypeandusethattocreatea *WITHOUTOVERLAPSconstraint(i.e.atemporalconstraint).
*/ if (!index_form->indisunique)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is not a unique index", index_name),
errdetail("Cannot create a primary key or unique constraint using such an index."),
parser_errposition(cxt->pstate, constraint->location)));
if (RelationGetIndexExpressions(index_rel) != NIL)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("index \"%s\" contains expressions", index_name),
errdetail("Cannot create a primary key or unique constraint using such an index."),
parser_errposition(cxt->pstate, constraint->location)));
if (RelationGetIndexPredicate(index_rel) != NIL)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is a partial index", index_name),
errdetail("Cannot create a primary key or unique constraint using such an index."),
parser_errposition(cxt->pstate, constraint->location)));
/* *It'sprobablyunsafetochangeadeferredindextonon-deferred.(A *non-constraintindexcouldn'tbedeferredanyway,sothiscase *shouldneveroccur;noneedtosweat,butlet'scheckit.)
*/ if (!index_form->indimmediate && !constraint->deferrable)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" is a deferrable index", index_name),
errdetail("Cannot create a non-deferrable constraint using a deferrable index."),
parser_errposition(cxt->pstate, constraint->location)));
/* *Insistonitbeingabtree.Wemusthaveanindexthatexactly *matcheswhatyou'dgetfromplainADDCONSTRAINTsyntax,elsedump *andreloadwillproduceadifferentindex(breakingpg_upgradein *particular).
*/ if (index_rel->rd_rel->relam != get_index_am_oid(DEFAULT_INDEX_TYPE, false))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("index \"%s\" is not a btree", index_name),
parser_errposition(cxt->pstate, constraint->location)));
/* Must get indclass the hard way */
indclassDatum = SysCacheGetAttrNotNull(INDEXRELID,
index_rel->rd_indextuple,
Anum_pg_index_indclass);
indclass = (oidvector *) DatumGetPointer(indclassDatum);
for (i = 0; i < index_form->indnatts; i++)
{
int16 attnum = index_form->indkey.values[i]; const FormData_pg_attribute *attform; char *attname;
Oid defopclass;
if (i < index_form->indnkeyatts)
{ /* *Insistondefaultopclass,collation,andsortoptions. *Whiletheindexwouldstillworkasaconstraintwith *non-defaultsettings,itmightnotprovideexactlythesame *uniquenesssemanticsasyou'dgetfromanormally-created *constraint;andthere'salsothedump/reloadproblem *mentionedabove.
*/
Datum attoptions =
get_attoptions(RelationGetRelid(index_rel), i + 1);
defopclass = GetDefaultOpClass(attform->atttypid,
index_rel->rd_rel->relam); if (indclass->values[i] != defopclass ||
attform->attcollation != index_rel->rd_indcollation[i] ||
attoptions != (Datum) 0 ||
index_rel->rd_indoption[i] != 0)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("index \"%s\" column number %d does not have default sorting behavior", index_name, i + 1),
errdetail("Cannot create a primary key or unique constraint using such an index."),
parser_errposition(cxt->pstate, constraint->location)));
/* If a PK, ensure the columns get not null constraints */ if (constraint->contype == CONSTR_PRIMARY)
cxt->nnconstraints =
lappend(cxt->nnconstraints,
makeNotNullConstraint(makeString(attname)));
rel = table_openrv(inh, AccessShareLock); /* check user requested inheritance from valid relkind */ if (rel->rd_rel->relkind != RELKIND_RELATION &&
rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("inherited relation \"%s\" is not a table or foreign table",
inh->relname))); for (count = 0; count < rel->rd_att->natts; count++)
{
Form_pg_attribute inhattr = TupleDescAttr(rel->rd_att,
count); char *inhname = NameStr(inhattr->attname);
if (inhattr->attisdropped) continue; if (strcmp(key, inhname) == 0)
{
found = true;
typid = inhattr->atttypid;
if (constraint->contype == CONSTR_PRIMARY)
cxt->nnconstraints =
lappend(cxt->nnconstraints,
makeNotNullConstraint(makeString(pstrdup(inhname)))); break;
}
}
table_close(rel, NoLock); if (found) break;
}
}
/* *IntheALTERTABLEcase,don'tcomplainaboutindexkeysnot *createdinthecommand;theymaywellexistalready. *DefineIndexwillcomplainaboutthemifnot.
*/ if (!found && !cxt->isalter)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" named in key does not exist", key),
parser_errposition(cxt->pstate, constraint->location)));
for (int i = 0; i < rel->rd_att->natts; i++)
{
Form_pg_attribute attr = TupleDescAttr(rel->rd_att, i); constchar *attname;
if (attr->attisdropped) continue;
attname = NameStr(attr->attname); if (strcmp(attname, key) == 0)
{
found = true;
typid = attr->atttypid; break;
}
}
} if (found)
{ /* Look up column type if we didn't already */ if (!OidIsValid(typid) && column)
typid = typenameTypeId(cxt->pstate,
column->typeName); /* Look through any domain */ if (OidIsValid(typid))
typid = getBaseType(typid); /* Complain if not range/multirange */ if (!OidIsValid(typid) ||
!(type_is_range(typid) || type_is_multirange(typid)))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("column \"%s\" in WITHOUT OVERLAPS is not a range or multirange type", key),
parser_errposition(cxt->pstate, constraint->location)));
}
}
if (constraint->without_overlaps)
{ /* *Thisenforcesthatthereisatleastoneequalitycolumn *besidestheWITHOUTOVERLAPScolumns.ThisisperSQL *standard.XXXDoweneedthis?
*/ if (list_length(constraint->keys) < 2)
ereport(ERROR,
errcode(ERRCODE_SYNTAX_ERROR),
errmsg("constraint using WITHOUT OVERLAPS needs at least two columns"));
/* WITHOUT OVERLAPS requires a GiST index */
index->accessMethod = "gist";
}
rel = table_openrv(inh, AccessShareLock); /* check user requested inheritance from valid relkind */ if (rel->rd_rel->relkind != RELKIND_RELATION &&
rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("inherited relation \"%s\" is not a table or foreign table",
inh->relname))); for (count = 0; count < rel->rd_att->natts; count++)
{
Form_pg_attribute inhattr = TupleDescAttr(rel->rd_att,
count); char *inhname = NameStr(inhattr->attname);
if (inhattr->attisdropped) continue; if (strcmp(key, inhname) == 0)
{
found = true; break;
}
}
table_close(rel, NoLock); if (found) break;
}
}
}
/* *IntheALTERTABLEcase,don'tcomplainaboutindexkeysnot *createdinthecommand;theymaywellexistalready.DefineIndex *willcomplainaboutthemifnot.
*/ if (!found && !cxt->isalter)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" named in key does not exist", key),
parser_errposition(cxt->pstate, constraint->location)));
/* OK, add it to the index definition */
iparam = makeNode(IndexElem);
iparam->name = pstrdup(key);
iparam->expr = NULL;
iparam->indexcolname = NULL;
iparam->collation = NIL;
iparam->opclass = NIL;
iparam->opclassopts = NIL;
index->indexIncludingParams = lappend(index->indexIncludingParams, iparam);
}
/* no to join list, yes to namespaces */
addNSItemToQuery(pstate, nsitem, false, true, true);
/* take care of the where clause */ if (stmt->whereClause)
{
stmt->whereClause = transformWhereClause(pstate,
stmt->whereClause,
EXPR_KIND_INDEX_PREDICATE, "WHERE"); /* we have to fix its collations too */
assign_expr_collations(pstate, stmt->whereClause);
}
/* take care of any index expressions */
foreach(l, stmt->indexParams)
{
IndexElem *ielem = (IndexElem *) lfirst(l);
if (ielem->expr)
{ /* Extract preliminary index col name before transforming expr */ if (ielem->indexcolname == NULL)
ielem->indexcolname = FigureIndexColname(ielem->expr);
/* Now do parse transformation of the expression */
ielem->expr = transformExpr(pstate, ielem->expr,
EXPR_KIND_INDEX_EXPRESSION);
/* We have to fix its collations too */
assign_expr_collations(pstate, ielem->expr);
/* *Checkthatonlythebaserelismentioned.(Thisshouldbedeadcode *nowthatadd_missing_fromishistory.)
*/ if (list_length(pstate->p_rtable) != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("index expressions and predicates can refer only to the table being indexed")));
free_parsestate(pstate);
/* Close relation */
table_close(rel, NoLock);
/* Mark statement as successfully transformed */
stmt->transformed = true;
/* no to join list, yes to namespaces */
addNSItemToQuery(pstate, nsitem, false, true, true);
/* take care of any expressions */
foreach(l, stmt->exprs)
{
StatsElem *selem = (StatsElem *) lfirst(l);
if (selem->expr)
{ /* Now do parse transformation of the expression */
selem->expr = transformExpr(pstate, selem->expr,
EXPR_KIND_STATS_EXPRESSION);
/* We have to fix its collations too */
assign_expr_collations(pstate, selem->expr);
}
}
/* *Checkthatonlythebaserelismentioned.(Thisshouldbedeadcode *nowthatadd_missing_fromishistory.)
*/ if (list_length(pstate->p_rtable) != 1)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("statistics expressions can refer only to the table being referenced")));
free_parsestate(pstate);
/* Close relation */
table_close(rel, NoLock);
/* Mark statement as successfully transformed */
stmt->transformed = true;
if (rel->rd_rel->relkind == RELKIND_MATVIEW)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("rules on materialized views are not supported")));
/* Set up pstate */
pstate = make_parsestate(NULL);
pstate->p_sourcetext = queryString;
/* take care of the where clause */
*whereClause = transformWhereClause(pstate,
stmt->whereClause,
EXPR_KIND_WHERE, "WHERE"); /* we have to fix its collations too */
assign_expr_collations(pstate, *whereClause);
/* this is probably dead code without add_missing_from: */ if (list_length(pstate->p_rtable) != 2) /* naughty, naughty... */
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("rule WHERE condition cannot contain references to other relations")));
/* *Wecannotsupportutility-statementactions(egNOTIFY)with *nonemptyruleWHEREconditions,becausethere'snowaytomake *theutilityactionexecuteconditionally.
*/ if (top_subqry->commandType == CMD_UTILITY &&
*whereClause != NULL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("rules with WHERE conditions can only have SELECT, INSERT, UPDATE, or DELETE actions")));
switch (stmt->event)
{ case CMD_SELECT: if (has_old)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("ON SELECT rule cannot use OLD"))); if (has_new)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("ON SELECT rule cannot use NEW"))); break; case CMD_UPDATE: /* both are OK */ break; case CMD_INSERT: if (has_old)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("ON INSERT rule cannot use OLD"))); break; case CMD_DELETE: if (has_new)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("ON DELETE rule cannot use NEW"))); break; default:
elog(ERROR, "unrecognized event type: %d",
(int) stmt->event); break;
}
/* *OLD/NEWarenotallowedinWITHqueries,becausetheywould *amounttoouterreferencesfortheWITH,whichwedisallow. *However,theywerealreadyintheouterrangetablewhenwe *analyzedthequery,sowehavetocheck. * *NotethatintheINSERT...SELECTcase,weneedtoexaminethe *CTElistsofbothtop_subqryandsub_qry. * *Notethatwearen'tdiggingintothebodyofthequerylooking *forWITHsinnestedsub-SELECTs.AWITHdowntherecan *legitimatelyrefertoOLD/NEW,becauseit'dbean *indirect-correlatedouterreference.
*/ if (rangeTableEntry_used((Node *) top_subqry->cteList,
PRS2_OLD_VARNO, 0) ||
rangeTableEntry_used((Node *) sub_qry->cteList,
PRS2_OLD_VARNO, 0))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot refer to OLD within WITH query"))); if (rangeTableEntry_used((Node *) top_subqry->cteList,
PRS2_NEW_VARNO, 0) ||
rangeTableEntry_used((Node *) sub_qry->cteList,
PRS2_NEW_VARNO, 0))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot refer to NEW within WITH query")));
attnum = get_attnum(relid, cmd->name); if (attnum == InvalidAttrNumber)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
cmd->name, RelationGetRelationName(rel))));
attnum = get_attnum(relid, cmd->name); if (attnum == InvalidAttrNumber)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of relation \"%s\" does not exist",
cmd->name, RelationGetRelationName(rel))));
if (column->collClause)
{
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(ctype);
LookupCollation(cxt->pstate,
column->collClause->collname,
column->collClause->location); /* Complain if COLLATE is applied to an uncollatable type */ if (!OidIsValid(typtup->typcollation))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("collations are not supported by type %s",
format_type_be(typtup->oid)),
parser_errposition(cxt->pstate,
column->collClause->location)));
}
result = NIL;
result = list_concat(result, cxt.sequences);
result = list_concat(result, cxt.tables);
result = list_concat(result, cxt.views);
result = list_concat(result, cxt.indexes);
result = list_concat(result, cxt.triggers);
result = list_concat(result, cxt.grants);
return result;
}
/* *setSchemaName *SetorcheckschemanameinanelementofaCREATESCHEMAcommand
*/ staticvoid
setSchemaName(constchar *context_schema, char **stmt_schema_name)
{ if (*stmt_schema_name == NULL)
*stmt_schema_name = unconstify(char *, context_schema); elseif (strcmp(context_schema, *stmt_schema_name) != 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_SCHEMA_DEFINITION),
errmsg("CREATE specifies a schema (%s) " "different from the one being created (%s)",
*stmt_schema_name, context_schema)));
}
switch (parentRel->rd_rel->relkind)
{ case RELKIND_PARTITIONED_TABLE: /* transform the partition bound, if any */
Assert(RelationGetPartitionKey(parentRel) != NULL); if (cmd->bound != NULL)
cxt->partbound = transformPartitionBound(cxt->pstate, parentRel,
cmd->bound); break; case RELKIND_PARTITIONED_INDEX:
/* *Apartitionedindexcannothaveapartitionboundset.ALTER *INDEXpreventsthatwithitsgrammar,butnotALTERTABLE.
*/ if (cmd->bound != NULL)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("\"%s\" is not a partitioned table",
RelationGetRelationName(parentRel)))); break; case RELKIND_RELATION: /* the table must be partitioned */
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("table \"%s\" is not partitioned",
RelationGetRelationName(parentRel)))); break; case RELKIND_INDEX: /* the index must be partitioned */
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("index \"%s\" is not partitioned",
RelationGetRelationName(parentRel)))); break; default: /* parser shouldn't let this case through */
elog(ERROR, "\"%s\" is not a partitioned table or index",
RelationGetRelationName(parentRel)); break;
}
}
/* Avoid scribbling on input */
result_spec = copyObject(spec);
if (spec->is_default)
{ /* *Hashpartitioningdoesnotsupportadefaultpartition;there'sno *usecaseforit(sincethesetofpartitionstocreateisperfectly *defined),andifusersdogetintoitaccidentally,it'shardto *backoutfromitafterwards.
*/ if (strategy == PARTITION_STRATEGY_HASH)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("a hash-partitioned table may not have a default partition")));
if (strategy == PARTITION_STRATEGY_HASH)
{ if (spec->strategy != PARTITION_STRATEGY_HASH)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("invalid bound specification for a hash partition"),
parser_errposition(pstate, exprLocation((Node *) spec))));
if (spec->modulus <= 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("modulus for hash partition must be an integer value greater than zero")));
Assert(spec->remainder >= 0);
if (spec->remainder >= spec->modulus)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("remainder for hash partition must be less than modulus")));
} elseif (strategy == PARTITION_STRATEGY_LIST)
{
ListCell *cell; char *colname;
Oid coltype;
int32 coltypmod;
Oid partcollation;
if (spec->strategy != PARTITION_STRATEGY_LIST)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("invalid bound specification for a list partition"),
parser_errposition(pstate, exprLocation((Node *) spec))));
/* Get the only column's name in case we need to output an error */ if (key->partattrs[0] != 0)
colname = get_attname(RelationGetRelid(parent),
key->partattrs[0], false); else
colname = deparse_expression((Node *) linitial(partexprs),
deparse_context_for(RelationGetRelationName(parent),
RelationGetRelid(parent)), false, false); /* Need its type data too */
coltype = get_partition_col_typid(key, 0);
coltypmod = get_partition_col_typmod(key, 0);
partcollation = get_partition_col_collation(key, 0);
value = transformPartitionBoundValue(pstate, expr,
colname, coltype, coltypmod,
partcollation);
/* Don't add to the result if the value is a duplicate */
duplicate = false;
foreach(cell2, result_spec->listdatums)
{ Const *value2 = lfirst_node(Const, cell2);
if (equal(value, value2))
{
duplicate = true; break;
}
} if (duplicate) continue;
result_spec->listdatums = lappend(result_spec->listdatums,
value);
}
} elseif (strategy == PARTITION_STRATEGY_RANGE)
{ if (spec->strategy != PARTITION_STRATEGY_RANGE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("invalid bound specification for a range partition"),
parser_errposition(pstate, exprLocation((Node *) spec))));
if (list_length(spec->lowerdatums) != partnatts)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("FROM must specify exactly one value per partitioning column"))); if (list_length(spec->upperdatums) != partnatts)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("TO must specify exactly one value per partitioning column")));
if (prd == NULL)
{ char *colname;
Oid coltype;
int32 coltypmod;
Oid partcollation; Const *value;
/* Get the column's name in case we need to output an error */ if (key->partattrs[i] != 0)
colname = get_attname(RelationGetRelid(parent),
key->partattrs[i], false); else
{
colname = deparse_expression((Node *) list_nth(partexprs, j),
deparse_context_for(RelationGetRelationName(parent),
RelationGetRelid(parent)), false, false);
++j;
}
/* Need its type data too */
coltype = get_partition_col_typid(key, i);
coltypmod = get_partition_col_typmod(key, i);
partcollation = get_partition_col_collation(key, i);
value = transformPartitionBoundValue(pstate, expr,
colname,
coltype, coltypmod,
partcollation); if (value->constisnull)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("cannot specify NULL in range bound")));
prd = makeNode(PartitionRangeDatum);
prd->kind = PARTITION_RANGE_DATUM_VALUE;
prd->value = (Node *) value;
}
switch (kind)
{ case PARTITION_RANGE_DATUM_VALUE:
kind = prd->kind; break;
case PARTITION_RANGE_DATUM_MAXVALUE:
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("every bound following MAXVALUE must also be MAXVALUE"),
parser_errposition(pstate, exprLocation((Node *) prd)))); break;
case PARTITION_RANGE_DATUM_MINVALUE:
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("every bound following MINVALUE must also be MINVALUE"),
parser_errposition(pstate, exprLocation((Node *) prd)))); break;
}
}
}
/* *Transformoneentryinapartitionboundspec,producingaconstant.
*/ staticConst *
transformPartitionBoundValue(ParseState *pstate, Node *val, constchar *colName, Oid colType, int32 colTypmod,
Oid partCollation)
{
Node *value;
/* Transform raw parsetree */
value = transformExpr(pstate, val, EXPR_KIND_PARTITION_BOUND);
if (value == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("specified value cannot be cast to type %s for column \"%s\"",
format_type_be(colType), colName),
parser_errposition(pstate, exprLocation(val))));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.