PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
parse_utilcmd.c File Reference
Include dependency graph for parse_utilcmd.c:

Go to the source code of this file.

Data Structures

struct  CreateStmtContext
 
struct  CreateSchemaStmtContext
 

Macros

#define SUPPORTS_ATTRS(node)
 

Functions

static void transformColumnDefinition (CreateStmtContext *cxt, ColumnDef *column)
 
static void transformTableConstraint (CreateStmtContext *cxt, Constraint *constraint)
 
static void transformTableLikeClause (CreateStmtContext *cxt, TableLikeClause *table_like_clause)
 
static void transformOfType (CreateStmtContext *cxt, TypeName *ofTypename)
 
static IndexStmtgenerateClonedIndexStmt (CreateStmtContext *cxt, Relation source_idx, const AttrNumber *attmap, int attmap_length)
 
static Listget_collation (Oid collation, Oid actual_datatype)
 
static Listget_opclass (Oid opclass, Oid actual_datatype)
 
static void transformIndexConstraints (CreateStmtContext *cxt)
 
static IndexStmttransformIndexConstraint (Constraint *constraint, CreateStmtContext *cxt)
 
static void transformFKConstraints (CreateStmtContext *cxt, bool skipValidation, bool isAddConstraint)
 
static void transformCheckConstraints (CreateStmtContext *cxt, bool skipValidation)
 
static void transformConstraintAttrs (CreateStmtContext *cxt, List *constraintList)
 
static void transformColumnType (CreateStmtContext *cxt, ColumnDef *column)
 
static void setSchemaName (char *context_schema, char **stmt_schema_name)
 
static void transformPartitionCmd (CreateStmtContext *cxt, PartitionCmd *cmd)
 
ListtransformCreateStmt (CreateStmt *stmt, const char *queryString)
 
IndexStmttransformIndexStmt (Oid relid, IndexStmt *stmt, const char *queryString)
 
void transformRuleStmt (RuleStmt *stmt, const char *queryString, List **actions, Node **whereClause)
 
ListtransformAlterTableStmt (Oid relid, AlterTableStmt *stmt, const char *queryString)
 
ListtransformCreateSchemaStmt (CreateSchemaStmt *stmt)
 
NodetransformPartitionBound (ParseState *pstate, Relation parent, Node *bound)
 

Macro Definition Documentation

#define SUPPORTS_ATTRS (   node)
Value:
((node) != NULL && \
((node)->contype == CONSTR_PRIMARY || \
(node)->contype == CONSTR_UNIQUE || \
(node)->contype == CONSTR_EXCLUSION || \
(node)->contype == CONSTR_FOREIGN))
#define NULL
Definition: c.h:229

Referenced by transformConstraintAttrs().

Function Documentation

static IndexStmt * generateClonedIndexStmt ( CreateStmtContext cxt,
Relation  source_idx,
const AttrNumber attmap,
int  attmap_length 
)
static

Definition at line 1125 of file parse_utilcmd.c.

References IndexStmt::accessMethod, IndexAmRoutine::amcanorder, AMOID, Anum_pg_class_reloptions, Anum_pg_constraint_conexclop, Anum_pg_index_indclass, Anum_pg_index_indcollation, Anum_pg_index_indexprs, Anum_pg_index_indpred, Assert, AttributeNumberIsValid, IndexElem::collation, IndexStmt::concurrent, CONSTRAINT_EXCLUSION, CONSTROID, DatumGetArrayTypeP, DatumGetObjectId, DatumGetPointer, deconstruct_array(), IndexStmt::deferrable, elog, ereport, errcode(), errdetail(), errmsg(), ERROR, IndexStmt::excludeOpNames, IndexElem::expr, exprType(), get_atttype(), get_collation(), get_index_constraint(), get_namespace_name(), get_opclass(), get_relid_attribute_name(), get_tablespace_name(), GETSTRUCT, HeapTupleIsValid, i, IndexStmt::idxcomment, IndexStmt::idxname, IndexStmt::if_not_exists, IndexElem::indexcolname, IndexStmt::indexOid, IndexStmt::indexParams, INDEXRELID, INDOPTION_DESC, INDOPTION_NULLS_FIRST, IndexStmt::initdeferred, InvalidOid, IndexStmt::isconstraint, lappend(), lfirst, list_head(), list_make2, lnext, makeNode, makeString(), map_variable_attnos(), IndexElem::name, NameStr, NIL, NULL, IndexElem::nulls_ordering, ObjectIdGetDatum, OidIsValid, OIDOID, IndexStmt::oldNode, IndexElem::opclass, OPEROID, IndexStmt::options, IndexElem::ordering, IndexStmt::primary, pstrdup(), RelationData::rd_amroutine, RelationData::rd_indextuple, RelationData::rd_indoption, CreateStmtContext::relation, IndexStmt::relation, RelationGetDescr, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), RELOID, SearchSysCache1, SORTBY_DEFAULT, SORTBY_DESC, SORTBY_NULLS_DEFAULT, SORTBY_NULLS_FIRST, SORTBY_NULLS_LAST, stringToNode(), SysCacheGetAttr(), IndexStmt::tableSpace, TextDatumGetCString, IndexStmt::transformed, IndexStmt::unique, untransformRelOptions(), oidvector::values, and IndexStmt::whereClause.

Referenced by transformTableLikeClause().

1127 {
1128  Oid source_relid = RelationGetRelid(source_idx);
1129  Form_pg_attribute *attrs = RelationGetDescr(source_idx)->attrs;
1130  HeapTuple ht_idxrel;
1131  HeapTuple ht_idx;
1132  HeapTuple ht_am;
1133  Form_pg_class idxrelrec;
1134  Form_pg_index idxrec;
1135  Form_pg_am amrec;
1136  oidvector *indcollation;
1137  oidvector *indclass;
1138  IndexStmt *index;
1139  List *indexprs;
1140  ListCell *indexpr_item;
1141  Oid indrelid;
1142  int keyno;
1143  Oid keycoltype;
1144  Datum datum;
1145  bool isnull;
1146 
1147  /*
1148  * Fetch pg_class tuple of source index. We can't use the copy in the
1149  * relcache entry because it doesn't include optional fields.
1150  */
1151  ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(source_relid));
1152  if (!HeapTupleIsValid(ht_idxrel))
1153  elog(ERROR, "cache lookup failed for relation %u", source_relid);
1154  idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
1155 
1156  /* Fetch pg_index tuple for source index from relcache entry */
1157  ht_idx = source_idx->rd_indextuple;
1158  idxrec = (Form_pg_index) GETSTRUCT(ht_idx);
1159  indrelid = idxrec->indrelid;
1160 
1161  /* Fetch the pg_am tuple of the index' access method */
1162  ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam));
1163  if (!HeapTupleIsValid(ht_am))
1164  elog(ERROR, "cache lookup failed for access method %u",
1165  idxrelrec->relam);
1166  amrec = (Form_pg_am) GETSTRUCT(ht_am);
1167 
1168  /* Extract indcollation from the pg_index tuple */
1169  datum = SysCacheGetAttr(INDEXRELID, ht_idx,
1170  Anum_pg_index_indcollation, &isnull);
1171  Assert(!isnull);
1172  indcollation = (oidvector *) DatumGetPointer(datum);
1173 
1174  /* Extract indclass from the pg_index tuple */
1175  datum = SysCacheGetAttr(INDEXRELID, ht_idx,
1176  Anum_pg_index_indclass, &isnull);
1177  Assert(!isnull);
1178  indclass = (oidvector *) DatumGetPointer(datum);
1179 
1180  /* Begin building the IndexStmt */
1181  index = makeNode(IndexStmt);
1182  index->relation = cxt->relation;
1183  index->accessMethod = pstrdup(NameStr(amrec->amname));
1184  if (OidIsValid(idxrelrec->reltablespace))
1185  index->tableSpace = get_tablespace_name(idxrelrec->reltablespace);
1186  else
1187  index->tableSpace = NULL;
1188  index->excludeOpNames = NIL;
1189  index->idxcomment = NULL;
1190  index->indexOid = InvalidOid;
1191  index->oldNode = InvalidOid;
1192  index->unique = idxrec->indisunique;
1193  index->primary = idxrec->indisprimary;
1194  index->transformed = true; /* don't need transformIndexStmt */
1195  index->concurrent = false;
1196  index->if_not_exists = false;
1197 
1198  /*
1199  * We don't try to preserve the name of the source index; instead, just
1200  * let DefineIndex() choose a reasonable name. (If we tried to preserve
1201  * the name, we'd get duplicate-relation-name failures unless the source
1202  * table was in a different schema.)
1203  */
1204  index->idxname = NULL;
1205 
1206  /*
1207  * If the index is marked PRIMARY or has an exclusion condition, it's
1208  * certainly from a constraint; else, if it's not marked UNIQUE, it
1209  * certainly isn't. If it is or might be from a constraint, we have to
1210  * fetch the pg_constraint record.
1211  */
1212  if (index->primary || index->unique || idxrec->indisexclusion)
1213  {
1214  Oid constraintId = get_index_constraint(source_relid);
1215 
1216  if (OidIsValid(constraintId))
1217  {
1218  HeapTuple ht_constr;
1219  Form_pg_constraint conrec;
1220 
1221  ht_constr = SearchSysCache1(CONSTROID,
1222  ObjectIdGetDatum(constraintId));
1223  if (!HeapTupleIsValid(ht_constr))
1224  elog(ERROR, "cache lookup failed for constraint %u",
1225  constraintId);
1226  conrec = (Form_pg_constraint) GETSTRUCT(ht_constr);
1227 
1228  index->isconstraint = true;
1229  index->deferrable = conrec->condeferrable;
1230  index->initdeferred = conrec->condeferred;
1231 
1232  /* If it's an exclusion constraint, we need the operator names */
1233  if (idxrec->indisexclusion)
1234  {
1235  Datum *elems;
1236  int nElems;
1237  int i;
1238 
1239  Assert(conrec->contype == CONSTRAINT_EXCLUSION);
1240  /* Extract operator OIDs from the pg_constraint tuple */
1241  datum = SysCacheGetAttr(CONSTROID, ht_constr,
1243  &isnull);
1244  if (isnull)
1245  elog(ERROR, "null conexclop for constraint %u",
1246  constraintId);
1247 
1249  OIDOID, sizeof(Oid), true, 'i',
1250  &elems, NULL, &nElems);
1251 
1252  for (i = 0; i < nElems; i++)
1253  {
1254  Oid operid = DatumGetObjectId(elems[i]);
1255  HeapTuple opertup;
1256  Form_pg_operator operform;
1257  char *oprname;
1258  char *nspname;
1259  List *namelist;
1260 
1261  opertup = SearchSysCache1(OPEROID,
1262  ObjectIdGetDatum(operid));
1263  if (!HeapTupleIsValid(opertup))
1264  elog(ERROR, "cache lookup failed for operator %u",
1265  operid);
1266  operform = (Form_pg_operator) GETSTRUCT(opertup);
1267  oprname = pstrdup(NameStr(operform->oprname));
1268  /* For simplicity we always schema-qualify the op name */
1269  nspname = get_namespace_name(operform->oprnamespace);
1270  namelist = list_make2(makeString(nspname),
1271  makeString(oprname));
1272  index->excludeOpNames = lappend(index->excludeOpNames,
1273  namelist);
1274  ReleaseSysCache(opertup);
1275  }
1276  }
1277 
1278  ReleaseSysCache(ht_constr);
1279  }
1280  else
1281  index->isconstraint = false;
1282  }
1283  else
1284  index->isconstraint = false;
1285 
1286  /* Get the index expressions, if any */
1287  datum = SysCacheGetAttr(INDEXRELID, ht_idx,
1288  Anum_pg_index_indexprs, &isnull);
1289  if (!isnull)
1290  {
1291  char *exprsString;
1292 
1293  exprsString = TextDatumGetCString(datum);
1294  indexprs = (List *) stringToNode(exprsString);
1295  }
1296  else
1297  indexprs = NIL;
1298 
1299  /* Build the list of IndexElem */
1300  index->indexParams = NIL;
1301 
1302  indexpr_item = list_head(indexprs);
1303  for (keyno = 0; keyno < idxrec->indnatts; keyno++)
1304  {
1305  IndexElem *iparam;
1306  AttrNumber attnum = idxrec->indkey.values[keyno];
1307  int16 opt = source_idx->rd_indoption[keyno];
1308 
1309  iparam = makeNode(IndexElem);
1310 
1311  if (AttributeNumberIsValid(attnum))
1312  {
1313  /* Simple index column */
1314  char *attname;
1315 
1316  attname = get_relid_attribute_name(indrelid, attnum);
1317  keycoltype = get_atttype(indrelid, attnum);
1318 
1319  iparam->name = attname;
1320  iparam->expr = NULL;
1321  }
1322  else
1323  {
1324  /* Expressional index */
1325  Node *indexkey;
1326  bool found_whole_row;
1327 
1328  if (indexpr_item == NULL)
1329  elog(ERROR, "too few entries in indexprs list");
1330  indexkey = (Node *) lfirst(indexpr_item);
1331  indexpr_item = lnext(indexpr_item);
1332 
1333  /* Adjust Vars to match new table's column numbering */
1334  indexkey = map_variable_attnos(indexkey,
1335  1, 0,
1336  attmap, attmap_length,
1337  &found_whole_row);
1338 
1339  /* As in transformTableLikeClause, reject whole-row variables */
1340  if (found_whole_row)
1341  ereport(ERROR,
1342  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1343  errmsg("cannot convert whole-row table reference"),
1344  errdetail("Index \"%s\" contains a whole-row table reference.",
1345  RelationGetRelationName(source_idx))));
1346 
1347  iparam->name = NULL;
1348  iparam->expr = indexkey;
1349 
1350  keycoltype = exprType(indexkey);
1351  }
1352 
1353  /* Copy the original index column name */
1354  iparam->indexcolname = pstrdup(NameStr(attrs[keyno]->attname));
1355 
1356  /* Add the collation name, if non-default */
1357  iparam->collation = get_collation(indcollation->values[keyno], keycoltype);
1358 
1359  /* Add the operator class name, if non-default */
1360  iparam->opclass = get_opclass(indclass->values[keyno], keycoltype);
1361 
1362  iparam->ordering = SORTBY_DEFAULT;
1364 
1365  /* Adjust options if necessary */
1366  if (source_idx->rd_amroutine->amcanorder)
1367  {
1368  /*
1369  * If it supports sort ordering, copy DESC and NULLS opts. Don't
1370  * set non-default settings unnecessarily, though, so as to
1371  * improve the chance of recognizing equivalence to constraint
1372  * indexes.
1373  */
1374  if (opt & INDOPTION_DESC)
1375  {
1376  iparam->ordering = SORTBY_DESC;
1377  if ((opt & INDOPTION_NULLS_FIRST) == 0)
1379  }
1380  else
1381  {
1382  if (opt & INDOPTION_NULLS_FIRST)
1384  }
1385  }
1386 
1387  index->indexParams = lappend(index->indexParams, iparam);
1388  }
1389 
1390  /* Copy reloptions if any */
1391  datum = SysCacheGetAttr(RELOID, ht_idxrel,
1392  Anum_pg_class_reloptions, &isnull);
1393  if (!isnull)
1394  index->options = untransformRelOptions(datum);
1395 
1396  /* If it's a partial index, decompile and append the predicate */
1397  datum = SysCacheGetAttr(INDEXRELID, ht_idx,
1398  Anum_pg_index_indpred, &isnull);
1399  if (!isnull)
1400  {
1401  char *pred_str;
1402  Node *pred_tree;
1403  bool found_whole_row;
1404 
1405  /* Convert text string to node tree */
1406  pred_str = TextDatumGetCString(datum);
1407  pred_tree = (Node *) stringToNode(pred_str);
1408 
1409  /* Adjust Vars to match new table's column numbering */
1410  pred_tree = map_variable_attnos(pred_tree,
1411  1, 0,
1412  attmap, attmap_length,
1413  &found_whole_row);
1414 
1415  /* As in transformTableLikeClause, reject whole-row variables */
1416  if (found_whole_row)
1417  ereport(ERROR,
1418  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1419  errmsg("cannot convert whole-row table reference"),
1420  errdetail("Index \"%s\" contains a whole-row table reference.",
1421  RelationGetRelationName(source_idx))));
1422 
1423  index->whereClause = pred_tree;
1424  }
1425 
1426  /* Clean up */
1427  ReleaseSysCache(ht_idxrel);
1428  ReleaseSysCache(ht_am);
1429 
1430  return index;
1431 }
#define list_make2(x1, x2)
Definition: pg_list.h:134
bool deferrable
Definition: parsenodes.h:2653
Node * map_variable_attnos(Node *node, int target_varno, int sublevels_up, const AttrNumber *attno_map, int map_length, bool *found_whole_row)
Value * makeString(char *str)
Definition: value.c:53
signed short int16
Definition: c.h:255
#define NIL
Definition: pg_list.h:69
static List * get_opclass(Oid opclass, Oid actual_datatype)
Definition: c.h:478
bool primary
Definition: parsenodes.h:2651
#define INDOPTION_NULLS_FIRST
Definition: pg_index.h:100
void * stringToNode(char *str)
Definition: read.c:38
int16 * rd_indoption
Definition: rel.h:186
SortByDir ordering
Definition: parsenodes.h:682
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
Definition: syscache.h:36
List * options
Definition: parsenodes.h:2644
#define RelationGetDescr(relation)
Definition: rel.h:429
#define OIDOID
Definition: pg_type.h:328
char * tableSpace
Definition: parsenodes.h:2642
#define Anum_pg_class_reloptions
Definition: pg_class.h:134
#define DatumGetObjectId(X)
Definition: postgres.h:506
char * pstrdup(const char *in)
Definition: mcxt.c:1077
Node * whereClause
Definition: parsenodes.h:2645
#define Anum_pg_index_indclass
Definition: pg_index.h:89
Definition: nodes.h:504
#define CONSTRAINT_EXCLUSION
int errcode(int sqlerrcode)
Definition: elog.c:575
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:538
struct IndexAmRoutine * rd_amroutine
Definition: rel.h:181
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:152
struct HeapTupleData * rd_indextuple
Definition: rel.h:161
Definition: type.h:90
Oid indexOid
Definition: parsenodes.h:2648
Node * expr
Definition: parsenodes.h:678
RangeVar * relation
Definition: parse_utilcmd.c:76
RangeVar * relation
Definition: parsenodes.h:2640
SortByNulls nulls_ordering
Definition: parsenodes.h:683
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3006
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:486
bool transformed
Definition: parsenodes.h:2655
int errdetail(const char *fmt,...)
Definition: elog.c:873
char * indexcolname
Definition: parsenodes.h:679
#define RelationGetRelationName(relation)
Definition: rel.h:437
static ListCell * list_head(const List *l)
Definition: pg_list.h:77
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:184
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:676
Oid get_atttype(Oid relid, AttrNumber attnum)
Definition: lsyscache.c:846
#define lnext(lc)
Definition: pg_list.h:105
#define ereport(elevel, rest)
Definition: elog.h:122
List * lappend(List *list, void *datum)
Definition: list.c:128
char * idxname
Definition: parsenodes.h:2639
char * get_relid_attribute_name(Oid relid, AttrNumber attnum)
Definition: lsyscache.c:801
FormData_pg_index * Form_pg_index
Definition: pg_index.h:67
#define AttributeNumberIsValid(attributeNumber)
Definition: attnum.h:34
#define TextDatumGetCString(d)
Definition: builtins.h:92
bool if_not_exists
Definition: parsenodes.h:2657
uintptr_t Datum
Definition: postgres.h:372
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1278
bool unique
Definition: parsenodes.h:2650
List * untransformRelOptions(Datum options)
Definition: reloptions.c:898
char * accessMethod
Definition: parsenodes.h:2641
#define InvalidOid
Definition: postgres_ext.h:36
List * opclass
Definition: parsenodes.h:681
#define Anum_pg_index_indpred
Definition: pg_index.h:92
#define makeNode(_type_)
Definition: nodes.h:552
FormData_pg_constraint * Form_pg_constraint
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
#define INDOPTION_DESC
Definition: pg_index.h:99
List * indexParams
Definition: parsenodes.h:2643
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
List * excludeOpNames
Definition: parsenodes.h:2646
bool initdeferred
Definition: parsenodes.h:2654
bool amcanorder
Definition: amapi.h:171
char * name
Definition: parsenodes.h:677
char * idxcomment
Definition: parsenodes.h:2647
FormData_pg_operator* Form_pg_operator
Definition: pg_operator.h:57
#define DatumGetPointer(X)
Definition: postgres.h:555
#define Anum_pg_index_indcollation
Definition: pg_index.h:88
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3475
FormData_pg_class * Form_pg_class
Definition: pg_class.h:95
bool concurrent
Definition: parsenodes.h:2656
bool isconstraint
Definition: parsenodes.h:2652
FormData_pg_am * Form_pg_am
Definition: pg_am.h:46
int errmsg(const char *fmt,...)
Definition: elog.c:797
char * get_tablespace_name(Oid spc_oid)
Definition: tablespace.c:1426
int i
#define NameStr(name)
Definition: c.h:499
List * collation
Definition: parsenodes.h:680
#define elog
Definition: elog.h:219
static List * get_collation(Oid collation, Oid actual_datatype)
Definition: pg_list.h:45
int16 AttrNumber
Definition: attnum.h:21
#define RelationGetRelid(relation)
Definition: rel.h:417
#define Anum_pg_constraint_conexclop
#define Anum_pg_index_indexprs
Definition: pg_index.h:91
#define DatumGetArrayTypeP(X)
Definition: array.h:242
static List * get_collation ( Oid  collation,
Oid  actual_datatype 
)
static

Definition at line 1440 of file parse_utilcmd.c.

References COLLOID, elog, ERROR, get_namespace_name(), get_typcollation(), GETSTRUCT, HeapTupleIsValid, list_make2, makeString(), NameStr, NIL, ObjectIdGetDatum, OidIsValid, pstrdup(), ReleaseSysCache(), result, and SearchSysCache1.

Referenced by generateClonedIndexStmt().

1441 {
1442  List *result;
1443  HeapTuple ht_coll;
1444  Form_pg_collation coll_rec;
1445  char *nsp_name;
1446  char *coll_name;
1447 
1448  if (!OidIsValid(collation))
1449  return NIL; /* easy case */
1450  if (collation == get_typcollation(actual_datatype))
1451  return NIL; /* just let it default */
1452 
1453  ht_coll = SearchSysCache1(COLLOID, ObjectIdGetDatum(collation));
1454  if (!HeapTupleIsValid(ht_coll))
1455  elog(ERROR, "cache lookup failed for collation %u", collation);
1456  coll_rec = (Form_pg_collation) GETSTRUCT(ht_coll);
1457 
1458  /* For simplicity, we always schema-qualify the name */
1459  nsp_name = get_namespace_name(coll_rec->collnamespace);
1460  coll_name = pstrdup(NameStr(coll_rec->collname));
1461  result = list_make2(makeString(nsp_name), makeString(coll_name));
1462 
1463  ReleaseSysCache(ht_coll);
1464  return result;
1465 }
#define list_make2(x1, x2)
Definition: pg_list.h:134
Value * makeString(char *str)
Definition: value.c:53
#define NIL
Definition: pg_list.h:69
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
char * pstrdup(const char *in)
Definition: mcxt.c:1077
return result
Definition: formatting.c:1618
#define OidIsValid(objectId)
Definition: c.h:538
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:152
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3006
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
Oid get_typcollation(Oid typid)
Definition: lsyscache.c:2749
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
FormData_pg_collation * Form_pg_collation
Definition: pg_collation.h:51
#define NameStr(name)
Definition: c.h:499
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
static List * get_opclass ( Oid  opclass,
Oid  actual_datatype 
)
static

Definition at line 1474 of file parse_utilcmd.c.

References CLAOID, elog, ERROR, get_namespace_name(), GetDefaultOpClass(), GETSTRUCT, HeapTupleIsValid, list_make2, makeString(), NameStr, NIL, ObjectIdGetDatum, pstrdup(), ReleaseSysCache(), result, and SearchSysCache1.

Referenced by generateClonedIndexStmt().

1475 {
1476  List *result = NIL;
1477  HeapTuple ht_opc;
1478  Form_pg_opclass opc_rec;
1479 
1480  ht_opc = SearchSysCache1(CLAOID, ObjectIdGetDatum(opclass));
1481  if (!HeapTupleIsValid(ht_opc))
1482  elog(ERROR, "cache lookup failed for opclass %u", opclass);
1483  opc_rec = (Form_pg_opclass) GETSTRUCT(ht_opc);
1484 
1485  if (GetDefaultOpClass(actual_datatype, opc_rec->opcmethod) != opclass)
1486  {
1487  /* For simplicity, we always schema-qualify the name */
1488  char *nsp_name = get_namespace_name(opc_rec->opcnamespace);
1489  char *opc_name = pstrdup(NameStr(opc_rec->opcname));
1490 
1491  result = list_make2(makeString(nsp_name), makeString(opc_name));
1492  }
1493 
1494  ReleaseSysCache(ht_opc);
1495  return result;
1496 }
#define list_make2(x1, x2)
Definition: pg_list.h:134
Value * makeString(char *str)
Definition: value.c:53
#define NIL
Definition: pg_list.h:69
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:1378
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
char * pstrdup(const char *in)
Definition: mcxt.c:1077
return result
Definition: formatting.c:1618
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:152
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3006
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NameStr(name)
Definition: c.h:499
#define elog
Definition: elog.h:219
FormData_pg_opclass * Form_pg_opclass
Definition: pg_opclass.h:68
Definition: pg_list.h:45
static void setSchemaName ( char *  context_schema,
char **  stmt_schema_name 
)
static

Definition at line 3012 of file parse_utilcmd.c.

References ereport, errcode(), errmsg(), ERROR, and NULL.

Referenced by transformCreateSchemaStmt().

3013 {
3014  if (*stmt_schema_name == NULL)
3015  *stmt_schema_name = context_schema;
3016  else if (strcmp(context_schema, *stmt_schema_name) != 0)
3017  ereport(ERROR,
3018  (errcode(ERRCODE_INVALID_SCHEMA_DEFINITION),
3019  errmsg("CREATE specifies a schema (%s) "
3020  "different from the one being created (%s)",
3021  *stmt_schema_name, context_schema)));
3022 }
int errcode(int sqlerrcode)
Definition: elog.c:575
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
#define NULL
Definition: c.h:229
int errmsg(const char *fmt,...)
Definition: elog.c:797
List* transformAlterTableStmt ( Oid  relid,
AlterTableStmt stmt,
const char *  queryString 
)

Definition at line 2505 of file parse_utilcmd.c.

References addRangeTableEntryForRelation(), addRTEtoQuery(), CreateStmtContext::alist, AT_AddColumn, AT_AddColumnToView, AT_AddConstraint, AT_AddIndex, AT_AddIndexConstraint, AT_AlterColumnType, AT_AttachPartition, AT_DetachPartition, AT_ProcessedConstraint, CreateStmtContext::blist, PartitionCmd::bound, castNode, CreateStmtContext::ckconstraints, AlterTableStmt::cmds, CreateStmtContext::columns, CONSTR_FOREIGN, ColumnDef::constraints, ColumnDef::cooked_default, copyObject(), AlterTableCmd::def, elog, ERROR, EXPR_KIND_ALTER_COL_TRANSFORM, CreateStmtContext::fkconstraints, CreateStmtContext::hasoids, IndexStmt::indexOid, CreateStmtContext::inh_indexes, CreateStmtContext::inhRelations, IsA, CreateStmtContext::isalter, CreateStmtContext::isforeign, CreateStmtContext::ispartitioned, CreateStmtContext::ixconstraints, lappend(), lfirst, list_concat(), make_parsestate(), makeNode, NIL, nodeTag, NoLock, NULL, OBJECT_FOREIGN_TABLE, OidIsValid, ParseState::p_sourcetext, CreateStmtContext::partbound, CreateStmtContext::pkey, CreateStmtContext::pstate, ColumnDef::raw_default, RelationData::rd_rel, CreateStmtContext::rel, CreateStmtContext::relation, AlterTableStmt::relation, relation_close(), relation_open(), AlterTableStmt::relkind, RELKIND_PARTITIONED_TABLE, result, CreateStmtContext::stmtType, AlterTableCmd::subtype, transformCheckConstraints(), transformColumnDefinition(), transformExpr(), transformFKConstraints(), transformIndexConstraints(), transformIndexStmt(), transformPartitionCmd(), and transformTableConstraint().

Referenced by ATPostAlterTypeParse(), and ProcessUtilitySlow().

2507 {
2508  Relation rel;
2509  ParseState *pstate;
2510  CreateStmtContext cxt;
2511  List *result;
2512  List *save_alist;
2513  ListCell *lcmd,
2514  *l;
2515  List *newcmds = NIL;
2516  bool skipValidation = true;
2517  AlterTableCmd *newcmd;
2518  RangeTblEntry *rte;
2519 
2520  /*
2521  * We must not scribble on the passed-in AlterTableStmt, so copy it. (This
2522  * is overkill, but easy.)
2523  */
2524  stmt = (AlterTableStmt *) copyObject(stmt);
2525 
2526  /* Caller is responsible for locking the relation */
2527  rel = relation_open(relid, NoLock);
2528 
2529  /* Set up pstate */
2530  pstate = make_parsestate(NULL);
2531  pstate->p_sourcetext = queryString;
2532  rte = addRangeTableEntryForRelation(pstate,
2533  rel,
2534  NULL,
2535  false,
2536  true);
2537  addRTEtoQuery(pstate, rte, false, true, true);
2538 
2539  /* Set up CreateStmtContext */
2540  cxt.pstate = pstate;
2541  if (stmt->relkind == OBJECT_FOREIGN_TABLE)
2542  {
2543  cxt.stmtType = "ALTER FOREIGN TABLE";
2544  cxt.isforeign = true;
2545  }
2546  else
2547  {
2548  cxt.stmtType = "ALTER TABLE";
2549  cxt.isforeign = false;
2550  }
2551  cxt.relation = stmt->relation;
2552  cxt.rel = rel;
2553  cxt.inhRelations = NIL;
2554  cxt.isalter = true;
2555  cxt.hasoids = false; /* need not be right */
2556  cxt.columns = NIL;
2557  cxt.ckconstraints = NIL;
2558  cxt.fkconstraints = NIL;
2559  cxt.ixconstraints = NIL;
2560  cxt.inh_indexes = NIL;
2561  cxt.blist = NIL;
2562  cxt.alist = NIL;
2563  cxt.pkey = NULL;
2564  cxt.ispartitioned = (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
2565  cxt.partbound = NULL;
2566 
2567  /*
2568  * The only subtypes that currently require parse transformation handling
2569  * are ADD COLUMN, ADD CONSTRAINT and SET DATA TYPE. These largely re-use
2570  * code from CREATE TABLE.
2571  */
2572  foreach(lcmd, stmt->cmds)
2573  {
2574  AlterTableCmd *cmd = (AlterTableCmd *) lfirst(lcmd);
2575 
2576  switch (cmd->subtype)
2577  {
2578  case AT_AddColumn:
2579  case AT_AddColumnToView:
2580  {
2581  ColumnDef *def = castNode(ColumnDef, cmd->def);
2582 
2583  transformColumnDefinition(&cxt, def);
2584 
2585  /*
2586  * If the column has a non-null default, we can't skip
2587  * validation of foreign keys.
2588  */
2589  if (def->raw_default != NULL)
2590  skipValidation = false;
2591 
2592  /*
2593  * All constraints are processed in other ways. Remove the
2594  * original list
2595  */
2596  def->constraints = NIL;
2597 
2598  newcmds = lappend(newcmds, cmd);
2599  break;
2600  }
2601 
2602  case AT_AddConstraint:
2603 
2604  /*
2605  * The original AddConstraint cmd node doesn't go to newcmds
2606  */
2607  if (IsA(cmd->def, Constraint))
2608  {
2609  transformTableConstraint(&cxt, (Constraint *) cmd->def);
2610  if (((Constraint *) cmd->def)->contype == CONSTR_FOREIGN)
2611  skipValidation = false;
2612  }
2613  else
2614  elog(ERROR, "unrecognized node type: %d",
2615  (int) nodeTag(cmd->def));
2616  break;
2617 
2619 
2620  /*
2621  * Already-transformed ADD CONSTRAINT, so just make it look
2622  * like the standard case.
2623  */
2624  cmd->subtype = AT_AddConstraint;
2625  newcmds = lappend(newcmds, cmd);
2626  break;
2627 
2628  case AT_AlterColumnType:
2629  {
2630  ColumnDef *def = (ColumnDef *) cmd->def;
2631 
2632  /*
2633  * For ALTER COLUMN TYPE, transform the USING clause if
2634  * one was specified.
2635  */
2636  if (def->raw_default)
2637  {
2638  def->cooked_default =
2639  transformExpr(pstate, def->raw_default,
2641  }
2642 
2643  newcmds = lappend(newcmds, cmd);
2644  break;
2645  }
2646 
2647  case AT_AttachPartition:
2648  case AT_DetachPartition:
2649  {
2650  PartitionCmd *partcmd = (PartitionCmd *) cmd->def;
2651 
2652  transformPartitionCmd(&cxt, partcmd);
2653  /* assign transformed value of the partition bound */
2654  partcmd->bound = cxt.partbound;
2655  }
2656 
2657  newcmds = lappend(newcmds, cmd);
2658  break;
2659 
2660  default:
2661  newcmds = lappend(newcmds, cmd);
2662  break;
2663  }
2664  }
2665 
2666  /*
2667  * transformIndexConstraints wants cxt.alist to contain only index
2668  * statements, so transfer anything we already have into save_alist
2669  * immediately.
2670  */
2671  save_alist = cxt.alist;
2672  cxt.alist = NIL;
2673 
2674  /* Postprocess constraints */
2676  transformFKConstraints(&cxt, skipValidation, true);
2677  transformCheckConstraints(&cxt, false);
2678 
2679  /*
2680  * Push any index-creation commands into the ALTER, so that they can be
2681  * scheduled nicely by tablecmds.c. Note that tablecmds.c assumes that
2682  * the IndexStmt attached to an AT_AddIndex or AT_AddIndexConstraint
2683  * subcommand has already been through transformIndexStmt.
2684  */
2685  foreach(l, cxt.alist)
2686  {
2687  IndexStmt *idxstmt = castNode(IndexStmt, lfirst(l));
2688 
2689  idxstmt = transformIndexStmt(relid, idxstmt, queryString);
2690  newcmd = makeNode(AlterTableCmd);
2692  newcmd->def = (Node *) idxstmt;
2693  newcmds = lappend(newcmds, newcmd);
2694  }
2695  cxt.alist = NIL;
2696 
2697  /* Append any CHECK or FK constraints to the commands list */
2698  foreach(l, cxt.ckconstraints)
2699  {
2700  newcmd = makeNode(AlterTableCmd);
2701  newcmd->subtype = AT_AddConstraint;
2702  newcmd->def = (Node *) lfirst(l);
2703  newcmds = lappend(newcmds, newcmd);
2704  }
2705  foreach(l, cxt.fkconstraints)
2706  {
2707  newcmd = makeNode(AlterTableCmd);
2708  newcmd->subtype = AT_AddConstraint;
2709  newcmd->def = (Node *) lfirst(l);
2710  newcmds = lappend(newcmds, newcmd);
2711  }
2712 
2713  /* Close rel */
2714  relation_close(rel, NoLock);
2715 
2716  /*
2717  * Output results.
2718  */
2719  stmt->cmds = newcmds;
2720 
2721  result = lappend(cxt.blist, stmt);
2722  result = list_concat(result, cxt.alist);
2723  result = list_concat(result, save_alist);
2724 
2725  return result;
2726 }
#define NIL
Definition: pg_list.h:69
#define IsA(nodeptr, _type_)
Definition: nodes.h:555
#define castNode(_type_, nodeptr)
Definition: nodes.h:573
Node * bound
Definition: parsenodes.h:814
List * constraints
Definition: parsenodes.h:642
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:147
Definition: nodes.h:504
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1263
AlterTableType subtype
Definition: parsenodes.h:1725
List * list_concat(List *list1, List *list2)
Definition: list.c:321
return result
Definition: formatting.c:1618
Form_pg_class rd_rel
Definition: rel.h:114
#define OidIsValid(objectId)
Definition: c.h:538
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
void * copyObject(const void *from)
Definition: copyfuncs.c:4619
ParseState * pstate
Definition: parse_utilcmd.c:74
Node * cooked_default
Definition: parsenodes.h:639
Oid indexOid
Definition: parsenodes.h:2648
RangeVar * relation
Definition: parse_utilcmd.c:76
IndexStmt * pkey
Definition: parse_utilcmd.c:91
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
const char * p_sourcetext
Definition: parse_node.h:167
ObjectType relkind
Definition: parsenodes.h:1643
void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
Node * raw_default
Definition: parsenodes.h:638
List * lappend(List *list, void *datum)
Definition: list.c:128
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
#define makeNode(_type_)
Definition: nodes.h:552
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
static void transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
RangeTblEntry * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, Alias *alias, bool inh, bool inFromCl)
static void transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd)
static void transformFKConstraints(CreateStmtContext *cxt, bool skipValidation, bool isAddConstraint)
#define nodeTag(nodeptr)
Definition: nodes.h:509
const char * stmtType
Definition: parse_utilcmd.c:75
RangeVar * relation
Definition: parsenodes.h:1641
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1117
#define elog
Definition: elog.h:219
static void transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
static void transformIndexConstraints(CreateStmtContext *cxt)
IndexStmt * transformIndexStmt(Oid relid, IndexStmt *stmt, const char *queryString)
Definition: pg_list.h:45
static void transformCheckConstraints(CreateStmtContext *cxt, bool skipValidation)
static void transformCheckConstraints ( CreateStmtContext cxt,
bool  skipValidation 
)
static

Definition at line 1995 of file parse_utilcmd.c.

References CreateStmtContext::ckconstraints, Constraint::initially_valid, lfirst, NIL, and Constraint::skip_validation.

Referenced by transformAlterTableStmt(), and transformCreateStmt().

1996 {
1997  ListCell *ckclist;
1998 
1999  if (cxt->ckconstraints == NIL)
2000  return;
2001 
2002  /*
2003  * If creating a new table, we can safely skip validation of check
2004  * constraints, and nonetheless mark them valid. (This will override any
2005  * user-supplied NOT VALID flag.)
2006  */
2007  if (skipValidation)
2008  {
2009  foreach(ckclist, cxt->ckconstraints)
2010  {
2011  Constraint *constraint = (Constraint *) lfirst(ckclist);
2012 
2013  constraint->skip_validation = true;
2014  constraint->initially_valid = true;
2015  }
2016  }
2017 }
#define NIL
Definition: pg_list.h:69
bool initially_valid
Definition: parsenodes.h:2064
#define lfirst(lc)
Definition: pg_list.h:106
bool skip_validation
Definition: parsenodes.h:2063
static void transformColumnDefinition ( CreateStmtContext cxt,
ColumnDef column 
)
static

Definition at line 365 of file parse_utilcmd.c.

References CreateStmtContext::alist, TypeCast::arg, TypeName::arrayBounds, Assert, AT_AlterColumnGenericOptions, AlterTableCmd::behavior, CreateStmtContext::blist, castNode, ChooseRelationName(), CreateStmtContext::ckconstraints, AlterTableStmt::cmds, ColumnDef::colname, CreateStmtContext::columns, CONSTR_ATTR_DEFERRABLE, CONSTR_ATTR_DEFERRED, CONSTR_ATTR_IMMEDIATE, CONSTR_ATTR_NOT_DEFERRABLE, CONSTR_CHECK, CONSTR_DEFAULT, CONSTR_EXCLUSION, CONSTR_FOREIGN, CONSTR_NOTNULL, CONSTR_NULL, CONSTR_PRIMARY, CONSTR_UNIQUE, ColumnDef::constraints, Constraint::contype, Constraint::cooked_expr, DEBUG1, AlterTableCmd::def, DROP_RESTRICT, elog, ereport, errcode(), errmsg(), ERROR, FALSE, ColumnDef::fdwoptions, Constraint::fk_attrs, CreateStmtContext::fkconstraints, get_namespace_name(), INT2OID, INT4OID, INT8OID, InvalidOid, ColumnDef::is_not_null, CreateStmtContext::isforeign, CreateStmtContext::ispartitioned, CreateStmtContext::ixconstraints, Constraint::keys, lappend(), lfirst, linitial, list_length(), list_make1, list_make3, TypeName::location, A_Const::location, TypeCast::location, Constraint::location, makeDefElem(), makeFuncCall(), makeNode, makeRangeVar(), makeString(), makeTypeNameFromOid(), AlterTableCmd::missing_ok, AlterTableCmd::name, TypeName::names, NIL, NULL, OBJECT_FOREIGN_TABLE, CreateSeqStmt::options, AlterSeqStmt::options, CreateSeqStmt::ownerId, parser_errposition(), TypeName::pct_type, CreateStmtContext::pstate, quote_qualified_identifier(), RangeVarAdjustRelationPersistence(), RangeVarGetCreationNamespace(), ColumnDef::raw_default, Constraint::raw_expr, RelationData::rd_rel, CreateStmtContext::rel, CreateStmtContext::relation, AlterTableStmt::relation, RelationGetNamespace, AlterTableStmt::relkind, RangeVar::relname, CreateSeqStmt::sequence, AlterSeqStmt::sequence, CreateStmtContext::stmtType, Value::ValUnion::str, strVal, AlterTableCmd::subtype, SystemFuncName(), SystemTypeName(), T_String, transformColumnType(), transformConstraintAttrs(), TRUE, Value::type, TypeCast::typeName, ColumnDef::typeName, TypeName::typeOid, Value::val, and A_Const::val.

Referenced by transformAlterTableStmt(), and transformCreateStmt().

366 {
367  bool is_serial;
368  bool saw_nullable;
369  bool saw_default;
370  Constraint *constraint;
371  ListCell *clist;
372 
373  cxt->columns = lappend(cxt->columns, column);
374 
375  /* Check for SERIAL pseudo-types */
376  is_serial = false;
377  if (column->typeName
378  && list_length(column->typeName->names) == 1
379  && !column->typeName->pct_type)
380  {
381  char *typname = strVal(linitial(column->typeName->names));
382 
383  if (strcmp(typname, "smallserial") == 0 ||
384  strcmp(typname, "serial2") == 0)
385  {
386  is_serial = true;
387  column->typeName->names = NIL;
388  column->typeName->typeOid = INT2OID;
389  }
390  else if (strcmp(typname, "serial") == 0 ||
391  strcmp(typname, "serial4") == 0)
392  {
393  is_serial = true;
394  column->typeName->names = NIL;
395  column->typeName->typeOid = INT4OID;
396  }
397  else if (strcmp(typname, "bigserial") == 0 ||
398  strcmp(typname, "serial8") == 0)
399  {
400  is_serial = true;
401  column->typeName->names = NIL;
402  column->typeName->typeOid = INT8OID;
403  }
404 
405  /*
406  * We have to reject "serial[]" explicitly, because once we've set
407  * typeid, LookupTypeName won't notice arrayBounds. We don't need any
408  * special coding for serial(typmod) though.
409  */
410  if (is_serial && column->typeName->arrayBounds != NIL)
411  ereport(ERROR,
412  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
413  errmsg("array of serial is not implemented"),
415  column->typeName->location)));
416  }
417 
418  /* Do necessary work on the column type declaration */
419  if (column->typeName)
420  transformColumnType(cxt, column);
421 
422  /* Special actions for SERIAL pseudo-types */
423  if (is_serial)
424  {
425  Oid snamespaceid;
426  char *snamespace;
427  char *sname;
428  char *qstring;
429  A_Const *snamenode;
430  TypeCast *castnode;
431  FuncCall *funccallnode;
432  CreateSeqStmt *seqstmt;
433  AlterSeqStmt *altseqstmt;
434  List *attnamelist;
435 
436  /*
437  * Determine namespace and name to use for the sequence.
438  *
439  * Although we use ChooseRelationName, it's not guaranteed that the
440  * selected sequence name won't conflict; given sufficiently long
441  * field names, two different serial columns in the same table could
442  * be assigned the same sequence name, and we'd not notice since we
443  * aren't creating the sequence quite yet. In practice this seems
444  * quite unlikely to be a problem, especially since few people would
445  * need two serial columns in one table.
446  */
447  if (cxt->rel)
448  snamespaceid = RelationGetNamespace(cxt->rel);
449  else
450  {
451  snamespaceid = RangeVarGetCreationNamespace(cxt->relation);
452  RangeVarAdjustRelationPersistence(cxt->relation, snamespaceid);
453  }
454  snamespace = get_namespace_name(snamespaceid);
455  sname = ChooseRelationName(cxt->relation->relname,
456  column->colname,
457  "seq",
458  snamespaceid);
459 
460  ereport(DEBUG1,
461  (errmsg("%s will create implicit sequence \"%s\" for serial column \"%s.%s\"",
462  cxt->stmtType, sname,
463  cxt->relation->relname, column->colname)));
464 
465  /*
466  * Build a CREATE SEQUENCE command to create the sequence object, and
467  * add it to the list of things to be done before this CREATE/ALTER
468  * TABLE.
469  */
470  seqstmt = makeNode(CreateSeqStmt);
471  seqstmt->sequence = makeRangeVar(snamespace, sname, -1);
472  seqstmt->options = list_make1(makeDefElem("as", (Node *) makeTypeNameFromOid(column->typeName->typeOid, -1), -1));
473 
474  /*
475  * If this is ALTER ADD COLUMN, make sure the sequence will be owned
476  * by the table's owner. The current user might be someone else
477  * (perhaps a superuser, or someone who's only a member of the owning
478  * role), but the SEQUENCE OWNED BY mechanisms will bleat unless table
479  * and sequence have exactly the same owning role.
480  */
481  if (cxt->rel)
482  seqstmt->ownerId = cxt->rel->rd_rel->relowner;
483  else
484  seqstmt->ownerId = InvalidOid;
485 
486  cxt->blist = lappend(cxt->blist, seqstmt);
487 
488  /*
489  * Build an ALTER SEQUENCE ... OWNED BY command to mark the sequence
490  * as owned by this column, and add it to the list of things to be
491  * done after this CREATE/ALTER TABLE.
492  */
493  altseqstmt = makeNode(AlterSeqStmt);
494  altseqstmt->sequence = makeRangeVar(snamespace, sname, -1);
495  attnamelist = list_make3(makeString(snamespace),
496  makeString(cxt->relation->relname),
497  makeString(column->colname));
498  altseqstmt->options = list_make1(makeDefElem("owned_by",
499  (Node *) attnamelist, -1));
500 
501  cxt->alist = lappend(cxt->alist, altseqstmt);
502 
503  /*
504  * Create appropriate constraints for SERIAL. We do this in full,
505  * rather than shortcutting, so that we will detect any conflicting
506  * constraints the user wrote (like a different DEFAULT).
507  *
508  * Create an expression tree representing the function call
509  * nextval('sequencename'). We cannot reduce the raw tree to cooked
510  * form until after the sequence is created, but there's no need to do
511  * so.
512  */
513  qstring = quote_qualified_identifier(snamespace, sname);
514  snamenode = makeNode(A_Const);
515  snamenode->val.type = T_String;
516  snamenode->val.val.str = qstring;
517  snamenode->location = -1;
518  castnode = makeNode(TypeCast);
519  castnode->typeName = SystemTypeName("regclass");
520  castnode->arg = (Node *) snamenode;
521  castnode->location = -1;
522  funccallnode = makeFuncCall(SystemFuncName("nextval"),
523  list_make1(castnode),
524  -1);
525  constraint = makeNode(Constraint);
526  constraint->contype = CONSTR_DEFAULT;
527  constraint->location = -1;
528  constraint->raw_expr = (Node *) funccallnode;
529  constraint->cooked_expr = NULL;
530  column->constraints = lappend(column->constraints, constraint);
531 
532  constraint = makeNode(Constraint);
533  constraint->contype = CONSTR_NOTNULL;
534  constraint->location = -1;
535  column->constraints = lappend(column->constraints, constraint);
536  }
537 
538  /* Process column constraints, if any... */
540 
541  saw_nullable = false;
542  saw_default = false;
543 
544  foreach(clist, column->constraints)
545  {
546  constraint = castNode(Constraint, lfirst(clist));
547 
548  switch (constraint->contype)
549  {
550  case CONSTR_NULL:
551  if (saw_nullable && column->is_not_null)
552  ereport(ERROR,
553  (errcode(ERRCODE_SYNTAX_ERROR),
554  errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
555  column->colname, cxt->relation->relname),
557  constraint->location)));
558  column->is_not_null = FALSE;
559  saw_nullable = true;
560  break;
561 
562  case CONSTR_NOTNULL:
563  if (saw_nullable && !column->is_not_null)
564  ereport(ERROR,
565  (errcode(ERRCODE_SYNTAX_ERROR),
566  errmsg("conflicting NULL/NOT NULL declarations for column \"%s\" of table \"%s\"",
567  column->colname, cxt->relation->relname),
569  constraint->location)));
570  column->is_not_null = TRUE;
571  saw_nullable = true;
572  break;
573 
574  case CONSTR_DEFAULT:
575  if (saw_default)
576  ereport(ERROR,
577  (errcode(ERRCODE_SYNTAX_ERROR),
578  errmsg("multiple default values specified for column \"%s\" of table \"%s\"",
579  column->colname, cxt->relation->relname),
581  constraint->location)));
582  column->raw_default = constraint->raw_expr;
583  Assert(constraint->cooked_expr == NULL);
584  saw_default = true;
585  break;
586 
587  case CONSTR_CHECK:
588  cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
589  break;
590 
591  case CONSTR_PRIMARY:
592  if (cxt->isforeign)
593  ereport(ERROR,
594  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
595  errmsg("primary key constraints are not supported on foreign tables"),
597  constraint->location)));
598  if (cxt->ispartitioned)
599  ereport(ERROR,
600  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
601  errmsg("primary key constraints are not supported on partitioned tables"),
603  constraint->location)));
604  /* FALL THRU */
605 
606  case CONSTR_UNIQUE:
607  if (cxt->isforeign)
608  ereport(ERROR,
609  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
610  errmsg("unique constraints are not supported on foreign tables"),
612  constraint->location)));
613  if (cxt->ispartitioned)
614  ereport(ERROR,
615  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
616  errmsg("unique constraints are not supported on partitioned tables"),
618  constraint->location)));
619  if (constraint->keys == NIL)
620  constraint->keys = list_make1(makeString(column->colname));
621  cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
622  break;
623 
624  case CONSTR_EXCLUSION:
625  /* grammar does not allow EXCLUDE as a column constraint */
626  elog(ERROR, "column exclusion constraints are not supported");
627  break;
628 
629  case CONSTR_FOREIGN:
630  if (cxt->isforeign)
631  ereport(ERROR,
632  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
633  errmsg("foreign key constraints are not supported on foreign tables"),
635  constraint->location)));
636  if (cxt->ispartitioned)
637  ereport(ERROR,
638  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
639  errmsg("foreign key constraints are not supported on partitioned tables"),
641  constraint->location)));
642 
643  /*
644  * Fill in the current attribute's name and throw it into the
645  * list of FK constraints to be processed later.
646  */
647  constraint->fk_attrs = list_make1(makeString(column->colname));
648  cxt->fkconstraints = lappend(cxt->fkconstraints, constraint);
649  break;
650 
655  /* transformConstraintAttrs took care of these */
656  break;
657 
658  default:
659  elog(ERROR, "unrecognized constraint type: %d",
660  constraint->contype);
661  break;
662  }
663  }
664 
665  /*
666  * If needed, generate ALTER FOREIGN TABLE ALTER COLUMN statement to add
667  * per-column foreign data wrapper options to this column after creation.
668  */
669  if (column->fdwoptions != NIL)
670  {
671  AlterTableStmt *stmt;
672  AlterTableCmd *cmd;
673 
674  cmd = makeNode(AlterTableCmd);
676  cmd->name = column->colname;
677  cmd->def = (Node *) column->fdwoptions;
678  cmd->behavior = DROP_RESTRICT;
679  cmd->missing_ok = false;
680 
681  stmt = makeNode(AlterTableStmt);
682  stmt->relation = cxt->relation;
683  stmt->cmds = NIL;
685  stmt->cmds = lappend(stmt->cmds, cmd);
686 
687  cxt->alist = lappend(cxt->alist, stmt);
688  }
689 }
Value * makeString(char *str)
Definition: value.c:53
#define list_make3(x1, x2, x3)
Definition: pg_list.h:135
#define NIL
Definition: pg_list.h:69
List * SystemFuncName(char *name)
Oid typeOid
Definition: parsenodes.h:201
List * keys
Definition: parsenodes.h:2039
#define DEBUG1
Definition: elog.h:25
List * names
Definition: parsenodes.h:200
#define castNode(_type_, nodeptr)
Definition: nodes.h:573
List * constraints
Definition: parsenodes.h:642
Node * raw_expr
Definition: parsenodes.h:2035
#define INT4OID
Definition: pg_type.h:316
Definition: nodes.h:504
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:575
AlterTableType subtype
Definition: parsenodes.h:1725
bool is_not_null
Definition: parsenodes.h:635
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
DefElem * makeDefElem(char *name, Node *arg, int location)
Definition: makefuncs.c:543
void RangeVarAdjustRelationPersistence(RangeVar *newRelation, Oid nspid)
Definition: namespace.c:614
List * options
Definition: parsenodes.h:2422
int location
Definition: parsenodes.h:291
#define list_make1(x1)
Definition: pg_list.h:133
ParseState * pstate
Definition: parse_utilcmd.c:74
char * relname
Definition: primnodes.h:68
RangeVar * relation
Definition: parse_utilcmd.c:76
#define linitial(l)
Definition: pg_list.h:110
#define ERROR
Definition: elog.h:43
static void transformConstraintAttrs(CreateStmtContext *cxt, List *constraintList)
#define FALSE
Definition: c.h:221
#define INT2OID
Definition: pg_type.h:308
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3006
union Value::ValUnion val
List * fdwoptions
Definition: parsenodes.h:643
static void transformColumnType(CreateStmtContext *cxt, ColumnDef *column)
#define ereport(elevel, rest)
Definition: elog.h:122
ObjectType relkind
Definition: parsenodes.h:1643
Node * raw_default
Definition: parsenodes.h:638
List * lappend(List *list, void *datum)
Definition: list.c:128
char * quote_qualified_identifier(const char *qualifier, const char *ident)
Definition: ruleutils.c:10281
FuncCall * makeFuncCall(List *name, List *args, int location)
Definition: makefuncs.c:582
TypeName * SystemTypeName(char *name)
TypeName * typeName
Definition: parsenodes.h:290
TypeName * makeTypeNameFromOid(Oid typeOid, int32 typmod)
Definition: makefuncs.c:469
#define InvalidOid
Definition: postgres_ext.h:36
RangeVar * sequence
Definition: parsenodes.h:2421
RangeVar * sequence
Definition: parsenodes.h:2412
#define INT8OID
Definition: pg_type.h:304
#define makeNode(_type_)
Definition: nodes.h:552
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
int location
Definition: parsenodes.h:280
int location
Definition: parsenodes.h:207
static int list_length(const List *l)
Definition: pg_list.h:89
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:109
TypeName * typeName
Definition: parsenodes.h:632
const char * stmtType
Definition: parse_utilcmd.c:75
List * arrayBounds
Definition: parsenodes.h:206
int errmsg(const char *fmt,...)
Definition: elog.c:797
RangeVar * relation
Definition: parsenodes.h:1641
char * str
Definition: value.h:48
ConstrType contype
Definition: parsenodes.h:2025
DropBehavior behavior
Definition: parsenodes.h:1731
char * colname
Definition: parsenodes.h:631
#define TRUE
Definition: c.h:217
char * ChooseRelationName(const char *name1, const char *name2, const char *label, Oid namespaceid)
Definition: indexcmds.c:1566
#define elog
Definition: elog.h:219
char * cooked_expr
Definition: parsenodes.h:2036
Value val
Definition: parsenodes.h:279
Definition: pg_list.h:45
List * fk_attrs
Definition: parsenodes.h:2054
RangeVar * makeRangeVar(char *schemaname, char *relname, int location)
Definition: makefuncs.c:419
Oid RangeVarGetCreationNamespace(const RangeVar *newRelation)
Definition: namespace.c:420
List * options
Definition: parsenodes.h:2413
NodeTag type
Definition: value.h:44
bool pct_type
Definition: parsenodes.h:203
Node * arg
Definition: parsenodes.h:289
#define RelationGetNamespace(relation)
Definition: rel.h:444
static void transformColumnType ( CreateStmtContext cxt,
ColumnDef column 
)
static

Definition at line 2854 of file parse_utilcmd.c.

References ColumnDef::collClause, CollateClause::collname, ereport, errcode(), errmsg(), ERROR, format_type_be(), GETSTRUCT, HeapTupleGetOid, CollateClause::location, LookupCollation(), NULL, OidIsValid, parser_errposition(), CreateStmtContext::pstate, ReleaseSysCache(), ColumnDef::typeName, and typenameType().

Referenced by transformColumnDefinition().

2855 {
2856  /*
2857  * All we really need to do here is verify that the type is valid,
2858  * including any collation spec that might be present.
2859  */
2860  Type ctype = typenameType(cxt->pstate, column->typeName, NULL);
2861 
2862  if (column->collClause)
2863  {
2864  Form_pg_type typtup = (Form_pg_type) GETSTRUCT(ctype);
2865 
2866  LookupCollation(cxt->pstate,
2867  column->collClause->collname,
2868  column->collClause->location);
2869  /* Complain if COLLATE is applied to an uncollatable type */
2870  if (!OidIsValid(typtup->typcollation))
2871  ereport(ERROR,
2872  (errcode(ERRCODE_DATATYPE_MISMATCH),
2873  errmsg("collations are not supported by type %s",
2876  column->collClause->location)));
2877  }
2878 
2879  ReleaseSysCache(ctype);
2880 }
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:247
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
#define OidIsValid(objectId)
Definition: c.h:538
ParseState * pstate
Definition: parse_utilcmd.c:74
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
Oid LookupCollation(ParseState *pstate, List *collnames, int location)
Definition: parse_type.c:496
#define NULL
Definition: c.h:229
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:109
TypeName * typeName
Definition: parsenodes.h:632
CollateClause * collClause
Definition: parsenodes.h:640
List * collname
Definition: parsenodes.h:301
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
static void transformConstraintAttrs ( CreateStmtContext cxt,
List constraintList 
)
static

Definition at line 2739 of file parse_utilcmd.c.

References CONSTR_ATTR_DEFERRABLE, CONSTR_ATTR_DEFERRED, CONSTR_ATTR_IMMEDIATE, CONSTR_ATTR_NOT_DEFERRABLE, Constraint::contype, Constraint::deferrable, elog, ereport, errcode(), errmsg(), ERROR, Constraint::initdeferred, IsA, lfirst, Constraint::location, nodeTag, NULL, parser_errposition(), CreateStmtContext::pstate, and SUPPORTS_ATTRS.

Referenced by transformColumnDefinition().

2740 {
2741  Constraint *lastprimarycon = NULL;
2742  bool saw_deferrability = false;
2743  bool saw_initially = false;
2744  ListCell *clist;
2745 
2746 #define SUPPORTS_ATTRS(node) \
2747  ((node) != NULL && \
2748  ((node)->contype == CONSTR_PRIMARY || \
2749  (node)->contype == CONSTR_UNIQUE || \
2750  (node)->contype == CONSTR_EXCLUSION || \
2751  (node)->contype == CONSTR_FOREIGN))
2752 
2753  foreach(clist, constraintList)
2754  {
2755  Constraint *con = (Constraint *) lfirst(clist);
2756 
2757  if (!IsA(con, Constraint))
2758  elog(ERROR, "unrecognized node type: %d",
2759  (int) nodeTag(con));
2760  switch (con->contype)
2761  {
2763  if (!SUPPORTS_ATTRS(lastprimarycon))
2764  ereport(ERROR,
2765  (errcode(ERRCODE_SYNTAX_ERROR),
2766  errmsg("misplaced DEFERRABLE clause"),
2767  parser_errposition(cxt->pstate, con->location)));
2768  if (saw_deferrability)
2769  ereport(ERROR,
2770  (errcode(ERRCODE_SYNTAX_ERROR),
2771  errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"),
2772  parser_errposition(cxt->pstate, con->location)));
2773  saw_deferrability = true;
2774  lastprimarycon->deferrable = true;
2775  break;
2776 
2778  if (!SUPPORTS_ATTRS(lastprimarycon))
2779  ereport(ERROR,
2780  (errcode(ERRCODE_SYNTAX_ERROR),
2781  errmsg("misplaced NOT DEFERRABLE clause"),
2782  parser_errposition(cxt->pstate, con->location)));
2783  if (saw_deferrability)
2784  ereport(ERROR,
2785  (errcode(ERRCODE_SYNTAX_ERROR),
2786  errmsg("multiple DEFERRABLE/NOT DEFERRABLE clauses not allowed"),
2787  parser_errposition(cxt->pstate, con->location)));
2788  saw_deferrability = true;
2789  lastprimarycon->deferrable = false;
2790  if (saw_initially &&
2791  lastprimarycon->initdeferred)
2792  ereport(ERROR,
2793  (errcode(ERRCODE_SYNTAX_ERROR),
2794  errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
2795  parser_errposition(cxt->pstate, con->location)));
2796  break;
2797 
2798  case CONSTR_ATTR_DEFERRED:
2799  if (!SUPPORTS_ATTRS(lastprimarycon))
2800  ereport(ERROR,
2801  (errcode(ERRCODE_SYNTAX_ERROR),
2802  errmsg("misplaced INITIALLY DEFERRED clause"),
2803  parser_errposition(cxt->pstate, con->location)));
2804  if (saw_initially)
2805  ereport(ERROR,
2806  (errcode(ERRCODE_SYNTAX_ERROR),
2807  errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"),
2808  parser_errposition(cxt->pstate, con->location)));
2809  saw_initially = true;
2810  lastprimarycon->initdeferred = true;
2811 
2812  /*
2813  * If only INITIALLY DEFERRED appears, assume DEFERRABLE
2814  */
2815  if (!saw_deferrability)
2816  lastprimarycon->deferrable = true;
2817  else if (!lastprimarycon->deferrable)
2818  ereport(ERROR,
2819  (errcode(ERRCODE_SYNTAX_ERROR),
2820  errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
2821  parser_errposition(cxt->pstate, con->location)));
2822  break;
2823 
2824  case CONSTR_ATTR_IMMEDIATE:
2825  if (!SUPPORTS_ATTRS(lastprimarycon))
2826  ereport(ERROR,
2827  (errcode(ERRCODE_SYNTAX_ERROR),
2828  errmsg("misplaced INITIALLY IMMEDIATE clause"),
2829  parser_errposition(cxt->pstate, con->location)));
2830  if (saw_initially)
2831  ereport(ERROR,
2832  (errcode(ERRCODE_SYNTAX_ERROR),
2833  errmsg("multiple INITIALLY IMMEDIATE/DEFERRED clauses not allowed"),
2834  parser_errposition(cxt->pstate, con->location)));
2835  saw_initially = true;
2836  lastprimarycon->initdeferred = false;
2837  break;
2838 
2839  default:
2840  /* Otherwise it's not an attribute */
2841  lastprimarycon = con;
2842  /* reset flags for new primary node */
2843  saw_deferrability = false;
2844  saw_initially = false;
2845  break;
2846  }
2847  }
2848 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:555
int errcode(int sqlerrcode)
Definition: elog.c:575
bool initdeferred
Definition: parsenodes.h:2030
ParseState * pstate
Definition: parse_utilcmd.c:74
#define ERROR
Definition: elog.h:43
bool deferrable
Definition: parsenodes.h:2029
#define ereport(elevel, rest)
Definition: elog.h:122
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:109
#define nodeTag(nodeptr)
Definition: nodes.h:509
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define SUPPORTS_ATTRS(node)
ConstrType contype
Definition: parsenodes.h:2025
#define elog
Definition: elog.h:219
List* transformCreateSchemaStmt ( CreateSchemaStmt stmt)

Definition at line 2907 of file parse_utilcmd.c.

References CreateSchemaStmtContext::authrole, CreateSchemaStmt::authrole, element(), elog, ERROR, CreateSchemaStmtContext::grants, CreateSchemaStmtContext::indexes, lappend(), lfirst, list_concat(), NIL, nodeTag, CreateStmt::relation, CreateTrigStmt::relation, IndexStmt::relation, result, CreateSchemaStmt::schemaElts, RangeVar::schemaname, CreateSchemaStmtContext::schemaname, CreateSchemaStmt::schemaname, CreateSeqStmt::sequence, CreateSchemaStmtContext::sequences, setSchemaName(), CreateSchemaStmtContext::stmtType, T_CreateSeqStmt, T_CreateStmt, T_CreateTrigStmt, T_GrantStmt, T_IndexStmt, T_ViewStmt, CreateSchemaStmtContext::tables, CreateSchemaStmtContext::triggers, ViewStmt::view, and CreateSchemaStmtContext::views.

Referenced by CreateSchemaCommand().

2908 {
2910  List *result;
2911  ListCell *elements;
2912 
2913  cxt.stmtType = "CREATE SCHEMA";
2914  cxt.schemaname = stmt->schemaname;
2915  cxt.authrole = (RoleSpec *) stmt->authrole;
2916  cxt.sequences = NIL;
2917  cxt.tables = NIL;
2918  cxt.views = NIL;
2919  cxt.indexes = NIL;
2920  cxt.triggers = NIL;
2921  cxt.grants = NIL;
2922 
2923  /*
2924  * Run through each schema element in the schema element list. Separate
2925  * statements by type, and do preliminary analysis.
2926  */
2927  foreach(elements, stmt->schemaElts)
2928  {
2929  Node *element = lfirst(elements);
2930 
2931  switch (nodeTag(element))
2932  {
2933  case T_CreateSeqStmt:
2934  {
2935  CreateSeqStmt *elp = (CreateSeqStmt *) element;
2936 
2938  cxt.sequences = lappend(cxt.sequences, element);
2939  }
2940  break;
2941 
2942  case T_CreateStmt:
2943  {
2944  CreateStmt *elp = (CreateStmt *) element;
2945 
2947 
2948  /*
2949  * XXX todo: deal with constraints
2950  */
2951  cxt.tables = lappend(cxt.tables, element);
2952  }
2953  break;
2954 
2955  case T_ViewStmt:
2956  {
2957  ViewStmt *elp = (ViewStmt *) element;
2958 
2959  setSchemaName(cxt.schemaname, &elp->view->schemaname);
2960 
2961  /*
2962  * XXX todo: deal with references between views
2963  */
2964  cxt.views = lappend(cxt.views, element);
2965  }
2966  break;
2967 
2968  case T_IndexStmt:
2969  {
2970  IndexStmt *elp = (IndexStmt *) element;
2971 
2973  cxt.indexes = lappend(cxt.indexes, element);
2974  }
2975  break;
2976 
2977  case T_CreateTrigStmt:
2978  {
2979  CreateTrigStmt *elp = (CreateTrigStmt *) element;
2980 
2982  cxt.triggers = lappend(cxt.triggers, element);
2983  }
2984  break;
2985 
2986  case T_GrantStmt:
2987  cxt.grants = lappend(cxt.grants, element);
2988  break;
2989 
2990  default:
2991  elog(ERROR, "unrecognized node type: %d",
2992  (int) nodeTag(element));
2993  }
2994  }
2995 
2996  result = NIL;
2997  result = list_concat(result, cxt.sequences);
2998  result = list_concat(result, cxt.tables);
2999  result = list_concat(result, cxt.views);
3000  result = list_concat(result, cxt.indexes);
3001  result = list_concat(result, cxt.triggers);
3002  result = list_concat(result, cxt.grants);
3003 
3004  return result;
3005 }
RangeVar * relation
Definition: parsenodes.h:1948
#define NIL
Definition: pg_list.h:69
Definition: nodes.h:504
List * list_concat(List *list1, List *list2)
Definition: list.c:321
return result
Definition: formatting.c:1618
RangeVar * view
Definition: parsenodes.h:2941
char * schemaname
Definition: primnodes.h:67
RangeVar * relation
Definition: parsenodes.h:2640
RoleSpec * authrole
Definition: parsenodes.h:1623
#define ERROR
Definition: elog.h:43
List * lappend(List *list, void *datum)
Definition: list.c:128
static chr element(struct vars *v, const chr *startp, const chr *endp)
Definition: regc_locale.c:380
RangeVar * sequence
Definition: parsenodes.h:2412
#define lfirst(lc)
Definition: pg_list.h:106
static void setSchemaName(char *context_schema, char **stmt_schema_name)
#define nodeTag(nodeptr)
Definition: nodes.h:509
RangeVar * relation
Definition: parsenodes.h:2297
#define elog
Definition: elog.h:219
Definition: pg_list.h:45
List* transformCreateStmt ( CreateStmt stmt,
const char *  queryString 
)

Definition at line 154 of file parse_utilcmd.c.

References CreateStmtContext::alist, Assert, CreateStmtContext::blist, cancel_parser_errposition_callback(), CreateStmtContext::ckconstraints, CreateStmtContext::columns, CreateStmt::constraints, copyObject(), element(), elog, ereport, errcode(), errmsg(), ERROR, CreateStmtContext::fkconstraints, get_namespace_name(), CreateStmtContext::hasoids, CreateStmt::if_not_exists, CreateStmtContext::inh_indexes, CreateStmtContext::inhRelations, CreateStmt::inhRelations, interpretOidsOption(), IsA, CreateStmtContext::isalter, CreateStmtContext::isforeign, CreateStmtContext::ispartitioned, CreateStmtContext::ixconstraints, lappend(), lcons(), lfirst, list_concat(), list_length(), RangeVar::location, make_parsestate(), makeDefElem(), makeInteger(), NIL, nodeTag, NoLock, NOTICE, NULL, CreateStmt::ofTypename, OidIsValid, CreateStmt::options, ParseState::p_sourcetext, CreateStmt::partbound, PARTITION_MAX_KEYS, PartitionSpec::partParams, CreateStmt::partspec, pg_strcasecmp(), CreateStmtContext::pkey, CreateStmtContext::pstate, RangeVarGetAndCheckCreationNamespace(), CreateStmtContext::rel, CreateStmtContext::relation, CreateStmt::relation, RangeVar::relname, RangeVar::relpersistence, RELPERSISTENCE_TEMP, result, RangeVar::schemaname, setup_parser_errposition_callback(), CreateStmtContext::stmtType, PartitionSpec::strategy, T_ColumnDef, T_Constraint, T_TableLikeClause, CreateStmt::tableElts, transformCheckConstraints(), transformColumnDefinition(), transformFKConstraints(), transformIndexConstraints(), transformOfType(), transformTableConstraint(), and transformTableLikeClause().

Referenced by ProcessUtilitySlow().

155 {
156  ParseState *pstate;
157  CreateStmtContext cxt;
158  List *result;
159  List *save_alist;
160  ListCell *elements;
161  Oid namespaceid;
162  Oid existing_relid;
163  ParseCallbackState pcbstate;
164  bool like_found = false;
165 
166  /*
167  * We must not scribble on the passed-in CreateStmt, so copy it. (This is
168  * overkill, but easy.)
169  */
170  stmt = (CreateStmt *) copyObject(stmt);
171 
172  /* Set up pstate */
173  pstate = make_parsestate(NULL);
174  pstate->p_sourcetext = queryString;
175 
176  /*
177  * Look up the creation namespace. This also checks permissions on the
178  * target namespace, locks it against concurrent drops, checks for a
179  * preexisting relation in that namespace with the same name, and updates
180  * stmt->relation->relpersistence if the selected namespace is temporary.
181  */
182  setup_parser_errposition_callback(&pcbstate, pstate,
183  stmt->relation->location);
184  namespaceid =
186  &existing_relid);
188 
189  /*
190  * If the relation already exists and the user specified "IF NOT EXISTS",
191  * bail out with a NOTICE.
192  */
193  if (stmt->if_not_exists && OidIsValid(existing_relid))
194  {
195  ereport(NOTICE,
196  (errcode(ERRCODE_DUPLICATE_TABLE),
197  errmsg("relation \"%s\" already exists, skipping",
198  stmt->relation->relname)));
199  return NIL;
200  }
201 
202  /*
203  * If the target relation name isn't schema-qualified, make it so. This
204  * prevents some corner cases in which added-on rewritten commands might
205  * think they should apply to other relations that have the same name and
206  * are earlier in the search path. But a local temp table is effectively
207  * specified to be in pg_temp, so no need for anything extra in that case.
208  */
209  if (stmt->relation->schemaname == NULL
211  stmt->relation->schemaname = get_namespace_name(namespaceid);
212 
213  /* Set up CreateStmtContext */
214  cxt.pstate = pstate;
215  if (IsA(stmt, CreateForeignTableStmt))
216  {
217  cxt.stmtType = "CREATE FOREIGN TABLE";
218  cxt.isforeign = true;
219  }
220  else
221  {
222  cxt.stmtType = "CREATE TABLE";
223  cxt.isforeign = false;
224  }
225  cxt.relation = stmt->relation;
226  cxt.rel = NULL;
227  cxt.inhRelations = stmt->inhRelations;
228  cxt.isalter = false;
229  cxt.columns = NIL;
230  cxt.ckconstraints = NIL;
231  cxt.fkconstraints = NIL;
232  cxt.ixconstraints = NIL;
233  cxt.inh_indexes = NIL;
234  cxt.blist = NIL;
235  cxt.alist = NIL;
236  cxt.pkey = NULL;
237  cxt.ispartitioned = stmt->partspec != NULL;
238 
239  /*
240  * Notice that we allow OIDs here only for plain tables, even though
241  * foreign tables also support them. This is necessary because the
242  * default_with_oids GUC must apply only to plain tables and not any other
243  * relkind; doing otherwise would break existing pg_dump files. We could
244  * allow explicit "WITH OIDS" while not allowing default_with_oids to
245  * affect other relkinds, but it would complicate interpretOidsOption(),
246  * and right now there's no WITH OIDS option in CREATE FOREIGN TABLE
247  * anyway.
248  */
249  cxt.hasoids = interpretOidsOption(stmt->options, !cxt.isforeign);
250 
251  Assert(!stmt->ofTypename || !stmt->inhRelations); /* grammar enforces */
252 
253  if (stmt->ofTypename)
254  transformOfType(&cxt, stmt->ofTypename);
255 
256  if (stmt->partspec)
257  {
258  int partnatts = list_length(stmt->partspec->partParams);
259 
260  if (stmt->inhRelations && !stmt->partbound)
261  ereport(ERROR,
262  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
263  errmsg("cannot create partitioned table as inheritance child")));
264 
265  if (partnatts > PARTITION_MAX_KEYS)
266  ereport(ERROR,
267  (errcode(ERRCODE_TOO_MANY_COLUMNS),
268  errmsg("cannot partition using more than %d columns",
270 
271  if (!pg_strcasecmp(stmt->partspec->strategy, "list") &&
272  partnatts > 1)
273  ereport(ERROR,
274  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
275  errmsg("cannot list partition using more than one column")));
276  }
277 
278  /*
279  * Run through each primary element in the table creation clause. Separate
280  * column defs from constraints, and do preliminary analysis.
281  */
282  foreach(elements, stmt->tableElts)
283  {
284  Node *element = lfirst(elements);
285 
286  switch (nodeTag(element))
287  {
288  case T_ColumnDef:
289  transformColumnDefinition(&cxt, (ColumnDef *) element);
290  break;
291 
292  case T_Constraint:
293  transformTableConstraint(&cxt, (Constraint *) element);
294  break;
295 
296  case T_TableLikeClause:
297  like_found = true;
298  transformTableLikeClause(&cxt, (TableLikeClause *) element);
299  break;
300 
301  default:
302  elog(ERROR, "unrecognized node type: %d",
303  (int) nodeTag(element));
304  break;
305  }
306  }
307 
308  /*
309  * If we had any LIKE tables, they may require creation of an OID column
310  * even though the command's own WITH clause didn't ask for one (or,
311  * perhaps, even specifically rejected having one). Insert a WITH option
312  * to ensure that happens. We prepend to the list because the first oid
313  * option will be honored, and we want to override anything already there.
314  * (But note that DefineRelation will override this again to add an OID
315  * column if one appears in an inheritance parent table.)
316  */
317  if (like_found && cxt.hasoids)
318  stmt->options = lcons(makeDefElem("oids",
319  (Node *) makeInteger(true), -1),
320  stmt->options);
321 
322  /*
323  * transformIndexConstraints wants cxt.alist to contain only index
324  * statements, so transfer anything we already have into save_alist.
325  */
326  save_alist = cxt.alist;
327  cxt.alist = NIL;
328 
329  Assert(stmt->constraints == NIL);
330 
331  /*
332  * Postprocess constraints that give rise to index definitions.
333  */
335 
336  /*
337  * Postprocess foreign-key constraints.
338  */
339  transformFKConstraints(&cxt, true, false);
340 
341  /*
342  * Postprocess check constraints.
343  */
344  transformCheckConstraints(&cxt, true);
345 
346  /*
347  * Output results.
348  */
349  stmt->tableElts = cxt.columns;
350  stmt->constraints = cxt.ckconstraints;
351 
352  result = lappend(cxt.blist, stmt);
353  result = list_concat(result, cxt.alist);
354  result = list_concat(result, save_alist);
355 
356  return result;
357 }
RangeVar * relation
Definition: parsenodes.h:1948
#define NIL
Definition: pg_list.h:69
List * inhRelations
Definition: parsenodes.h:1950
#define IsA(nodeptr, _type_)
Definition: nodes.h:555
List * partParams
Definition: parsenodes.h:765
Definition: nodes.h:504
int errcode(int sqlerrcode)
Definition: elog.c:575
#define PARTITION_MAX_KEYS
List * list_concat(List *list1, List *list2)
Definition: list.c:321
return result
Definition: formatting.c:1618
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:538
DefElem * makeDefElem(char *name, Node *arg, int location)
Definition: makefuncs.c:543
char * schemaname
Definition: primnodes.h:67
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
void * copyObject(const void *from)
Definition: copyfuncs.c:4619
List * constraints
Definition: parsenodes.h:1955
bool if_not_exists
Definition: parsenodes.h:1959
int location
Definition: primnodes.h:73
ParseState * pstate
Definition: parse_utilcmd.c:74
char * relname
Definition: primnodes.h:68
Value * makeInteger(long i)
Definition: value.c:23
RangeVar * relation
Definition: parse_utilcmd.c:76
IndexStmt * pkey
Definition: parse_utilcmd.c:91
void cancel_parser_errposition_callback(ParseCallbackState *pcbstate)
Definition: parse_node.c:159
#define ERROR
Definition: elog.h:43
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3006
#define NoLock
Definition: lockdefs.h:34
List * options
Definition: parsenodes.h:1956
const char * p_sourcetext
Definition: parse_node.h:167
#define ereport(elevel, rest)
Definition: elog.h:122
void setup_parser_errposition_callback(ParseCallbackState *pcbstate, ParseState *pstate, int location)
Definition: parse_node.c:143
List * lappend(List *list, void *datum)
Definition: list.c:128
static chr element(struct vars *v, const chr *startp, const chr *endp)
Definition: regc_locale.c:380
Oid RangeVarGetAndCheckCreationNamespace(RangeVar *relation, LOCKMODE lockmode, Oid *existing_relation_id)
Definition: namespace.c:507
Node * partbound
Definition: parsenodes.h:1952
#define NOTICE
Definition: elog.h:37
List * tableElts
Definition: parsenodes.h:1949
List * lcons(void *datum, List *list)
Definition: list.c:259
static void transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
static void transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
static int list_length(const List *l)
Definition: pg_list.h:89
static void transformFKConstraints(CreateStmtContext *cxt, bool skipValidation, bool isAddConstraint)
#define nodeTag(nodeptr)
Definition: nodes.h:509
const char * stmtType
Definition: parse_utilcmd.c:75
char relpersistence
Definition: primnodes.h:71
bool interpretOidsOption(List *defList, bool allowOids)
Definition: parse_clause.c:244
char * strategy
Definition: parsenodes.h:764
int errmsg(const char *fmt,...)
Definition: elog.c:797
#define elog
Definition: elog.h:219
#define RELPERSISTENCE_TEMP
Definition: pg_class.h:172
static void transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
static void transformIndexConstraints(CreateStmtContext *cxt)
PartitionSpec * partspec
Definition: parsenodes.h:1953
Definition: pg_list.h:45
static void transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_clause)
TypeName * ofTypename
Definition: parsenodes.h:1954
static void transformCheckConstraints(CreateStmtContext *cxt, bool skipValidation)
static void transformFKConstraints ( CreateStmtContext cxt,
bool  skipValidation,
bool  isAddConstraint 
)
static

Definition at line 2024 of file parse_utilcmd.c.

References CreateStmtContext::alist, AT_ProcessedConstraint, AlterTableStmt::cmds, AlterTableCmd::def, CreateStmtContext::fkconstraints, Constraint::initially_valid, lappend(), lfirst, makeNode, AlterTableCmd::name, NIL, NULL, OBJECT_TABLE, CreateStmtContext::relation, AlterTableStmt::relation, AlterTableStmt::relkind, Constraint::skip_validation, and AlterTableCmd::subtype.

Referenced by transformAlterTableStmt(), and transformCreateStmt().

2026 {
2027  ListCell *fkclist;
2028 
2029  if (cxt->fkconstraints == NIL)
2030  return;
2031 
2032  /*
2033  * If CREATE TABLE or adding a column with NULL default, we can safely
2034  * skip validation of FK constraints, and nonetheless mark them valid.
2035  * (This will override any user-supplied NOT VALID flag.)
2036  */
2037  if (skipValidation)
2038  {
2039  foreach(fkclist, cxt->fkconstraints)
2040  {
2041  Constraint *constraint = (Constraint *) lfirst(fkclist);
2042 
2043  constraint->skip_validation = true;
2044  constraint->initially_valid = true;
2045  }
2046  }
2047 
2048  /*
2049  * For CREATE TABLE or ALTER TABLE ADD COLUMN, gin up an ALTER TABLE ADD
2050  * CONSTRAINT command to execute after the basic command is complete. (If
2051  * called from ADD CONSTRAINT, that routine will add the FK constraints to
2052  * its own subcommand list.)
2053  *
2054  * Note: the ADD CONSTRAINT command must also execute after any index
2055  * creation commands. Thus, this should run after
2056  * transformIndexConstraints, so that the CREATE INDEX commands are
2057  * already in cxt->alist.
2058  */
2059  if (!isAddConstraint)
2060  {
2061  AlterTableStmt *alterstmt = makeNode(AlterTableStmt);
2062 
2063  alterstmt->relation = cxt->relation;
2064  alterstmt->cmds = NIL;
2065  alterstmt->relkind = OBJECT_TABLE;
2066 
2067  foreach(fkclist, cxt->fkconstraints)
2068  {
2069  Constraint *constraint = (Constraint *) lfirst(fkclist);
2070  AlterTableCmd *altercmd = makeNode(AlterTableCmd);
2071 
2072  altercmd->subtype = AT_ProcessedConstraint;
2073  altercmd->name = NULL;
2074  altercmd->def = (Node *) constraint;
2075  alterstmt->cmds = lappend(alterstmt->cmds, altercmd);
2076  }
2077 
2078  cxt->alist = lappend(cxt->alist, alterstmt);
2079  }
2080 }
#define NIL
Definition: pg_list.h:69
Definition: nodes.h:504
AlterTableType subtype
Definition: parsenodes.h:1725
RangeVar * relation
Definition: parse_utilcmd.c:76
ObjectType relkind
Definition: parsenodes.h:1643
List * lappend(List *list, void *datum)
Definition: list.c:128
bool initially_valid
Definition: parsenodes.h:2064
#define makeNode(_type_)
Definition: nodes.h:552
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
RangeVar * relation
Definition: parsenodes.h:1641
bool skip_validation
Definition: parsenodes.h:2063
static IndexStmt * transformIndexConstraint ( Constraint constraint,
CreateStmtContext cxt 
)
static

Definition at line 1613 of file parse_utilcmd.c.

References Constraint::access_method, IndexStmt::accessMethod, AccessShareLock, Anum_pg_index_indclass, Assert, tupleDesc::attrs, castNode, IndexElem::collation, ColumnDef::colname, CreateStmtContext::columns, IndexStmt::concurrent, Constraint::conname, CONSTR_EXCLUSION, CONSTR_PRIMARY, CONSTR_UNIQUE, Constraint::contype, DatumGetPointer, DEFAULT_INDEX_TYPE, Constraint::deferrable, IndexStmt::deferrable, ereport, errcode(), errdetail(), errmsg(), ERROR, IndexStmt::excludeOpNames, Constraint::exclusions, IndexElem::expr, get_index_am_oid(), get_index_constraint(), get_relname_relid(), GetDefaultOpClass(), CreateStmtContext::hasoids, heap_close, heap_openrv(), i, IndexStmt::idxcomment, IndexStmt::idxname, IndexStmt::if_not_exists, index_open(), IndexElem::indexcolname, IndexIsValid, Constraint::indexname, IndexStmt::indexOid, IndexStmt::indexParams, INDEXRELID, Constraint::indexspace, CreateStmtContext::inhRelations, Constraint::initdeferred, IndexStmt::initdeferred, InvalidOid, ColumnDef::is_not_null, CreateStmtContext::isalter, IndexStmt::isconstraint, Constraint::keys, lappend(), lfirst, linitial, list_length(), Constraint::location, lsecond, makeNode, makeString(), IndexElem::name, NameStr, tupleDesc::natts, NIL, NoLock, NULL, IndexElem::nulls_ordering, OidIsValid, IndexStmt::oldNode, IndexElem::opclass, Constraint::options, IndexStmt::options, IndexElem::ordering, parser_errposition(), CreateStmtContext::pkey, IndexStmt::primary, CreateStmtContext::pstate, pstrdup(), RelationData::rd_att, RelationData::rd_index, RelationData::rd_indextuple, RelationData::rd_indoption, RelationData::rd_rel, CreateStmtContext::rel, CreateStmtContext::relation, IndexStmt::relation, relation_close(), RelationGetIndexExpressions(), RelationGetIndexPredicate(), RelationGetNamespace, RelationGetRelationName, RelationGetRelid, RELKIND_FOREIGN_TABLE, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, RangeVar::relname, SORTBY_DEFAULT, SORTBY_NULLS_DEFAULT, strVal, SysCacheGetAttr(), SystemAttributeByName(), SystemAttributeDefinition(), IndexStmt::tableSpace, IndexStmt::transformed, TRUE, IndexStmt::unique, oidvector::values, Constraint::where_clause, and IndexStmt::whereClause.

Referenced by transformIndexConstraints().

1614 {
1615  IndexStmt *index;
1616  ListCell *lc;
1617 
1618  index = makeNode(IndexStmt);
1619 
1620  index->unique = (constraint->contype != CONSTR_EXCLUSION);
1621  index->primary = (constraint->contype == CONSTR_PRIMARY);
1622  if (index->primary)
1623  {
1624  if (cxt->pkey != NULL)
1625  ereport(ERROR,
1626  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
1627  errmsg("multiple primary keys for table \"%s\" are not allowed",
1628  cxt->relation->relname),
1629  parser_errposition(cxt->pstate, constraint->location)));
1630  cxt->pkey = index;
1631 
1632  /*
1633  * In ALTER TABLE case, a primary index might already exist, but
1634  * DefineIndex will check for it.
1635  */
1636  }
1637  index->isconstraint = true;
1638  index->deferrable = constraint->deferrable;
1639  index->initdeferred = constraint->initdeferred;
1640 
1641  if (constraint->conname != NULL)
1642  index->idxname = pstrdup(constraint->conname);
1643  else
1644  index->idxname = NULL; /* DefineIndex will choose name */
1645 
1646  index->relation = cxt->relation;
1647  index->accessMethod = constraint->access_method ? constraint->access_method : DEFAULT_INDEX_TYPE;
1648  index->options = constraint->options;
1649  index->tableSpace = constraint->indexspace;
1650  index->whereClause = constraint->where_clause;
1651  index->indexParams = NIL;
1652  index->excludeOpNames = NIL;
1653  index->idxcomment = NULL;
1654  index->indexOid = InvalidOid;
1655  index->oldNode = InvalidOid;
1656  index->transformed = false;
1657  index->concurrent = false;
1658  index->if_not_exists = false;
1659 
1660  /*
1661  * If it's ALTER TABLE ADD CONSTRAINT USING INDEX, look up the index and
1662  * verify it's usable, then extract the implied column name list. (We
1663  * will not actually need the column name list at runtime, but we need it
1664  * now to check for duplicate column entries below.)
1665  */
1666  if (constraint->indexname != NULL)
1667  {
1668  char *index_name = constraint->indexname;
1669  Relation heap_rel = cxt->rel;
1670  Oid index_oid;
1671  Relation index_rel;
1672  Form_pg_index index_form;
1673  oidvector *indclass;
1674  Datum indclassDatum;
1675  bool isnull;
1676  int i;
1677 
1678  /* Grammar should not allow this with explicit column list */
1679  Assert(constraint->keys == NIL);
1680 
1681  /* Grammar should only allow PRIMARY and UNIQUE constraints */
1682  Assert(constraint->contype == CONSTR_PRIMARY ||
1683  constraint->contype == CONSTR_UNIQUE);
1684 
1685  /* Must be ALTER, not CREATE, but grammar doesn't enforce that */
1686  if (!cxt->isalter)
1687  ereport(ERROR,
1688  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1689  errmsg("cannot use an existing index in CREATE TABLE"),
1690  parser_errposition(cxt->pstate, constraint->location)));
1691 
1692  /* Look for the index in the same schema as the table */
1693  index_oid = get_relname_relid(index_name, RelationGetNamespace(heap_rel));
1694 
1695  if (!OidIsValid(index_oid))
1696  ereport(ERROR,
1697  (errcode(ERRCODE_UNDEFINED_OBJECT),
1698  errmsg("index \"%s\" does not exist", index_name),
1699  parser_errposition(cxt->pstate, constraint->location)));
1700 
1701  /* Open the index (this will throw an error if it is not an index) */
1702  index_rel = index_open(index_oid, AccessShareLock);
1703  index_form = index_rel->rd_index;
1704 
1705  /* Check that it does not have an associated constraint already */
1706  if (OidIsValid(get_index_constraint(index_oid)))
1707  ereport(ERROR,
1708  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1709  errmsg("index \"%s\" is already associated with a constraint",
1710  index_name),
1711  parser_errposition(cxt->pstate, constraint->location)));
1712 
1713  /* Perform validity checks on the index */
1714  if (index_form->indrelid != RelationGetRelid(heap_rel))
1715  ereport(ERROR,
1716  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1717  errmsg("index \"%s\" does not belong to table \"%s\"",
1718  index_name, RelationGetRelationName(heap_rel)),
1719  parser_errposition(cxt->pstate, constraint->location)));
1720 
1721  if (!IndexIsValid(index_form))
1722  ereport(ERROR,
1723  (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
1724  errmsg("index \"%s\" is not valid", index_name),
1725  parser_errposition(cxt->pstate, constraint->location)));
1726 
1727  if (!index_form->indisunique)
1728  ereport(ERROR,
1729  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1730  errmsg("\"%s\" is not a unique index", index_name),
1731  errdetail("Cannot create a primary key or unique constraint using such an index."),
1732  parser_errposition(cxt->pstate, constraint->location)));
1733 
1734  if (RelationGetIndexExpressions(index_rel) != NIL)
1735  ereport(ERROR,
1736  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1737  errmsg("index \"%s\" contains expressions", index_name),
1738  errdetail("Cannot create a primary key or unique constraint using such an index."),
1739  parser_errposition(cxt->pstate, constraint->location)));
1740 
1741  if (RelationGetIndexPredicate(index_rel) != NIL)
1742  ereport(ERROR,
1743  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1744  errmsg("\"%s\" is a partial index", index_name),
1745  errdetail("Cannot create a primary key or unique constraint using such an index."),
1746  parser_errposition(cxt->pstate, constraint->location)));
1747 
1748  /*
1749  * It's probably unsafe to change a deferred index to non-deferred. (A
1750  * non-constraint index couldn't be deferred anyway, so this case
1751  * should never occur; no need to sweat, but let's check it.)
1752  */
1753  if (!index_form->indimmediate && !constraint->deferrable)
1754  ereport(ERROR,
1755  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1756  errmsg("\"%s\" is a deferrable index", index_name),
1757  errdetail("Cannot create a non-deferrable constraint using a deferrable index."),
1758  parser_errposition(cxt->pstate, constraint->location)));
1759 
1760  /*
1761  * Insist on it being a btree. That's the only kind that supports
1762  * uniqueness at the moment anyway; but we must have an index that
1763  * exactly matches what you'd get from plain ADD CONSTRAINT syntax,
1764  * else dump and reload will produce a different index (breaking
1765  * pg_upgrade in particular).
1766  */
1767  if (index_rel->rd_rel->relam != get_index_am_oid(DEFAULT_INDEX_TYPE, false))
1768  ereport(ERROR,
1769  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1770  errmsg("index \"%s\" is not a btree", index_name),
1771  parser_errposition(cxt->pstate, constraint->location)));
1772 
1773  /* Must get indclass the hard way */
1774  indclassDatum = SysCacheGetAttr(INDEXRELID, index_rel->rd_indextuple,
1775  Anum_pg_index_indclass, &isnull);
1776  Assert(!isnull);
1777  indclass = (oidvector *) DatumGetPointer(indclassDatum);
1778 
1779  for (i = 0; i < index_form->indnatts; i++)
1780  {
1781  int16 attnum = index_form->indkey.values[i];
1782  Form_pg_attribute attform;
1783  char *attname;
1784  Oid defopclass;
1785 
1786  /*
1787  * We shouldn't see attnum == 0 here, since we already rejected
1788  * expression indexes. If we do, SystemAttributeDefinition will
1789  * throw an error.
1790  */
1791  if (attnum > 0)
1792  {
1793  Assert(attnum <= heap_rel->rd_att->natts);
1794  attform = heap_rel->rd_att->attrs[attnum - 1];
1795  }
1796  else
1797  attform = SystemAttributeDefinition(attnum,
1798  heap_rel->rd_rel->relhasoids);
1799  attname = pstrdup(NameStr(attform->attname));
1800 
1801  /*
1802  * Insist on default opclass and sort options. While the index
1803  * would still work as a constraint with non-default settings, it
1804  * might not provide exactly the same uniqueness semantics as
1805  * you'd get from a normally-created constraint; and there's also
1806  * the dump/reload problem mentioned above.
1807  */
1808  defopclass = GetDefaultOpClass(attform->atttypid,
1809  index_rel->rd_rel->relam);
1810  if (indclass->values[i] != defopclass ||
1811  index_rel->rd_indoption[i] != 0)
1812  ereport(ERROR,
1813  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1814  errmsg("index \"%s\" does not have default sorting behavior", index_name),
1815  errdetail("Cannot create a primary key or unique constraint using such an index."),
1816  parser_errposition(cxt->pstate, constraint->location)));
1817 
1818  constraint->keys = lappend(constraint->keys, makeString(attname));
1819  }
1820 
1821  /* Close the index relation but keep the lock */
1822  relation_close(index_rel, NoLock);
1823 
1824  index->indexOid = index_oid;
1825  }
1826 
1827  /*
1828  * If it's an EXCLUDE constraint, the grammar returns a list of pairs of
1829  * IndexElems and operator names. We have to break that apart into
1830  * separate lists.
1831  */
1832  if (constraint->contype == CONSTR_EXCLUSION)
1833  {
1834  foreach(lc, constraint->exclusions)
1835  {
1836  List *pair = (List *) lfirst(lc);
1837  IndexElem *elem;
1838  List *opname;
1839 
1840  Assert(list_length(pair) == 2);
1841  elem = castNode(IndexElem, linitial(pair));
1842  opname = castNode(List, lsecond(pair));
1843 
1844  index->indexParams = lappend(index->indexParams, elem);
1845  index->excludeOpNames = lappend(index->excludeOpNames, opname);
1846  }
1847 
1848  return index;
1849  }
1850 
1851  /*
1852  * For UNIQUE and PRIMARY KEY, we just have a list of column names.
1853  *
1854  * Make sure referenced keys exist. If we are making a PRIMARY KEY index,
1855  * also make sure they are NOT NULL, if possible. (Although we could leave
1856  * it to DefineIndex to mark the columns NOT NULL, it's more efficient to
1857  * get it right the first time.)
1858  */
1859  foreach(lc, constraint->keys)
1860  {
1861  char *key = strVal(lfirst(lc));
1862  bool found = false;
1863  ColumnDef *column = NULL;
1864  ListCell *columns;
1865  IndexElem *iparam;
1866 
1867  foreach(columns, cxt->columns)
1868  {
1869  column = castNode(ColumnDef, lfirst(columns));
1870  if (strcmp(column->colname, key) == 0)
1871  {
1872  found = true;
1873  break;
1874  }
1875  }
1876  if (found)
1877  {
1878  /* found column in the new table; force it to be NOT NULL */
1879  if (constraint->contype == CONSTR_PRIMARY)
1880  column->is_not_null = TRUE;
1881  }
1882  else if (SystemAttributeByName(key, cxt->hasoids) != NULL)
1883  {
1884  /*
1885  * column will be a system column in the new table, so accept it.
1886  * System columns can't ever be null, so no need to worry about
1887  * PRIMARY/NOT NULL constraint.
1888  */
1889  found = true;
1890  }
1891  else if (cxt->inhRelations)
1892  {
1893  /* try inherited tables */
1894  ListCell *inher;
1895 
1896  foreach(inher, cxt->inhRelations)
1897  {
1898  RangeVar *inh = castNode(RangeVar, lfirst(inher));
1899  Relation rel;
1900  int count;
1901 
1902  rel = heap_openrv(inh, AccessShareLock);
1903  /* check user requested inheritance from valid relkind */
1904  if (rel->rd_rel->relkind != RELKIND_RELATION &&
1905  rel->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
1906  rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
1907  ereport(ERROR,
1908  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
1909  errmsg("inherited relation \"%s\" is not a table or foreign table",
1910  inh->relname)));
1911  for (count = 0; count < rel->rd_att->natts; count++)
1912  {
1913  Form_pg_attribute inhattr = rel->rd_att->attrs[count];
1914  char *inhname = NameStr(inhattr->attname);
1915 
1916  if (inhattr->attisdropped)
1917  continue;
1918  if (strcmp(key, inhname) == 0)
1919  {
1920  found = true;
1921 
1922  /*
1923  * We currently have no easy way to force an inherited
1924  * column to be NOT NULL at creation, if its parent
1925  * wasn't so already. We leave it to DefineIndex to
1926  * fix things up in this case.
1927  */
1928  break;
1929  }
1930  }
1931  heap_close(rel, NoLock);
1932  if (found)
1933  break;
1934  }
1935  }
1936 
1937  /*
1938  * In the ALTER TABLE case, don't complain about index keys not
1939  * created in the command; they may well exist already. DefineIndex
1940  * will complain about them if not, and will also take care of marking
1941  * them NOT NULL.
1942  */
1943  if (!found && !cxt->isalter)
1944  ereport(ERROR,
1945  (errcode(ERRCODE_UNDEFINED_COLUMN),
1946  errmsg("column \"%s\" named in key does not exist", key),
1947  parser_errposition(cxt->pstate, constraint->location)));
1948 
1949  /* Check for PRIMARY KEY(foo, foo) */
1950  foreach(columns, index->indexParams)
1951  {
1952  iparam = (IndexElem *) lfirst(columns);
1953  if (iparam->name && strcmp(key, iparam->name) == 0)
1954  {
1955  if (index->primary)
1956  ereport(ERROR,
1957  (errcode(ERRCODE_DUPLICATE_COLUMN),
1958  errmsg("column \"%s\" appears twice in primary key constraint",
1959  key),
1960  parser_errposition(cxt->pstate, constraint->location)));
1961  else
1962  ereport(ERROR,
1963  (errcode(ERRCODE_DUPLICATE_COLUMN),
1964  errmsg("column \"%s\" appears twice in unique constraint",
1965  key),
1966  parser_errposition(cxt->pstate, constraint->location)));
1967  }
1968  }
1969 
1970  /* OK, add it to the index definition */
1971  iparam = makeNode(IndexElem);
1972  iparam->name = pstrdup(key);
1973  iparam->expr = NULL;
1974  iparam->indexcolname = NULL;
1975  iparam->collation = NIL;
1976  iparam->opclass = NIL;
1977  iparam->ordering = SORTBY_DEFAULT;
1979  index->indexParams = lappend(index->indexParams, iparam);
1980  }
1981 
1982  return index;
1983 }
bool deferrable
Definition: parsenodes.h:2653
Value * makeString(char *str)
Definition: value.c:53
signed short int16
Definition: c.h:255
#define NIL
Definition: pg_list.h:69
Definition: c.h:478
bool primary
Definition: parsenodes.h:2651
List * keys
Definition: parsenodes.h:2039
List * exclusions
Definition: parsenodes.h:2042
int16 * rd_indoption
Definition: rel.h:186
Oid GetDefaultOpClass(Oid type_id, Oid am_id)
Definition: indexcmds.c:1378
SortByDir ordering
Definition: parsenodes.h:682
List * options
Definition: parsenodes.h:2644
#define IndexIsValid(indexForm)
Definition: pg_index.h:107
#define castNode(_type_, nodeptr)
Definition: nodes.h:573
char * tableSpace
Definition: parsenodes.h:2642
char * pstrdup(const char *in)
Definition: mcxt.c:1077
Form_pg_attribute * attrs
Definition: tupdesc.h:74
Node * whereClause
Definition: parsenodes.h:2645
#define Anum_pg_index_indclass
Definition: pg_index.h:89
Form_pg_attribute SystemAttributeByName(const char *attname, bool relhasoids)
Definition: heap.c:214
#define AccessShareLock
Definition: lockdefs.h:36
#define strVal(v)
Definition: value.h:54
int errcode(int sqlerrcode)
Definition: elog.c:575
void relation_close(Relation relation, LOCKMODE lockmode)
Definition: heapam.c:1263
bool initdeferred
Definition: parsenodes.h:2030
#define heap_close(r, l)
Definition: heapam.h:97
char * conname
Definition: parsenodes.h:2028
bool is_not_null
Definition: parsenodes.h:635
Form_pg_class rd_rel
Definition: rel.h:114
unsigned int Oid
Definition: postgres_ext.h:31
#define OidIsValid(objectId)
Definition: c.h:538
int natts
Definition: tupdesc.h:73
#define lsecond(l)
Definition: pg_list.h:114
List * options
Definition: parsenodes.h:2045
List * RelationGetIndexPredicate(Relation relation)
Definition: relcache.c:4753
struct HeapTupleData * rd_indextuple
Definition: rel.h:161
Definition: type.h:90
ParseState * pstate
Definition: parse_utilcmd.c:74
char * relname
Definition: primnodes.h:68
Oid indexOid
Definition: parsenodes.h:2648
Node * expr
Definition: parsenodes.h:678
RangeVar * relation
Definition: parse_utilcmd.c:76
RangeVar * relation
Definition: parsenodes.h:2640
IndexStmt * pkey
Definition: parse_utilcmd.c:91
Form_pg_index rd_index
Definition: rel.h:159
#define linitial(l)
Definition: pg_list.h:110
SortByNulls nulls_ordering
Definition: parsenodes.h:683
#define ERROR
Definition: elog.h:43
bool deferrable
Definition: parsenodes.h:2029
Oid get_relname_relid(const char *relname, Oid relnamespace)
Definition: lsyscache.c:1651
Oid get_index_am_oid(const char *amname, bool missing_ok)
Definition: amcmds.c:183
#define NoLock
Definition: lockdefs.h:34
List * RelationGetIndexExpressions(Relation relation)
Definition: relcache.c:4690
Oid values[FLEXIBLE_ARRAY_MEMBER]
Definition: c.h:486
bool transformed
Definition: parsenodes.h:2655
int errdetail(const char *fmt,...)
Definition: elog.c:873
char * indexcolname
Definition: parsenodes.h:679
#define DEFAULT_INDEX_TYPE
Definition: index.h:21
#define RelationGetRelationName(relation)
Definition: rel.h:437
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:184
Oid get_index_constraint(Oid indexId)
Definition: pg_depend.c:676
#define RELKIND_FOREIGN_TABLE
Definition: pg_class.h:167
#define ereport(elevel, rest)
Definition: elog.h:122
List * lappend(List *list, void *datum)
Definition: list.c:128
char * idxname
Definition: parsenodes.h:2639
FormData_pg_index * Form_pg_index
Definition: pg_index.h:67
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
bool if_not_exists
Definition: parsenodes.h:2657
uintptr_t Datum
Definition: postgres.h:372
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1278
bool unique
Definition: parsenodes.h:2650
TupleDesc rd_att
Definition: rel.h:115
char * accessMethod
Definition: parsenodes.h:2641
Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: heapam.c:1315
Form_pg_attribute SystemAttributeDefinition(AttrNumber attno, bool relhasoids)
Definition: heap.c:200
#define InvalidOid
Definition: postgres_ext.h:36
List * opclass
Definition: parsenodes.h:681
Node * where_clause
Definition: parsenodes.h:2050
#define makeNode(_type_)
Definition: nodes.h:552
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
List * indexParams
Definition: parsenodes.h:2643
List * excludeOpNames
Definition: parsenodes.h:2646
static int list_length(const List *l)
Definition: pg_list.h:89
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:109
bool initdeferred
Definition: parsenodes.h:2654
char * name
Definition: parsenodes.h:677
char * idxcomment
Definition: parsenodes.h:2647
#define DatumGetPointer(X)
Definition: postgres.h:555
bool concurrent
Definition: parsenodes.h:2656
bool isconstraint
Definition: parsenodes.h:2652
char * indexname
Definition: parsenodes.h:2046
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define NameStr(name)
Definition: c.h:499
ConstrType contype
Definition: parsenodes.h:2025
List * collation
Definition: parsenodes.h:680
char * colname
Definition: parsenodes.h:631
#define TRUE
Definition: c.h:217
#define RELKIND_RELATION
Definition: pg_class.h:160
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:417
char * access_method
Definition: parsenodes.h:2049
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:151
char * indexspace
Definition: parsenodes.h:2047
#define RelationGetNamespace(relation)
Definition: rel.h:444
static void transformIndexConstraints ( CreateStmtContext cxt)
static

Definition at line 1506 of file parse_utilcmd.c.

References IndexStmt::accessMethod, CreateStmtContext::alist, Assert, castNode, CONSTR_EXCLUSION, CONSTR_PRIMARY, CONSTR_UNIQUE, Constraint::contype, IndexStmt::deferrable, equal(), ereport, errcode(), errmsg(), ERROR, IndexStmt::excludeOpNames, IndexStmt::idxname, IndexStmt::indexParams, CreateStmtContext::inh_indexes, IndexStmt::initdeferred, CreateStmtContext::ixconstraints, lappend(), lfirst, list_make1, NIL, NULL, CreateStmtContext::pkey, IndexStmt::primary, CreateStmtContext::relation, RangeVar::relname, transformIndexConstraint(), IndexStmt::unique, and IndexStmt::whereClause.

Referenced by transformAlterTableStmt(), and transformCreateStmt().

1507 {
1508  IndexStmt *index;
1509  List *indexlist = NIL;
1510  ListCell *lc;
1511 
1512  /*
1513  * Run through the constraints that need to generate an index. For PRIMARY
1514  * KEY, mark each column as NOT NULL and create an index. For UNIQUE or
1515  * EXCLUDE, create an index as for PRIMARY KEY, but do not insist on NOT
1516  * NULL.
1517  */
1518  foreach(lc, cxt->ixconstraints)
1519  {
1520  Constraint *constraint = castNode(Constraint, lfirst(lc));
1521 
1522  Assert(constraint->contype == CONSTR_PRIMARY ||
1523  constraint->contype == CONSTR_UNIQUE ||
1524  constraint->contype == CONSTR_EXCLUSION);
1525 
1526  index = transformIndexConstraint(constraint, cxt);
1527 
1528  indexlist = lappend(indexlist, index);
1529  }
1530 
1531  /* Add in any indexes defined by LIKE ... INCLUDING INDEXES */
1532  foreach(lc, cxt->inh_indexes)
1533  {
1534  index = (IndexStmt *) lfirst(lc);
1535 
1536  if (index->primary)
1537  {
1538  if (cxt->pkey != NULL)
1539  ereport(ERROR,
1540  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
1541  errmsg("multiple primary keys for table \"%s\" are not allowed",
1542  cxt->relation->relname)));
1543  cxt->pkey = index;
1544  }
1545 
1546  indexlist = lappend(indexlist, index);
1547  }
1548 
1549  /*
1550  * Scan the index list and remove any redundant index specifications. This
1551  * can happen if, for instance, the user writes UNIQUE PRIMARY KEY. A
1552  * strict reading of SQL would suggest raising an error instead, but that
1553  * strikes me as too anal-retentive. - tgl 2001-02-14
1554  *
1555  * XXX in ALTER TABLE case, it'd be nice to look for duplicate
1556  * pre-existing indexes, too.
1557  */
1558  Assert(cxt->alist == NIL);
1559  if (cxt->pkey != NULL)
1560  {
1561  /* Make sure we keep the PKEY index in preference to others... */
1562  cxt->alist = list_make1(cxt->pkey);
1563  }
1564 
1565  foreach(lc, indexlist)
1566  {
1567  bool keep = true;
1568  ListCell *k;
1569 
1570  index = lfirst(lc);
1571 
1572  /* if it's pkey, it's already in cxt->alist */
1573  if (index == cxt->pkey)
1574  continue;
1575 
1576  foreach(k, cxt->alist)
1577  {
1578  IndexStmt *priorindex = lfirst(k);
1579 
1580  if (equal(index->indexParams, priorindex->indexParams) &&
1581  equal(index->whereClause, priorindex->whereClause) &&
1582  equal(index->excludeOpNames, priorindex->excludeOpNames) &&
1583  strcmp(index->accessMethod, priorindex->accessMethod) == 0 &&
1584  index->deferrable == priorindex->deferrable &&
1585  index->initdeferred == priorindex->initdeferred)
1586  {
1587  priorindex->unique |= index->unique;
1588 
1589  /*
1590  * If the prior index is as yet unnamed, and this one is
1591  * named, then transfer the name to the prior index. This
1592  * ensures that if we have named and unnamed constraints,
1593  * we'll use (at least one of) the names for the index.
1594  */
1595  if (priorindex->idxname == NULL)
1596  priorindex->idxname = index->idxname;
1597  keep = false;
1598  break;
1599  }
1600  }
1601 
1602  if (keep)
1603  cxt->alist = lappend(cxt->alist, index);
1604  }
1605 }
bool deferrable
Definition: parsenodes.h:2653
#define NIL
Definition: pg_list.h:69
bool primary
Definition: parsenodes.h:2651
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2946
#define castNode(_type_, nodeptr)
Definition: nodes.h:573
Node * whereClause
Definition: parsenodes.h:2645
int errcode(int sqlerrcode)
Definition: elog.c:575
Definition: type.h:90
#define list_make1(x1)
Definition: pg_list.h:133
char * relname
Definition: primnodes.h:68
RangeVar * relation
Definition: parse_utilcmd.c:76
IndexStmt * pkey
Definition: parse_utilcmd.c:91
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
List * lappend(List *list, void *datum)
Definition: list.c:128
char * idxname
Definition: parsenodes.h:2639
static IndexStmt * transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
bool unique
Definition: parsenodes.h:2650
char * accessMethod
Definition: parsenodes.h:2641
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
List * indexParams
Definition: parsenodes.h:2643
List * excludeOpNames
Definition: parsenodes.h:2646
bool initdeferred
Definition: parsenodes.h:2654
int errmsg(const char *fmt,...)
Definition: elog.c:797
ConstrType contype
Definition: parsenodes.h:2025
Definition: pg_list.h:45
IndexStmt* transformIndexStmt ( Oid  relid,
IndexStmt stmt,
const char *  queryString 
)

Definition at line 2095 of file parse_utilcmd.c.

References addRangeTableEntryForRelation(), addRTEtoQuery(), assign_expr_collations(), copyObject(), ereport, errcode(), errmsg(), ERROR, IndexElem::expr, EXPR_KIND_INDEX_EXPRESSION, EXPR_KIND_INDEX_PREDICATE, FigureIndexColname(), free_parsestate(), heap_close, IndexElem::indexcolname, IndexStmt::indexParams, lfirst, list_length(), make_parsestate(), NoLock, NULL, ParseState::p_rtable, ParseState::p_sourcetext, relation_open(), IndexStmt::transformed, transformExpr(), transformWhereClause(), and IndexStmt::whereClause.

Referenced by ATPostAlterTypeParse(), ProcessUtilitySlow(), and transformAlterTableStmt().

2096 {
2097  ParseState *pstate;
2098  RangeTblEntry *rte;
2099  ListCell *l;
2100  Relation rel;
2101 
2102  /* Nothing to do if statement already transformed. */
2103  if (stmt->transformed)
2104  return stmt;
2105 
2106  /*
2107  * We must not scribble on the passed-in IndexStmt, so copy it. (This is
2108  * overkill, but easy.)
2109  */
2110  stmt = (IndexStmt *) copyObject(stmt);
2111 
2112  /* Set up pstate */
2113  pstate = make_parsestate(NULL);
2114  pstate->p_sourcetext = queryString;
2115 
2116  /*
2117  * Put the parent table into the rtable so that the expressions can refer
2118  * to its fields without qualification. Caller is responsible for locking
2119  * relation, but we still need to open it.
2120  */
2121  rel = relation_open(relid, NoLock);
2122  rte = addRangeTableEntryForRelation(pstate, rel, NULL, false, true);
2123 
2124  /* no to join list, yes to namespaces */
2125  addRTEtoQuery(pstate, rte, false, true, true);
2126 
2127  /* take care of the where clause */
2128  if (stmt->whereClause)
2129  {
2130  stmt->whereClause = transformWhereClause(pstate,
2131  stmt->whereClause,
2133  "WHERE");
2134  /* we have to fix its collations too */
2135  assign_expr_collations(pstate, stmt->whereClause);
2136  }
2137 
2138  /* take care of any index expressions */
2139  foreach(l, stmt->indexParams)
2140  {
2141  IndexElem *ielem = (IndexElem *) lfirst(l);
2142 
2143  if (ielem->expr)
2144  {
2145  /* Extract preliminary index col name before transforming expr */
2146  if (ielem->indexcolname == NULL)
2147  ielem->indexcolname = FigureIndexColname(ielem->expr);
2148 
2149  /* Now do parse transformation of the expression */
2150  ielem->expr = transformExpr(pstate, ielem->expr,
2152 
2153  /* We have to fix its collations too */
2154  assign_expr_collations(pstate, ielem->expr);
2155 
2156  /*
2157  * transformExpr() should have already rejected subqueries,
2158  * aggregates, window functions, and SRFs, based on the EXPR_KIND_
2159  * for an index expression.
2160  *
2161  * DefineIndex() will make more checks.
2162  */
2163  }
2164  }
2165 
2166  /*
2167  * Check that only the base rel is mentioned. (This should be dead code
2168  * now that add_missing_from is history.)
2169  */
2170  if (list_length(pstate->p_rtable) != 1)
2171  ereport(ERROR,
2172  (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
2173  errmsg("index expressions and predicates can refer only to the table being indexed")));
2174 
2175  free_parsestate(pstate);
2176 
2177  /* Close relation */
2178  heap_close(rel, NoLock);
2179 
2180  /* Mark statement as successfully transformed */
2181  stmt->transformed = true;
2182 
2183  return stmt;
2184 }
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:147
Node * whereClause
Definition: parsenodes.h:2645
int errcode(int sqlerrcode)
Definition: elog.c:575
char * FigureIndexColname(Node *node)
#define heap_close(r, l)
Definition: heapam.h:97
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
void * copyObject(const void *from)
Definition: copyfuncs.c:4619
void assign_expr_collations(ParseState *pstate, Node *expr)
Node * expr
Definition: parsenodes.h:678
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
bool transformed
Definition: parsenodes.h:2655
char * indexcolname
Definition: parsenodes.h:679
const char * p_sourcetext
Definition: parse_node.h:167
#define ereport(elevel, rest)
Definition: elog.h:122
void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
List * indexParams
Definition: parsenodes.h:2643
static int list_length(const List *l)
Definition: pg_list.h:89
RangeTblEntry * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, Alias *alias, bool inh, bool inFromCl)
int errmsg(const char *fmt,...)
Definition: elog.c:797
Relation relation_open(Oid relationId, LOCKMODE lockmode)
Definition: heapam.c:1117
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:75
List * p_rtable
Definition: parse_node.h:168
static void transformOfType ( CreateStmtContext cxt,
TypeName ofTypename 
)
static

Definition at line 1076 of file parse_utilcmd.c.

References AssertArg, tupleDesc::attrs, check_of_type(), ColumnDef::collClause, ColumnDef::collOid, ColumnDef::colname, CreateStmtContext::columns, ColumnDef::constraints, ColumnDef::cooked_default, DecrTupleDescRefCount(), HeapTupleGetOid, i, ColumnDef::inhcount, ColumnDef::is_from_type, ColumnDef::is_local, ColumnDef::is_not_null, lappend(), ColumnDef::location, lookup_rowtype_tupdesc(), makeNode, makeTypeNameFromOid(), NameStr, tupleDesc::natts, NIL, NULL, pstrdup(), ColumnDef::raw_default, ReleaseSysCache(), ColumnDef::storage, ColumnDef::typeName, typenameType(), and TypeName::typeOid.

Referenced by transformCreateStmt().

1077 {
1078  HeapTuple tuple;
1079  TupleDesc tupdesc;
1080  int i;
1081  Oid ofTypeId;
1082 
1083  AssertArg(ofTypename);
1084 
1085  tuple = typenameType(NULL, ofTypename, NULL);
1086  check_of_type(tuple);
1087  ofTypeId = HeapTupleGetOid(tuple);
1088  ofTypename->typeOid = ofTypeId; /* cached for later */
1089 
1090  tupdesc = lookup_rowtype_tupdesc(ofTypeId, -1);
1091  for (i = 0; i < tupdesc->natts; i++)
1092  {
1093  Form_pg_attribute attr = tupdesc->attrs[i];
1094  ColumnDef *n;
1095 
1096  if (attr->attisdropped)
1097  continue;
1098 
1099  n = makeNode(ColumnDef);
1100  n->colname = pstrdup(NameStr(attr->attname));
1101  n->typeName = makeTypeNameFromOid(attr->atttypid, attr->atttypmod);
1102  n->inhcount = 0;
1103  n->is_local = true;
1104  n->is_not_null = false;
1105  n->is_from_type = true;
1106  n->storage = 0;
1107  n->raw_default = NULL;
1108  n->cooked_default = NULL;
1109  n->collClause = NULL;
1110  n->collOid = attr->attcollation;
1111  n->constraints = NIL;
1112  n->location = -1;
1113  cxt->columns = lappend(cxt->columns, n);
1114  }
1115  DecrTupleDescRefCount(tupdesc);
1116 
1117  ReleaseSysCache(tuple);
1118 }
#define NIL
Definition: pg_list.h:69
Oid typeOid
Definition: parsenodes.h:201
Type typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
Definition: parse_type.c:247
char storage
Definition: parsenodes.h:637
TupleDesc lookup_rowtype_tupdesc(Oid type_id, int32 typmod)
Definition: typcache.c:1257
bool is_local
Definition: parsenodes.h:634
List * constraints
Definition: parsenodes.h:642
char * pstrdup(const char *in)
Definition: mcxt.c:1077
Form_pg_attribute * attrs
Definition: tupdesc.h:74
bool is_not_null
Definition: parsenodes.h:635
unsigned int Oid
Definition: postgres_ext.h:31
int natts
Definition: tupdesc.h:73
Node * cooked_default
Definition: parsenodes.h:639
void check_of_type(HeapTuple typetuple)
Definition: tablecmds.c:4959
Oid collOid
Definition: parsenodes.h:641
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:184
int location
Definition: parsenodes.h:644
#define AssertArg(condition)
Definition: c.h:677
Node * raw_default
Definition: parsenodes.h:638
List * lappend(List *list, void *datum)
Definition: list.c:128
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1116
TypeName * makeTypeNameFromOid(Oid typeOid, int32 typmod)
Definition: makefuncs.c:469
bool is_from_type
Definition: parsenodes.h:636
#define makeNode(_type_)
Definition: nodes.h:552
#define NULL
Definition: c.h:229
void DecrTupleDescRefCount(TupleDesc tupdesc)
Definition: tupdesc.c:334
TypeName * typeName
Definition: parsenodes.h:632
CollateClause * collClause
Definition: parsenodes.h:640
int i
int inhcount
Definition: parsenodes.h:633
#define NameStr(name)
Definition: c.h:499
char * colname
Definition: parsenodes.h:631
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
Node* transformPartitionBound ( ParseState pstate,
Relation  parent,
Node bound 
)

Definition at line 3056 of file parse_utilcmd.c.

References Assert, COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, copyObject(), deparse_context_for(), deparse_expression(), elog, equal(), ereport, errcode(), errmsg(), ERROR, expression_planner(), exprLocation(), exprType(), forboth, format_type_be(), get_partition_col_typid(), get_partition_col_typmod(), get_partition_exprs(), get_partition_natts(), get_partition_strategy(), get_relid_attribute_name(), i, PartitionRangeDatum::infinite, lappend(), lfirst, linitial, list_length(), list_nth(), PartitionBoundSpec::listdatums, A_Const::location, PartitionBoundSpec::lowerdatums, make_const(), NIL, NULL, parser_errposition(), PartitionKeyData::partattrs, PARTITION_STRATEGY_LIST, PARTITION_STRATEGY_RANGE, RelationGetPartitionKey, RelationGetRelationName, RelationGetRelid, PartitionBoundSpec::strategy, PartitionBoundSpec::upperdatums, A_Const::val, value, and PartitionRangeDatum::value.

Referenced by DefineRelation(), and transformPartitionCmd().

3057 {
3058  PartitionBoundSpec *spec = (PartitionBoundSpec *) bound,
3059  *result_spec;
3060  PartitionKey key = RelationGetPartitionKey(parent);
3061  char strategy = get_partition_strategy(key);
3062  int partnatts = get_partition_natts(key);
3063  List *partexprs = get_partition_exprs(key);
3064 
3065  result_spec = copyObject(spec);
3066 
3067  if (strategy == PARTITION_STRATEGY_LIST)
3068  {
3069  ListCell *cell;
3070  char *colname;
3071 
3072  /* Get the only column's name in case we need to output an error */
3073  if (key->partattrs[0] != 0)
3074  colname = get_relid_attribute_name(RelationGetRelid(parent),
3075  key->partattrs[0]);
3076  else
3077  colname = deparse_expression((Node *) linitial(partexprs),
3079  RelationGetRelid(parent)),
3080  false, false);
3081 
3082  if (spec->strategy != PARTITION_STRATEGY_LIST)
3083  ereport(ERROR,
3084  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3085  errmsg("invalid bound specification for a list partition"),
3086  parser_errposition(pstate, exprLocation(bound))));
3087 
3088  result_spec->listdatums = NIL;
3089  foreach(cell, spec->listdatums)
3090  {
3091  A_Const *con = (A_Const *) lfirst(cell);
3092  Node *value;
3093  ListCell *cell2;
3094  bool duplicate;
3095 
3096  value = (Node *) make_const(pstate, &con->val, con->location);
3097  value = coerce_to_target_type(pstate,
3098  value, exprType(value),
3099  get_partition_col_typid(key, 0),
3100  get_partition_col_typmod(key, 0),
3103  -1);
3104 
3105  if (value == NULL)
3106  ereport(ERROR,
3107  (errcode(ERRCODE_DATATYPE_MISMATCH),
3108  errmsg("specified value cannot be cast to type \"%s\" of column \"%s\"",
3110  colname),
3111  parser_errposition(pstate,
3112  exprLocation((Node *) con))));
3113 
3114  /* Simplify the expression */
3115  value = (Node *) expression_planner((Expr *) value);
3116 
3117  /* Don't add to the result if the value is a duplicate */
3118  duplicate = false;
3119  foreach(cell2, result_spec->listdatums)
3120  {
3121  Const *value2 = (Const *) lfirst(cell2);
3122 
3123  if (equal(value, value2))
3124  {
3125  duplicate = true;
3126  break;
3127  }
3128  }
3129  if (duplicate)
3130  continue;
3131 
3132  result_spec->listdatums = lappend(result_spec->listdatums,
3133  value);
3134  }
3135  }
3136  else if (strategy == PARTITION_STRATEGY_RANGE)
3137  {
3138  ListCell *cell1,
3139  *cell2;
3140  int i,
3141  j;
3142  char *colname;
3143 
3144  if (spec->strategy != PARTITION_STRATEGY_RANGE)
3145  ereport(ERROR,
3146  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3147  errmsg("invalid bound specification for a range partition"),
3148  parser_errposition(pstate, exprLocation(bound))));
3149 
3150  Assert(spec->lowerdatums != NIL && spec->upperdatums != NIL);
3151 
3152  if (list_length(spec->lowerdatums) != partnatts)
3153  ereport(ERROR,
3154  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3155  errmsg("FROM must specify exactly one value per partitioning column")));
3156  if (list_length(spec->upperdatums) != partnatts)
3157  ereport(ERROR,
3158  (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
3159  errmsg("TO must specify exactly one value per partitioning column")));
3160 
3161  i = j = 0;
3162  result_spec->lowerdatums = result_spec->upperdatums = NIL;
3163  forboth(cell1, spec->lowerdatums, cell2, spec->upperdatums)
3164  {
3165  PartitionRangeDatum *ldatum,
3166  *rdatum;
3167  Node *value;
3168  A_Const *lcon = NULL,
3169  *rcon = NULL;
3170 
3171  ldatum = (PartitionRangeDatum *) lfirst(cell1);
3172  rdatum = (PartitionRangeDatum *) lfirst(cell2);
3173  /* Get the column's name in case we need to output an error */
3174  if (key->partattrs[i] != 0)
3175  colname = get_relid_attribute_name(RelationGetRelid(parent),
3176  key->partattrs[i]);
3177  else
3178  {
3179  colname = deparse_expression((Node *) list_nth(partexprs, j),
3181  RelationGetRelid(parent)),
3182  false, false);
3183  ++j;
3184  }
3185 
3186  if (!ldatum->infinite)
3187  lcon = (A_Const *) ldatum->value;
3188  if (!rdatum->infinite)
3189  rcon = (A_Const *) rdatum->value;
3190 
3191  if (lcon)
3192  {
3193  value = (Node *) make_const(pstate, &lcon->val, lcon->location);
3194  if (((Const *) value)->constisnull)
3195  ereport(ERROR,
3196  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3197  errmsg("cannot specify NULL in range bound")));
3198  value = coerce_to_target_type(pstate,
3199  value, exprType(value),
3200  get_partition_col_typid(key, i),
3201  get_partition_col_typmod(key, i),
3204  -1);
3205  if (value == NULL)
3206  ereport(ERROR,
3207  (errcode(ERRCODE_DATATYPE_MISMATCH),
3208  errmsg("specified value cannot be cast to type \"%s\" of column \"%s\"",
3210  colname),
3211  parser_errposition(pstate, exprLocation((Node *) ldatum))));
3212 
3213  /* Simplify the expression */
3214  value = (Node *) expression_planner((Expr *) value);
3215  ldatum->value = value;
3216  }
3217 
3218  if (rcon)
3219  {
3220  value = (Node *) make_const(pstate, &rcon->val, rcon->location);
3221  if (((Const *) value)->constisnull)
3222  ereport(ERROR,
3223  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3224  errmsg("cannot specify NULL in range bound")));
3225  value = coerce_to_target_type(pstate,
3226  value, exprType(value),
3227  get_partition_col_typid(key, i),
3228  get_partition_col_typmod(key, i),
3231  -1);
3232  if (value == NULL)
3233  ereport(ERROR,
3234  (errcode(ERRCODE_DATATYPE_MISMATCH),
3235  errmsg("specified value cannot be cast to type \"%s\" of column \"%s\"",
3237  colname),
3238  parser_errposition(pstate, exprLocation((Node *) rdatum))));
3239 
3240  /* Simplify the expression */
3241  value = (Node *) expression_planner((Expr *) value);
3242  rdatum->value = value;
3243  }
3244 
3245  result_spec->lowerdatums = lappend(result_spec->lowerdatums,
3246  copyObject(ldatum));
3247  result_spec->upperdatums = lappend(result_spec->upperdatums,
3248  copyObject(rdatum));
3249 
3250  ++i;
3251  }
3252  }
3253  else
3254  elog(ERROR, "unexpected partition strategy: %d", (int) strategy);
3255 
3256  return (Node *) result_spec;
3257 }
#define NIL
Definition: pg_list.h:69
#define forboth(cell1, list1, cell2, list2)
Definition: pg_list.h:174
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1204
bool equal(const void *a, const void *b)
Definition: equalfuncs.c:2946
Expr * expression_planner(Expr *expr)
Definition: planner.c:5382
Definition: nodes.h:504
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
Const * make_const(ParseState *pstate, Value *value, int location)
Definition: parse_node.c:468
void * copyObject(const void *from)
Definition: copyfuncs.c:4619
static struct @114 value
static int get_partition_natts(PartitionKey key)
Definition: rel.h:597
#define linitial(l)
Definition: pg_list.h:110
#define ERROR
Definition: elog.h:43
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:77
void * list_nth(const List *list, int n)
Definition: list.c:410
static List * get_partition_exprs(PartitionKey key)
Definition: rel.h:603
List * deparse_context_for(const char *aliasname, Oid relid)
Definition: ruleutils.c:2956
#define RelationGetRelationName(relation)
Definition: rel.h:437
#define ereport(elevel, rest)
Definition: elog.h:122
List * lappend(List *list, void *datum)
Definition: list.c:128
static int32 get_partition_col_typmod(PartitionKey key, int col)
Definition: rel.h:624
char * get_relid_attribute_name(Oid relid, AttrNumber attnum)
Definition: lsyscache.c:801
AttrNumber * partattrs
Definition: rel.h:56
static Oid get_partition_col_typid(PartitionKey key, int col)
Definition: rel.h:618
static int get_partition_strategy(PartitionKey key)
Definition: rel.h:591
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define lfirst(lc)
Definition: pg_list.h:106
int location
Definition: parsenodes.h:280
char * deparse_expression(Node *expr, List *dpcontext, bool forceprefix, bool showimplicit)
Definition: ruleutils.c:2897
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
static int list_length(const List *l)
Definition: pg_list.h:89
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:109
#define PARTITION_STRATEGY_LIST
Definition: parsenodes.h:769
#define RelationGetPartitionKey(relation)
Definition: rel.h:585
#define PARTITION_STRATEGY_RANGE
Definition: parsenodes.h:770
int errmsg(const char *fmt,...)
Definition: elog.c:797
int i
#define elog
Definition: elog.h:219
Value val
Definition: parsenodes.h:279
Definition: pg_list.h:45
#define RelationGetRelid(relation)
Definition: rel.h:417
static void transformPartitionCmd ( CreateStmtContext cxt,
PartitionCmd cmd 
)
static

Definition at line 3032 of file parse_utilcmd.c.

References Assert, PartitionCmd::bound, ereport, errcode(), errmsg(), ERROR, NULL, CreateStmtContext::partbound, CreateStmtContext::pstate, RelationData::rd_rel, CreateStmtContext::rel, RelationGetPartitionKey, RelationGetRelationName, RELKIND_PARTITIONED_TABLE, and transformPartitionBound().

Referenced by transformAlterTableStmt().

3033 {
3034  Relation parentRel = cxt->rel;
3035 
3036  /* the table must be partitioned */
3037  if (parentRel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
3038  ereport(ERROR,
3039  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3040  errmsg("\"%s\" is not partitioned",
3041  RelationGetRelationName(parentRel))));
3042 
3043  /* transform the partition bound, if any */
3044  Assert(RelationGetPartitionKey(parentRel) != NULL);
3045  if (cmd->bound != NULL)
3046  cxt->partbound = transformPartitionBound(cxt->pstate, parentRel,
3047  cmd->bound);
3048 }
Node * transformPartitionBound(ParseState *pstate, Relation parent, Node *bound)
Node * bound
Definition: parsenodes.h:814
int errcode(int sqlerrcode)
Definition: elog.c:575
Form_pg_class rd_rel
Definition: rel.h:114
ParseState * pstate
Definition: parse_utilcmd.c:74
#define ERROR
Definition: elog.h:43
#define RelationGetRelationName(relation)
Definition: rel.h:437
#define ereport(elevel, rest)
Definition: elog.h:122
#define RELKIND_PARTITIONED_TABLE
Definition: pg_class.h:168
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
#define RelationGetPartitionKey(relation)
Definition: rel.h:585
int errmsg(const char *fmt,...)
Definition: elog.c:797
void transformRuleStmt ( RuleStmt stmt,
const char *  queryString,
List **  actions,
Node **  whereClause 
)

Definition at line 2200 of file parse_utilcmd.c.

References AccessExclusiveLock, RuleStmt::actions, addRangeTableEntryForRelation(), addRTEtoQuery(), assign_expr_collations(), CMD_DELETE, CMD_INSERT, CMD_NOTHING, CMD_SELECT, CMD_UPDATE, CMD_UTILITY, Query::commandType, copyObject(), Query::cteList, elog, ereport, errcode(), errmsg(), ERROR, RuleStmt::event, EXPR_KIND_WHERE, free_parsestate(), FromExpr::fromlist, getInsertSelectQuery(), heap_close, heap_openrv(), Query::jointree, lappend(), lfirst, list_length(), list_make1, make_parsestate(), makeAlias(), makeFromExpr(), makeNode, NIL, NoLock, NULL, ParseState::p_joinlist, ParseState::p_rtable, ParseState::p_sourcetext, PRS2_NEW_VARNO, PRS2_OLD_VARNO, rangeTableEntry_used(), RelationData::rd_rel, RuleStmt::relation, RELKIND_MATVIEW, RangeTblEntry::requiredPerms, Query::rtable, Query::setOperations, transformStmt(), transformWhereClause(), and RuleStmt::whereClause.

Referenced by DefineRule().

2202 {
2203  Relation rel;
2204  ParseState *pstate;
2205  RangeTblEntry *oldrte;
2206  RangeTblEntry *newrte;
2207 
2208  /*
2209  * To avoid deadlock, make sure the first thing we do is grab
2210  * AccessExclusiveLock on the target relation. This will be needed by
2211  * DefineQueryRewrite(), and we don't want to grab a lesser lock
2212  * beforehand.
2213  */
2215 
2216  if (rel->rd_rel->relkind == RELKIND_MATVIEW)
2217  ereport(ERROR,
2218  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2219  errmsg("rules on materialized views are not supported")));
2220 
2221  /* Set up pstate */
2222  pstate = make_parsestate(NULL);
2223  pstate->p_sourcetext = queryString;
2224 
2225  /*
2226  * NOTE: 'OLD' must always have a varno equal to 1 and 'NEW' equal to 2.
2227  * Set up their RTEs in the main pstate for use in parsing the rule
2228  * qualification.
2229  */
2230  oldrte = addRangeTableEntryForRelation(pstate, rel,
2231  makeAlias("old", NIL),
2232  false, false);
2233  newrte = addRangeTableEntryForRelation(pstate, rel,
2234  makeAlias("new", NIL),
2235  false, false);
2236  /* Must override addRangeTableEntry's default access-check flags */
2237  oldrte->requiredPerms = 0;
2238  newrte->requiredPerms = 0;
2239 
2240  /*
2241  * They must be in the namespace too for lookup purposes, but only add the
2242  * one(s) that are relevant for the current kind of rule. In an UPDATE
2243  * rule, quals must refer to OLD.field or NEW.field to be unambiguous, but
2244  * there's no need to be so picky for INSERT & DELETE. We do not add them
2245  * to the joinlist.
2246  */
2247  switch (stmt->event)
2248  {
2249  case CMD_SELECT:
2250  addRTEtoQuery(pstate, oldrte, false, true, true);
2251  break;
2252  case CMD_UPDATE:
2253  addRTEtoQuery(pstate, oldrte, false, true, true);
2254  addRTEtoQuery(pstate, newrte, false, true, true);
2255  break;
2256  case CMD_INSERT:
2257  addRTEtoQuery(pstate, newrte, false, true, true);
2258  break;
2259  case CMD_DELETE:
2260  addRTEtoQuery(pstate, oldrte, false, true, true);
2261  break;
2262  default:
2263  elog(ERROR, "unrecognized event type: %d",
2264  (int) stmt->event);
2265  break;
2266  }
2267 
2268  /* take care of the where clause */
2269  *whereClause = transformWhereClause(pstate,
2270  (Node *) copyObject(stmt->whereClause),
2272  "WHERE");
2273  /* we have to fix its collations too */
2274  assign_expr_collations(pstate, *whereClause);
2275 
2276  /* this is probably dead code without add_missing_from: */
2277  if (list_length(pstate->p_rtable) != 2) /* naughty, naughty... */
2278  ereport(ERROR,
2279  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2280  errmsg("rule WHERE condition cannot contain references to other relations")));
2281 
2282  /*
2283  * 'instead nothing' rules with a qualification need a query rangetable so
2284  * the rewrite handler can add the negated rule qualification to the
2285  * original query. We create a query with the new command type CMD_NOTHING
2286  * here that is treated specially by the rewrite system.
2287  */
2288  if (stmt->actions == NIL)
2289  {
2290  Query *nothing_qry = makeNode(Query);
2291 
2292  nothing_qry->commandType = CMD_NOTHING;
2293  nothing_qry->rtable = pstate->p_rtable;
2294  nothing_qry->jointree = makeFromExpr(NIL, NULL); /* no join wanted */
2295 
2296  *actions = list_make1(nothing_qry);
2297  }
2298  else
2299  {
2300  ListCell *l;
2301  List *newactions = NIL;
2302 
2303  /*
2304  * transform each statement, like parse_sub_analyze()
2305  */
2306  foreach(l, stmt->actions)
2307  {
2308  Node *action = (Node *) lfirst(l);
2309  ParseState *sub_pstate = make_parsestate(NULL);
2310  Query *sub_qry,
2311  *top_subqry;
2312  bool has_old,
2313  has_new;
2314 
2315  /*
2316  * Since outer ParseState isn't parent of inner, have to pass down
2317  * the query text by hand.
2318  */
2319  sub_pstate->p_sourcetext = queryString;
2320 
2321  /*
2322  * Set up OLD/NEW in the rtable for this statement. The entries
2323  * are added only to relnamespace, not varnamespace, because we
2324  * don't want them to be referred to by unqualified field names
2325  * nor "*" in the rule actions. We decide later whether to put
2326  * them in the joinlist.
2327  */
2328  oldrte = addRangeTableEntryForRelation(sub_pstate, rel,
2329  makeAlias("old", NIL),
2330  false, false);
2331  newrte = addRangeTableEntryForRelation(sub_pstate, rel,
2332  makeAlias("new", NIL),
2333  false, false);
2334  oldrte->requiredPerms = 0;
2335  newrte->requiredPerms = 0;
2336  addRTEtoQuery(sub_pstate, oldrte, false, true, false);
2337  addRTEtoQuery(sub_pstate, newrte, false, true, false);
2338 
2339  /* Transform the rule action statement */
2340  top_subqry = transformStmt(sub_pstate,
2341  (Node *) copyObject(action));
2342 
2343  /*
2344  * We cannot support utility-statement actions (eg NOTIFY) with
2345  * nonempty rule WHERE conditions, because there's no way to make
2346  * the utility action execute conditionally.
2347  */
2348  if (top_subqry->commandType == CMD_UTILITY &&
2349  *whereClause != NULL)
2350  ereport(ERROR,
2351  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2352  errmsg("rules with WHERE conditions can only have SELECT, INSERT, UPDATE, or DELETE actions")));
2353 
2354  /*
2355  * If the action is INSERT...SELECT, OLD/NEW have been pushed down
2356  * into the SELECT, and that's what we need to look at. (Ugly
2357  * kluge ... try to fix this when we redesign querytrees.)
2358  */
2359  sub_qry = getInsertSelectQuery(top_subqry, NULL);
2360 
2361  /*
2362  * If the sub_qry is a setop, we cannot attach any qualifications
2363  * to it, because the planner won't notice them. This could
2364  * perhaps be relaxed someday, but for now, we may as well reject
2365  * such a rule immediately.
2366  */
2367  if (sub_qry->setOperations != NULL && *whereClause != NULL)
2368  ereport(ERROR,
2369  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2370  errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
2371 
2372  /*
2373  * Validate action's use of OLD/NEW, qual too
2374  */
2375  has_old =
2376  rangeTableEntry_used((Node *) sub_qry, PRS2_OLD_VARNO, 0) ||
2377  rangeTableEntry_used(*whereClause, PRS2_OLD_VARNO, 0);
2378  has_new =
2379  rangeTableEntry_used((Node *) sub_qry, PRS2_NEW_VARNO, 0) ||
2380  rangeTableEntry_used(*whereClause, PRS2_NEW_VARNO, 0);
2381 
2382  switch (stmt->event)
2383  {
2384  case CMD_SELECT:
2385  if (has_old)
2386  ereport(ERROR,
2387  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2388  errmsg("ON SELECT rule cannot use OLD")));
2389  if (has_new)
2390  ereport(ERROR,
2391  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2392  errmsg("ON SELECT rule cannot use NEW")));
2393  break;
2394  case CMD_UPDATE:
2395  /* both are OK */
2396  break;
2397  case CMD_INSERT:
2398  if (has_old)
2399  ereport(ERROR,
2400  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2401  errmsg("ON INSERT rule cannot use OLD")));
2402  break;
2403  case CMD_DELETE:
2404  if (has_new)
2405  ereport(ERROR,
2406  (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2407  errmsg("ON DELETE rule cannot use NEW")));
2408  break;
2409  default:
2410  elog(ERROR, "unrecognized event type: %d",
2411  (int) stmt->event);
2412  break;
2413  }
2414 
2415  /*
2416  * OLD/NEW are not allowed in WITH queries, because they would
2417  * amount to outer references for the WITH, which we disallow.
2418  * However, they were already in the outer rangetable when we
2419  * analyzed the query, so we have to check.
2420  *
2421  * Note that in the INSERT...SELECT case, we need to examine the
2422  * CTE lists of both top_subqry and sub_qry.
2423  *
2424  * Note that we aren't digging into the body of the query looking
2425  * for WITHs in nested sub-SELECTs. A WITH down there can
2426  * legitimately refer to OLD/NEW, because it'd be an
2427  * indirect-correlated outer reference.
2428  */
2429  if (rangeTableEntry_used((Node *) top_subqry->cteList,
2430  PRS2_OLD_VARNO, 0) ||
2431  rangeTableEntry_used((Node *) sub_qry->cteList,
2432  PRS2_OLD_VARNO, 0))
2433  ereport(ERROR,
2434  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2435  errmsg("cannot refer to OLD within WITH query")));
2436  if (rangeTableEntry_used((Node *) top_subqry->cteList,
2437  PRS2_NEW_VARNO, 0) ||
2438  rangeTableEntry_used((Node *) sub_qry->cteList,
2439  PRS2_NEW_VARNO, 0))
2440  ereport(ERROR,
2441  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2442  errmsg("cannot refer to NEW within WITH query")));
2443 
2444  /*
2445  * For efficiency's sake, add OLD to the rule action's jointree
2446  * only if it was actually referenced in the statement or qual.
2447  *
2448  * For INSERT, NEW is not really a relation (only a reference to
2449  * the to-be-inserted tuple) and should never be added to the
2450  * jointree.
2451  *
2452  * For UPDATE, we treat NEW as being another kind of reference to
2453  * OLD, because it represents references to *transformed* tuples
2454  * of the existing relation. It would be wrong to enter NEW
2455  * separately in the jointree, since that would cause a double
2456  * join of the updated relation. It's also wrong to fail to make
2457  * a jointree entry if only NEW and not OLD is mentioned.
2458  */
2459  if (has_old || (has_new && stmt->event == CMD_UPDATE))
2460  {
2461  /*
2462  * If sub_qry is a setop, manipulating its jointree will do no
2463  * good at all, because the jointree is dummy. (This should be
2464  * a can't-happen case because of prior tests.)
2465  */
2466  if (sub_qry->setOperations != NULL)
2467  ereport(ERROR,
2468  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2469  errmsg("conditional UNION/INTERSECT/EXCEPT statements are not implemented")));
2470  /* hack so we can use addRTEtoQuery() */
2471  sub_pstate->p_rtable = sub_qry->rtable;
2472  sub_pstate->p_joinlist = sub_qry->jointree->fromlist;
2473  addRTEtoQuery(sub_pstate, oldrte, true, false, false);
2474  sub_qry->jointree->fromlist = sub_pstate->p_joinlist;
2475  }
2476 
2477  newactions = lappend(newactions, top_subqry);
2478 
2479  free_parsestate(sub_pstate);
2480  }
2481 
2482  *actions = newactions;
2483  }
2484 
2485  free_parsestate(pstate);
2486 
2487  /* Close relation, but keep the exclusive lock */
2488  heap_close(rel, NoLock);
2489 }
#define NIL
Definition: pg_list.h:69
Query * getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr)
Definition: rewriteManip.c:921
FromExpr * makeFromExpr(List *fromlist, Node *quals)
Definition: makefuncs.c:282
FromExpr * jointree
Definition: parsenodes.h:129
#define RELKIND_MATVIEW
Definition: pg_class.h:165
Definition: nodes.h:504
int errcode(int sqlerrcode)
Definition: elog.c:575
List * actions
Definition: parsenodes.h:2818
AclMode requiredPerms
Definition: parsenodes.h:1004
List * fromlist
Definition: primnodes.h:1455
#define heap_close(r, l)
Definition: heapam.h:97
Form_pg_class rd_rel
Definition: rel.h:114
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
void * copyObject(const void *from)
Definition: copyfuncs.c:4619
#define list_make1(x1)
Definition: pg_list.h:133
void assign_expr_collations(ParseState *pstate, Node *expr)
Alias * makeAlias(const char *aliasname, List *colnames)
Definition: makefuncs.c:384
List * rtable
Definition: parsenodes.h:128
#define ERROR
Definition: elog.h:43
#define NoLock
Definition: lockdefs.h:34
const char * p_sourcetext
Definition: parse_node.h:167
#define ereport(elevel, rest)
Definition: elog.h:122
void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte, bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace)
Query * transformStmt(ParseState *pstate, Node *parseTree)
Definition: analyze.c:247
List * lappend(List *list, void *datum)
Definition: list.c:128
#define PRS2_OLD_VARNO
Definition: primnodes.h:160
Relation heap_openrv(const RangeVar *relation, LOCKMODE lockmode)
Definition: heapam.c:1315
CmdType commandType
Definition: parsenodes.h:103
#define makeNode(_type_)
Definition: nodes.h:552
CmdType event
Definition: parsenodes.h:2816
#define NULL
Definition: c.h:229
#define lfirst(lc)
Definition: pg_list.h:106
Node * transformWhereClause(ParseState *pstate, Node *clause, ParseExprKind exprKind, const char *constructName)
Node * whereClause
Definition: parsenodes.h:2815
static int list_length(const List *l)
Definition: pg_list.h:89
RangeTblEntry * addRangeTableEntryForRelation(ParseState *pstate, Relation rel, Alias *alias, bool inh, bool inFromCl)
#define AccessExclusiveLock
Definition: lockdefs.h:46
List * cteList
Definition: parsenodes.h:126
Node * setOperations
Definition: parsenodes.h:154
int errmsg(const char *fmt,...)
Definition: elog.c:797
List * p_joinlist
Definition: parse_node.h:170
bool rangeTableEntry_used(Node *node, int rt_index, int sublevels_up)
Definition: rewriteManip.c:889
#define elog
Definition: elog.h:219
RangeVar * relation
Definition: parsenodes.h:2813
void free_parsestate(ParseState *pstate)
Definition: parse_node.c:75
Definition: pg_list.h:45
#define PRS2_NEW_VARNO
Definition: primnodes.h:161
List * p_rtable
Definition: parse_node.h:168
static void transformTableConstraint ( CreateStmtContext cxt,
Constraint constraint 
)
static

