From 38bb77a5d15aa022248488bc8c0147139ce120a9 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 2 Aug 2002 18:15:10 +0000 Subject: [PATCH] ALTER TABLE DROP COLUMN works. Patch by Christopher Kings-Lynne, code review by Tom Lane. Remaining issues: functions that take or return tuple types are likely to break if one drops (or adds!) a column in the table defining the type. Need to think about what to do here. Along the way: some code review for recent COPY changes; mark system columns attnotnull = true where appropriate, per discussion a month ago. --- contrib/dblink/dblink.c | 90 ++-- doc/src/sgml/catalogs.sgml | 13 +- doc/src/sgml/ref/alter_table.sgml | 92 ++-- doc/src/sgml/ref/copy.sgml | 29 +- doc/src/sgml/release.sgml | 4 +- src/backend/access/common/tupdesc.c | 9 +- src/backend/bootstrap/bootstrap.c | 51 +- src/backend/catalog/dependency.c | 5 +- src/backend/catalog/heap.c | 88 +++- src/backend/catalog/pg_proc.c | 51 +- src/backend/commands/analyze.c | 27 +- src/backend/commands/comment.c | 6 +- src/backend/commands/copy.c | 591 +++++++++++----------- src/backend/commands/indexcmds.c | 12 +- src/backend/commands/tablecmds.c | 202 ++++++-- src/backend/optimizer/prep/preptlist.c | 27 +- src/backend/optimizer/prep/prepunion.c | 15 +- src/backend/parser/analyze.c | 25 +- src/backend/parser/parse_func.c | 5 +- src/backend/parser/parse_relation.c | 155 +++++- src/backend/parser/parse_target.c | 10 +- src/backend/parser/parse_type.c | 6 +- src/backend/rewrite/rewriteDefine.c | 12 +- src/backend/rewrite/rewriteHandler.c | 6 +- src/backend/utils/adt/not_in.c | 29 +- src/backend/utils/cache/lsyscache.c | 37 +- src/backend/utils/cache/syscache.c | 67 ++- src/bin/pg_dump/pg_dump.c | 53 +- src/bin/pg_dump/pg_dump.h | 3 +- src/bin/psql/describe.c | 4 +- src/bin/psql/tab-complete.c | 4 +- src/include/catalog/catversion.h | 4 +- src/include/catalog/heap.h | 3 +- src/include/catalog/pg_attribute.h | 446 ++++++++-------- src/include/catalog/pg_class.h | 4 +- src/include/executor/executor.h | 3 +- src/include/parser/parse_relation.h | 4 +- src/include/utils/lsyscache.h | 5 +- src/include/utils/syscache.h | 6 +- src/pl/plpgsql/src/pl_comp.c | 7 +- src/test/regress/expected/alter_table.out | 294 ++++++++++- src/test/regress/expected/copy2.out | 44 +- src/test/regress/sql/alter_table.sql | 160 ++++++ src/test/regress/sql/copy2.sql | 6 + 44 files changed, 1823 insertions(+), 891 deletions(-) diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index 26fa62417f..d396f070dd 100644 --- a/contrib/dblink/dblink.c +++ b/contrib/dblink/dblink.c @@ -829,8 +829,9 @@ dblink_replace_text(PG_FUNCTION_ARGS) left_text = DatumGetTextP(DirectFunctionCall3(text_substr, PointerGetDatum(buf_text), 1, DatumGetInt32(DirectFunctionCall2(textpos, PointerGetDatum(buf_text), PointerGetDatum(from_sub_text))) - 1)); right_text = DatumGetTextP(DirectFunctionCall3(text_substr, PointerGetDatum(buf_text), DatumGetInt32(DirectFunctionCall2(textpos, PointerGetDatum(buf_text), PointerGetDatum(from_sub_text))) + from_sub_text_len, -1)); - appendStringInfo(str, DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(left_text)))); - appendStringInfo(str, to_sub_str); + appendStringInfo(str, "%s", + DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(left_text)))); + appendStringInfo(str, "%s", to_sub_str); pfree(buf_text); pfree(left_text); @@ -838,7 +839,8 @@ dblink_replace_text(PG_FUNCTION_ARGS) curr_posn = DatumGetInt32(DirectFunctionCall2(textpos, PointerGetDatum(buf_text), PointerGetDatum(from_sub_text))); } - appendStringInfo(str, DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(buf_text)))); + appendStringInfo(str, "%s", + DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(buf_text)))); pfree(buf_text); ret_str = pstrdup(str->data); @@ -1013,10 +1015,11 @@ get_sql_insert(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval TupleDesc tupdesc; int natts; StringInfo str = makeStringInfo(); - char *sql = NULL; - char *val = NULL; + char *sql; + char *val; int16 key; - unsigned int i; + int i; + bool needComma; /* * Open relation using relid @@ -1029,12 +1032,19 @@ get_sql_insert(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval tuple = get_tuple_of_interest(relid, pkattnums, pknumatts, src_pkattvals); appendStringInfo(str, "INSERT INTO %s(", quote_ident_cstr(relname)); + + needComma = false; for (i = 0; i < natts; i++) { - if (i > 0) + if (tupdesc->attrs[i]->attisdropped) + continue; + + if (needComma) appendStringInfo(str, ","); - appendStringInfo(str, NameStr(tupdesc->attrs[i]->attname)); + appendStringInfo(str, "%s", + quote_ident_cstr(NameStr(tupdesc->attrs[i]->attname))); + needComma = true; } appendStringInfo(str, ") VALUES("); @@ -1042,9 +1052,13 @@ get_sql_insert(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval /* * remember attvals are 1 based */ + needComma = false; for (i = 0; i < natts; i++) { - if (i > 0) + if (tupdesc->attrs[i]->attisdropped) + continue; + + if (needComma) appendStringInfo(str, ","); if (tgt_pkattvals != NULL) @@ -1059,11 +1073,12 @@ get_sql_insert(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval if (val != NULL) { - appendStringInfo(str, quote_literal_cstr(val)); + appendStringInfo(str, "%s", quote_literal_cstr(val)); pfree(val); } else appendStringInfo(str, "NULL"); + needComma = true; } appendStringInfo(str, ")"); @@ -1083,9 +1098,9 @@ get_sql_delete(Oid relid, int16 *pkattnums, int16 pknumatts, char **tgt_pkattval TupleDesc tupdesc; int natts; StringInfo str = makeStringInfo(); - char *sql = NULL; - char *val = NULL; - unsigned int i; + char *sql; + char *val; + int i; /* * Open relation using relid @@ -1103,21 +1118,24 @@ get_sql_delete(Oid relid, int16 *pkattnums, int16 pknumatts, char **tgt_pkattval if (i > 0) appendStringInfo(str, " AND "); - appendStringInfo(str, NameStr(tupdesc->attrs[pkattnum - 1]->attname)); + appendStringInfo(str, "%s", + quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum - 1]->attname))); if (tgt_pkattvals != NULL) val = pstrdup(tgt_pkattvals[i]); else + { elog(ERROR, "Target key array must not be NULL"); + val = NULL; /* keep compiler quiet */ + } if (val != NULL) { - appendStringInfo(str, "="); - appendStringInfo(str, quote_literal_cstr(val)); + appendStringInfo(str, " = %s", quote_literal_cstr(val)); pfree(val); } else - appendStringInfo(str, "IS NULL"); + appendStringInfo(str, " IS NULL"); } sql = pstrdup(str->data); @@ -1137,10 +1155,11 @@ get_sql_update(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval TupleDesc tupdesc; int natts; StringInfo str = makeStringInfo(); - char *sql = NULL; - char *val = NULL; + char *sql; + char *val; int16 key; int i; + bool needComma; /* * Open relation using relid @@ -1154,13 +1173,17 @@ get_sql_update(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval appendStringInfo(str, "UPDATE %s SET ", quote_ident_cstr(relname)); + needComma = false; for (i = 0; i < natts; i++) { - if (i > 0) - appendStringInfo(str, ","); + if (tupdesc->attrs[i]->attisdropped) + continue; - appendStringInfo(str, NameStr(tupdesc->attrs[i]->attname)); - appendStringInfo(str, "="); + if (needComma) + appendStringInfo(str, ", "); + + appendStringInfo(str, "%s = ", + quote_ident_cstr(NameStr(tupdesc->attrs[i]->attname))); if (tgt_pkattvals != NULL) key = get_attnum_pk_pos(pkattnums, pknumatts, i + 1); @@ -1174,11 +1197,12 @@ get_sql_update(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval if (val != NULL) { - appendStringInfo(str, quote_literal_cstr(val)); + appendStringInfo(str, "%s", quote_literal_cstr(val)); pfree(val); } else appendStringInfo(str, "NULL"); + needComma = true; } appendStringInfo(str, " WHERE "); @@ -1190,7 +1214,8 @@ get_sql_update(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval if (i > 0) appendStringInfo(str, " AND "); - appendStringInfo(str, NameStr(tupdesc->attrs[pkattnum - 1]->attname)); + appendStringInfo(str, "%s", + quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum - 1]->attname))); if (tgt_pkattvals != NULL) val = pstrdup(tgt_pkattvals[i]); @@ -1199,12 +1224,11 @@ get_sql_update(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval if (val != NULL) { - appendStringInfo(str, "="); - appendStringInfo(str, quote_literal_cstr(val)); + appendStringInfo(str, " = %s", quote_literal_cstr(val)); pfree(val); } else - appendStringInfo(str, "IS NULL"); + appendStringInfo(str, " IS NULL"); } sql = pstrdup(str->data); @@ -1297,7 +1321,7 @@ get_tuple_of_interest(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_p * Build sql statement to look up tuple of interest * Use src_pkattvals as the criteria. */ - appendStringInfo(str, "SELECT * from %s WHERE ", relname); + appendStringInfo(str, "SELECT * FROM %s WHERE ", quote_ident_cstr(relname)); for (i = 0; i < pknumatts; i++) { @@ -1306,17 +1330,17 @@ get_tuple_of_interest(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_p if (i > 0) appendStringInfo(str, " AND "); - appendStringInfo(str, NameStr(tupdesc->attrs[pkattnum - 1]->attname)); + appendStringInfo(str, "%s", + quote_ident_cstr(NameStr(tupdesc->attrs[pkattnum - 1]->attname))); val = pstrdup(src_pkattvals[i]); if (val != NULL) { - appendStringInfo(str, "="); - appendStringInfo(str, quote_literal_cstr(val)); + appendStringInfo(str, " = %s", quote_literal_cstr(val)); pfree(val); } else - appendStringInfo(str, "IS NULL"); + appendStringInfo(str, " IS NULL"); } sql = pstrdup(str->data); diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 8bf4bf816f..573815388f 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1,6 +1,6 @@ @@ -810,6 +810,17 @@ + + attisdropped + bool + + + This column has been dropped and is no longer valid. A dropped + column is still physically present in the table, but is + ignored by the parser and so cannot be accessed via SQL. + + + diff --git a/doc/src/sgml/ref/alter_table.sgml b/doc/src/sgml/ref/alter_table.sgml index 11da9fdf60..0bfe88cf54 100644 --- a/doc/src/sgml/ref/alter_table.sgml +++ b/doc/src/sgml/ref/alter_table.sgml @@ -1,5 +1,5 @@ @@ -23,6 +23,8 @@ PostgreSQL documentation ALTER TABLE [ ONLY ] table [ * ] ADD [ COLUMN ] column type [ column_constraint [ ... ] ] +ALTER TABLE [ ONLY ] table [ * ] + DROP [ COLUMN ] column [ RESTRICT | CASCADE ] ALTER TABLE [ ONLY ] table [ * ] ALTER [ COLUMN ] column { SET DEFAULT value | DROP DEFAULT } ALTER TABLE [ ONLY ] table [ * ] @@ -126,6 +128,26 @@ ALTER TABLE table + + CASCADE + + + Automatically drop objects that depend on the dropped column + or constraint (for example, views referencing the column). + + + + + + RESTRICT + + + Refuse to drop the column or constraint if there are any dependent + objects. This is the default behavior. + + + + @@ -186,6 +208,19 @@ ALTER TABLE table + + DROP COLUMN + + + This form drops a column from a table. Note that indexes and + table constraints involving the column will be automatically + dropped as well. You will need to say CASCADE if + anything outside the table depends on the column --- for example, + foreign key references, views, etc. + + + + SET/DROP DEFAULT @@ -317,6 +352,22 @@ ALTER TABLE table form after you've entered non-null values for the column in all rows. + + The DROP COLUMN command does not physically remove + the column, but simply makes it invisible to SQL operations. Subsequent + inserts and updates of the table will store a NULL for the column. + Thus, dropping a column is quick but it will not immediately reduce the + on-disk size of your table, as the space occupied + by the dropped column is not reclaimed. The space will be + reclaimed over time as existing rows are updated. + To reclaim the space at once, do a dummy UPDATE of all rows + and then vacuum, as in: + +UPDATE table SET col = col; +VACUUM FULL table; + + + Changing any part of the schema of a system catalog is not permitted. @@ -342,6 +393,13 @@ ALTER TABLE distributors ADD COLUMN address VARCHAR(30); + + To drop a column from a table: + +ALTER TABLE distributors DROP COLUMN address RESTRICT; + + + To rename an existing column: @@ -420,38 +478,6 @@ ALTER TABLE distributors ADD PRIMARY KEY (dist_id); The ALTER COLUMN form is in full compliance. - - SQL92 specifies some additional capabilities for ALTER TABLE - statement which are not yet directly supported by PostgreSQL: - - - - - -ALTER TABLE table DROP [ COLUMN ] column { RESTRICT | CASCADE } - - - - - Removes a column from a table. - Currently, to remove an existing column the table must be - recreated and reloaded: - -CREATE TABLE temp AS SELECT did, city FROM distributors; -DROP TABLE distributors; -CREATE TABLE distributors ( - did DECIMAL(3) DEFAULT 1, - name VARCHAR(40) NOT NULL -); -INSERT INTO distributors SELECT * FROM temp; -DROP TABLE temp; - - - - - - - The clauses to rename tables, columns, indexes, and sequences are PostgreSQL extensions from SQL92. diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml index 484b0a6208..d09b6706dd 100644 --- a/doc/src/sgml/ref/copy.sgml +++ b/doc/src/sgml/ref/copy.sgml @@ -1,5 +1,5 @@ @@ -21,16 +21,14 @@ PostgreSQL documentation 1999-12-11 -COPY table - [ ( column [, ...] ) ] +COPY table [ ( column [, ...] ) ] FROM { 'filename' | stdin } [ [ WITH ] [ BINARY ] [ OIDS ] [ DELIMITER [ AS ] 'delimiter' ] [ NULL [ AS ] 'null string' ] ] -COPY table - [ ( column [, ...] ) ] +COPY table [ ( column [, ...] ) ] TO { 'filename' | stdout } [ [ WITH ] [ BINARY ] @@ -201,10 +199,10 @@ ERROR: reason If a list of columns is specified, COPY will - only copy the data in the specified columns to or from the table. - If there are any columns in the table that are not in the table, - COPY FROM will insert the default value for - that column. + only copy the data in the specified columns to or from the file. + If there are any columns in the table that are not in the file, + COPY FROM will insert the default values for + those columns. @@ -266,8 +264,8 @@ ERROR: reason - COPY FROM will invoke any triggers or check - constraints. However, it will not invoke rules. + COPY FROM will invoke any triggers and check + constraints on the destination table. However, it will not invoke rules. @@ -330,12 +328,9 @@ ERROR: reason The attribute values themselves are strings generated by the output function, or acceptable to the input function, of each attribute's data type. The specified null-value string is used in - place of attributes that are NULL. When using COPY - FROM without a column list, each row of the input file - must contain data for each attribute in the table: no missing data - is allowed. Similarly, COPY FROM will raise - an error if it encounters any data in the input file that would - not be inserted into the table: extra data is not allowed. + place of attributes that are NULL. + COPY FROM will raise an error if any line of the + input file contains more or fewer columns than are expected. If OIDS is specified, the OID is read or written as the first column, diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml index af82154d8c..0da3d9ef29 100644 --- a/doc/src/sgml/release.sgml +++ b/doc/src/sgml/release.sgml @@ -1,5 +1,5 @@ @@ -24,6 +24,8 @@ CDATA means the content is "SGML-free", so you can write without worries about funny characters. --> natts; i++) { desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); - memmove(desc->attrs[i], + memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE); desc->attrs[i]->attnotnull = false; @@ -146,7 +146,7 @@ CreateTupleDescCopyConstr(TupleDesc tupdesc) for (i = 0; i < desc->natts; i++) { desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); - memmove(desc->attrs[i], + memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE); } @@ -263,6 +263,8 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) return false; if (attr1->attnotnull != attr2->attnotnull) return false; + if (attr1->attisdropped != attr2->attisdropped) + return false; } if (tupdesc1->constr != NULL) { @@ -385,6 +387,7 @@ TupleDescInitEntry(TupleDesc desc, att->attnotnull = false; att->atthasdef = false; + att->attisdropped = false; tuple = SearchSysCache(TYPEOID, ObjectIdGetDatum(oidtypeid), diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index 4300c0211d..f48c8389ce 100644 --- a/src/backend/bootstrap/bootstrap.c +++ b/src/backend/bootstrap/bootstrap.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.133 2002/07/20 05:16:56 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.134 2002/08/02 18:15:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -522,19 +522,6 @@ boot_openrel(char *relname) (char *) boot_reldesc->rd_att->attrs[i], ATTRIBUTE_TUPLE_SIZE); - /* Some old pg_attribute tuples might not have attisset. */ - - /* - * If the attname is attisset, don't look for it - it may not be - * defined yet. - */ - if (namestrcmp(&attrtypes[i]->attname, "attisset") == 0) - attrtypes[i]->attisset = - get_attisset(RelationGetRelid(boot_reldesc), - NameStr(attrtypes[i]->attname)); - else - attrtypes[i]->attisset = false; - { Form_pg_attribute at = attrtypes[i]; @@ -598,15 +585,19 @@ DefineAttr(char *name, char *type, int attnum) closerel(relname); } - typeoid = gettype(type); if (attrtypes[attnum] == (Form_pg_attribute) NULL) attrtypes[attnum] = AllocateAttribute(); + MemSet(attrtypes[attnum], 0, ATTRIBUTE_TUPLE_SIZE); + + namestrcpy(&attrtypes[attnum]->attname, name); + elog(DEBUG3, "column %s %s", NameStr(attrtypes[attnum]->attname), type); + attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */ + + typeoid = gettype(type); + if (Typ != (struct typmap **) NULL) { attrtypes[attnum]->atttypid = Ap->am_oid; - namestrcpy(&attrtypes[attnum]->attname, name); - elog(DEBUG3, "column %s %s", NameStr(attrtypes[attnum]->attname), type); - attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */ attlen = attrtypes[attnum]->attlen = Ap->am_typ.typlen; attrtypes[attnum]->attbyval = Ap->am_typ.typbyval; attrtypes[attnum]->attstorage = Ap->am_typ.typstorage; @@ -615,9 +606,6 @@ DefineAttr(char *name, char *type, int attnum) else { attrtypes[attnum]->atttypid = Procid[typeoid].oid; - namestrcpy(&attrtypes[attnum]->attname, name); - elog(DEBUG3, "column %s %s", NameStr(attrtypes[attnum]->attname), type); - attrtypes[attnum]->attnum = 1 + attnum; /* fillatt */ attlen = attrtypes[attnum]->attlen = Procid[typeoid].len; /* @@ -656,6 +644,23 @@ DefineAttr(char *name, char *type, int attnum) } attrtypes[attnum]->attcacheoff = -1; attrtypes[attnum]->atttypmod = -1; + /* + * Mark as "not null" if type is fixed-width and prior columns are too. + * This corresponds to case where column can be accessed directly via + * C struct declaration. + */ + if (attlen > 0) + { + int i; + + for (i = 0; i < attnum; i++) + { + if (attrtypes[i]->attlen <= 0) + break; + } + if (i == attnum) + attrtypes[attnum]->attnotnull = true; + } } @@ -896,8 +901,8 @@ gettype(char *type) * AllocateAttribute * ---------------- */ -static Form_pg_attribute /* XXX */ -AllocateAttribute() +static Form_pg_attribute +AllocateAttribute(void) { Form_pg_attribute attribute = (Form_pg_attribute) malloc(ATTRIBUTE_TUPLE_SIZE); diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index ae88c4bf05..d51c8d589a 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.7 2002/07/29 22:14:10 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.8 2002/08/02 18:15:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -567,7 +567,8 @@ doDeletion(const ObjectAddress *object) else { if (object->objectSubId != 0) - elog(ERROR, "DROP COLUMN not implemented yet"); + RemoveAttributeById(object->objectId, + object->objectSubId); else heap_drop_with_catalog(object->objectId); } diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 6045c17bb6..ec9165c55b 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.214 2002/07/31 17:19:51 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.215 2002/08/02 18:15:05 tgl Exp $ * * * INTERFACE ROUTINES @@ -97,37 +97,37 @@ static void RemoveStatistics(Relation rel); static FormData_pg_attribute a1 = { 0, {"ctid"}, TIDOID, 0, sizeof(ItemPointerData), SelfItemPointerAttributeNumber, 0, -1, -1, - false, 'p', false, 'i', true, false + false, 'p', false, 'i', true, false, false }; static FormData_pg_attribute a2 = { 0, {"oid"}, OIDOID, 0, sizeof(Oid), ObjectIdAttributeNumber, 0, -1, -1, - true, 'p', false, 'i', true, false + true, 'p', false, 'i', true, false, false }; static FormData_pg_attribute a3 = { 0, {"xmin"}, XIDOID, 0, sizeof(TransactionId), MinTransactionIdAttributeNumber, 0, -1, -1, - true, 'p', false, 'i', true, false + true, 'p', false, 'i', true, false, false }; static FormData_pg_attribute a4 = { 0, {"cmin"}, CIDOID, 0, sizeof(CommandId), MinCommandIdAttributeNumber, 0, -1, -1, - true, 'p', false, 'i', true, false + true, 'p', false, 'i', true, false, false }; static FormData_pg_attribute a5 = { 0, {"xmax"}, XIDOID, 0, sizeof(TransactionId), MaxTransactionIdAttributeNumber, 0, -1, -1, - true, 'p', false, 'i', true, false + true, 'p', false, 'i', true, false, false }; static FormData_pg_attribute a6 = { 0, {"cmax"}, CIDOID, 0, sizeof(CommandId), MaxCommandIdAttributeNumber, 0, -1, -1, - true, 'p', false, 'i', true, false + true, 'p', false, 'i', true, false, false }; /* @@ -139,7 +139,7 @@ static FormData_pg_attribute a6 = { static FormData_pg_attribute a7 = { 0, {"tableoid"}, OIDOID, 0, sizeof(Oid), TableOidAttributeNumber, 0, -1, -1, - true, 'p', false, 'i', true, false + true, 'p', false, 'i', true, false, false }; static Form_pg_attribute SysAtt[] = {&a1, &a2, &a3, &a4, &a5, &a6, &a7}; @@ -892,6 +892,78 @@ DeleteAttributeTuples(Oid relid) heap_close(attrel, RowExclusiveLock); } +/* + * RemoveAttributeById + * + * This is the guts of ALTER TABLE DROP COLUMN: actually mark the attribute + * deleted in pg_attribute. (Everything else needed, such as getting rid + * of any pg_attrdef entry, is handled by dependency.c.) + */ +void +RemoveAttributeById(Oid relid, AttrNumber attnum) +{ + Relation rel; + Relation attr_rel; + HeapTuple tuple; + Form_pg_attribute attStruct; + char newattname[NAMEDATALEN]; + + /* + * Grab an exclusive lock on the target table, which we will NOT + * release until end of transaction. (In the simple case where + * we are directly dropping this column, AlterTableDropColumn already + * did this ... but when cascading from a drop of some other object, + * we may not have any lock.) + */ + rel = heap_open(relid, AccessExclusiveLock); + + attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock); + + tuple = SearchSysCacheCopy(ATTNUM, + ObjectIdGetDatum(relid), + Int16GetDatum(attnum), + 0, 0); + if (!HeapTupleIsValid(tuple)) /* shouldn't happen */ + elog(ERROR, "RemoveAttributeById: Failed to find attribute %d in relation %u", + attnum, relid); + attStruct = (Form_pg_attribute) GETSTRUCT(tuple); + + /* Mark the attribute as dropped */ + attStruct->attisdropped = true; + + /* Remove any NOT NULL constraint the column may have */ + attStruct->attnotnull = false; + + /* We don't want to keep stats for it anymore */ + attStruct->attstattarget = 0; + + /* Change the column name to something that isn't likely to conflict */ + snprintf(newattname, NAMEDATALEN, "........pg.dropped.%d........", attnum); + namestrcpy(&(attStruct->attname), newattname); + + simple_heap_update(attr_rel, &tuple->t_self, tuple); + + /* keep the system catalog indices current */ + if (RelationGetForm(attr_rel)->relhasindex) + { + Relation idescs[Num_pg_attr_indices]; + + CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs); + CatalogIndexInsert(idescs, Num_pg_attr_indices, attr_rel, tuple); + CatalogCloseIndices(Num_pg_attr_indices, idescs); + } + + /* + * Because updating the pg_attribute row will trigger a relcache flush + * for the target relation, we need not do anything else to notify + * other backends of the change. + */ + + heap_close(attr_rel, RowExclusiveLock); + + heap_close(rel, NoLock); +} + /* * RemoveAttrDefault * diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 2a11474e9f..2624fdaf25 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.81 2002/07/24 19:11:09 petere Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.82 2002/08/02 18:15:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -327,9 +327,9 @@ checkretval(Oid rettype, List *queryTreeList) Oid typerelid; Oid restype; Relation reln; - Oid relid; - int relnatts; - int i; + int relnatts; /* physical number of columns in rel */ + int rellogcols; /* # of nondeleted columns in rel */ + int colindex; /* physical column index */ /* guard against empty function body; OK only if no return type */ if (queryTreeList == NIL) @@ -404,42 +404,55 @@ checkretval(Oid rettype, List *queryTreeList) /* * By here, the procedure returns a tuple or set of tuples. This part * of the typechecking is a hack. We look up the relation that is the - * declared return type, and be sure that attributes 1 .. n in the - * target list match the declared types. + * declared return type, and scan the non-deleted attributes to ensure + * that they match the datatypes of the non-resjunk columns. */ reln = heap_open(typerelid, AccessShareLock); - relid = reln->rd_id; relnatts = reln->rd_rel->relnatts; + rellogcols = 0; /* we'll count nondeleted cols as we go */ + colindex = 0; - if (tlistlen != relnatts) - elog(ERROR, "function declared to return %s does not SELECT the right number of columns (%d)", - format_type_be(rettype), relnatts); - - /* expect attributes 1 .. n in order */ - i = 0; foreach(tlistitem, tlist) { TargetEntry *tle = (TargetEntry *) lfirst(tlistitem); + Form_pg_attribute attr; Oid tletype; Oid atttype; if (tle->resdom->resjunk) continue; + + do { + colindex++; + if (colindex > relnatts) + elog(ERROR, "function declared to return %s does not SELECT the right number of columns (%d)", + format_type_be(rettype), rellogcols); + attr = reln->rd_att->attrs[colindex - 1]; + } while (attr->attisdropped); + rellogcols++; + tletype = exprType(tle->expr); - atttype = reln->rd_att->attrs[i]->atttypid; + atttype = attr->atttypid; if (!IsBinaryCompatible(tletype, atttype)) elog(ERROR, "function declared to return %s returns %s instead of %s at column %d", format_type_be(rettype), format_type_be(tletype), format_type_be(atttype), - i + 1); - i++; + rellogcols); } - /* this shouldn't happen, but let's just check... */ - if (i != relnatts) + for (;;) + { + colindex++; + if (colindex > relnatts) + break; + if (!reln->rd_att->attrs[colindex - 1]->attisdropped) + rellogcols++; + } + + if (tlistlen != rellogcols) elog(ERROR, "function declared to return %s does not SELECT the right number of columns (%d)", - format_type_be(rettype), relnatts); + format_type_be(rettype), rellogcols); heap_close(reln, AccessShareLock); } diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 55069aa6fe..9844a5df0a 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.39 2002/07/31 17:19:51 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.40 2002/08/02 18:15:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -27,6 +27,7 @@ #include "commands/vacuum.h" #include "miscadmin.h" #include "parser/parse_oper.h" +#include "parser/parse_relation.h" #include "utils/acl.h" #include "utils/builtins.h" #include "utils/datum.h" @@ -147,7 +148,6 @@ void analyze_rel(Oid relid, VacuumStmt *vacstmt) { Relation onerel; - Form_pg_attribute *attr; int attr_cnt, tcnt, i; @@ -234,9 +234,6 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt) * * Note that system attributes are never analyzed. */ - attr = onerel->rd_att->attrs; - attr_cnt = onerel->rd_att->natts; - if (vacstmt->va_cols != NIL) { List *le; @@ -248,15 +245,8 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt) { char *col = strVal(lfirst(le)); - for (i = 0; i < attr_cnt; i++) - { - if (namestrcmp(&(attr[i]->attname), col) == 0) - break; - } - if (i >= attr_cnt) - elog(ERROR, "ANALYZE: there is no attribute %s in %s", - col, RelationGetRelationName(onerel)); - vacattrstats[tcnt] = examine_attribute(onerel, i + 1); + i = attnameAttNum(onerel, col, false); + vacattrstats[tcnt] = examine_attribute(onerel, i); if (vacattrstats[tcnt] != NULL) tcnt++; } @@ -264,12 +254,13 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt) } else { + attr_cnt = onerel->rd_att->natts; vacattrstats = (VacAttrStats **) palloc(attr_cnt * sizeof(VacAttrStats *)); tcnt = 0; - for (i = 0; i < attr_cnt; i++) + for (i = 1; i <= attr_cnt; i++) { - vacattrstats[tcnt] = examine_attribute(onerel, i + 1); + vacattrstats[tcnt] = examine_attribute(onerel, i); if (vacattrstats[tcnt] != NULL) tcnt++; } @@ -388,6 +379,10 @@ examine_attribute(Relation onerel, int attnum) Oid ltopr = InvalidOid; VacAttrStats *stats; + /* Don't analyze dropped columns */ + if (attr->attisdropped) + return NULL; + /* Don't analyze column if user has specified not to */ if (attr->attstattarget == 0) return NULL; diff --git a/src/backend/commands/comment.c b/src/backend/commands/comment.c index c5dee8f8af..118c2c4b77 100644 --- a/src/backend/commands/comment.c +++ b/src/backend/commands/comment.c @@ -7,7 +7,7 @@ * Copyright (c) 1996-2001, PostgreSQL Global Development Group * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.53 2002/07/29 23:46:35 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.54 2002/08/02 18:15:05 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -382,8 +382,8 @@ CommentAttribute(List *qualname, char *comment) attnum = get_attnum(RelationGetRelid(relation), attrname); if (attnum == InvalidAttrNumber) - elog(ERROR, "\"%s\" is not an attribute of class \"%s\"", - attrname, RelationGetRelationName(relation)); + elog(ERROR, "Relation \"%s\" has no column \"%s\"", + RelationGetRelationName(relation), attrname); /* Create the comment using the relation's oid */ diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 19e17ed287..2529b72823 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.161 2002/07/30 16:55:06 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.162 2002/08/02 18:15:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -31,6 +31,7 @@ #include "rewrite/rewriteHandler.h" #include "libpq/libpq.h" #include "miscadmin.h" +#include "parser/parse_relation.h" #include "tcop/pquery.h" #include "tcop/tcopprot.h" #include "utils/acl.h" @@ -53,13 +54,15 @@ typedef enum CopyReadResult } CopyReadResult; /* non-export function prototypes */ -static void CopyTo(Relation rel, List *attlist, bool binary, bool oids, FILE *fp, char *delim, char *null_print); -static void CopyFrom(Relation rel, List *attlist, bool binary, bool oids, FILE *fp, char *delim, char *null_print); +static void CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, + FILE *fp, char *delim, char *null_print); +static void CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, + FILE *fp, char *delim, char *null_print); static Oid GetInputFunction(Oid type); static Oid GetTypeElement(Oid type); static char *CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result); static void CopyAttributeOut(FILE *fp, char *string, char *delim); -static void CopyCheckAttlist(Relation rel, List *attlist); +static List *CopyGetAttnums(Relation rel, List *attnamelist); static const char BinarySignature[12] = "PGBCOPY\n\377\r\n\0"; @@ -275,7 +278,8 @@ DoCopy(const CopyStmt *stmt) bool is_from = stmt->is_from; bool pipe = (stmt->filename == NULL); List *option; - List *attlist = stmt->attlist; + List *attnamelist = stmt->attlist; + List *attnumlist; bool binary = false; bool oids = false; char *delim = NULL; @@ -373,6 +377,11 @@ DoCopy(const CopyStmt *stmt) elog(ERROR, "COPY: table \"%s\" does not have OIDs", RelationGetRelationName(rel)); + /* + * Generate or convert list of attributes to process + */ + attnumlist = CopyGetAttnums(rel, attnamelist); + /* * Set up variables to avoid per-attribute overhead. */ @@ -382,26 +391,6 @@ DoCopy(const CopyStmt *stmt) server_encoding = GetDatabaseEncoding(); #endif - if (attlist == NIL) - { - /* get list of attributes in the relation */ - TupleDesc desc = RelationGetDescr(rel); - int i; - for (i = 0; i < desc->natts; ++i) - { - Ident *id = makeNode(Ident); - id->name = NameStr(desc->attrs[i]->attname); - attlist = lappend(attlist,id); - } - } - else - { - if (binary) - elog(ERROR,"COPY: BINARY format cannot be used with specific column list"); - - CopyCheckAttlist(rel, attlist); - } - if (is_from) { /* copy from file to database */ if (rel->rd_rel->relkind != RELKIND_RELATION) @@ -442,10 +431,10 @@ DoCopy(const CopyStmt *stmt) if (S_ISDIR(st.st_mode)) { FreeFile(fp); - elog(ERROR, "COPY: %s is a directory.", filename); + elog(ERROR, "COPY: %s is a directory", filename); } } - CopyFrom(rel, attlist, binary, oids, fp, delim, null_print); + CopyFrom(rel, attnumlist, binary, oids, fp, delim, null_print); } else { /* copy from database to file */ @@ -483,7 +472,7 @@ DoCopy(const CopyStmt *stmt) */ if (filename[0] != '/') elog(ERROR, "Relative path not allowed for server side" - " COPY command."); + " COPY command"); oumask = umask((mode_t) 022); fp = AllocateFile(filename, PG_BINARY_W); @@ -498,10 +487,10 @@ DoCopy(const CopyStmt *stmt) if (S_ISDIR(st.st_mode)) { FreeFile(fp); - elog(ERROR, "COPY: %s is a directory.", filename); + elog(ERROR, "COPY: %s is a directory", filename); } } - CopyTo(rel, attlist, binary, oids, fp, delim, null_print); + CopyTo(rel, attnumlist, binary, oids, fp, delim, null_print); } if (!pipe) @@ -529,14 +518,14 @@ DoCopy(const CopyStmt *stmt) * Copy from relation TO file. */ static void -CopyTo(Relation rel, List *attlist, bool binary, bool oids, +CopyTo(Relation rel, List *attnumlist, bool binary, bool oids, FILE *fp, char *delim, char *null_print) { HeapTuple tuple; TupleDesc tupDesc; HeapScanDesc scandesc; - int attr_count, - i; + int num_phys_attrs; + int attr_count; Form_pg_attribute *attr; FmgrInfo *out_functions; Oid *elements; @@ -544,48 +533,33 @@ CopyTo(Relation rel, List *attlist, bool binary, bool oids, int16 fld_size; char *string; Snapshot mySnapshot; - int copy_attr_count; - int *attmap; - int p = 0; List *cur; tupDesc = rel->rd_att; - attr_count = rel->rd_att->natts; - attr = rel->rd_att->attrs; - - copy_attr_count = length(attlist); - attmap = (int *) palloc(copy_attr_count * sizeof(int)); - - foreach(cur, attlist) - { - const char *currAtt = strVal(lfirst(cur)); - - for (i = 0; i < attr_count; i++) - { - if (namestrcmp(&attr[i]->attname, currAtt) == 0) - { - attmap[p++] = i; - continue; - } - } - } + attr = tupDesc->attrs; + num_phys_attrs = tupDesc->natts; + attr_count = length(attnumlist); /* + * Get info about the columns we need to process. + * * For binary copy we really only need isvarlena, but compute it * all... */ - out_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo)); - elements = (Oid *) palloc(attr_count * sizeof(Oid)); - isvarlena = (bool *) palloc(attr_count * sizeof(bool)); - for (i = 0; i < attr_count; i++) + out_functions = (FmgrInfo *) palloc(num_phys_attrs * sizeof(FmgrInfo)); + elements = (Oid *) palloc(num_phys_attrs * sizeof(Oid)); + isvarlena = (bool *) palloc(num_phys_attrs * sizeof(bool)); + foreach(cur, attnumlist) { + int attnum = lfirsti(cur); Oid out_func_oid; - if (!getTypeOutputInfo(attr[i]->atttypid, - &out_func_oid, &elements[i], &isvarlena[i])) + if (!getTypeOutputInfo(attr[attnum-1]->atttypid, + &out_func_oid, &elements[attnum-1], + &isvarlena[attnum-1])) elog(ERROR, "COPY: couldn't lookup info for type %u", - attr[i]->atttypid); - fmgr_info(out_func_oid, &out_functions[i]); + attr[attnum-1]->atttypid); + fmgr_info(out_func_oid, &out_functions[attnum-1]); } if (binary) @@ -650,14 +624,14 @@ CopyTo(Relation rel, List *attlist, bool binary, bool oids, } } - for (i = 0; i < copy_attr_count; i++) + foreach(cur, attnumlist) { + int attnum = lfirsti(cur); Datum origvalue, value; bool isnull; - int mi = attmap[i]; - origvalue = heap_getattr(tuple, mi + 1, tupDesc, &isnull); + origvalue = heap_getattr(tuple, attnum, tupDesc, &isnull); if (!binary) { @@ -686,25 +660,25 @@ CopyTo(Relation rel, List *attlist, bool binary, bool oids, * (or for binary case, becase we must output untoasted * value). */ - if (isvarlena[mi]) + if (isvarlena[attnum-1]) value = PointerGetDatum(PG_DETOAST_DATUM(origvalue)); else value = origvalue; if (!binary) { - string = DatumGetCString(FunctionCall3(&out_functions[mi], + string = DatumGetCString(FunctionCall3(&out_functions[attnum-1], value, - ObjectIdGetDatum(elements[mi]), - Int32GetDatum(attr[mi]->atttypmod))); + ObjectIdGetDatum(elements[attnum-1]), + Int32GetDatum(attr[attnum-1]->atttypmod))); CopyAttributeOut(fp, string, delim); pfree(string); } else { - fld_size = attr[mi]->attlen; + fld_size = attr[attnum-1]->attlen; CopySendData(&fld_size, sizeof(int16), fp); - if (isvarlena[mi]) + if (isvarlena[attnum-1]) { /* varlena */ Assert(fld_size == -1); @@ -712,7 +686,7 @@ CopyTo(Relation rel, List *attlist, bool binary, bool oids, VARSIZE(value), fp); } - else if (!attr[mi]->attbyval) + else if (!attr[attnum-1]->attbyval) { /* fixed-length pass-by-reference */ Assert(fld_size > 0); @@ -767,36 +741,36 @@ CopyTo(Relation rel, List *attlist, bool binary, bool oids, * Copy FROM file to relation. */ static void -CopyFrom(Relation rel, List *attlist, bool binary, bool oids, +CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids, FILE *fp, char *delim, char *null_print) { HeapTuple tuple; TupleDesc tupDesc; Form_pg_attribute *attr; - AttrNumber attr_count, copy_attr_count, def_attr_count; + AttrNumber num_phys_attrs, attr_count, num_defaults; FmgrInfo *in_functions; Oid *elements; int i; + List *cur; Oid in_func_oid; Datum *values; char *nulls; - int done = 0; + bool done = false; ResultRelInfo *resultRelInfo; EState *estate = CreateExecutorState(); /* for ExecConstraints() */ TupleTable tupleTable; TupleTableSlot *slot; bool file_has_oids; - int *attmap = NULL; - int *defmap = NULL; - Node **defexprs = NULL; /* array of default att expressions */ + int *defmap; + Node **defexprs; /* array of default att expressions */ ExprContext *econtext; /* used for ExecEvalExpr for default atts */ - ExprDoneCond isdone; + MemoryContext oldcontext = CurrentMemoryContext; tupDesc = RelationGetDescr(rel); attr = tupDesc->attrs; - attr_count = tupDesc->natts; - copy_attr_count = length(attlist); - def_attr_count = 0; + num_phys_attrs = tupDesc->natts; + attr_count = length(attnumlist); + num_defaults = 0; /* * We need a ResultRelInfo so we can use the regular executor's @@ -819,50 +793,40 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids, slot = ExecAllocTableSlot(tupleTable); ExecSetSlotDescriptor(slot, tupDesc, false); - if (!binary) + /* + * pick up the input function and default expression (if any) for + * each attribute in the relation. (We don't actually use the + * input function if it's a binary copy.) + */ + defmap = (int *) palloc(sizeof(int) * num_phys_attrs); + defexprs = (Node **) palloc(sizeof(Node *) * num_phys_attrs); + in_functions = (FmgrInfo *) palloc(num_phys_attrs * sizeof(FmgrInfo)); + elements = (Oid *) palloc(num_phys_attrs * sizeof(Oid)); + + for (i = 0; i < num_phys_attrs; i++) { - /* - * pick up the input function and default expression (if any) for - * each attribute in the relation. - */ - attmap = (int *) palloc(sizeof(int) * attr_count); - defmap = (int *) palloc(sizeof(int) * attr_count); - defexprs = (Node **) palloc(sizeof(Node *) * attr_count); - in_functions = (FmgrInfo *) palloc(attr_count * sizeof(FmgrInfo)); - elements = (Oid *) palloc(attr_count * sizeof(Oid)); - for (i = 0; i < attr_count; i++) + /* We don't need info for dropped attributes */ + if (attr[i]->attisdropped) + continue; + + in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid); + fmgr_info(in_func_oid, &in_functions[i]); + elements[i] = GetTypeElement(attr[i]->atttypid); + + /* if column not specified, use default value if one exists */ + if (!intMember(i + 1, attnumlist)) { - List *l; - int p = 0; - bool specified = false; - - in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid); - fmgr_info(in_func_oid, &in_functions[i]); - elements[i] = GetTypeElement(attr[i]->atttypid); - - foreach(l, attlist) + defexprs[num_defaults] = build_column_default(rel, i + 1); + if (defexprs[num_defaults] != NULL) { - if (namestrcmp(&attr[i]->attname, strVal(lfirst(l))) == 0) - { - attmap[p] = i; - specified = true; - continue; - } - p++; - } - - /* if column not specified, use default value if one exists */ - if (! specified) - { - defexprs[def_attr_count] = build_column_default(rel, i + 1); - - if (defexprs[def_attr_count] != NULL) - { - defmap[def_attr_count] = i; - def_attr_count++; - } + defmap[num_defaults] = i; + num_defaults++; } } + } + + if (!binary) + { file_has_oids = oids; /* must rely on user to tell us this... */ } else @@ -898,13 +862,10 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids, if (CopyGetEof(fp)) elog(ERROR, "COPY BINARY: bogus file header (wrong length)"); } - - in_functions = NULL; - elements = NULL; } - values = (Datum *) palloc(attr_count * sizeof(Datum)); - nulls = (char *) palloc(attr_count * sizeof(char)); + values = (Datum *) palloc(num_phys_attrs * sizeof(Datum)); + nulls = (char *) palloc(num_phys_attrs * sizeof(char)); copy_lineno = 0; fe_eof = false; @@ -914,58 +875,77 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids, while (!done) { bool skip_tuple; - Oid loaded_oid; + Oid loaded_oid = InvalidOid; CHECK_FOR_INTERRUPTS(); copy_lineno++; - /* Reset the per-output-tuple exprcontext */ + /* Reset the per-tuple exprcontext */ ResetPerTupleExprContext(estate); + /* Switch to and reset per-tuple memory context, too */ + MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); + MemoryContextReset(CurrentMemoryContext); + /* Initialize all values for row to NULL */ - MemSet(values, 0, attr_count * sizeof(Datum)); - MemSet(nulls, 'n', attr_count * sizeof(char)); + MemSet(values, 0, num_phys_attrs * sizeof(Datum)); + MemSet(nulls, 'n', num_phys_attrs * sizeof(char)); if (!binary) { - CopyReadResult result; + CopyReadResult result = NORMAL_ATTR; char *string; if (file_has_oids) { string = CopyReadAttribute(fp, delim, &result); - if (result == END_OF_FILE) - done = 1; - else if (string == NULL || strcmp(string, null_print) == 0) - elog(ERROR, "COPY TEXT: NULL Oid"); + if (result == END_OF_FILE && *string == '\0') + { + /* EOF at start of line: all is well */ + done = true; + break; + } + + if (strcmp(string, null_print) == 0) + elog(ERROR, "NULL Oid"); else { loaded_oid = DatumGetObjectId(DirectFunctionCall1(oidin, CStringGetDatum(string))); if (loaded_oid == InvalidOid) - elog(ERROR, "COPY TEXT: Invalid Oid"); + elog(ERROR, "Invalid Oid"); } } - /* - * here, we only try to read as many attributes as - * were specified. + /* + * Loop to read the user attributes on the line. */ - for (i = 0; i < copy_attr_count && !done; i++) + foreach(cur, attnumlist) { - int m = attmap[i]; + int attnum = lfirsti(cur); + int m = attnum - 1; + + /* + * If prior attr on this line was ended by newline or EOF, + * complain. + */ + if (result != NORMAL_ATTR) + elog(ERROR, "Missing data for column \"%s\"", + NameStr(attr[m]->attname)); string = CopyReadAttribute(fp, delim, &result); - /* If we got an end-of-line before we expected, bail out */ - if (result == END_OF_LINE && i < (copy_attr_count - 1)) - elog(ERROR, "COPY TEXT: Missing data for attribute %d", i + 1); + if (result == END_OF_FILE && *string == '\0' && + cur == attnumlist && !file_has_oids) + { + /* EOF at start of line: all is well */ + done = true; + break; /* out of per-attr loop */ + } - if (result == END_OF_FILE) - done = 1; - else if (strcmp(string, null_print) == 0) + if (strcmp(string, null_print) == 0) { /* we read an SQL NULL, no need to do anything */ } @@ -979,124 +959,149 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids, } } - if (result == NORMAL_ATTR && !done) - elog(ERROR, "COPY TEXT: Extra data encountered"); + if (done) + break; /* out of per-row loop */ + + /* Complain if there are more fields on the input line */ + if (result == NORMAL_ATTR) + elog(ERROR, "Extra data after last expected column"); /* - * as above, we only try a default lookup if one is - * known to be available + * If we got some data on the line, but it was ended by EOF, + * process the line normally but set flag to exit the loop + * when we return to the top. */ - for (i = 0; i < def_attr_count && !done; i++) - { - bool isnull; - values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext, - &isnull, &isdone); - - if (! isnull) - nulls[defmap[i]] = ' '; - } + if (result == END_OF_FILE) + done = true; } else - { /* binary */ + { + /* binary */ int16 fld_count, fld_size; CopyGetData(&fld_count, sizeof(int16), fp); if (CopyGetEof(fp) || fld_count == -1) - done = 1; - else { - if (fld_count <= 0 || fld_count > attr_count) - elog(ERROR, "COPY BINARY: tuple field count is %d, expected %d", - (int) fld_count, attr_count); + done = true; + break; + } - if (file_has_oids) + if (fld_count != attr_count) + elog(ERROR, "COPY BINARY: tuple field count is %d, expected %d", + (int) fld_count, attr_count); + + if (file_has_oids) + { + CopyGetData(&fld_size, sizeof(int16), fp); + if (CopyGetEof(fp)) + elog(ERROR, "COPY BINARY: unexpected EOF"); + if (fld_size != (int16) sizeof(Oid)) + elog(ERROR, "COPY BINARY: sizeof(Oid) is %d, expected %d", + (int) fld_size, (int) sizeof(Oid)); + CopyGetData(&loaded_oid, sizeof(Oid), fp); + if (CopyGetEof(fp)) + elog(ERROR, "COPY BINARY: unexpected EOF"); + if (loaded_oid == InvalidOid) + elog(ERROR, "COPY BINARY: Invalid Oid"); + } + + i = 0; + foreach(cur, attnumlist) + { + int attnum = lfirsti(cur); + + i++; + + CopyGetData(&fld_size, sizeof(int16), fp); + if (CopyGetEof(fp)) + elog(ERROR, "COPY BINARY: unexpected EOF"); + if (fld_size == 0) + continue; /* it's NULL; nulls[attnum-1] already set */ + if (fld_size != attr[attnum-1]->attlen) + elog(ERROR, "COPY BINARY: sizeof(field %d) is %d, expected %d", + i, (int) fld_size, (int) attr[attnum-1]->attlen); + if (fld_size == -1) { - CopyGetData(&fld_size, sizeof(int16), fp); + /* varlena field */ + int32 varlena_size; + Pointer varlena_ptr; + + CopyGetData(&varlena_size, sizeof(int32), fp); if (CopyGetEof(fp)) elog(ERROR, "COPY BINARY: unexpected EOF"); - if (fld_size != (int16) sizeof(Oid)) - elog(ERROR, "COPY BINARY: sizeof(Oid) is %d, expected %d", - (int) fld_size, (int) sizeof(Oid)); - CopyGetData(&loaded_oid, sizeof(Oid), fp); + if (varlena_size < (int32) sizeof(int32)) + elog(ERROR, "COPY BINARY: bogus varlena length"); + varlena_ptr = (Pointer) palloc(varlena_size); + VARATT_SIZEP(varlena_ptr) = varlena_size; + CopyGetData(VARDATA(varlena_ptr), + varlena_size - sizeof(int32), + fp); if (CopyGetEof(fp)) elog(ERROR, "COPY BINARY: unexpected EOF"); - if (loaded_oid == InvalidOid) - elog(ERROR, "COPY BINARY: Invalid Oid"); + values[attnum-1] = PointerGetDatum(varlena_ptr); + } + else if (!attr[attnum-1]->attbyval) + { + /* fixed-length pass-by-reference */ + Pointer refval_ptr; + + Assert(fld_size > 0); + refval_ptr = (Pointer) palloc(fld_size); + CopyGetData(refval_ptr, fld_size, fp); + if (CopyGetEof(fp)) + elog(ERROR, "COPY BINARY: unexpected EOF"); + values[attnum-1] = PointerGetDatum(refval_ptr); + } + else + { + /* pass-by-value */ + Datum datumBuf; + + /* + * We need this horsing around because we don't + * know how shorter data values are aligned within + * a Datum. + */ + Assert(fld_size > 0 && fld_size <= sizeof(Datum)); + CopyGetData(&datumBuf, fld_size, fp); + if (CopyGetEof(fp)) + elog(ERROR, "COPY BINARY: unexpected EOF"); + values[attnum-1] = fetch_att(&datumBuf, true, fld_size); } - for (i = 0; i < (int) fld_count; i++) - { - CopyGetData(&fld_size, sizeof(int16), fp); - if (CopyGetEof(fp)) - elog(ERROR, "COPY BINARY: unexpected EOF"); - if (fld_size == 0) - continue; /* it's NULL; nulls[i] already set */ - if (fld_size != attr[i]->attlen) - elog(ERROR, "COPY BINARY: sizeof(field %d) is %d, expected %d", - i + 1, (int) fld_size, (int) attr[i]->attlen); - if (fld_size == -1) - { - /* varlena field */ - int32 varlena_size; - Pointer varlena_ptr; - - CopyGetData(&varlena_size, sizeof(int32), fp); - if (CopyGetEof(fp)) - elog(ERROR, "COPY BINARY: unexpected EOF"); - if (varlena_size < (int32) sizeof(int32)) - elog(ERROR, "COPY BINARY: bogus varlena length"); - varlena_ptr = (Pointer) palloc(varlena_size); - VARATT_SIZEP(varlena_ptr) = varlena_size; - CopyGetData(VARDATA(varlena_ptr), - varlena_size - sizeof(int32), - fp); - if (CopyGetEof(fp)) - elog(ERROR, "COPY BINARY: unexpected EOF"); - values[i] = PointerGetDatum(varlena_ptr); - } - else if (!attr[i]->attbyval) - { - /* fixed-length pass-by-reference */ - Pointer refval_ptr; - - Assert(fld_size > 0); - refval_ptr = (Pointer) palloc(fld_size); - CopyGetData(refval_ptr, fld_size, fp); - if (CopyGetEof(fp)) - elog(ERROR, "COPY BINARY: unexpected EOF"); - values[i] = PointerGetDatum(refval_ptr); - } - else - { - /* pass-by-value */ - Datum datumBuf; - - /* - * We need this horsing around because we don't - * know how shorter data values are aligned within - * a Datum. - */ - Assert(fld_size > 0 && fld_size <= sizeof(Datum)); - CopyGetData(&datumBuf, fld_size, fp); - if (CopyGetEof(fp)) - elog(ERROR, "COPY BINARY: unexpected EOF"); - values[i] = fetch_att(&datumBuf, true, fld_size); - } - - nulls[i] = ' '; - } + nulls[attnum-1] = ' '; } } - if (done) - break; + /* + * 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++) + { + bool isnull; + values[defmap[i]] = ExecEvalExpr(defexprs[i], econtext, + &isnull, NULL); + if (!isnull) + nulls[defmap[i]] = ' '; + } + + /* + * And now we can form the input tuple. + */ tuple = heap_formtuple(tupDesc, values, nulls); if (oids && file_has_oids) HeapTupleSetOid(tuple, loaded_oid); + /* + * Triggers and stuff need to be invoked in query context. + */ + MemoryContextSwitchTo(oldcontext); + skip_tuple = false; /* BEFORE ROW INSERT Triggers */ @@ -1118,6 +1123,7 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids, if (!skip_tuple) { + /* Place tuple in tuple slot */ ExecStoreTuple(tuple, slot, InvalidBuffer, false); /* @@ -1138,8 +1144,6 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids, if (resultRelInfo->ri_TrigDesc) ExecARInsertTriggers(estate, resultRelInfo, tuple); } - - heap_freetuple(tuple); } /* @@ -1147,6 +1151,8 @@ CopyFrom(Relation rel, List *attlist, bool binary, bool oids, */ copy_lineno = 0; + MemoryContextSwitchTo(oldcontext); + pfree(values); pfree(nulls); @@ -1197,12 +1203,11 @@ GetTypeElement(Oid type) /* * Read the value of a single attribute. * - * Results are returned in the status indicator, as well as the - * return value. If a value was successfully read but there is - * more to read before EOL, NORMAL_ATTR is set and the value read - * is returned. If a value was read and we hit EOL, END_OF_LINE - * is set and the value read is returned. If we hit the EOF, - * END_OF_FILE is set and NULL is returned. + * *result is set to indicate what terminated the read: + * NORMAL_ATTR: column delimiter + * END_OF_LINE: newline + * END_OF_FILE: EOF indication + * In all cases, the string read up to the terminator is returned. * * Note: This function does not care about SQL NULL values -- it * is the caller's responsibility to check if the returned string @@ -1215,8 +1220,7 @@ static char * CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result) { int c; - int delimc = (unsigned char)delim[0]; - + int delimc = (unsigned char) delim[0]; #ifdef MULTIBYTE int mblen; unsigned char s[2]; @@ -1230,7 +1234,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result) attribute_buf.len = 0; attribute_buf.data[0] = '\0'; - /* set default */ + /* set default status */ *result = NORMAL_ATTR; for (;;) @@ -1239,7 +1243,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result) if (c == EOF) { *result = END_OF_FILE; - return NULL; + goto copy_eof; } if (c == '\n') { @@ -1254,7 +1258,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result) if (c == EOF) { *result = END_OF_FILE; - return NULL; + goto copy_eof; } switch (c) { @@ -1286,7 +1290,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result) if (c == EOF) { *result = END_OF_FILE; - return NULL; + goto copy_eof; } CopyDonePeek(fp, c, false /* put back */ ); } @@ -1296,7 +1300,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result) if (c == EOF) { *result = END_OF_FILE; - return NULL; + goto copy_eof; } CopyDonePeek(fp, c, false /* put back */ ); } @@ -1336,7 +1340,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result) if (c != '\n') elog(ERROR, "CopyReadAttribute: end of record marker corrupted"); *result = END_OF_FILE; - return NULL; + goto copy_eof; } } appendStringInfoCharMacro(&attribute_buf, c); @@ -1353,7 +1357,7 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result) if (c == EOF) { *result = END_OF_FILE; - return NULL; + goto copy_eof; } appendStringInfoCharMacro(&attribute_buf, c); } @@ -1361,6 +1365,8 @@ CopyReadAttribute(FILE *fp, const char *delim, CopyReadResult *result) #endif } +copy_eof: + #ifdef MULTIBYTE if (client_encoding != server_encoding) { @@ -1468,50 +1474,51 @@ CopyAttributeOut(FILE *fp, char *server_string, char *delim) } /* - * CopyCheckAttlist: elog(ERROR,...) if the specified attlist - * is not valid for the Relation + * CopyGetAttnums - build an integer list of attnums to be copied + * + * The input attnamelist is either the user-specified column list, + * or NIL if there was none (in which case we want all the non-dropped + * columns). */ -static void -CopyCheckAttlist(Relation rel, List *attlist) +static List * +CopyGetAttnums(Relation rel, List *attnamelist) { - TupleDesc tupDesc; - int attr_count; - List *l; + List *attnums = NIL; - if (attlist == NIL) - return; - - tupDesc = RelationGetDescr(rel); - Assert(tupDesc != NULL); - - /* - * make sure there aren't more columns specified than are in the table - */ - attr_count = tupDesc->natts; - if (attr_count < length(attlist)) - elog(ERROR, "COPY: Too many columns specified"); - - /* - * make sure no columns are specified that don't exist in the table - */ - foreach(l, attlist) + if (attnamelist == NIL) { - char *colName = strVal(lfirst(l)); - bool found = false; - int i; + /* Generate default column list */ + TupleDesc tupDesc = RelationGetDescr(rel); + Form_pg_attribute *attr = tupDesc->attrs; + int attr_count = tupDesc->natts; + int i; for (i = 0; i < attr_count; i++) { - if (namestrcmp(&tupDesc->attrs[i]->attname, colName) == 0) - { - found = true; - break; - } + if (attr[i]->attisdropped) + continue; + attnums = lappendi(attnums, i + 1); } - - if (!found) - elog(ERROR, "COPY: Specified column \"%s\" does not exist", - colName); } -} + else + { + /* Validate the user-supplied list and extract attnums */ + List *l; + foreach(l, attnamelist) + { + char *name = strVal(lfirst(l)); + int attnum; + + /* Lookup column name, elog on failure */ + /* Note we disallow system columns here */ + attnum = attnameAttNum(rel, name, false); + /* Check for duplicates */ + if (intMember(attnum, attnums)) + elog(ERROR, "Attribute \"%s\" specified more than once", name); + attnums = lappendi(attnums, attnum); + } + } + + return attnums; +} diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 4049e7435c..9edebc1e69 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.79 2002/07/29 23:46:35 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.80 2002/08/02 18:15:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -294,10 +294,7 @@ FuncIndexArgs(IndexInfo *indexInfo, HeapTuple tuple; Form_pg_attribute att; - tuple = SearchSysCache(ATTNAME, - ObjectIdGetDatum(relId), - PointerGetDatum(arg), - 0, 0); + tuple = SearchSysCacheAttName(relId, arg); if (!HeapTupleIsValid(tuple)) elog(ERROR, "DefineIndex: attribute \"%s\" not found", arg); att = (Form_pg_attribute) GETSTRUCT(tuple); @@ -387,10 +384,7 @@ NormIndexAttrs(IndexInfo *indexInfo, if (attribute->name == NULL) elog(ERROR, "missing attribute for define index"); - atttuple = SearchSysCache(ATTNAME, - ObjectIdGetDatum(relId), - PointerGetDatum(attribute->name), - 0, 0); + atttuple = SearchSysCacheAttName(relId, attribute->name); if (!HeapTupleIsValid(atttuple)) elog(ERROR, "DefineIndex: attribute \"%s\" not found", attribute->name); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index cfcf5d5ddf..4972c09b4a 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.25 2002/07/31 17:19:51 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/tablecmds.c,v 1.26 2002/08/02 18:15:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -503,7 +503,7 @@ MergeAttributes(List *schema, List *supers, bool istemp, /* * newattno[] will contain the child-table attribute numbers for * the attributes of this parent table. (They are not the same - * for parents after the first one.) + * for parents after the first one, nor if we have dropped columns.) */ newattno = (AttrNumber *) palloc(tupleDesc->natts * sizeof(AttrNumber)); @@ -516,6 +516,19 @@ MergeAttributes(List *schema, List *supers, bool istemp, ColumnDef *def; TypeName *typename; + /* + * Ignore dropped columns in the parent. + */ + if (attribute->attisdropped) + { + /* + * change_varattnos_of_a_node asserts that this is greater than + * zero, so if anything tries to use it, we should find out. + */ + newattno[parent_attno - 1] = 0; + continue; + } + /* * Does it conflict with some previously inherited column? */ @@ -1062,17 +1075,17 @@ renameatt(Oid relid, attrelation = heap_openr(AttributeRelationName, RowExclusiveLock); - atttup = SearchSysCacheCopy(ATTNAME, - ObjectIdGetDatum(relid), - PointerGetDatum(oldattname), - 0, 0); + atttup = SearchSysCacheCopyAttName(relid, oldattname); if (!HeapTupleIsValid(atttup)) - elog(ERROR, "renameatt: attribute \"%s\" does not exist", oldattname); + elog(ERROR, "renameatt: attribute \"%s\" does not exist", + oldattname); if (((Form_pg_attribute) GETSTRUCT(atttup))->attnum < 0) - elog(ERROR, "renameatt: system attribute \"%s\" not renamed", oldattname); + elog(ERROR, "renameatt: system attribute \"%s\" may not be renamed", + oldattname); /* should not already exist */ + /* this test is deliberately not attisdropped-aware */ if (SearchSysCacheExists(ATTNAME, ObjectIdGetDatum(relid), PointerGetDatum(newattname), @@ -1126,10 +1139,7 @@ renameatt(Oid relid, * Okay, look to see if any column name of the index matches the * old attribute name. */ - atttup = SearchSysCacheCopy(ATTNAME, - ObjectIdGetDatum(indexoid), - PointerGetDatum(oldattname), - 0, 0); + atttup = SearchSysCacheCopyAttName(indexoid, oldattname); if (!HeapTupleIsValid(atttup)) continue; /* Nope, so ignore it */ @@ -1634,6 +1644,10 @@ AlterTableAddColumn(Oid myrelid, elog(ERROR, "ALTER TABLE: relation \"%s\" not found", RelationGetRelationName(rel)); + /* + * this test is deliberately not attisdropped-aware, since if one tries + * to add a column matching a dropped column name, it's gonna fail anyway. + */ if (SearchSysCacheExists(ATTNAME, ObjectIdGetDatum(myrelid), PointerGetDatum(colDef->colname), @@ -1681,6 +1695,7 @@ AlterTableAddColumn(Oid myrelid, attribute->attnotnull = colDef->is_not_null; attribute->atthasdef = (colDef->raw_default != NULL || colDef->cooked_default != NULL); + attribute->attisdropped = false; ReleaseSysCache(typeTuple); @@ -1821,17 +1836,11 @@ AlterTableAlterColumnDropNotNull(Oid myrelid, /* * get the number of the attribute */ - tuple = SearchSysCache(ATTNAME, - ObjectIdGetDatum(myrelid), - PointerGetDatum(colName), - 0, 0); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"", + attnum = get_attnum(myrelid, colName); + if (attnum == InvalidAttrNumber) + elog(ERROR, "Relation \"%s\" has no column \"%s\"", RelationGetRelationName(rel), colName); - attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum; - ReleaseSysCache(tuple); - /* Prevent them from altering a system attribute */ if (attnum < 0) elog(ERROR, "ALTER TABLE: Cannot alter system attribute \"%s\"", @@ -1884,10 +1893,7 @@ AlterTableAlterColumnDropNotNull(Oid myrelid, */ attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock); - tuple = SearchSysCacheCopy(ATTNAME, - ObjectIdGetDatum(myrelid), - PointerGetDatum(colName), - 0, 0); + tuple = SearchSysCacheCopyAttName(myrelid, colName); if (!HeapTupleIsValid(tuple)) /* shouldn't happen */ elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"", RelationGetRelationName(rel), colName); @@ -1971,17 +1977,11 @@ AlterTableAlterColumnSetNotNull(Oid myrelid, /* * get the number of the attribute */ - tuple = SearchSysCache(ATTNAME, - ObjectIdGetDatum(myrelid), - PointerGetDatum(colName), - 0, 0); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"", + attnum = get_attnum(myrelid, colName); + if (attnum == InvalidAttrNumber) + elog(ERROR, "Relation \"%s\" has no column \"%s\"", RelationGetRelationName(rel), colName); - attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum; - ReleaseSysCache(tuple); - /* Prevent them from altering a system attribute */ if (attnum < 0) elog(ERROR, "ALTER TABLE: Cannot alter system attribute \"%s\"", @@ -2014,10 +2014,7 @@ AlterTableAlterColumnSetNotNull(Oid myrelid, */ attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock); - tuple = SearchSysCacheCopy(ATTNAME, - ObjectIdGetDatum(myrelid), - PointerGetDatum(colName), - 0, 0); + tuple = SearchSysCacheCopyAttName(myrelid, colName); if (!HeapTupleIsValid(tuple)) /* shouldn't happen */ elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"", RelationGetRelationName(rel), colName); @@ -2051,7 +2048,6 @@ AlterTableAlterColumnDefault(Oid myrelid, Node *newDefault) { Relation rel; - HeapTuple tuple; AttrNumber attnum; rel = heap_open(myrelid, AccessExclusiveLock); @@ -2106,16 +2102,15 @@ AlterTableAlterColumnDefault(Oid myrelid, /* * get the number of the attribute */ - tuple = SearchSysCache(ATTNAME, - ObjectIdGetDatum(myrelid), - PointerGetDatum(colName), - 0, 0); - if (!HeapTupleIsValid(tuple)) - elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"", + attnum = get_attnum(myrelid, colName); + if (attnum == InvalidAttrNumber) + elog(ERROR, "Relation \"%s\" has no column \"%s\"", RelationGetRelationName(rel), colName); - attnum = ((Form_pg_attribute) GETSTRUCT(tuple))->attnum; - ReleaseSysCache(tuple); + /* Prevent them from altering a system attribute */ + if (attnum < 0) + elog(ERROR, "ALTER TABLE: Cannot alter system attribute \"%s\"", + colName); /* * Remove any old default for the column. We use RESTRICT here for @@ -2254,10 +2249,7 @@ AlterTableAlterColumnFlags(Oid myrelid, attrelation = heap_openr(AttributeRelationName, RowExclusiveLock); - tuple = SearchSysCacheCopy(ATTNAME, - ObjectIdGetDatum(myrelid), - PointerGetDatum(colName), - 0, 0); + tuple = SearchSysCacheCopyAttName(myrelid, colName); if (!HeapTupleIsValid(tuple)) elog(ERROR, "ALTER TABLE: relation \"%s\" has no column \"%s\"", RelationGetRelationName(rel), colName); @@ -2309,7 +2301,99 @@ AlterTableDropColumn(Oid myrelid, bool inh, const char *colName, DropBehavior behavior) { - elog(ERROR, "ALTER TABLE / DROP COLUMN is not implemented"); + Relation rel; + AttrNumber attnum; + AttrNumber n; + TupleDesc tupleDesc; + bool success; + ObjectAddress object; + + rel = heap_open(myrelid, AccessExclusiveLock); + + if (rel->rd_rel->relkind != RELKIND_RELATION) + elog(ERROR, "ALTER TABLE: relation \"%s\" is not a table", + RelationGetRelationName(rel)); + + if (!allowSystemTableMods + && IsSystemRelation(rel)) + elog(ERROR, "ALTER TABLE: relation \"%s\" is a system catalog", + RelationGetRelationName(rel)); + + if (!pg_class_ownercheck(myrelid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, RelationGetRelationName(rel)); + + /* + * get the number of the attribute + */ + attnum = get_attnum(myrelid, colName); + if (attnum == InvalidAttrNumber) + elog(ERROR, "Relation \"%s\" has no column \"%s\"", + RelationGetRelationName(rel), colName); + + /* Can't drop a system attribute */ + if (attnum < 0) + elog(ERROR, "ALTER TABLE: Cannot drop system attribute \"%s\"", + colName); + + /* + * Make sure there will be at least one user column left in the relation + * after we drop this one. Zero-length tuples tend to confuse us. + */ + tupleDesc = RelationGetDescr(rel); + + success = false; + for (n = 1; n <= tupleDesc->natts; n++) + { + Form_pg_attribute attribute = tupleDesc->attrs[n - 1]; + + if (!attribute->attisdropped && n != attnum) + { + success = true; + break; + } + } + + if (!success) + elog(ERROR, "ALTER TABLE: Cannot drop last column from table \"%s\"", + RelationGetRelationName(rel)); + + /* + * Propagate to children if desired + */ + if (inh) + { + List *child, + *children; + + /* this routine is actually in the planner */ + children = find_all_inheritors(myrelid); + + /* + * find_all_inheritors does the recursive search of the + * inheritance hierarchy, so all we have to do is process all of + * the relids in the list that it returns. + */ + foreach(child, children) + { + Oid childrelid = lfirsti(child); + + if (childrelid == myrelid) + continue; + AlterTableDropColumn(childrelid, + false, colName, behavior); + } + } + + /* + * Perform the actual deletion + */ + object.classId = RelOid_pg_class; + object.objectId = myrelid; + object.objectSubId = attnum; + + performDeletion(&object, behavior); + + heap_close(rel, NoLock); /* close rel, but keep lock! */ } @@ -2722,8 +2806,13 @@ createForeignKeyConstraint(Relation rel, Relation pkrel, foreach(l, fkconstraint->fk_attrs) { Ident *id = (Ident *) lfirst(l); + AttrNumber attno; - fkattr[i++] = get_attnum(RelationGetRelid(rel), id->name); + attno = get_attnum(RelationGetRelid(rel), id->name); + if (attno == InvalidAttrNumber) + elog(ERROR, "Relation \"%s\" has no column \"%s\"", + RelationGetRelationName(rel), id->name); + fkattr[i++] = attno; } /* The same for the referenced primary key attrs */ @@ -2733,8 +2822,13 @@ createForeignKeyConstraint(Relation rel, Relation pkrel, foreach(l, fkconstraint->pk_attrs) { Ident *id = (Ident *) lfirst(l); + AttrNumber attno; - pkattr[i++] = get_attnum(RelationGetRelid(pkrel), id->name); + attno = get_attnum(RelationGetRelid(pkrel), id->name); + if (attno == InvalidAttrNumber) + elog(ERROR, "Relation \"%s\" has no column \"%s\"", + RelationGetRelationName(pkrel), id->name); + pkattr[i++] = attno; } /* Now we can make the pg_constraint entry */ diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index 1cc9f5af48..b7c0bac12c 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.53 2002/06/20 20:29:31 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.54 2002/08/02 18:15:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -165,6 +165,8 @@ expand_targetlist(List *tlist, int command_type, * * For UPDATE, generate a Var reference to the existing value of * the attribute, so that it gets copied to the new tuple. + * But generate a NULL for dropped columns (we want to drop any + * old values). */ Oid atttype = att_tup->atttypid; int32 atttypmod = att_tup->atttypmod; @@ -182,11 +184,21 @@ expand_targetlist(List *tlist, int command_type, false); break; case CMD_UPDATE: - new_expr = (Node *) makeVar(result_relation, - attrno, - atttype, - atttypmod, - 0); + /* Insert NULLs for dropped columns */ + if (att_tup->attisdropped) + new_expr = (Node *) makeConst(atttype, + att_tup->attlen, + (Datum) 0, + true, /* isnull */ + att_tup->attbyval, + false, /* not a set */ + false); + else + new_expr = (Node *) makeVar(result_relation, + attrno, + atttype, + atttypmod, + 0); break; default: elog(ERROR, "expand_targetlist: unexpected command_type"); @@ -210,7 +222,8 @@ expand_targetlist(List *tlist, int command_type, * the end of the new tlist, making sure they have resnos higher than * the last real attribute. (Note: although the rewriter already did * such renumbering, we have to do it again here in case we are doing - * an UPDATE in an inheritance child table with more columns.) + * an UPDATE in a table with dropped columns, or an inheritance child + * table with extra columns.) */ while (tlist) { diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 367ef4a58a..f41466dbd5 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.74 2002/06/20 20:29:31 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.75 2002/08/02 18:15:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -797,9 +797,16 @@ adjust_inherited_attrs_mutator(Node *node, { var->varno = context->new_rt_index; if (var->varattno > 0) - var->varattno = get_attnum(context->new_relid, - get_attname(context->old_relid, - var->varattno)); + { + char *attname = get_attname(context->old_relid, + var->varattno); + + var->varattno = get_attnum(context->new_relid, attname); + if (var->varattno == InvalidAttrNumber) + elog(ERROR, "Relation \"%s\" has no column \"%s\"", + get_rel_name(context->new_relid), attname); + pfree(attname); + } } return (Node *) var; } diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 6337b61f2a..e3d8ce070b 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.239 2002/07/16 22:12:19 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.240 2002/08/02 18:15:06 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1143,6 +1143,8 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt) Form_pg_attribute inhattr = rel->rd_att->attrs[count]; char *inhname = NameStr(inhattr->attname); + if (inhattr->attisdropped) + continue; if (strcmp(key->name, inhname) == 0) { found = true; @@ -1178,10 +1180,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt) /* ALTER TABLE case: does column already exist? */ HeapTuple atttuple; - atttuple = SearchSysCache(ATTNAME, - ObjectIdGetDatum(cxt->relOid), - PointerGetDatum(key->name), - 0, 0); + atttuple = SearchSysCacheAttName(cxt->relOid, key->name); if (HeapTupleIsValid(atttuple)) { found = true; @@ -2369,7 +2368,7 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) origTarget = (ResTarget *) lfirst(origTargetList); updateTargetListEntry(pstate, tle, origTarget->name, attnameAttNum(pstate->p_target_relation, - origTarget->name), + origTarget->name, true), origTarget->indirection); origTargetList = lnext(origTargetList); } @@ -2820,11 +2819,14 @@ transformFkeyGetColType(CreateStmtContext *cxt, char *colname) inh->relname); for (count = 0; count < rel->rd_att->natts; count++) { - char *name = NameStr(rel->rd_att->attrs[count]->attname); + Form_pg_attribute inhattr = rel->rd_att->attrs[count]; + char *inhname = NameStr(inhattr->attname); - if (strcmp(name, colname) == 0) + if (inhattr->attisdropped) + continue; + if (strcmp(inhname, colname) == 0) { - result = rel->rd_att->attrs[count]->atttypid; + result = inhattr->atttypid; heap_close(rel, NoLock); return result; } @@ -2836,10 +2838,7 @@ transformFkeyGetColType(CreateStmtContext *cxt, char *colname) { HeapTuple atttuple; - atttuple = SearchSysCache(ATTNAME, - ObjectIdGetDatum(cxt->relOid), - PointerGetDatum(colname), - 0, 0); + atttuple = SearchSysCacheAttName(cxt->relOid, colname); if (HeapTupleIsValid(atttuple)) { result = ((Form_pg_attribute) GETSTRUCT(atttuple))->atttypid; diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index f92bbe8ac5..677acf9d1a 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.132 2002/06/20 20:29:32 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.133 2002/08/02 18:15:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1150,6 +1150,9 @@ setup_field_select(Node *input, char *attname, Oid relid) AttrNumber attno; attno = get_attnum(relid, attname); + if (attno == InvalidAttrNumber) + elog(ERROR, "Relation \"%s\" has no column \"%s\"", + get_rel_name(relid), attname); fselect->arg = input; fselect->fieldnum = attno; diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 78a16ea08f..99b639d73e 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.70 2002/06/20 20:29:33 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.71 2002/08/02 18:15:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -37,7 +37,9 @@ static Node *scanNameSpaceForRefname(ParseState *pstate, Node *nsnode, static Node *scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname); static bool isForUpdate(ParseState *pstate, char *refname); -static int specialAttNum(char *a); +static bool get_rte_attribute_is_dropped(RangeTblEntry *rte, + AttrNumber attnum); +static int specialAttNum(const char *attname); static void warnAutoRange(ParseState *pstate, RangeVar *relation); @@ -267,12 +269,28 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname) /* * Scan the user column names (or aliases) for a match. Complain if * multiple matches. + * + * Note: because eref->colnames may include names of dropped columns, + * we need to check for non-droppedness before accepting a match. + * This takes an extra cache lookup, but we can skip the lookup most + * of the time by exploiting the knowledge that dropped columns are + * assigned dummy names starting with '.', which is an unusual choice + * for actual column names. + * + * Should the user try to fool us by altering pg_attribute.attname + * for a dropped column, we'll still catch it by virtue of the checks + * in get_rte_attribute_type(), which is called by make_var(). That + * routine has to do a cache lookup anyway, so the check there is + * cheap. */ foreach(c, rte->eref->colnames) { attnum++; if (strcmp(strVal(lfirst(c)), colname) == 0) { + if (colname[0] == '.' && /* see note above */ + get_rte_attribute_is_dropped(rte, attnum)) + continue; if (result) elog(ERROR, "Column reference \"%s\" is ambiguous", colname); result = (Node *) make_var(pstate, rte, attnum); @@ -962,6 +980,9 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte, { Form_pg_attribute attr = rel->rd_att->attrs[varattno]; + if (attr->attisdropped) + continue; + if (colnames) { char *label; @@ -1051,6 +1072,9 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte, { Form_pg_attribute attr = rel->rd_att->attrs[varattno]; + if (attr->attisdropped) + continue; + if (colnames) { char *label; @@ -1246,9 +1270,16 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum, 0, 0); /* this shouldn't happen... */ if (!HeapTupleIsValid(tp)) - elog(ERROR, "Relation %s does not have attribute %d", + elog(ERROR, "Relation \"%s\" does not have attribute %d", get_rel_name(rte->relid), attnum); att_tup = (Form_pg_attribute) GETSTRUCT(tp); + /* + * If dropped column, pretend it ain't there. See notes + * in scanRTEForColumn. + */ + if (att_tup->attisdropped) + elog(ERROR, "Relation \"%s\" has no column \"%s\"", + get_rel_name(rte->relid), NameStr(att_tup->attname)); *vartype = att_tup->atttypid; *vartypmod = att_tup->atttypmod; ReleaseSysCache(tp); @@ -1298,6 +1329,14 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum, elog(ERROR, "Relation %s does not have attribute %d", get_rel_name(funcrelid), attnum); att_tup = (Form_pg_attribute) GETSTRUCT(tp); + /* + * If dropped column, pretend it ain't there. See notes + * in scanRTEForColumn. + */ + if (att_tup->attisdropped) + elog(ERROR, "Relation \"%s\" has no column \"%s\"", + get_rel_name(funcrelid), + NameStr(att_tup->attname)); *vartype = att_tup->atttypid; *vartypmod = att_tup->atttypmod; ReleaseSysCache(tp); @@ -1329,6 +1368,86 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum, } } +/* + * get_rte_attribute_is_dropped + * Check whether attempted attribute ref is to a dropped column + */ +static bool +get_rte_attribute_is_dropped(RangeTblEntry *rte, AttrNumber attnum) +{ + bool result; + + switch (rte->rtekind) + { + case RTE_RELATION: + { + /* Plain relation RTE --- get the attribute's type info */ + HeapTuple tp; + Form_pg_attribute att_tup; + + tp = SearchSysCache(ATTNUM, + ObjectIdGetDatum(rte->relid), + Int16GetDatum(attnum), + 0, 0); + /* this shouldn't happen... */ + if (!HeapTupleIsValid(tp)) + elog(ERROR, "Relation \"%s\" does not have attribute %d", + get_rel_name(rte->relid), attnum); + att_tup = (Form_pg_attribute) GETSTRUCT(tp); + result = att_tup->attisdropped; + ReleaseSysCache(tp); + } + break; + case RTE_SUBQUERY: + case RTE_JOIN: + /* Subselect and join RTEs never have dropped columns */ + result = false; + break; + case RTE_FUNCTION: + { + /* Function RTE */ + Oid funcrettype = exprType(rte->funcexpr); + Oid funcrelid = typeidTypeRelid(funcrettype); + + if (OidIsValid(funcrelid)) + { + /* + * Composite data type, i.e. a table's row type + * Same as ordinary relation RTE + */ + HeapTuple tp; + Form_pg_attribute att_tup; + + tp = SearchSysCache(ATTNUM, + ObjectIdGetDatum(funcrelid), + Int16GetDatum(attnum), + 0, 0); + /* this shouldn't happen... */ + if (!HeapTupleIsValid(tp)) + elog(ERROR, "Relation %s does not have attribute %d", + get_rel_name(funcrelid), attnum); + att_tup = (Form_pg_attribute) GETSTRUCT(tp); + result = att_tup->attisdropped; + ReleaseSysCache(tp); + } + else + { + /* + * Must be a base data type, i.e. scalar + */ + result = false; + } + } + break; + default: + elog(ERROR, "get_rte_attribute_is_dropped: unsupported RTE kind %d", + (int) rte->rtekind); + result = false; /* keep compiler quiet */ + } + + return result; +} + /* * given relation and att name, return id of variable * @@ -1337,23 +1456,30 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum, * for access to non-opened relations. */ int -attnameAttNum(Relation rd, char *a) +attnameAttNum(Relation rd, const char *attname, bool sysColOK) { int i; for (i = 0; i < rd->rd_rel->relnatts; i++) - if (namestrcmp(&(rd->rd_att->attrs[i]->attname), a) == 0) - return i + 1; - - if ((i = specialAttNum(a)) != InvalidAttrNumber) { - if (i != ObjectIdAttributeNumber || rd->rd_rel->relhasoids) - return i; + Form_pg_attribute att = rd->rd_att->attrs[i]; + + if (namestrcmp(&(att->attname), attname) == 0 && !att->attisdropped) + return i + 1; + } + + if (sysColOK) + { + if ((i = specialAttNum(attname)) != InvalidAttrNumber) + { + if (i != ObjectIdAttributeNumber || rd->rd_rel->relhasoids) + return i; + } } /* on failure */ - elog(ERROR, "Relation '%s' does not have attribute '%s'", - RelationGetRelationName(rd), a); + elog(ERROR, "Relation \"%s\" has no column \"%s\"", + RelationGetRelationName(rd), attname); return InvalidAttrNumber; /* lint */ } @@ -1367,11 +1493,12 @@ attnameAttNum(Relation rd, char *a) * at least in the case of "oid", which is now optional. */ static int -specialAttNum(char *a) +specialAttNum(const char *attname) { Form_pg_attribute sysatt; - sysatt = SystemAttributeByName(a, true /* "oid" will be accepted */ ); + sysatt = SystemAttributeByName(attname, + true /* "oid" will be accepted */ ); if (sysatt != NULL) return sysatt->attnum; return InvalidAttrNumber; diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c index 608ca7613d..1e51f23d70 100644 --- a/src/backend/parser/parse_target.c +++ b/src/backend/parser/parse_target.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.85 2002/06/20 20:29:33 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.86 2002/08/02 18:15:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -385,8 +385,12 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos) for (i = 0; i < numcol; i++) { - ResTarget *col = makeNode(ResTarget); + ResTarget *col; + if (attr[i]->attisdropped) + continue; + + col = makeNode(ResTarget); col->name = pstrdup(NameStr(attr[i]->attname)); col->indirection = NIL; col->val = NULL; @@ -407,7 +411,7 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos) int attrno; /* Lookup column name, elog on failure */ - attrno = attnameAttNum(pstate->p_target_relation, name); + attrno = attnameAttNum(pstate->p_target_relation, name, false); /* Check for duplicates */ if (intMember(attrno, *attrnos)) elog(ERROR, "Attribute '%s' specified more than once", name); diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index 159428894e..59c534a7ef 100644 --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.46 2002/07/29 23:46:35 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.47 2002/08/02 18:15:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -85,8 +85,8 @@ LookupTypeName(const TypeName *typename) relid = RangeVarGetRelid(rel, false); attnum = get_attnum(relid, field); if (attnum == InvalidAttrNumber) - elog(ERROR, "'%s' is not an attribute of class '%s'", - field, rel->relname); + elog(ERROR, "Relation \"%s\" has no column \"%s\"", + rel->relname, field); restype = get_atttype(relid, attnum); /* this construct should never have an array indicator */ diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index 59d0744dce..577ce2bd52 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.75 2002/07/16 05:53:34 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.76 2002/08/02 18:15:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -257,6 +257,16 @@ DefineQueryRewrite(RuleStmt *stmt) attr = event_relation->rd_att->attrs[i - 1]; attname = NameStr(attr->attname); + /* + * Disallow dropped columns in the relation. This won't happen + * in the cases we actually care about (namely creating a view + * via CREATE TABLE then CREATE RULE). Trying to cope with it + * is much more trouble than it's worth, because we'd have to + * modify the rule to insert dummy NULLs at the right positions. + */ + if (attr->attisdropped) + elog(ERROR, "cannot convert relation containing dropped columns to view"); + if (strcmp(resdom->resname, attname) != 0) elog(ERROR, "select rule's target entry %d has different column name from %s", i, attname); diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 0ae1e223ba..95ab639d0a 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.104 2002/07/18 04:43:50 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.105 2002/08/02 18:15:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -264,6 +264,10 @@ rewriteTargetList(Query *parsetree, Relation target_relation) Form_pg_attribute att_tup = target_relation->rd_att->attrs[attrno-1]; TargetEntry *new_tle = NULL; + /* We can ignore deleted attributes */ + if (att_tup->attisdropped) + continue; + /* * Look for targetlist entries matching this attr. We match by * resno, but the resname should match too. diff --git a/src/backend/utils/adt/not_in.c b/src/backend/utils/adt/not_in.c index 5982e434da..7c6be4533e 100644 --- a/src/backend/utils/adt/not_in.c +++ b/src/backend/utils/adt/not_in.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/not_in.c,v 1.30 2002/06/20 20:29:37 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/not_in.c,v 1.31 2002/08/02 18:15:07 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -28,9 +28,9 @@ #include "access/heapam.h" #include "catalog/namespace.h" +#include "parser/parse_relation.h" #include "utils/builtins.h" -static int my_varattno(Relation rd, char *a); /* ---------------------------------------------------------------- * @@ -65,15 +65,10 @@ int4notin(PG_FUNCTION_ARGS) relrv = makeRangeVarFromNameList(names); /* Open the relation and get a relation descriptor */ - relation_to_scan = heap_openrv(relrv, AccessShareLock); /* Find the column to search */ - - attrid = my_varattno(relation_to_scan, attribute); - if (attrid < 0) - elog(ERROR, "int4notin: unknown attribute %s for relation %s", - attribute, RelationGetRelationName(relation_to_scan)); + attrid = attnameAttNum(relation_to_scan, attribute, true); scan_descriptor = heap_beginscan(relation_to_scan, SnapshotNow, 0, (ScanKey) NULL); @@ -118,21 +113,3 @@ oidnotin(PG_FUNCTION_ARGS) /* XXX assume oid maps to int4 */ return int4notin(fcinfo); } - -/* - * XXX - * If varattno (in parser/catalog_utils.h) ever is added to - * cinterface.a, this routine should go away - */ -static int -my_varattno(Relation rd, char *a) -{ - int i; - - for (i = 0; i < rd->rd_rel->relnatts; i++) - { - if (namestrcmp(&rd->rd_att->attrs[i]->attname, a) == 0) - return i + 1; - } - return -1; -} diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index e383ab892d..9b5b4cd6f1 100644 --- a/src/backend/utils/cache/lsyscache.c +++ b/src/backend/utils/cache/lsyscache.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.76 2002/07/12 18:43:18 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.77 2002/08/02 18:15:08 tgl Exp $ * * NOTES * Eventually, the index information should go through here, too. @@ -115,16 +115,15 @@ get_attname(Oid relid, AttrNumber attnum) * * Given the relation id and the attribute name, * return the "attnum" field from the attribute relation. + * + * Returns InvalidAttrNumber if the attr doesn't exist (or is dropped). */ AttrNumber -get_attnum(Oid relid, char *attname) +get_attnum(Oid relid, const char *attname) { HeapTuple tp; - tp = SearchSysCache(ATTNAME, - ObjectIdGetDatum(relid), - PointerGetDatum(attname), - 0, 0); + tp = SearchSysCacheAttName(relid, attname); if (HeapTupleIsValid(tp)) { Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp); @@ -166,32 +165,6 @@ get_atttype(Oid relid, AttrNumber attnum) return InvalidOid; } -/* This routine uses the attname instead of the attnum because it - * replaces the routine find_atttype, which is called sometimes when - * only the attname, not the attno, is available. - */ -bool -get_attisset(Oid relid, char *attname) -{ - HeapTuple tp; - - tp = SearchSysCache(ATTNAME, - ObjectIdGetDatum(relid), - PointerGetDatum(attname), - 0, 0); - if (HeapTupleIsValid(tp)) - { - Form_pg_attribute att_tup = (Form_pg_attribute) GETSTRUCT(tp); - bool result; - - result = att_tup->attisset; - ReleaseSysCache(tp); - return result; - } - else - return false; -} - /* * get_atttypmod * diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 0e114f3696..c9b68b1d8d 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.84 2002/07/25 10:07:12 ishii Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.85 2002/08/02 18:15:08 tgl Exp $ * * NOTES * These routines allow the parser/planner/executor to perform @@ -622,6 +622,71 @@ GetSysCacheOid(int cacheId, return result; } + +/* + * SearchSysCacheAttName + * + * This routine is equivalent to SearchSysCache on the ATTNAME cache, + * except that it will return NULL if the found attribute is marked + * attisdropped. This is convenient for callers that want to act as + * though dropped attributes don't exist. + */ +HeapTuple +SearchSysCacheAttName(Oid relid, const char *attname) +{ + HeapTuple tuple; + + tuple = SearchSysCache(ATTNAME, + ObjectIdGetDatum(relid), + CStringGetDatum(attname), + 0, 0); + if (!HeapTupleIsValid(tuple)) + return NULL; + if (((Form_pg_attribute) GETSTRUCT(tuple))->attisdropped) + { + ReleaseSysCache(tuple); + return NULL; + } + return tuple; +} + +/* + * SearchSysCacheCopyAttName + * + * As above, an attisdropped-aware version of SearchSysCacheCopy. + */ +HeapTuple +SearchSysCacheCopyAttName(Oid relid, const char *attname) +{ + HeapTuple tuple, + newtuple; + + tuple = SearchSysCacheAttName(relid, attname); + if (!HeapTupleIsValid(tuple)) + return tuple; + newtuple = heap_copytuple(tuple); + ReleaseSysCache(tuple); + return newtuple; +} + +/* + * SearchSysCacheExistsAttName + * + * As above, an attisdropped-aware version of SearchSysCacheExists. + */ +bool +SearchSysCacheExistsAttName(Oid relid, const char *attname) +{ + HeapTuple tuple; + + tuple = SearchSysCacheAttName(relid, attname); + if (!HeapTupleIsValid(tuple)) + return false; + ReleaseSysCache(tuple); + return true; +} + + /* * SysCacheGetAttr * diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 7ca027e010..0a44b4cbbc 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -22,7 +22,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.278 2002/07/31 17:19:52 tgl Exp $ + * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.279 2002/08/02 18:15:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -863,13 +863,15 @@ dumpClasses_nodumpData(Archive *fout, char *oid, void *dctxv) { appendPQExpBuffer(q, "COPY %s %s WITH OIDS TO stdout;", fmtQualifiedId(tbinfo->relnamespace->nspname, - classname),column_list); + classname), + column_list); } else { appendPQExpBuffer(q, "COPY %s %s TO stdout;", fmtQualifiedId(tbinfo->relnamespace->nspname, - classname), column_list); + classname), + column_list); } res = PQexec(g_conn, q->data); if (!res || @@ -1193,10 +1195,13 @@ dumpClasses(const TableInfo *tblinfo, const int numTables, Archive *fout, if (!dumpData) { /* Dump/restore using COPY */ + const char *column_list; + dumpFn = dumpClasses_nodumpData; + column_list = fmtCopyColumnList(&(tblinfo[i])); sprintf(copyBuf, "COPY %s %s %sFROM stdin;\n", - fmtQualifiedId(tblinfo[i].relnamespace->nspname,tblinfo[i].relname), - fmtCopyColumnList(&(tblinfo[i])), + fmtId(tblinfo[i].relname, force_quotes), + column_list, (oids && tblinfo[i].hasoids) ? "WITH OIDS " : ""); copyStmt = copyBuf; } @@ -2347,6 +2352,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) int i_attstattarget; int i_attnotnull; int i_atthasdef; + int i_attisdropped; PGresult *res; int ntups; bool hasdefaults; @@ -2386,7 +2392,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) if (g_fout->remoteVersion >= 70300) { appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, attstattarget, " - "attnotnull, atthasdef, " + "attnotnull, atthasdef, attisdropped, " "pg_catalog.format_type(atttypid,atttypmod) as atttypname " "from pg_catalog.pg_attribute a " "where attrelid = '%s'::pg_catalog.oid " @@ -2402,7 +2408,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) * explicitly set or was just a default. */ appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, -1 as attstattarget, " - "attnotnull, atthasdef, " + "attnotnull, atthasdef, false as attisdropped, " "format_type(atttypid,atttypmod) as atttypname " "from pg_attribute a " "where attrelid = '%s'::oid " @@ -2414,7 +2420,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) { /* format_type not available before 7.1 */ appendPQExpBuffer(q, "SELECT attnum, attname, atttypmod, -1 as attstattarget, " - "attnotnull, atthasdef, " + "attnotnull, atthasdef, false as attisdropped, " "(select typname from pg_type where oid = atttypid) as atttypname " "from pg_attribute a " "where attrelid = '%s'::oid " @@ -2439,12 +2445,14 @@ getTableAttrs(TableInfo *tblinfo, int numTables) i_attstattarget = PQfnumber(res, "attstattarget"); i_attnotnull = PQfnumber(res, "attnotnull"); i_atthasdef = PQfnumber(res, "atthasdef"); + i_attisdropped = PQfnumber(res, "attisdropped"); tblinfo[i].numatts = ntups; tblinfo[i].attnames = (char **) malloc(ntups * sizeof(char *)); tblinfo[i].atttypnames = (char **) malloc(ntups * sizeof(char *)); tblinfo[i].atttypmod = (int *) malloc(ntups * sizeof(int)); tblinfo[i].attstattarget = (int *) malloc(ntups * sizeof(int)); + tblinfo[i].attisdropped = (bool *) malloc(ntups * sizeof(bool)); tblinfo[i].notnull = (bool *) malloc(ntups * sizeof(bool)); tblinfo[i].adef_expr = (char **) malloc(ntups * sizeof(char *)); tblinfo[i].inhAttrs = (bool *) malloc(ntups * sizeof(bool)); @@ -2458,6 +2466,7 @@ getTableAttrs(TableInfo *tblinfo, int numTables) tblinfo[i].atttypnames[j] = strdup(PQgetvalue(res, j, i_atttypname)); tblinfo[i].atttypmod[j] = atoi(PQgetvalue(res, j, i_atttypmod)); tblinfo[i].attstattarget[j] = atoi(PQgetvalue(res, j, i_attstattarget)); + tblinfo[i].attisdropped[j] = (PQgetvalue(res, j, i_attisdropped)[0] == 't'); tblinfo[i].notnull[j] = (PQgetvalue(res, j, i_attnotnull)[0] == 't'); tblinfo[i].adef_expr[j] = NULL; /* fix below */ if (PQgetvalue(res, j, i_atthasdef)[0] == 't') @@ -4999,8 +5008,8 @@ dumpOneTable(Archive *fout, TableInfo *tbinfo, TableInfo *g_tblinfo) actual_atts = 0; for (j = 0; j < tbinfo->numatts; j++) { - /* Is this one of the table's own attrs ? */ - if (!tbinfo->inhAttrs[j]) + /* Is this one of the table's own attrs, and not dropped ? */ + if (!tbinfo->inhAttrs[j] && !tbinfo->attisdropped[j]) { /* Format properly if not first attr */ if (actual_atts > 0) @@ -5161,7 +5170,8 @@ dumpOneTable(Archive *fout, TableInfo *tbinfo, TableInfo *g_tblinfo) */ for (j = 0; j < tbinfo->numatts; j++) { - if (tbinfo->attstattarget[j] >= 0) + if (tbinfo->attstattarget[j] >= 0 && + !tbinfo->attisdropped[j]) { appendPQExpBuffer(q, "ALTER TABLE %s ", fmtId(tbinfo->relname, force_quotes)); @@ -6274,7 +6284,7 @@ fmtQualifiedId(const char *schema, const char *id) } /* - * return a column list clause for the qualified relname. + * return a column list clause for the given relation. * returns an empty string if the remote server is older than * 7.3. */ @@ -6284,9 +6294,11 @@ fmtCopyColumnList(const TableInfo* ti) static PQExpBuffer q = NULL; int numatts = ti->numatts; char** attnames = ti->attnames; + bool* attisdropped = ti->attisdropped; + bool needComma; int i; - if (g_fout->remoteVersion < 70300 ) + if (g_fout->remoteVersion < 70300) return ""; if (q) /* first time through? */ @@ -6295,15 +6307,18 @@ fmtCopyColumnList(const TableInfo* ti) q = createPQExpBuffer(); resetPQExpBuffer(q); - - appendPQExpBuffer(q,"("); + + appendPQExpBuffer(q, "("); + needComma = false; for (i = 0; i < numatts; i++) { - if( i > 0 ) - appendPQExpBuffer(q,","); - appendPQExpBuffer(q, fmtId(attnames[i], force_quotes)); + if (attisdropped[i]) + continue; + if (needComma) + appendPQExpBuffer(q, ","); + appendPQExpBuffer(q, "%s", fmtId(attnames[i], force_quotes)); + needComma = true; } appendPQExpBuffer(q, ")"); return q->data; } - diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index 6a6322c9ca..9a208f1e14 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_dump.h,v 1.93 2002/07/31 17:19:53 tgl Exp $ + * $Id: pg_dump.h,v 1.94 2002/08/02 18:15:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -128,6 +128,7 @@ typedef struct _tableInfo * all interesting tables so that we can tell which constraints were * inherited. */ + bool *attisdropped; /* true if attr is dropped; don't dump it */ bool *notnull; /* Not null constraints on attributes */ char **adef_expr; /* DEFAULT expressions */ bool *inhAttrs; /* true if each attribute is inherited */ diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index d60483870a..bff6c5b73d 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -3,7 +3,7 @@ * * Copyright 2000 by PostgreSQL Global Development Group * - * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.56 2002/07/20 05:57:31 momjian Exp $ + * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.57 2002/08/02 18:15:08 tgl Exp $ */ #include "postgres_fe.h" #include "describe.h" @@ -536,7 +536,7 @@ describeTableDetails(const char *name, bool desc) appendPQExpBuffer(&buf, "\nFROM pg_class c, pg_attribute a"); if (tableinfo.relkind == 'i') appendPQExpBuffer(&buf, ", pg_index i"); - appendPQExpBuffer(&buf, "\nWHERE c.relname = '%s'\n AND a.attnum > 0 AND a.attrelid = c.oid", name); + appendPQExpBuffer(&buf, "\nWHERE c.relname = '%s'\n AND a.attnum > 0 AND NOT a.attisdropped AND a.attrelid = c.oid", name); if (tableinfo.relkind == 'i') appendPQExpBuffer(&buf, " AND a.attrelid = i.indexrelid"); appendPQExpBuffer(&buf, "\nORDER BY a.attnum"); diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index f60ccae324..3eef1d55ee 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -3,7 +3,7 @@ * * Copyright 2000 by PostgreSQL Global Development Group * - * $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.53 2002/07/31 17:19:53 tgl Exp $ + * $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.54 2002/08/02 18:15:09 tgl Exp $ */ /*---------------------------------------------------------------------- @@ -156,7 +156,7 @@ pgsql_thing_t words_after_create[] = { #define Query_for_list_of_tables words_after_create[9].query #define Query_for_list_of_indexes words_after_create[4].query #define Query_for_list_of_databases words_after_create[1].query -#define Query_for_list_of_attributes "SELECT a.attname FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c WHERE c.oid = a.attrelid and a.attnum>0 and substr(a.attname,1,%d)='%s' and c.relname='%s'" +#define Query_for_list_of_attributes "SELECT a.attname FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c WHERE c.oid = a.attrelid and a.attnum>0 and not a.attisdropped and substr(a.attname,1,%d)='%s' and c.relname='%s'" #define Query_for_list_of_users words_after_create[14].query /* A couple of macros to ease typing. You can use these to complete the given diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 9dcd646e6f..f3e36226b0 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: catversion.h,v 1.143 2002/07/25 10:07:12 ishii Exp $ + * $Id: catversion.h,v 1.144 2002/08/02 18:15:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200207251 +#define CATALOG_VERSION_NO 200208011 #endif diff --git a/src/include/catalog/heap.h b/src/include/catalog/heap.h index 3148fd3263..f45c61515a 100644 --- a/src/include/catalog/heap.h +++ b/src/include/catalog/heap.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: heap.h,v 1.54 2002/07/15 16:33:31 tgl Exp $ + * $Id: heap.h,v 1.55 2002/08/02 18:15:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -63,6 +63,7 @@ extern int RemoveRelConstraints(Relation rel, const char *constrName, extern void DeleteRelationTuple(Oid relid); extern void DeleteAttributeTuples(Oid relid); +extern void RemoveAttributeById(Oid relid, AttrNumber attnum); extern void RemoveAttrDefault(Oid relid, AttrNumber attnum, DropBehavior behavior, bool complain); extern void RemoveAttrDefaultById(Oid attrdefId); diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h index 15945192a0..a888fcf523 100644 --- a/src/include/catalog/pg_attribute.h +++ b/src/include/catalog/pg_attribute.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_attribute.h,v 1.95 2002/07/31 17:19:54 tgl Exp $ + * $Id: pg_attribute.h,v 1.96 2002/08/02 18:15:09 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -143,6 +143,9 @@ CATALOG(pg_attribute) BOOTSTRAP BKI_WITHOUT_OIDS /* Has DEFAULT value or not */ bool atthasdef; + + /* Is dropped (ie, logically invisible) or not */ + bool attisdropped; } FormData_pg_attribute; /* @@ -151,7 +154,7 @@ CATALOG(pg_attribute) BOOTSTRAP BKI_WITHOUT_OIDS * because of alignment padding at the end of the struct.) */ #define ATTRIBUTE_TUPLE_SIZE \ - (offsetof(FormData_pg_attribute,atthasdef) + sizeof(bool)) + (offsetof(FormData_pg_attribute,attisdropped) + sizeof(bool)) /* ---------------- * Form_pg_attribute corresponds to a pointer to a tuple with @@ -165,7 +168,7 @@ typedef FormData_pg_attribute *Form_pg_attribute; * ---------------- */ -#define Natts_pg_attribute 15 +#define Natts_pg_attribute 16 #define Anum_pg_attribute_attrelid 1 #define Anum_pg_attribute_attname 2 #define Anum_pg_attribute_atttypid 3 @@ -181,6 +184,7 @@ typedef FormData_pg_attribute *Form_pg_attribute; #define Anum_pg_attribute_attalign 13 #define Anum_pg_attribute_attnotnull 14 #define Anum_pg_attribute_atthasdef 15 +#define Anum_pg_attribute_attisdropped 16 @@ -211,264 +215,266 @@ typedef FormData_pg_attribute *Form_pg_attribute; * ---------------- */ #define Schema_pg_type \ -{ 1247, {"typname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', false, 'i', false, false }, \ -{ 1247, {"typnamespace"}, 26, 0, 4, 2, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1247, {"typowner"}, 23, 0, 4, 3, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1247, {"typlen"}, 21, 0, 2, 4, 0, -1, -1, true, 'p', false, 's', false, false }, \ -{ 1247, {"typbyval"}, 16, 0, 1, 5, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1247, {"typtype"}, 18, 0, 1, 6, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1247, {"typisdefined"}, 16, 0, 1, 7, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1247, {"typdelim"}, 18, 0, 1, 8, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1247, {"typrelid"}, 26, 0, 4, 9, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1247, {"typelem"}, 26, 0, 4, 10, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1247, {"typinput"}, 24, 0, 4, 11, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1247, {"typoutput"}, 24, 0, 4, 12, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1247, {"typalign"}, 18, 0, 1, 13, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1247, {"typstorage"}, 18, 0, 1, 14, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1247, {"typnotnull"}, 16, 0, 1, 15, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1247, {"typbasetype"}, 26, 0, 4, 16, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1247, {"typtypmod"}, 23, 0, 4, 17, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1247, {"typndims"}, 23, 0, 4, 18, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1247, {"typdefaultbin"}, 25, 0, -1, 19, 0, -1, -1, false, 'x', false, 'i', false, false }, \ -{ 1247, {"typdefault"}, 25, 0, -1, 20, 0, -1, -1, false, 'x', false, 'i', false, false } +{ 1247, {"typname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', false, 'i', true, false, false }, \ +{ 1247, {"typnamespace"}, 26, 0, 4, 2, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1247, {"typowner"}, 23, 0, 4, 3, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1247, {"typlen"}, 21, 0, 2, 4, 0, -1, -1, true, 'p', false, 's', true, false, false }, \ +{ 1247, {"typbyval"}, 16, 0, 1, 5, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1247, {"typtype"}, 18, 0, 1, 6, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1247, {"typisdefined"}, 16, 0, 1, 7, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1247, {"typdelim"}, 18, 0, 1, 8, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1247, {"typrelid"}, 26, 0, 4, 9, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1247, {"typelem"}, 26, 0, 4, 10, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1247, {"typinput"}, 24, 0, 4, 11, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1247, {"typoutput"}, 24, 0, 4, 12, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1247, {"typalign"}, 18, 0, 1, 13, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1247, {"typstorage"}, 18, 0, 1, 14, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1247, {"typnotnull"}, 16, 0, 1, 15, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1247, {"typbasetype"}, 26, 0, 4, 16, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1247, {"typtypmod"}, 23, 0, 4, 17, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1247, {"typndims"}, 23, 0, 4, 18, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1247, {"typdefaultbin"}, 25, 0, -1, 19, 0, -1, -1, false, 'x', false, 'i', false, false, false }, \ +{ 1247, {"typdefault"}, 25, 0, -1, 20, 0, -1, -1, false, 'x', false, 'i', false, false, false } -DATA(insert ( 1247 typname 19 -1 NAMEDATALEN 1 0 -1 -1 f p f i f f)); -DATA(insert ( 1247 typnamespace 26 0 4 2 0 -1 -1 t p f i f f)); -DATA(insert ( 1247 typowner 23 0 4 3 0 -1 -1 t p f i f f)); -DATA(insert ( 1247 typlen 21 0 2 4 0 -1 -1 t p f s f f)); -DATA(insert ( 1247 typbyval 16 0 1 5 0 -1 -1 t p f c f f)); -DATA(insert ( 1247 typtype 18 0 1 6 0 -1 -1 t p f c f f)); -DATA(insert ( 1247 typisdefined 16 0 1 7 0 -1 -1 t p f c f f)); -DATA(insert ( 1247 typdelim 18 0 1 8 0 -1 -1 t p f c f f)); -DATA(insert ( 1247 typrelid 26 0 4 9 0 -1 -1 t p f i f f)); -DATA(insert ( 1247 typelem 26 0 4 10 0 -1 -1 t p f i f f)); -DATA(insert ( 1247 typinput 24 0 4 11 0 -1 -1 t p f i f f)); -DATA(insert ( 1247 typoutput 24 0 4 12 0 -1 -1 t p f i f f)); -DATA(insert ( 1247 typalign 18 0 1 13 0 -1 -1 t p f c f f)); -DATA(insert ( 1247 typstorage 18 0 1 14 0 -1 -1 t p f c f f)); -DATA(insert ( 1247 typnotnull 16 0 1 15 0 -1 -1 t p f c f f)); -DATA(insert ( 1247 typbasetype 26 0 4 16 0 -1 -1 t p f i f f)); -DATA(insert ( 1247 typtypmod 23 0 4 17 0 -1 -1 t p f i f f)); -DATA(insert ( 1247 typndims 23 0 4 18 0 -1 -1 t p f i f f)); -DATA(insert ( 1247 typdefaultbin 25 0 -1 19 0 -1 -1 f x f i f f)); -DATA(insert ( 1247 typdefault 25 0 -1 20 0 -1 -1 f x f i f f)); -DATA(insert ( 1247 ctid 27 0 6 -1 0 -1 -1 f p f i f f)); -DATA(insert ( 1247 oid 26 0 4 -2 0 -1 -1 t p f i f f)); -DATA(insert ( 1247 xmin 28 0 4 -3 0 -1 -1 t p f i f f)); -DATA(insert ( 1247 cmin 29 0 4 -4 0 -1 -1 t p f i f f)); -DATA(insert ( 1247 xmax 28 0 4 -5 0 -1 -1 t p f i f f)); -DATA(insert ( 1247 cmax 29 0 4 -6 0 -1 -1 t p f i f f)); -DATA(insert ( 1247 tableoid 26 0 4 -7 0 -1 -1 t p f i f f)); +DATA(insert ( 1247 typname 19 -1 NAMEDATALEN 1 0 -1 -1 f p f i t f f)); +DATA(insert ( 1247 typnamespace 26 0 4 2 0 -1 -1 t p f i t f f)); +DATA(insert ( 1247 typowner 23 0 4 3 0 -1 -1 t p f i t f f)); +DATA(insert ( 1247 typlen 21 0 2 4 0 -1 -1 t p f s t f f)); +DATA(insert ( 1247 typbyval 16 0 1 5 0 -1 -1 t p f c t f f)); +DATA(insert ( 1247 typtype 18 0 1 6 0 -1 -1 t p f c t f f)); +DATA(insert ( 1247 typisdefined 16 0 1 7 0 -1 -1 t p f c t f f)); +DATA(insert ( 1247 typdelim 18 0 1 8 0 -1 -1 t p f c t f f)); +DATA(insert ( 1247 typrelid 26 0 4 9 0 -1 -1 t p f i t f f)); +DATA(insert ( 1247 typelem 26 0 4 10 0 -1 -1 t p f i t f f)); +DATA(insert ( 1247 typinput 24 0 4 11 0 -1 -1 t p f i t f f)); +DATA(insert ( 1247 typoutput 24 0 4 12 0 -1 -1 t p f i t f f)); +DATA(insert ( 1247 typalign 18 0 1 13 0 -1 -1 t p f c t f f)); +DATA(insert ( 1247 typstorage 18 0 1 14 0 -1 -1 t p f c t f f)); +DATA(insert ( 1247 typnotnull 16 0 1 15 0 -1 -1 t p f c t f f)); +DATA(insert ( 1247 typbasetype 26 0 4 16 0 -1 -1 t p f i t f f)); +DATA(insert ( 1247 typtypmod 23 0 4 17 0 -1 -1 t p f i t f f)); +DATA(insert ( 1247 typndims 23 0 4 18 0 -1 -1 t p f i t f f)); +DATA(insert ( 1247 typdefaultbin 25 0 -1 19 0 -1 -1 f x f i f f f)); +DATA(insert ( 1247 typdefault 25 0 -1 20 0 -1 -1 f x f i f f f)); +DATA(insert ( 1247 ctid 27 0 6 -1 0 -1 -1 f p f i t f f)); +DATA(insert ( 1247 oid 26 0 4 -2 0 -1 -1 t p f i t f f)); +DATA(insert ( 1247 xmin 28 0 4 -3 0 -1 -1 t p f i t f f)); +DATA(insert ( 1247 cmin 29 0 4 -4 0 -1 -1 t p f i t f f)); +DATA(insert ( 1247 xmax 28 0 4 -5 0 -1 -1 t p f i t f f)); +DATA(insert ( 1247 cmax 29 0 4 -6 0 -1 -1 t p f i t f f)); +DATA(insert ( 1247 tableoid 26 0 4 -7 0 -1 -1 t p f i t f f)); /* ---------------- * pg_database * ---------------- */ -DATA(insert ( 1262 datname 19 0 NAMEDATALEN 1 0 -1 -1 f p f i f f)); -DATA(insert ( 1262 datdba 23 0 4 2 0 -1 -1 t p f i f f)); -DATA(insert ( 1262 encoding 23 0 4 3 0 -1 -1 t p f i f f)); -DATA(insert ( 1262 datistemplate 16 0 1 4 0 -1 -1 t p f c f f)); -DATA(insert ( 1262 datallowconn 16 0 1 5 0 -1 -1 t p f c f f)); -DATA(insert ( 1262 datlastsysoid 26 0 4 6 0 -1 -1 t p f i f f)); -DATA(insert ( 1262 datvacuumxid 28 0 4 7 0 -1 -1 t p f i f f)); -DATA(insert ( 1262 datfrozenxid 28 0 4 8 0 -1 -1 t p f i f f)); +DATA(insert ( 1262 datname 19 0 NAMEDATALEN 1 0 -1 -1 f p f i t f f)); +DATA(insert ( 1262 datdba 23 0 4 2 0 -1 -1 t p f i t f f)); +DATA(insert ( 1262 encoding 23 0 4 3 0 -1 -1 t p f i t f f)); +DATA(insert ( 1262 datistemplate 16 0 1 4 0 -1 -1 t p f c t f f)); +DATA(insert ( 1262 datallowconn 16 0 1 5 0 -1 -1 t p f c t f f)); +DATA(insert ( 1262 datlastsysoid 26 0 4 6 0 -1 -1 t p f i t f f)); +DATA(insert ( 1262 datvacuumxid 28 0 4 7 0 -1 -1 t p f i t f f)); +DATA(insert ( 1262 datfrozenxid 28 0 4 8 0 -1 -1 t p f i t f f)); /* do not mark datpath as toastable; GetRawDatabaseInfo won't cope */ -DATA(insert ( 1262 datpath 25 0 -1 9 0 -1 -1 f p f i f f)); -DATA(insert ( 1262 datconfig 1009 0 -1 10 0 -1 -1 f x f i f f)); -DATA(insert ( 1262 datacl 1034 0 -1 11 0 -1 -1 f x f i f f)); -DATA(insert ( 1262 ctid 27 0 6 -1 0 -1 -1 f p f i f f)); -DATA(insert ( 1262 oid 26 0 4 -2 0 -1 -1 t p f i f f)); -DATA(insert ( 1262 xmin 28 0 4 -3 0 -1 -1 t p f i f f)); -DATA(insert ( 1262 cmin 29 0 4 -4 0 -1 -1 t p f i f f)); -DATA(insert ( 1262 xmax 28 0 4 -5 0 -1 -1 t p f i f f)); -DATA(insert ( 1262 cmax 29 0 4 -6 0 -1 -1 t p f i f f)); -DATA(insert ( 1262 tableoid 26 0 4 -7 0 -1 -1 t p f i f f)); +DATA(insert ( 1262 datpath 25 0 -1 9 0 -1 -1 f p f i t f f)); +DATA(insert ( 1262 datconfig 1009 0 -1 10 0 -1 -1 f x f i f f f)); +DATA(insert ( 1262 datacl 1034 0 -1 11 0 -1 -1 f x f i f f f)); +DATA(insert ( 1262 ctid 27 0 6 -1 0 -1 -1 f p f i t f f)); +DATA(insert ( 1262 oid 26 0 4 -2 0 -1 -1 t p f i t f f)); +DATA(insert ( 1262 xmin 28 0 4 -3 0 -1 -1 t p f i t f f)); +DATA(insert ( 1262 cmin 29 0 4 -4 0 -1 -1 t p f i t f f)); +DATA(insert ( 1262 xmax 28 0 4 -5 0 -1 -1 t p f i t f f)); +DATA(insert ( 1262 cmax 29 0 4 -6 0 -1 -1 t p f i t f f)); +DATA(insert ( 1262 tableoid 26 0 4 -7 0 -1 -1 t p f i t f f)); /* ---------------- * pg_proc * ---------------- */ #define Schema_pg_proc \ -{ 1255, {"proname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', false, 'i', false, false }, \ -{ 1255, {"pronamespace"}, 26, 0, 4, 2, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1255, {"proowner"}, 23, 0, 4, 3, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1255, {"prolang"}, 26, 0, 4, 4, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1255, {"proisagg"}, 16, 0, 1, 5, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1255, {"prosecdef"}, 16, 0, 1, 6, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1255, {"proisstrict"}, 16, 0, 1, 7, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1255, {"proretset"}, 16, 0, 1, 8, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1255, {"provolatile"}, 18, 0, 1, 9, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1255, {"pronargs"}, 21, 0, 2, 10, 0, -1, -1, true, 'p', false, 's', false, false }, \ -{ 1255, {"prorettype"}, 26, 0, 4, 11, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1255, {"proargtypes"}, 30, 0, INDEX_MAX_KEYS*4, 12, 0, -1, -1, false, 'p', false, 'i', false, false }, \ -{ 1255, {"prosrc"}, 25, 0, -1, 13, 0, -1, -1, false, 'x', false, 'i', false, false }, \ -{ 1255, {"probin"}, 17, 0, -1, 14, 0, -1, -1, false, 'x', false, 'i', false, false }, \ -{ 1255, {"proacl"}, 1034, 0, -1, 15, 0, -1, -1, false, 'x', false, 'i', false, false } +{ 1255, {"proname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', false, 'i', true, false, false }, \ +{ 1255, {"pronamespace"}, 26, 0, 4, 2, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1255, {"proowner"}, 23, 0, 4, 3, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1255, {"prolang"}, 26, 0, 4, 4, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1255, {"proisagg"}, 16, 0, 1, 5, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1255, {"prosecdef"}, 16, 0, 1, 6, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1255, {"proisstrict"}, 16, 0, 1, 7, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1255, {"proretset"}, 16, 0, 1, 8, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1255, {"provolatile"}, 18, 0, 1, 9, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1255, {"pronargs"}, 21, 0, 2, 10, 0, -1, -1, true, 'p', false, 's', true, false, false }, \ +{ 1255, {"prorettype"}, 26, 0, 4, 11, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1255, {"proargtypes"}, 30, 0, INDEX_MAX_KEYS*4, 12, 0, -1, -1, false, 'p', false, 'i', true, false, false }, \ +{ 1255, {"prosrc"}, 25, 0, -1, 13, 0, -1, -1, false, 'x', false, 'i', false, false, false }, \ +{ 1255, {"probin"}, 17, 0, -1, 14, 0, -1, -1, false, 'x', false, 'i', false, false, false }, \ +{ 1255, {"proacl"}, 1034, 0, -1, 15, 0, -1, -1, false, 'x', false, 'i', false, false, false } -DATA(insert ( 1255 proname 19 -1 NAMEDATALEN 1 0 -1 -1 f p f i f f)); -DATA(insert ( 1255 pronamespace 26 0 4 2 0 -1 -1 t p f i f f)); -DATA(insert ( 1255 proowner 23 0 4 3 0 -1 -1 t p f i f f)); -DATA(insert ( 1255 prolang 26 0 4 4 0 -1 -1 t p f i f f)); -DATA(insert ( 1255 proisagg 16 0 1 5 0 -1 -1 t p f c f f)); -DATA(insert ( 1255 prosecdef 16 0 1 6 0 -1 -1 t p f c f f)); -DATA(insert ( 1255 proisstrict 16 0 1 7 0 -1 -1 t p f c f f)); -DATA(insert ( 1255 proretset 16 0 1 8 0 -1 -1 t p f c f f)); -DATA(insert ( 1255 provolatile 18 0 1 9 0 -1 -1 t p f c f f)); -DATA(insert ( 1255 pronargs 21 0 2 10 0 -1 -1 t p f s f f)); -DATA(insert ( 1255 prorettype 26 0 4 11 0 -1 -1 t p f i f f)); -DATA(insert ( 1255 proargtypes 30 0 INDEX_MAX_KEYS*4 12 0 -1 -1 f p f i f f)); -DATA(insert ( 1255 prosrc 25 0 -1 13 0 -1 -1 f x f i f f)); -DATA(insert ( 1255 probin 17 0 -1 14 0 -1 -1 f x f i f f)); -DATA(insert ( 1255 proacl 1034 0 -1 15 0 -1 -1 f x f i f f)); -DATA(insert ( 1255 ctid 27 0 6 -1 0 -1 -1 f p f i f f)); -DATA(insert ( 1255 oid 26 0 4 -2 0 -1 -1 t p f i f f)); -DATA(insert ( 1255 xmin 28 0 4 -3 0 -1 -1 t p f i f f)); -DATA(insert ( 1255 cmin 29 0 4 -4 0 -1 -1 t p f i f f)); -DATA(insert ( 1255 xmax 28 0 4 -5 0 -1 -1 t p f i f f)); -DATA(insert ( 1255 cmax 29 0 4 -6 0 -1 -1 t p f i f f)); -DATA(insert ( 1255 tableoid 26 0 4 -7 0 -1 -1 t p f i f f)); +DATA(insert ( 1255 proname 19 -1 NAMEDATALEN 1 0 -1 -1 f p f i t f f)); +DATA(insert ( 1255 pronamespace 26 0 4 2 0 -1 -1 t p f i t f f)); +DATA(insert ( 1255 proowner 23 0 4 3 0 -1 -1 t p f i t f f)); +DATA(insert ( 1255 prolang 26 0 4 4 0 -1 -1 t p f i t f f)); +DATA(insert ( 1255 proisagg 16 0 1 5 0 -1 -1 t p f c t f f)); +DATA(insert ( 1255 prosecdef 16 0 1 6 0 -1 -1 t p f c t f f)); +DATA(insert ( 1255 proisstrict 16 0 1 7 0 -1 -1 t p f c t f f)); +DATA(insert ( 1255 proretset 16 0 1 8 0 -1 -1 t p f c t f f)); +DATA(insert ( 1255 provolatile 18 0 1 9 0 -1 -1 t p f c t f f)); +DATA(insert ( 1255 pronargs 21 0 2 10 0 -1 -1 t p f s t f f)); +DATA(insert ( 1255 prorettype 26 0 4 11 0 -1 -1 t p f i t f f)); +DATA(insert ( 1255 proargtypes 30 0 INDEX_MAX_KEYS*4 12 0 -1 -1 f p f i t f f)); +DATA(insert ( 1255 prosrc 25 0 -1 13 0 -1 -1 f x f i f f f)); +DATA(insert ( 1255 probin 17 0 -1 14 0 -1 -1 f x f i f f f)); +DATA(insert ( 1255 proacl 1034 0 -1 15 0 -1 -1 f x f i f f f)); +DATA(insert ( 1255 ctid 27 0 6 -1 0 -1 -1 f p f i t f f)); +DATA(insert ( 1255 oid 26 0 4 -2 0 -1 -1 t p f i t f f)); +DATA(insert ( 1255 xmin 28 0 4 -3 0 -1 -1 t p f i t f f)); +DATA(insert ( 1255 cmin 29 0 4 -4 0 -1 -1 t p f i t f f)); +DATA(insert ( 1255 xmax 28 0 4 -5 0 -1 -1 t p f i t f f)); +DATA(insert ( 1255 cmax 29 0 4 -6 0 -1 -1 t p f i t f f)); +DATA(insert ( 1255 tableoid 26 0 4 -7 0 -1 -1 t p f i t f f)); /* ---------------- * pg_shadow * ---------------- */ -DATA(insert ( 1260 usename 19 -1 NAMEDATALEN 1 0 -1 -1 f p f i f f)); -DATA(insert ( 1260 usesysid 23 -1 4 2 0 -1 -1 t p f i f f)); -DATA(insert ( 1260 usecreatedb 16 0 1 3 0 -1 -1 t p f c f f)); -DATA(insert ( 1260 usesuper 16 0 1 4 0 -1 -1 t p f c f f)); -DATA(insert ( 1260 usecatupd 16 0 1 5 0 -1 -1 t p f c f f)); -DATA(insert ( 1260 passwd 25 0 -1 6 0 -1 -1 f x f i f f)); -DATA(insert ( 1260 valuntil 702 0 4 7 0 -1 -1 t p f i f f)); -DATA(insert ( 1260 useconfig 1009 0 -1 8 0 -1 -1 f x f i f f)); -DATA(insert ( 1260 ctid 27 0 6 -1 0 -1 -1 f p f i f f)); +DATA(insert ( 1260 usename 19 -1 NAMEDATALEN 1 0 -1 -1 f p f i t f f)); +DATA(insert ( 1260 usesysid 23 -1 4 2 0 -1 -1 t p f i t f f)); +DATA(insert ( 1260 usecreatedb 16 0 1 3 0 -1 -1 t p f c t f f)); +DATA(insert ( 1260 usesuper 16 0 1 4 0 -1 -1 t p f c t f f)); +DATA(insert ( 1260 usecatupd 16 0 1 5 0 -1 -1 t p f c t f f)); +DATA(insert ( 1260 passwd 25 0 -1 6 0 -1 -1 f x f i f f f)); +DATA(insert ( 1260 valuntil 702 0 4 7 0 -1 -1 t p f i f f f)); +DATA(insert ( 1260 useconfig 1009 0 -1 8 0 -1 -1 f x f i f f f)); +DATA(insert ( 1260 ctid 27 0 6 -1 0 -1 -1 f p f i t f f)); /* no OIDs in pg_shadow */ -DATA(insert ( 1260 xmin 28 0 4 -3 0 -1 -1 t p f i f f)); -DATA(insert ( 1260 cmin 29 0 4 -4 0 -1 -1 t p f i f f)); -DATA(insert ( 1260 xmax 28 0 4 -5 0 -1 -1 t p f i f f)); -DATA(insert ( 1260 cmax 29 0 4 -6 0 -1 -1 t p f i f f)); -DATA(insert ( 1260 tableoid 26 0 4 -7 0 -1 -1 t p f i f f)); +DATA(insert ( 1260 xmin 28 0 4 -3 0 -1 -1 t p f i t f f)); +DATA(insert ( 1260 cmin 29 0 4 -4 0 -1 -1 t p f i t f f)); +DATA(insert ( 1260 xmax 28 0 4 -5 0 -1 -1 t p f i t f f)); +DATA(insert ( 1260 cmax 29 0 4 -6 0 -1 -1 t p f i t f f)); +DATA(insert ( 1260 tableoid 26 0 4 -7 0 -1 -1 t p f i t f f)); /* ---------------- * pg_group * ---------------- */ -DATA(insert ( 1261 groname 19 -1 NAMEDATALEN 1 0 -1 -1 f p f i f f)); -DATA(insert ( 1261 grosysid 23 -1 4 2 0 -1 -1 t p f i f f)); -DATA(insert ( 1261 grolist 1007 0 -1 3 0 -1 -1 f x f i f f)); -DATA(insert ( 1261 ctid 27 0 6 -1 0 -1 -1 f p f i f f)); +DATA(insert ( 1261 groname 19 -1 NAMEDATALEN 1 0 -1 -1 f p f i t f f)); +DATA(insert ( 1261 grosysid 23 -1 4 2 0 -1 -1 t p f i t f f)); +DATA(insert ( 1261 grolist 1007 0 -1 3 0 -1 -1 f x f i f f f)); +DATA(insert ( 1261 ctid 27 0 6 -1 0 -1 -1 f p f i t f f)); /* no OIDs in pg_group */ -DATA(insert ( 1261 xmin 28 0 4 -3 0 -1 -1 t p f i f f)); -DATA(insert ( 1261 cmin 29 0 4 -4 0 -1 -1 t p f i f f)); -DATA(insert ( 1261 xmax 28 0 4 -5 0 -1 -1 t p f i f f)); -DATA(insert ( 1261 cmax 29 0 4 -6 0 -1 -1 t p f i f f)); -DATA(insert ( 1261 tableoid 26 0 4 -7 0 -1 -1 t p f i f f)); +DATA(insert ( 1261 xmin 28 0 4 -3 0 -1 -1 t p f i t f f)); +DATA(insert ( 1261 cmin 29 0 4 -4 0 -1 -1 t p f i t f f)); +DATA(insert ( 1261 xmax 28 0 4 -5 0 -1 -1 t p f i t f f)); +DATA(insert ( 1261 cmax 29 0 4 -6 0 -1 -1 t p f i t f f)); +DATA(insert ( 1261 tableoid 26 0 4 -7 0 -1 -1 t p f i t f f)); /* ---------------- * pg_attribute * ---------------- */ #define Schema_pg_attribute \ -{ 1249, {"attrelid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1249, {"attname"}, 19, -1, NAMEDATALEN, 2, 0, -1, -1, false, 'p', false, 'i', false, false }, \ -{ 1249, {"atttypid"}, 26, 0, 4, 3, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1249, {"attstattarget"}, 23, 0, 4, 4, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1249, {"attlen"}, 21, 0, 2, 5, 0, -1, -1, true, 'p', false, 's', false, false }, \ -{ 1249, {"attnum"}, 21, 0, 2, 6, 0, -1, -1, true, 'p', false, 's', false, false }, \ -{ 1249, {"attndims"}, 23, 0, 4, 7, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1249, {"attcacheoff"}, 23, 0, 4, 8, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1249, {"atttypmod"}, 23, 0, 4, 9, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1249, {"attbyval"}, 16, 0, 1, 10, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1249, {"attstorage"}, 18, 0, 1, 11, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1249, {"attisset"}, 16, 0, 1, 12, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1249, {"attalign"}, 18, 0, 1, 13, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1249, {"attnotnull"}, 16, 0, 1, 14, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1249, {"atthasdef"}, 16, 0, 1, 15, 0, -1, -1, true, 'p', false, 'c', false, false } +{ 1249, {"attrelid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1249, {"attname"}, 19, -1, NAMEDATALEN, 2, 0, -1, -1, false, 'p', false, 'i', true, false, false }, \ +{ 1249, {"atttypid"}, 26, 0, 4, 3, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1249, {"attstattarget"}, 23, 0, 4, 4, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1249, {"attlen"}, 21, 0, 2, 5, 0, -1, -1, true, 'p', false, 's', true, false, false }, \ +{ 1249, {"attnum"}, 21, 0, 2, 6, 0, -1, -1, true, 'p', false, 's', true, false, false }, \ +{ 1249, {"attndims"}, 23, 0, 4, 7, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1249, {"attcacheoff"}, 23, 0, 4, 8, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1249, {"atttypmod"}, 23, 0, 4, 9, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1249, {"attbyval"}, 16, 0, 1, 10, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1249, {"attstorage"}, 18, 0, 1, 11, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1249, {"attisset"}, 16, 0, 1, 12, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1249, {"attalign"}, 18, 0, 1, 13, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1249, {"attnotnull"}, 16, 0, 1, 14, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1249, {"atthasdef"}, 16, 0, 1, 15, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1249, {"attisdropped"}, 16, 0, 1, 16, 0, -1, -1, true, 'p', false, 'c', true, false, false } -DATA(insert ( 1249 attrelid 26 -1 4 1 0 -1 -1 t p f i f f)); -DATA(insert ( 1249 attname 19 -1 NAMEDATALEN 2 0 -1 -1 f p f i f f)); -DATA(insert ( 1249 atttypid 26 0 4 3 0 -1 -1 t p f i f f)); -DATA(insert ( 1249 attstattarget 23 0 4 4 0 -1 -1 t p f i f f)); -DATA(insert ( 1249 attlen 21 0 2 5 0 -1 -1 t p f s f f)); -DATA(insert ( 1249 attnum 21 0 2 6 0 -1 -1 t p f s f f)); -DATA(insert ( 1249 attndims 23 0 4 7 0 -1 -1 t p f i f f)); -DATA(insert ( 1249 attcacheoff 23 0 4 8 0 -1 -1 t p f i f f)); -DATA(insert ( 1249 atttypmod 23 0 4 9 0 -1 -1 t p f i f f)); -DATA(insert ( 1249 attbyval 16 0 1 10 0 -1 -1 t p f c f f)); -DATA(insert ( 1249 attstorage 18 0 1 11 0 -1 -1 t p f c f f)); -DATA(insert ( 1249 attisset 16 0 1 12 0 -1 -1 t p f c f f)); -DATA(insert ( 1249 attalign 18 0 1 13 0 -1 -1 t p f c f f)); -DATA(insert ( 1249 attnotnull 16 0 1 14 0 -1 -1 t p f c f f)); -DATA(insert ( 1249 atthasdef 16 0 1 15 0 -1 -1 t p f c f f)); -DATA(insert ( 1249 ctid 27 0 6 -1 0 -1 -1 f p f i f f)); +DATA(insert ( 1249 attrelid 26 -1 4 1 0 -1 -1 t p f i t f f)); +DATA(insert ( 1249 attname 19 -1 NAMEDATALEN 2 0 -1 -1 f p f i t f f)); +DATA(insert ( 1249 atttypid 26 0 4 3 0 -1 -1 t p f i t f f)); +DATA(insert ( 1249 attstattarget 23 0 4 4 0 -1 -1 t p f i t f f)); +DATA(insert ( 1249 attlen 21 0 2 5 0 -1 -1 t p f s t f f)); +DATA(insert ( 1249 attnum 21 0 2 6 0 -1 -1 t p f s t f f)); +DATA(insert ( 1249 attndims 23 0 4 7 0 -1 -1 t p f i t f f)); +DATA(insert ( 1249 attcacheoff 23 0 4 8 0 -1 -1 t p f i t f f)); +DATA(insert ( 1249 atttypmod 23 0 4 9 0 -1 -1 t p f i t f f)); +DATA(insert ( 1249 attbyval 16 0 1 10 0 -1 -1 t p f c t f f)); +DATA(insert ( 1249 attstorage 18 0 1 11 0 -1 -1 t p f c t f f)); +DATA(insert ( 1249 attisset 16 0 1 12 0 -1 -1 t p f c t f f)); +DATA(insert ( 1249 attalign 18 0 1 13 0 -1 -1 t p f c t f f)); +DATA(insert ( 1249 attnotnull 16 0 1 14 0 -1 -1 t p f c t f f)); +DATA(insert ( 1249 atthasdef 16 0 1 15 0 -1 -1 t p f c t f f)); +DATA(insert ( 1249 attisdropped 16 0 1 16 0 -1 -1 t p f c t f f)); +DATA(insert ( 1249 ctid 27 0 6 -1 0 -1 -1 f p f i t f f)); /* no OIDs in pg_attribute */ -DATA(insert ( 1249 xmin 28 0 4 -3 0 -1 -1 t p f i f f)); -DATA(insert ( 1249 cmin 29 0 4 -4 0 -1 -1 t p f i f f)); -DATA(insert ( 1249 xmax 28 0 4 -5 0 -1 -1 t p f i f f)); -DATA(insert ( 1249 cmax 29 0 4 -6 0 -1 -1 t p f i f f)); -DATA(insert ( 1249 tableoid 26 0 4 -7 0 -1 -1 t p f i f f)); +DATA(insert ( 1249 xmin 28 0 4 -3 0 -1 -1 t p f i t f f)); +DATA(insert ( 1249 cmin 29 0 4 -4 0 -1 -1 t p f i t f f)); +DATA(insert ( 1249 xmax 28 0 4 -5 0 -1 -1 t p f i t f f)); +DATA(insert ( 1249 cmax 29 0 4 -6 0 -1 -1 t p f i t f f)); +DATA(insert ( 1249 tableoid 26 0 4 -7 0 -1 -1 t p f i t f f)); /* ---------------- * pg_class * ---------------- */ #define Schema_pg_class \ -{ 1259, {"relname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', false, 'i', false, false }, \ -{ 1259, {"relnamespace"}, 26, 0, 4, 2, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1259, {"reltype"}, 26, 0, 4, 3, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1259, {"relowner"}, 23, 0, 4, 4, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1259, {"relam"}, 26, 0, 4, 5, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1259, {"relfilenode"}, 26, 0, 4, 6, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1259, {"relpages"}, 23, 0, 4, 7, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1259, {"reltuples"}, 700, 0, 4, 8, 0, -1, -1, false, 'p', false, 'i', false, false }, \ -{ 1259, {"reltoastrelid"}, 26, 0, 4, 9, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1259, {"reltoastidxid"}, 26, 0, 4, 10, 0, -1, -1, true, 'p', false, 'i', false, false }, \ -{ 1259, {"relhasindex"}, 16, 0, 1, 11, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1259, {"relisshared"}, 16, 0, 1, 12, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1259, {"relkind"}, 18, 0, 1, 13, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1259, {"relnatts"}, 21, 0, 2, 14, 0, -1, -1, true, 'p', false, 's', false, false }, \ -{ 1259, {"relchecks"}, 21, 0, 2, 15, 0, -1, -1, true, 'p', false, 's', false, false }, \ -{ 1259, {"reltriggers"}, 21, 0, 2, 16, 0, -1, -1, true, 'p', false, 's', false, false }, \ -{ 1259, {"relukeys"}, 21, 0, 2, 17, 0, -1, -1, true, 'p', false, 's', false, false }, \ -{ 1259, {"relfkeys"}, 21, 0, 2, 18, 0, -1, -1, true, 'p', false, 's', false, false }, \ -{ 1259, {"relrefs"}, 21, 0, 2, 19, 0, -1, -1, true, 'p', false, 's', false, false }, \ -{ 1259, {"relhasoids"}, 16, 0, 1, 20, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1259, {"relhaspkey"}, 16, 0, 1, 21, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1259, {"relhasrules"}, 16, 0, 1, 22, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1259, {"relhassubclass"},16, 0, 1, 23, 0, -1, -1, true, 'p', false, 'c', false, false }, \ -{ 1259, {"relacl"}, 1034, 0, -1, 24, 0, -1, -1, false, 'x', false, 'i', false, false } +{ 1259, {"relname"}, 19, -1, NAMEDATALEN, 1, 0, -1, -1, false, 'p', false, 'i', true, false, false }, \ +{ 1259, {"relnamespace"}, 26, 0, 4, 2, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1259, {"reltype"}, 26, 0, 4, 3, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1259, {"relowner"}, 23, 0, 4, 4, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1259, {"relam"}, 26, 0, 4, 5, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1259, {"relfilenode"}, 26, 0, 4, 6, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1259, {"relpages"}, 23, 0, 4, 7, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1259, {"reltuples"}, 700, 0, 4, 8, 0, -1, -1, false, 'p', false, 'i', true, false, false }, \ +{ 1259, {"reltoastrelid"}, 26, 0, 4, 9, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1259, {"reltoastidxid"}, 26, 0, 4, 10, 0, -1, -1, true, 'p', false, 'i', true, false, false }, \ +{ 1259, {"relhasindex"}, 16, 0, 1, 11, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1259, {"relisshared"}, 16, 0, 1, 12, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1259, {"relkind"}, 18, 0, 1, 13, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1259, {"relnatts"}, 21, 0, 2, 14, 0, -1, -1, true, 'p', false, 's', true, false, false }, \ +{ 1259, {"relchecks"}, 21, 0, 2, 15, 0, -1, -1, true, 'p', false, 's', true, false, false }, \ +{ 1259, {"reltriggers"}, 21, 0, 2, 16, 0, -1, -1, true, 'p', false, 's', true, false, false }, \ +{ 1259, {"relukeys"}, 21, 0, 2, 17, 0, -1, -1, true, 'p', false, 's', true, false, false }, \ +{ 1259, {"relfkeys"}, 21, 0, 2, 18, 0, -1, -1, true, 'p', false, 's', true, false, false }, \ +{ 1259, {"relrefs"}, 21, 0, 2, 19, 0, -1, -1, true, 'p', false, 's', true, false, false }, \ +{ 1259, {"relhasoids"}, 16, 0, 1, 20, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1259, {"relhaspkey"}, 16, 0, 1, 21, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1259, {"relhasrules"}, 16, 0, 1, 22, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1259, {"relhassubclass"},16, 0, 1, 23, 0, -1, -1, true, 'p', false, 'c', true, false, false }, \ +{ 1259, {"relacl"}, 1034, 0, -1, 24, 0, -1, -1, false, 'x', false, 'i', false, false, false } -DATA(insert ( 1259 relname 19 -1 NAMEDATALEN 1 0 -1 -1 f p f i f f)); -DATA(insert ( 1259 relnamespace 26 0 4 2 0 -1 -1 t p f i f f)); -DATA(insert ( 1259 reltype 26 0 4 3 0 -1 -1 t p f i f f)); -DATA(insert ( 1259 relowner 23 0 4 4 0 -1 -1 t p f i f f)); -DATA(insert ( 1259 relam 26 0 4 5 0 -1 -1 t p f i f f)); -DATA(insert ( 1259 relfilenode 26 0 4 6 0 -1 -1 t p f i f f)); -DATA(insert ( 1259 relpages 23 0 4 7 0 -1 -1 t p f i f f)); -DATA(insert ( 1259 reltuples 700 0 4 8 0 -1 -1 f p f i f f)); -DATA(insert ( 1259 reltoastrelid 26 0 4 9 0 -1 -1 t p f i f f)); -DATA(insert ( 1259 reltoastidxid 26 0 4 10 0 -1 -1 t p f i f f)); -DATA(insert ( 1259 relhasindex 16 0 1 11 0 -1 -1 t p f c f f)); -DATA(insert ( 1259 relisshared 16 0 1 12 0 -1 -1 t p f c f f)); -DATA(insert ( 1259 relkind 18 0 1 13 0 -1 -1 t p f c f f)); -DATA(insert ( 1259 relnatts 21 0 2 14 0 -1 -1 t p f s f f)); -DATA(insert ( 1259 relchecks 21 0 2 15 0 -1 -1 t p f s f f)); -DATA(insert ( 1259 reltriggers 21 0 2 16 0 -1 -1 t p f s f f)); -DATA(insert ( 1259 relukeys 21 0 2 17 0 -1 -1 t p f s f f)); -DATA(insert ( 1259 relfkeys 21 0 2 18 0 -1 -1 t p f s f f)); -DATA(insert ( 1259 relrefs 21 0 2 19 0 -1 -1 t p f s f f)); -DATA(insert ( 1259 relhasoids 16 0 1 20 0 -1 -1 t p f c f f)); -DATA(insert ( 1259 relhaspkey 16 0 1 21 0 -1 -1 t p f c f f)); -DATA(insert ( 1259 relhasrules 16 0 1 22 0 -1 -1 t p f c f f)); -DATA(insert ( 1259 relhassubclass 16 0 1 23 0 -1 -1 t p f c f f)); -DATA(insert ( 1259 relacl 1034 0 -1 24 0 -1 -1 f x f i f f)); -DATA(insert ( 1259 ctid 27 0 6 -1 0 -1 -1 f p f i f f)); -DATA(insert ( 1259 oid 26 0 4 -2 0 -1 -1 t p f i f f)); -DATA(insert ( 1259 xmin 28 0 4 -3 0 -1 -1 t p f i f f)); -DATA(insert ( 1259 cmin 29 0 4 -4 0 -1 -1 t p f i f f)); -DATA(insert ( 1259 xmax 28 0 4 -5 0 -1 -1 t p f i f f)); -DATA(insert ( 1259 cmax 29 0 4 -6 0 -1 -1 t p f i f f)); -DATA(insert ( 1259 tableoid 26 0 4 -7 0 -1 -1 t p f i f f)); +DATA(insert ( 1259 relname 19 -1 NAMEDATALEN 1 0 -1 -1 f p f i t f f)); +DATA(insert ( 1259 relnamespace 26 0 4 2 0 -1 -1 t p f i t f f)); +DATA(insert ( 1259 reltype 26 0 4 3 0 -1 -1 t p f i t f f)); +DATA(insert ( 1259 relowner 23 0 4 4 0 -1 -1 t p f i t f f)); +DATA(insert ( 1259 relam 26 0 4 5 0 -1 -1 t p f i t f f)); +DATA(insert ( 1259 relfilenode 26 0 4 6 0 -1 -1 t p f i t f f)); +DATA(insert ( 1259 relpages 23 0 4 7 0 -1 -1 t p f i t f f)); +DATA(insert ( 1259 reltuples 700 0 4 8 0 -1 -1 f p f i t f f)); +DATA(insert ( 1259 reltoastrelid 26 0 4 9 0 -1 -1 t p f i t f f)); +DATA(insert ( 1259 reltoastidxid 26 0 4 10 0 -1 -1 t p f i t f f)); +DATA(insert ( 1259 relhasindex 16 0 1 11 0 -1 -1 t p f c t f f)); +DATA(insert ( 1259 relisshared 16 0 1 12 0 -1 -1 t p f c t f f)); +DATA(insert ( 1259 relkind 18 0 1 13 0 -1 -1 t p f c t f f)); +DATA(insert ( 1259 relnatts 21 0 2 14 0 -1 -1 t p f s t f f)); +DATA(insert ( 1259 relchecks 21 0 2 15 0 -1 -1 t p f s t f f)); +DATA(insert ( 1259 reltriggers 21 0 2 16 0 -1 -1 t p f s t f f)); +DATA(insert ( 1259 relukeys 21 0 2 17 0 -1 -1 t p f s t f f)); +DATA(insert ( 1259 relfkeys 21 0 2 18 0 -1 -1 t p f s t f f)); +DATA(insert ( 1259 relrefs 21 0 2 19 0 -1 -1 t p f s t f f)); +DATA(insert ( 1259 relhasoids 16 0 1 20 0 -1 -1 t p f c t f f)); +DATA(insert ( 1259 relhaspkey 16 0 1 21 0 -1 -1 t p f c t f f)); +DATA(insert ( 1259 relhasrules 16 0 1 22 0 -1 -1 t p f c t f f)); +DATA(insert ( 1259 relhassubclass 16 0 1 23 0 -1 -1 t p f c t f f)); +DATA(insert ( 1259 relacl 1034 0 -1 24 0 -1 -1 f x f i f f f)); +DATA(insert ( 1259 ctid 27 0 6 -1 0 -1 -1 f p f i t f f)); +DATA(insert ( 1259 oid 26 0 4 -2 0 -1 -1 t p f i t f f)); +DATA(insert ( 1259 xmin 28 0 4 -3 0 -1 -1 t p f i t f f)); +DATA(insert ( 1259 cmin 29 0 4 -4 0 -1 -1 t p f i t f f)); +DATA(insert ( 1259 xmax 28 0 4 -5 0 -1 -1 t p f i t f f)); +DATA(insert ( 1259 cmax 29 0 4 -6 0 -1 -1 t p f i t f f)); +DATA(insert ( 1259 tableoid 26 0 4 -7 0 -1 -1 t p f i t f f)); /* ---------------- * pg_xactlock - this is not a real relation, but is a placeholder @@ -478,6 +484,6 @@ DATA(insert ( 1259 tableoid 26 0 4 -7 0 -1 -1 t p f i f f)); * table; and this entry is just to link to that one. * ---------------- */ -DATA(insert ( 376 xactlockfoo 26 0 4 1 0 -1 -1 t p f i f f)); +DATA(insert ( 376 xactlockfoo 26 0 4 1 0 -1 -1 t p f i t f f)); #endif /* PG_ATTRIBUTE_H */ diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index 827769029f..2d5011e6d6 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_class.h,v 1.69 2002/07/24 19:11:12 petere Exp $ + * $Id: pg_class.h,v 1.70 2002/08/02 18:15:09 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -136,7 +136,7 @@ typedef FormData_pg_class *Form_pg_class; DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 f f r 20 0 0 0 0 0 t f f f _null_ )); DESCR(""); -DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 f f r 15 0 0 0 0 0 f f f f _null_ )); +DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 f f r 16 0 0 0 0 0 f f f f _null_ )); DESCR(""); DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 f f r 15 0 0 0 0 0 t f f f _null_ )); DESCR(""); diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 9eb7367f2e..2fdb5bc210 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: executor.h,v 1.72 2002/07/20 15:12:55 tgl Exp $ + * $Id: executor.h,v 1.73 2002/08/02 18:15:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -159,7 +159,6 @@ extern void ExecAssignScanType(CommonScanState *csstate, TupleDesc tupDesc, bool shouldFree); extern void ExecAssignScanTypeFromOuterPlan(Plan *node, CommonScanState *csstate); -extern Form_pg_attribute ExecGetTypeInfo(Relation relDesc); extern ExprContext *MakeExprContext(TupleTableSlot *slot, MemoryContext queryContext); diff --git a/src/include/parser/parse_relation.h b/src/include/parser/parse_relation.h index 5ff6d74e36..a34e2a5619 100644 --- a/src/include/parser/parse_relation.h +++ b/src/include/parser/parse_relation.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: parse_relation.h,v 1.34 2002/06/20 20:29:51 momjian Exp $ + * $Id: parse_relation.h,v 1.35 2002/08/02 18:15:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -58,7 +58,7 @@ extern RangeTblEntry *addImplicitRTE(ParseState *pstate, RangeVar *relation); extern void expandRTE(ParseState *pstate, RangeTblEntry *rte, List **colnames, List **colvars); extern List *expandRelAttrs(ParseState *pstate, RangeTblEntry *rte); -extern int attnameAttNum(Relation rd, char *a); +extern int attnameAttNum(Relation rd, const char *attname, bool sysColOK); extern Name attnumAttName(Relation rd, int attid); extern Oid attnumTypeId(Relation rd, int attid); diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index dcc310aab5..ab06031b2c 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: lsyscache.h,v 1.55 2002/07/12 18:43:19 tgl Exp $ + * $Id: lsyscache.h,v 1.56 2002/08/02 18:15:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -18,9 +18,8 @@ extern bool op_in_opclass(Oid opno, Oid opclass); extern bool op_requires_recheck(Oid opno, Oid opclass); extern char *get_attname(Oid relid, AttrNumber attnum); -extern AttrNumber get_attnum(Oid relid, char *attname); +extern AttrNumber get_attnum(Oid relid, const char *attname); extern Oid get_atttype(Oid relid, AttrNumber attnum); -extern bool get_attisset(Oid relid, char *attname); extern int32 get_atttypmod(Oid relid, AttrNumber attnum); extern void get_atttypetypmod(Oid relid, AttrNumber attnum, Oid *typid, int32 *typmod); diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index e8c70fa00b..b9a17c7453 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -9,7 +9,7 @@ * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: syscache.h,v 1.51 2002/07/25 10:07:13 ishii Exp $ + * $Id: syscache.h,v 1.52 2002/08/02 18:15:09 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -78,6 +78,10 @@ extern bool SearchSysCacheExists(int cacheId, extern Oid GetSysCacheOid(int cacheId, Datum key1, Datum key2, Datum key3, Datum key4); +extern HeapTuple SearchSysCacheAttName(Oid relid, const char *attname); +extern HeapTuple SearchSysCacheCopyAttName(Oid relid, const char *attname); +extern bool SearchSysCacheExistsAttName(Oid relid, const char *attname); + extern Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull); diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 8f6ff87cf6..bc95eba1ed 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -3,7 +3,7 @@ * procedural language * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.42 2002/06/15 19:54:24 momjian Exp $ + * $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.43 2002/08/02 18:15:09 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -1037,10 +1037,7 @@ plpgsql_parse_dblwordtype(char *string) /* * Fetch the named table field and it's type */ - attrtup = SearchSysCache(ATTNAME, - ObjectIdGetDatum(classOid), - PointerGetDatum(word2), - 0, 0); + attrtup = SearchSysCacheAttName(classOid, word2); if (!HeapTupleIsValid(attrtup)) { ReleaseSysCache(classtup); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 2dc64f3ccf..741b012c28 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -635,9 +635,9 @@ delete from atacc1; alter table atacc1 alter test set not null; -- try altering a non-existent column, should fail alter table atacc1 alter bar set not null; -ERROR: ALTER TABLE: relation "atacc1" has no column "bar" +ERROR: Relation "atacc1" has no column "bar" alter table atacc1 alter bar drop not null; -ERROR: ALTER TABLE: relation "atacc1" has no column "bar" +ERROR: Relation "atacc1" has no column "bar" -- try altering the oid column, should fail alter table atacc1 alter oid set not null; ERROR: ALTER TABLE: Cannot alter system attribute "oid" @@ -707,7 +707,7 @@ ERROR: pg_atoi: error in "wrong_datatype": can't parse "wrong_datatype" alter table def_test alter column c2 set default 20; -- set defaults on a non-existent column: this should fail alter table def_test alter column c3 set default 30; -ERROR: ALTER TABLE: relation "def_test" has no column "c3" +ERROR: Relation "def_test" has no column "c3" -- set defaults on views: we need to create a view, add a rule -- to allow insertions into it, and then alter the view to add -- a default @@ -735,3 +735,291 @@ select * from def_view_test; drop rule def_view_test_ins on def_view_test; drop view def_view_test; drop table def_test; +-- alter table / drop column tests +-- try altering system catalogs, should fail +alter table pg_class drop column relname; +ERROR: ALTER TABLE: relation "pg_class" is a system catalog +-- try altering non-existent table, should fail +alter table foo drop column bar; +ERROR: Relation "foo" does not exist +-- test dropping columns +create table atacc1 (a int4 not null, b int4, c int4 not null, d int4); +insert into atacc1 values (1, 2, 3, 4); +alter table atacc1 drop a; +alter table atacc1 drop a; +ERROR: Relation "atacc1" has no column "a" +-- SELECTs +select * from atacc1; + b | c | d +---+---+--- + 2 | 3 | 4 +(1 row) + +select * from atacc1 order by a; +ERROR: Attribute "a" not found +select * from atacc1 order by "........pg.dropped.1........"; +ERROR: Attribute "........pg.dropped.1........" not found +select * from atacc1 group by a; +ERROR: Attribute "a" not found +select * from atacc1 group by "........pg.dropped.1........"; +ERROR: Attribute "........pg.dropped.1........" not found +select atacc1.* from atacc1; + b | c | d +---+---+--- + 2 | 3 | 4 +(1 row) + +select a from atacc1; +ERROR: Attribute "a" not found +select atacc1.a from atacc1; +ERROR: No such attribute atacc1.a +select b,c,d from atacc1; + b | c | d +---+---+--- + 2 | 3 | 4 +(1 row) + +select a,b,c,d from atacc1; +ERROR: Attribute "a" not found +select * from atacc1 where a = 1; +ERROR: Attribute "a" not found +select "........pg.dropped.1........" from atacc1; +ERROR: Attribute "........pg.dropped.1........" not found +select atacc1."........pg.dropped.1........" from atacc1; +ERROR: No such attribute atacc1.........pg.dropped.1........ +select "........pg.dropped.1........",b,c,d from atacc1; +ERROR: Attribute "........pg.dropped.1........" not found +select * from atacc1 where "........pg.dropped.1........" = 1; +ERROR: Attribute "........pg.dropped.1........" not found +-- UPDATEs +update atacc1 set a = 3; +ERROR: Relation "atacc1" has no column "a" +update atacc1 set b = 2 where a = 3; +ERROR: Attribute "a" not found +update atacc1 set "........pg.dropped.1........" = 3; +ERROR: Relation "atacc1" has no column "........pg.dropped.1........" +update atacc1 set b = 2 where "........pg.dropped.1........" = 3; +ERROR: Attribute "........pg.dropped.1........" not found +-- INSERTs +insert into atacc1 values (10, 11, 12, 13); +ERROR: INSERT has more expressions than target columns +insert into atacc1 values (default, 11, 12, 13); +ERROR: INSERT has more expressions than target columns +insert into atacc1 values (11, 12, 13); +insert into atacc1 (a) values (10); +ERROR: Relation "atacc1" has no column "a" +insert into atacc1 (a) values (default); +ERROR: Relation "atacc1" has no column "a" +insert into atacc1 (a,b,c,d) values (10,11,12,13); +ERROR: Relation "atacc1" has no column "a" +insert into atacc1 (a,b,c,d) values (default,11,12,13); +ERROR: Relation "atacc1" has no column "a" +insert into atacc1 (b,c,d) values (11,12,13); +insert into atacc1 ("........pg.dropped.1........") values (10); +ERROR: Relation "atacc1" has no column "........pg.dropped.1........" +insert into atacc1 ("........pg.dropped.1........") values (default); +ERROR: Relation "atacc1" has no column "........pg.dropped.1........" +insert into atacc1 ("........pg.dropped.1........",b,c,d) values (10,11,12,13); +ERROR: Relation "atacc1" has no column "........pg.dropped.1........" +insert into atacc1 ("........pg.dropped.1........",b,c,d) values (default,11,12,13); +ERROR: Relation "atacc1" has no column "........pg.dropped.1........" +-- DELETEs +delete from atacc1 where a = 3; +ERROR: Attribute "a" not found +delete from atacc1 where "........pg.dropped.1........" = 3; +ERROR: Attribute "........pg.dropped.1........" not found +delete from atacc1; +-- try dropping a non-existent column, should fail +alter table atacc1 drop bar; +ERROR: Relation "atacc1" has no column "bar" +-- try dropping the oid column, should fail +alter table atacc1 drop oid; +ERROR: ALTER TABLE: Cannot drop system attribute "oid" +-- try creating a view and altering that, should fail +create view myview as select * from atacc1; +select * from myview; + b | c | d +---+---+--- +(0 rows) + +alter table myview drop d; +ERROR: ALTER TABLE: relation "myview" is not a table +drop view myview; +-- test some commands to make sure they fail on the dropped column +analyze atacc1(a); +ERROR: Relation "atacc1" has no column "a" +analyze atacc1("........pg.dropped.1........"); +ERROR: Relation "atacc1" has no column "........pg.dropped.1........" +vacuum analyze atacc1(a); +ERROR: Relation "atacc1" has no column "a" +vacuum analyze atacc1("........pg.dropped.1........"); +ERROR: Relation "atacc1" has no column "........pg.dropped.1........" +comment on column atacc1.a is 'testing'; +ERROR: Relation "atacc1" has no column "a" +comment on column atacc1."........pg.dropped.1........" is 'testing'; +ERROR: Relation "atacc1" has no column "........pg.dropped.1........" +alter table atacc1 alter a set storage plain; +ERROR: ALTER TABLE: relation "atacc1" has no column "a" +alter table atacc1 alter "........pg.dropped.1........" set storage plain; +ERROR: ALTER TABLE: relation "atacc1" has no column "........pg.dropped.1........" +alter table atacc1 alter a set statistics 0; +ERROR: ALTER TABLE: relation "atacc1" has no column "a" +alter table atacc1 alter "........pg.dropped.1........" set statistics 0; +ERROR: ALTER TABLE: relation "atacc1" has no column "........pg.dropped.1........" +alter table atacc1 alter a set default 3; +ERROR: Relation "atacc1" has no column "a" +alter table atacc1 alter "........pg.dropped.1........" set default 3; +ERROR: Relation "atacc1" has no column "........pg.dropped.1........" +alter table atacc1 alter a drop default; +ERROR: Relation "atacc1" has no column "a" +alter table atacc1 alter "........pg.dropped.1........" drop default; +ERROR: Relation "atacc1" has no column "........pg.dropped.1........" +alter table atacc1 alter a set not null; +ERROR: Relation "atacc1" has no column "a" +alter table atacc1 alter "........pg.dropped.1........" set not null; +ERROR: Relation "atacc1" has no column "........pg.dropped.1........" +alter table atacc1 alter a drop not null; +ERROR: Relation "atacc1" has no column "a" +alter table atacc1 alter "........pg.dropped.1........" drop not null; +ERROR: Relation "atacc1" has no column "........pg.dropped.1........" +alter table atacc1 rename a to x; +ERROR: renameatt: attribute "a" does not exist +alter table atacc1 rename "........pg.dropped.1........" to x; +ERROR: renameatt: attribute "........pg.dropped.1........" does not exist +alter table atacc1 add primary key(a); +ERROR: ALTER TABLE: column "a" named in key does not exist +alter table atacc1 add primary key("........pg.dropped.1........"); +ERROR: ALTER TABLE: column "........pg.dropped.1........" named in key does not exist +alter table atacc1 add unique(a); +ERROR: ALTER TABLE: column "a" named in key does not exist +alter table atacc1 add unique("........pg.dropped.1........"); +ERROR: ALTER TABLE: column "........pg.dropped.1........" named in key does not exist +alter table atacc1 add check (a > 3); +ERROR: Attribute "a" not found +alter table atacc1 add check ("........pg.dropped.1........" > 3); +ERROR: Attribute "........pg.dropped.1........" not found +create table atacc2 (id int4 unique); +NOTICE: CREATE TABLE / UNIQUE will create implicit index 'atacc2_id_key' for table 'atacc2' +alter table atacc1 add foreign key (a) references atacc2(id); +NOTICE: ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s) +ERROR: ALTER TABLE: column "a" referenced in foreign key constraint does not exist +alter table atacc1 add foreign key ("........pg.dropped.1........") references atacc2(id); +NOTICE: ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s) +ERROR: ALTER TABLE: column "........pg.dropped.1........" referenced in foreign key constraint does not exist +alter table atacc2 add foreign key (id) references atacc1(a); +NOTICE: ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s) +ERROR: UNIQUE constraint matching given keys for referenced table "atacc1" not found +alter table atacc2 add foreign key (id) references atacc1("........pg.dropped.1........"); +NOTICE: ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s) +ERROR: UNIQUE constraint matching given keys for referenced table "atacc1" not found +drop table atacc2; +create index "testing_idx" on atacc1(a); +ERROR: DefineIndex: attribute "a" not found +create index "testing_idx" on atacc1("........pg.dropped.1........"); +ERROR: DefineIndex: attribute "........pg.dropped.1........" not found +-- test create as and select into +insert into atacc1 values (21, 22, 23); +create table test1 as select * from atacc1; +select * from test1; + b | c | d +----+----+---- + 21 | 22 | 23 +(1 row) + +drop table test1; +select * into test2 from atacc1; +select * from test2; + b | c | d +----+----+---- + 21 | 22 | 23 +(1 row) + +drop table test2; +-- try dropping all columns +alter table atacc1 drop c; +alter table atacc1 drop d; +alter table atacc1 drop b; +ERROR: ALTER TABLE: Cannot drop last column from table "atacc1" +select * from atacc1; + b +---- + 21 +(1 row) + +drop table atacc1; +-- test inheritance +create table parent (a int, b int, c int); +insert into parent values (1, 2, 3); +alter table parent drop a; +create table child (d varchar(255)) inherits (parent); +insert into child values (12, 13, 'testing'); +select * from parent; + b | c +----+---- + 2 | 3 + 12 | 13 +(2 rows) + +select * from child; + b | c | d +----+----+--------- + 12 | 13 | testing +(1 row) + +alter table parent drop c; +select * from parent; + b +---- + 2 + 12 +(2 rows) + +select * from child; + b | d +----+--------- + 12 | testing +(1 row) + +drop table child; +drop table parent; +-- test copy in/out +create table test (a int4, b int4, c int4); +insert into test values (1,2,3); +alter table test drop a; +copy test to stdout; +2 3 +copy test(a) to stdout; +ERROR: Relation "test" has no column "a" +copy test("........pg.dropped.1........") to stdout; +ERROR: Relation "test" has no column "........pg.dropped.1........" +copy test from stdin; +ERROR: copy: line 1, Extra data after last expected column +lost synchronization with server, resetting connection +select * from test; + b | c +---+--- + 2 | 3 +(1 row) + +copy test from stdin; +select * from test; + b | c +----+---- + 2 | 3 + 21 | 22 +(2 rows) + +copy test(a) from stdin; +ERROR: Relation "test" has no column "a" +copy test("........pg.dropped.1........") from stdin; +ERROR: Relation "test" has no column "........pg.dropped.1........" +copy test(b,c) from stdin; +select * from test; + b | c +----+---- + 2 | 3 + 21 | 22 + 31 | 32 +(3 rows) + +drop table test; diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out index e4f806c8a5..58a5b6eb22 100644 --- a/src/test/regress/expected/copy2.out +++ b/src/test/regress/expected/copy2.out @@ -29,26 +29,44 @@ COPY x (b, d) from stdin; COPY x (a, b, c, d, e) from stdin; -- non-existent column in column list: should fail COPY x (xyz) from stdin; -ERROR: COPY: Specified column "xyz" does not exist +ERROR: Relation "x" has no column "xyz" -- too many columns in column list: should fail COPY x (a, b, c, d, e, d, c) from stdin; -ERROR: COPY: Too many columns specified +ERROR: Attribute "d" specified more than once -- missing data: should fail COPY x from stdin; -ERROR: copy: line 1, COPY TEXT: Missing data for attribute 1 +ERROR: copy: line 1, Missing data for column "b" lost synchronization with server, resetting connection COPY x from stdin; -ERROR: copy: line 1, COPY TEXT: Missing data for attribute 4 +ERROR: copy: line 1, Missing data for column "e" lost synchronization with server, resetting connection COPY x from stdin; -ERROR: copy: line 1, COPY TEXT: Missing data for attribute 4 +ERROR: copy: line 1, Missing data for column "e" lost synchronization with server, resetting connection -- extra data: should fail COPY x from stdin; -ERROR: copy: line 1, COPY TEXT: Extra data encountered +ERROR: copy: line 1, Extra data after last expected column lost synchronization with server, resetting connection -- various COPY options: delimiters, oids, NULL string COPY x (b, c, d, e) from stdin with oids delimiter ',' null 'x'; +-- check results of copy in +SELECT * FROM x; + a | b | c | d | e +-------+----+-------+--------+---------------------- + 10000 | 21 | 31 | 41 | before trigger fired + 10001 | 22 | 32 | 42 | before trigger fired + 10002 | 23 | 33 | 43 | before trigger fired + 10003 | 24 | 34 | 44 | before trigger fired + 10004 | 25 | 35 | 45 | before trigger fired + 10005 | 26 | 36 | 46 | before trigger fired + 6 | | 45 | 80 | before trigger fired + 1 | 1 | stuff | test_1 | after trigger fired + 2 | 2 | stuff | test_2 | after trigger fired + 3 | 3 | stuff | test_3 | after trigger fired + 4 | 4 | stuff | test_4 | after trigger fired + 5 | 5 | stuff | test_5 | after trigger fired +(12 rows) + -- COPY w/ oids on a table w/o oids should fail CREATE TABLE no_oids ( a int, @@ -61,6 +79,7 @@ COPY no_oids FROM stdin WITH OIDS; ERROR: COPY: table "no_oids" does not have OIDs COPY no_oids TO stdout WITH OIDS; ERROR: COPY: table "no_oids" does not have OIDs +-- check copy out COPY x TO stdout; 10000 21 31 41 before trigger fired 10001 22 32 42 before trigger fired @@ -87,6 +106,19 @@ stuff after trigger fired stuff after trigger fired stuff after trigger fired stuff after trigger fired +COPY x (b, e) TO stdout WITH NULL 'I''m null'; +21 before trigger fired +22 before trigger fired +23 before trigger fired +24 before trigger fired +25 before trigger fired +26 before trigger fired +I'm null before trigger fired +1 after trigger fired +2 after trigger fired +3 after trigger fired +4 after trigger fired +5 after trigger fired DROP TABLE x; DROP FUNCTION fn_x_before(); DROP FUNCTION fn_x_after(); diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index f39998073d..8946d2b15b 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -571,3 +571,163 @@ select * from def_view_test; drop rule def_view_test_ins on def_view_test; drop view def_view_test; drop table def_test; + +-- alter table / drop column tests +-- try altering system catalogs, should fail +alter table pg_class drop column relname; + +-- try altering non-existent table, should fail +alter table foo drop column bar; + +-- test dropping columns +create table atacc1 (a int4 not null, b int4, c int4 not null, d int4); +insert into atacc1 values (1, 2, 3, 4); +alter table atacc1 drop a; +alter table atacc1 drop a; + +-- SELECTs +select * from atacc1; +select * from atacc1 order by a; +select * from atacc1 order by "........pg.dropped.1........"; +select * from atacc1 group by a; +select * from atacc1 group by "........pg.dropped.1........"; +select atacc1.* from atacc1; +select a from atacc1; +select atacc1.a from atacc1; +select b,c,d from atacc1; +select a,b,c,d from atacc1; +select * from atacc1 where a = 1; +select "........pg.dropped.1........" from atacc1; +select atacc1."........pg.dropped.1........" from atacc1; +select "........pg.dropped.1........",b,c,d from atacc1; +select * from atacc1 where "........pg.dropped.1........" = 1; + +-- UPDATEs +update atacc1 set a = 3; +update atacc1 set b = 2 where a = 3; +update atacc1 set "........pg.dropped.1........" = 3; +update atacc1 set b = 2 where "........pg.dropped.1........" = 3; + +-- INSERTs +insert into atacc1 values (10, 11, 12, 13); +insert into atacc1 values (default, 11, 12, 13); +insert into atacc1 values (11, 12, 13); +insert into atacc1 (a) values (10); +insert into atacc1 (a) values (default); +insert into atacc1 (a,b,c,d) values (10,11,12,13); +insert into atacc1 (a,b,c,d) values (default,11,12,13); +insert into atacc1 (b,c,d) values (11,12,13); +insert into atacc1 ("........pg.dropped.1........") values (10); +insert into atacc1 ("........pg.dropped.1........") values (default); +insert into atacc1 ("........pg.dropped.1........",b,c,d) values (10,11,12,13); +insert into atacc1 ("........pg.dropped.1........",b,c,d) values (default,11,12,13); + +-- DELETEs +delete from atacc1 where a = 3; +delete from atacc1 where "........pg.dropped.1........" = 3; +delete from atacc1; + +-- try dropping a non-existent column, should fail +alter table atacc1 drop bar; + +-- try dropping the oid column, should fail +alter table atacc1 drop oid; + +-- try creating a view and altering that, should fail +create view myview as select * from atacc1; +select * from myview; +alter table myview drop d; +drop view myview; + +-- test some commands to make sure they fail on the dropped column +analyze atacc1(a); +analyze atacc1("........pg.dropped.1........"); +vacuum analyze atacc1(a); +vacuum analyze atacc1("........pg.dropped.1........"); +comment on column atacc1.a is 'testing'; +comment on column atacc1."........pg.dropped.1........" is 'testing'; +alter table atacc1 alter a set storage plain; +alter table atacc1 alter "........pg.dropped.1........" set storage plain; +alter table atacc1 alter a set statistics 0; +alter table atacc1 alter "........pg.dropped.1........" set statistics 0; +alter table atacc1 alter a set default 3; +alter table atacc1 alter "........pg.dropped.1........" set default 3; +alter table atacc1 alter a drop default; +alter table atacc1 alter "........pg.dropped.1........" drop default; +alter table atacc1 alter a set not null; +alter table atacc1 alter "........pg.dropped.1........" set not null; +alter table atacc1 alter a drop not null; +alter table atacc1 alter "........pg.dropped.1........" drop not null; +alter table atacc1 rename a to x; +alter table atacc1 rename "........pg.dropped.1........" to x; +alter table atacc1 add primary key(a); +alter table atacc1 add primary key("........pg.dropped.1........"); +alter table atacc1 add unique(a); +alter table atacc1 add unique("........pg.dropped.1........"); +alter table atacc1 add check (a > 3); +alter table atacc1 add check ("........pg.dropped.1........" > 3); +create table atacc2 (id int4 unique); +alter table atacc1 add foreign key (a) references atacc2(id); +alter table atacc1 add foreign key ("........pg.dropped.1........") references atacc2(id); +alter table atacc2 add foreign key (id) references atacc1(a); +alter table atacc2 add foreign key (id) references atacc1("........pg.dropped.1........"); +drop table atacc2; +create index "testing_idx" on atacc1(a); +create index "testing_idx" on atacc1("........pg.dropped.1........"); + +-- test create as and select into +insert into atacc1 values (21, 22, 23); +create table test1 as select * from atacc1; +select * from test1; +drop table test1; +select * into test2 from atacc1; +select * from test2; +drop table test2; + +-- try dropping all columns +alter table atacc1 drop c; +alter table atacc1 drop d; +alter table atacc1 drop b; +select * from atacc1; + +drop table atacc1; + +-- test inheritance +create table parent (a int, b int, c int); +insert into parent values (1, 2, 3); +alter table parent drop a; +create table child (d varchar(255)) inherits (parent); +insert into child values (12, 13, 'testing'); + +select * from parent; +select * from child; +alter table parent drop c; +select * from parent; +select * from child; + +drop table child; +drop table parent; + +-- test copy in/out +create table test (a int4, b int4, c int4); +insert into test values (1,2,3); +alter table test drop a; +copy test to stdout; +copy test(a) to stdout; +copy test("........pg.dropped.1........") to stdout; +copy test from stdin; +10 11 12 +\. +select * from test; +copy test from stdin; +21 22 +\. +select * from test; +copy test(a) from stdin; +copy test("........pg.dropped.1........") from stdin; +copy test(b,c) from stdin; +31 32 +\. +select * from test; +drop table test; + diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql index b0ccfe6716..4f0d50247f 100644 --- a/src/test/regress/sql/copy2.sql +++ b/src/test/regress/sql/copy2.sql @@ -76,6 +76,9 @@ COPY x (b, c, d, e) from stdin with oids delimiter ',' null 'x'; 500000,x,45,80,90 \. +-- check results of copy in +SELECT * FROM x; + -- COPY w/ oids on a table w/o oids should fail CREATE TABLE no_oids ( a int, @@ -89,8 +92,11 @@ INSERT INTO no_oids (a, b) VALUES (20, 30); COPY no_oids FROM stdin WITH OIDS; COPY no_oids TO stdout WITH OIDS; +-- check copy out COPY x TO stdout; COPY x (c, e) TO stdout; +COPY x (b, e) TO stdout WITH NULL 'I''m null'; + DROP TABLE x; DROP FUNCTION fn_x_before(); DROP FUNCTION fn_x_after();