diff -dcrpN pgsql.orig/doc/src/sgml/catalogs.sgml pgsql/doc/src/sgml/catalogs.sgml *** pgsql.orig/doc/src/sgml/catalogs.sgml 2007-02-15 12:35:59.000000000 +0100 --- pgsql/doc/src/sgml/catalogs.sgml 2007-02-28 08:48:34.000000000 +0100 *************** *** 969,974 **** --- 969,993 ---- + + attidentity + bool + + + This column is an IDENTITY column. + + + + + attforceddef + bool + + + This column is defined as GENERATED ALWAYS and the + default value is always enforced. + + + diff -dcrpN pgsql.orig/doc/src/sgml/datatype.sgml pgsql/doc/src/sgml/datatype.sgml *** pgsql.orig/doc/src/sgml/datatype.sgml 2007-02-09 07:22:55.000000000 +0100 --- pgsql/doc/src/sgml/datatype.sgml 2007-02-28 08:48:34.000000000 +0100 *************** ALTER SEQUENCE + Identity Columns + + + identity + + + + sequence + and identity column + + + + Identity columns are similar to the + pseudo data types serial and + bigserial but also have different properties. + + + + Identity is not a type, but a type + modifier. As such, an identity column isn't + limited to numeric types. Every type that has an implicit + cast from int8 can be used as an + identity column. + + + CREATE TABLE tablename ( + colname coltype + GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY + ); + + + In the above example coltype can be e.g. float, + decimal or text. + + + + There is a difference in the order of events that + leads to the generation of the next value of the + underlying sequence. A serial column gets + its default value the same way as other, non-serial + columns, e.g. the columns are assigned with default values + first, then the row is validated the row via NOT NULL, + CHECK and other constraints. The identity column + is left out of these checks in the first phase then + it gets assigned with its default value and after all + finally it's also validated via constraints. That means + that the sequence values are not inflated when some other + field fails its constraint validation. This is especially + important for some application where strict numbering + is required. As a consequence, an identity + column cannot have a CHECK constraint. + + + + Sequence generation options can be specified at table creation: + + + CREATE TABLE tablename ( + colname coltype + GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [( sequence_options )] + ); + + + The optional sequence_options + are the same sequence options that can be used to + CREATE or ALTER a sequence. + + + + For an identity column, either + GENERATED ALWAYS or + GENERATED BY DEFAULT can be specified. + The behaviour for GENERATED BY DEFAULT + is similar to the serial pseudo-type, e.g. + the sequence next value generation can be suppressed + at INSERT by providing a value manually. + With GENERATED ALWAYS, the sequence + generation cannot be suppressed, the manually provided + value is ignored. + + + + There can be only one identity column + in a table at any time. + + + + The identity column in PostgreSQL conforms + to the SQL:2003 standard. + + + + + Generated Columns + + + generated + + + + Generated is not a type, but a type + modifier. As such, a generated column isn't + limited to numeric types. Generated columns + are columns with enforced DEFAULT values. + This kind of columns can be used to keep a "static" value + in the table whose value may depend on other columns of + the same row. + + + CREATE TABLE tablename ( + colname coltype + GENERATED ALWAYS AS ( expression ) + ); + + + + + The value of the generated column is + computed after all other columns are assigned with their + values but before the identity column's + next serial value is computed. A generated + column cannot reference other generated + or identity columns. A generated + column cannot have a CHECK constraint. + + + + The generated column in PostgreSQL conforms + to the SQL:2003 standard. + + diff -dcrpN pgsql.orig/doc/src/sgml/ref/alter_table.sgml pgsql/doc/src/sgml/ref/alter_table.sgml *** pgsql.orig/doc/src/sgml/ref/alter_table.sgml 2007-02-09 07:23:10.000000000 +0100 --- pgsql/doc/src/sgml/ref/alter_table.sgml 2007-02-28 08:48:34.000000000 +0100 *************** where act *** 36,41 **** --- 36,43 ---- ALTER [ COLUMN ] column TYPE type [ USING expression ] ALTER [ COLUMN ] column SET DEFAULT expression ALTER [ COLUMN ] column DROP DEFAULT + ALTER [ COLUMN ] column SET GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY + ALTER [ COLUMN ] column DROP IDENTITY ALTER [ COLUMN ] column { SET | DROP } NOT NULL ALTER [ COLUMN ] column SET STATISTICS integer ALTER [ COLUMN ] column SET STORAGE { PLAIN | EXTERNAL | EXTENDED | MAIN } *************** where act *** 118,123 **** --- 120,146 ---- + SET/GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY + + + This form "upgrades" a column that has an associated + sequence to an IDENTITY column. See also + ALTER SEQUENCE ... OWNED BY + + + + + + SET/DROP IDENTITY + + + This form downgrades an IDENTITY to a regular column. + The column still keeps the OWNED sequence and its DEFAULT. + + + + + SET/DROP NOT NULL *************** where act *** 358,363 **** --- 381,393 ---- (or an index, sequence, or view) or the name of an individual column in a table. There is no effect on the stored data. + + + If the renamed column is SERIAL or it's an + identity column, the underlying sequence is + also renamed so it always tries to keep the + tablename_columnname_seq form. + *************** ALTER TABLE table ALTER COLUMN anycol TY *** 661,667 **** drop the default with DROP DEFAULT, perform the ALTER TYPE, and then use SET DEFAULT to add a suitable new default. Similar considerations apply to indexes and constraints involving ! the column. --- 691,698 ---- drop the default with DROP DEFAULT, perform the ALTER TYPE, and then use SET DEFAULT to add a suitable new default. Similar considerations apply to indexes and constraints involving ! the column. Note that both SET DEFAULT and DROP DEFAULT are forbidden ! on IDENTITY and GENERATED ALWAYS columns. diff -dcrpN pgsql.orig/doc/src/sgml/ref/copy.sgml pgsql/doc/src/sgml/ref/copy.sgml *** pgsql.orig/doc/src/sgml/ref/copy.sgml 2007-02-09 07:23:11.000000000 +0100 --- pgsql/doc/src/sgml/ref/copy.sgml 2007-02-28 08:48:34.000000000 +0100 *************** PostgreSQL documentation *** 22,27 **** --- 22,28 ---- COPY tablename [ ( column [, ...] ) ] + [ OVERRIDING { SYSTEM | USER } VALUE ] FROM { 'filename' | STDIN } [ [ WITH ] [ BINARY ] *************** COPY { ta *** 116,121 **** --- 117,134 ---- + OVERRIDING { SYSTEM | USER } VALUE + + + Specifies that values override enforced default values + for GENERATED ALWAYS columns. Only effective for + COPY tablename FROM + Only allowed for the owner of the table. + + + + + filename diff -dcrpN pgsql.orig/doc/src/sgml/ref/create_table.sgml pgsql/doc/src/sgml/ref/create_table.sgml *** pgsql.orig/doc/src/sgml/ref/create_table.sgml 2007-02-09 07:23:12.000000000 +0100 --- pgsql/doc/src/sgml/ref/create_table.sgml 2007-02-28 08:48:34.000000000 +0100 *************** PostgreSQL documentation *** 21,27 **** CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name ( [ ! { column_name data_type [ DEFAULT default_expr ] [ column_constraint [ ... ] ] | table_constraint | LIKE parent_table [ { INCLUDING | EXCLUDING } { DEFAULTS | CONSTRAINTS } ] ... } [, ... ] --- 21,29 ---- CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE table_name ( [ ! { column_name data_type ! | [ DEFAULT default_expr | GENERATED ALWAYS AS (default_expr ) | GENERATED { ALWAYS | BY DEFAULT } AS IDENTITY [ ( sequence_options ) ] ] ! | [ column_constraint [ ... ] ] | table_constraint | LIKE parent_table [ { INCLUDING | EXCLUDING } { DEFAULTS | CONSTRAINTS } ] ... } [, ... ] *************** and table *** 186,191 **** --- 188,236 ---- + GENERATED ALWAYS AS ( + default_expr ) + + + This creates a GENERATED column. It's similar + to the DEFAULT clause, with the following + exceptions. In an INSERT operation the default value + will be enforced even when an expression is specified. + This can be overridden by specifying OVERRIDING SYSTEM VALUE + but it's only allowed for the table owner. + In an UPDATE statement, only + SET colname = DEFAULT + is allowed for such columns. + + + + + + GENERATED { ALWAYS BY DEFAULT } AS IDENTITY [ ( + sequence_options ) ] + + + This clause creates an identity column, whose default value + will be generated by an automatically created sequence. + For the SERIAL pseudo-type this is implicit. + However, any type that has implicit cast from bigint + can be specified for the column. + + + + With GENERATED ALWAYS AS IDENTITY, the default value + will always be enforced in an INSERT operation. + OVERRIDING SYSTEM VALUE works the same just as with GENERATED columns. + However, any occurence of such columns in an UPDATE statement is forbidden. + With this feature, one can approximate the autoincrementer type + that other DBMSs provide, e.g.: + INSERT INTO table (id, ... ) VALUES (0, ...); + will insert a new column with the next sequence value instead of 0. + + + + + INHERITS ( parent_table [, ... ] ) diff -dcrpN pgsql.orig/doc/src/sgml/ref/insert.sgml pgsql/doc/src/sgml/ref/insert.sgml *** pgsql.orig/doc/src/sgml/ref/insert.sgml 2007-02-09 07:23:12.000000000 +0100 --- pgsql/doc/src/sgml/ref/insert.sgml 2007-02-28 08:48:34.000000000 +0100 *************** PostgreSQL documentation *** 21,26 **** --- 21,27 ---- INSERT INTO table [ ( column [, ...] ) ] + [ OVERRIDING { SYSTEM | USER } VALUE ] { DEFAULT VALUES | VALUES ( { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * | output_expression [ AS output_name ] [, ...] ] *************** INSERT INTO objtype == ACL_OBJECT_RELATION && + pg_class_tuple->relkind == RELKIND_SEQUENCE && + (istmt->privileges & (ACL_UPDATE|ACL_INSERT))) + { + InternalGrant seq_istmt; + Oid sequenceId; + int idx; + + seq_istmt.is_grant = istmt->is_grant; + seq_istmt.objtype = ACL_OBJECT_SEQUENCE; + seq_istmt.all_privs = true; + seq_istmt.privileges = ACL_ALL_RIGHTS_SEQUENCE; + seq_istmt.grantees = istmt->grantees; + /* don't give out GRANT on the supporting sequence */ + seq_istmt.grant_option = false; + seq_istmt.behavior = istmt->behavior; + seq_istmt.objects = NIL; + for (idx = 0; idx < relation->rd_att->natts; idx++) + { + if (relation->rd_att->attrs[idx]->attisdropped) + continue; + if (relation->rd_att->attrs[idx]->attidentity) + { + sequenceId = get_relid_att_serial_sequence(relOid, idx); + if (OidIsValid(sequenceId)) + seq_istmt.objects = lappend_oid(seq_istmt.objects, sequenceId); + } + } + if (seq_istmt.objects) + { + ExecGrantStmt_oids(&seq_istmt); + list_free(seq_istmt.objects); + } + } + ReleaseSysCache(tuple); pfree(new_acl); *************** ExecGrant_Relation(InternalGrant *istmt) *** 720,725 **** --- 761,877 ---- heap_close(relation, RowExclusiveLock); } + /* + * This is called when a new IDENTITY column is + * added to the table. It adds UPDATE permission + * for those who have INSERT or UPDATE permission + * on the table over the newly created sequence. + */ + void + ExecGrant_Sequence(Oid relOid, int attnum, Oid seqOid) + { + Relation relation; + Datum aclDatum; + Form_pg_class pg_class_tuple; + bool isNull; + AclMode avail_goptions; + AclMode this_privileges; + Acl *acl; + Oid grantorId; + Oid ownerId; + HeapTuple tuple; + int nmembers; + Oid *members; + InternalGrant istmt; + int idx; + + /* + * Fill istmt in advance. + */ + istmt.is_grant = true; + istmt.objtype = ACL_OBJECT_SEQUENCE; + istmt.all_privs = true; + istmt.privileges = ACL_ALL_RIGHTS_SEQUENCE; + istmt.grantees = NULL; + istmt.grant_option = false; + istmt.behavior = DROP_RESTRICT; + istmt.objects = NULL; + + relation = heap_open(RelationRelationId, RowExclusiveLock); + + tuple = SearchSysCache(RELOID, + ObjectIdGetDatum(relOid), + 0, 0, 0); + + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", relOid); + pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple); + + /* Not sensible to grant on an index */ + if (pg_class_tuple->relkind == RELKIND_INDEX) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is an index", + NameStr(pg_class_tuple->relname)))); + + /* Composite types aren't tables either */ + if (pg_class_tuple->relkind == RELKIND_COMPOSITE_TYPE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is a composite type", + NameStr(pg_class_tuple->relname)))); + + /* + * Get owner ID and working copy of existing ACL. If there's no ACL, + * substitute the proper default. + */ + ownerId = pg_class_tuple->relowner; + aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl, + &isNull); + + if (isNull) + acl = acldefault(ACL_OBJECT_RELATION, ownerId); + else + acl = DatumGetAclPCopy(aclDatum); + + /* Determine ID to do the grant as, and available grant options */ + this_privileges = ACL_ALL_RIGHTS_SEQUENCE; + select_best_grantor(GetUserId(), this_privileges, + acl, ownerId, + &grantorId, &avail_goptions); + + /* + * Restrict the privileges to what we can actually grant, and emit + * the standards-mandated warning and error messages. + */ + this_privileges = + restrict_and_check_grant(false, avail_goptions, + true, + this_privileges, + relOid, grantorId, + ACL_KIND_CLASS, + NameStr(pg_class_tuple->relname)); + + nmembers = aclmemberspriv(acl, &members, (ACL_UPDATE|ACL_INSERT), false); + for (idx = 0; idx < nmembers; idx++) + istmt.grantees = lappend_oid(istmt.grantees, members[idx]); + pfree(members); + + ReleaseSysCache(tuple); + + pfree(acl); + + heap_close(relation, RowExclusiveLock); + + if (istmt.grantees != NULL) + { + istmt.objects = list_make1_oid(seqOid); + ExecGrant_Relation(&istmt); + list_free(istmt.grantees); + list_free(istmt.objects); + } + } + static void ExecGrant_Database(InternalGrant *istmt) { diff -dcrpN pgsql.orig/src/backend/catalog/heap.c pgsql/src/backend/catalog/heap.c *** pgsql.orig/src/backend/catalog/heap.c 2007-02-15 12:36:04.000000000 +0100 --- pgsql/src/backend/catalog/heap.c 2007-02-28 08:48:34.000000000 +0100 *************** RemoveAttrDefaultById(Oid attrdefId) *** 1199,1204 **** --- 1199,1206 ---- myattnum, myrelid); ((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false; + ((Form_pg_attribute) GETSTRUCT(tuple))->attidentity = false; + ((Form_pg_attribute) GETSTRUCT(tuple))->attforceddef = false; simple_heap_update(attr_rel, &tuple->t_self, tuple); *************** heap_drop_with_catalog(Oid relid) *** 1292,1298 **** * The expression must be presented as a nodeToString() string. */ void ! StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin) { Node *expr; char *adsrc; --- 1294,1300 ---- * The expression must be presented as a nodeToString() string. */ void ! StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin, bool attidentity, bool attforceddef) { Node *expr; char *adsrc; *************** StoreAttrDefault(Relation rel, AttrNumbe *** 1306,1312 **** Oid attrdefOid; ObjectAddress colobject, defobject; ! /* * Need to construct source equivalent of given node-string. */ --- 1308,1315 ---- Oid attrdefOid; ObjectAddress colobject, defobject; ! List *rtable; ! /* * Need to construct source equivalent of given node-string. */ *************** StoreAttrDefault(Relation rel, AttrNumbe *** 1365,1370 **** --- 1368,1375 ---- if (!attStruct->atthasdef) { attStruct->atthasdef = true; + attStruct->attidentity = attidentity; + attStruct->attforceddef = attforceddef; simple_heap_update(attrrel, &atttup->t_self, atttup); /* keep catalog indexes current */ CatalogUpdateIndexes(attrrel, atttup); *************** StoreAttrDefault(Relation rel, AttrNumbe *** 1385,1391 **** /* * Record dependencies on objects used in the expression, too. */ ! recordDependencyOnExpr(&defobject, expr, NIL, DEPENDENCY_NORMAL); } /* --- 1390,1412 ---- /* * Record dependencies on objects used in the expression, too. */ ! if (!attidentity && attforceddef) ! { ! ParseState *pstate; ! RangeTblEntry *rte; ! ! pstate = make_parsestate(NULL); ! rte = addRangeTableEntryForRelation(pstate, ! rel, ! NULL, ! false, ! true); ! addRTEtoQuery(pstate, rte, true, true, true); ! rtable = list_make1(rte); ! } ! else ! rtable = NIL; ! recordDependencyOnExpr(&defobject, expr, rtable, DEPENDENCY_NORMAL); } /* *************** StoreConstraints(Relation rel, TupleDesc *** 1504,1510 **** for (i = 0; i < constr->num_defval; i++) StoreAttrDefault(rel, constr->defval[i].adnum, ! constr->defval[i].adbin); for (i = 0; i < constr->num_check; i++) StoreRelCheck(rel, constr->check[i].ccname, --- 1525,1532 ---- for (i = 0; i < constr->num_defval; i++) StoreAttrDefault(rel, constr->defval[i].adnum, ! constr->defval[i].adbin, ! false, false); for (i = 0; i < constr->num_check; i++) StoreRelCheck(rel, constr->check[i].ccname, *************** AddRelationRawConstraints(Relation rel, *** 1554,1559 **** --- 1576,1583 ---- ListCell *cell; Node *expr; CookedConstraint *cooked; + int varno; + int sublevels_up; /* * Get info about existing constraints. *************** AddRelationRawConstraints(Relation rel, *** 1584,1601 **** { RawColumnDefault *colDef = (RawColumnDefault *) lfirst(cell); Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1]; expr = cookDefault(pstate, colDef->raw_default, atp->atttypid, atp->atttypmod, ! NameStr(atp->attname)); ! StoreAttrDefault(rel, colDef->attnum, nodeToString(expr)); cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint)); cooked->contype = CONSTR_DEFAULT; cooked->name = NULL; cooked->attnum = colDef->attnum; cooked->expr = expr; cookedConstraints = lappend(cookedConstraints, cooked); } --- 1608,1660 ---- { RawColumnDefault *colDef = (RawColumnDefault *) lfirst(cell); Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1]; + int attnum; expr = cookDefault(pstate, colDef->raw_default, atp->atttypid, atp->atttypmod, ! NameStr(atp->attname), ! !colDef->is_identity && colDef->force_default); ! varno = RTERangeTablePosn(pstate, rte, &sublevels_up); ! ! if (!colDef->is_identity && colDef->force_default) ! { ! varno = RTERangeTablePosn(pstate, rte, &sublevels_up); ! ! for (attnum = 1; attnum <= tupleDesc->natts; attnum++) ! { ! if (tupleDesc->attrs[attnum - 1]->attisdropped) ! continue; ! if (tupleDesc->attrs[attnum - 1]->attidentity || ! tupleDesc->attrs[attnum - 1]->attforceddef) ! { ! Node *var; ! ! var = scanRTEForColumn(pstate, ! rte, ! NameStr(tupleDesc->attrs[attnum - 1]->attname), ! -1); ! if (contain_var_reference(expr, varno, ((Var *)var)->varattno, sublevels_up)) ! ereport(ERROR, ! (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), ! errmsg("%s column \"%s\" of table \"%s\" cannot be referenced by GENERATED column \"%s\"", ! tupleDesc->attrs[attnum - 1]->attidentity ? ! "IDENTITY" : "GENERATED", ! get_attname(RelationGetRelid(rel), attnum), ! RelationGetRelationName(rel), ! get_attname(RelationGetRelid(rel), colDef->attnum)))); ! } ! } ! } ! ! StoreAttrDefault(rel, colDef->attnum, nodeToString(expr), colDef->is_identity, colDef->force_default); cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint)); cooked->contype = CONSTR_DEFAULT; cooked->name = NULL; cooked->attnum = colDef->attnum; cooked->expr = expr; + cooked->force_default = colDef->force_default; cookedConstraints = lappend(cookedConstraints, cooked); } *************** AddRelationRawConstraints(Relation rel, *** 1608,1613 **** --- 1667,1673 ---- { Constraint *cdef = (Constraint *) lfirst(cell); char *ccname; + int attnum; if (cdef->contype != CONSTR_CHECK || cdef->raw_expr == NULL) continue; *************** AddRelationRawConstraints(Relation rel, *** 1618,1623 **** --- 1678,1709 ---- */ expr = transformExpr(pstate, cdef->raw_expr); + varno = RTERangeTablePosn(pstate, rte, &sublevels_up); + + for (attnum = 1; attnum <= tupleDesc->natts; attnum++) + { + if (tupleDesc->attrs[attnum - 1]->attisdropped) + continue; + if (tupleDesc->attrs[attnum - 1]->attidentity || + tupleDesc->attrs[attnum - 1]->attforceddef) + { + Node *var; + + var = scanRTEForColumn(pstate, + rte, + NameStr(tupleDesc->attrs[attnum - 1]->attname), + -1); + if (contain_var_reference(expr, varno, ((Var *)var)->varattno, sublevels_up)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), + errmsg("%s column \"%s\" of table \"%s\" cannot be referenced in CHECK constraint", + tupleDesc->attrs[attnum - 1]->attidentity ? + "IDENTITY" : "GENERATED", + get_attname(RelationGetRelid(rel), attnum), + RelationGetRelationName(rel)))); + } + } + /* * Make sure it yields a boolean result. */ *************** cookDefault(ParseState *pstate, *** 1799,1805 **** Node *raw_default, Oid atttypid, int32 atttypmod, ! char *attname) { Node *expr; --- 1885,1892 ---- Node *raw_default, Oid atttypid, int32 atttypmod, ! char *attname, ! bool force_default) { Node *expr; *************** cookDefault(ParseState *pstate, *** 1813,1819 **** /* * Make sure default expr does not refer to any vars. */ ! if (contain_var_clause(expr)) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("cannot use column references in default expression"))); --- 1900,1906 ---- /* * Make sure default expr does not refer to any vars. */ ! if (!force_default && contain_var_clause(expr)) ereport(ERROR, (errcode(ERRCODE_INVALID_COLUMN_REFERENCE), errmsg("cannot use column references in default expression"))); diff -dcrpN pgsql.orig/src/backend/catalog/index.c pgsql/src/backend/catalog/index.c *** pgsql.orig/src/backend/catalog/index.c 2007-02-15 12:36:04.000000000 +0100 --- pgsql/src/backend/catalog/index.c 2007-02-28 08:48:34.000000000 +0100 *************** ConstructTupleDescriptor(Relation heapRe *** 166,171 **** --- 166,173 ---- to->atthasdef = false; to->attislocal = true; to->attinhcount = 0; + to->attidentity = false; + to->attforceddef = false; } else { diff -dcrpN pgsql.orig/src/backend/commands/copy.c pgsql/src/backend/commands/copy.c *** pgsql.orig/src/backend/commands/copy.c 2007-02-25 16:14:15.000000000 +0100 --- pgsql/src/backend/commands/copy.c 2007-02-28 12:44:02.000000000 +0100 *************** *** 40,45 **** --- 40,46 ---- #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/memutils.h" + #include "utils/rel.h" #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7')) *************** typedef struct CopyStateData *** 159,164 **** --- 160,167 ---- char *raw_buf; int raw_buf_index; /* next byte to process */ int raw_buf_len; /* total # of bytes stored */ + + bool overriding; /* OVERRIDING SYSTEM VALUE */ } CopyStateData; typedef CopyStateData *CopyState; *************** DoCopy(const CopyStmt *stmt) *** 1137,1142 **** --- 1140,1146 ---- cstate->copy_dest = COPY_FILE; /* default */ cstate->filename = stmt->filename; + cstate->overriding = stmt->overriding; /* OVERRIDING SYSTEM VALUE */ if (is_from) /* copy from file to database */ CopyFrom(cstate); *************** CopyFrom(CopyState cstate) *** 1640,1645 **** --- 1644,1651 ---- Oid in_func_oid; Datum *values; char *nulls; + char *unknown; + char *replace; int nfields; char **field_strings; bool done = false; *************** CopyFrom(CopyState cstate) *** 1654,1659 **** --- 1660,1666 ---- MemoryContext oldcontext = CurrentMemoryContext; ErrorContextCallback errcontext; bool use_wal = true; /* By default, we use WAL to log db changes */ + bool hasforceddef; Assert(cstate->rel); *************** CopyFrom(CopyState cstate) *** 1676,1681 **** --- 1683,1706 ---- RelationGetRelationName(cstate->rel)))); } + tupDesc = RelationGetDescr(cstate->rel); + attr = tupDesc->attrs; + num_phys_attrs = tupDesc->natts; + + hasforceddef = false; + for (attnum = 1; attnum <= num_phys_attrs; attnum++) + { + if (attr[attnum - 1]->attisdropped) + continue; + hasforceddef |= attr[attnum - 1]->attforceddef; + } + if (cstate->overriding && hasforceddef) + { + Oid relid = RelationGetRelid(cstate->rel); + if (!pg_class_ownercheck(relid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + get_rel_name(relid)); + } if (pipe) { if (whereToSendOutput == DestRemote) *************** CopyFrom(CopyState cstate) *** 1705,1713 **** } } - tupDesc = RelationGetDescr(cstate->rel); - attr = tupDesc->attrs; - num_phys_attrs = tupDesc->natts; attr_count = list_length(cstate->attnumlist); num_defaults = 0; --- 1730,1735 ---- *************** CopyFrom(CopyState cstate) *** 1735,1740 **** --- 1757,1763 ---- slot = MakeSingleTupleTableSlot(tupDesc); econtext = GetPerTupleExprContext(estate); + econtext->ecxt_scantuple = slot; /* * Pick up the required catalog information for each attribute in the *************** CopyFrom(CopyState cstate) *** 1840,1845 **** --- 1863,1870 ---- values = (Datum *) palloc(num_phys_attrs * sizeof(Datum)); nulls = (char *) palloc(num_phys_attrs * sizeof(char)); + unknown = (char *) palloc(num_phys_attrs * sizeof(char)); + replace = (char *) palloc(num_phys_attrs * sizeof(char)); /* create workspace for CopyReadAttributes results */ nfields = file_has_oids ? (attr_count + 1) : attr_count; *************** CopyFrom(CopyState cstate) *** 1903,1911 **** /* Switch into its memory context */ MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); ! /* Initialize all values for row to NULL */ MemSet(values, 0, num_phys_attrs * sizeof(Datum)); MemSet(nulls, 'n', num_phys_attrs * sizeof(char)); if (!cstate->binary) { --- 1928,1940 ---- /* Switch into its memory context */ MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); ! /* ! * Initialize all values for row to NULL. ! * Also make a note that all values are unknown. ! */ MemSet(values, 0, num_phys_attrs * sizeof(Datum)); MemSet(nulls, 'n', num_phys_attrs * sizeof(char)); + MemSet(unknown, 'u', num_phys_attrs * sizeof(char)); if (!cstate->binary) { *************** CopyFrom(CopyState cstate) *** 1986,1993 **** string, typioparams[m], attr[m]->atttypmod); ! if (string != NULL) ! nulls[m] = ' '; cstate->cur_attname = NULL; cstate->cur_attval = NULL; } --- 2015,2022 ---- string, typioparams[m], attr[m]->atttypmod); ! nulls[m] = string != NULL ? ' ' : 'n'; ! unknown[m] = ' '; cstate->cur_attname = NULL; cstate->cur_attval = NULL; } *************** CopyFrom(CopyState cstate) *** 2045,2050 **** --- 2074,2080 ---- attr[m]->atttypmod, &isnull); nulls[m] = isnull ? 'n' : ' '; + unknown[m] = ' '; cstate->cur_attname = NULL; } } *************** CopyFrom(CopyState cstate) *** 2052,2065 **** /* * Now compute and insert any defaults available for the columns not * provided by the input data. Anything not processed here or above ! * will remain NULL. */ for (i = 0; i < num_defaults; i++) { ! values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext, &isnull, NULL); ! if (!isnull) ! nulls[defmap[i]] = ' '; } /* And now we can form the input tuple. */ --- 2082,2099 ---- /* * Now compute and insert any defaults available for the columns not * provided by the input data. Anything not processed here or above ! * will remain NULL. Skip IDENTITY and GENERATED for now. */ for (i = 0; i < num_defaults; i++) { ! if (!attr[defmap[i]]->attidentity && ! !attr[defmap[i]]->attforceddef) ! { ! values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext, &isnull, NULL); ! nulls[defmap[i]] = isnull ? 'n' : ' '; ! unknown[defmap[i]] = ' '; ! } } /* And now we can form the input tuple. */ *************** CopyFrom(CopyState cstate) *** 2092,2103 **** if (!skip_tuple) { /* Place tuple in tuple slot */ ExecStoreTuple(tuple, slot, InvalidBuffer, false); /* Check the constraints of the tuple */ if (cstate->rel->rd_att->constr) ! ExecConstraints(resultRelInfo, slot, estate); /* OK, store the tuple and create index entries for it */ fast_heap_insert(cstate->rel, tuple, use_wal); --- 2126,2185 ---- if (!skip_tuple) { + bool replaced; + /* Place tuple in tuple slot */ ExecStoreTuple(tuple, slot, InvalidBuffer, false); /* Check the constraints of the tuple */ if (cstate->rel->rd_att->constr) ! ExecConstraints(resultRelInfo, slot, estate, false, false); ! ! /* Generate DEFAULTs for GENERATED and IDENTITY columns here. */ ! replaced = false; ! MemSet(replace, ' ', num_phys_attrs * sizeof(char)); ! for (i = 0; i < num_defaults; i++) ! { ! if (attr[defmap[i]]->attforceddef && ! !attr[defmap[i]]->attidentity && ! (!cstate->overriding || unknown[defmap[i]] == 'u')) ! { ! values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext, ! &isnull, NULL); ! nulls[defmap[i]] = isnull ? 'n' : ' '; ! unknown[defmap[i]] = ' '; ! replace[defmap[i]] = 'r'; ! replaced = true; ! } ! } ! if (replaced) ! { ! tuple = heap_modifytuple(tuple, tupDesc, values, nulls, replace); ! if (cstate->rel->rd_att->constr) ! ExecConstraints(resultRelInfo, slot, estate, false, true); ! } ! replaced = false; ! MemSet(replace, ' ', num_phys_attrs * sizeof(char)); ! for (i = 0; i < num_defaults; i++) ! { ! if (attr[defmap[i]]->attidentity && ! (!cstate->overriding || unknown[defmap[i]] == 'u')) ! { ! values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext, ! &isnull, NULL); ! nulls[defmap[i]] = isnull ? 'n' : ' '; ! unknown[defmap[i]] = ' '; ! replace[defmap[i]] = 'r'; ! replaced = true; ! } ! } ! if (replaced) ! { ! tuple = heap_modifytuple(tuple, tupDesc, values, nulls, replace); ! ExecStoreTuple(tuple, slot, InvalidBuffer, false); ! if (cstate->rel->rd_att->constr) ! ExecConstraints(resultRelInfo, slot, estate, true, false); ! } /* OK, store the tuple and create index entries for it */ fast_heap_insert(cstate->rel, tuple, use_wal); *************** CopyFrom(CopyState cstate) *** 2156,2161 **** --- 2238,2245 ---- pfree(values); pfree(nulls); + pfree(unknown); + pfree(replace); pfree(field_strings); pfree(in_functions); diff -dcrpN pgsql.orig/src/backend/commands/sequence.c pgsql/src/backend/commands/sequence.c *** pgsql.orig/src/backend/commands/sequence.c 2007-02-09 07:23:21.000000000 +0100 --- pgsql/src/backend/commands/sequence.c 2007-02-28 08:48:34.000000000 +0100 *************** DefineSequence(CreateSeqStmt *seq) *** 129,134 **** --- 129,136 ---- coldef->raw_default = NULL; coldef->cooked_default = NULL; coldef->constraints = NIL; + coldef->is_identity = false; + coldef->force_default = false; null[i - 1] = ' '; *************** process_owned_by(Relation seqrel, List * *** 1234,1247 **** { ObjectAddress refobject, depobject; refobject.classId = RelationRelationId; ! refobject.objectId = RelationGetRelid(tablerel); refobject.objectSubId = attnum; depobject.classId = RelationRelationId; ! depobject.objectId = RelationGetRelid(seqrel); depobject.objectSubId = 0; recordDependencyOn(&depobject, &refobject, DEPENDENCY_AUTO); } /* Done, but hold lock until commit */ --- 1236,1253 ---- { ObjectAddress refobject, depobject; + Oid tableId, seqId; + tableId = RelationGetRelid(tablerel); + seqId = RelationGetRelid(seqrel); refobject.classId = RelationRelationId; ! refobject.objectId = tableId; refobject.objectSubId = attnum; depobject.classId = RelationRelationId; ! depobject.objectId = seqId; depobject.objectSubId = 0; recordDependencyOn(&depobject, &refobject, DEPENDENCY_AUTO); + ExecGrant_Sequence(tableId, attnum, seqId); } /* Done, but hold lock until commit */ diff -dcrpN pgsql.orig/src/backend/commands/tablecmds.c pgsql/src/backend/commands/tablecmds.c *** pgsql.orig/src/backend/commands/tablecmds.c 2007-02-20 14:59:37.000000000 +0100 --- pgsql/src/backend/commands/tablecmds.c 2007-02-28 11:22:52.000000000 +0100 *************** *** 34,39 **** --- 34,40 ---- #include "catalog/toasting.h" #include "commands/cluster.h" #include "commands/defrem.h" + #include "commands/sequence.h" #include "commands/tablecmds.h" #include "commands/tablespace.h" #include "commands/trigger.h" *************** *** 44,49 **** --- 45,51 ---- #include "optimizer/clauses.h" #include "optimizer/plancat.h" #include "optimizer/prep.h" + #include "optimizer/var.h" #include "parser/analyze.h" #include "parser/gramparse.h" #include "parser/parse_clause.h" *************** static void StoreCatalogInheritance1(Oid *** 173,178 **** --- 175,181 ---- int16 seqNumber, Relation inhRelation); static int findAttrByName(const char *attributeName, List *schema); static void setRelhassubclassInRelation(Oid relationId, bool relhassubclass); + static void renameseqfor(Oid tableOid, const char *newrelname, const char *oldattname, const char *newattname); static void AlterIndexNamespaces(Relation classRel, Relation rel, Oid oldNspOid, Oid newNspOid); static void AlterSeqNamespaces(Relation classRel, Relation rel, *************** static void ATExecEnableDisableTrigger(R *** 256,261 **** --- 259,266 ---- bool enable, bool skip_system); static void ATExecAddInherit(Relation rel, RangeVar *parent); static void ATExecDropInherit(Relation rel, RangeVar *parent); + static void ATExecAlterSeq(Relation rel, char *column, List *seq_opts); + static void ATExecIdentity(Relation rel, char *column, bool is_identity, bool force_default); static void copy_relation_data(Relation rel, SMgrRelation dst); *************** DefineRelation(CreateStmt *stmt, char re *** 284,289 **** --- 289,295 ---- Datum reloptions; ListCell *listptr; AttrNumber attnum; + int identity_count; /* * Truncate relname to appropriate length (probably a waste of time, as *************** DefineRelation(CreateStmt *stmt, char re *** 367,372 **** --- 373,393 ---- stmt->relation->istemp, &inheritOids, &old_constraints, &parentOidCount); + identity_count = 0; + foreach(listptr, schema) + { + ColumnDef *colDef = lfirst(listptr); + + if (colDef->is_identity) + { + identity_count++; + if (identity_count > 1) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("multiple IDENTITY columns are not allowed"))); + } + } + /* * Create a relation descriptor from the relation schema and create the * relation. Note that in this stage only inherited (pre-cooked) defaults *************** DefineRelation(CreateStmt *stmt, char re *** 481,486 **** --- 502,509 ---- rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault)); rawEnt->attnum = attnum; rawEnt->raw_default = colDef->raw_default; + rawEnt->is_identity = colDef->is_identity; + rawEnt->force_default = colDef->force_default; rawDefaults = lappend(rawDefaults, rawEnt); } } *************** MergeAttributes(List *schema, List *supe *** 932,937 **** --- 955,962 ---- def->raw_default = NULL; def->cooked_default = NULL; def->constraints = NIL; + def->is_identity = false; + def->force_default = false; inhSchema = lappend(inhSchema, def); newattno[parent_attno - 1] = ++child_attno; } *************** MergeAttributes(List *schema, List *supe *** 976,981 **** --- 1001,1008 ---- def->cooked_default = bogus_marker; have_bogus_defaults = true; } + def->is_identity = attribute->attidentity; + def->force_default = attribute->attforceddef; } } *************** MergeAttributes(List *schema, List *supe *** 1066,1071 **** --- 1093,1100 ---- { def->raw_default = newdef->raw_default; def->cooked_default = newdef->cooked_default; + def->is_identity = newdef->is_identity; + def->force_default = newdef->force_default; } } else *************** setRelhassubclassInRelation(Oid relation *** 1410,1415 **** --- 1439,1471 ---- } + static void renameseqfor(Oid tableOid, const char *newrelname, const char *oldattname, const char *newattname) + { + int attnum; + Oid sequenceId; + + if (!newrelname) + newrelname = get_rel_name(tableOid); + attnum = get_attnum(tableOid, oldattname); + if (attnum == InvalidAttrNumber) + return; + + sequenceId = get_relid_att_serial_sequence(tableOid, attnum); + + if (OidIsValid(sequenceId)) + { + char *sname; + + sname = ChooseRelationName(newrelname, + newattname, + "seq", + get_rel_namespace(sequenceId)); + renamerel(sequenceId, sname); + elog(NOTICE, "supporting sequence for column \"%s\" renamed to \"%s\"", newattname, sname); + pfree(sname); + } + } + /* * renameatt - changes the name of a attribute in a relation * *************** renameatt(Oid myrelid, *** 1612,1617 **** --- 1668,1679 ---- heap_close(attrelation, RowExclusiveLock); relation_close(targetrelation, NoLock); /* close rel but keep lock */ + + /* + * Also rename the underlying sequence + * if this column is SERIAL or GENERATED AS IDENTITY. + */ + renameseqfor(myrelid, NULL, oldattname, newattname); } /* *************** renamerel(Oid myrelid, const char *newre *** 1633,1638 **** --- 1695,1701 ---- char *oldrelname; char relkind; bool relhastriggers; + int idx; /* * Grab an exclusive lock on the target table or index, which we will NOT *************** renamerel(Oid myrelid, const char *newre *** 1680,1685 **** --- 1743,1757 ---- /* keep the system catalog indexes current */ CatalogUpdateIndexes(relrelation, reltup); + for (idx = 0; idx < targetrelation->rd_att->natts; idx++) + { + char *attname; + if (targetrelation->rd_att->attrs[idx]->attisdropped) + continue; + attname = NameStr(targetrelation->rd_att->attrs[idx]->attname); + renameseqfor(myrelid, newrelname, attname, attname); + } + heap_freetuple(reltup); heap_close(relrelation, RowExclusiveLock); *************** ATPrepCmd(List **wqueue, Relation rel, A *** 1966,1971 **** --- 2038,2046 ---- case AT_DisableTrigUser: case AT_AddInherit: /* INHERIT / NO INHERIT */ case AT_DropInherit: + case AT_SetSeqOpts: + case AT_SetIdentity: + case AT_DropIdentity: ATSimplePermissions(rel, false); /* These commands never recurse */ /* No command-specific prep needed */ *************** ATExecCmd(AlteredTableInfo *tab, Relatio *** 2155,2160 **** --- 2230,2244 ---- case AT_DropInherit: ATExecDropInherit(rel, (RangeVar *) cmd->def); break; + case AT_SetSeqOpts: + ATExecAlterSeq(rel, cmd->name, (List *)cmd->def); + break; + case AT_SetIdentity: + ATExecIdentity(rel, cmd->name, true, cmd->force_default); + break; + case AT_DropIdentity: + ATExecIdentity(rel, cmd->name, false, false); + break; default: /* oops */ elog(ERROR, "unrecognized alter table type: %d", (int) cmd->subtype); *************** ATExecAddColumn(AlteredTableInfo *tab, R *** 2914,2919 **** --- 2998,3013 ---- Form_pg_type tform; Expr *defval; + if (colDef->is_identity) + { + for (i = 0; i < rel->rd_att->natts; i++) + if (rel->rd_att->attrs[i]->attidentity) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("multiple IDENTITY columns are not allowed"))); + + } + attrdesc = heap_open(AttributeRelationId, RowExclusiveLock); /* *************** ATExecAddColumn(AlteredTableInfo *tab, R *** 3021,3026 **** --- 3115,3122 ---- attribute->attisdropped = false; attribute->attislocal = colDef->is_local; attribute->attinhcount = colDef->inhcount; + attribute->attidentity = colDef->is_identity; + attribute->attforceddef = colDef->force_default; ReleaseSysCache(typeTuple); *************** ATExecAddColumn(AlteredTableInfo *tab, R *** 3058,3063 **** --- 3154,3161 ---- rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault)); rawEnt->attnum = attribute->attnum; rawEnt->raw_default = copyObject(colDef->raw_default); + rawEnt->is_identity = colDef->is_identity; + rawEnt->force_default = colDef->force_default; /* * This function is intended for CREATE TABLE, so it processes a *************** ATExecColumnDefault(Relation rel, const *** 3315,3320 **** --- 3413,3430 ---- errmsg("cannot alter system column \"%s\"", colName))); + if (rel->rd_att->attrs[attnum - 1]->attidentity) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot alter IDENTITY column \"%s\"", + colName))); + + if (rel->rd_att->attrs[attnum - 1]->attforceddef) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot alter GENERATED ALWAYS column \"%s\"", + colName))); + /* * Remove any old default for the column. We use RESTRICT here for * safety, but at present we do not expect anything to depend on the *************** ATExecColumnDefault(Relation rel, const *** 3330,3335 **** --- 3440,3447 ---- rawEnt = (RawColumnDefault *) palloc(sizeof(RawColumnDefault)); rawEnt->attnum = attnum; rawEnt->raw_default = newDefault; + rawEnt->is_identity = false; + rawEnt->force_default = false; /* * This function is intended for CREATE TABLE, so it processes a *************** ATExecDropColumn(Relation rel, const cha *** 3511,3516 **** --- 3623,3629 ---- DropBehavior behavior, bool recurse, bool recursing) { + TupleDesc tupleDesc; HeapTuple tuple; Form_pg_attribute targetatt; AttrNumber attnum; *************** ATExecDropColumn(Relation rel, const cha *** 3640,3645 **** --- 3753,3812 ---- } /* + * Check for GENERATED columns that reference this column + */ + tupleDesc = RelationGetDescr(rel); + if (attnum >= 1 && + !tupleDesc->attrs[attnum - 1]->attidentity && + !tupleDesc->attrs[attnum - 1]->attforceddef) + { + ParseState *pstate; + RangeTblEntry *rte; + int gen_attnum; + int varno; + int sublevels_up; + + pstate = make_parsestate(NULL); + rte = addRangeTableEntryForRelation(pstate, + rel, + NULL, + false, + true); + addRTEtoQuery(pstate, rte, true, true, true); + varno = RTERangeTablePosn(pstate, rte, &sublevels_up); + + for (gen_attnum = 1; gen_attnum <= tupleDesc->natts; gen_attnum++) + { + if (tupleDesc->attrs[gen_attnum - 1]->attisdropped) + continue; + if (tupleDesc->attrs[gen_attnum - 1]->attforceddef && + !tupleDesc->attrs[gen_attnum - 1]->attidentity) + { + Node *expr; + Node *var; + expr = build_column_default(rel, gen_attnum); + var = scanRTEForColumn(pstate, + rte, + NameStr(tupleDesc->attrs[attnum - 1]->attname), + -1); + if (contain_var_reference(expr, varno, ((Var *)var)->varattno, sublevels_up)) + { + ereport(NOTICE, + (errcode(ERRCODE_WARNING), + errmsg("GENERATED column \"%s\" of relation \"%s\" referencing column \"%s\" was dropped", + NameStr(tupleDesc->attrs[gen_attnum - 1]->attname), + RelationGetRelationName(rel), + colName))); + ATExecDropColumn(rel, + NameStr(tupleDesc->attrs[gen_attnum - 1]->attname), + DROP_CASCADE, + false, false); + } + } + } + } + + /* * Perform the actual column deletion */ object.classId = RelationRelationId; *************** ATExecAlterColumnType(AlteredTableInfo * *** 4793,4798 **** --- 4960,4967 ---- ScanKeyData key[3]; SysScanDesc scan; HeapTuple depTup; + bool attidentity; + bool attforceddef; attrelation = heap_open(AttributeRelationId, RowExclusiveLock); *************** ATExecAlterColumnType(AlteredTableInfo * *** 4850,4855 **** --- 5019,5026 ---- } else defaultexpr = NULL; + attidentity = attTup->attidentity; + attforceddef = attTup->attforceddef; /* * Find everything that depends on the column (constraints, indexes, etc), *************** ATExecAlterColumnType(AlteredTableInfo * *** 5098,5104 **** */ RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true); ! StoreAttrDefault(rel, attnum, nodeToString(defaultexpr)); } /* Cleanup */ --- 5269,5275 ---- */ RemoveAttrDefault(RelationGetRelid(rel), attnum, DROP_RESTRICT, true); ! StoreAttrDefault(rel, attnum, nodeToString(defaultexpr), attidentity, attforceddef); } /* Cleanup */ *************** decompile_conbin(HeapTuple contup, Tuple *** 6024,6029 **** --- 6195,6328 ---- } /* + * ALTER TABLE RESTART WITH / SET sequence_options + */ + static void + ATExecAlterSeq(Relation rel, char *column, List *seq_opts) + { + Oid tableOid; + AttrNumber attnum; + Oid sequenceId; + + tableOid = RelationGetRelid(rel); + attnum = get_attnum(tableOid, column); + + if (attnum == InvalidAttrNumber) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + column, RelationGetRelationName(rel)))); + + sequenceId = get_relid_att_serial_sequence(tableOid, attnum); + if (OidIsValid(sequenceId)) + { + HeapTuple seqtup; + + seqtup = SearchSysCache(RELOID, + ObjectIdGetDatum(sequenceId), + 0, 0, 0); + if (HeapTupleIsValid(seqtup)) + { + Form_pg_class seq = (Form_pg_class) GETSTRUCT(seqtup); + HeapTuple nsptup; + RangeVar *rv = NULL; + + nsptup = SearchSysCache(NAMESPACEOID, + ObjectIdGetDatum(seq->relnamespace), + 0, 0, 0); + if (HeapTupleIsValid(nsptup)) + { + Form_pg_namespace nsp = (Form_pg_namespace) GETSTRUCT(nsptup); + rv = makeRangeVar(NameStr(nsp->nspname), NameStr(seq->relname)); + ReleaseSysCache(nsptup); + } + + ReleaseSysCache(seqtup); + + if (rv != NULL) + { + AlterSeqStmt *newcmd; + + newcmd = makeNode(AlterSeqStmt); + newcmd->sequence = rv; + newcmd->options = seq_opts; + AlterSequence(newcmd); + pfree(newcmd); + pfree(rv); + } + } + } else + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("column \"%s\" of relation \"%s\" is not an IDENTITY or SERIAL column", + column, RelationGetRelationName(rel)))); + } + + static void + ATExecIdentity(Relation rel, char *column, bool is_identity, bool force_default) + { + Oid tableOid; + AttrNumber attnum; + Oid sequenceId; + TupleDesc tupleDesc; + int idx; + + tableOid = RelationGetRelid(rel); + attnum = get_attnum(tableOid, column); + + if (attnum == InvalidAttrNumber) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_COLUMN), + errmsg("column \"%s\" of relation \"%s\" does not exist", + column, RelationGetRelationName(rel)))); + + tupleDesc = RelationGetDescr(rel); + if (is_identity) + { + for (idx = 0; idx < tupleDesc->natts; idx++) + { + if (tupleDesc->attrs[idx]->attisdropped) + continue; + if (attnum != (idx + 1) && + tupleDesc->attrs[idx]->attidentity) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("multiple IDENTITY columns are not allowed"))); + } + } else + force_default = false; + + sequenceId = get_relid_att_serial_sequence(tableOid, attnum); + + if (OidIsValid(sequenceId) && + ((is_identity && + !tupleDesc->attrs[attnum - 1]->attidentity && + !tupleDesc->attrs[attnum - 1]->attforceddef) || + (!is_identity && + tupleDesc->attrs[attnum - 1]->attidentity))) + { + Node *old_default = build_column_default(rel, attnum); + + /* Rewrite the DEFAULT parameters */ + + RemoveAttrDefault(RelationGetRelid(rel), + attnum, + DROP_RESTRICT, + false); + + StoreAttrDefault(rel, + attnum, + nodeToString(old_default), + is_identity, + force_default); + } else + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("column \"%s\" of relation \"%s\" is not a plain SERIAL column", + column, RelationGetRelationName(rel)))); + } + + /* * Check columns in child table match up with columns in parent, and increment * their attinhcount. * diff -dcrpN pgsql.orig/src/backend/commands/typecmds.c pgsql/src/backend/commands/typecmds.c *** pgsql.orig/src/backend/commands/typecmds.c 2007-02-15 12:36:06.000000000 +0100 --- pgsql/src/backend/commands/typecmds.c 2007-02-28 08:48:35.000000000 +0100 *************** DefineDomain(CreateDomainStmt *stmt) *** 718,724 **** defaultExpr = cookDefault(pstate, constr->raw_expr, basetypeoid, basetypeMod, ! domainName); /* * Expression must be stored as a nodeToString result, but we --- 718,725 ---- defaultExpr = cookDefault(pstate, constr->raw_expr, basetypeoid, basetypeMod, ! domainName, ! false); /* * Expression must be stored as a nodeToString result, but we *************** AlterDomainDefault(List *names, Node *de *** 1285,1291 **** defaultExpr = cookDefault(pstate, defaultRaw, typTup->typbasetype, typTup->typtypmod, ! NameStr(typTup->typname)); /* * Expression must be stored as a nodeToString result, but we also --- 1286,1293 ---- defaultExpr = cookDefault(pstate, defaultRaw, typTup->typbasetype, typTup->typtypmod, ! NameStr(typTup->typname), ! false); /* * Expression must be stored as a nodeToString result, but we also diff -dcrpN pgsql.orig/src/backend/commands/view.c pgsql/src/backend/commands/view.c *** pgsql.orig/src/backend/commands/view.c 2007-01-10 19:58:23.000000000 +0100 --- pgsql/src/backend/commands/view.c 2007-02-28 08:48:35.000000000 +0100 *************** DefineVirtualRelation(const RangeVar *re *** 126,131 **** --- 126,133 ---- def->raw_default = NULL; def->cooked_default = NULL; def->constraints = NIL; + def->is_identity = false; + def->force_default = false; attrList = lappend(attrList, def); } diff -dcrpN pgsql.orig/src/backend/executor/execMain.c pgsql/src/backend/executor/execMain.c *** pgsql.orig/src/backend/executor/execMain.c 2007-02-27 08:27:35.000000000 +0100 --- pgsql/src/backend/executor/execMain.c 2007-02-28 10:27:17.000000000 +0100 *************** *** 45,55 **** --- 45,58 ---- #include "executor/instrument.h" #include "executor/nodeSubplan.h" #include "miscadmin.h" + #include "nodes/makefuncs.h" #include "optimizer/clauses.h" #include "parser/parse_clause.h" #include "parser/parsetree.h" + #include "rewrite/rewriteHandler.h" #include "storage/smgr.h" #include "utils/acl.h" + #include "./utils/datum.h" #include "utils/lsyscache.h" #include "utils/memutils.h" *************** static TupleTableSlot *ExecutePlan(EStat *** 75,92 **** CmdType operation, long numberTuples, ScanDirection direction, ! DestReceiver *dest); static void ExecSelect(TupleTableSlot *slot, DestReceiver *dest, EState *estate); static void ExecInsert(TupleTableSlot *slot, ItemPointer tupleid, TupleTableSlot *planSlot, ! DestReceiver *dest, EState *estate); static void ExecDelete(ItemPointer tupleid, TupleTableSlot *planSlot, DestReceiver *dest, EState *estate); static void ExecUpdate(TupleTableSlot *slot, ItemPointer tupleid, TupleTableSlot *planSlot, ! DestReceiver *dest, EState *estate); static void ExecProcessReturning(ProjectionInfo *projectReturning, TupleTableSlot *tupleSlot, TupleTableSlot *planSlot, --- 78,102 ---- CmdType operation, long numberTuples, ScanDirection direction, ! DestReceiver *dest, ! bool idSetToDefault); static void ExecSelect(TupleTableSlot *slot, DestReceiver *dest, EState *estate); static void ExecInsert(TupleTableSlot *slot, ItemPointer tupleid, TupleTableSlot *planSlot, ! DestReceiver *dest, EState *estate, ! bool idSetToDefault); static void ExecDelete(ItemPointer tupleid, TupleTableSlot *planSlot, DestReceiver *dest, EState *estate); static void ExecUpdate(TupleTableSlot *slot, ItemPointer tupleid, TupleTableSlot *planSlot, ! DestReceiver *dest, EState *estate, ! bool idSetToDefault); ! static HeapTuple ExecGenerated(TupleTableSlot *slot, ! HeapTuple tuple, ! EState *estate, ! bool idSetToDefault); static void ExecProcessReturning(ProjectionInfo *projectReturning, TupleTableSlot *tupleSlot, TupleTableSlot *planSlot, *************** ExecutorRun(QueryDesc *queryDesc, *** 245,251 **** operation, count, direction, ! dest); /* * shutdown tuple receiver, if we started it --- 255,262 ---- operation, count, direction, ! dest, ! queryDesc->idSetToDefault); /* * shutdown tuple receiver, if we started it *************** ExecutePlan(EState *estate, *** 1051,1057 **** CmdType operation, long numberTuples, ScanDirection direction, ! DestReceiver *dest) { JunkFilter *junkfilter; TupleTableSlot *planSlot; --- 1062,1069 ---- CmdType operation, long numberTuples, ScanDirection direction, ! DestReceiver *dest, ! bool idSetToDefault) { JunkFilter *junkfilter; TupleTableSlot *planSlot; *************** lnext: ; *** 1260,1266 **** break; case CMD_INSERT: ! ExecInsert(slot, tupleid, planSlot, dest, estate); result = NULL; break; --- 1272,1278 ---- break; case CMD_INSERT: ! ExecInsert(slot, tupleid, planSlot, dest, estate, idSetToDefault); result = NULL; break; *************** lnext: ; *** 1270,1276 **** break; case CMD_UPDATE: ! ExecUpdate(slot, tupleid, planSlot, dest, estate); result = NULL; break; --- 1282,1288 ---- break; case CMD_UPDATE: ! ExecUpdate(slot, tupleid, planSlot, dest, estate, idSetToDefault); result = NULL; break; *************** ExecInsert(TupleTableSlot *slot, *** 1347,1353 **** ItemPointer tupleid, TupleTableSlot *planSlot, DestReceiver *dest, ! EState *estate) { HeapTuple tuple; ResultRelInfo *resultRelInfo; --- 1359,1366 ---- ItemPointer tupleid, TupleTableSlot *planSlot, DestReceiver *dest, ! EState *estate, ! bool idSetToDefault) { HeapTuple tuple; ResultRelInfo *resultRelInfo; *************** ExecInsert(TupleTableSlot *slot, *** 1396,1405 **** } /* ! * Check the constraints of the tuple */ if (resultRelationDesc->rd_att->constr) ! ExecConstraints(resultRelInfo, slot, estate); /* * insert the tuple --- 1409,1420 ---- } /* ! * Check the constraints of the tuple, skipping IDENTITY/GENERATED columns */ if (resultRelationDesc->rd_att->constr) ! ExecConstraints(resultRelInfo, slot, estate, false, false); ! ! tuple = ExecGenerated(slot, tuple, estate, idSetToDefault); /* * insert the tuple *************** ExecUpdate(TupleTableSlot *slot, *** 1579,1585 **** ItemPointer tupleid, TupleTableSlot *planSlot, DestReceiver *dest, ! EState *estate) { HeapTuple tuple; ResultRelInfo *resultRelInfo; --- 1594,1601 ---- ItemPointer tupleid, TupleTableSlot *planSlot, DestReceiver *dest, ! EState *estate, ! bool idSetToDefault) { HeapTuple tuple; ResultRelInfo *resultRelInfo; *************** ExecUpdate(TupleTableSlot *slot, *** 1648,1654 **** */ lreplace:; if (resultRelationDesc->rd_att->constr) ! ExecConstraints(resultRelInfo, slot, estate); /* * replace the heap tuple --- 1664,1672 ---- */ lreplace:; if (resultRelationDesc->rd_att->constr) ! ExecConstraints(resultRelInfo, slot, estate, false, false); ! ! tuple = ExecGenerated(slot, tuple, estate, idSetToDefault); /* * replace the heap tuple *************** ExecRelCheck(ResultRelInfo *resultRelInf *** 1795,1801 **** void ExecConstraints(ResultRelInfo *resultRelInfo, ! TupleTableSlot *slot, EState *estate) { Relation rel = resultRelInfo->ri_RelationDesc; TupleConstr *constr = rel->rd_att->constr; --- 1813,1820 ---- void ExecConstraints(ResultRelInfo *resultRelInfo, ! TupleTableSlot *slot, EState *estate, ! bool process_identity, bool process_generated) { Relation rel = resultRelInfo->ri_RelationDesc; TupleConstr *constr = rel->rd_att->constr; *************** ExecConstraints(ResultRelInfo *resultRel *** 1810,1815 **** --- 1829,1842 ---- for (attrChk = 1; attrChk <= natts; attrChk++) { if (rel->rd_att->attrs[attrChk - 1]->attnotnull && + ((!process_identity && !process_generated && + !rel->rd_att->attrs[attrChk - 1]->attidentity && + !rel->rd_att->attrs[attrChk - 1]->attforceddef) || + ( process_identity && + rel->rd_att->attrs[attrChk - 1]->attidentity) || + ( process_generated && + rel->rd_att->attrs[attrChk - 1]->attforceddef && + !rel->rd_att->attrs[attrChk - 1]->attidentity)) && slot_attisnull(slot, attrChk)) ereport(ERROR, (errcode(ERRCODE_NOT_NULL_VIOLATION), *************** ExecConstraints(ResultRelInfo *resultRel *** 1818,1824 **** } } ! if (constr->num_check > 0) { const char *failed; --- 1845,1852 ---- } } ! if (constr->num_check > 0 && ! !process_identity && !process_generated) { const char *failed; *************** ExecConstraints(ResultRelInfo *resultRel *** 1831,1836 **** --- 1859,2007 ---- } /* + * ExecGenerated --- evaluate IDENTITY/GENERATED columns + */ + static HeapTuple + ExecGenerated(TupleTableSlot *slot, + HeapTuple tuple, + EState *estate, + bool idSetToDefault) + { + ResultRelInfo *resultRelInfo; + Relation resultRelationDesc; + TupleDesc tupleDesc; + int attnum; + bool saw_generated; + int identity_attnum; + + resultRelInfo = estate->es_result_relation_info; + resultRelationDesc = resultRelInfo->ri_RelationDesc; + + saw_generated = false; + identity_attnum = 0; + tupleDesc = resultRelationDesc->rd_att; + for (attnum = 1; attnum <= tupleDesc->natts; attnum++) + { + if (tupleDesc->attrs[attnum - 1]->attisdropped) + continue; + if (tupleDesc->attrs[attnum - 1]->attidentity) + identity_attnum = attnum; + else if (tupleDesc->attrs[attnum - 1]->attforceddef) + saw_generated = true; + } + + if (saw_generated || identity_attnum > 0) + { + ExprContext *econtext; + ExprState *exprstate; + Datum values[tupleDesc->natts]; + bool isnull[tupleDesc->natts]; + bool replace[tupleDesc->natts]; + + econtext = GetPerTupleExprContext(estate); + econtext->ecxt_scantuple = slot; + + if (saw_generated) + { + heap_deform_tuple(tuple, tupleDesc, values, isnull); + memset(replace, 0, sizeof(replace)); + + for (attnum = 1; attnum <= tupleDesc->natts; attnum++) + { + Form_pg_attribute att_tup = tupleDesc->attrs[attnum - 1]; + + if (att_tup->attisdropped || att_tup->attidentity) + continue; + if (att_tup->attforceddef) + { + Expr *expr; + Datum const_val; + bool const_is_null; + int16 resultTypLen; + bool resultTypByVal; + + expr = (Expr *) + build_column_default(resultRelationDesc, + attnum); + exprstate = ExecPrepareExpr(expr, estate); + const_val = ExecEvalExprSwitchContext(exprstate, + econtext, + &const_is_null, + NULL); + get_typlenbyval(att_tup->atttypid, + &resultTypLen, + &resultTypByVal); + if (!const_is_null) + const_val = datumCopy(const_val, + resultTypByVal, + resultTypLen); + values[attnum - 1] = const_val; + isnull[attnum - 1] = const_is_null; + replace[attnum - 1] = true; + } + } + + tuple = heap_modify_tuple(tuple, tupleDesc, + values, + isnull, + replace); + + slot = ExecStoreTuple(tuple, slot, InvalidBuffer, false); + + if (resultRelationDesc->rd_att->constr) + ExecConstraints(resultRelInfo, slot, estate, false, true); + } + + if (identity_attnum > 0) + { + Form_pg_attribute att_tup = tupleDesc->attrs[identity_attnum - 1]; + + if (idSetToDefault) + { + Expr *expr; + Datum const_val; + bool const_is_null; + int16 resultTypLen; + bool resultTypByVal; + + heap_deform_tuple(tuple, tupleDesc, values, isnull); + memset(replace, 0, sizeof(replace)); + + expr = (Expr *) + build_column_default(resultRelationDesc, + identity_attnum); + exprstate = ExecPrepareExpr(expr, estate); + const_val = ExecEvalExprSwitchContext(exprstate, + econtext, + &const_is_null, + NULL); + get_typlenbyval(att_tup->atttypid, + &resultTypLen, + &resultTypByVal); + if (!const_is_null) + const_val = datumCopy(const_val, + resultTypByVal, + resultTypLen); + values[identity_attnum - 1] = const_val; + isnull[identity_attnum - 1] = const_is_null; + replace[identity_attnum - 1] = true; + + tuple = heap_modify_tuple(tuple, tupleDesc, + values, + isnull, + replace); + + slot = ExecStoreTuple(tuple, slot, InvalidBuffer, false); + } + + if (resultRelationDesc->rd_att->constr) + ExecConstraints(resultRelInfo, slot, estate, true, false); + } + } + return tuple; + } + + /* * ExecProcessReturning --- evaluate a RETURNING list and send to dest * * projectReturning: RETURNING projection info for current result rel diff -dcrpN pgsql.orig/src/backend/nodes/copyfuncs.c pgsql/src/backend/nodes/copyfuncs.c *** pgsql.orig/src/backend/nodes/copyfuncs.c 2007-02-27 08:27:36.000000000 +0100 --- pgsql/src/backend/nodes/copyfuncs.c 2007-02-28 08:48:35.000000000 +0100 *************** _copyPlannedStmt(PlannedStmt *from) *** 83,88 **** --- 83,89 ---- COPY_NODE_FIELD(returningLists); COPY_NODE_FIELD(rowMarks); COPY_SCALAR_FIELD(nParamExec); + COPY_SCALAR_FIELD(idSetToDefault); return newnode; } *************** _copyColumnDef(ColumnDef *from) *** 1735,1740 **** --- 1736,1743 ---- COPY_NODE_FIELD(raw_default); COPY_STRING_FIELD(cooked_default); COPY_NODE_FIELD(constraints); + COPY_SCALAR_FIELD(is_identity); + COPY_SCALAR_FIELD(force_default); return newnode; } *************** _copyConstraint(Constraint *from) *** 1751,1756 **** --- 1754,1761 ---- COPY_NODE_FIELD(keys); COPY_NODE_FIELD(options); COPY_STRING_FIELD(indexspace); + COPY_SCALAR_FIELD(force_default); + COPY_NODE_FIELD(seq_opts); return newnode; } *************** _copyQuery(Query *from) *** 1815,1820 **** --- 1820,1827 ---- COPY_NODE_FIELD(limitCount); COPY_NODE_FIELD(rowMarks); COPY_NODE_FIELD(setOperations); + COPY_SCALAR_FIELD(commandOverride); + COPY_SCALAR_FIELD(idSetToDefault); return newnode; } *************** _copyInsertStmt(InsertStmt *from) *** 1828,1833 **** --- 1835,1841 ---- COPY_NODE_FIELD(cols); COPY_NODE_FIELD(selectStmt); COPY_NODE_FIELD(returningList); + COPY_SCALAR_FIELD(commandOverride); return newnode; } *************** _copyAlterTableCmd(AlterTableCmd *from) *** 1921,1926 **** --- 1929,1935 ---- COPY_NODE_FIELD(def); COPY_NODE_FIELD(transform); COPY_SCALAR_FIELD(behavior); + COPY_SCALAR_FIELD(force_default); return newnode; } diff -dcrpN pgsql.orig/src/backend/nodes/equalfuncs.c pgsql/src/backend/nodes/equalfuncs.c *** pgsql.orig/src/backend/nodes/equalfuncs.c 2007-02-25 16:14:18.000000000 +0100 --- pgsql/src/backend/nodes/equalfuncs.c 2007-02-28 08:48:35.000000000 +0100 *************** _equalQuery(Query *a, Query *b) *** 715,720 **** --- 715,722 ---- COMPARE_NODE_FIELD(limitCount); COMPARE_NODE_FIELD(rowMarks); COMPARE_NODE_FIELD(setOperations); + COMPARE_SCALAR_FIELD(commandOverride); + COMPARE_SCALAR_FIELD(idSetToDefault); return true; } *************** _equalInsertStmt(InsertStmt *a, InsertSt *** 726,731 **** --- 728,734 ---- COMPARE_NODE_FIELD(cols); COMPARE_NODE_FIELD(selectStmt); COMPARE_NODE_FIELD(returningList); + COMPARE_SCALAR_FIELD(commandOverride); return true; } *************** _equalAlterTableCmd(AlterTableCmd *a, Al *** 807,812 **** --- 810,816 ---- COMPARE_NODE_FIELD(def); COMPARE_NODE_FIELD(transform); COMPARE_SCALAR_FIELD(behavior); + COMPARE_SCALAR_FIELD(force_default); return true; } *************** _equalColumnDef(ColumnDef *a, ColumnDef *** 1736,1741 **** --- 1740,1747 ---- COMPARE_NODE_FIELD(raw_default); COMPARE_STRING_FIELD(cooked_default); COMPARE_NODE_FIELD(constraints); + COMPARE_SCALAR_FIELD(is_identity); + COMPARE_SCALAR_FIELD(force_default); return true; } *************** _equalConstraint(Constraint *a, Constrai *** 1750,1755 **** --- 1756,1763 ---- COMPARE_NODE_FIELD(keys); COMPARE_NODE_FIELD(options); COMPARE_STRING_FIELD(indexspace); + COMPARE_SCALAR_FIELD(force_default); + COMPARE_NODE_FIELD(seq_opts); return true; } diff -dcrpN pgsql.orig/src/backend/nodes/outfuncs.c pgsql/src/backend/nodes/outfuncs.c *** pgsql.orig/src/backend/nodes/outfuncs.c 2007-02-27 08:27:36.000000000 +0100 --- pgsql/src/backend/nodes/outfuncs.c 2007-02-28 08:48:35.000000000 +0100 *************** _outPlannedStmt(StringInfo str, PlannedS *** 250,255 **** --- 250,256 ---- WRITE_NODE_FIELD(returningLists); WRITE_NODE_FIELD(rowMarks); WRITE_INT_FIELD(nParamExec); + WRITE_BOOL_FIELD(idSetToDefault); } /* *************** _outColumnDef(StringInfo str, ColumnDef *** 1607,1612 **** --- 1608,1615 ---- WRITE_NODE_FIELD(raw_default); WRITE_STRING_FIELD(cooked_default); WRITE_NODE_FIELD(constraints); + WRITE_BOOL_FIELD(is_identity); + WRITE_BOOL_FIELD(force_default); } static void *************** _outQuery(StringInfo str, Query *node) *** 1696,1701 **** --- 1699,1706 ---- WRITE_NODE_FIELD(limitCount); WRITE_NODE_FIELD(rowMarks); WRITE_NODE_FIELD(setOperations); + WRITE_BOOL_FIELD(commandOverride); + WRITE_BOOL_FIELD(idSetToDefault); } static void *************** _outConstraint(StringInfo str, Constrain *** 1960,1971 **** --- 1965,1982 ---- appendStringInfo(str, "DEFAULT"); WRITE_NODE_FIELD(raw_expr); WRITE_STRING_FIELD(cooked_expr); + WRITE_BOOL_FIELD(force_default); break; case CONSTR_NOTNULL: appendStringInfo(str, "NOT_NULL"); break; + case CONSTR_IDENTITY: + appendStringInfo(str, "IDENTITY"); + WRITE_NODE_FIELD(seq_opts); + break; + default: appendStringInfo(str, ""); break; diff -dcrpN pgsql.orig/src/backend/nodes/readfuncs.c pgsql/src/backend/nodes/readfuncs.c *** pgsql.orig/src/backend/nodes/readfuncs.c 2007-02-25 16:14:18.000000000 +0100 --- pgsql/src/backend/nodes/readfuncs.c 2007-02-28 08:48:35.000000000 +0100 *************** _readQuery(void) *** 154,159 **** --- 154,161 ---- READ_NODE_FIELD(limitCount); READ_NODE_FIELD(rowMarks); READ_NODE_FIELD(setOperations); + READ_BOOL_FIELD(commandOverride); + READ_BOOL_FIELD(idSetToDefault); READ_DONE(); } diff -dcrpN pgsql.orig/src/backend/optimizer/plan/planner.c pgsql/src/backend/optimizer/plan/planner.c *** pgsql.orig/src/backend/optimizer/plan/planner.c 2007-02-27 08:27:37.000000000 +0100 --- pgsql/src/backend/optimizer/plan/planner.c 2007-02-28 08:48:35.000000000 +0100 *************** planner(Query *parse, bool isCursor, int *** 163,168 **** --- 163,169 ---- result->returningLists = root->returningLists; result->rowMarks = parse->rowMarks; result->nParamExec = list_length(glob->paramlist); + result->idSetToDefault = parse->idSetToDefault; return result; } diff -dcrpN pgsql.orig/src/backend/parser/analyze.c pgsql/src/backend/parser/analyze.c *** pgsql.orig/src/backend/parser/analyze.c 2007-02-25 16:14:24.000000000 +0100 --- pgsql/src/backend/parser/analyze.c 2007-02-28 08:48:35.000000000 +0100 *************** transformInsertStmt(ParseState *pstate, *** 548,553 **** --- 548,554 ---- ListCell *lc; qry->commandType = CMD_INSERT; + qry->commandOverride = stmt->commandOverride; pstate->p_is_insert = true; /* *************** transformColumnDefinition(ParseState *ps *** 1035,1040 **** --- 1036,1044 ---- bool saw_nullable; Constraint *constraint; ListCell *clist; + bool saw_identity; + bool force_default; + List *seq_opts; cxt->columns = lappend(cxt->columns, column); *************** transformColumnDefinition(ParseState *ps *** 1060,1070 **** } } /* Do necessary work on the column type declaration */ transformColumnType(pstate, column); ! /* Special actions for SERIAL pseudo-types */ ! if (is_serial) { Oid snamespaceid; char *snamespace; --- 1064,1098 ---- } } + /* Check for GENERATED ... AS IDENTITY constructs */ + saw_identity = false; + force_default = false; + seq_opts = NULL; + foreach(clist, column->constraints) + { + constraint = lfirst(clist); + + switch (constraint->contype) { + case CONSTR_IDENTITY: + if (saw_identity) + ereport(ERROR, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("multiple GENERATED ... AS IDENTITY constructs specified for column \"%s\" of table \"%s\"", + column->colname, cxt->relation->relname))); + saw_identity = true; + force_default = constraint->force_default; + seq_opts = constraint->seq_opts; + break; + default: + continue; + } + } + /* Do necessary work on the column type declaration */ transformColumnType(pstate, column); ! /* Special actions for SERIAL pseudo-types or IDENTITY columns */ ! if (is_serial || saw_identity) { Oid snamespaceid; char *snamespace; *************** transformColumnDefinition(ParseState *ps *** 1106,1112 **** */ seqstmt = makeNode(CreateSeqStmt); seqstmt->sequence = makeRangeVar(snamespace, sname); ! seqstmt->options = NIL; cxt->blist = lappend(cxt->blist, seqstmt); --- 1134,1140 ---- */ seqstmt = makeNode(CreateSeqStmt); seqstmt->sequence = makeRangeVar(snamespace, sname); ! seqstmt->options = seq_opts; cxt->blist = lappend(cxt->blist, seqstmt); *************** transformColumnDefinition(ParseState *ps *** 1152,1157 **** --- 1180,1186 ---- constraint->raw_expr = (Node *) funccallnode; constraint->cooked_expr = NULL; constraint->keys = NIL; + constraint->force_default = force_default; column->constraints = lappend(column->constraints, constraint); constraint = makeNode(Constraint); *************** transformColumnDefinition(ParseState *ps *** 1213,1221 **** --- 1242,1254 ---- errmsg("multiple default values specified for column \"%s\" of table \"%s\"", column->colname, cxt->relation->relname))); column->raw_default = constraint->raw_expr; + force_default = constraint->force_default; Assert(constraint->cooked_expr == NULL); break; + case CONSTR_IDENTITY: /* This was processed above, we only have to detect it here. */ + break; + case CONSTR_PRIMARY: case CONSTR_UNIQUE: if (constraint->keys == NIL) *************** transformColumnDefinition(ParseState *ps *** 1240,1245 **** --- 1273,1280 ---- break; } } + column->is_identity = saw_identity; + column->force_default = force_default; } static void *************** transformInhRelation(ParseState *pstate, *** 1383,1388 **** --- 1418,1425 ---- def->raw_default = NULL; def->cooked_default = NULL; def->constraints = NIL; + def->is_identity = false; + def->force_default = false; /* * Add to column list *************** transformInhRelation(ParseState *pstate, *** 1417,1422 **** --- 1454,1461 ---- */ def->cooked_default = pstrdup(this_default); + def->is_identity = attribute->attidentity; + def->force_default = attribute->attforceddef; } } diff -dcrpN pgsql.orig/src/backend/parser/gram.y pgsql/src/backend/parser/gram.y *** pgsql.orig/src/backend/parser/gram.y 2007-02-25 16:14:26.000000000 +0100 --- pgsql/src/backend/parser/gram.y 2007-02-28 10:38:05.000000000 +0100 *************** static Node *makeXmlExpr(XmlExprOp op, c *** 285,291 **** %type fetch_direction select_limit_value select_offset_value ! %type OptSeqList %type OptSeqElem %type insert_rest --- 285,291 ---- %type fetch_direction select_limit_value select_offset_value ! %type OptSeqList SeqList %type OptSeqElem %type insert_rest *************** static Node *makeXmlExpr(XmlExprOp op, c *** 313,318 **** --- 313,319 ---- %type relation_expr %type relation_expr_opt_alias %type target_el single_set_clause set_target insert_column_item + %type OptOverride UserSystem %type Typename SimpleTypename ConstTypename GenericType Numeric opt_float *************** static Node *makeXmlExpr(XmlExprOp op, c *** 340,345 **** --- 341,348 ---- %type TableLikeOption %type ColQualList %type ColConstraint ColConstraintElem ConstraintAttr + %type AlwaysByDefault IdentityGenerated IdentitySpec + %type SetIdentityAlwaysByDefault %type key_actions key_delete key_match key_update key_action %type ConstraintAttributeSpec ConstraintDeferrabilitySpec ConstraintTimeSpec *************** static Node *makeXmlExpr(XmlExprOp op, c *** 365,371 **** /* ordinary key words in alphabetical order */ %token ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER ! AGGREGATE ALL ALSO ALTER ANALYSE ANALYZE AND ANY ARRAY AS ASC ASSERTION ASSIGNMENT ASYMMETRIC AT AUTHORIZATION BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT --- 368,374 ---- /* ordinary key words in alphabetical order */ %token ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER ! AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC ASSERTION ASSIGNMENT ASYMMETRIC AT AUTHORIZATION BACKWARD BEFORE BEGIN_P BETWEEN BIGINT BINARY BIT *************** static Node *makeXmlExpr(XmlExprOp op, c *** 389,399 **** FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD FREEZE FROM FULL FUNCTION ! GLOBAL GRANT GRANTED GREATEST GROUP_P HANDLER HAVING HEADER_P HOLD HOUR_P ! IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION --- 392,402 ---- FALSE_P FAMILY FETCH FIRST_P FLOAT_P FOR FORCE FOREIGN FORWARD FREEZE FROM FULL FUNCTION ! GENERATED GLOBAL GRANT GRANTED GREATEST GROUP_P HANDLER HAVING HEADER_P HOLD HOUR_P ! IDENTITY IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION *************** static Node *makeXmlExpr(XmlExprOp op, c *** 413,419 **** NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NULLS_P NUMERIC OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR ! ORDER OUT_P OUTER_P OVERLAPS OVERLAY OWNED OWNER PARTIAL PASSWORD PLACING POSITION PRECISION PRESERVE PREPARE PREPARED PRIMARY --- 416,422 ---- NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NULLS_P NUMERIC OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR ! ORDER OUT_P OUTER_P OVERLAPS OVERLAY OVERRIDING OWNED OWNER PARTIAL PASSWORD PLACING POSITION PRECISION PRESERVE PREPARE PREPARED PRIMARY *************** alter_table_cmd: *** 1410,1415 **** --- 1413,1449 ---- n->def = (Node *) makeString($6); $$ = (Node *)n; } + | ALTER opt_column ColId SET SeqList + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_SetSeqOpts; + n->name = $3; + n->def = (Node *) $5; + $$ = (Node *)n; + } + | ALTER opt_column ColId RESTART opt_with NumericOnly + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_SetSeqOpts; + n->name = $3; + n->def = (Node *)list_make1(makeDefElem("restart", (Node *)$6)); + $$ = (Node *)n; + } + | ALTER opt_column ColId SET GENERATED SetIdentityAlwaysByDefault AS IDENTITY + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_SetIdentity; + n->name = $3; + n->force_default = $6; + $$ = (Node *)n; + } + | ALTER opt_column ColId DROP IDENTITY + { + AlterTableCmd *n = makeNode(AlterTableCmd); + n->subtype = AT_DropIdentity; + n->name = $3; + $$ = (Node *)n; + } /* ALTER TABLE DROP [COLUMN] [RESTRICT|CASCADE] */ | DROP opt_column ColId opt_drop_behavior { *************** alter_using: *** 1602,1607 **** --- 1636,1646 ---- | /* EMPTY */ { $$ = NULL; } ; + SetIdentityAlwaysByDefault: + ALWAYS { $$ = true; } + | BY DEFAULT { $$ = false; } + ; + /***************************************************************************** *************** ClosePortalStmt: *** 1635,1649 **** * *****************************************************************************/ ! CopyStmt: COPY opt_binary qualified_name opt_column_list opt_oids copy_from copy_file_name copy_delimiter opt_with copy_opt_list { CopyStmt *n = makeNode(CopyStmt); n->relation = $3; n->query = NULL; n->attlist = $4; ! n->is_from = $6; ! n->filename = $7; n->options = NIL; /* Concatenate user-supplied flags */ --- 1674,1689 ---- * *****************************************************************************/ ! CopyStmt: COPY opt_binary qualified_name opt_column_list opt_oids OptOverride copy_from copy_file_name copy_delimiter opt_with copy_opt_list { CopyStmt *n = makeNode(CopyStmt); n->relation = $3; n->query = NULL; n->attlist = $4; ! n->overriding = $6; ! n->is_from = $7; ! n->filename = $8; n->options = NIL; /* Concatenate user-supplied flags */ *************** CopyStmt: COPY opt_binary qualified_name *** 1651,1660 **** n->options = lappend(n->options, $2); if ($5) n->options = lappend(n->options, $5); ! if ($8) ! n->options = lappend(n->options, $8); ! if ($10) ! n->options = list_concat(n->options, $10); $$ = (Node *)n; } | COPY select_with_parens TO copy_file_name opt_with --- 1691,1700 ---- n->options = lappend(n->options, $2); if ($5) n->options = lappend(n->options, $5); ! if ($9) ! n->options = lappend(n->options, $9); ! if ($11) ! n->options = list_concat(n->options, $11); $$ = (Node *)n; } | COPY select_with_parens TO copy_file_name opt_with *************** columnDef: ColId Typename ColQualList *** 1856,1861 **** --- 1896,1903 ---- n->typename = $2; n->constraints = $3; n->is_local = true; + n->is_identity = false; + n->force_default = false; $$ = (Node *)n; } ; *************** ColConstraintElem: *** 1997,2002 **** --- 2039,2103 ---- n->initdeferred = FALSE; $$ = (Node *)n; } + | GENERATED AlwaysByDefault + { + $$ = $2; + } + ; + + AlwaysByDefault: + BY DEFAULT AS IDENTITY IdentitySpec { $$ = $5; } + | ALWAYS AS IdentityGenerated + { + Constraint *n = (Constraint *)$3; + n->force_default = true; + $$ = (Node *)n; + } + ; + + IdentityGenerated: + '(' a_expr ')' + { + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_DEFAULT; + n->name = NULL; + n->raw_expr = $2; + n->cooked_expr = NULL; + n->keys = NULL; + n->indexspace = NULL; + $$ = (Node *)n; + } + | IDENTITY IdentitySpec + { + $$ = $2; + } + ; + + IdentitySpec: + '(' SeqList ')' + { + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_IDENTITY; + n->name = NULL; + n->raw_expr = NULL; + n->cooked_expr = NULL; + n->keys = NULL; + n->indexspace = NULL; + n->seq_opts = $2; + $$ = (Node *)n; + } + | /* EMPTY */ + { + Constraint *n = makeNode(Constraint); + n->contype = CONSTR_IDENTITY; + n->name = NULL; + n->raw_expr = NULL; + n->cooked_expr = NULL; + n->keys = NULL; + n->indexspace = NULL; + n->seq_opts = NULL; + $$ = (Node *)n; + } ; /* *************** CreateAsElement: *** 2309,2314 **** --- 2410,2417 ---- n->raw_default = NULL; n->cooked_default = NULL; n->constraints = NIL; + n->is_identity = false; + n->force_default = false; $$ = (Node *)n; } ; *************** OptSeqList: OptSeqList OptSeqElem { *** 2347,2352 **** --- 2450,2460 ---- | /*EMPTY*/ { $$ = NIL; } ; + SeqList: SeqList OptSeqElem { $$ = lappend($1, $2); } + | OptSeqElem { $$ = list_make1($1); } + ; + + OptSeqElem: CACHE NumericOnly { $$ = makeDefElem("cache", (Node *)$2); *************** InsertStmt: *** 5527,5543 **** ; insert_rest: ! SelectStmt { $$ = makeNode(InsertStmt); $$->cols = NIL; ! $$->selectStmt = $1; } ! | '(' insert_column_list ')' SelectStmt { $$ = makeNode(InsertStmt); $$->cols = $2; ! $$->selectStmt = $4; } | DEFAULT VALUES { --- 5635,5653 ---- ; insert_rest: ! OptOverride SelectStmt { $$ = makeNode(InsertStmt); $$->cols = NIL; ! $$->commandOverride = $1; ! $$->selectStmt = $2; } ! | '(' insert_column_list ')' OptOverride SelectStmt { $$ = makeNode(InsertStmt); $$->cols = $2; ! $$->commandOverride = $4; ! $$->selectStmt = $5; } | DEFAULT VALUES { *************** set_target_list: *** 5710,5715 **** --- 5820,5841 ---- ; + OptOverride: + OVERRIDING UserSystem VALUE_P + { + $$ = $2; + } + | /* EMPTY */ + { + $$ = false; + } + ; + + UserSystem: + SYSTEM_P { $$ = true; } + | USER { $$ = false; } + ; + /***************************************************************************** * * QUERY: *************** unreserved_keyword: *** 8667,8672 **** --- 8793,8799 ---- | AGGREGATE | ALSO | ALTER + | ALWAYS | ASSERTION | ASSIGNMENT | AT *************** unreserved_keyword: *** 8731,8736 **** --- 8858,8864 ---- | FORCE | FORWARD | FUNCTION + | GENERATED | GLOBAL | GRANTED | HANDLER *************** unreserved_keyword: *** 8791,8796 **** --- 8919,8925 ---- | OIDS | OPERATOR | OPTION + | OVERRIDING | OWNED | OWNER | PARTIAL *************** reserved_keyword: *** 9016,9021 **** --- 9145,9151 ---- | GRANT | GROUP_P | HAVING + | IDENTITY | IN_P | INITIALLY | INTERSECT diff -dcrpN pgsql.orig/src/backend/parser/keywords.c pgsql/src/backend/parser/keywords.c *** pgsql.orig/src/backend/parser/keywords.c 2007-01-26 18:53:03.000000000 +0100 --- pgsql/src/backend/parser/keywords.c 2007-02-28 08:48:35.000000000 +0100 *************** static const ScanKeyword ScanKeywords[] *** 42,47 **** --- 42,48 ---- {"all", ALL}, {"also", ALSO}, {"alter", ALTER}, + {"always", ALWAYS}, {"analyse", ANALYSE}, /* British spelling */ {"analyze", ANALYZE}, {"and", AND}, *************** static const ScanKeyword ScanKeywords[] *** 157,162 **** --- 158,164 ---- {"from", FROM}, {"full", FULL}, {"function", FUNCTION}, + {"generated", GENERATED}, {"global", GLOBAL}, {"grant", GRANT}, {"granted", GRANTED}, *************** static const ScanKeyword ScanKeywords[] *** 167,172 **** --- 169,175 ---- {"header", HEADER_P}, {"hold", HOLD}, {"hour", HOUR_P}, + {"identity", IDENTITY}, {"if", IF_P}, {"ilike", ILIKE}, {"immediate", IMMEDIATE}, *************** static const ScanKeyword ScanKeywords[] *** 262,267 **** --- 265,271 ---- {"outer", OUTER_P}, {"overlaps", OVERLAPS}, {"overlay", OVERLAY}, + {"overriding", OVERRIDING}, {"owned", OWNED}, {"owner", OWNER}, {"partial", PARTIAL}, diff -dcrpN pgsql.orig/src/backend/rewrite/rewriteHandler.c pgsql/src/backend/rewrite/rewriteHandler.c *** pgsql.orig/src/backend/rewrite/rewriteHandler.c 2007-02-09 07:23:34.000000000 +0100 --- pgsql/src/backend/rewrite/rewriteHandler.c 2007-02-28 08:48:35.000000000 +0100 *************** *** 13,18 **** --- 13,19 ---- */ #include "postgres.h" + #include "miscadmin.h" #include "access/heapam.h" #include "catalog/pg_type.h" #include "nodes/makefuncs.h" *************** *** 23,28 **** --- 24,30 ---- #include "parser/parsetree.h" #include "rewrite/rewriteHandler.h" #include "rewrite/rewriteManip.h" + #include "utils/acl.h" #include "utils/builtins.h" #include "utils/lsyscache.h" *************** rewriteTargetList(Query *parsetree, Rela *** 534,539 **** --- 536,542 ---- List **attrno_list) { CmdType commandType = parsetree->commandType; + bool commandOverride = parsetree->commandOverride; TargetEntry **new_tles; List *new_tlist = NIL; List *junk_tlist = NIL; *************** rewriteTargetList(Query *parsetree, Rela *** 543,548 **** --- 546,553 ---- numattrs; ListCell *temp; + parsetree->idSetToDefault = false; + if (attrno_list) /* initialize optional result list */ *attrno_list = NIL; *************** rewriteTargetList(Query *parsetree, Rela *** 618,632 **** continue; /* ! * Handle the two cases where we need to insert a default expression: ! * it's an INSERT and there's no tlist entry for the column, or the ! * tlist entry is a DEFAULT placeholder node. */ ! if ((new_tle == NULL && commandType == CMD_INSERT) || (new_tle && new_tle->expr && IsA(new_tle->expr, SetToDefault))) { Node *new_expr; new_expr = build_column_default(target_relation, attrno); /* --- 623,681 ---- continue; /* ! * Handle the three cases where we need to insert a default expression: ! * - it's an INSERT and there's no tlist entry for the column, or ! * - it's an INSERT and the column is GENERATED ALWAYS ! * - the tlist entry is a DEFAULT placeholder node ! * Fail for UPDATE to non-default on GENERATED ALWAYS AS () columns. ! * Fail for UPDATE on GENERATED ALWAYS AS IDENTITY columns ! * Fail for INSERT into GENERATED ALWAYS column with OVERRIDING SYSTEM VALUE by a non-owner */ ! if (commandType == CMD_UPDATE && att_tup->atthasdef && att_tup->attforceddef && ! new_tle && new_tle->expr) ! { ! if (att_tup->attidentity) ! elog(ERROR, "UPDATE prohibited on GENERATED ALWAYS AS IDENTITY attributes"); ! else if (!IsA(new_tle->expr, SetToDefault)) ! elog(ERROR, "UPDATE to non-default value prohibited on GENERATED ALWAYS attributes"); ! } ! if (commandType == CMD_INSERT && att_tup->atthasdef && att_tup->attforceddef) ! { ! if (commandOverride && ! !pg_class_ownercheck(RelationGetRelid(target_relation), ! GetUserId())) ! aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, ! RelationGetRelationName(target_relation)); ! if (att_tup->attidentity) ! { ! parsetree->idSetToDefault = true; ! continue; ! } ! } ! if (((new_tle == NULL || (att_tup->atthasdef && att_tup->attforceddef && !commandOverride)) && commandType == CMD_INSERT) || (new_tle && new_tle->expr && IsA(new_tle->expr, SetToDefault))) { Node *new_expr; + /* + * We have to make note of an unassigned IDENTITY column here + * so we can distinguish unassigned and assigned state later. + */ + if (att_tup->attidentity) + { + if ((commandType == CMD_INSERT && new_tle == NULL) || + (new_tle && new_tle->expr && IsA(new_tle->expr, SetToDefault))) + { + parsetree->idSetToDefault = true; + continue; + } + } + /* + * Skip all GENERATED columns that were assigned with DEFAULT. + */ + if (att_tup->attforceddef && !att_tup->attidentity) + continue; + new_expr = build_column_default(target_relation, attrno); /* diff -dcrpN pgsql.orig/src/backend/tcop/pquery.c pgsql/src/backend/tcop/pquery.c *** pgsql.orig/src/backend/tcop/pquery.c 2007-02-25 16:14:28.000000000 +0100 --- pgsql/src/backend/tcop/pquery.c 2007-02-28 08:48:35.000000000 +0100 *************** CreateQueryDesc(PlannedStmt *plannedstmt *** 79,84 **** --- 79,85 ---- qd->tupDesc = NULL; qd->estate = NULL; qd->planstate = NULL; + qd->idSetToDefault = plannedstmt->idSetToDefault; return qd; } diff -dcrpN pgsql.orig/src/backend/utils/adt/acl.c pgsql/src/backend/utils/adt/acl.c *** pgsql.orig/src/backend/utils/adt/acl.c 2007-02-28 08:46:29.000000000 +0100 --- pgsql/src/backend/utils/adt/acl.c 2007-02-28 08:48:35.000000000 +0100 *************** aclmembers(const Acl *acl, Oid **roleids *** 1225,1230 **** --- 1225,1302 ---- } /* + * aclmemberspriv + * Find out all the roleids mentioned in an Acl + * if they have all or any of the privileges. + * Note that we do not distinguish grantors from grantees. + * + * *roleids is set to point to a palloc'd array containing distinct OIDs + * in sorted order. The length of the array is the function result. + */ + int + aclmemberspriv(const Acl *acl, Oid **roleids, AclMode privs, bool is_equal) + { + Oid *list; + const AclItem *acldat; + int i, + j, + k; + + if (acl == NULL || ACL_NUM(acl) == 0) + { + *roleids = NULL; + return 0; + } + + /* Check only PRIVILEGES, not GRANT options */ + privs &= 0xFFFF; + + check_acl(acl); + + /* Allocate the worst-case space requirement */ + list = palloc(ACL_NUM(acl) * 2 * sizeof(Oid)); + acldat = ACL_DAT(acl); + + /* + * Walk the ACL collecting mentioned RoleIds. + */ + j = 0; + for (i = 0; i < ACL_NUM(acl); i++) + { + const AclItem *ai = &acldat[i]; + + if ((is_equal && (ai->ai_privs & 0xFFFF) == privs) || + (!is_equal && (ai->ai_privs & privs))) + { + if (ai->ai_grantee != ACL_ID_PUBLIC) + list[j++] = ai->ai_grantee; + /* grantor is currently never PUBLIC, but let's check anyway */ + if (ai->ai_grantor != ACL_ID_PUBLIC) + list[j++] = ai->ai_grantor; + } + } + + /* Sort the array */ + qsort(list, j, sizeof(Oid), oidComparator); + + /* Remove duplicates from the array */ + k = 0; + for (i = 1; i < j; i++) + { + if (list[k] != list[i]) + list[++k] = list[i]; + } + + /* + * We could repalloc the array down to minimum size, but it's hardly worth + * it since it's only transient memory. + */ + *roleids = list; + + return k + 1; + } + + /* * oidComparator * qsort comparison function for Oids */ diff -dcrpN pgsql.orig/src/backend/utils/adt/ruleutils.c pgsql/src/backend/utils/adt/ruleutils.c *** pgsql.orig/src/backend/utils/adt/ruleutils.c 2007-02-28 08:46:33.000000000 +0100 --- pgsql/src/backend/utils/adt/ruleutils.c 2007-02-28 08:48:35.000000000 +0100 *************** pg_get_serial_sequence(PG_FUNCTION_ARGS) *** 1258,1268 **** Oid tableOid; char *column; AttrNumber attnum; ! Oid sequenceId = InvalidOid; ! Relation depRel; ! ScanKeyData key[3]; ! SysScanDesc scan; ! HeapTuple tup; /* Get the OID of the table */ tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename)); --- 1258,1264 ---- Oid tableOid; char *column; AttrNumber attnum; ! Oid sequenceId; /* Get the OID of the table */ tablerv = makeRangeVarFromNameList(textToQualifiedNameList(tablename)); *************** pg_get_serial_sequence(PG_FUNCTION_ARGS) *** 1279,1324 **** errmsg("column \"%s\" of relation \"%s\" does not exist", column, tablerv->relname))); ! /* Search the dependency table for the dependent sequence */ ! depRel = heap_open(DependRelationId, AccessShareLock); ! ! ScanKeyInit(&key[0], ! Anum_pg_depend_refclassid, ! BTEqualStrategyNumber, F_OIDEQ, ! ObjectIdGetDatum(RelationRelationId)); ! ScanKeyInit(&key[1], ! Anum_pg_depend_refobjid, ! BTEqualStrategyNumber, F_OIDEQ, ! ObjectIdGetDatum(tableOid)); ! ScanKeyInit(&key[2], ! Anum_pg_depend_refobjsubid, ! BTEqualStrategyNumber, F_INT4EQ, ! Int32GetDatum(attnum)); ! ! scan = systable_beginscan(depRel, DependReferenceIndexId, true, ! SnapshotNow, 3, key); ! ! while (HeapTupleIsValid(tup = systable_getnext(scan))) ! { ! Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup); ! ! /* ! * We assume any auto dependency of a sequence on a column must be ! * what we are looking for. (We need the relkind test because indexes ! * can also have auto dependencies on columns.) ! */ ! if (deprec->classid == RelationRelationId && ! deprec->objsubid == 0 && ! deprec->deptype == DEPENDENCY_AUTO && ! get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE) ! { ! sequenceId = deprec->objid; ! break; ! } ! } ! ! systable_endscan(scan); ! heap_close(depRel, AccessShareLock); if (OidIsValid(sequenceId)) { --- 1275,1281 ---- errmsg("column \"%s\" of relation \"%s\" does not exist", column, tablerv->relname))); ! sequenceId = get_relid_att_serial_sequence(tableOid, attnum); if (OidIsValid(sequenceId)) { diff -dcrpN pgsql.orig/src/backend/utils/cache/lsyscache.c pgsql/src/backend/utils/cache/lsyscache.c *** pgsql.orig/src/backend/utils/cache/lsyscache.c 2007-02-15 12:36:11.000000000 +0100 --- pgsql/src/backend/utils/cache/lsyscache.c 2007-02-28 08:48:35.000000000 +0100 *************** *** 15,25 **** --- 15,30 ---- */ #include "postgres.h" + #include "access/genam.h" #include "access/hash.h" + #include "access/heapam.h" #include "access/nbtree.h" #include "bootstrap/bootstrap.h" + #include "catalog/dependency.h" + #include "catalog/indexing.h" #include "catalog/pg_amop.h" #include "catalog/pg_amproc.h" + #include "catalog/pg_depend.h" #include "catalog/pg_constraint.h" #include "catalog/pg_namespace.h" #include "catalog/pg_opclass.h" *************** *** 32,37 **** --- 37,43 ---- #include "utils/array.h" #include "utils/builtins.h" #include "utils/datum.h" + #include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/syscache.h" *************** get_relid_attribute_name(Oid relid, Attr *** 786,791 **** --- 792,855 ---- } /* + * get_relid_attribute_sequence + * Expose pg_get_serial_sequence() internally. + * Assumes that attnum is valid for the table. + */ + Oid + get_relid_att_serial_sequence(Oid relid, AttrNumber attnum) + { + Oid sequenceId = InvalidOid; + Relation depRel; + ScanKeyData key[3]; + SysScanDesc scan; + HeapTuple tup; + + /* Search the dependency table for the dependent sequence */ + depRel = heap_open(DependRelationId, AccessShareLock); + + ScanKeyInit(&key[0], + Anum_pg_depend_refclassid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(RelationRelationId)); + ScanKeyInit(&key[1], + Anum_pg_depend_refobjid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(relid)); + ScanKeyInit(&key[2], + Anum_pg_depend_refobjsubid, + BTEqualStrategyNumber, F_INT4EQ, + Int32GetDatum(attnum)); + + scan = systable_beginscan(depRel, DependReferenceIndexId, true, + SnapshotNow, 3, key); + + while (HeapTupleIsValid(tup = systable_getnext(scan))) + { + Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup); + + /* + * We assume any auto dependency of a sequence on a column must be + * what we are looking for. (We need the relkind test because indexes + * can also have auto dependencies on columns.) + */ + if (deprec->classid == RelationRelationId && + deprec->objsubid == 0 && + deprec->deptype == DEPENDENCY_AUTO && + get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE) + { + sequenceId = deprec->objid; + break; + } + } + + systable_endscan(scan); + heap_close(depRel, AccessShareLock); + + return sequenceId; + } + + /* * get_attnum * * Given the relation id and the attribute name, diff -dcrpN pgsql.orig/src/backend/utils/cache/relcache.c pgsql/src/backend/utils/cache/relcache.c *** pgsql.orig/src/backend/utils/cache/relcache.c 2007-02-28 08:46:36.000000000 +0100 --- pgsql/src/backend/utils/cache/relcache.c 2007-02-28 08:48:35.000000000 +0100 *************** RelationBuildLocalRelation(const char *r *** 2273,2278 **** --- 2273,2285 ---- for (i = 0; i < natts; i++) { rel->rd_att->attrs[i]->attnotnull = tupDesc->attrs[i]->attnotnull; + /* + * Initialize these early so AddRelationRawConstraints() + * can detect the field properties correctly on just to be + * created tables. + */ + rel->rd_att->attrs[i]->attidentity = tupDesc->attrs[i]->attidentity; + rel->rd_att->attrs[i]->attforceddef = tupDesc->attrs[i]->attforceddef; has_not_null |= tupDesc->attrs[i]->attnotnull; } diff -dcrpN pgsql.orig/src/bin/pg_dump/pg_dump.c pgsql/src/bin/pg_dump/pg_dump.c *** pgsql.orig/src/bin/pg_dump/pg_dump.c 2007-02-15 12:36:14.000000000 +0100 --- pgsql/src/bin/pg_dump/pg_dump.c 2007-02-28 08:48:35.000000000 +0100 *************** dumpTableData_insert(Archive *fout, void *** 1196,1201 **** --- 1196,1203 ---- appendPQExpBuffer(q, ") "); archputs(q->data, fout); } + if (tbinfo->hasforceddef) + archprintf(fout, "OVERRIDING SYSTEM VALUE "); archprintf(fout, "VALUES ("); for (field = 0; field < nfields; field++) { *************** dumpTableData(Archive *fout, TableDataIn *** 1297,1304 **** /* must use 2 steps here 'cause fmtId is nonreentrant */ appendPQExpBuffer(copyBuf, "COPY %s ", fmtId(tbinfo->dobj.name)); ! appendPQExpBuffer(copyBuf, "%s %sFROM stdin;\n", fmtCopyColumnList(tbinfo), (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : ""); copyStmt = copyBuf->data; } --- 1299,1307 ---- /* must use 2 steps here 'cause fmtId is nonreentrant */ appendPQExpBuffer(copyBuf, "COPY %s ", fmtId(tbinfo->dobj.name)); ! appendPQExpBuffer(copyBuf, "%s %s%sFROM stdin;\n", fmtCopyColumnList(tbinfo), + tbinfo->hasforceddef ? "OVERRIDING SYSTEM VALUE " : "", (tdinfo->oids && tbinfo->hasoids) ? "WITH OIDS " : ""); copyStmt = copyBuf->data; } *************** getTableAttrs(TableInfo *tblinfo, int nu *** 4260,4265 **** --- 4263,4270 ---- int i_atthasdef; int i_attisdropped; int i_attislocal; + int i_attidentity; + int i_attforceddef; PGresult *res; int ntups; bool hasdefaults; *************** getTableAttrs(TableInfo *tblinfo, int nu *** 4297,4308 **** resetPQExpBuffer(q); ! if (g_fout->remoteVersion >= 70300) { /* need left join here to not fail on dropped columns ... */ appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, a.attstattarget, a.attstorage, t.typstorage, " "a.attnotnull, a.atthasdef, a.attisdropped, a.attislocal, " ! "pg_catalog.format_type(t.oid,a.atttypmod) as atttypname " "from pg_catalog.pg_attribute a left join pg_catalog.pg_type t " "on a.atttypid = t.oid " "where a.attrelid = '%u'::pg_catalog.oid " --- 4302,4328 ---- resetPQExpBuffer(q); ! if (g_fout->remoteVersion >= 80300) { /* need left join here to not fail on dropped columns ... */ appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, a.attstattarget, a.attstorage, t.typstorage, " "a.attnotnull, a.atthasdef, a.attisdropped, a.attislocal, " ! "pg_catalog.format_type(t.oid,a.atttypmod) as atttypname, " ! "a.attidentity, a.attforceddef " ! "from pg_catalog.pg_attribute a left join pg_catalog.pg_type t " ! "on a.atttypid = t.oid " ! "where a.attrelid = '%u'::pg_catalog.oid " ! "and a.attnum > 0::pg_catalog.int2 " ! "order by a.attrelid, a.attnum", ! tbinfo->dobj.catId.oid); ! } ! else if (g_fout->remoteVersion >= 70300) ! { ! /* need left join here to not fail on dropped columns ... */ ! appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, a.attstattarget, a.attstorage, t.typstorage, " ! "a.attnotnull, a.atthasdef, a.attisdropped, a.attislocal, " ! "pg_catalog.format_type(t.oid,a.atttypmod) as atttypname, " ! "false as attidentity, false as attforceddef " "from pg_catalog.pg_attribute a left join pg_catalog.pg_type t " "on a.atttypid = t.oid " "where a.attrelid = '%u'::pg_catalog.oid " *************** getTableAttrs(TableInfo *tblinfo, int nu *** 4319,4325 **** */ appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, -1 as attstattarget, a.attstorage, t.typstorage, " "a.attnotnull, a.atthasdef, false as attisdropped, false as attislocal, " ! "format_type(t.oid,a.atttypmod) as atttypname " "from pg_attribute a left join pg_type t " "on a.atttypid = t.oid " "where a.attrelid = '%u'::oid " --- 4339,4346 ---- */ appendPQExpBuffer(q, "SELECT a.attnum, a.attname, a.atttypmod, -1 as attstattarget, a.attstorage, t.typstorage, " "a.attnotnull, a.atthasdef, false as attisdropped, false as attislocal, " ! "format_type(t.oid,a.atttypmod) as atttypname, " ! "false as attidentity, false as attforceddef " "from pg_attribute a left join pg_type t " "on a.atttypid = t.oid " "where a.attrelid = '%u'::oid " *************** getTableAttrs(TableInfo *tblinfo, int nu *** 4332,4338 **** /* format_type not available before 7.1 */ appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, -1 as attstattarget, attstorage, attstorage as typstorage, " "attnotnull, atthasdef, false as attisdropped, false as attislocal, " ! "(select typname from pg_type where oid = atttypid) as atttypname " "from pg_attribute a " "where attrelid = '%u'::oid " "and attnum > 0::int2 " --- 4353,4360 ---- /* format_type not available before 7.1 */ appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, -1 as attstattarget, attstorage, attstorage as typstorage, " "attnotnull, atthasdef, false as attisdropped, false as attislocal, " ! "(select typname from pg_type where oid = atttypid) as atttypname, " ! "false as attidentity, false as attforceddef " "from pg_attribute a " "where attrelid = '%u'::oid " "and attnum > 0::int2 " *************** getTableAttrs(TableInfo *tblinfo, int nu *** 4356,4361 **** --- 4378,4385 ---- i_atthasdef = PQfnumber(res, "atthasdef"); i_attisdropped = PQfnumber(res, "attisdropped"); i_attislocal = PQfnumber(res, "attislocal"); + i_attidentity = PQfnumber(res, "attidentity"); + i_attforceddef = PQfnumber(res, "attforceddef"); tbinfo->numatts = ntups; tbinfo->attnames = (char **) malloc(ntups * sizeof(char *)); *************** getTableAttrs(TableInfo *tblinfo, int nu *** 4366,4371 **** --- 4390,4397 ---- tbinfo->typstorage = (char *) malloc(ntups * sizeof(char)); tbinfo->attisdropped = (bool *) malloc(ntups * sizeof(bool)); tbinfo->attislocal = (bool *) malloc(ntups * sizeof(bool)); + tbinfo->attidentity = (bool *) malloc(ntups * sizeof(bool)); + tbinfo->attforceddef = (bool *) malloc(ntups * sizeof(bool)); tbinfo->notnull = (bool *) malloc(ntups * sizeof(bool)); tbinfo->attrdefs = (AttrDefInfo **) malloc(ntups * sizeof(AttrDefInfo *)); tbinfo->inhAttrs = (bool *) malloc(ntups * sizeof(bool)); *************** getTableAttrs(TableInfo *tblinfo, int nu *** 4389,4394 **** --- 4415,4423 ---- tbinfo->typstorage[j] = *(PQgetvalue(res, j, i_typstorage)); tbinfo->attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't'); tbinfo->attislocal[j] = (PQgetvalue(res, j, i_attislocal)[0] == 't'); + tbinfo->attidentity[j] = (PQgetvalue(res, j, i_attidentity)[0] == 't'); + tbinfo->attforceddef[j] = (PQgetvalue(res, j, i_attforceddef)[0] == 't'); + tbinfo->hasforceddef |= tbinfo->attforceddef[j]; tbinfo->notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't'); tbinfo->attrdefs[j] = NULL; /* fix below */ if (PQgetvalue(res, j, i_atthasdef)[0] == 't') *************** dumpTableSchema(Archive *fout, TableInfo *** 7872,7879 **** /* * Default value --- suppress if inherited or to be printed * separately. */ ! if (tbinfo->attrdefs[j] != NULL && !tbinfo->inhAttrDef[j] && !tbinfo->attrdefs[j]->separate) appendPQExpBuffer(q, " DEFAULT %s", --- 7901,7917 ---- /* * Default value --- suppress if inherited or to be printed * separately. + * A GENERATED column cannot be built from building block + * such as a SERIAL or IDENTITY column, only ADDed or DROPped. + * Hence emit the GENERATED property in the schema itself. */ ! if (tbinfo->attforceddef[j] && ! !tbinfo->attidentity[j]) ! { ! appendPQExpBuffer(q, " GENERATED ALWAYS AS ( %s )", ! tbinfo->attrdefs[j]->adef_expr); ! } ! else if (tbinfo->attrdefs[j] != NULL && !tbinfo->inhAttrDef[j] && !tbinfo->attrdefs[j]->separate) appendPQExpBuffer(q, " DEFAULT %s", *************** dumpAttrDef(Archive *fout, AttrDefInfo * *** 8044,8055 **** q = createPQExpBuffer(); delq = createPQExpBuffer(); ! appendPQExpBuffer(q, "ALTER TABLE %s ", fmtId(tbinfo->dobj.name)); ! appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n", fmtId(tbinfo->attnames[adnum - 1]), adinfo->adef_expr); /* * DROP must be fully qualified in case same name appears in pg_catalog */ --- 8082,8108 ---- q = createPQExpBuffer(); delq = createPQExpBuffer(); ! if (tbinfo->attidentity[adnum - 1] || ! !tbinfo->attforceddef[adnum - 1]) ! { ! appendPQExpBuffer(q, "ALTER TABLE %s ", fmtId(tbinfo->dobj.name)); ! appendPQExpBuffer(q, "ALTER COLUMN %s SET DEFAULT %s;\n", fmtId(tbinfo->attnames[adnum - 1]), adinfo->adef_expr); + if (tbinfo->attidentity[adnum - 1]) + { + appendPQExpBuffer(q, "ALTER TABLE %s", + fmtId(tbinfo->dobj.name)); + appendPQExpBuffer(q, " ALTER %s", + fmtId(tbinfo->attnames[adnum - 1])); + appendPQExpBuffer(q, " SET GENERATED %s AS IDENTITY;\n", + tbinfo->attforceddef[adnum - 1] ? + "ALWAYS" : "BY DEFAULT"); + } + } + /* * DROP must be fully qualified in case same name appears in pg_catalog */ diff -dcrpN pgsql.orig/src/bin/pg_dump/pg_dump.h pgsql/src/bin/pg_dump/pg_dump.h *** pgsql.orig/src/bin/pg_dump/pg_dump.h 2007-02-20 14:59:53.000000000 +0100 --- pgsql/src/bin/pg_dump/pg_dump.h 2007-02-28 08:48:35.000000000 +0100 *************** typedef struct _tableInfo *** 258,263 **** --- 258,266 ---- char *typstorage; /* type storage scheme */ bool *attisdropped; /* true if attr is dropped; don't dump it */ bool *attislocal; /* true if attr has local definition */ + bool *attidentity; /* true if attr is GENERATED AS IDENTITY */ + bool *attforceddef; /* true if attr is GENERATED ALWAYS */ + bool hasforceddef; /* true if any of the attrs is GENERATED ALWAYS */ /* * Note: we need to store per-attribute notnull, default, and constraint diff -dcrpN pgsql.orig/src/include/catalog/heap.h pgsql/src/include/catalog/heap.h *** pgsql.orig/src/include/catalog/heap.h 2007-01-10 19:59:08.000000000 +0100 --- pgsql/src/include/catalog/heap.h 2007-02-28 08:48:35.000000000 +0100 *************** typedef struct RawColumnDefault *** 21,26 **** --- 21,28 ---- { AttrNumber attnum; /* attribute to attach default to */ Node *raw_default; /* default value (untransformed parse tree) */ + bool is_identity; /* column is GENERATED AS IDENTITY */ + bool force_default; /* column is GENERATED ALWAYS */ } RawColumnDefault; typedef struct CookedConstraint *************** typedef struct CookedConstraint *** 29,34 **** --- 31,37 ---- char *name; /* name, or NULL if none */ AttrNumber attnum; /* which attr (only for DEFAULT) */ Node *expr; /* transformed default or check expr */ + bool force_default; /* GENERATED ALWAYS */ } CookedConstraint; extern Relation heap_create(const char *relname, *************** extern List *AddRelationRawConstraints(R *** 71,83 **** List *rawColDefaults, List *rawConstraints); ! extern void StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin); extern Node *cookDefault(ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, ! char *attname); extern int RemoveRelConstraints(Relation rel, const char *constrName, DropBehavior behavior); --- 74,87 ---- List *rawColDefaults, List *rawConstraints); ! extern void StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin, bool attidentity, bool attforceddef); extern Node *cookDefault(ParseState *pstate, Node *raw_default, Oid atttypid, int32 atttypmod, ! char *attname, ! bool force_default); extern int RemoveRelConstraints(Relation rel, const char *constrName, DropBehavior behavior); diff -dcrpN pgsql.orig/src/include/catalog/pg_attribute.h pgsql/src/include/catalog/pg_attribute.h *** pgsql.orig/src/include/catalog/pg_attribute.h 2007-01-26 18:53:15.000000000 +0100 --- pgsql/src/include/catalog/pg_attribute.h 2007-02-28 08:48:35.000000000 +0100 *************** CATALOG(pg_attribute,1249) BKI_BOOTSTRAP *** 149,154 **** --- 149,160 ---- /* Number of times inherited from direct parent relation(s) */ int4 attinhcount; + + /* GENERATED ... AS IDENTITY or SERIAL */ + bool attidentity; + + /* GENERATED ALWAYS */ + bool attforceddef; } FormData_pg_attribute; /* *************** CATALOG(pg_attribute,1249) BKI_BOOTSTRAP *** 157,163 **** * because of alignment padding at the end of the struct.) */ #define ATTRIBUTE_TUPLE_SIZE \ ! (offsetof(FormData_pg_attribute,attinhcount) + sizeof(int4)) /* ---------------- * Form_pg_attribute corresponds to a pointer to a tuple with --- 163,169 ---- * because of alignment padding at the end of the struct.) */ #define ATTRIBUTE_TUPLE_SIZE \ ! (offsetof(FormData_pg_attribute,attforceddef) + sizeof(bool)) /* ---------------- * Form_pg_attribute corresponds to a pointer to a tuple with *************** typedef FormData_pg_attribute *Form_pg_a *** 171,177 **** * ---------------- */ ! #define Natts_pg_attribute 17 #define Anum_pg_attribute_attrelid 1 #define Anum_pg_attribute_attname 2 #define Anum_pg_attribute_atttypid 3 --- 177,183 ---- * ---------------- */ ! #define Natts_pg_attribute 19 #define Anum_pg_attribute_attrelid 1 #define Anum_pg_attribute_attname 2 #define Anum_pg_attribute_atttypid 3 *************** typedef FormData_pg_attribute *Form_pg_a *** 189,194 **** --- 195,202 ---- #define Anum_pg_attribute_attisdropped 15 #define Anum_pg_attribute_attislocal 16 #define Anum_pg_attribute_attinhcount 17 + #define Anum_pg_attribute_attidentity 18 + #define Anum_pg_attribute_attforceddef 19 *************** typedef FormData_pg_attribute *Form_pg_a *** 222,455 **** * ---------------- */ #define Schema_pg_type \ ! { 1247, {"typname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ ! { 1247, {"typnamespace"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1247, {"typowner"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1247, {"typlen"}, 21, -1, 2, 4, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ ! { 1247, {"typbyval"}, 16, -1, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1247, {"typtype"}, 18, -1, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1247, {"typisdefined"}, 16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1247, {"typdelim"}, 18, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1247, {"typrelid"}, 26, -1, 4, 9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1247, {"typelem"}, 26, -1, 4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1247, {"typinput"}, 24, -1, 4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1247, {"typoutput"}, 24, -1, 4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1247, {"typreceive"}, 24, -1, 4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1247, {"typsend"}, 24, -1, 4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1247, {"typmodin"}, 24, -1, 4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1247, {"typmodout"}, 24, -1, 4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1247, {"typanalyze"}, 24, -1, 4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1247, {"typalign"}, 18, -1, 1, 18, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1247, {"typstorage"}, 18, -1, 1, 19, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1247, {"typnotnull"}, 16, -1, 1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1247, {"typbasetype"}, 26, -1, 4, 21, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1247, {"typtypmod"}, 23, -1, 4, 22, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1247, {"typndims"}, 23, -1, 4, 23, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1247, {"typdefaultbin"}, 25, -1, -1, 24, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ ! { 1247, {"typdefault"}, 25, -1, -1, 25, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 } ! DATA(insert ( 1247 typname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0)); ! DATA(insert ( 1247 typnamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 typowner 26 -1 4 3 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 typlen 21 -1 2 4 0 -1 -1 t p s t f f t 0)); ! DATA(insert ( 1247 typbyval 16 -1 1 5 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1247 typtype 18 -1 1 6 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1247 typisdefined 16 -1 1 7 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1247 typdelim 18 -1 1 8 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1247 typrelid 26 -1 4 9 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 typelem 26 -1 4 10 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 typinput 24 -1 4 11 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 typoutput 24 -1 4 12 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 typreceive 24 -1 4 13 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 typsend 24 -1 4 14 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 typmodin 24 -1 4 15 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 typmodout 24 -1 4 16 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 typanalyze 24 -1 4 17 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 typalign 18 -1 1 18 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1247 typstorage 18 -1 1 19 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1247 typnotnull 16 -1 1 20 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1247 typbasetype 26 -1 4 21 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 typtypmod 23 -1 4 22 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 typndims 23 -1 4 23 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 typdefaultbin 25 -1 -1 24 0 -1 -1 f x i f f f t 0)); ! DATA(insert ( 1247 typdefault 25 -1 -1 25 0 -1 -1 f x i f f f t 0)); ! DATA(insert ( 1247 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0)); ! DATA(insert ( 1247 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 cmin 29 0 4 -4 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1247 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); /* ---------------- * pg_proc * ---------------- */ #define Schema_pg_proc \ ! { 1255, {"proname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ ! { 1255, {"pronamespace"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1255, {"proowner"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1255, {"prolang"}, 26, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1255, {"procost"}, 700, -1, 4, 5, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ ! { 1255, {"prorows"}, 700, -1, 4, 6, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ ! { 1255, {"proisagg"}, 16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1255, {"prosecdef"}, 16, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1255, {"proisstrict"}, 16, -1, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1255, {"proretset"}, 16, -1, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1255, {"provolatile"}, 18, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1255, {"pronargs"}, 21, -1, 2, 12, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ ! { 1255, {"prorettype"}, 26, -1, 4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1255, {"proargtypes"}, 30, -1, -1, 14, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ ! { 1255, {"proallargtypes"}, 1028, -1, -1, 15, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ ! { 1255, {"proargmodes"}, 1002, -1, -1, 16, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ ! { 1255, {"proargnames"}, 1009, -1, -1, 17, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ ! { 1255, {"prosrc"}, 25, -1, -1, 18, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ ! { 1255, {"probin"}, 17, -1, -1, 19, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ ! { 1255, {"proacl"}, 1034, -1, -1, 20, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 } ! DATA(insert ( 1255 proname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0)); ! DATA(insert ( 1255 pronamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1255 proowner 26 -1 4 3 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1255 prolang 26 -1 4 4 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1255 procost 700 -1 4 5 0 -1 -1 f p i t f f t 0)); ! DATA(insert ( 1255 prorows 700 -1 4 6 0 -1 -1 f p i t f f t 0)); ! DATA(insert ( 1255 proisagg 16 -1 1 7 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1255 prosecdef 16 -1 1 8 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1255 proisstrict 16 -1 1 9 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1255 proretset 16 -1 1 10 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1255 provolatile 18 -1 1 11 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1255 pronargs 21 -1 2 12 0 -1 -1 t p s t f f t 0)); ! DATA(insert ( 1255 prorettype 26 -1 4 13 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1255 proargtypes 30 -1 -1 14 1 -1 -1 f p i t f f t 0)); ! DATA(insert ( 1255 proallargtypes 1028 -1 -1 15 1 -1 -1 f x i f f f t 0)); ! DATA(insert ( 1255 proargmodes 1002 -1 -1 16 1 -1 -1 f x i f f f t 0)); ! DATA(insert ( 1255 proargnames 1009 -1 -1 17 1 -1 -1 f x i f f f t 0)); ! DATA(insert ( 1255 prosrc 25 -1 -1 18 0 -1 -1 f x i f f f t 0)); ! DATA(insert ( 1255 probin 17 -1 -1 19 0 -1 -1 f x i f f f t 0)); ! DATA(insert ( 1255 proacl 1034 -1 -1 20 1 -1 -1 f x i f f f t 0)); ! DATA(insert ( 1255 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0)); ! DATA(insert ( 1255 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1255 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1255 cmin 29 0 4 -4 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1255 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1255 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1255 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); /* ---------------- * pg_attribute * ---------------- */ #define Schema_pg_attribute \ ! { 1249, {"attrelid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1249, {"attname"}, 19, -1, NAMEDATALEN, 2, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ ! { 1249, {"atttypid"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1249, {"attstattarget"}, 23, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1249, {"attlen"}, 21, -1, 2, 5, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ ! { 1249, {"attnum"}, 21, -1, 2, 6, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ ! { 1249, {"attndims"}, 23, -1, 4, 7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1249, {"attcacheoff"}, 23, -1, 4, 8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1249, {"atttypmod"}, 23, -1, 4, 9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1249, {"attbyval"}, 16, -1, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1249, {"attstorage"}, 18, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1249, {"attalign"}, 18, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1249, {"attnotnull"}, 16, -1, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1249, {"atthasdef"}, 16, -1, 1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1249, {"attisdropped"}, 16, -1, 1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1249, {"attislocal"}, 16, -1, 1, 16, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1249, {"attinhcount"}, 23, -1, 4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 } ! DATA(insert ( 1249 attrelid 26 -1 4 1 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1249 attname 19 -1 NAMEDATALEN 2 0 -1 -1 f p i t f f t 0)); ! DATA(insert ( 1249 atttypid 26 -1 4 3 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1249 attstattarget 23 -1 4 4 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1249 attlen 21 -1 2 5 0 -1 -1 t p s t f f t 0)); ! DATA(insert ( 1249 attnum 21 -1 2 6 0 -1 -1 t p s t f f t 0)); ! DATA(insert ( 1249 attndims 23 -1 4 7 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1249 attcacheoff 23 -1 4 8 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1249 atttypmod 23 -1 4 9 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1249 attbyval 16 -1 1 10 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1249 attstorage 18 -1 1 11 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1249 attalign 18 -1 1 12 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1249 attnotnull 16 -1 1 13 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1249 atthasdef 16 -1 1 14 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1249 attisdropped 16 -1 1 15 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1249 attislocal 16 -1 1 16 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1249 attinhcount 23 -1 4 17 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1249 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0)); /* no OIDs in pg_attribute */ ! DATA(insert ( 1249 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1249 cmin 29 0 4 -4 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1249 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1249 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1249 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); /* ---------------- * pg_class * ---------------- */ #define Schema_pg_class \ ! { 1259, {"relname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ ! { 1259, {"relnamespace"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1259, {"reltype"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1259, {"relowner"}, 26, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1259, {"relam"}, 26, -1, 4, 5, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1259, {"relfilenode"}, 26, -1, 4, 6, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1259, {"reltablespace"}, 26, -1, 4, 7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1259, {"relpages"}, 23, -1, 4, 8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1259, {"reltuples"}, 700, -1, 4, 9, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ ! { 1259, {"reltoastrelid"}, 26, -1, 4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1259, {"reltoastidxid"}, 26, -1, 4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1259, {"relhasindex"}, 16, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1259, {"relisshared"}, 16, -1, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1259, {"relkind"}, 18, -1, 1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1259, {"relnatts"}, 21, -1, 2, 15, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ ! { 1259, {"relchecks"}, 21, -1, 2, 16, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ ! { 1259, {"reltriggers"}, 21, -1, 2, 17, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ ! { 1259, {"relukeys"}, 21, -1, 2, 18, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ ! { 1259, {"relfkeys"}, 21, -1, 2, 19, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ ! { 1259, {"relrefs"}, 21, -1, 2, 20, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ ! { 1259, {"relhasoids"}, 16, -1, 1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1259, {"relhaspkey"}, 16, -1, 1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1259, {"relhasrules"}, 16, -1, 1, 23, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1259, {"relhassubclass"},16, -1, 1, 24, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 1259, {"relfrozenxid"}, 28, -1, 4, 25, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 1259, {"relacl"}, 1034, -1, -1, 26, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ ! { 1259, {"reloptions"}, 1009, -1, -1, 27, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 } ! DATA(insert ( 1259 relname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0)); ! DATA(insert ( 1259 relnamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1259 reltype 26 -1 4 3 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1259 relowner 26 -1 4 4 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1259 relam 26 -1 4 5 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1259 relfilenode 26 -1 4 6 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1259 reltablespace 26 -1 4 7 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1259 relpages 23 -1 4 8 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1259 reltuples 700 -1 4 9 0 -1 -1 f p i t f f t 0)); ! DATA(insert ( 1259 reltoastrelid 26 -1 4 10 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1259 reltoastidxid 26 -1 4 11 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1259 relhasindex 16 -1 1 12 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1259 relisshared 16 -1 1 13 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1259 relkind 18 -1 1 14 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1259 relnatts 21 -1 2 15 0 -1 -1 t p s t f f t 0)); ! DATA(insert ( 1259 relchecks 21 -1 2 16 0 -1 -1 t p s t f f t 0)); ! DATA(insert ( 1259 reltriggers 21 -1 2 17 0 -1 -1 t p s t f f t 0)); ! DATA(insert ( 1259 relukeys 21 -1 2 18 0 -1 -1 t p s t f f t 0)); ! DATA(insert ( 1259 relfkeys 21 -1 2 19 0 -1 -1 t p s t f f t 0)); ! DATA(insert ( 1259 relrefs 21 -1 2 20 0 -1 -1 t p s t f f t 0)); ! DATA(insert ( 1259 relhasoids 16 -1 1 21 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1259 relhaspkey 16 -1 1 22 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1259 relhasrules 16 -1 1 23 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1259 relhassubclass 16 -1 1 24 0 -1 -1 t p c t f f t 0)); ! DATA(insert ( 1259 relfrozenxid 28 -1 4 25 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1259 relacl 1034 -1 -1 26 1 -1 -1 f x i f f f t 0)); ! DATA(insert ( 1259 reloptions 1009 -1 -1 27 1 -1 -1 f x i f f f t 0)); ! DATA(insert ( 1259 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0)); ! DATA(insert ( 1259 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1259 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1259 cmin 29 0 4 -4 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1259 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1259 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0)); ! DATA(insert ( 1259 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); /* ---------------- * pg_index --- 230,468 ---- * ---------------- */ #define Schema_pg_type \ ! { 1247, {"typname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1247, {"typnamespace"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1247, {"typowner"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1247, {"typlen"}, 21, -1, 2, 4, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, false, false }, \ ! { 1247, {"typbyval"}, 16, -1, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1247, {"typtype"}, 18, -1, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1247, {"typisdefined"}, 16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1247, {"typdelim"}, 18, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1247, {"typrelid"}, 26, -1, 4, 9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1247, {"typelem"}, 26, -1, 4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1247, {"typinput"}, 24, -1, 4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1247, {"typoutput"}, 24, -1, 4, 12, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1247, {"typreceive"}, 24, -1, 4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1247, {"typsend"}, 24, -1, 4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1247, {"typmodin"}, 24, -1, 4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1247, {"typmodout"}, 24, -1, 4, 16, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1247, {"typanalyze"}, 24, -1, 4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1247, {"typalign"}, 18, -1, 1, 18, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1247, {"typstorage"}, 18, -1, 1, 19, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1247, {"typnotnull"}, 16, -1, 1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1247, {"typbasetype"}, 26, -1, 4, 21, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1247, {"typtypmod"}, 23, -1, 4, 22, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1247, {"typndims"}, 23, -1, 4, 23, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1247, {"typdefaultbin"}, 25, -1, -1, 24, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, false, false }, \ ! { 1247, {"typdefault"}, 25, -1, -1, 25, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, false, false } ! DATA(insert ( 1247 typname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0 f f)); ! DATA(insert ( 1247 typnamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 typowner 26 -1 4 3 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 typlen 21 -1 2 4 0 -1 -1 t p s t f f t 0 f f)); ! DATA(insert ( 1247 typbyval 16 -1 1 5 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1247 typtype 18 -1 1 6 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1247 typisdefined 16 -1 1 7 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1247 typdelim 18 -1 1 8 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1247 typrelid 26 -1 4 9 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 typelem 26 -1 4 10 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 typinput 24 -1 4 11 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 typoutput 24 -1 4 12 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 typreceive 24 -1 4 13 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 typsend 24 -1 4 14 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 typmodin 24 -1 4 15 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 typmodout 24 -1 4 16 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 typanalyze 24 -1 4 17 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 typalign 18 -1 1 18 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1247 typstorage 18 -1 1 19 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1247 typnotnull 16 -1 1 20 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1247 typbasetype 26 -1 4 21 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 typtypmod 23 -1 4 22 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 typndims 23 -1 4 23 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 typdefaultbin 25 -1 -1 24 0 -1 -1 f x i f f f t 0 f f)); ! DATA(insert ( 1247 typdefault 25 -1 -1 25 0 -1 -1 f x i f f f t 0 f f)); ! DATA(insert ( 1247 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0 f f)); ! DATA(insert ( 1247 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 cmin 29 0 4 -4 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1247 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0 f f)); /* ---------------- * pg_proc * ---------------- */ #define Schema_pg_proc \ ! { 1255, {"proname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1255, {"pronamespace"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1255, {"proowner"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1255, {"prolang"}, 26, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1255, {"procost"}, 700, -1, 4, 5, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1255, {"prorows"}, 700, -1, 4, 6, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1255, {"proisagg"}, 16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1255, {"prosecdef"}, 16, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1255, {"proisstrict"}, 16, -1, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1255, {"proretset"}, 16, -1, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1255, {"provolatile"}, 18, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1255, {"pronargs"}, 21, -1, 2, 12, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, false, false }, \ ! { 1255, {"prorettype"}, 26, -1, 4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1255, {"proargtypes"}, 30, -1, -1, 14, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1255, {"proallargtypes"}, 1028, -1, -1, 15, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, false, false }, \ ! { 1255, {"proargmodes"}, 1002, -1, -1, 16, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, false, false }, \ ! { 1255, {"proargnames"}, 1009, -1, -1, 17, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, false, false }, \ ! { 1255, {"prosrc"}, 25, -1, -1, 18, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, false, false }, \ ! { 1255, {"probin"}, 17, -1, -1, 19, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, false, false }, \ ! { 1255, {"proacl"}, 1034, -1, -1, 20, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, false, false } ! DATA(insert ( 1255 proname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0 f f)); ! DATA(insert ( 1255 pronamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1255 proowner 26 -1 4 3 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1255 prolang 26 -1 4 4 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1255 procost 700 -1 4 5 0 -1 -1 f p i t f f t 0 f f)); ! DATA(insert ( 1255 prorows 700 -1 4 6 0 -1 -1 f p i t f f t 0 f f)); ! DATA(insert ( 1255 proisagg 16 -1 1 7 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1255 prosecdef 16 -1 1 8 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1255 proisstrict 16 -1 1 9 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1255 proretset 16 -1 1 10 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1255 provolatile 18 -1 1 11 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1255 pronargs 21 -1 2 12 0 -1 -1 t p s t f f t 0 f f)); ! DATA(insert ( 1255 prorettype 26 -1 4 13 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1255 proargtypes 30 -1 -1 14 1 -1 -1 f p i t f f t 0 f f)); ! DATA(insert ( 1255 proallargtypes 1028 -1 -1 15 1 -1 -1 f x i f f f t 0 f f)); ! DATA(insert ( 1255 proargmodes 1002 -1 -1 16 1 -1 -1 f x i f f f t 0 f f)); ! DATA(insert ( 1255 proargnames 1009 -1 -1 17 1 -1 -1 f x i f f f t 0 f f)); ! DATA(insert ( 1255 prosrc 25 -1 -1 18 0 -1 -1 f x i f f f t 0 f f)); ! DATA(insert ( 1255 probin 17 -1 -1 19 0 -1 -1 f x i f f f t 0 f f)); ! DATA(insert ( 1255 proacl 1034 -1 -1 20 1 -1 -1 f x i f f f t 0 f f)); ! DATA(insert ( 1255 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0 f f)); ! DATA(insert ( 1255 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1255 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1255 cmin 29 0 4 -4 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1255 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1255 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1255 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0 f f)); /* ---------------- * pg_attribute * ---------------- */ #define Schema_pg_attribute \ ! { 1249, {"attrelid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1249, {"attname"}, 19, -1, NAMEDATALEN, 2, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1249, {"atttypid"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1249, {"attstattarget"}, 23, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1249, {"attlen"}, 21, -1, 2, 5, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, false, false }, \ ! { 1249, {"attnum"}, 21, -1, 2, 6, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, false, false }, \ ! { 1249, {"attndims"}, 23, -1, 4, 7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1249, {"attcacheoff"}, 23, -1, 4, 8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1249, {"atttypmod"}, 23, -1, 4, 9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1249, {"attbyval"}, 16, -1, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1249, {"attstorage"}, 18, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1249, {"attalign"}, 18, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1249, {"attnotnull"}, 16, -1, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1249, {"atthasdef"}, 16, -1, 1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1249, {"attisdropped"}, 16, -1, 1, 15, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1249, {"attislocal"}, 16, -1, 1, 16, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1249, {"attinhcount"}, 23, -1, 4, 17, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1249, {"attidentity"}, 16, -1, 1, 18, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1249, {"attforceddef"}, 16, -1, 1, 19, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false } ! ! DATA(insert ( 1249 attrelid 26 -1 4 1 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1249 attname 19 -1 NAMEDATALEN 2 0 -1 -1 f p i t f f t 0 f f)); ! DATA(insert ( 1249 atttypid 26 -1 4 3 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1249 attstattarget 23 -1 4 4 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1249 attlen 21 -1 2 5 0 -1 -1 t p s t f f t 0 f f)); ! DATA(insert ( 1249 attnum 21 -1 2 6 0 -1 -1 t p s t f f t 0 f f)); ! DATA(insert ( 1249 attndims 23 -1 4 7 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1249 attcacheoff 23 -1 4 8 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1249 atttypmod 23 -1 4 9 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1249 attbyval 16 -1 1 10 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1249 attstorage 18 -1 1 11 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1249 attalign 18 -1 1 12 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1249 attnotnull 16 -1 1 13 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1249 atthasdef 16 -1 1 14 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1249 attisdropped 16 -1 1 15 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1249 attislocal 16 -1 1 16 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1249 attinhcount 23 -1 4 17 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1249 attidentity 16 -1 1 18 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1249 attforceddef 16 -1 1 19 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1249 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0 f f)); /* no OIDs in pg_attribute */ ! DATA(insert ( 1249 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1249 cmin 29 0 4 -4 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1249 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1249 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1249 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0 f f)); /* ---------------- * pg_class * ---------------- */ #define Schema_pg_class \ ! { 1259, {"relname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1259, {"relnamespace"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1259, {"reltype"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1259, {"relowner"}, 26, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1259, {"relam"}, 26, -1, 4, 5, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1259, {"relfilenode"}, 26, -1, 4, 6, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1259, {"reltablespace"}, 26, -1, 4, 7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1259, {"relpages"}, 23, -1, 4, 8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1259, {"reltuples"}, 700, -1, 4, 9, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1259, {"reltoastrelid"}, 26, -1, 4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1259, {"reltoastidxid"}, 26, -1, 4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1259, {"relhasindex"}, 16, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1259, {"relisshared"}, 16, -1, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1259, {"relkind"}, 18, -1, 1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1259, {"relnatts"}, 21, -1, 2, 15, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, false, false }, \ ! { 1259, {"relchecks"}, 21, -1, 2, 16, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, false, false }, \ ! { 1259, {"reltriggers"}, 21, -1, 2, 17, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, false, false }, \ ! { 1259, {"relukeys"}, 21, -1, 2, 18, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, false, false }, \ ! { 1259, {"relfkeys"}, 21, -1, 2, 19, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, false, false }, \ ! { 1259, {"relrefs"}, 21, -1, 2, 20, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, false, false }, \ ! { 1259, {"relhasoids"}, 16, -1, 1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1259, {"relhaspkey"}, 16, -1, 1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1259, {"relhasrules"}, 16, -1, 1, 23, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1259, {"relhassubclass"},16, -1, 1, 24, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 1259, {"relfrozenxid"}, 28, -1, 4, 25, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 1259, {"relacl"}, 1034, -1, -1, 26, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, false, false }, \ ! { 1259, {"reloptions"}, 1009, -1, -1, 27, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0, false, false } ! DATA(insert ( 1259 relname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0 f f)); ! DATA(insert ( 1259 relnamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1259 reltype 26 -1 4 3 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1259 relowner 26 -1 4 4 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1259 relam 26 -1 4 5 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1259 relfilenode 26 -1 4 6 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1259 reltablespace 26 -1 4 7 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1259 relpages 23 -1 4 8 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1259 reltuples 700 -1 4 9 0 -1 -1 f p i t f f t 0 f f)); ! DATA(insert ( 1259 reltoastrelid 26 -1 4 10 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1259 reltoastidxid 26 -1 4 11 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1259 relhasindex 16 -1 1 12 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1259 relisshared 16 -1 1 13 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1259 relkind 18 -1 1 14 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1259 relnatts 21 -1 2 15 0 -1 -1 t p s t f f t 0 f f)); ! DATA(insert ( 1259 relchecks 21 -1 2 16 0 -1 -1 t p s t f f t 0 f f)); ! DATA(insert ( 1259 reltriggers 21 -1 2 17 0 -1 -1 t p s t f f t 0 f f)); ! DATA(insert ( 1259 relukeys 21 -1 2 18 0 -1 -1 t p s t f f t 0 f f)); ! DATA(insert ( 1259 relfkeys 21 -1 2 19 0 -1 -1 t p s t f f t 0 f f)); ! DATA(insert ( 1259 relrefs 21 -1 2 20 0 -1 -1 t p s t f f t 0 f f)); ! DATA(insert ( 1259 relhasoids 16 -1 1 21 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1259 relhaspkey 16 -1 1 22 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1259 relhasrules 16 -1 1 23 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1259 relhassubclass 16 -1 1 24 0 -1 -1 t p c t f f t 0 f f)); ! DATA(insert ( 1259 relfrozenxid 28 -1 4 25 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1259 relacl 1034 -1 -1 26 1 -1 -1 f x i f f f t 0 f f)); ! DATA(insert ( 1259 reloptions 1009 -1 -1 27 1 -1 -1 f x i f f f t 0 f f)); ! DATA(insert ( 1259 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0 f f)); ! DATA(insert ( 1259 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1259 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1259 cmin 29 0 4 -4 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1259 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1259 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0 f f)); ! DATA(insert ( 1259 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0 f f)); /* ---------------- * pg_index *************** DATA(insert ( 1259 tableoid 26 0 4 - *** 460,476 **** * ---------------- */ #define Schema_pg_index \ ! { 0, {"indexrelid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 0, {"indrelid"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ ! { 0, {"indnatts"}, 21, -1, 2, 3, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ ! { 0, {"indisunique"}, 16, -1, 1, 4, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 0, {"indisprimary"}, 16, -1, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 0, {"indisclustered"}, 16, -1, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 0, {"indisvalid"}, 16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ ! { 0, {"indkey"}, 22, -1, -1, 8, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ ! { 0, {"indclass"}, 30, -1, -1, 9, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ ! { 0, {"indoption"}, 22, -1, -1, 10, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ ! { 0, {"indexprs"}, 25, -1, -1, 11, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ ! { 0, {"indpred"}, 25, -1, -1, 12, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 } #endif /* PG_ATTRIBUTE_H */ --- 473,489 ---- * ---------------- */ #define Schema_pg_index \ ! { 0, {"indexrelid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 0, {"indrelid"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 0, {"indnatts"}, 21, -1, 2, 3, 0, -1, -1, true, 'p', 's', true, false, false, true, 0, false, false }, \ ! { 0, {"indisunique"}, 16, -1, 1, 4, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 0, {"indisprimary"}, 16, -1, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 0, {"indisclustered"}, 16, -1, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 0, {"indisvalid"}, 16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0, false, false }, \ ! { 0, {"indkey"}, 22, -1, -1, 8, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 0, {"indclass"}, 30, -1, -1, 9, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 0, {"indoption"}, 22, -1, -1, 10, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, false, false }, \ ! { 0, {"indexprs"}, 25, -1, -1, 11, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, false, false }, \ ! { 0, {"indpred"}, 25, -1, -1, 12, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, false, false } #endif /* PG_ATTRIBUTE_H */ diff -dcrpN pgsql.orig/src/include/catalog/pg_class.h pgsql/src/include/catalog/pg_class.h *** pgsql.orig/src/include/catalog/pg_class.h 2007-01-26 18:53:15.000000000 +0100 --- pgsql/src/include/catalog/pg_class.h 2007-02-28 08:48:35.000000000 +0100 *************** typedef FormData_pg_class *Form_pg_class *** 134,140 **** /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */ DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 25 0 0 0 0 0 t f f f 3 _null_ _null_ )); DESCR(""); ! DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 0 0 0 0 f f f f 3 _null_ _null_ )); DESCR(""); DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 20 0 0 0 0 0 t f f f 3 _null_ _null_ )); DESCR(""); --- 134,140 ---- /* Note: "3" in the relfrozenxid column stands for FirstNormalTransactionId */ DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 25 0 0 0 0 0 t f f f 3 _null_ _null_ )); DESCR(""); ! DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 19 0 0 0 0 0 f f f f 3 _null_ _null_ )); DESCR(""); DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 20 0 0 0 0 0 t f f f 3 _null_ _null_ )); DESCR(""); diff -dcrpN pgsql.orig/src/include/executor/execdesc.h pgsql/src/include/executor/execdesc.h *** pgsql.orig/src/include/executor/execdesc.h 2007-02-25 16:14:32.000000000 +0100 --- pgsql/src/include/executor/execdesc.h 2007-02-28 08:48:35.000000000 +0100 *************** typedef struct QueryDesc *** 47,52 **** --- 47,54 ---- TupleDesc tupDesc; /* descriptor for result tuples */ EState *estate; /* executor's query-wide state */ PlanState *planstate; /* tree of per-plan-node state */ + bool idSetToDefault; /* The table in the query has an IDENTITY column + and it has to be set to DEFAULT */ } QueryDesc; /* in pquery.c */ diff -dcrpN pgsql.orig/src/include/executor/executor.h pgsql/src/include/executor/executor.h *** pgsql.orig/src/include/executor/executor.h 2007-02-27 08:27:40.000000000 +0100 --- pgsql/src/include/executor/executor.h 2007-02-28 08:48:35.000000000 +0100 *************** extern void ExecutorEnd(QueryDesc *query *** 132,138 **** extern void ExecutorRewind(QueryDesc *queryDesc); extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids); extern void ExecConstraints(ResultRelInfo *resultRelInfo, ! TupleTableSlot *slot, EState *estate); extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid, TransactionId priorXmax, CommandId curCid); extern DestReceiver *CreateIntoRelDestReceiver(void); --- 132,139 ---- extern void ExecutorRewind(QueryDesc *queryDesc); extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids); extern void ExecConstraints(ResultRelInfo *resultRelInfo, ! TupleTableSlot *slot, EState *estate, ! bool process_identity, bool process_generated); extern TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid, TransactionId priorXmax, CommandId curCid); extern DestReceiver *CreateIntoRelDestReceiver(void); diff -dcrpN pgsql.orig/src/include/nodes/parsenodes.h pgsql/src/include/nodes/parsenodes.h *** pgsql.orig/src/include/nodes/parsenodes.h 2007-02-25 16:14:32.000000000 +0100 --- pgsql/src/include/nodes/parsenodes.h 2007-02-28 08:48:35.000000000 +0100 *************** typedef struct Query *** 129,134 **** --- 129,139 ---- Node *setOperations; /* set-operation tree if this is top level of * a UNION/INTERSECT/EXCEPT query */ + + bool commandOverride; /* OVERRIDING SYSTEM VALUE */ + + bool idSetToDefault; /* The table query has an IDENTITY column and + it has to be set to DEFAULT */ } Query; *************** typedef struct ColumnDef *** 389,394 **** --- 394,401 ---- Node *raw_default; /* default value (untransformed parse tree) */ char *cooked_default; /* nodeToString representation */ List *constraints; /* other constraints on column */ + bool is_identity; /* GENERATED AS IDENTITY */ + bool force_default; /* GENERATED ALWAYS */ } ColumnDef; /* *************** typedef struct InsertStmt *** 673,678 **** --- 680,686 ---- List *cols; /* optional: names of the target columns */ Node *selectStmt; /* the source SELECT/VALUES, or NULL */ List *returningList; /* list of expressions to return */ + bool commandOverride;/* OVERRIDING SYSTEM VALUE */ } InsertStmt; /* ---------------------- *************** typedef enum AlterTableType *** 903,909 **** AT_EnableTrigUser, /* ENABLE TRIGGER USER */ AT_DisableTrigUser, /* DISABLE TRIGGER USER */ AT_AddInherit, /* INHERIT parent */ ! AT_DropInherit /* NO INHERIT parent */ } AlterTableType; typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */ --- 911,920 ---- AT_EnableTrigUser, /* ENABLE TRIGGER USER */ AT_DisableTrigUser, /* DISABLE TRIGGER USER */ AT_AddInherit, /* INHERIT parent */ ! AT_DropInherit, /* NO INHERIT parent */ ! AT_SetSeqOpts, /* SET sequence_options for IDENTITY columns */ ! AT_SetIdentity, /* SET IDENTITY */ ! AT_DropIdentity /* DROP IDENTITY */ } AlterTableType; typedef struct AlterTableCmd /* one subcommand of an ALTER TABLE */ *************** typedef struct AlterTableCmd /* one subc *** 916,921 **** --- 927,935 ---- * index, constraint, or parent table */ Node *transform; /* transformation expr for ALTER TYPE */ DropBehavior behavior; /* RESTRICT or CASCADE for DROP cases */ + bool force_default; /* SET GENERATED + { ALWAYS | BY DEFAULT } + AS IDENTITY */ } AlterTableCmd; *************** typedef struct CopyStmt *** 1035,1040 **** --- 1049,1055 ---- bool is_from; /* TO or FROM */ char *filename; /* filename, or NULL for STDIN/STDOUT */ List *options; /* List of DefElem nodes */ + bool overriding; /* OVERRIDING SYSTEM VALUE */ } CopyStmt; /* ---------------------- *************** typedef enum ConstrType /* types of co *** 1094,1100 **** CONSTR_ATTR_DEFERRABLE, /* attributes for previous constraint node */ CONSTR_ATTR_NOT_DEFERRABLE, CONSTR_ATTR_DEFERRED, ! CONSTR_ATTR_IMMEDIATE } ConstrType; typedef struct Constraint --- 1109,1116 ---- CONSTR_ATTR_DEFERRABLE, /* attributes for previous constraint node */ CONSTR_ATTR_NOT_DEFERRABLE, CONSTR_ATTR_DEFERRED, ! CONSTR_ATTR_IMMEDIATE, ! CONSTR_IDENTITY } ConstrType; typedef struct Constraint *************** typedef struct Constraint *** 1108,1113 **** --- 1124,1131 ---- List *options; /* options from WITH clause */ char *indexspace; /* index tablespace for PKEY/UNIQUE * constraints; NULL for default */ + bool force_default; /* GENERATED ALWAYS */ + List *seq_opts; /* SEQUENCE options for GENERATED ... AS IDENTITY */ } Constraint; /* ---------- diff -dcrpN pgsql.orig/src/include/nodes/plannodes.h pgsql/src/include/nodes/plannodes.h *** pgsql.orig/src/include/nodes/plannodes.h 2007-02-27 08:27:40.000000000 +0100 --- pgsql/src/include/nodes/plannodes.h 2007-02-28 08:48:35.000000000 +0100 *************** typedef struct PlannedStmt *** 67,72 **** --- 67,75 ---- List *rowMarks; /* a list of RowMarkClause's */ int nParamExec; /* number of PARAM_EXEC Params used */ + + bool idSetToDefault; /* The table in query has an IDENTITY column + and it has to be set to DEFAULT */ } PlannedStmt; /* macro for fetching the Plan associated with a SubPlan node */ diff -dcrpN pgsql.orig/src/include/utils/acl.h pgsql/src/include/utils/acl.h *** pgsql.orig/src/include/utils/acl.h 2007-01-26 18:53:18.000000000 +0100 --- pgsql/src/include/utils/acl.h 2007-02-28 08:48:35.000000000 +0100 *************** extern Acl *aclnewowner(const Acl *old_a *** 215,221 **** extern AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId, AclMode mask, AclMaskHow how); extern int aclmembers(const Acl *acl, Oid **roleids); ! extern bool has_privs_of_role(Oid member, Oid role); extern bool is_member_of_role(Oid member, Oid role); extern bool is_member_of_role_nosuper(Oid member, Oid role); --- 215,221 ---- extern AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId, AclMode mask, AclMaskHow how); extern int aclmembers(const Acl *acl, Oid **roleids); ! extern int aclmemberspriv(const Acl *acl, Oid **roleids, AclMode privs, bool is_equal); extern bool has_privs_of_role(Oid member, Oid role); extern bool is_member_of_role(Oid member, Oid role); extern bool is_member_of_role_nosuper(Oid member, Oid role); *************** extern Datum hash_aclitem(PG_FUNCTION_AR *** 245,250 **** --- 245,251 ---- */ extern void ExecuteGrantStmt(GrantStmt *stmt); extern void ExecGrantStmt_oids(InternalGrant *istmt); + extern void ExecGrant_Sequence(Oid relOid, int attnum, Oid seqOid); extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid, AclMode mask, AclMaskHow how); diff -dcrpN pgsql.orig/src/include/utils/lsyscache.h pgsql/src/include/utils/lsyscache.h *** pgsql.orig/src/include/utils/lsyscache.h 2007-02-15 12:36:15.000000000 +0100 --- pgsql/src/include/utils/lsyscache.h 2007-02-28 08:48:35.000000000 +0100 *************** extern Oid get_opfamily_proc(Oid opfamil *** 53,58 **** --- 53,59 ---- int16 procnum); extern char *get_attname(Oid relid, AttrNumber attnum); extern char *get_relid_attribute_name(Oid relid, AttrNumber attnum); + extern Oid get_relid_att_serial_sequence(Oid relid, AttrNumber attnum); extern AttrNumber get_attnum(Oid relid, const char *attname); extern Oid get_atttype(Oid relid, AttrNumber attnum); extern int32 get_atttypmod(Oid relid, AttrNumber attnum); diff -dcrpN pgsql.orig/src/test/regress/expected/identity.out pgsql/src/test/regress/expected/identity.out *** pgsql.orig/src/test/regress/expected/identity.out 1970-01-01 01:00:00.000000000 +0100 --- pgsql/src/test/regress/expected/identity.out 2007-02-28 12:50:23.000000000 +0100 *************** *** 0 **** --- 1,744 ---- + -- + -- IDENTITY + -- 2006.08.01 Zoltan Boszormenyi + -- + -- + -- Test GENERATED BY DEFAULT AS IDENTITY with default sequence + -- + create table id (id serial generated by default as identity primary key, name text); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "id_pkey" for table "id" + insert into id (name) values ('a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (0, 'a'); + -- + -- This must complain about UNIQUE violation + -- + insert into id (id, name) values (0, 'a'); + ERROR: duplicate key violates unique constraint "id_pkey" + select * from id; + id | name + ----+------ + 1 | a + 2 | a + 3 | a + 4 | a + 0 | a + (5 rows) + + -- + -- This must complain because SERIAL and IDENTITY has + -- implicit NOT NULL constraint + -- + insert into id (id, name) values (null, 'a'); + ERROR: null value in column "id" violates not-null constraint + select * from id; + id | name + ----+------ + 1 | a + 2 | a + 3 | a + 4 | a + 0 | a + (5 rows) + + update id set id = default where id = 0; + select * from id; + id | name + ----+------ + 1 | a + 2 | a + 3 | a + 4 | a + 5 | a + (5 rows) + + drop table id; + -- + -- Test GENERATED BY DEFAULT AS IDENTITY with modified sequence + -- + create table id (id serial generated by default as identity(start 3) primary key, name text); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "id_pkey" for table "id" + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (0, 'a'); + -- + -- This must complain about UNIQUE violation + -- + insert into id (id, name) values (0, 'a'); + ERROR: duplicate key violates unique constraint "id_pkey" + select * from id; + id | name + ----+------ + 3 | a + 4 | a + 5 | a + 0 | a + (4 rows) + + drop table id; + -- + -- Test GENERATED ALWAYS AS IDENTITY with default sequence + -- + create table id (id serial generated always as identity primary key, name text); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "id_pkey" for table "id" + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (0, 'a'); + insert into id (id, name) values (0, 'a'); + insert into id (id, name) values (0, 'a'); + select * from id; + id | name + ----+------ + 1 | a + 2 | a + 3 | a + 4 | a + 5 | a + 6 | a + (6 rows) + + -- + -- It should update 0 rows + -- + update id set name = 'b' where id = 0; + select * from id; + id | name + ----+------ + 1 | a + 2 | a + 3 | a + 4 | a + 5 | a + 6 | a + (6 rows) + + drop table id; + -- + -- Test GENERATED ALWAYS AS IDENTITY with modified sequence + -- + create table id (id serial generated always as identity(start 3) primary key, name text); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "id_pkey" for table "id" + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (0, 'a'); + insert into id (id, name) values (0, 'a'); + insert into id (id, name) values (0, 'a'); + select * from id; + id | name + ----+------ + 3 | a + 4 | a + 5 | a + 6 | a + 7 | a + 8 | a + (6 rows) + + -- + -- It should update 0 rows + -- + update id set name = 'b' where id = 0; + select * from id; + id | name + ----+------ + 3 | a + 4 | a + 5 | a + 6 | a + 7 | a + 8 | a + (6 rows) + + drop table id; + -- + -- Test GENERATED BY DEFAULT AS (expr) + -- It must give a syntax error but drop it anyway. + -- + create table id (id integer generated by default as (1), name text); + ERROR: syntax error at or near "(" + LINE 1: ...eate table id (id integer generated by default as (1), name ... + ^ + drop table id; + ERROR: table "id" does not exist + -- + -- Test GENERATED ALWAYS AS ( expr ) + -- + create table id (id integer generated always as (1), name text); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (0, 'a'); + select * from id; + id | name + ----+------ + 1 | a + 1 | a + (2 rows) + + -- + -- It should update 0 rows + -- + update id set name = 'b' where id = 0; + select * from id; + id | name + ----+------ + 1 | a + 1 | a + (2 rows) + + drop table id; + -- + -- Test IDENTITY with non-integer columns + -- + create table id (id decimal(10,2) generated always as identity(start 3), name text); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (0, 'a'); + select * from id; + id | name + ------+------ + 3.00 | a + 4.00 | a + (2 rows) + + alter table id alter id type real; + insert into id (id, name) values (0, 'a'); + select * from id; + id | name + ----+------ + 3 | a + 4 | a + 5 | a + (3 rows) + + alter table id alter id type integer; + insert into id (id, name) values (0, 'a'); + select * from id; + id | name + ----+------ + 3 | a + 4 | a + 5 | a + 6 | a + (4 rows) + + -- + -- It should update 0 rows + -- + update id set name = 'b' where id = 0; + select * from id; + id | name + ----+------ + 3 | a + 4 | a + 5 | a + 6 | a + (4 rows) + + update id set name = 'b' where id = 5; + select * from id; + id | name + ----+------ + 3 | a + 4 | a + 6 | a + 5 | b + (4 rows) + + drop table id; + -- + -- Test OVERRIDING and UPDATE on GENERATED ALWAYS columns + -- + create table id (id serial generated always as identity, name text generated always as ('x')); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + insert into id (id, name) values (0, 'a'); + insert into id (id, name) overriding user value values (0, 'a'); + insert into id (id, name) overriding system value values (0, 'a'); + -- + -- It's expected to fail because of GENERATED ALWAYS AS IDENTITY. + -- + update id set id = 6 where id = 0; + ERROR: UPDATE prohibited on GENERATED ALWAYS AS IDENTITY attributes + -- + -- It's expected to fail because of GENERATED ALWAYS AS IDENTITY. + -- + update id set id = default where id = 0; + ERROR: UPDATE prohibited on GENERATED ALWAYS AS IDENTITY attributes + -- + -- It's expected to fail because of GENERATED ALWAYS. + -- + update id set name = 'b' where id = 0; + ERROR: UPDATE to non-default value prohibited on GENERATED ALWAYS attributes + -- + -- It's expected to succeed + -- + update id set name = default where id = 0; + -- + -- Test ALTER TABLE sequence options + -- + alter table id alter id restart with 10; + insert into id (id, name) values (0, 'a'); + alter table id alter id set increment by 5; + insert into id (id, name) values (0, 'a'); + select * from id; + id | name + ----+------ + 1 | x + 2 | x + 3 | x + 10 | x + 15 | x + (5 rows) + + -- + -- Test ALTER TABLE RENAME + -- + select pg_get_serial_sequence('id', 'id'); + pg_get_serial_sequence + ------------------------ + public.id_id_seq + (1 row) + + alter table id rename id to di; + NOTICE: supporting sequence for column "di" renamed to "id_di_seq" + insert into id (di, name) values (0, 'a'); + select pg_get_serial_sequence('id', 'di'); + pg_get_serial_sequence + ------------------------ + public.id_di_seq + (1 row) + + alter table id rename to di; + NOTICE: supporting sequence for column "di" renamed to "di_di_seq" + insert into di (di, name) values (0, 'a'); + select pg_get_serial_sequence('di', 'di'); + pg_get_serial_sequence + ------------------------ + public.di_di_seq + (1 row) + + select * from di; + di | name + ----+------ + 1 | x + 2 | x + 3 | x + 10 | x + 15 | x + 20 | x + 25 | x + (7 rows) + + -- + -- Test SET/DROP DEFAULT + -- + alter table di alter di drop default; + ERROR: cannot alter IDENTITY column "di" + alter table di alter di set default 1; + ERROR: cannot alter IDENTITY column "di" + -- + -- Test ALTER TABLE DROP COLUMN + -- + alter table di add column id integer; + update di set id = di; + alter table di drop column di; + select * from di; + name | id + ------+---- + x | 1 + x | 2 + x | 3 + x | 10 + x | 15 + x | 20 + x | 25 + (7 rows) + + -- + -- Test privilege over the underlying sequence[s]. + -- I use it to test for two things: + -- 1) DROP USER fails because objects are still referenced + -- 2) It doesn't crash because of overzealous + -- pfree()/list_free() usage. + -- + create user mytestuser; + grant insert on di to mytestuser; + alter table di add id5 serial generated always as identity (start 20); + NOTICE: ALTER TABLE will create implicit sequence "di_id5_seq" for serial column "di.id5" + drop user mytestuser; + ERROR: role "mytestuser" cannot be dropped because some objects depend on it + DETAIL: access to sequence di_id5_seq + access to table di + alter table di drop id5; + drop user mytestuser; + ERROR: role "mytestuser" cannot be dropped because some objects depend on it + DETAIL: access to table di + revoke all on di from mytestuser; + drop user mytestuser; + drop table di; + -- + -- Test the late generation of the IDENTITY column + -- + create table id (id serial generated always as identity (start 3), t text not null); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + insert into id (id, t) values (0, null); + ERROR: null value in column "t" violates not-null constraint + insert into id (id, t) values (0, 't'); + insert into id (id, t) values (0, null); + ERROR: null value in column "t" violates not-null constraint + insert into id (id, t) values (0, 't'); + select * from id; + id | t + ----+--- + 3 | t + 4 | t + (2 rows) + + drop table id; + -- + -- Test multiple IDENTITY columns in a single table + -- + -- This must fail, no multiple IDENTITY allowed + create table id ( + id1 serial generated always as identity (start 3), + id2 serial generated always as identity (start 5) + ); + NOTICE: CREATE TABLE will create implicit sequence "id_id1_seq" for serial column "id.id1" + NOTICE: CREATE TABLE will create implicit sequence "id_id2_seq" for serial column "id.id2" + ERROR: multiple IDENTITY columns are not allowed + -- This succeeds + create table id (id1 serial generated always as identity (start 3), t text not null); + NOTICE: CREATE TABLE will create implicit sequence "id_id1_seq" for serial column "id.id1" + insert into id (t) values (null) returning id1; + ERROR: null value in column "t" violates not-null constraint + insert into id (t) values ('a') returning id1; + id1 + ----- + 3 + (1 row) + + select * from id; + id1 | t + -----+--- + 3 | a + (1 row) + + -- This must fail, no multiple IDENTITY allowed + alter table id add id2 serial generated always as identity (start 5); + NOTICE: ALTER TABLE will create implicit sequence "id_id2_seq" for serial column "id.id2" + ERROR: multiple IDENTITY columns are not allowed + -- Downgrade id1 to normal serial + alter table id alter id1 drop identity; + insert into id (t) values (null) returning id1; + ERROR: null value in column "t" violates not-null constraint + insert into id (t) values ('a') returning id1; + id1 + ----- + 5 + (1 row) + + select * from id; + id1 | t + -----+--- + 3 | a + 5 | a + (2 rows) + + -- Not this succeeds + alter table id add id2 serial generated always as identity (start 5); + NOTICE: ALTER TABLE will create implicit sequence "id_id2_seq" for serial column "id.id2" + insert into id (t) values (null) returning id1, id2; + ERROR: null value in column "t" violates not-null constraint + insert into id (t) values ('a') returning id1, id2; + id1 | id2 + -----+----- + 7 | 7 + (1 row) + + select * from id; + id1 | t | id2 + -----+---+----- + 3 | a | 5 + 5 | a | 6 + 7 | a | 7 + (3 rows) + + -- Downgrade id2 to normal serial + alter table id alter id2 drop identity; + insert into id (t) values (null) returning id1, id2; + ERROR: null value in column "t" violates not-null constraint + insert into id (t) values ('a') returning id1, id2; + id1 | id2 + -----+----- + 9 | 9 + (1 row) + + select * from id; + id1 | t | id2 + -----+---+----- + 3 | a | 5 + 5 | a | 6 + 7 | a | 7 + 9 | a | 9 + (4 rows) + + -- Upgrade id1 to identity + alter table id alter id1 set generated always as identity; + -- Upgrade id2 to identity, this must fail + alter table id alter id2 set generated always as identity; + ERROR: multiple IDENTITY columns are not allowed + select * from id; + id1 | t | id2 + -----+---+----- + 3 | a | 5 + 5 | a | 6 + 7 | a | 7 + 9 | a | 9 + (4 rows) + + drop table id; + -- + -- Check for forbidden CHECK constraints + -- + create table id ( + id serial generated always as identity check (id > 3), + t varchar(40) generated always as ('') not null check (t <> '')); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + ERROR: IDENTITY column "id" of table "id" cannot be referenced in CHECK constraint + drop table id; + ERROR: table "id" does not exist + create table id ( + t varchar(40) generated always as ('') not null check (t <> ''), + id serial generated always as identity check (id > 3)); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + ERROR: GENERATED column "t" of table "id" cannot be referenced in CHECK constraint + drop table id; + ERROR: table "id" does not exist + create table id ( + id serial generated always as identity, + t varchar(40) generated always as ('') not null, + check (id > 3), + check (t <> '')); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + ERROR: IDENTITY column "id" of table "id" cannot be referenced in CHECK constraint + drop table id; + ERROR: table "id" does not exist + create table id ( + id serial generated always as identity, + t varchar(40) generated always as ('') not null); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + alter table id add check(id > 3); + ERROR: IDENTITY column "id" of table "id" cannot be referenced in CHECK constraint + alter table id add check(t <> ''); + ERROR: GENERATED column "t" of table "id" cannot be referenced in CHECK constraint + alter table id add t2 text generated always as ('a') check (t2 <> ''); + ERROR: GENERATED column "t2" of table "id" cannot be referenced in CHECK constraint + drop table id; + -- + -- Test GENERATED columns + -- + -- + -- This should fail, IDENTITY cannot be referenced by GENERATED + -- + create table id ( + id serial generated always as identity, + g integer generated always as ( id + 1 )); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + ERROR: IDENTITY column "id" of table "id" cannot be referenced by GENERATED column "g" + drop table id; + ERROR: table "id" does not exist + -- + -- This should fail, GENERATED cannot be referenced by GENERATED + -- + create table id ( + id serial generated always as identity, + i1 integer, + i2 integer, + g1 integer generated always as ( i1 + i2 ), + g2 integer generated always as ( i1 + g1 )); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + ERROR: GENERATED column "g1" of table "id" cannot be referenced by GENERATED column "g2" + drop table id; + ERROR: table "id" does not exist + -- + -- Test simple expression (col1 + col2) as GENERATED column + -- + -- + -- Test INSERT with GENERATED columns + -- + create table id ( + id serial generated always as identity, + i1 integer, + i2 integer, + g1 integer generated always as ( i1 + i2 )); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + -- + -- g1 has to be 3 + -- + insert into id (i1, i2) values (1, 2); + insert into id (id, i1, i2, g1) values (default, 1, 2, default); + select * from id; + id | i1 | i2 | g1 + ----+----+----+---- + 1 | 1 | 2 | 3 + 2 | 1 | 2 | 3 + (2 rows) + + -- + -- g1 has to be recomputed as 4 + -- + update id set i1 = 2 where id = 1; + select * from id; + id | i1 | i2 | g1 + ----+----+----+---- + 2 | 1 | 2 | 3 + 1 | 2 | 2 | 4 + (2 rows) + + drop table id; + -- + -- Test complex expression as GENERATED column + -- + create table id ( + id serial generated always as identity, + i1 integer, + i2 integer, + g1 integer generated always as ( + case when i1 is null and i2 is null then -1 + when i1 is null then i2 + when i2 is null then i1 + else i1 + i2 + end )); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + insert into id (i1, i2) values (null, null); + insert into id (i1, i2) values (10, null); + insert into id (i1, i2) values (null, 20 ); + insert into id (i1, i2) values (10, 20 ); + select * from id; + id | i1 | i2 | g1 + ----+----+----+---- + 1 | | | -1 + 2 | 10 | | 10 + 3 | | 20 | 20 + 4 | 10 | 20 | 30 + (4 rows) + + -- + -- Test DROP COLUMN on a column referenced by the GENERATED column + -- + \d id + Table "public.id" + Column | Type | Modifiers + --------+---------+---------------------------------------------------------------------------------------------------------------------------------- + id | integer | not null default nextval('id_id_seq'::regclass) + i1 | integer | + i2 | integer | + g1 | integer | default CASE WHEN ((i1 IS NULL) AND (i2 IS NULL)) THEN -1 WHEN (i1 IS NULL) THEN i2 WHEN (i2 IS NULL) THEN i1 ELSE (i1 + i2) END + + alter table id drop i2; + NOTICE: GENERATED column "g1" of relation "id" referencing column "i2" was dropped + \d id + Table "public.id" + Column | Type | Modifiers + --------+---------+------------------------------------------------- + id | integer | not null default nextval('id_id_seq'::regclass) + i1 | integer | + + drop table id; + -- + -- Test plain COPY on IDENTITY/GENERATED columns + -- + create table id ( + id serial generated always as identity, + i1 integer, + i2 integer, + g1 integer generated always as ( + case when i1 is null and i2 is null then -1 + when i1 is null then i2 + when i2 is null then i1 + else i1 + i2 + end )); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + copy id (i1, i2) from stdin; + select * from id; + id | i1 | i2 | g1 + ----+----+----+---- + 1 | | | -1 + 2 | 10 | | 10 + 3 | | 20 | 20 + 4 | 10 | 20 | 30 + (4 rows) + + drop table id; + -- + -- Test plain COPY OVERRIDING SYSTEM VALUE on IDENTITY/GENERATED columns + -- with missing column values. These should be generated. + -- + create table id ( + id serial generated always as identity, + i1 integer, + i2 integer, + g1 integer generated always as ( + case when i1 is null and i2 is null then -1 + when i1 is null then i2 + when i2 is null then i1 + else i1 + i2 + end )); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + copy id (i1, i2) overriding system value from stdin; + select * from id; + id | i1 | i2 | g1 + ----+----+----+---- + 1 | | | -1 + 2 | 10 | | 10 + 3 | | 20 | 20 + 4 | 10 | 20 | 30 + (4 rows) + + drop table id; + -- + -- Test plain COPY OVERRIDING SYSTEM VALUE on IDENTITY/GENERATED columns + -- with explicit column values. These should accept explicit values. + -- + create table id ( + id serial generated always as identity, + i1 integer, + i2 integer, + g1 integer generated always as ( + case when i1 is null and i2 is null then -1 + when i1 is null then i2 + when i2 is null then i1 + else i1 + i2 + end )); + NOTICE: CREATE TABLE will create implicit sequence "id_id_seq" for serial column "id.id" + copy id (id, i1, i2, g1) overriding system value from stdin; + select * from id; + id | i1 | i2 | g1 + ----+----+----+---- + 1 | | | -2 + 2 | 10 | | 37 + 3 | | 20 | 36 + 4 | 10 | 20 | 25 + (4 rows) + + -- + -- Regenerate GENERATED values + -- + update id set g1 = default where id = id; + select * from id; + id | i1 | i2 | g1 + ----+----+----+---- + 1 | | | -1 + 2 | 10 | | 10 + 3 | | 20 | 20 + 4 | 10 | 20 | 30 + (4 rows) + + drop table id; diff -dcrpN pgsql.orig/src/test/regress/parallel_schedule pgsql/src/test/regress/parallel_schedule *** pgsql.orig/src/test/regress/parallel_schedule 2007-02-09 07:23:50.000000000 +0100 --- pgsql/src/test/regress/parallel_schedule 2007-02-28 08:48:35.000000000 +0100 *************** *** 2,8 **** # The first group of parallel test # $PostgreSQL: pgsql/src/test/regress/parallel_schedule,v 1.39 2007/02/09 03:35:35 tgl Exp $ # ---------- ! test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric uuid # Depends on things setup during char, varchar and text test: strings --- 2,8 ---- # The first group of parallel test # $PostgreSQL: pgsql/src/test/regress/parallel_schedule,v 1.39 2007/02/09 03:35:35 tgl Exp $ # ---------- ! test: boolean char name varchar text int2 int4 int8 oid float4 float8 bit numeric uuid identity # Depends on things setup during char, varchar and text test: strings diff -dcrpN pgsql.orig/src/test/regress/serial_schedule pgsql/src/test/regress/serial_schedule *** pgsql.orig/src/test/regress/serial_schedule 2007-02-09 07:23:51.000000000 +0100 --- pgsql/src/test/regress/serial_schedule 2007-02-28 08:48:35.000000000 +0100 *************** test: float8 *** 14,19 **** --- 14,20 ---- test: bit test: numeric test: uuid + test: identity test: strings test: numerology test: point diff -dcrpN pgsql.orig/src/test/regress/sql/identity.sql pgsql/src/test/regress/sql/identity.sql *** pgsql.orig/src/test/regress/sql/identity.sql 1970-01-01 01:00:00.000000000 +0100 --- pgsql/src/test/regress/sql/identity.sql 2007-02-28 12:49:44.000000000 +0100 *************** *** 0 **** --- 1,394 ---- + -- + -- IDENTITY + -- 2006.08.01 Zoltan Boszormenyi + -- + + -- + -- Test GENERATED BY DEFAULT AS IDENTITY with default sequence + -- + create table id (id serial generated by default as identity primary key, name text); + insert into id (name) values ('a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (0, 'a'); + -- + -- This must complain about UNIQUE violation + -- + insert into id (id, name) values (0, 'a'); + select * from id; + -- + -- This must complain because SERIAL and IDENTITY has + -- implicit NOT NULL constraint + -- + insert into id (id, name) values (null, 'a'); + select * from id; + update id set id = default where id = 0; + select * from id; + drop table id; + -- + -- Test GENERATED BY DEFAULT AS IDENTITY with modified sequence + -- + create table id (id serial generated by default as identity(start 3) primary key, name text); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (0, 'a'); + -- + -- This must complain about UNIQUE violation + -- + insert into id (id, name) values (0, 'a'); + select * from id; + drop table id; + -- + -- Test GENERATED ALWAYS AS IDENTITY with default sequence + -- + create table id (id serial generated always as identity primary key, name text); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (0, 'a'); + insert into id (id, name) values (0, 'a'); + insert into id (id, name) values (0, 'a'); + select * from id; + -- + -- It should update 0 rows + -- + update id set name = 'b' where id = 0; + select * from id; + drop table id; + -- + -- Test GENERATED ALWAYS AS IDENTITY with modified sequence + -- + create table id (id serial generated always as identity(start 3) primary key, name text); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (0, 'a'); + insert into id (id, name) values (0, 'a'); + insert into id (id, name) values (0, 'a'); + select * from id; + -- + -- It should update 0 rows + -- + update id set name = 'b' where id = 0; + select * from id; + drop table id; + -- + -- Test GENERATED BY DEFAULT AS (expr) + -- It must give a syntax error but drop it anyway. + -- + create table id (id integer generated by default as (1), name text); + drop table id; + -- + -- Test GENERATED ALWAYS AS ( expr ) + -- + create table id (id integer generated always as (1), name text); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (0, 'a'); + select * from id; + -- + -- It should update 0 rows + -- + update id set name = 'b' where id = 0; + select * from id; + drop table id; + -- + -- Test IDENTITY with non-integer columns + -- + create table id (id decimal(10,2) generated always as identity(start 3), name text); + insert into id (id, name) values (default, 'a'); + insert into id (id, name) values (0, 'a'); + select * from id; + alter table id alter id type real; + insert into id (id, name) values (0, 'a'); + select * from id; + alter table id alter id type integer; + insert into id (id, name) values (0, 'a'); + select * from id; + -- + -- It should update 0 rows + -- + update id set name = 'b' where id = 0; + select * from id; + update id set name = 'b' where id = 5; + select * from id; + drop table id; + -- + -- Test OVERRIDING and UPDATE on GENERATED ALWAYS columns + -- + create table id (id serial generated always as identity, name text generated always as ('x')); + insert into id (id, name) values (0, 'a'); + insert into id (id, name) overriding user value values (0, 'a'); + insert into id (id, name) overriding system value values (0, 'a'); + -- + -- It's expected to fail because of GENERATED ALWAYS AS IDENTITY. + -- + update id set id = 6 where id = 0; + -- + -- It's expected to fail because of GENERATED ALWAYS AS IDENTITY. + -- + update id set id = default where id = 0; + -- + -- It's expected to fail because of GENERATED ALWAYS. + -- + update id set name = 'b' where id = 0; + -- + -- It's expected to succeed + -- + update id set name = default where id = 0; + -- + -- Test ALTER TABLE sequence options + -- + alter table id alter id restart with 10; + insert into id (id, name) values (0, 'a'); + alter table id alter id set increment by 5; + insert into id (id, name) values (0, 'a'); + select * from id; + -- + -- Test ALTER TABLE RENAME + -- + select pg_get_serial_sequence('id', 'id'); + alter table id rename id to di; + insert into id (di, name) values (0, 'a'); + select pg_get_serial_sequence('id', 'di'); + alter table id rename to di; + insert into di (di, name) values (0, 'a'); + select pg_get_serial_sequence('di', 'di'); + select * from di; + -- + -- Test SET/DROP DEFAULT + -- + alter table di alter di drop default; + alter table di alter di set default 1; + -- + -- Test ALTER TABLE DROP COLUMN + -- + alter table di add column id integer; + update di set id = di; + alter table di drop column di; + select * from di; + -- + -- Test privilege over the underlying sequence[s]. + -- I use it to test for two things: + -- 1) DROP USER fails because objects are still referenced + -- 2) It doesn't crash because of overzealous + -- pfree()/list_free() usage. + -- + create user mytestuser; + grant insert on di to mytestuser; + alter table di add id5 serial generated always as identity (start 20); + drop user mytestuser; + alter table di drop id5; + drop user mytestuser; + revoke all on di from mytestuser; + drop user mytestuser; + drop table di; + -- + -- Test the late generation of the IDENTITY column + -- + create table id (id serial generated always as identity (start 3), t text not null); + insert into id (id, t) values (0, null); + insert into id (id, t) values (0, 't'); + insert into id (id, t) values (0, null); + insert into id (id, t) values (0, 't'); + select * from id; + drop table id; + -- + -- Test multiple IDENTITY columns in a single table + -- + -- This must fail, no multiple IDENTITY allowed + create table id ( + id1 serial generated always as identity (start 3), + id2 serial generated always as identity (start 5) + ); + -- This succeeds + create table id (id1 serial generated always as identity (start 3), t text not null); + insert into id (t) values (null) returning id1; + insert into id (t) values ('a') returning id1; + select * from id; + -- This must fail, no multiple IDENTITY allowed + alter table id add id2 serial generated always as identity (start 5); + -- Downgrade id1 to normal serial + alter table id alter id1 drop identity; + insert into id (t) values (null) returning id1; + insert into id (t) values ('a') returning id1; + select * from id; + -- Not this succeeds + alter table id add id2 serial generated always as identity (start 5); + insert into id (t) values (null) returning id1, id2; + insert into id (t) values ('a') returning id1, id2; + select * from id; + -- Downgrade id2 to normal serial + alter table id alter id2 drop identity; + insert into id (t) values (null) returning id1, id2; + insert into id (t) values ('a') returning id1, id2; + select * from id; + -- Upgrade id1 to identity + alter table id alter id1 set generated always as identity; + -- Upgrade id2 to identity, this must fail + alter table id alter id2 set generated always as identity; + select * from id; + drop table id; + -- + -- Check for forbidden CHECK constraints + -- + create table id ( + id serial generated always as identity check (id > 3), + t varchar(40) generated always as ('') not null check (t <> '')); + drop table id; + create table id ( + t varchar(40) generated always as ('') not null check (t <> ''), + id serial generated always as identity check (id > 3)); + drop table id; + create table id ( + id serial generated always as identity, + t varchar(40) generated always as ('') not null, + check (id > 3), + check (t <> '')); + drop table id; + create table id ( + id serial generated always as identity, + t varchar(40) generated always as ('') not null); + alter table id add check(id > 3); + alter table id add check(t <> ''); + alter table id add t2 text generated always as ('a') check (t2 <> ''); + drop table id; + -- + -- Test GENERATED columns + -- + -- + -- This should fail, IDENTITY cannot be referenced by GENERATED + -- + create table id ( + id serial generated always as identity, + g integer generated always as ( id + 1 )); + drop table id; + -- + -- This should fail, GENERATED cannot be referenced by GENERATED + -- + create table id ( + id serial generated always as identity, + i1 integer, + i2 integer, + g1 integer generated always as ( i1 + i2 ), + g2 integer generated always as ( i1 + g1 )); + drop table id; + -- + -- Test simple expression (col1 + col2) as GENERATED column + -- + -- + -- Test INSERT with GENERATED columns + -- + create table id ( + id serial generated always as identity, + i1 integer, + i2 integer, + g1 integer generated always as ( i1 + i2 )); + -- + -- g1 has to be 3 + -- + insert into id (i1, i2) values (1, 2); + insert into id (id, i1, i2, g1) values (default, 1, 2, default); + select * from id; + -- + -- g1 has to be recomputed as 4 + -- + update id set i1 = 2 where id = 1; + select * from id; + drop table id; + -- + -- Test complex expression as GENERATED column + -- + create table id ( + id serial generated always as identity, + i1 integer, + i2 integer, + g1 integer generated always as ( + case when i1 is null and i2 is null then -1 + when i1 is null then i2 + when i2 is null then i1 + else i1 + i2 + end )); + insert into id (i1, i2) values (null, null); + insert into id (i1, i2) values (10, null); + insert into id (i1, i2) values (null, 20 ); + insert into id (i1, i2) values (10, 20 ); + select * from id; + -- + -- Test DROP COLUMN on a column referenced by the GENERATED column + -- + \d id + alter table id drop i2; + \d id + drop table id; + -- + -- Test plain COPY on IDENTITY/GENERATED columns + -- + create table id ( + id serial generated always as identity, + i1 integer, + i2 integer, + g1 integer generated always as ( + case when i1 is null and i2 is null then -1 + when i1 is null then i2 + when i2 is null then i1 + else i1 + i2 + end )); + copy id (i1, i2) from stdin; + \N \N + 10 \N + \N 20 + 10 20 + \. + select * from id; + drop table id; + -- + -- Test plain COPY OVERRIDING SYSTEM VALUE on IDENTITY/GENERATED columns + -- with missing column values. These should be generated. + -- + create table id ( + id serial generated always as identity, + i1 integer, + i2 integer, + g1 integer generated always as ( + case when i1 is null and i2 is null then -1 + when i1 is null then i2 + when i2 is null then i1 + else i1 + i2 + end )); + copy id (i1, i2) overriding system value from stdin; + \N \N + 10 \N + \N 20 + 10 20 + \. + select * from id; + drop table id; + -- + -- Test plain COPY OVERRIDING SYSTEM VALUE on IDENTITY/GENERATED columns + -- with explicit column values. These should accept explicit values. + -- + create table id ( + id serial generated always as identity, + i1 integer, + i2 integer, + g1 integer generated always as ( + case when i1 is null and i2 is null then -1 + when i1 is null then i2 + when i2 is null then i1 + else i1 + i2 + end )); + copy id (id, i1, i2, g1) overriding system value from stdin; + 1 \N \N -2 + 2 10 \N 37 + 3 \N 20 36 + 4 10 20 25 + \. + select * from id; + -- + -- Regenerate GENERATED values + -- + update id set g1 = default where id = id; + select * from id; + drop table id;