Definition at line 696 of file parse_utilcmd.c.

References CreateStmtContext::ckconstraints, CONSTR_ATTR_DEFERRABLE, CONSTR_ATTR_DEFERRED, CONSTR_ATTR_IMMEDIATE, CONSTR_ATTR_NOT_DEFERRABLE, CONSTR_CHECK, CONSTR_DEFAULT, CONSTR_EXCLUSION, CONSTR_FOREIGN, CONSTR_NOTNULL, CONSTR_NULL, CONSTR_PRIMARY, CONSTR_UNIQUE, Constraint::contype, elog, ereport, errcode(), errmsg(), ERROR, CreateStmtContext::fkconstraints, CreateStmtContext::isforeign, CreateStmtContext::ispartitioned, CreateStmtContext::ixconstraints, lappend(), Constraint::location, parser_errposition(), and CreateStmtContext::pstate.

Referenced by transformAlterTableStmt(), and transformCreateStmt().

697 {
698  switch (constraint->contype)
699  {
700  case CONSTR_PRIMARY:
701  if (cxt->isforeign)
702  ereport(ERROR,
703  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
704  errmsg("primary key constraints are not supported on foreign tables"),
706  constraint->location)));
707  if (cxt->ispartitioned)
708  ereport(ERROR,
709  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
710  errmsg("primary key constraints are not supported on partitioned tables"),
712  constraint->location)));
713  cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
714  break;
715 
716  case CONSTR_UNIQUE:
717  if (cxt->isforeign)
718  ereport(ERROR,
719  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
720  errmsg("unique constraints are not supported on foreign tables"),
722  constraint->location)));
723  if (cxt->ispartitioned)
724  ereport(ERROR,
725  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
726  errmsg("unique constraints are not supported on partitioned tables"),
728  constraint->location)));
729  cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
730  break;
731 
732  case CONSTR_EXCLUSION:
733  if (cxt->isforeign)
734  ereport(ERROR,
735  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
736  errmsg("exclusion constraints are not supported on foreign tables"),
738  constraint->location)));
739  if (cxt->ispartitioned)
740  ereport(ERROR,
741  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
742  errmsg("exclusion constraints are not supported on partitioned tables"),
744  constraint->location)));
745  cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
746  break;
747 
748  case CONSTR_CHECK:
749  cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
750  break;
751 
752  case CONSTR_FOREIGN:
753  if (cxt->isforeign)
754  ereport(ERROR,
755  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
756  errmsg("foreign key constraints are not supported on foreign tables"),
758  constraint->location)));
759  if (cxt->ispartitioned)
760  ereport(ERROR,
761  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
762  errmsg("foreign key constraints are not supported on partitioned tables"),
764  constraint->location)));
765  cxt->fkconstraints = lappend(cxt->fkconstraints, constraint);
766  break;
767 
768  case CONSTR_NULL:
769  case CONSTR_NOTNULL:
770  case CONSTR_DEFAULT:
775  elog(ERROR, "invalid context for constraint type %d",
776  constraint->contype);
777  break;
778 
779  default:
780  elog(ERROR, "unrecognized constraint type: %d",
781  constraint->contype);
782  break;
783  }
784 }
int errcode(int sqlerrcode)
Definition: elog.c:575
ParseState * pstate
Definition: parse_utilcmd.c:74
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:122
List * lappend(List *list, void *datum)
Definition: list.c:128
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:109
int errmsg(const char *fmt,...)
Definition: elog.c:797
ConstrType contype
Definition: parsenodes.h:2025
#define elog
Definition: elog.h:219
static void transformTableLikeClause ( CreateStmtContext cxt,
TableLikeClause table_like_clause 
)
static

Definition at line 794 of file parse_utilcmd.c.

References AccessShareLock, ACL_KIND_CLASS, ACL_KIND_TYPE, ACL_SELECT, ACL_USAGE, aclcheck_error(), ACLCHECK_OK, CreateStmtContext::alist, Assert, tupleDesc::attrs, cancel_parser_errposition_callback(), constrCheck::ccbin, constrCheck::ccname, tupleConstr::check, CreateStmtContext::ckconstraints, ColumnDef::collClause, ColumnDef::collOid, ColumnDef::colname, CreateStmtContext::columns, CommentStmt::comment, Constraint::conname, tupleDesc::constr, CONSTR_CHECK, ConstraintRelationId, ColumnDef::constraints, Constraint::contype, ColumnDef::cooked_default, Constraint::cooked_expr, CREATE_TABLE_LIKE_COMMENTS, CREATE_TABLE_LIKE_CONSTRAINTS, CREATE_TABLE_LIKE_DEFAULTS, CREATE_TABLE_LIKE_INDEXES, CREATE_TABLE_LIKE_STORAGE, tupleConstr::defval, ereport, errcode(), errdetail(), errmsg(), ERROR, generateClonedIndexStmt(), get_relation_constraint_oid(), GetComment(), GetUserId(), CreateStmtContext::hasoids, heap_close, i, IndexStmt::idxcomment, index_close(), index_open(), CreateStmtContext::inh_indexes, ColumnDef::inhcount, ColumnDef::is_from_type, ColumnDef::is_local, ColumnDef::is_not_null, CreateStmtContext::isforeign, lappend(), lfirst_oid, list_length(), list_make3, RangeVar::location, ColumnDef::location, Constraint::location, makeNode, makeString(), makeTypeNameFromOid(), map_variable_attnos(), NameStr, tupleDesc::natts, NIL, nodeToString(), NoLock, NULL, tupleConstr::num_check, tupleConstr::num_defval, CommentStmt::object, OBJECT_COLUMN, OBJECT_TABCONSTRAINT, CommentStmt::objtype, TableLikeClause::options, palloc0(), pg_class_aclcheck(), pg_type_aclcheck(), CreateStmtContext::pstate, pstrdup(), ColumnDef::raw_default, Constraint::raw_expr, RelationData::rd_rel, CreateStmtContext::relation, TableLikeClause::relation, relation_openrv(), RelationGetDescr, RelationGetIndexList(), RelationGetRelationName, RelationGetRelid, RelationRelationId, RELKIND_COMPOSITE_TYPE, RELKIND_FOREIGN_TABLE, RELKIND_MATVIEW, RELKIND_PARTITIONED_TABLE, RELKIND_RELATION, RELKIND_VIEW, RangeVar::relname, RangeVar::schemaname, setup_parser_errposition_callback(), ColumnDef::storage, stringToNode(), and ColumnDef::typeName.

Referenced by transformCreateStmt().

795 {
796  AttrNumber parent_attno;
797  Relation relation;
799  TupleConstr *constr;
800  AttrNumber *attmap;
801  AclResult aclresult;
802  char *comment;
803  ParseCallbackState pcbstate;
804 
806  table_like_clause->relation->location);
807 
808  /* we could support LIKE in many cases, but worry about it another day */
809  if (cxt->isforeign)
810  ereport(ERROR,
811  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
812  errmsg("LIKE is not supported for creating foreign tables")));
813 
814  relation = relation_openrv(table_like_clause->relation, AccessShareLock);
815 
816  if (relation->rd_rel->relkind != RELKIND_RELATION &&
817  relation->rd_rel->relkind != RELKIND_VIEW &&
818  relation->rd_rel->relkind != RELKIND_MATVIEW &&
819  relation->rd_rel->relkind != RELKIND_COMPOSITE_TYPE &&
820  relation->rd_rel->relkind != RELKIND_FOREIGN_TABLE &&
821  relation->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
822  ereport(ERROR,
823  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
824  errmsg("\"%s\" is not a table, view, materialized view, composite type, or foreign table",
825  RelationGetRelationName(relation))));
826 
828 
829  /*
830  * Check for privileges
831  */
832  if (relation->rd_rel->relkind == RELKIND_COMPOSITE_TYPE)
833  {
834  aclresult = pg_type_aclcheck(relation->rd_rel->reltype, GetUserId(),
835  ACL_USAGE);
836  if (aclresult != ACLCHECK_OK)
837  aclcheck_error(aclresult, ACL_KIND_TYPE,
838  RelationGetRelationName(relation));
839  }
840  else
841  {
842  aclresult = pg_class_aclcheck(RelationGetRelid(relation), GetUserId(),
843  ACL_SELECT);
844  if (aclresult != ACLCHECK_OK)
845  aclcheck_error(aclresult, ACL_KIND_CLASS,
846  RelationGetRelationName(relation));
847  }
848 
849  tupleDesc = RelationGetDescr(relation);
850  constr = tupleDesc->constr;
851 
852  /*
853  * Initialize column number map for map_variable_attnos(). We need this
854  * since dropped columns in the source table aren't copied, so the new
855  * table can have different column numbers.
856  */
857  attmap = (AttrNumber *) palloc0(sizeof(AttrNumber) * tupleDesc->natts);
858 
859  /*
860  * Insert the copied attributes into the cxt for the new table definition.
861  */
862  for (parent_attno = 1; parent_attno <= tupleDesc->natts;
863  parent_attno++)
864  {
865  Form_pg_attribute attribute = tupleDesc->attrs[parent_attno - 1];
866  char *attributeName = NameStr(attribute->attname);
867  ColumnDef *def;
868 
869  /*
870  * Ignore dropped columns in the parent. attmap entry is left zero.
871  */
872  if (attribute->attisdropped)
873  continue;
874 
875  /*
876  * Create a new column, which is marked as NOT inherited.
877  *
878  * For constraints, ONLY the NOT NULL constraint is inherited by the
879  * new column definition per SQL99.
880  */
881  def = makeNode(ColumnDef);
882  def->colname = pstrdup(attributeName);
883  def->typeName = makeTypeNameFromOid(attribute->atttypid,
884  attribute->atttypmod);
885  def->inhcount = 0;
886  def->is_local = true;
887  def->is_not_null = attribute->attnotnull;
888  def->is_from_type = false;
889  def->storage = 0;
890  def->raw_default = NULL;
891  def->cooked_default = NULL;
892  def->collClause = NULL;
893  def->collOid = attribute->attcollation;
894  def->constraints = NIL;
895  def->location = -1;
896 
897  /*
898  * Add to column list
899  */
900  cxt->columns = lappend(cxt->columns, def);
901 
902  attmap[parent_attno - 1] = list_length(cxt->columns);
903 
904  /*
905  * Copy default, if present and the default has been requested
906  */
907  if (attribute->atthasdef &&
908  (table_like_clause->options & CREATE_TABLE_LIKE_DEFAULTS))
909  {
910  Node *this_default = NULL;
911  AttrDefault *attrdef;
912  int i;
913 
914  /* Find default in constraint structure */
915  Assert(constr != NULL);
916  attrdef = constr->defval;
917  for (i = 0; i < constr->num_defval; i++)
918  {
919  if (attrdef[i].adnum == parent_attno)
920  {
921  this_default = stringToNode(attrdef[i].adbin);
922  break;
923  }
924  }
925  Assert(this_default != NULL);
926 
927  /*
928  * If default expr could contain any vars, we'd need to fix 'em,
929  * but it can't; so default is ready to apply to child.
930  */
931 
932  def->cooked_default = this_default;
933  }
934 
935  /* Likewise, copy storage if requested */
936  if (table_like_clause->options & CREATE_TABLE_LIKE_STORAGE)
937  def->storage = attribute->attstorage;
938  else
939  def->storage = 0;
940 
941  /* Likewise, copy comment if requested */
942  if ((table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) &&
943  (comment = GetComment(attribute->attrelid,
945  attribute->attnum)) != NULL)
946  {
948 
949  stmt->objtype = OBJECT_COLUMN;
950  stmt->object = (Node *) list_make3(makeString(cxt->relation->schemaname),
951  makeString(cxt->relation->relname),
952  makeString(def->colname));
953  stmt->comment = comment;
954 
955  cxt->alist = lappend(cxt->alist, stmt);
956  }
957  }
958 
959  /* We use oids if at least one LIKE'ed table has oids. */
960  cxt->hasoids |= relation->rd_rel->relhasoids;
961 
962  /*
963  * Copy CHECK constraints if requested, being careful to adjust attribute
964  * numbers so they match the child.
965  */
966  if ((table_like_clause->options & CREATE_TABLE_LIKE_CONSTRAINTS) &&
967  tupleDesc->constr)
968  {
969  int ccnum;
970 
971  for (ccnum = 0; ccnum < tupleDesc->constr->num_check; ccnum++)
972  {
973  char *ccname = tupleDesc->constr->check[ccnum].ccname;
974  char *ccbin = tupleDesc->constr->check[ccnum].ccbin;
976  Node *ccbin_node;
977  bool found_whole_row;
978 
979  ccbin_node = map_variable_attnos(stringToNode(ccbin),
980  1, 0,
981  attmap, tupleDesc->natts,
982  &found_whole_row);
983 
984  /*
985  * We reject whole-row variables because the whole point of LIKE
986  * is that the new table's rowtype might later diverge from the
987  * parent's. So, while translation might be possible right now,
988  * it wouldn't be possible to guarantee it would work in future.
989  */
990  if (found_whole_row)
991  ereport(ERROR,
992  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
993  errmsg("cannot convert whole-row table reference"),
994  errdetail("Constraint \"%s\" contains a whole-row reference to table \"%s\".",
995  ccname,
996  RelationGetRelationName(relation))));
997 
998  n->contype = CONSTR_CHECK;
999  n->location = -1;
1000  n->conname = pstrdup(ccname);
1001  n->raw_expr = NULL;
1002  n->cooked_expr = nodeToString(ccbin_node);
1003  cxt->ckconstraints = lappend(cxt->ckconstraints, n);
1004 
1005  /* Copy comment on constraint */
1006  if ((table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS) &&
1008  n->conname, false),
1010  0)) != NULL)
1011  {
1012  CommentStmt *stmt = makeNode(CommentStmt);
1013 
1014  stmt->objtype = OBJECT_TABCONSTRAINT;
1015  stmt->object = (Node *) list_make3(makeString(cxt->relation->schemaname),
1016  makeString(cxt->relation->relname),
1017  makeString(n->conname));
1018  stmt->comment = comment;
1019 
1020  cxt->alist = lappend(cxt->alist, stmt);
1021  }
1022  }
1023  }
1024 
1025  /*
1026  * Likewise, copy indexes if requested
1027  */
1028  if ((table_like_clause->options & CREATE_TABLE_LIKE_INDEXES) &&
1029  relation->rd_rel->relhasindex)
1030  {
1031  List *parent_indexes;
1032  ListCell *l;
1033 
1034  parent_indexes = RelationGetIndexList(relation);
1035 
1036  foreach(l, parent_indexes)
1037  {
1038  Oid parent_index_oid = lfirst_oid(l);
1039  Relation parent_index;
1040  IndexStmt *index_stmt;
1041 
1042  parent_index = index_open(parent_index_oid, AccessShareLock);
1043 
1044  /* Build CREATE INDEX statement to recreate the parent_index */
1045  index_stmt = generateClonedIndexStmt(cxt, parent_index,
1046  attmap, tupleDesc->natts);
1047 
1048  /* Copy comment on index, if requested */
1049  if (table_like_clause->options & CREATE_TABLE_LIKE_COMMENTS)
1050  {
1051  comment = GetComment(parent_index_oid, RelationRelationId, 0);
1052 
1053  /*
1054  * We make use of IndexStmt's idxcomment option, so as not to
1055  * need to know now what name the index will have.
1056  */
1057  index_stmt->idxcomment = comment;
1058  }
1059 
1060  /* Save it in the inh_indexes list for the time being */
1061  cxt->inh_indexes = lappend(cxt->inh_indexes, index_stmt);
1062