1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-10 17:42:29 +03:00

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.
This commit is contained in:
Tom Lane
2005-03-29 00:17:27 +00:00
parent 119191609c
commit 70c9763d48
61 changed files with 819 additions and 581 deletions

View File

@@ -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()

View File

@@ -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);

View File

@@ -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;
for (slot = 0; *intString && slot < INDEX_MAX_KEYS; slot++)
result = (int2vector *) palloc0(Int2VectorSize(FUNC_MAX_ARGS));
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;
int2vector *result;
for (slot = 0; slot < INDEX_MAX_KEYS; slot++)
result[slot] = (int16) pq_getmsgint(buf, sizeof(int16));
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);
}

View File

@@ -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;
oidvector *result;
for (slot = 0; slot < INDEX_MAX_KEYS; slot++)
result[slot] = (Oid) pq_getmsgint(buf, sizeof(Oid));
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;
int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
for (i = 0; i < INDEX_MAX_KEYS; i++)
if (arg1[i] != arg2[i])
PG_RETURN_BOOL(arg1[i] < arg2[i]);
PG_RETURN_BOOL(false);
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;
int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
for (i = 0; i < INDEX_MAX_KEYS; i++)
if (arg1[i] != arg2[i])
PG_RETURN_BOOL(arg1[i] <= arg2[i]);
PG_RETURN_BOOL(true);
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;
int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
for (i = 0; i < INDEX_MAX_KEYS; i++)
if (arg1[i] != arg2[i])
PG_RETURN_BOOL(arg1[i] >= arg2[i]);
PG_RETURN_BOOL(true);
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;
int32 cmp = DatumGetInt32(btoidvectorcmp(fcinfo));
for (i = 0; i < INDEX_MAX_KEYS; i++)
if (arg1[i] != arg2[i])
PG_RETURN_BOOL(arg1[i] > arg2[i]);
PG_RETURN_BOOL(false);
PG_RETURN_BOOL(cmp > 0);
}
Datum

View File

@@ -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, ',');

View File

@@ -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++;
}

View File

@@ -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;

View File

@@ -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;
@@ -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);

View File

@@ -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,

View File

@@ -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: