From: Tom Lane Date: Tue, 29 Mar 2005 00:17:27 +0000 (+0000) Subject: Convert oidvector and int2vector into variable-length arrays. This X-Git-Tag: REL8_1_0BETA1~1094 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=70c9763d4815ac847f0f7694f43eb6a59a236868;p=postgresql Convert oidvector and int2vector into variable-length arrays. This change saves a great deal of space in pg_proc and its primary index, and it eliminates the former requirement that INDEX_MAX_KEYS and FUNC_MAX_ARGS have the same value. INDEX_MAX_KEYS is still embedded in the on-disk representation (because it affects index tuple header size), but FUNC_MAX_ARGS is not. I believe it would now be possible to increase FUNC_MAX_ARGS at little cost, but haven't experimented yet. There are still a lot of vestigial references to FUNC_MAX_ARGS, which I will clean up in a separate pass. However, getting rid of it altogether would require changing the FunctionCallInfoData struct, and I'm not sure I want to buy into that. --- diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c index 5de1514459..75ce4c440d 100644 --- a/contrib/dblink/dblink.c +++ b/contrib/dblink/dblink.c @@ -74,13 +74,13 @@ static HTAB *createConnHash(void); static void createNewConnection(const char *name, remoteConn * con); static void deleteConnection(const char *name); static char **get_pkey_attnames(Oid relid, int16 *numatts); -static char *get_sql_insert(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals); -static char *get_sql_delete(Oid relid, int16 *pkattnums, int16 pknumatts, char **tgt_pkattvals); -static char *get_sql_update(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals); +static char *get_sql_insert(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals); +static char *get_sql_delete(Oid relid, int2vector *pkattnums, int16 pknumatts, char **tgt_pkattvals); +static char *get_sql_update(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals); static char *quote_literal_cstr(char *rawstr); static char *quote_ident_cstr(char *rawstr); -static int16 get_attnum_pk_pos(int16 *pkattnums, int16 pknumatts, int16 key); -static HeapTuple get_tuple_of_interest(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattvals); +static int16 get_attnum_pk_pos(int2vector *pkattnums, int16 pknumatts, int16 key); +static HeapTuple get_tuple_of_interest(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals); static Oid get_relid_from_relname(text *relname_text); static char *generate_relation_name(Oid relid); @@ -1094,7 +1094,7 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS) { Oid relid; text *relname_text; - int16 *pkattnums; + int2vector *pkattnums; int pknumatts_tmp; int16 pknumatts = 0; char **src_pkattvals; @@ -1126,7 +1126,7 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS) errmsg("relation \"%s\" does not exist", GET_STR(relname_text)))); - pkattnums = (int16 *) PG_GETARG_POINTER(1); + pkattnums = (int2vector *) PG_GETARG_POINTER(1); pknumatts_tmp = PG_GETARG_INT32(2); if (pknumatts_tmp <= SHRT_MAX) pknumatts = pknumatts_tmp; @@ -1246,7 +1246,7 @@ dblink_build_sql_delete(PG_FUNCTION_ARGS) { Oid relid; text *relname_text; - int16 *pkattnums; + int2vector *pkattnums; int pknumatts_tmp; int16 pknumatts = 0; char **tgt_pkattvals; @@ -1273,7 +1273,7 @@ dblink_build_sql_delete(PG_FUNCTION_ARGS) errmsg("relation \"%s\" does not exist", GET_STR(relname_text)))); - pkattnums = (int16 *) PG_GETARG_POINTER(1); + pkattnums = (int2vector *) PG_GETARG_POINTER(1); pknumatts_tmp = PG_GETARG_INT32(2); if (pknumatts_tmp <= SHRT_MAX) pknumatts = pknumatts_tmp; @@ -1363,7 +1363,7 @@ dblink_build_sql_update(PG_FUNCTION_ARGS) { Oid relid; text *relname_text; - int16 *pkattnums; + int2vector *pkattnums; int pknumatts_tmp; int16 pknumatts = 0; char **src_pkattvals; @@ -1395,7 +1395,7 @@ dblink_build_sql_update(PG_FUNCTION_ARGS) errmsg("relation \"%s\" does not exist", GET_STR(relname_text)))); - pkattnums = (int16 *) PG_GETARG_POINTER(1); + pkattnums = (int2vector *) PG_GETARG_POINTER(1); pknumatts_tmp = PG_GETARG_INT32(2); if (pknumatts_tmp <= SHRT_MAX) pknumatts = pknumatts_tmp; @@ -1552,16 +1552,13 @@ get_pkey_attnames(Oid relid, int16 *numatts) /* we're only interested if it is the primary key */ if (index->indisprimary == TRUE) { - i = 0; - while (index->indkey[i++] != 0) - (*numatts)++; - + *numatts = index->indnatts; if (*numatts > 0) { result = (char **) palloc(*numatts * sizeof(char *)); for (i = 0; i < *numatts; i++) - result[i] = SPI_fname(tupdesc, index->indkey[i]); + result[i] = SPI_fname(tupdesc, index->indkey.values[i]); } break; } @@ -1574,7 +1571,7 @@ get_pkey_attnames(Oid relid, int16 *numatts) } static char * -get_sql_insert(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals) +get_sql_insert(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals) { Relation rel; char *relname; @@ -1664,7 +1661,7 @@ get_sql_insert(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval } static char * -get_sql_delete(Oid relid, int16 *pkattnums, int16 pknumatts, char **tgt_pkattvals) +get_sql_delete(Oid relid, int2vector *pkattnums, int16 pknumatts, char **tgt_pkattvals) { Relation rel; char *relname; @@ -1688,7 +1685,7 @@ get_sql_delete(Oid relid, int16 *pkattnums, int16 pknumatts, char **tgt_pkattval appendStringInfo(str, "DELETE FROM %s WHERE ", relname); for (i = 0; i < pknumatts; i++) { - int16 pkattnum = pkattnums[i]; + int16 pkattnum = pkattnums->values[i]; if (i > 0) appendStringInfo(str, " AND "); @@ -1720,7 +1717,7 @@ get_sql_delete(Oid relid, int16 *pkattnums, int16 pknumatts, char **tgt_pkattval } static char * -get_sql_update(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals) +get_sql_update(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals) { Relation rel; char *relname; @@ -1788,7 +1785,7 @@ get_sql_update(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattval for (i = 0; i < pknumatts; i++) { - int16 pkattnum = pkattnums[i]; + int16 pkattnum = pkattnums->values[i]; if (i > 0) appendStringInfo(str, " AND "); @@ -1855,7 +1852,7 @@ quote_ident_cstr(char *rawstr) } static int16 -get_attnum_pk_pos(int16 *pkattnums, int16 pknumatts, int16 key) +get_attnum_pk_pos(int2vector *pkattnums, int16 pknumatts, int16 key) { int i; @@ -1863,14 +1860,14 @@ get_attnum_pk_pos(int16 *pkattnums, int16 pknumatts, int16 key) * Not likely a long list anyway, so just scan for the value */ for (i = 0; i < pknumatts; i++) - if (key == pkattnums[i]) + if (key == pkattnums->values[i]) return i; return -1; } static HeapTuple -get_tuple_of_interest(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattvals) +get_tuple_of_interest(Oid relid, int2vector *pkattnums, int16 pknumatts, char **src_pkattvals) { Relation rel; char *relname; @@ -1907,7 +1904,7 @@ get_tuple_of_interest(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_p for (i = 0; i < pknumatts; i++) { - int16 pkattnum = pkattnums[i]; + int16 pkattnum = pkattnums->values[i]; if (i > 0) appendStringInfo(str, " AND "); diff --git a/contrib/dbmirror/pending.c b/contrib/dbmirror/pending.c index 48e91acd78..3ed9d2128c 100644 --- a/contrib/dbmirror/pending.c +++ b/contrib/dbmirror/pending.c @@ -1,7 +1,7 @@ /**************************************************************************** * pending.c - * $Id: pending.c,v 1.20 2004/09/10 04:31:06 neilc Exp $ - * $PostgreSQL: pgsql/contrib/dbmirror/pending.c,v 1.20 2004/09/10 04:31:06 neilc Exp $ + * $Id: pending.c,v 1.21 2005/03/29 00:16:48 tgl Exp $ + * $PostgreSQL: pgsql/contrib/dbmirror/pending.c,v 1.21 2005/03/29 00:16:48 tgl Exp $ * * This file contains a trigger for Postgresql-7.x to record changes to tables * to a pending table for mirroring. @@ -349,8 +349,8 @@ getPrimaryKey(Oid tblOid) resDatum = SPI_getbinval(resTuple, SPI_tuptable->tupdesc, 1, &isNull); tpResultKey = (int2vector *) DatumGetPointer(resDatum); - resultKey = SPI_palloc(sizeof(int2vector)); - memcpy(resultKey, tpResultKey, sizeof(int2vector)); + resultKey = SPI_palloc(VARSIZE(tpResultKey)); + memcpy(resultKey, tpResultKey, VARSIZE(tpResultKey)); return resultKey; } @@ -438,11 +438,8 @@ packageData(HeapTuple tTupleData, TupleDesc tTupleDesc, Oid tableOid, } if (tpPKeys != NULL) - { debug_msg("dbmirror:packageData have primary keys"); - } - cpDataBlock = SPI_palloc(BUFFER_SIZE); iDataBlockSize = BUFFER_SIZE; iUsedDataBlock = 0; /* To account for the null */ @@ -462,11 +459,10 @@ packageData(HeapTuple tTupleData, TupleDesc tTupleDesc, Oid tableOid, /* Determine if this is a primary key or not. */ iIsPrimaryKey = 0; for (iPrimaryKeyIndex = 0; - (*tpPKeys)[iPrimaryKeyIndex] != 0; + iPrimaryKeyIndex < tpPKeys->dim1; iPrimaryKeyIndex++) { - if ((*tpPKeys)[iPrimaryKeyIndex] - == iColumnCounter) + if (tpPKeys->values[iPrimaryKeyIndex] == iColumnCounter) { iIsPrimaryKey = 1; break; diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index 2dc8b30095..946dd53b34 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -1,6 +1,6 @@ @@ -2007,32 +2007,6 @@ The OID of the pg_class entry for the table this index is for - - indkey - int2vector - pg_attribute.attnum - - This is an array of indnatts (up to - INDEX_MAX_KEYS) values that indicate which - table columns this index indexes. For example a value of - 1 3 would mean that the first and the third table - columns make up the index key. A zero in this array indicates that the - corresponding index attribute is an expression over the table columns, - rather than a simple column reference. - - - - - indclass - oidvector - pg_opclass.oid - - For each column in the index key this contains the OID of - the operator class to use. See - pg_opclass for details. - - - indnatts int2 @@ -2063,6 +2037,31 @@ If true, the table was last clustered on this index. + + indkey + int2vector + pg_attribute.attnum + + This is an array of indnatts values that + indicate which table columns this index indexes. For example a value + of 1 3 would mean that the first and the third table + columns make up the index key. A zero in this array indicates that the + corresponding index attribute is an expression over the table columns, + rather than a simple column reference. + + + + + indclass + oidvector + pg_opclass.oid + + For each column in the index key this contains the OID of + the operator class to use. See + pg_opclass for details. + + + indexprs text @@ -3637,7 +3636,7 @@ (typlen = -1), but some fixed-length (typlen > 0) types also have nonzero typelem, for example - name and oidvector. + name and point. If a fixed-length type has a typelem then its internal representation must be some number of values of the typelem data type with no other data. diff --git a/doc/src/sgml/trigger.sgml b/doc/src/sgml/trigger.sgml index 5960ff93ad..e6c8271f1d 100644 --- a/doc/src/sgml/trigger.sgml +++ b/doc/src/sgml/trigger.sgml @@ -1,5 +1,5 @@ @@ -453,7 +453,8 @@ typedef struct Trigger bool tgdeferrable; bool tginitdeferred; int16 tgnargs; - int16 tgattr[FUNC_MAX_ARGS]; + int16 tgnattr; + int16 *tgattr; char **tgargs; } Trigger; diff --git a/src/backend/access/hash/hashfunc.c b/src/backend/access/hash/hashfunc.c index 549dc32d50..46033b19e9 100644 --- a/src/backend/access/hash/hashfunc.c +++ b/src/backend/access/hash/hashfunc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.42 2004/12/31 21:59:13 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.43 2005/03/29 00:16:50 tgl Exp $ * * NOTES * These functions are stored in pg_amproc. For each operator class @@ -107,17 +107,17 @@ hashfloat8(PG_FUNCTION_ARGS) Datum hashoidvector(PG_FUNCTION_ARGS) { - Oid *key = (Oid *) PG_GETARG_POINTER(0); + oidvector *key = (oidvector *) PG_GETARG_POINTER(0); - return hash_any((unsigned char *) key, INDEX_MAX_KEYS * sizeof(Oid)); + return hash_any((unsigned char *) key->values, key->dim1 * sizeof(Oid)); } Datum hashint2vector(PG_FUNCTION_ARGS) { - int16 *key = (int16 *) PG_GETARG_POINTER(0); + int2vector *key = (int2vector *) PG_GETARG_POINTER(0); - return hash_any((unsigned char *) key, INDEX_MAX_KEYS * sizeof(int16)); + return hash_any((unsigned char *) key->values, key->dim1 * sizeof(int2)); } Datum diff --git a/src/backend/access/index/genam.c b/src/backend/access/index/genam.c index ceded59a2b..74f5bb7dd6 100644 --- a/src/backend/access/index/genam.c +++ b/src/backend/access/index/genam.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.45 2005/03/27 23:52:59 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.46 2005/03/29 00:16:51 tgl Exp $ * * NOTES * many of the old access method routines have been turned into @@ -219,7 +219,7 @@ systable_beginscan(Relation heapRelation, */ for (i = 0; i < nkeys; i++) { - Assert(key[i].sk_attno == irel->rd_index->indkey[i]); + Assert(key[i].sk_attno == irel->rd_index->indkey.values[i]); key[i].sk_attno = i + 1; } diff --git a/src/backend/access/nbtree/nbtcompare.c b/src/backend/access/nbtree/nbtcompare.c index aa0f75e814..a5c3fb567e 100644 --- a/src/backend/access/nbtree/nbtcompare.c +++ b/src/backend/access/nbtree/nbtcompare.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtcompare.c,v 1.50 2004/12/31 21:59:22 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtcompare.c,v 1.51 2005/03/29 00:16:52 tgl Exp $ * * NOTES * @@ -198,15 +198,19 @@ btoidcmp(PG_FUNCTION_ARGS) Datum btoidvectorcmp(PG_FUNCTION_ARGS) { - Oid *a = (Oid *) PG_GETARG_POINTER(0); - Oid *b = (Oid *) PG_GETARG_POINTER(1); + oidvector *a = (oidvector *) PG_GETARG_POINTER(0); + oidvector *b = (oidvector *) PG_GETARG_POINTER(1); int i; - for (i = 0; i < INDEX_MAX_KEYS; i++) + /* We arbitrarily choose to sort first by vector length */ + if (a->dim1 != b->dim1) + PG_RETURN_INT32(a->dim1 - b->dim1); + + for (i = 0; i < a->dim1; i++) { - if (a[i] != b[i]) + if (a->values[i] != b->values[i]) { - if (a[i] > b[i]) + if (a->values[i] > b->values[i]) PG_RETURN_INT32(1); else PG_RETURN_INT32(-1); diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c index df071343cc..17b3b0dcdd 100644 --- a/src/backend/access/nbtree/nbtsearch.c +++ b/src/backend/access/nbtree/nbtsearch.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.90 2004/12/31 21:59:22 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.91 2005/03/29 00:16:52 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -684,7 +684,7 @@ _bt_first(IndexScanDesc scan, ScanDirection dir) { RegProcedure cmp_proc; - cmp_proc = get_opclass_proc(rel->rd_index->indclass[i], + cmp_proc = get_opclass_proc(rel->rd_indclass->values[i], cur->sk_subtype, BTORDER_PROC); ScanKeyEntryInitialize(scankeys + i, diff --git a/src/backend/access/rtree/rtscan.c b/src/backend/access/rtree/rtscan.c index e608cb431b..f6656a23b9 100644 --- a/src/backend/access/rtree/rtscan.c +++ b/src/backend/access/rtree/rtscan.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/rtree/rtscan.c,v 1.57 2005/01/18 23:25:48 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/access/rtree/rtscan.c,v 1.58 2005/03/29 00:16:53 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -135,7 +135,7 @@ rtrescan(PG_FUNCTION_ARGS) Oid int_oper; RegProcedure int_proc; - opclass = s->indexRelation->rd_index->indclass[attno - 1]; + opclass = s->indexRelation->rd_indclass->values[attno - 1]; int_strategy = RTMapToInternalOperator(s->keyData[i].sk_strategy); int_oper = get_opclass_member(opclass, s->keyData[i].sk_subtype, diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c index 279ceba48e..05d73e2709 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 - * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.199 2005/02/20 02:21:31 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.200 2005/03/29 00:16:54 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -139,9 +139,9 @@ static const struct typinfo TypInfo[] = { F_XIDIN, F_XIDOUT}, {"cid", CIDOID, 0, 4, true, 'i', 'p', F_CIDIN, F_CIDOUT}, - {"int2vector", INT2VECTOROID, INT2OID, INDEX_MAX_KEYS * 2, false, 's', 'p', + {"int2vector", INT2VECTOROID, INT2OID, -1, false, 'i', 'p', F_INT2VECTORIN, F_INT2VECTOROUT}, - {"oidvector", OIDVECTOROID, OIDOID, INDEX_MAX_KEYS * 4, false, 'i', 'p', + {"oidvector", OIDVECTOROID, OIDOID, -1, false, 'i', 'p', F_OIDVECTORIN, F_OIDVECTOROUT}, {"_int4", INT4ARRAYOID, INT4OID, -1, false, 'i', 'x', F_ARRAY_IN, F_ARRAY_OUT}, @@ -667,7 +667,6 @@ closerel(char *name) void DefineAttr(char *name, char *type, int attnum) { - int attlen; Oid typeoid; if (boot_reldesc != NULL) @@ -689,7 +688,7 @@ DefineAttr(char *name, char *type, int attnum) if (Typ != NULL) { attrtypes[attnum]->atttypid = Ap->am_oid; - attlen = attrtypes[attnum]->attlen = Ap->am_typ.typlen; + attrtypes[attnum]->attlen = Ap->am_typ.typlen; attrtypes[attnum]->attbyval = Ap->am_typ.typbyval; attrtypes[attnum]->attstorage = Ap->am_typ.typstorage; attrtypes[attnum]->attalign = Ap->am_typ.typalign; @@ -702,12 +701,13 @@ DefineAttr(char *name, char *type, int attnum) else { attrtypes[attnum]->atttypid = TypInfo[typeoid].oid; - attlen = attrtypes[attnum]->attlen = TypInfo[typeoid].len; + attrtypes[attnum]->attlen = TypInfo[typeoid].len; attrtypes[attnum]->attbyval = TypInfo[typeoid].byval; attrtypes[attnum]->attstorage = TypInfo[typeoid].storage; attrtypes[attnum]->attalign = TypInfo[typeoid].align; /* if an array type, assume 1-dimensional attribute */ - if (TypInfo[typeoid].elem != InvalidOid && attlen < 0) + if (TypInfo[typeoid].elem != InvalidOid && + attrtypes[attnum]->attlen < 0) attrtypes[attnum]->attndims = 1; else attrtypes[attnum]->attndims = 0; @@ -722,14 +722,22 @@ DefineAttr(char *name, char *type, int attnum) * 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. + * + * oidvector and int2vector are also treated as not-nullable, even + * though they are no longer fixed-width. */ - if (attlen > 0) +#define MARKNOTNULL(att) \ + ((att)->attlen > 0 || \ + (att)->atttypid == OIDVECTOROID || \ + (att)->atttypid == INT2VECTOROID) + + if (MARKNOTNULL(attrtypes[attnum])) { int i; for (i = 0; i < attnum; i++) { - if (attrtypes[i]->attlen <= 0) + if (!MARKNOTNULL(attrtypes[i])) break; } if (i == attnum) diff --git a/src/backend/catalog/genbki.sh b/src/backend/catalog/genbki.sh index a961002cb3..fdb4b6b012 100644 --- a/src/backend/catalog/genbki.sh +++ b/src/backend/catalog/genbki.sh @@ -10,7 +10,7 @@ # # # IDENTIFICATION -# $PostgreSQL: pgsql/src/backend/catalog/genbki.sh,v 1.32 2004/01/04 05:57:21 tgl Exp $ +# $PostgreSQL: pgsql/src/backend/catalog/genbki.sh,v 1.33 2005/03/29 00:16:55 tgl Exp $ # # NOTES # non-essential whitespace is removed from the generated file. @@ -113,15 +113,6 @@ for dir in $INCLUDE_DIRS; do fi done -# Get INDEX_MAX_KEYS from pg_config_manual.h -# (who needs consistency?) -for dir in $INCLUDE_DIRS; do - if [ -f "$dir/pg_config_manual.h" ]; then - INDEXMAXKEYS=`grep '^#define[ ]*INDEX_MAX_KEYS' $dir/pg_config_manual.h | $AWK '{ print $3 }'` - break - fi -done - # Get PG_CATALOG_NAMESPACE from catalog/pg_namespace.h for dir in $INCLUDE_DIRS; do if [ -f "$dir/catalog/pg_namespace.h" ]; then @@ -139,14 +130,6 @@ for dir in $INCLUDE_DIRS; do done export BKIOBJECTID -# NOTE: we assume here that FUNC_MAX_ARGS has the same value as -# INDEX_MAX_KEYS, and don't read it separately from -# pg_config_manual.h. This is OK because both of them must be equal -# to the length of oidvector. - -INDEXMAXKEYS2=`expr $INDEXMAXKEYS '*' 2` || exit -INDEXMAXKEYS4=`expr $INDEXMAXKEYS '*' 4` || exit - touch ${OUTPUT_PREFIX}.description.$$ # ---------------- @@ -181,12 +164,6 @@ sed -e "s/;[ ]*$//g" \ -e "s/PGUID/1/g" \ -e "s/NAMEDATALEN/$NAMEDATALEN/g" \ -e "s/PGNSP/$PG_CATALOG_NAMESPACE/g" \ - -e "s/INDEX_MAX_KEYS\*2/$INDEXMAXKEYS2/g" \ - -e "s/INDEX_MAX_KEYS\*4/$INDEXMAXKEYS4/g" \ - -e "s/INDEX_MAX_KEYS/$INDEXMAXKEYS/g" \ - -e "s/FUNC_MAX_ARGS\*2/$INDEXMAXKEYS2/g" \ - -e "s/FUNC_MAX_ARGS\*4/$INDEXMAXKEYS4/g" \ - -e "s/FUNC_MAX_ARGS/$INDEXMAXKEYS/g" \ | $AWK ' # ---------------- # now use awk to process remaining .h file.. diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c index 2f6eb1bac4..ebe303ed22 100644 --- a/src/backend/catalog/index.c +++ b/src/backend/catalog/index.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.249 2005/03/21 01:24:01 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.250 2005/03/29 00:16:55 tgl Exp $ * * * INTERFACE ROUTINES @@ -347,8 +347,8 @@ UpdateIndexRelation(Oid indexoid, Oid *classOids, bool primary) { - int16 indkey[INDEX_MAX_KEYS]; - Oid indclass[INDEX_MAX_KEYS]; + int2vector *indkey; + oidvector *indclass; Datum exprsDatum; Datum predDatum; Datum values[Natts_pg_index]; @@ -358,15 +358,13 @@ UpdateIndexRelation(Oid indexoid, int i; /* - * Copy the index key and opclass info into zero-filled vectors + * Copy the index key and opclass info into arrays (should we make the + * caller pass them like this to start with?) */ - MemSet(indkey, 0, sizeof(indkey)); - MemSet(indclass, 0, sizeof(indclass)); + indkey = buildint2vector(NULL, indexInfo->ii_NumIndexAttrs); + indclass = buildoidvector(classOids, indexInfo->ii_NumIndexAttrs); for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++) - { - indkey[i] = indexInfo->ii_KeyAttrNumbers[i]; - indclass[i] = classOids[i]; - } + indkey->values[i] = indexInfo->ii_KeyAttrNumbers[i]; /* * Convert the index expressions (if any) to a text datum @@ -411,12 +409,12 @@ UpdateIndexRelation(Oid indexoid, values[Anum_pg_index_indexrelid - 1] = ObjectIdGetDatum(indexoid); values[Anum_pg_index_indrelid - 1] = ObjectIdGetDatum(heapoid); - values[Anum_pg_index_indkey - 1] = PointerGetDatum(indkey); - values[Anum_pg_index_indclass - 1] = PointerGetDatum(indclass); values[Anum_pg_index_indnatts - 1] = Int16GetDatum(indexInfo->ii_NumIndexAttrs); values[Anum_pg_index_indisunique - 1] = BoolGetDatum(indexInfo->ii_Unique); values[Anum_pg_index_indisprimary - 1] = BoolGetDatum(primary); values[Anum_pg_index_indisclustered - 1] = BoolGetDatum(false); + values[Anum_pg_index_indkey - 1] = PointerGetDatum(indkey); + values[Anum_pg_index_indclass - 1] = PointerGetDatum(indclass); values[Anum_pg_index_indexprs - 1] = exprsDatum; if (exprsDatum == (Datum) 0) nulls[Anum_pg_index_indexprs - 1] = 'n'; @@ -871,7 +869,7 @@ BuildIndexInfo(Relation index) numKeys, RelationGetRelid(index)); ii->ii_NumIndexAttrs = numKeys; for (i = 0; i < numKeys; i++) - ii->ii_KeyAttrNumbers[i] = indexStruct->indkey[i]; + ii->ii_KeyAttrNumbers[i] = indexStruct->indkey.values[i]; /* fetch any expressions needed for expressional indexes */ ii->ii_Expressions = RelationGetIndexExpressions(index); diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql index d4e8a523f0..c9202b5fc9 100644 --- a/src/backend/catalog/information_schema.sql +++ b/src/backend/catalog/information_schema.sql @@ -4,7 +4,7 @@ * * Copyright (c) 2003-2005, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.26 2005/01/01 20:44:14 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.27 2005/03/29 00:16:56 tgl Exp $ */ /* @@ -30,13 +30,22 @@ SET search_path TO information_schema, public; * A few supporting functions first ... */ -/* This returns the integers from 1 to INDEX_MAX_KEYS/FUNC_MAX_ARGS */ -CREATE FUNCTION _pg_keypositions() RETURNS SETOF integer - LANGUAGE sql - IMMUTABLE - AS 'select g.s - from generate_series(1,current_setting(''max_index_keys'')::int,1) - as g(s)'; +/* Expand an oidvector or smallint[] into a set with integers 1..N */ +CREATE TYPE _pg_expandoidvector_type AS (o oid, n int); + +CREATE FUNCTION _pg_expandoidvector(oidvector) + RETURNS SETOF _pg_expandoidvector_type + LANGUAGE sql STRICT IMMUTABLE + AS 'select $1[s], s+1 + from generate_series(0,array_upper($1,1),1) as g(s)'; + +CREATE TYPE _pg_expandsmallint_type AS (i smallint, n int); + +CREATE FUNCTION _pg_expandsmallint(smallint[]) + RETURNS SETOF _pg_expandsmallint_type + LANGUAGE sql STRICT IMMUTABLE + AS 'select $1[s], s + from generate_series(1,array_upper($1,1),1) as g(s)'; CREATE FUNCTION _pg_keyissubset(smallint[], smallint[]) RETURNS boolean LANGUAGE sql @@ -501,12 +510,12 @@ CREATE VIEW constraint_column_usage AS /* unique/primary key/foreign key constraints */ SELECT nr.nspname, r.relname, r.relowner, a.attname, nc.nspname, c.conname FROM pg_namespace nr, pg_class r, pg_attribute a, pg_namespace nc, - pg_constraint c, _pg_keypositions() AS pos(n) + pg_constraint c WHERE nr.oid = r.relnamespace AND r.oid = a.attrelid AND nc.oid = c.connamespace - AND (CASE WHEN c.contype = 'f' THEN r.oid = c.confrelid AND c.confkey[pos.n] = a.attnum - ELSE r.oid = c.conrelid AND c.conkey[pos.n] = a.attnum END) + AND (CASE WHEN c.contype = 'f' THEN r.oid = c.confrelid AND a.attnum = ANY (c.confkey) + ELSE r.oid = c.conrelid AND a.attnum = ANY (c.conkey) END) AND NOT a.attisdropped AND c.contype IN ('p', 'u', 'f') AND r.relkind = 'r' @@ -707,26 +716,30 @@ GRANT SELECT ON enabled_roles TO PUBLIC; CREATE VIEW key_column_usage AS SELECT CAST(current_database() AS sql_identifier) AS constraint_catalog, - CAST(nc.nspname AS sql_identifier) AS constraint_schema, - CAST(c.conname AS sql_identifier) AS constraint_name, + CAST(nc_nspname AS sql_identifier) AS constraint_schema, + CAST(conname AS sql_identifier) AS constraint_name, CAST(current_database() AS sql_identifier) AS table_catalog, - CAST(nr.nspname AS sql_identifier) AS table_schema, - CAST(r.relname AS sql_identifier) AS table_name, + CAST(nr_nspname AS sql_identifier) AS table_schema, + CAST(relname AS sql_identifier) AS table_name, CAST(a.attname AS sql_identifier) AS column_name, - CAST(pos.n AS cardinal_number) AS ordinal_position - - FROM pg_namespace nr, pg_class r, pg_attribute a, pg_namespace nc, - pg_constraint c, pg_user u, _pg_keypositions() AS pos(n) - WHERE nr.oid = r.relnamespace - AND r.oid = a.attrelid - AND r.oid = c.conrelid - AND nc.oid = c.connamespace - AND c.conkey[pos.n] = a.attnum - AND NOT a.attisdropped - AND c.contype IN ('p', 'u', 'f') - AND r.relkind = 'r' - AND r.relowner = u.usesysid - AND u.usename = current_user; + CAST((ss.x).n AS cardinal_number) AS ordinal_position + + FROM pg_attribute a, + (SELECT r.oid, nc.nspname AS nc_nspname, c.conname, + nr.nspname AS nr_nspname, r.relname, + _pg_expandsmallint(c.conkey) AS x + FROM pg_namespace nr, pg_class r, pg_namespace nc, + pg_constraint c, pg_user u + WHERE nr.oid = r.relnamespace + AND r.oid = c.conrelid + AND nc.oid = c.connamespace + AND c.contype IN ('p', 'u', 'f') + AND r.relkind = 'r' + AND r.relowner = u.usesysid + AND u.usename = current_user) AS ss + WHERE ss.oid = a.attrelid + AND a.attnum = (ss.x).i + AND NOT a.attisdropped; GRANT SELECT ON key_column_usage TO PUBLIC; @@ -738,13 +751,13 @@ GRANT SELECT ON key_column_usage TO PUBLIC; CREATE VIEW parameters AS SELECT CAST(current_database() AS sql_identifier) AS specific_catalog, - CAST(n.nspname AS sql_identifier) AS specific_schema, - CAST(p.proname || '_' || CAST(p.oid AS text) AS sql_identifier) AS specific_name, - CAST(pos.n AS cardinal_number) AS ordinal_position, + CAST(n_nspname AS sql_identifier) AS specific_schema, + CAST(proname || '_' || CAST(p_oid AS text) AS sql_identifier) AS specific_name, + CAST((ss.x).n AS cardinal_number) AS ordinal_position, CAST('IN' AS character_data) AS parameter_mode, CAST('NO' AS character_data) AS is_result, CAST('NO' AS character_data) AS as_locator, - CAST(NULLIF(p.proargnames[pos.n], '') AS sql_identifier) AS parameter_name, + CAST(NULLIF(proargnames[(ss.x).n], '') AS sql_identifier) AS parameter_name, CAST( CASE WHEN t.typelem <> 0 AND t.typlen = -1 THEN 'ARRAY' WHEN nt.nspname = 'pg_catalog' THEN format_type(t.oid, null) @@ -771,15 +784,17 @@ CREATE VIEW parameters AS CAST(null AS sql_identifier) AS scope_schema, CAST(null AS sql_identifier) AS scope_name, CAST(null AS cardinal_number) AS maximum_cardinality, - CAST(pos.n AS sql_identifier) AS dtd_identifier - - FROM pg_namespace n, pg_proc p, pg_type t, pg_namespace nt, pg_user u, - _pg_keypositions() AS pos(n) + CAST((ss.x).n AS sql_identifier) AS dtd_identifier - WHERE n.oid = p.pronamespace AND p.pronargs >= pos.n - AND p.proargtypes[pos.n-1] = t.oid AND t.typnamespace = nt.oid - AND p.proowner = u.usesysid - AND (u.usename = current_user OR has_function_privilege(p.oid, 'EXECUTE')); + FROM pg_type t, pg_namespace nt, + (SELECT n.nspname AS n_nspname, p.proname, p.oid AS p_oid, + p.proargnames, _pg_expandoidvector(p.proargtypes) AS x + FROM pg_namespace n, pg_proc p, pg_user u + WHERE n.oid = p.pronamespace + AND p.proowner = u.usesysid + AND (u.usename = current_user OR + has_function_privilege(p.oid, 'EXECUTE'))) AS ss + WHERE t.oid = (ss.x).o AND t.typnamespace = nt.oid; GRANT SELECT ON parameters TO PUBLIC; @@ -1702,10 +1717,11 @@ CREATE VIEW element_types AS UNION ALL /* parameters */ - SELECT p.pronamespace, CAST(p.proname || '_' || CAST(p.oid AS text) AS sql_identifier), - 'ROUTINE'::text, pos.n, p.proargtypes[pos.n-1] - FROM pg_proc p, _pg_keypositions() AS pos(n) - WHERE p.pronargs >= pos.n + SELECT pronamespace, CAST(proname || '_' || CAST(oid AS text) AS sql_identifier), + 'ROUTINE'::text, (ss.x).n, (ss.x).o + FROM (SELECT p.pronamespace, p.proname, p.oid, + _pg_expandoidvector(p.proargtypes) AS x + FROM pg_proc p) AS ss UNION ALL diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c index e7960b3845..ac47d23bf1 100644 --- a/src/backend/catalog/namespace.c +++ b/src/backend/catalog/namespace.c @@ -13,7 +13,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.73 2004/12/31 21:59:38 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.74 2005/03/29 00:16:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -471,25 +471,22 @@ FuncnameGetCandidates(List *names, int nargs) recomputeNamespacePath(); } - /* Search syscache by name and (optionally) nargs only */ - if (nargs >= 0) - catlist = SearchSysCacheList(PROCNAMENSP, 2, - CStringGetDatum(funcname), - Int16GetDatum(nargs), - 0, 0); - else - catlist = SearchSysCacheList(PROCNAMENSP, 1, - CStringGetDatum(funcname), - 0, 0, 0); + /* Search syscache by name only */ + catlist = SearchSysCacheList(PROCNAMEARGSNSP, 1, + CStringGetDatum(funcname), + 0, 0, 0); for (i = 0; i < catlist->n_members; i++) { HeapTuple proctup = &catlist->members[i]->tuple; Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup); + int pronargs = procform->pronargs; int pathpos = 0; FuncCandidateList newResult; - nargs = procform->pronargs; + /* Ignore if it doesn't match requested argument count */ + if (nargs >= 0 && pronargs != nargs) + continue; if (OidIsValid(namespaceId)) { @@ -529,9 +526,10 @@ FuncnameGetCandidates(List *names, int nargs) if (catlist->ordered) { - if (nargs == resultList->nargs && - memcmp(procform->proargtypes, resultList->args, - nargs * sizeof(Oid)) == 0) + if (pronargs == resultList->nargs && + memcmp(procform->proargtypes.values, + resultList->args, + pronargs * sizeof(Oid)) == 0) prevResult = resultList; else prevResult = NULL; @@ -542,9 +540,10 @@ FuncnameGetCandidates(List *names, int nargs) prevResult; prevResult = prevResult->next) { - if (nargs == prevResult->nargs && - memcmp(procform->proargtypes, prevResult->args, - nargs * sizeof(Oid)) == 0) + if (pronargs == prevResult->nargs && + memcmp(procform->proargtypes.values, + prevResult->args, + pronargs * sizeof(Oid)) == 0) break; } } @@ -567,11 +566,12 @@ FuncnameGetCandidates(List *names, int nargs) */ newResult = (FuncCandidateList) palloc(sizeof(struct _FuncCandidateList) - sizeof(Oid) - + nargs * sizeof(Oid)); + + pronargs * sizeof(Oid)); newResult->pathpos = pathpos; newResult->oid = HeapTupleGetOid(proctup); - newResult->nargs = nargs; - memcpy(newResult->args, procform->proargtypes, nargs * sizeof(Oid)); + newResult->nargs = pronargs; + memcpy(newResult->args, procform->proargtypes.values, + pronargs * sizeof(Oid)); newResult->next = resultList; resultList = newResult; @@ -632,7 +632,7 @@ FunctionIsVisible(Oid funcid) for (; clist; clist = clist->next) { - if (memcmp(clist->args, procform->proargtypes, + if (memcmp(clist->args, procform->proargtypes.values, nargs * sizeof(Oid)) == 0) { /* Found the expected entry; is it the right proc? */ diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 01c67c2bfc..2042d67042 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.123 2005/01/27 23:23:51 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.124 2005/03/29 00:16:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -78,7 +78,7 @@ ProcedureCreate(const char *procedureName, char nulls[Natts_pg_proc]; Datum values[Natts_pg_proc]; char replaces[Natts_pg_proc]; - Oid typev[FUNC_MAX_ARGS]; + oidvector *proargtypes; Datum namesarray; Oid relid; NameData procname; @@ -125,10 +125,9 @@ ProcedureCreate(const char *procedureName, errdetail("A function returning \"anyarray\" or \"anyelement\" must have at least one argument of either type."))); } - /* Make sure we have a zero-padded param type array */ - MemSet(typev, 0, FUNC_MAX_ARGS * sizeof(Oid)); - if (parameterCount > 0) - memcpy(typev, parameterTypes, parameterCount * sizeof(Oid)); + /* Convert param types to oidvector */ + /* (Probably we should make caller pass it this way to start with) */ + proargtypes = buildoidvector(parameterTypes, parameterCount); /* Process param names, if given */ namesarray = create_parameternames_array(parameterCount, parameterNames); @@ -137,13 +136,13 @@ ProcedureCreate(const char *procedureName, * don't allow functions of complex types that have the same name as * existing attributes of the type */ - if (parameterCount == 1 && OidIsValid(typev[0]) && - (relid = typeidTypeRelid(typev[0])) != InvalidOid && + if (parameterCount == 1 && OidIsValid(parameterTypes[0]) && + (relid = typeidTypeRelid(parameterTypes[0])) != InvalidOid && get_attnum(relid, procedureName) != InvalidAttrNumber) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_COLUMN), errmsg("\"%s\" is already an attribute of type %s", - procedureName, format_type_be(typev[0])))); + procedureName, format_type_be(parameterTypes[0])))); /* * All seems OK; prepare the data to be inserted into pg_proc. @@ -162,15 +161,15 @@ ProcedureCreate(const char *procedureName, values[i++] = ObjectIdGetDatum(procNamespace); /* pronamespace */ values[i++] = Int32GetDatum(GetUserId()); /* proowner */ values[i++] = ObjectIdGetDatum(languageObjectId); /* prolang */ - values[i++] = BoolGetDatum(isAgg); /* proisagg */ + values[i++] = BoolGetDatum(isAgg); /* proisagg */ values[i++] = BoolGetDatum(security_definer); /* prosecdef */ values[i++] = BoolGetDatum(isStrict); /* proisstrict */ values[i++] = BoolGetDatum(returnsSet); /* proretset */ values[i++] = CharGetDatum(volatility); /* provolatile */ values[i++] = UInt16GetDatum(parameterCount); /* pronargs */ values[i++] = ObjectIdGetDatum(returnType); /* prorettype */ - values[i++] = PointerGetDatum(typev); /* proargtypes */ - values[i++] = namesarray; /* proargnames */ + values[i++] = PointerGetDatum(proargtypes); /* proargtypes */ + values[i++] = namesarray; /* proargnames */ if (namesarray == PointerGetDatum(NULL)) nulls[Anum_pg_proc_proargnames - 1] = 'n'; values[i++] = DirectFunctionCall1(textin, /* prosrc */ @@ -183,11 +182,11 @@ ProcedureCreate(const char *procedureName, tupDesc = RelationGetDescr(rel); /* Check for pre-existing definition */ - oldtup = SearchSysCache(PROCNAMENSP, + oldtup = SearchSysCache(PROCNAMEARGSNSP, PointerGetDatum(procedureName), - UInt16GetDatum(parameterCount), - PointerGetDatum(typev), - ObjectIdGetDatum(procNamespace)); + PointerGetDatum(proargtypes), + ObjectIdGetDatum(procNamespace), + 0); if (HeapTupleIsValid(oldtup)) { @@ -290,7 +289,7 @@ ProcedureCreate(const char *procedureName, for (i = 0; i < parameterCount; i++) { referenced.classId = RelOid_pg_type; - referenced.objectId = typev[i]; + referenced.objectId = parameterTypes[i]; referenced.objectSubId = 0; recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); } @@ -492,16 +491,16 @@ fmgr_sql_validator(PG_FUNCTION_ARGS) haspolyarg = false; for (i = 0; i < proc->pronargs; i++) { - if (get_typtype(proc->proargtypes[i]) == 'p') + if (get_typtype(proc->proargtypes.values[i]) == 'p') { - if (proc->proargtypes[i] == ANYARRAYOID || - proc->proargtypes[i] == ANYELEMENTOID) + if (proc->proargtypes.values[i] == ANYARRAYOID || + proc->proargtypes.values[i] == ANYELEMENTOID) haspolyarg = true; else ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("SQL functions cannot have arguments of type %s", - format_type_be(proc->proargtypes[i])))); + format_type_be(proc->proargtypes.values[i])))); } } @@ -534,7 +533,7 @@ fmgr_sql_validator(PG_FUNCTION_ARGS) if (!haspolyarg) { querytree_list = pg_parse_and_rewrite(prosrc, - proc->proargtypes, + proc->proargtypes.values, proc->pronargs); (void) check_sql_fn_retval(proc->prorettype, functyptype, querytree_list, NULL); diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c index ea2a36f6a8..7d4cbe3642 100644 --- a/src/backend/commands/aggregatecmds.c +++ b/src/backend/commands/aggregatecmds.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.22 2004/12/31 21:59:41 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.23 2005/03/29 00:16:57 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -246,11 +246,11 @@ RenameAggregate(List *name, TypeName *basetype, const char *newname) namespaceOid = procForm->pronamespace; /* make sure the new name doesn't exist */ - if (SearchSysCacheExists(PROCNAMENSP, + if (SearchSysCacheExists(PROCNAMEARGSNSP, CStringGetDatum(newname), - Int16GetDatum(procForm->pronargs), - PointerGetDatum(procForm->proargtypes), - ObjectIdGetDatum(namespaceOid))) + PointerGetDatum(&procForm->proargtypes), + ObjectIdGetDatum(namespaceOid), + 0)) { if (basetypeOid == ANYOID) ereport(ERROR, @@ -264,7 +264,7 @@ RenameAggregate(List *name, TypeName *basetype, const char *newname) errmsg("function %s already exists in schema \"%s\"", funcname_signature_string(newname, procForm->pronargs, - procForm->proargtypes), + procForm->proargtypes.values), get_namespace_name(namespaceOid)))); } diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index e9f364fa9a..e29750c535 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.133 2005/03/20 22:00:52 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.134 2005/03/29 00:16:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -347,7 +347,7 @@ check_index_is_clusterable(Relation OldHeap, Oid indexOid) * at the first column; multicolumn-capable AMs are *required* to * index nulls in columns after the first. */ - colno = OldIndex->rd_index->indkey[0]; + colno = OldIndex->rd_index->indkey.values[0]; if (colno > 0) { /* ordinary user attribute */ diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index cbe14d130b..069adf46af 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.56 2005/03/14 00:19:36 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.57 2005/03/29 00:16:57 tgl Exp $ * * DESCRIPTION * These routines take the parse tree and pick out the @@ -716,18 +716,18 @@ RenameFunction(List *name, List *argtypes, const char *newname) namespaceOid = procForm->pronamespace; /* make sure the new name doesn't exist */ - if (SearchSysCacheExists(PROCNAMENSP, + if (SearchSysCacheExists(PROCNAMEARGSNSP, CStringGetDatum(newname), - Int16GetDatum(procForm->pronargs), - PointerGetDatum(procForm->proargtypes), - ObjectIdGetDatum(namespaceOid))) + PointerGetDatum(&procForm->proargtypes), + ObjectIdGetDatum(namespaceOid), + 0)) { ereport(ERROR, (errcode(ERRCODE_DUPLICATE_FUNCTION), errmsg("function %s already exists in schema \"%s\"", funcname_signature_string(newname, procForm->pronargs, - procForm->proargtypes), + procForm->proargtypes.values), get_namespace_name(namespaceOid)))); } @@ -962,11 +962,11 @@ SetFunctionArgType(Oid funcOid, int argIndex, Oid newArgType) procForm = (Form_pg_proc) GETSTRUCT(tup); if (argIndex < 0 || argIndex >= procForm->pronargs || - procForm->proargtypes[argIndex] != OPAQUEOID) + procForm->proargtypes.values[argIndex] != OPAQUEOID) elog(ERROR, "function %u doesn't take OPAQUE", funcOid); /* okay to overwrite copied tuple */ - procForm->proargtypes[argIndex] = newArgType; + procForm->proargtypes.values[argIndex] = newArgType; /* update the catalog and its indexes */ simple_heap_update(pg_proc_rel, &tup->t_self, tup); @@ -1064,15 +1064,15 @@ CreateCast(CreateCastStmt *stmt) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("cast function must take one to three arguments"))); - if (procstruct->proargtypes[0] != sourcetypeid) + if (procstruct->proargtypes.values[0] != sourcetypeid) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("argument of cast function must match source data type"))); - if (nargs > 1 && procstruct->proargtypes[1] != INT4OID) + if (nargs > 1 && procstruct->proargtypes.values[1] != INT4OID) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("second argument of cast function must be type integer"))); - if (nargs > 2 && procstruct->proargtypes[2] != BOOLOID) + if (nargs > 2 && procstruct->proargtypes.values[2] != BOOLOID) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("third argument of cast function must be type boolean"))); diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c index 4778b957e4..9af0ae15db 100644 --- a/src/backend/commands/opclasscmds.c +++ b/src/backend/commands/opclasscmds.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.29 2004/12/31 21:59:41 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.30 2005/03/29 00:16:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -486,7 +486,7 @@ assignProcSubtype(Oid amoid, Oid typeoid, Oid procOid) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("btree procedures must return integer"))); - if (procform->proargtypes[0] != typeoid) + if (procform->proargtypes.values[0] != typeoid) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("btree procedures must have index type as first input"))); @@ -495,10 +495,10 @@ assignProcSubtype(Oid amoid, Oid typeoid, Oid procOid) * The subtype is "default" (0) if second input type matches the * operator class, otherwise it is the second input type. */ - if (procform->proargtypes[1] == typeoid) + if (procform->proargtypes.values[1] == typeoid) subtype = InvalidOid; else - subtype = procform->proargtypes[1]; + subtype = procform->proargtypes.values[1]; ReleaseSysCache(proctup); return subtype; } diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index b441b09b0b..21655e7d61 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.151 2005/03/25 18:04:34 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.152 2005/03/29 00:16:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1419,7 +1419,7 @@ renameatt(Oid myrelid, for (i = 0; i < indexform->indnatts; i++) { - if (attnum != indexform->indkey[i]) + if (attnum != indexform->indkey.values[i]) continue; /* @@ -1676,9 +1676,10 @@ update_ri_trigger_args(Oid relid, * line; so does trigger.c ... */ tgnargs = pg_trigger->tgnargs; - val = (bytea *) fastgetattr(tuple, - Anum_pg_trigger_tgargs, - tgrel->rd_att, &isnull); + val = (bytea *) + DatumGetPointer(fastgetattr(tuple, + Anum_pg_trigger_tgargs, + tgrel->rd_att, &isnull)); if (isnull || tgnargs < RI_FIRST_ATTNAME_ARGNO || tgnargs > RI_MAX_ARGUMENTS) { @@ -3202,7 +3203,7 @@ ATExecDropNotNull(Relation rel, const char *colName) */ for (i = 0; i < indexStruct->indnatts; i++) { - if (indexStruct->indkey[i] == attnum) + if (indexStruct->indkey.values[i] == attnum) ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("column \"%s\" is in a primary key", @@ -4096,6 +4097,9 @@ transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, ListCell *indexoidscan; HeapTuple indexTuple = NULL; Form_pg_index indexStruct = NULL; + Datum indclassDatum; + bool isnull; + oidvector *indclass; int i; /* @@ -4135,6 +4139,12 @@ transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, errmsg("there is no primary key for referenced table \"%s\"", RelationGetRelationName(pkrel)))); + /* Must get indclass the hard way */ + indclassDatum = SysCacheGetAttr(INDEXRELID, indexTuple, + Anum_pg_index_indclass, &isnull); + Assert(!isnull); + indclass = (oidvector *) DatumGetPointer(indclassDatum); + /* * Now build the list of PK attributes from the indkey definition (we * assume a primary key cannot have expressional elements) @@ -4142,11 +4152,11 @@ transformFkeyGetPrimaryKey(Relation pkrel, Oid *indexOid, *attnamelist = NIL; for (i = 0; i < indexStruct->indnatts; i++) { - int pkattno = indexStruct->indkey[i]; + int pkattno = indexStruct->indkey.values[i]; attnums[i] = pkattno; atttypids[i] = attnumTypeId(pkrel, pkattno); - opclasses[i] = indexStruct->indclass[i]; + opclasses[i] = indclass->values[i]; *attnamelist = lappend(*attnamelist, makeString(pstrdup(NameStr(*attnumAttName(pkrel, pkattno))))); } @@ -4205,6 +4215,16 @@ transformFkeyCheckAttrs(Relation pkrel, heap_attisnull(indexTuple, Anum_pg_index_indpred) && heap_attisnull(indexTuple, Anum_pg_index_indexprs)) { + /* Must get indclass the hard way */ + Datum indclassDatum; + bool isnull; + oidvector *indclass; + + indclassDatum = SysCacheGetAttr(INDEXRELID, indexTuple, + Anum_pg_index_indclass, &isnull); + Assert(!isnull); + indclass = (oidvector *) DatumGetPointer(indclassDatum); + /* * The given attnum list may match the index columns in any * order. Check that each list is a subset of the other. @@ -4214,7 +4234,7 @@ transformFkeyCheckAttrs(Relation pkrel, found = false; for (j = 0; j < numattrs; j++) { - if (attnums[i] == indexStruct->indkey[j]) + if (attnums[i] == indexStruct->indkey.values[j]) { found = true; break; @@ -4230,9 +4250,9 @@ transformFkeyCheckAttrs(Relation pkrel, found = false; for (j = 0; j < numattrs; j++) { - if (attnums[j] == indexStruct->indkey[i]) + if (attnums[j] == indexStruct->indkey.values[i]) { - opclasses[j] = indexStruct->indclass[i]; + opclasses[j] = indclass->values[i]; found = true; break; } diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index 277d874448..a9e8bc9e7f 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.181 2005/03/25 21:57:58 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/trigger.c,v 1.182 2005/03/29 00:16:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -67,7 +67,7 @@ Oid CreateTrigger(CreateTrigStmt *stmt, bool forConstraint) { int16 tgtype; - int16 tgattr[FUNC_MAX_ARGS]; + int2vector *tgattr; Datum values[Natts_pg_trigger]; char nulls[Natts_pg_trigger]; Relation rel; @@ -77,7 +77,7 @@ CreateTrigger(CreateTrigStmt *stmt, bool forConstraint) ScanKeyData key; Relation pgrel; HeapTuple tuple; - Oid fargtypes[FUNC_MAX_ARGS]; + Oid fargtypes[1]; /* dummy */ Oid funcoid; Oid funcrettype; Oid trigoid; @@ -275,7 +275,6 @@ CreateTrigger(CreateTrigStmt *stmt, bool forConstraint) /* * Find and validate the trigger function. */ - MemSet(fargtypes, 0, FUNC_MAX_ARGS * sizeof(Oid)); funcoid = LookupFuncName(stmt->funcname, 0, fargtypes, false); funcrettype = get_func_rettype(funcoid); if (funcrettype != TRIGGEROID) @@ -359,7 +358,8 @@ CreateTrigger(CreateTrigStmt *stmt, bool forConstraint) values[Anum_pg_trigger_tgargs - 1] = DirectFunctionCall1(byteain, CStringGetDatum("")); } - MemSet(tgattr, 0, FUNC_MAX_ARGS * sizeof(int16)); + /* tgattr is currently always a zero-length array */ + tgattr = buildint2vector(NULL, 0); values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr); tuple = heap_formtuple(tgrel->rd_att, values, nulls); @@ -774,8 +774,16 @@ RelationBuildTriggers(Relation relation) build->tgdeferrable = pg_trigger->tgdeferrable; build->tginitdeferred = pg_trigger->tginitdeferred; build->tgnargs = pg_trigger->tgnargs; - memcpy(build->tgattr, &(pg_trigger->tgattr), - FUNC_MAX_ARGS * sizeof(int16)); + /* tgattr is first var-width field, so OK to access directly */ + build->tgnattr = pg_trigger->tgattr.dim1; + if (build->tgnattr > 0) + { + build->tgattr = (int2 *) palloc(build->tgnattr * sizeof(int2)); + memcpy(build->tgattr, &(pg_trigger->tgattr.values), + build->tgnattr * sizeof(int2)); + } + else + build->tgattr = NULL; if (build->tgnargs > 0) { bytea *val; @@ -783,9 +791,10 @@ RelationBuildTriggers(Relation relation) char *p; int i; - val = (bytea *) fastgetattr(htup, - Anum_pg_trigger_tgargs, - tgrel->rd_att, &isnull); + val = (bytea *) + DatumGetPointer(fastgetattr(htup, + Anum_pg_trigger_tgargs, + tgrel->rd_att, &isnull)); if (isnull) elog(ERROR, "tgargs is null in trigger for relation \"%s\"", RelationGetRelationName(relation)); @@ -928,6 +937,15 @@ CopyTriggerDesc(TriggerDesc *trigdesc) for (i = 0; i < trigdesc->numtriggers; i++) { trigger->tgname = pstrdup(trigger->tgname); + if (trigger->tgnattr > 0) + { + int2 *newattr; + + newattr = (int2 *) palloc(trigger->tgnattr * sizeof(int2)); + memcpy(newattr, trigger->tgattr, + trigger->tgnattr * sizeof(int2)); + trigger->tgattr = newattr; + } if (trigger->tgnargs > 0) { char **newargs; @@ -1031,6 +1049,8 @@ FreeTriggerDesc(TriggerDesc *trigdesc) for (i = 0; i < trigdesc->numtriggers; i++) { pfree(trigger->tgname); + if (trigger->tgnattr > 0) + pfree(trigger->tgattr); if (trigger->tgnargs > 0) { while (--(trigger->tgnargs) >= 0) @@ -1092,8 +1112,11 @@ equalTriggerDescs(TriggerDesc *trigdesc1, TriggerDesc *trigdesc2) return false; if (trig1->tgnargs != trig2->tgnargs) return false; - if (memcmp(trig1->tgattr, trig2->tgattr, - sizeof(trig1->tgattr)) != 0) + if (trig1->tgnattr != trig2->tgnattr) + return false; + if (trig1->tgnattr > 0 && + memcmp(trig1->tgattr, trig2->tgattr, + trig1->tgnattr * sizeof(int2)) != 0) return false; for (j = 0; j < trig1->tgnargs; j++) if (strcmp(trig1->tgargs[j], trig2->tgargs[j]) != 0) diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 63a734ea0f..9d915af91a 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.174 2005/03/22 20:13:06 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.175 2005/03/29 00:16:59 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -724,9 +724,17 @@ init_fcache(Oid foid, FuncExprState *fcache, MemoryContext fcacheCxt) if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_PROC, get_func_name(foid)); - /* Safety check (should never fail, as parser should check sooner) */ + /* + * Safety check on nargs. Under normal circumstances this should never + * fail, as parser should check sooner. But possibly it might fail + * if server has been compiled with FUNC_MAX_ARGS smaller than some + * functions declared in pg_proc? + */ if (list_length(fcache->args) > FUNC_MAX_ARGS) - elog(ERROR, "too many arguments"); + ereport(ERROR, + (errcode(ERRCODE_TOO_MANY_ARGUMENTS), + errmsg("cannot pass more than %d arguments to a function", + FUNC_MAX_ARGS))); /* Set up the primary fmgr lookup information */ fmgr_info_cxt(foid, &(fcache->func), fcacheCxt); diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index fdbd6107a0..2ddc614cf7 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.93 2005/03/25 21:57:58 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.94 2005/03/29 00:16:59 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -228,7 +228,7 @@ init_sql_fcache(FmgrInfo *finfo) argOidVect = (Oid *) palloc(nargs * sizeof(Oid)); memcpy(argOidVect, - procedureStruct->proargtypes, + procedureStruct->proargtypes.values, nargs * sizeof(Oid)); /* Resolve any polymorphic argument types */ for (argnum = 0; argnum < nargs; argnum++) diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 1756f35e7b..c5963a1d12 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -61,7 +61,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.131 2005/03/22 20:13:06 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/nodeAgg.c,v 1.132 2005/03/29 00:16:59 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1300,15 +1300,16 @@ ExecInitAgg(Agg *node, EState *estate) if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID) { /* have to fetch the agg's declared input type... */ - Oid agg_arg_types[FUNC_MAX_ARGS]; + Oid *agg_arg_types; int agg_nargs; (void) get_func_signature(aggref->aggfnoid, - agg_arg_types, &agg_nargs); + &agg_arg_types, &agg_nargs); Assert(agg_nargs == 1); aggtranstype = resolve_generic_type(aggtranstype, inputType, agg_arg_types[0]); + pfree(agg_arg_types); } /* build expression trees using actual argument & result types */ diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 15418d4e95..76255de53d 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.190 2005/03/28 00:58:24 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.191 2005/03/29 00:17:02 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -421,15 +421,16 @@ count_agg_clauses_walker(Node *node, AggClauseCounts *counts) if (aggtranstype == ANYARRAYOID || aggtranstype == ANYELEMENTOID) { /* have to fetch the agg's declared input type... */ - Oid agg_arg_types[FUNC_MAX_ARGS]; + Oid *agg_arg_types; int agg_nargs; (void) get_func_signature(aggref->aggfnoid, - agg_arg_types, &agg_nargs); + &agg_arg_types, &agg_nargs); Assert(agg_nargs == 1); aggtranstype = resolve_generic_type(aggtranstype, inputType, agg_arg_types[0]); + pfree(agg_arg_types); } /* @@ -2187,7 +2188,7 @@ inline_function(Oid funcid, Oid result_type, List *args, { Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple); bool polymorphic = false; - Oid argtypes[FUNC_MAX_ARGS]; + Oid *argtypes; char *src; Datum tmp; bool isNull; @@ -2220,22 +2221,6 @@ inline_function(Oid funcid, Oid result_type, List *args, if (pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE) != ACLCHECK_OK) return NULL; - /* Check for polymorphic arguments, and substitute actual arg types */ - memcpy(argtypes, funcform->proargtypes, FUNC_MAX_ARGS * sizeof(Oid)); - for (i = 0; i < funcform->pronargs; i++) - { - if (argtypes[i] == ANYARRAYOID || - argtypes[i] == ANYELEMENTOID) - { - polymorphic = true; - argtypes[i] = exprType((Node *) list_nth(args, i)); - } - } - - if (funcform->prorettype == ANYARRAYOID || - funcform->prorettype == ANYELEMENTOID) - polymorphic = true; - /* * Setup error traceback support for ereport(). This is so that we * can finger the function that bad information came from. @@ -2256,6 +2241,24 @@ inline_function(Oid funcid, Oid result_type, List *args, ALLOCSET_DEFAULT_MAXSIZE); oldcxt = MemoryContextSwitchTo(mycxt); + /* Check for polymorphic arguments, and substitute actual arg types */ + argtypes = (Oid *) palloc(funcform->pronargs * sizeof(Oid)); + memcpy(argtypes, funcform->proargtypes.values, + funcform->pronargs * sizeof(Oid)); + for (i = 0; i < funcform->pronargs; i++) + { + if (argtypes[i] == ANYARRAYOID || + argtypes[i] == ANYELEMENTOID) + { + polymorphic = true; + argtypes[i] = exprType((Node *) list_nth(args, i)); + } + } + + if (funcform->prorettype == ANYARRAYOID || + funcform->prorettype == ANYELEMENTOID) + polymorphic = true; + /* Fetch and parse the function body */ tmp = SysCacheGetAttr(PROCOID, func_tuple, diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c index 6099211ba4..c64f2aad1f 100644 --- a/src/backend/optimizer/util/plancat.c +++ b/src/backend/optimizer/util/plancat.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.102 2005/03/27 06:29:42 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.103 2005/03/29 00:17:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -137,8 +137,8 @@ get_relation_info(Oid relationObjectId, RelOptInfo *rel) for (i = 0; i < ncolumns; i++) { - info->classlist[i] = index->indclass[i]; - info->indexkeys[i] = index->indkey[i]; + info->classlist[i] = indexRelation->rd_indclass->values[i]; + info->indexkeys[i] = index->indkey.values[i]; } info->relam = indexRelation->rd_rel->relam; diff --git a/src/backend/parser/parse_agg.c b/src/backend/parser/parse_agg.c index 4781a58317..18a42c5742 100644 --- a/src/backend/parser/parse_agg.c +++ b/src/backend/parser/parse_agg.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.67 2005/03/10 23:21:23 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_agg.c,v 1.68 2005/03/29 00:17:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -367,14 +367,13 @@ build_aggregate_fnexprs(Oid agg_input_type, Expr **transfnexpr, Expr **finalfnexpr) { - Oid transfn_arg_types[FUNC_MAX_ARGS]; int transfn_nargs; Param *arg0; Param *arg1; List *args; - /* get the transition function signature (only need nargs) */ - (void) get_func_signature(transfn_oid, transfn_arg_types, &transfn_nargs); + /* get the transition function arg count */ + transfn_nargs = get_func_nargs(transfn_oid); /* * Build arg list to use in the transfn FuncExpr node. We really only diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 22f13fd99b..32455785a4 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.126 2004/12/31 22:00:27 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_coerce.c,v 2.127 2005/03/29 00:17:04 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -615,9 +615,9 @@ build_coercion_expression(Node *node, Oid funcId, Assert(!procstruct->proisagg); nargs = procstruct->pronargs; Assert(nargs >= 1 && nargs <= 3); - /* Assert(procstruct->proargtypes[0] == exprType(node)); */ - Assert(nargs < 2 || procstruct->proargtypes[1] == INT4OID); - Assert(nargs < 3 || procstruct->proargtypes[2] == BOOLOID); + /* Assert(procstruct->proargtypes.values[0] == exprType(node)); */ + Assert(nargs < 2 || procstruct->proargtypes.values[1] == INT4OID); + Assert(nargs < 3 || procstruct->proargtypes.values[2] == BOOLOID); ReleaseSysCache(tp); @@ -1672,11 +1672,21 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, * of array types. If so, and if the element types have a * suitable cast, use array_type_coerce() or * array_type_length_coerce(). + * + * Hack: disallow coercions to oidvector and int2vector, which + * otherwise tend to capture coercions that should go to "real" array + * types. We want those types to be considered "real" arrays for many + * purposes, but not this one. (Also, array_type_coerce isn't + * guaranteed to produce an output that meets the restrictions of + * these datatypes, such as being 1-dimensional.) */ Oid targetElemType; Oid sourceElemType; Oid elemfuncid; + if (targetTypeId == OIDVECTOROID || targetTypeId == INT2VECTOROID) + return false; + if ((targetElemType = get_element_type(targetTypeId)) != InvalidOid && (sourceElemType = get_element_type(sourceTypeId)) != InvalidOid) { @@ -1691,11 +1701,7 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, else { /* does the function take a typmod arg? */ - Oid argtypes[FUNC_MAX_ARGS]; - int nargs; - - (void) get_func_signature(elemfuncid, argtypes, &nargs); - if (nargs > 1) + if (get_func_nargs(elemfuncid) > 1) *funcid = F_ARRAY_TYPE_LENGTH_COERCE; else *funcid = F_ARRAY_TYPE_COERCE; diff --git a/src/backend/tcop/fastpath.c b/src/backend/tcop/fastpath.c index b2c8903353..f123e2f0cb 100644 --- a/src/backend/tcop/fastpath.c +++ b/src/backend/tcop/fastpath.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/fastpath.c,v 1.77 2004/12/31 22:01:16 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/fastpath.c,v 1.78 2005/03/29 00:17:05 tgl Exp $ * * NOTES * This cruft is the server side of PQfn. @@ -230,9 +230,14 @@ fetch_fp_info(Oid func_id, struct fp_info * fip) errmsg("function with OID %u does not exist", func_id))); pp = (Form_pg_proc) GETSTRUCT(func_htp); + /* watch out for catalog entries with more than FUNC_MAX_ARGS args */ + if (pp->pronargs > FUNC_MAX_ARGS) + elog(ERROR, "function %s has more than %d arguments", + NameStr(pp->proname), FUNC_MAX_ARGS); + fip->namespace = pp->pronamespace; fip->rettype = pp->prorettype; - memcpy(fip->argtypes, pp->proargtypes, FUNC_MAX_ARGS * sizeof(Oid)); + memcpy(fip->argtypes, pp->proargtypes.values, pp->pronargs * sizeof(Oid)); ReleaseSysCache(func_htp); diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 3ceac9cf4a..47edcc5a57 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.117 2005/03/24 21:50:37 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.118 2005/03/29 00:17:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -56,7 +56,7 @@ * * * There are also some "fixed-length array" datatypes, such as NAME and - * OIDVECTOR. These are simply a sequence of a fixed number of items each + * POINT. These are simply a sequence of a fixed number of items each * of a fixed-length datatype, with no overhead; the item size must be * a multiple of its alignment requirement, because we do no padding. * We support subscripting on these types, but array_in() and array_out() diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c index 346b6a27f0..0280196af9 100644 --- a/src/backend/utils/adt/format_type.c +++ b/src/backend/utils/adt/format_type.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/format_type.c,v 1.39 2004/12/31 22:01:21 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/format_type.c,v 1.40 2005/03/29 00:17:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -140,12 +140,15 @@ format_type_internal(Oid type_oid, int32 typemod, /* * Check if it's an array (and not a domain --- we don't want to show * the substructure of a domain type). Fixed-length array types such - * as "name" shouldn't get deconstructed either. + * as "name" shouldn't get deconstructed either. As of Postgres 8.1, + * rather than checking typlen we check the toast property, and don't + * deconstruct "plain storage" array types --- this is because we don't + * want to show oidvector as oid[]. */ array_base_type = typeform->typelem; if (array_base_type != InvalidOid && - typeform->typlen == -1 && + typeform->typstorage != 'p' && typeform->typtype != 'd') { /* Switch our attention to the array element type */ @@ -459,29 +462,17 @@ type_maximum_size(Oid type_oid, int32 typemod) /* * oidvectortypes - converts a vector of type OIDs to "typname" list - * - * The interface for this function is wrong: it should be told how many - * OIDs are significant in the input vector, so that trailing InvalidOid - * argument types can be recognized. */ Datum oidvectortypes(PG_FUNCTION_ARGS) { - Oid *oidArray = (Oid *) PG_GETARG_POINTER(0); + oidvector *oidArray = (oidvector *) PG_GETARG_POINTER(0); char *result; - int numargs; + int numargs = oidArray->dim1; int num; size_t total; size_t left; - /* Try to guess how many args there are :-( */ - numargs = 0; - for (num = 0; num < FUNC_MAX_ARGS; num++) - { - if (oidArray[num] != InvalidOid) - numargs = num + 1; - } - total = 20 * numargs + 1; result = palloc(total); result[0] = '\0'; @@ -489,7 +480,7 @@ oidvectortypes(PG_FUNCTION_ARGS) for (num = 0; num < numargs; num++) { - char *typename = format_type_internal(oidArray[num], -1, + char *typename = format_type_internal(oidArray->values[num], -1, false, true); size_t slen = strlen(typename); diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c index db36ac963e..d00a7d166a 100644 --- a/src/backend/utils/adt/int.c +++ b/src/backend/utils/adt/int.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.65 2005/02/27 08:31:30 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.66 2005/03/29 00:17:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -33,8 +33,10 @@ #include #include +#include "catalog/pg_type.h" #include "funcapi.h" #include "libpq/pqformat.h" +#include "utils/array.h" #include "utils/builtins.h" @@ -47,6 +49,8 @@ #define SAMESIGN(a,b) (((a) < 0) == ((b) < 0)) +#define Int2VectorSize(n) (offsetof(int2vector, values) + (n) * sizeof(int2)) + typedef struct { int32 current; @@ -109,20 +113,49 @@ int2send(PG_FUNCTION_ARGS) } /* - * int2vectorin - converts "num num ..." to internal form + * construct int2vector given a raw array of int2s * - * Note: Fills any missing slots with zeroes. + * If int2s is NULL then caller must fill values[] afterward + */ +int2vector * +buildint2vector(const int2 *int2s, int n) +{ + int2vector *result; + + result = (int2vector *) palloc0(Int2VectorSize(n)); + + if (n > 0 && int2s) + memcpy(result->values, int2s, n * sizeof(int2)); + + /* + * Attach standard array header. For historical reasons, we set the + * index lower bound to 0 not 1. + */ + result->size = Int2VectorSize(n); + result->ndim = 1; + result->flags = 0; + result->elemtype = INT2OID; + result->dim1 = n; + result->lbound1 = 0; + + return result; +} + +/* + * int2vectorin - converts "num num ..." to internal form */ Datum int2vectorin(PG_FUNCTION_ARGS) { char *intString = PG_GETARG_CSTRING(0); - int16 *result = (int16 *) palloc(sizeof(int16[INDEX_MAX_KEYS])); - int slot; + int2vector *result; + int n; + + result = (int2vector *) palloc0(Int2VectorSize(FUNC_MAX_ARGS)); - for (slot = 0; *intString && slot < INDEX_MAX_KEYS; slot++) + for (n = 0; *intString && n < FUNC_MAX_ARGS; n++) { - if (sscanf(intString, "%hd", &result[slot]) != 1) + if (sscanf(intString, "%hd", &result->values[n]) != 1) break; while (*intString && isspace((unsigned char) *intString)) intString++; @@ -136,8 +169,12 @@ int2vectorin(PG_FUNCTION_ARGS) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("int2vector has too many elements"))); - while (slot < INDEX_MAX_KEYS) - result[slot++] = 0; + result->size = Int2VectorSize(n); + result->ndim = 1; + result->flags = 0; + result->elemtype = INT2OID; + result->dim1 = n; + result->lbound1 = 0; PG_RETURN_POINTER(result); } @@ -148,24 +185,19 @@ int2vectorin(PG_FUNCTION_ARGS) Datum int2vectorout(PG_FUNCTION_ARGS) { - int16 *int2Array = (int16 *) PG_GETARG_POINTER(0); + int2vector *int2Array = (int2vector *) PG_GETARG_POINTER(0); int num, - maxnum; + nnums = int2Array->dim1; char *rp; char *result; - /* find last non-zero value in vector */ - for (maxnum = INDEX_MAX_KEYS - 1; maxnum >= 0; maxnum--) - if (int2Array[maxnum] != 0) - break; - /* assumes sign, 5 digits, ' ' */ - rp = result = (char *) palloc((maxnum + 1) * 7 + 1); - for (num = 0; num <= maxnum; num++) + rp = result = (char *) palloc(nnums * 7 + 1); + for (num = 0; num < nnums; num++) { if (num != 0) *rp++ = ' '; - pg_itoa(int2Array[num], rp); + pg_itoa(int2Array->values[num], rp); while (*++rp != '\0') ; } @@ -180,11 +212,19 @@ Datum int2vectorrecv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); - int16 *result = (int16 *) palloc(sizeof(int16[INDEX_MAX_KEYS])); - int slot; - - for (slot = 0; slot < INDEX_MAX_KEYS; slot++) - result[slot] = (int16) pq_getmsgint(buf, sizeof(int16)); + int2vector *result; + + result = (int2vector *) + DatumGetPointer(DirectFunctionCall2(array_recv, + PointerGetDatum(buf), + ObjectIdGetDatum(INT2OID))); + /* sanity checks: int2vector must be 1-D, no nulls */ + if (result->ndim != 1 || + result->flags != 0 || + result->elemtype != INT2OID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), + errmsg("invalid int2vector data"))); PG_RETURN_POINTER(result); } @@ -194,14 +234,7 @@ int2vectorrecv(PG_FUNCTION_ARGS) Datum int2vectorsend(PG_FUNCTION_ARGS) { - int16 *int2Array = (int16 *) PG_GETARG_POINTER(0); - StringInfoData buf; - int slot; - - pq_begintypsend(&buf); - for (slot = 0; slot < INDEX_MAX_KEYS; slot++) - pq_sendint(&buf, int2Array[slot], sizeof(int16)); - PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); + return array_send(fcinfo); } /* @@ -211,10 +244,12 @@ int2vectorsend(PG_FUNCTION_ARGS) Datum int2vectoreq(PG_FUNCTION_ARGS) { - int16 *arg1 = (int16 *) PG_GETARG_POINTER(0); - int16 *arg2 = (int16 *) PG_GETARG_POINTER(1); + int2vector *a = (int2vector *) PG_GETARG_POINTER(0); + int2vector *b = (int2vector *) PG_GETARG_POINTER(1); - PG_RETURN_BOOL(memcmp(arg1, arg2, INDEX_MAX_KEYS * sizeof(int16)) == 0); + if (a->dim1 != b->dim1) + PG_RETURN_BOOL(false); + PG_RETURN_BOOL(memcmp(a->values, b->values, a->dim1 * sizeof(int2)) == 0); } diff --git a/src/backend/utils/adt/oid.c b/src/backend/utils/adt/oid.c index ababe641b2..4329f07b83 100644 --- a/src/backend/utils/adt/oid.c +++ b/src/backend/utils/adt/oid.c @@ -8,20 +8,24 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/oid.c,v 1.61 2005/02/11 04:08:58 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/oid.c,v 1.62 2005/03/29 00:17:08 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" #include -#include #include +#include "catalog/pg_type.h" #include "libpq/pqformat.h" +#include "utils/array.h" #include "utils/builtins.h" +#define OidVectorSize(n) (offsetof(oidvector, values) + (n) * sizeof(Oid)) + + /***************************************************************************** * USER I/O ROUTINES * *****************************************************************************/ @@ -151,27 +155,54 @@ oidsend(PG_FUNCTION_ARGS) PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); } +/* + * construct oidvector given a raw array of Oids + * + * If oids is NULL then caller must fill values[] afterward + */ +oidvector * +buildoidvector(const Oid *oids, int n) +{ + oidvector *result; + + result = (oidvector *) palloc0(OidVectorSize(n)); + + if (n > 0 && oids) + memcpy(result->values, oids, n * sizeof(Oid)); + + /* + * Attach standard array header. For historical reasons, we set the + * index lower bound to 0 not 1. + */ + result->size = OidVectorSize(n); + result->ndim = 1; + result->flags = 0; + result->elemtype = OIDOID; + result->dim1 = n; + result->lbound1 = 0; + + return result; +} /* * oidvectorin - converts "num num ..." to internal form - * - * Note: - * Fills any unsupplied positions with InvalidOid. */ Datum oidvectorin(PG_FUNCTION_ARGS) { char *oidString = PG_GETARG_CSTRING(0); - Oid *result = (Oid *) palloc(sizeof(Oid[INDEX_MAX_KEYS])); - int slot; + oidvector *result; + int n; - for (slot = 0; slot < INDEX_MAX_KEYS; slot++) + result = (oidvector *) palloc0(OidVectorSize(FUNC_MAX_ARGS)); + + for (n = 0; n < FUNC_MAX_ARGS; n++) { while (*oidString && isspace((unsigned char) *oidString)) oidString++; if (*oidString == '\0') break; - result[slot] = oidin_subr("oidvectorin", oidString, &oidString); + result->values[n] = oidin_subr("oidvectorin", oidString, &oidString); } while (*oidString && isspace((unsigned char) *oidString)) oidString++; @@ -179,8 +210,13 @@ oidvectorin(PG_FUNCTION_ARGS) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("oidvector has too many elements"))); - while (slot < INDEX_MAX_KEYS) - result[slot++] = InvalidOid; + + result->size = OidVectorSize(n); + result->ndim = 1; + result->flags = 0; + result->elemtype = OIDOID; + result->dim1 = n; + result->lbound1 = 0; PG_RETURN_POINTER(result); } @@ -191,24 +227,19 @@ oidvectorin(PG_FUNCTION_ARGS) Datum oidvectorout(PG_FUNCTION_ARGS) { - Oid *oidArray = (Oid *) PG_GETARG_POINTER(0); + oidvector *oidArray = (oidvector *) PG_GETARG_POINTER(0); int num, - maxnum; + nnums = oidArray->dim1; char *rp; char *result; - /* find last non-zero value in vector */ - for (maxnum = INDEX_MAX_KEYS - 1; maxnum >= 0; maxnum--) - if (oidArray[maxnum] != 0) - break; - /* assumes sign, 10 digits, ' ' */ - rp = result = (char *) palloc((maxnum + 1) * 12 + 1); - for (num = 0; num <= maxnum; num++) + rp = result = (char *) palloc(nnums * 12 + 1); + for (num = 0; num < nnums; num++) { if (num != 0) *rp++ = ' '; - sprintf(rp, "%u", oidArray[num]); + sprintf(rp, "%u", oidArray->values[num]); while (*++rp != '\0') ; } @@ -223,11 +254,19 @@ Datum oidvectorrecv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); - Oid *result = (Oid *) palloc(sizeof(Oid[INDEX_MAX_KEYS])); - int slot; - - for (slot = 0; slot < INDEX_MAX_KEYS; slot++) - result[slot] = (Oid) pq_getmsgint(buf, sizeof(Oid)); + oidvector *result; + + result = (oidvector *) + DatumGetPointer(DirectFunctionCall2(array_recv, + PointerGetDatum(buf), + ObjectIdGetDatum(OIDOID))); + /* sanity checks: oidvector must be 1-D, no nulls */ + if (result->ndim != 1 || + result->flags != 0 || + result->elemtype != OIDOID) + ereport(ERROR, + (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), + errmsg("invalid oidvector data"))); PG_RETURN_POINTER(result); } @@ -237,14 +276,7 @@ oidvectorrecv(PG_FUNCTION_ARGS) Datum oidvectorsend(PG_FUNCTION_ARGS) { - Oid *oidArray = (Oid *) PG_GETARG_POINTER(0); - StringInfoData buf; - int slot; - - pq_begintypsend(&buf); - for (slot = 0; slot < INDEX_MAX_KEYS; slot++) - pq_sendint(&buf, oidArray[slot], sizeof(Oid)); - PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); + return array_send(fcinfo); } @@ -327,71 +359,49 @@ oidsmaller(PG_FUNCTION_ARGS) Datum oidvectoreq(PG_FUNCTION_ARGS) { - Oid *arg1 = (Oid *) PG_GETARG_POINTER(0); - Oid *arg2 = (Oid *) PG_GETARG_POINTER(1); + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); - PG_RETURN_BOOL(memcmp(arg1, arg2, INDEX_MAX_KEYS * sizeof(Oid)) == 0); + PG_RETURN_BOOL(cmp == 0); } Datum oidvectorne(PG_FUNCTION_ARGS) { - Oid *arg1 = (Oid *) PG_GETARG_POINTER(0); - Oid *arg2 = (Oid *) PG_GETARG_POINTER(1); + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); - PG_RETURN_BOOL(memcmp(arg1, arg2, INDEX_MAX_KEYS * sizeof(Oid)) != 0); + PG_RETURN_BOOL(cmp != 0); } Datum oidvectorlt(PG_FUNCTION_ARGS) { - Oid *arg1 = (Oid *) PG_GETARG_POINTER(0); - Oid *arg2 = (Oid *) PG_GETARG_POINTER(1); - int i; - - for (i = 0; i < INDEX_MAX_KEYS; i++) - if (arg1[i] != arg2[i]) - PG_RETURN_BOOL(arg1[i] < arg2[i]); - PG_RETURN_BOOL(false); + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); + + PG_RETURN_BOOL(cmp < 0); } Datum oidvectorle(PG_FUNCTION_ARGS) { - Oid *arg1 = (Oid *) PG_GETARG_POINTER(0); - Oid *arg2 = (Oid *) PG_GETARG_POINTER(1); - int i; - - for (i = 0; i < INDEX_MAX_KEYS; i++) - if (arg1[i] != arg2[i]) - PG_RETURN_BOOL(arg1[i] <= arg2[i]); - PG_RETURN_BOOL(true); + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); + + PG_RETURN_BOOL(cmp <= 0); } Datum oidvectorge(PG_FUNCTION_ARGS) { - Oid *arg1 = (Oid *) PG_GETARG_POINTER(0); - Oid *arg2 = (Oid *) PG_GETARG_POINTER(1); - int i; - - for (i = 0; i < INDEX_MAX_KEYS; i++) - if (arg1[i] != arg2[i]) - PG_RETURN_BOOL(arg1[i] >= arg2[i]); - PG_RETURN_BOOL(true); + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); + + PG_RETURN_BOOL(cmp >= 0); } Datum oidvectorgt(PG_FUNCTION_ARGS) { - Oid *arg1 = (Oid *) PG_GETARG_POINTER(0); - Oid *arg2 = (Oid *) PG_GETARG_POINTER(1); - int i; - - for (i = 0; i < INDEX_MAX_KEYS; i++) - if (arg1[i] != arg2[i]) - PG_RETURN_BOOL(arg1[i] > arg2[i]); - PG_RETURN_BOOL(false); + int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo)); + + PG_RETURN_BOOL(cmp > 0); } Datum diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index a74d1feef4..42fddeb8d2 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -13,7 +13,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/regproc.c,v 1.92 2004/12/31 22:01:22 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/regproc.c,v 1.93 2005/03/29 00:17:08 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -98,7 +98,7 @@ regprocin(PG_FUNCTION_ARGS) CStringGetDatum(pro_name_or_oid)); hdesc = heap_openr(ProcedureRelationName, AccessShareLock); - sysscan = systable_beginscan(hdesc, ProcedureNameNspIndex, true, + sysscan = systable_beginscan(hdesc, ProcedureNameArgsNspIndex, true, SnapshotNow, 1, skey); while (HeapTupleIsValid(tuple = systable_getnext(sysscan))) @@ -336,7 +336,7 @@ format_procedure(Oid procedure_oid) quote_qualified_identifier(nspname, proname)); for (i = 0; i < nargs; i++) { - Oid thisargtype = procform->proargtypes[i]; + Oid thisargtype = procform->proargtypes.values[i]; if (i > 0) appendStringInfoChar(&buf, ','); diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index f3458a5abe..814deff5e3 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -3,7 +3,7 @@ * back to source text * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.188 2005/01/13 17:19:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.189 2005/03/29 00:17:08 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -553,9 +553,10 @@ pg_get_triggerdef(PG_FUNCTION_ARGS) char *p; int i; - val = (bytea *) fastgetattr(ht_trig, - Anum_pg_trigger_tgargs, - tgrel->rd_att, &isnull); + val = (bytea *) + DatumGetPointer(fastgetattr(ht_trig, + Anum_pg_trigger_tgargs, + tgrel->rd_att, &isnull)); if (isnull) elog(ERROR, "tgargs is null for trigger %u", trigid); p = (char *) VARDATA(val); @@ -637,6 +638,9 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags) Oid indrelid; int keyno; Oid keycoltype; + Datum indclassDatum; + bool isnull; + oidvector *indclass; StringInfoData buf; char *str; char *sep; @@ -654,6 +658,12 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags) indrelid = idxrec->indrelid; Assert(indexrelid == idxrec->indexrelid); + /* Must get indclass the hard way */ + indclassDatum = SysCacheGetAttr(INDEXRELID, ht_idx, + Anum_pg_index_indclass, &isnull); + Assert(!isnull); + indclass = (oidvector *) DatumGetPointer(indclassDatum); + /* * Fetch the pg_class tuple of the index relation */ @@ -720,7 +730,7 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags) sep = ""; for (keyno = 0; keyno < idxrec->indnatts; keyno++) { - AttrNumber attnum = idxrec->indkey[keyno]; + AttrNumber attnum = idxrec->indkey.values[keyno]; if (!colno) appendStringInfo(&buf, sep); @@ -764,7 +774,7 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags) * Add the operator class name */ if (!colno) - get_opclass_name(idxrec->indclass[keyno], keycoltype, + get_opclass_name(indclass->values[keyno], keycoltype, &buf); } @@ -3537,7 +3547,10 @@ get_func_expr(FuncExpr *expr, deparse_context *context, nargs = 0; foreach(l, expr->args) { - Assert(nargs < FUNC_MAX_ARGS); + if (nargs >= FUNC_MAX_ARGS) + ereport(ERROR, + (errcode(ERRCODE_TOO_MANY_ARGUMENTS), + errmsg("too many arguments"))); argtypes[nargs] = exprType((Node *) lfirst(l)); nargs++; } diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c index e417fcbec8..0b40a20b25 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 - * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.120 2005/01/27 23:36:12 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.121 2005/03/29 00:17:11 tgl Exp $ * * NOTES * Eventually, the index information should go through here, too. @@ -773,15 +773,36 @@ get_func_rettype(Oid funcid) return result; } +/* + * get_func_nargs + * Given procedure id, return the number of arguments. + */ +int +get_func_nargs(Oid funcid) +{ + HeapTuple tp; + int result; + + tp = SearchSysCache(PROCOID, + ObjectIdGetDatum(funcid), + 0, 0, 0); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for function %u", funcid); + + result = ((Form_pg_proc) GETSTRUCT(tp))->pronargs; + ReleaseSysCache(tp); + return result; +} + /* * get_func_signature * Given procedure id, return the function's argument and result types. * (The return value is the result type.) * - * argtypes must point to a vector of size FUNC_MAX_ARGS. + * The arguments are returned as a palloc'd array. */ Oid -get_func_signature(Oid funcid, Oid *argtypes, int *nargs) +get_func_signature(Oid funcid, Oid **argtypes, int *nargs) { HeapTuple tp; Form_pg_proc procstruct; @@ -796,8 +817,10 @@ get_func_signature(Oid funcid, Oid *argtypes, int *nargs) procstruct = (Form_pg_proc) GETSTRUCT(tp); result = procstruct->prorettype; - memcpy(argtypes, procstruct->proargtypes, FUNC_MAX_ARGS * sizeof(Oid)); *nargs = (int) procstruct->pronargs; + Assert(*nargs == procstruct->proargtypes.dim1); + *argtypes = (Oid *) palloc(*nargs * sizeof(Oid)); + memcpy(*argtypes, procstruct->proargtypes.values, *nargs * sizeof(Oid)); ReleaseSysCache(tp); return result; diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index a6660fc4d3..109a6e811a 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.217 2005/03/28 00:58:26 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.218 2005/03/29 00:17:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -27,7 +27,6 @@ */ #include "postgres.h" -#include #include #include #include @@ -81,6 +80,7 @@ static FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class}; static FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = {Schema_pg_attribute}; static FormData_pg_attribute Desc_pg_proc[Natts_pg_proc] = {Schema_pg_proc}; static FormData_pg_attribute Desc_pg_type[Natts_pg_type] = {Schema_pg_type}; +static FormData_pg_attribute Desc_pg_index[Natts_pg_index] = {Schema_pg_index}; /* * Hash tables that index the relation cache @@ -267,10 +267,11 @@ static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo, static Relation RelationBuildDesc(RelationBuildDescInfo buildinfo, Relation oldrelation); static void RelationInitPhysicalAddr(Relation relation); +static TupleDesc GetPgIndexDescriptor(void); static void AttrDefaultFetch(Relation relation); static void CheckConstraintFetch(Relation relation); static List *insert_ordered_oid(List *list, Oid datum); -static void IndexSupportInitialize(Form_pg_index iform, +static void IndexSupportInitialize(oidvector *indclass, Oid *indexOperator, RegProcedure *indexSupport, StrategyNumber maxStrategyNumber, @@ -918,6 +919,8 @@ RelationInitIndexAccessInfo(Relation relation) { HeapTuple tuple; Form_pg_am aform; + Datum indclassDatum; + bool isnull; MemoryContext indexcxt; MemoryContext oldcontext; Oid *operator; @@ -945,6 +948,18 @@ RelationInitIndexAccessInfo(Relation relation) MemoryContextSwitchTo(oldcontext); ReleaseSysCache(tuple); + /* + * indclass cannot be referenced directly through the C struct, because + * it is after the variable-width indkey field. Therefore we extract + * the datum the hard way and provide a direct link in the relcache. + */ + indclassDatum = fastgetattr(relation->rd_indextuple, + Anum_pg_index_indclass, + GetPgIndexDescriptor(), + &isnull); + Assert(!isnull); + relation->rd_indclass = (oidvector *) DatumGetPointer(indclassDatum); + /* * Make a copy of the pg_am entry for the index's access method */ @@ -1014,7 +1029,7 @@ RelationInitIndexAccessInfo(Relation relation) * Fill the operator and support procedure OID arrays. (supportinfo is * left as zeroes, and is filled on-the-fly when used) */ - IndexSupportInitialize(relation->rd_index, + IndexSupportInitialize(relation->rd_indclass, operator, support, amstrategies, amsupport, natts); @@ -1028,7 +1043,7 @@ RelationInitIndexAccessInfo(Relation relation) /* * IndexSupportInitialize * Initializes an index's cached opclass information, - * given the index's pg_index tuple. + * given the index's pg_index.indclass entry. * * Data is returned into *indexOperator and *indexSupport, which are arrays * allocated by the caller. @@ -1040,7 +1055,7 @@ RelationInitIndexAccessInfo(Relation relation) * access method. */ static void -IndexSupportInitialize(Form_pg_index iform, +IndexSupportInitialize(oidvector *indclass, Oid *indexOperator, RegProcedure *indexSupport, StrategyNumber maxStrategyNumber, @@ -1049,19 +1064,15 @@ IndexSupportInitialize(Form_pg_index iform, { int attIndex; - /* - * XXX note that the following assumes the INDEX tuple is well formed - * and that the *key and *class are 0 terminated. - */ for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++) { OpClassCacheEnt *opcentry; - if (!OidIsValid(iform->indclass[attIndex])) + if (!OidIsValid(indclass->values[attIndex])) elog(ERROR, "bogus pg_index tuple"); /* look up the info for this opclass, using a cache */ - opcentry = LookupOpclassInfo(iform->indclass[attIndex], + opcentry = LookupOpclassInfo(indclass->values[attIndex], maxStrategyNumber, maxSupportNumber); @@ -2479,6 +2490,53 @@ RelationCacheInitializePhase3(void) } } +/* + * GetPgIndexDescriptor -- get a predefined tuple descriptor for pg_index + * + * We need this kluge because we have to be able to access non-fixed-width + * fields of pg_index before we have the standard catalog caches available. + * We use predefined data that's set up in just the same way as the + * bootstrapped reldescs used by formrdesc(). The resulting tupdesc is + * not 100% kosher: it does not have the correct relation OID in attrelid, + * nor does it have a TupleConstr field. But it's good enough for the + * purpose of extracting fields. + */ +static TupleDesc +GetPgIndexDescriptor(void) +{ + static TupleDesc pgindexdesc = NULL; + MemoryContext oldcxt; + int i; + + /* Already done? */ + if (pgindexdesc) + return pgindexdesc; + + oldcxt = MemoryContextSwitchTo(CacheMemoryContext); + + pgindexdesc = CreateTemplateTupleDesc(Natts_pg_index, false); + pgindexdesc->tdtypeid = RECORDOID; /* not right, but we don't care */ + pgindexdesc->tdtypmod = -1; + + for (i = 0; i < Natts_pg_index; i++) + { + memcpy(pgindexdesc->attrs[i], + &Desc_pg_index[i], + ATTRIBUTE_TUPLE_SIZE); + /* make sure attcacheoff is valid */ + pgindexdesc->attrs[i]->attcacheoff = -1; + } + + /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */ + pgindexdesc->attrs[0]->attcacheoff = 0; + + /* Note: we don't bother to set up a TupleConstr entry */ + + MemoryContextSwitchTo(oldcxt); + + return pgindexdesc; +} + static void AttrDefaultFetch(Relation relation) { @@ -2773,15 +2831,11 @@ RelationGetIndexExpressions(Relation relation) * After successfully completing the work, we copy it into the * relcache entry. This avoids problems if we get some sort of error * partway through. - * - * We make use of the syscache's copy of pg_index's tupledesc to access - * the non-fixed fields of the tuple. We assume that the syscache - * will be initialized before any access of a partial index could - * occur. (This would probably fail if we were to allow partial - * indexes on system catalogs.) - */ - exprsDatum = SysCacheGetAttr(INDEXRELID, relation->rd_indextuple, - Anum_pg_index_indexprs, &isnull); + */ + exprsDatum = heap_getattr(relation->rd_indextuple, + Anum_pg_index_indexprs, + GetPgIndexDescriptor(), + &isnull); Assert(!isnull); exprsString = DatumGetCString(DirectFunctionCall1(textout, exprsDatum)); result = (List *) stringToNode(exprsString); @@ -2845,15 +2899,11 @@ RelationGetIndexPredicate(Relation relation) * After successfully completing the work, we copy it into the * relcache entry. This avoids problems if we get some sort of error * partway through. - * - * We make use of the syscache's copy of pg_index's tupledesc to access - * the non-fixed fields of the tuple. We assume that the syscache - * will be initialized before any access of a partial index could - * occur. (This would probably fail if we were to allow partial - * indexes on system catalogs.) - */ - predDatum = SysCacheGetAttr(INDEXRELID, relation->rd_indextuple, - Anum_pg_index_indpred, &isnull); + */ + predDatum = heap_getattr(relation->rd_indextuple, + Anum_pg_index_indpred, + GetPgIndexDescriptor(), + &isnull); Assert(!isnull); predString = DatumGetCString(DirectFunctionCall1(textout, predDatum)); result = (List *) stringToNode(predString); @@ -2990,6 +3040,8 @@ load_relcache_init_file(void) Relation rel; Form_pg_class relform; bool has_not_null; + Datum indclassDatum; + bool isnull; /* first read the relation descriptor length */ if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len)) @@ -3081,6 +3133,14 @@ load_relcache_init_file(void) rel->rd_indextuple->t_data = (HeapTupleHeader) ((char *) rel->rd_indextuple + HEAPTUPLESIZE); rel->rd_index = (Form_pg_index) GETSTRUCT(rel->rd_indextuple); + /* fix up indclass pointer too */ + indclassDatum = fastgetattr(rel->rd_indextuple, + Anum_pg_index_indclass, + GetPgIndexDescriptor(), + &isnull); + Assert(!isnull); + rel->rd_indclass = (oidvector *) DatumGetPointer(indclassDatum); + /* next, read the access method tuple form */ if ((nread = fread(&len, 1, sizeof(len), fp)) != sizeof(len)) goto read_failed; @@ -3133,6 +3193,7 @@ load_relcache_init_file(void) Assert(rel->rd_index == NULL); Assert(rel->rd_indextuple == NULL); + Assert(rel->rd_indclass == NULL); Assert(rel->rd_am == NULL); Assert(rel->rd_indexcxt == NULL); Assert(rel->rd_operator == NULL); diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c index 3435ac8ee0..b7b7ec249d 100644 --- a/src/backend/utils/cache/syscache.c +++ b/src/backend/utils/cache/syscache.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.96 2004/12/31 22:01:25 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.97 2005/03/29 00:17:12 tgl Exp $ * * NOTES * These routines allow the parser/planner/executor to perform @@ -334,15 +334,15 @@ static const struct cachedesc cacheinfo[] = { 0, 0 }}, - {ProcedureRelationName, /* PROCNAMENSP */ - ProcedureNameNspIndex, + {ProcedureRelationName, /* PROCNAMEARGSNSP */ + ProcedureNameArgsNspIndex, 0, - 4, + 3, { Anum_pg_proc_proname, - Anum_pg_proc_pronargs, Anum_pg_proc_proargtypes, - Anum_pg_proc_pronamespace + Anum_pg_proc_pronamespace, + 0 }}, {ProcedureRelationName, /* PROCOID */ ProcedureOidIndex, diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index e34a942aba..430cfeffc7 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.90 2005/03/22 20:13:07 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.91 2005/03/29 00:17:15 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -344,7 +344,7 @@ fmgr_info_C_lang(Oid functionId, FmgrInfo *finfo, HeapTuple procedureTuple) for (i = 0; i < procedureStruct->pronargs; i++) { fnextra->arg_toastable[i] = - TypeIsToastable(procedureStruct->proargtypes[i]); + TypeIsToastable(procedureStruct->proargtypes.values[i]); } break; case 1: diff --git a/src/include/c.h b/src/include/c.h index 58fe0f9f9a..ebed0ab945 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -12,7 +12,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/c.h,v 1.180 2005/02/22 04:41:51 momjian Exp $ + * $PostgreSQL: pgsql/src/include/c.h,v 1.181 2005/03/29 00:17:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -428,11 +428,36 @@ typedef struct varlena BpChar; /* blank-padded char, ie SQL char(n) */ typedef struct varlena VarChar; /* var-length char, ie SQL varchar(n) */ /* - * Fixed-length array types (these are not varlena's!) + * Specialized array types. These are physically laid out just the same + * as regular arrays (so that the regular array subscripting code works + * with them). They exist as distinct types mostly for historical reasons: + * they have nonstandard I/O behavior which we don't want to change for fear + * of breaking applications that look at the system catalogs. There is also + * an implementation issue for oidvector: it's part of the primary key for + * pg_proc, and we can't use the normal btree array support routines for that + * without circularity. */ +typedef struct +{ + int32 size; /* these fields must match ArrayType! */ + int ndim; + int flags; + Oid elemtype; + int dim1; + int lbound1; + int2 values[1]; /* VARIABLE LENGTH ARRAY */ +} int2vector; /* VARIABLE LENGTH STRUCT */ -typedef int2 int2vector[INDEX_MAX_KEYS]; -typedef Oid oidvector[INDEX_MAX_KEYS]; +typedef struct +{ + int32 size; /* these fields must match ArrayType! */ + int ndim; + int flags; + Oid elemtype; + int dim1; + int lbound1; + Oid values[1]; /* VARIABLE LENGTH ARRAY */ +} oidvector; /* VARIABLE LENGTH STRUCT */ /* * We want NameData to have length NAMEDATALEN and int alignment, diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index ba640078f5..24411878ce 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.260 2005/03/27 23:53:05 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.261 2005/03/29 00:17:16 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200503271 +#define CATALOG_VERSION_NO 200503281 #endif diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index 7e80496cf6..5b0a63cd4d 100644 --- a/src/include/catalog/indexing.h +++ b/src/include/catalog/indexing.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.84 2004/12/31 22:03:24 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.85 2005/03/29 00:17:17 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -63,7 +63,7 @@ #define OpclassOidIndex "pg_opclass_oid_index" #define OperatorNameNspIndex "pg_operator_oprname_l_r_n_index" #define OperatorOidIndex "pg_operator_oid_index" -#define ProcedureNameNspIndex "pg_proc_proname_args_nsp_index" +#define ProcedureNameArgsNspIndex "pg_proc_proname_args_nsp_index" #define ProcedureOidIndex "pg_proc_oid_index" #define RewriteOidIndex "pg_rewrite_oid_index" #define RewriteRelRulenameIndex "pg_rewrite_rel_rulename_index" @@ -161,7 +161,7 @@ DECLARE_UNIQUE_INDEX(pg_opclass_oid_index on pg_opclass using btree(oid oid_ops) DECLARE_UNIQUE_INDEX(pg_operator_oid_index on pg_operator using btree(oid oid_ops)); DECLARE_UNIQUE_INDEX(pg_operator_oprname_l_r_n_index on pg_operator using btree(oprname name_ops, oprleft oid_ops, oprright oid_ops, oprnamespace oid_ops)); DECLARE_UNIQUE_INDEX(pg_proc_oid_index on pg_proc using btree(oid oid_ops)); -DECLARE_UNIQUE_INDEX(pg_proc_proname_args_nsp_index on pg_proc using btree(proname name_ops, pronargs int2_ops, proargtypes oidvector_ops, pronamespace oid_ops)); +DECLARE_UNIQUE_INDEX(pg_proc_proname_args_nsp_index on pg_proc using btree(proname name_ops, proargtypes oidvector_ops, pronamespace oid_ops)); /* This following index is not used for a cache and is not unique */ DECLARE_UNIQUE_INDEX(pg_rewrite_oid_index on pg_rewrite using btree(oid oid_ops)); DECLARE_UNIQUE_INDEX(pg_rewrite_rel_rulename_index on pg_rewrite using btree(ev_class oid_ops, rulename name_ops)); diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h index 068f551d5e..2094f75f62 100644 --- a/src/include/catalog/pg_attribute.h +++ b/src/include/catalog/pg_attribute.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.113 2004/12/31 22:03:24 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.114 2005/03/29 00:17:17 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -317,7 +317,7 @@ DATA(insert ( 1262 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); { 1255, {"provolatile"}, 18, -1, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ { 1255, {"pronargs"}, 21, -1, 2, 10, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ { 1255, {"prorettype"}, 26, -1, 4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ -{ 1255, {"proargtypes"}, 30, -1, INDEX_MAX_KEYS*4, 12, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ +{ 1255, {"proargtypes"}, 30, -1, -1, 12, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 1255, {"proargnames"}, 1009, -1, -1, 13, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ { 1255, {"prosrc"}, 25, -1, -1, 14, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ { 1255, {"probin"}, 17, -1, -1, 15, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ @@ -334,7 +334,7 @@ DATA(insert ( 1255 proretset 16 -1 1 8 0 -1 -1 t p c t f f t 0)); DATA(insert ( 1255 provolatile 18 -1 1 9 0 -1 -1 t p c t f f t 0)); DATA(insert ( 1255 pronargs 21 -1 2 10 0 -1 -1 t p s t f f t 0)); DATA(insert ( 1255 prorettype 26 -1 4 11 0 -1 -1 t p i t f f t 0)); -DATA(insert ( 1255 proargtypes 30 -1 INDEX_MAX_KEYS*4 12 0 -1 -1 f p i t f f t 0)); +DATA(insert ( 1255 proargtypes 30 -1 -1 12 1 -1 -1 f p i t f f t 0)); DATA(insert ( 1255 proargnames 1009 -1 -1 13 1 -1 -1 f x i f f f t 0)); DATA(insert ( 1255 prosrc 25 -1 -1 14 0 -1 -1 f x i f f f t 0)); DATA(insert ( 1255 probin 17 -1 -1 15 0 -1 -1 f x i f f f t 0)); @@ -511,6 +511,26 @@ DATA(insert ( 1213 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1213 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1213 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); +/* ---------------- + * pg_index + * + * pg_index is not bootstrapped in the same way as the other relations that + * have hardwired pg_attribute entries in this file. However, we do need + * a "Schema_xxx" macro for it --- see relcache.c. + * ---------------- + */ +#define Schema_pg_index \ +{ 0, {"indexrelid"}, 26, -1, 4, 1, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 0, {"indrelid"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ +{ 0, {"indnatts"}, 21, -1, 2, 3, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ +{ 0, {"indisunique"}, 16, -1, 1, 4, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 0, {"indisprimary"}, 16, -1, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 0, {"indisclustered"}, 16, -1, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ +{ 0, {"indkey"}, 22, -1, -1, 7, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ +{ 0, {"indclass"}, 30, -1, -1, 8, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ +{ 0, {"indexprs"}, 25, -1, -1, 9, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \ +{ 0, {"indpred"}, 25, -1, -1, 10, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 } + /* ---------------- * pg_xactlock - this is not a real relation, but is a placeholder * to allow a relation OID to be used for transaction diff --git a/src/include/catalog/pg_index.h b/src/include/catalog/pg_index.h index 4c27a0170f..8ed1e29c06 100644 --- a/src/include/catalog/pg_index.h +++ b/src/include/catalog/pg_index.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_index.h,v 1.35 2004/12/31 22:03:24 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_index.h,v 1.36 2005/03/29 00:17:17 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -35,14 +35,14 @@ CATALOG(pg_index) BKI_WITHOUT_OIDS { Oid indexrelid; /* OID of the index */ Oid indrelid; /* OID of the relation it indexes */ - int2vector indkey; /* column numbers of indexed cols, or 0 */ - oidvector indclass; /* opclass identifiers */ int2 indnatts; /* number of columns in index */ bool indisunique; /* is this a unique index? */ bool indisprimary; /* is this index for primary key? */ bool indisclustered; /* is this the index last clustered by? */ /* VARIABLE LENGTH FIELDS: */ + int2vector indkey; /* column numbers of indexed cols, or 0 */ + oidvector indclass; /* opclass identifiers */ text indexprs; /* expression trees for index attributes * that are not simple column references; * one for each zero entry in indkey[] */ @@ -64,12 +64,12 @@ typedef FormData_pg_index *Form_pg_index; #define Natts_pg_index 10 #define Anum_pg_index_indexrelid 1 #define Anum_pg_index_indrelid 2 -#define Anum_pg_index_indkey 3 -#define Anum_pg_index_indclass 4 -#define Anum_pg_index_indnatts 5 -#define Anum_pg_index_indisunique 6 -#define Anum_pg_index_indisprimary 7 -#define Anum_pg_index_indisclustered 8 +#define Anum_pg_index_indnatts 3 +#define Anum_pg_index_indisunique 4 +#define Anum_pg_index_indisprimary 5 +#define Anum_pg_index_indisclustered 6 +#define Anum_pg_index_indkey 7 +#define Anum_pg_index_indclass 8 #define Anum_pg_index_indexprs 9 #define Anum_pg_index_indpred 10 diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 63a339e555..7477dca47a 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.354 2005/03/27 23:53:05 tgl Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.355 2005/03/29 00:17:17 tgl Exp $ * * NOTES * The script catalog/genbki.sh reads this file and generates .bki @@ -48,7 +48,7 @@ CATALOG(pg_proc) BOOTSTRAP char provolatile; /* see PROVOLATILE_ categories below */ int2 pronargs; /* number of arguments */ Oid prorettype; /* OID of result type */ - oidvector proargtypes; /* OIDs of argument types */ + oidvector proargtypes; /* VARIABLE LENGTH FIELD */ text proargnames[1]; /* VARIABLE LENGTH FIELD */ text prosrc; /* VARIABLE LENGTH FIELD */ bytea probin; /* VARIABLE LENGTH FIELD */ diff --git a/src/include/catalog/pg_trigger.h b/src/include/catalog/pg_trigger.h index a59ecec1b5..3f1754c994 100644 --- a/src/include/catalog/pg_trigger.h +++ b/src/include/catalog/pg_trigger.h @@ -38,12 +38,12 @@ CATALOG(pg_trigger) bool tgisconstraint; /* trigger is a RI constraint */ NameData tgconstrname; /* RI constraint name */ Oid tgconstrrelid; /* RI table of foreign key definition */ - - /* in the case of ON DELETE or ON UPDATE */ bool tgdeferrable; /* RI trigger is deferrable */ bool tginitdeferred; /* RI trigger is deferred initially */ int2 tgnargs; /* # of extra arguments in tgargs */ - int2vector tgattr; /* UPDATE of attr1, attr2 ... (NI) */ + + /* VARIABLE LENGTH FIELDS: */ + int2vector tgattr; /* reserved for column-specific triggers */ bytea tgargs; /* first\000second\000tgnargs\000 */ } FormData_pg_trigger; diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index db7426ba22..7b6bd6a948 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.158 2004/12/31 22:03:26 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.159 2005/03/29 00:17:17 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -88,7 +88,7 @@ CATALOG(pg_type) BOOTSTRAP * current type can then be subscripted like an array yielding values * of type typelem. A non-zero typelem does not guarantee this type to * be a "real" array type; some ordinary fixed-length types can also - * be subscripted (e.g., oidvector). Variable-length types can *not* + * be subscripted (e.g., name, point). Variable-length types can *not* * be turned into pseudo-arrays like that. Hence, the way to determine * whether a type is a "true" array type is if: * @@ -268,8 +268,8 @@ DATA(insert OID = 21 ( int2 PGNSP PGUID 2 t b t \054 0 0 int2in int2out int2 DESCR("-32 thousand to 32 thousand, 2-byte storage"); #define INT2OID 21 -DATA(insert OID = 22 ( int2vector PGNSP PGUID INDEX_MAX_KEYS*2 f b t \054 0 21 int2vectorin int2vectorout int2vectorrecv int2vectorsend - s p f 0 -1 0 _null_ _null_ )); -DESCR("array of INDEX_MAX_KEYS int2 integers, used in system tables"); +DATA(insert OID = 22 ( int2vector PGNSP PGUID -1 f b t \054 0 21 int2vectorin int2vectorout int2vectorrecv int2vectorsend - i p f 0 -1 0 _null_ _null_ )); +DESCR("array of int2, used in system tables"); #define INT2VECTOROID 22 DATA(insert OID = 23 ( int4 PGNSP PGUID 4 t b t \054 0 0 int4in int4out int4recv int4send - i p f 0 -1 0 _null_ _null_ )); @@ -300,8 +300,8 @@ DATA(insert OID = 29 ( cid PGNSP PGUID 4 t b t \054 0 0 cidin cidout cidrec DESCR("command identifier type, sequence in transaction id"); #define CIDOID 29 -DATA(insert OID = 30 ( oidvector PGNSP PGUID INDEX_MAX_KEYS*4 f b t \054 0 26 oidvectorin oidvectorout oidvectorrecv oidvectorsend - i p f 0 -1 0 _null_ _null_ )); -DESCR("array of INDEX_MAX_KEYS oids, used in system tables"); +DATA(insert OID = 30 ( oidvector PGNSP PGUID -1 f b t \054 0 26 oidvectorin oidvectorout oidvectorrecv oidvectorsend - i p f 0 -1 0 _null_ _null_ )); +DESCR("array of oids, used in system tables"); #define OIDVECTOROID 30 DATA(insert OID = 71 ( pg_type PGNSP PGUID -1 f c t \054 1247 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); diff --git a/src/include/utils/array.h b/src/include/utils/array.h index df5cd28b7d..92ff21bb64 100644 --- a/src/include/utils/array.h +++ b/src/include/utils/array.h @@ -10,7 +10,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/array.h,v 1.53 2005/03/24 21:50:38 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/array.h,v 1.54 2005/03/29 00:17:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -22,6 +22,9 @@ /* * Arrays are varlena objects, so must meet the varlena convention that * the first int32 of the object contains the total object size in bytes. + * + * CAUTION: if you change the header for ordinary arrays you will also + * need to change the headers for oidvector and int2vector! */ typedef struct { diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h index 26edd72c37..4caa5b4cba 100644 --- a/src/include/utils/builtins.h +++ b/src/include/utils/builtins.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.253 2005/02/27 08:31:30 neilc Exp $ + * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.254 2005/03/29 00:17:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -185,6 +185,7 @@ extern Datum int2shl(PG_FUNCTION_ARGS); extern Datum int2shr(PG_FUNCTION_ARGS); extern Datum generate_series_int4(PG_FUNCTION_ARGS); extern Datum generate_series_step_int4(PG_FUNCTION_ARGS); +extern int2vector *buildint2vector(const int2 *int2s, int n); /* name.c */ extern Datum namein(PG_FUNCTION_ARGS); @@ -392,6 +393,7 @@ extern Datum oidvectorlt(PG_FUNCTION_ARGS); extern Datum oidvectorle(PG_FUNCTION_ARGS); extern Datum oidvectorge(PG_FUNCTION_ARGS); extern Datum oidvectorgt(PG_FUNCTION_ARGS); +extern oidvector *buildoidvector(const Oid *oids, int n); /* pseudotypes.c */ extern Datum cstring_in(PG_FUNCTION_ARGS); diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h index 100d6d1277..1c5398a71b 100644 --- a/src/include/utils/lsyscache.h +++ b/src/include/utils/lsyscache.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.94 2005/01/27 23:36:15 neilc Exp $ + * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.95 2005/03/29 00:17:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -64,7 +64,8 @@ extern RegProcedure get_oprrest(Oid opno); extern RegProcedure get_oprjoin(Oid opno); extern char *get_func_name(Oid funcid); extern Oid get_func_rettype(Oid funcid); -extern Oid get_func_signature(Oid funcid, Oid *argtypes, int *nargs); +extern int get_func_nargs(Oid funcid); +extern Oid get_func_signature(Oid funcid, Oid **argtypes, int *nargs); extern bool get_func_retset(Oid funcid); extern bool func_strict(Oid funcid); extern char func_volatile(Oid funcid); diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 536651bf73..b6a1712efa 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.82 2005/01/10 20:02:24 tgl Exp $ + * $PostgreSQL: pgsql/src/include/utils/rel.h,v 1.83 2005/03/29 00:17:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -58,7 +58,8 @@ typedef struct Trigger bool tgdeferrable; bool tginitdeferred; int16 tgnargs; - int16 tgattr[FUNC_MAX_ARGS]; + int16 tgnattr; + int16 *tgattr; char **tgargs; } Trigger; @@ -137,6 +138,7 @@ typedef struct RelationData Form_pg_index rd_index; /* pg_index tuple describing this index */ struct HeapTupleData *rd_indextuple; /* all of pg_index tuple */ /* "struct HeapTupleData *" avoids need to include htup.h here */ + oidvector *rd_indclass; /* extracted pointer to rd_index field */ Form_pg_am rd_am; /* pg_am tuple for index's AM */ /* diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h index efc00c0c45..976788f405 100644 --- a/src/include/utils/syscache.h +++ b/src/include/utils/syscache.h @@ -9,7 +9,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.58 2004/12/31 22:03:46 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.59 2005/03/29 00:17:18 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -52,7 +52,7 @@ #define NAMESPACEOID 21 #define OPERNAMENSP 22 #define OPEROID 23 -#define PROCNAMENSP 24 +#define PROCNAMEARGSNSP 24 #define PROCOID 25 #define RELNAMENSP 26 #define RELOID 27 diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c index 620448b508..f9adb681a6 100644 --- a/src/pl/plperl/plperl.c +++ b/src/pl/plperl/plperl.c @@ -33,7 +33,7 @@ * ENHANCEMENTS, OR MODIFICATIONS. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.69 2005/02/23 04:34:05 momjian Exp $ + * $PostgreSQL: pgsql/src/pl/plperl/plperl.c,v 1.70 2005/03/29 00:17:20 tgl Exp $ * **********************************************************************/ @@ -1300,14 +1300,14 @@ compile_plperl_function(Oid fn_oid, bool is_trigger) for (i = 0; i < prodesc->nargs; i++) { typeTup = SearchSysCache(TYPEOID, - ObjectIdGetDatum(procStruct->proargtypes[i]), + ObjectIdGetDatum(procStruct->proargtypes.values[i]), 0, 0, 0); if (!HeapTupleIsValid(typeTup)) { free(prodesc->proname); free(prodesc); elog(ERROR, "cache lookup failed for type %u", - procStruct->proargtypes[i]); + procStruct->proargtypes.values[i]); } typeStruct = (Form_pg_type) GETSTRUCT(typeTup); @@ -1319,7 +1319,7 @@ compile_plperl_function(Oid fn_oid, bool is_trigger) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("plperl functions cannot take type %s", - format_type_be(procStruct->proargtypes[i])))); + format_type_be(procStruct->proargtypes.values[i])))); } if (typeStruct->typtype == 'c') diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c index 6ae93b7f20..4d23062f6e 100644 --- a/src/pl/plpgsql/src/pl_comp.c +++ b/src/pl/plpgsql/src/pl_comp.c @@ -3,7 +3,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.84 2005/02/22 07:18:24 neilc Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.85 2005/03/29 00:17:23 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -1843,7 +1843,7 @@ compute_function_hashkey(FunctionCallInfo fcinfo, /* get the argument types */ for (i = 0; i < procStruct->pronargs; i++) { - Oid argtypeid = procStruct->proargtypes[i]; + Oid argtypeid = procStruct->proargtypes.values[i]; /* * Check for polymorphic arguments. If found, use the actual diff --git a/src/pl/plpgsql/src/pl_handler.c b/src/pl/plpgsql/src/pl_handler.c index 06e7342916..c20efe7739 100644 --- a/src/pl/plpgsql/src/pl_handler.c +++ b/src/pl/plpgsql/src/pl_handler.c @@ -3,7 +3,7 @@ * procedural language * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.24 2005/02/22 07:18:24 neilc Exp $ + * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.25 2005/03/29 00:17:23 tgl Exp $ * * This software is copyrighted by Jan Wieck - Hamburg. * @@ -189,16 +189,16 @@ plpgsql_validator(PG_FUNCTION_ARGS) haspolyarg = false; for (i = 0; i < proc->pronargs; i++) { - if (get_typtype(proc->proargtypes[i]) == 'p') + if (get_typtype(proc->proargtypes.values[i]) == 'p') { - if (proc->proargtypes[i] == ANYARRAYOID || - proc->proargtypes[i] == ANYELEMENTOID) + if (proc->proargtypes.values[i] == ANYARRAYOID || + proc->proargtypes.values[i] == ANYELEMENTOID) haspolyarg = true; else ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("plpgsql functions cannot take type %s", - format_type_be(proc->proargtypes[i])))); + format_type_be(proc->proargtypes.values[i])))); } } diff --git a/src/pl/plpython/plpython.c b/src/pl/plpython/plpython.c index 431396d20d..9fb4e114de 100644 --- a/src/pl/plpython/plpython.c +++ b/src/pl/plpython/plpython.c @@ -29,7 +29,7 @@ * MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.59 2005/03/24 17:22:34 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/plpython/plpython.c,v 1.60 2005/03/29 00:17:24 tgl Exp $ * ********************************************************************* */ @@ -1082,11 +1082,11 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid, Form_pg_type argTypeStruct; argTypeTup = SearchSysCache(TYPEOID, - ObjectIdGetDatum(procStruct->proargtypes[i]), + ObjectIdGetDatum(procStruct->proargtypes.values[i]), 0, 0, 0); if (!HeapTupleIsValid(argTypeTup)) elog(ERROR, "cache lookup failed for type %u", - procStruct->proargtypes[i]); + procStruct->proargtypes.values[i]); argTypeStruct = (Form_pg_type) GETSTRUCT(argTypeTup); /* Disallow pseudotype argument */ @@ -1094,11 +1094,11 @@ PLy_procedure_create(FunctionCallInfo fcinfo, Oid tgreloid, ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("plpython functions cannot take type %s", - format_type_be(procStruct->proargtypes[i])))); + format_type_be(procStruct->proargtypes.values[i])))); if (argTypeStruct->typtype != 'c') PLy_input_datum_func(&(proc->args[i]), - procStruct->proargtypes[i], + procStruct->proargtypes.values[i], argTypeTup); else proc->args[i].is_rowtype = 2; /* still need to set I/O diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c index a95344759a..0bbd20f4f9 100644 --- a/src/pl/tcl/pltcl.c +++ b/src/pl/tcl/pltcl.c @@ -31,7 +31,7 @@ * ENHANCEMENTS, OR MODIFICATIONS. * * IDENTIFICATION - * $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.94 2004/11/21 21:17:05 tgl Exp $ + * $PostgreSQL: pgsql/src/pl/tcl/pltcl.c,v 1.95 2005/03/29 00:17:25 tgl Exp $ * **********************************************************************/ @@ -1128,14 +1128,14 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid) for (i = 0; i < prodesc->nargs; i++) { typeTup = SearchSysCache(TYPEOID, - ObjectIdGetDatum(procStruct->proargtypes[i]), + ObjectIdGetDatum(procStruct->proargtypes.values[i]), 0, 0, 0); if (!HeapTupleIsValid(typeTup)) { free(prodesc->proname); free(prodesc); elog(ERROR, "cache lookup failed for type %u", - procStruct->proargtypes[i]); + procStruct->proargtypes.values[i]); } typeStruct = (Form_pg_type) GETSTRUCT(typeTup); @@ -1147,7 +1147,7 @@ compile_pltcl_function(Oid fn_oid, Oid tgreloid) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("pltcl functions cannot take type %s", - format_type_be(procStruct->proargtypes[i])))); + format_type_be(procStruct->proargtypes.values[i])))); } if (typeStruct->typtype == 'c') diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out index 937f179439..8740b0e938 100644 --- a/src/test/regress/expected/opr_sanity.out +++ b/src/test/regress/expected/opr_sanity.out @@ -33,23 +33,13 @@ create function physically_coercible(oid, oid) returns bool as language sql; -- **************** pg_proc **************** -- Look for illegal values in pg_proc fields. --- NOTE: in reality pronargs could be more than 10, but I'm too lazy to put --- a larger number of proargtypes check clauses in here. If we ever have --- more-than-10-arg functions in the standard catalogs, extend this query. SELECT p1.oid, p1.proname FROM pg_proc as p1 WHERE p1.prolang = 0 OR p1.prorettype = 0 OR - p1.pronargs < 0 OR p1.pronargs > 10 OR - (p1.proargtypes[0] = 0 AND p1.pronargs > 0) OR - (p1.proargtypes[1] = 0 AND p1.pronargs > 1) OR - (p1.proargtypes[2] = 0 AND p1.pronargs > 2) OR - (p1.proargtypes[3] = 0 AND p1.pronargs > 3) OR - (p1.proargtypes[4] = 0 AND p1.pronargs > 4) OR - (p1.proargtypes[5] = 0 AND p1.pronargs > 5) OR - (p1.proargtypes[6] = 0 AND p1.pronargs > 6) OR - (p1.proargtypes[7] = 0 AND p1.pronargs > 7) OR - (p1.proargtypes[8] = 0 AND p1.pronargs > 8) OR - (p1.proargtypes[9] = 0 AND p1.pronargs > 9); + p1.pronargs < 0 OR + array_lower(p1.proargtypes, 1) != 0 OR + array_upper(p1.proargtypes, 1) != p1.pronargs-1 OR + 0::oid = ANY (p1.proargtypes); oid | proname -----+--------- (0 rows) @@ -218,7 +208,7 @@ WHERE p1.oid != p2.oid AND SELECT p1.oid, p1.proname FROM pg_proc as p1 WHERE p1.prorettype = 'internal'::regtype AND NOT - ('(' || oidvectortypes(p1.proargtypes) || ')') ~ '[^a-z0-9_]internal[^a-z0-9_]'; + 'internal'::regtype = ANY (p1.proargtypes); oid | proname ------+------------- 2304 | internal_in diff --git a/src/test/regress/expected/type_sanity.out b/src/test/regress/expected/type_sanity.out index 58b8dc6dd1..881220bf28 100644 --- a/src/test/regress/expected/type_sanity.out +++ b/src/test/regress/expected/type_sanity.out @@ -106,14 +106,18 @@ ORDER BY 1; (1 row) -- Varlena array types will point to array_in +-- Exception as of 8.1: int2vector and oidvector have their own I/O routines SELECT p1.oid, p1.typname, p2.oid, p2.proname FROM pg_type AS p1, pg_proc AS p2 WHERE p1.typinput = p2.oid AND p1.typtype in ('b', 'p') AND (p1.typelem != 0 AND p1.typlen < 0) AND NOT - (p2.oid = 'array_in'::regproc); - oid | typname | oid | proname ------+---------+-----+--------- -(0 rows) + (p2.oid = 'array_in'::regproc) +ORDER BY 1; + oid | typname | oid | proname +-----+------------+-----+-------------- + 22 | int2vector | 40 | int2vectorin + 30 | oidvector | 54 | oidvectorin +(2 rows) -- Check for bogus typoutput routines -- As of 8.0, this check finds refcursor, which is borrowing @@ -165,14 +169,18 @@ ORDER BY 1; (1 row) -- Varlena array types will point to array_recv +-- Exception as of 8.1: int2vector and oidvector have their own I/O routines SELECT p1.oid, p1.typname, p2.oid, p2.proname FROM pg_type AS p1, pg_proc AS p2 WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND (p1.typelem != 0 AND p1.typlen < 0) AND NOT - (p2.oid = 'array_recv'::regproc); - oid | typname | oid | proname ------+---------+-----+--------- -(0 rows) + (p2.oid = 'array_recv'::regproc) +ORDER BY 1; + oid | typname | oid | proname +-----+------------+------+---------------- + 22 | int2vector | 2410 | int2vectorrecv + 30 | oidvector | 2420 | oidvectorrecv +(2 rows) -- Check for bogus typsend routines -- As of 7.4, this check finds refcursor, which is borrowing @@ -203,7 +211,7 @@ WHERE p1.typsend = p2.oid AND p1.typtype in ('b', 'p') AND NOT -- Look for illegal values in pg_class fields SELECT p1.oid, p1.relname FROM pg_class as p1 -WHERE p1.relkind NOT IN ('r', 'i', 's', 'S', 't', 'v'); +WHERE p1.relkind NOT IN ('r', 'i', 's', 'S', 'c', 't', 'v'); oid | relname -----+--------- (0 rows) diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql index 567eb89e6b..84e9b9f738 100644 --- a/src/test/regress/sql/opr_sanity.sql +++ b/src/test/regress/sql/opr_sanity.sql @@ -39,24 +39,14 @@ language sql; -- **************** pg_proc **************** -- Look for illegal values in pg_proc fields. --- NOTE: in reality pronargs could be more than 10, but I'm too lazy to put --- a larger number of proargtypes check clauses in here. If we ever have --- more-than-10-arg functions in the standard catalogs, extend this query. SELECT p1.oid, p1.proname FROM pg_proc as p1 WHERE p1.prolang = 0 OR p1.prorettype = 0 OR - p1.pronargs < 0 OR p1.pronargs > 10 OR - (p1.proargtypes[0] = 0 AND p1.pronargs > 0) OR - (p1.proargtypes[1] = 0 AND p1.pronargs > 1) OR - (p1.proargtypes[2] = 0 AND p1.pronargs > 2) OR - (p1.proargtypes[3] = 0 AND p1.pronargs > 3) OR - (p1.proargtypes[4] = 0 AND p1.pronargs > 4) OR - (p1.proargtypes[5] = 0 AND p1.pronargs > 5) OR - (p1.proargtypes[6] = 0 AND p1.pronargs > 6) OR - (p1.proargtypes[7] = 0 AND p1.pronargs > 7) OR - (p1.proargtypes[8] = 0 AND p1.pronargs > 8) OR - (p1.proargtypes[9] = 0 AND p1.pronargs > 9); + p1.pronargs < 0 OR + array_lower(p1.proargtypes, 1) != 0 OR + array_upper(p1.proargtypes, 1) != p1.pronargs-1 OR + 0::oid = ANY (p1.proargtypes); -- Look for conflicting proc definitions (same names and input datatypes). -- (This test should be dead code now that we have the unique index @@ -179,7 +169,7 @@ WHERE p1.oid != p2.oid AND SELECT p1.oid, p1.proname FROM pg_proc as p1 WHERE p1.prorettype = 'internal'::regtype AND NOT - ('(' || oidvectortypes(p1.proargtypes) || ')') ~ '[^a-z0-9_]internal[^a-z0-9_]'; + 'internal'::regtype = ANY (p1.proargtypes); -- **************** pg_cast **************** diff --git a/src/test/regress/sql/type_sanity.sql b/src/test/regress/sql/type_sanity.sql index 3e421127d1..81f83525dd 100644 --- a/src/test/regress/sql/type_sanity.sql +++ b/src/test/regress/sql/type_sanity.sql @@ -88,11 +88,13 @@ WHERE p1.typinput = p2.oid AND p1.typtype in ('b', 'p') AND NOT ORDER BY 1; -- Varlena array types will point to array_in +-- Exception as of 8.1: int2vector and oidvector have their own I/O routines SELECT p1.oid, p1.typname, p2.oid, p2.proname FROM pg_type AS p1, pg_proc AS p2 WHERE p1.typinput = p2.oid AND p1.typtype in ('b', 'p') AND (p1.typelem != 0 AND p1.typlen < 0) AND NOT - (p2.oid = 'array_in'::regproc); + (p2.oid = 'array_in'::regproc) +ORDER BY 1; -- Check for bogus typoutput routines @@ -132,11 +134,13 @@ WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND NOT ORDER BY 1; -- Varlena array types will point to array_recv +-- Exception as of 8.1: int2vector and oidvector have their own I/O routines SELECT p1.oid, p1.typname, p2.oid, p2.proname FROM pg_type AS p1, pg_proc AS p2 WHERE p1.typreceive = p2.oid AND p1.typtype in ('b', 'p') AND (p1.typelem != 0 AND p1.typlen < 0) AND NOT - (p2.oid = 'array_recv'::regproc); + (p2.oid = 'array_recv'::regproc) +ORDER BY 1; -- Check for bogus typsend routines @@ -163,7 +167,7 @@ WHERE p1.typsend = p2.oid AND p1.typtype in ('b', 'p') AND NOT SELECT p1.oid, p1.relname FROM pg_class as p1 -WHERE p1.relkind NOT IN ('r', 'i', 's', 'S', 't', 'v'); +WHERE p1.relkind NOT IN ('r', 'i', 's', 'S', 'c', 't', 'v'); -- Indexes should have an access method, others not.