summaryrefslogtreecommitdiff
path: root/src/backend/utils
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2005-03-29 00:17:27 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2005-03-29 00:17:27 +0000
commit70c9763d4815ac847f0f7694f43eb6a59a236868 (patch)
tree7d8aa05f668f1ef7809ff521b6c1e12d31125fd7 /src/backend/utils
parent119191609c507528b20d74c59be69f2129127575 (diff)
downloadpostgresql-70c9763d4815ac847f0f7694f43eb6a59a236868.tar.gz
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.
Diffstat (limited to 'src/backend/utils')
-rw-r--r--src/backend/utils/adt/arrayfuncs.c4
-rw-r--r--src/backend/utils/adt/format_type.c27
-rw-r--r--src/backend/utils/adt/int.c105
-rw-r--r--src/backend/utils/adt/oid.c154
-rw-r--r--src/backend/utils/adt/regproc.c6
-rw-r--r--src/backend/utils/adt/ruleutils.c27
-rw-r--r--src/backend/utils/cache/lsyscache.c31
-rw-r--r--src/backend/utils/cache/relcache.c121
-rw-r--r--src/backend/utils/cache/syscache.c12
-rw-r--r--src/backend/utils/fmgr/fmgr.c4
10 files changed, 312 insertions, 179 deletions
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 <ctype.h>
#include <limits.h>
+#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 <ctype.h>
-#include <errno.h>
#include <limits.h>
+#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.
@@ -774,14 +774,35 @@ get_func_rettype(Oid funcid)
}
/*
+ * 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 <errno.h>
#include <sys/file.h>
#include <fcntl.h>
#include <unistd.h>
@@ -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;
@@ -946,6 +949,18 @@ RelationInitIndexAccessInfo(Relation relation)
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
*/
tuple = SearchSysCache(AMOID,
@@ -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: