mirror of
https://github.com/postgres/postgres.git
synced 2025-11-13 16:22:44 +03:00
Massive commit to run PGINDENT on all *.c and *.h files.
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* catalog.c--
|
||||
*
|
||||
*
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/catalog.c,v 1.7 1997/08/18 20:51:59 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/catalog.c,v 1.8 1997/09/07 04:40:00 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
#include <postgres.h>
|
||||
|
||||
#include <miscadmin.h> /* for DataDir */
|
||||
#include <miscadmin.h> /* for DataDir */
|
||||
#include <utils/syscache.h>
|
||||
#include <catalog/catname.h> /* NameIs{,Shared}SystemRelationName */
|
||||
#include <catalog/pg_type.h>
|
||||
@@ -23,175 +23,188 @@
|
||||
#include <access/transam.h>
|
||||
|
||||
/*
|
||||
* relpath - path to the relation
|
||||
* Perhaps this should be in-line code in relopen().
|
||||
* relpath - path to the relation
|
||||
* Perhaps this should be in-line code in relopen().
|
||||
*/
|
||||
char *
|
||||
char *
|
||||
relpath(char relname[])
|
||||
{
|
||||
char *path;
|
||||
|
||||
if (IsSharedSystemRelationName(relname)) {
|
||||
path = (char *) palloc(strlen(DataDir) + sizeof(NameData) + 2);
|
||||
sprintf(path, "%s/%s", DataDir, relname);
|
||||
return (path);
|
||||
}
|
||||
return(relname);
|
||||
char *path;
|
||||
|
||||
if (IsSharedSystemRelationName(relname))
|
||||
{
|
||||
path = (char *) palloc(strlen(DataDir) + sizeof(NameData) + 2);
|
||||
sprintf(path, "%s/%s", DataDir, relname);
|
||||
return (path);
|
||||
}
|
||||
return (relname);
|
||||
}
|
||||
|
||||
#ifdef NOT_USED
|
||||
/*
|
||||
* issystem - returns non-zero iff relname is a system catalog
|
||||
* issystem - returns non-zero iff relname is a system catalog
|
||||
*
|
||||
* We now make a new requirement where system catalog relns must begin
|
||||
* with pg_ while user relns are forbidden to do so. Make the test
|
||||
* trivial and instantaneous.
|
||||
* We now make a new requirement where system catalog relns must begin
|
||||
* with pg_ while user relns are forbidden to do so. Make the test
|
||||
* trivial and instantaneous.
|
||||
*
|
||||
* XXX this is way bogus. -- pma
|
||||
* XXX this is way bogus. -- pma
|
||||
*/
|
||||
bool
|
||||
issystem(char relname[])
|
||||
{
|
||||
if (relname[0] && relname[1] && relname[2])
|
||||
return (relname[0] == 'p' &&
|
||||
relname[1] == 'g' &&
|
||||
relname[2] == '_');
|
||||
else
|
||||
return FALSE;
|
||||
if (relname[0] && relname[1] && relname[2])
|
||||
return (relname[0] == 'p' &&
|
||||
relname[1] == 'g' &&
|
||||
relname[2] == '_');
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* IsSystemRelationName --
|
||||
* True iff name is the name of a system catalog relation.
|
||||
* True iff name is the name of a system catalog relation.
|
||||
*
|
||||
* We now make a new requirement where system catalog relns must begin
|
||||
* with pg_ while user relns are forbidden to do so. Make the test
|
||||
* trivial and instantaneous.
|
||||
* We now make a new requirement where system catalog relns must begin
|
||||
* with pg_ while user relns are forbidden to do so. Make the test
|
||||
* trivial and instantaneous.
|
||||
*
|
||||
* XXX this is way bogus. -- pma
|
||||
* XXX this is way bogus. -- pma
|
||||
*/
|
||||
bool
|
||||
IsSystemRelationName(char *relname)
|
||||
{
|
||||
if (relname[0] && relname[1] && relname[2])
|
||||
return (relname[0] == 'p' &&
|
||||
relname[1] == 'g' &&
|
||||
relname[2] == '_');
|
||||
else
|
||||
return FALSE;
|
||||
if (relname[0] && relname[1] && relname[2])
|
||||
return (relname[0] == 'p' &&
|
||||
relname[1] == 'g' &&
|
||||
relname[2] == '_');
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* IsSharedSystemRelationName --
|
||||
* True iff name is the name of a shared system catalog relation.
|
||||
* True iff name is the name of a shared system catalog relation.
|
||||
*/
|
||||
bool
|
||||
IsSharedSystemRelationName(char *relname)
|
||||
{
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Quick out: if it's not a system relation, it can't be a shared
|
||||
* system relation.
|
||||
*/
|
||||
if (!IsSystemRelationName(relname))
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Quick out: if it's not a system relation, it can't be a shared
|
||||
* system relation.
|
||||
*/
|
||||
if (!IsSystemRelationName(relname))
|
||||
return FALSE;
|
||||
|
||||
i = 0;
|
||||
while (SharedSystemRelationNames[i] != NULL)
|
||||
{
|
||||
if (strcmp(SharedSystemRelationNames[i], relname) == 0)
|
||||
return TRUE;
|
||||
i++;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
i = 0;
|
||||
while ( SharedSystemRelationNames[i] != NULL) {
|
||||
if (strcmp(SharedSystemRelationNames[i],relname) == 0)
|
||||
return TRUE;
|
||||
i++;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* newoid - returns a unique identifier across all catalogs.
|
||||
* newoid - returns a unique identifier across all catalogs.
|
||||
*
|
||||
* Object Id allocation is now done by GetNewObjectID in
|
||||
* access/transam/varsup.c. oids are now allocated correctly.
|
||||
* Object Id allocation is now done by GetNewObjectID in
|
||||
* access/transam/varsup.c. oids are now allocated correctly.
|
||||
*
|
||||
* old comments:
|
||||
* This needs to change soon, it fails if there are too many more
|
||||
* than one call per second when postgres restarts after it dies.
|
||||
* This needs to change soon, it fails if there are too many more
|
||||
* than one call per second when postgres restarts after it dies.
|
||||
*
|
||||
* The distribution of OID's should be done by the POSTMASTER.
|
||||
* Also there needs to be a facility to preallocate OID's. Ie.,
|
||||
* for a block of OID's to be declared as invalid ones to allow
|
||||
* user programs to use them for temporary object identifiers.
|
||||
* The distribution of OID's should be done by the POSTMASTER.
|
||||
* Also there needs to be a facility to preallocate OID's. Ie.,
|
||||
* for a block of OID's to be declared as invalid ones to allow
|
||||
* user programs to use them for temporary object identifiers.
|
||||
*/
|
||||
Oid newoid()
|
||||
Oid
|
||||
newoid()
|
||||
{
|
||||
Oid lastoid;
|
||||
|
||||
GetNewObjectId(&lastoid);
|
||||
if (! OidIsValid(lastoid))
|
||||
elog(WARN, "newoid: GetNewObjectId returns invalid oid");
|
||||
return lastoid;
|
||||
Oid lastoid;
|
||||
|
||||
GetNewObjectId(&lastoid);
|
||||
if (!OidIsValid(lastoid))
|
||||
elog(WARN, "newoid: GetNewObjectId returns invalid oid");
|
||||
return lastoid;
|
||||
}
|
||||
|
||||
/*
|
||||
* fillatt - fills the ATTRIBUTE relation fields from the TYP
|
||||
* fillatt - fills the ATTRIBUTE relation fields from the TYP
|
||||
*
|
||||
* Expects that the atttypid domain is set for each att[].
|
||||
* Returns with the attnum, and attlen domains set.
|
||||
* attnum, attproc, atttyparg, ... should be set by the user.
|
||||
* Expects that the atttypid domain is set for each att[].
|
||||
* Returns with the attnum, and attlen domains set.
|
||||
* attnum, attproc, atttyparg, ... should be set by the user.
|
||||
*
|
||||
* In the future, attnum may not be set?!? or may be passed as an arg?!?
|
||||
* In the future, attnum may not be set?!? or may be passed as an arg?!?
|
||||
*
|
||||
* Current implementation is very inefficient--should cashe the
|
||||
* information if this is at all possible.
|
||||
* Current implementation is very inefficient--should cashe the
|
||||
* information if this is at all possible.
|
||||
*
|
||||
* Check to see if this is really needed, and especially in the case
|
||||
* of index tuples.
|
||||
* Check to see if this is really needed, and especially in the case
|
||||
* of index tuples.
|
||||
*/
|
||||
void
|
||||
fillatt(TupleDesc tupleDesc)
|
||||
{
|
||||
AttributeTupleForm *attributeP;
|
||||
register TypeTupleForm typp;
|
||||
HeapTuple tuple;
|
||||
int i;
|
||||
int natts = tupleDesc->natts;
|
||||
AttributeTupleForm *att = tupleDesc->attrs;
|
||||
AttributeTupleForm *attributeP;
|
||||
register TypeTupleForm typp;
|
||||
HeapTuple tuple;
|
||||
int i;
|
||||
int natts = tupleDesc->natts;
|
||||
AttributeTupleForm *att = tupleDesc->attrs;
|
||||
|
||||
if (natts < 0 || natts > MaxHeapAttributeNumber)
|
||||
elog(WARN, "fillatt: %d attributes is too large", natts);
|
||||
if (natts == 0) {
|
||||
elog(DEBUG, "fillatt: called with natts == 0");
|
||||
return;
|
||||
}
|
||||
|
||||
attributeP = &att[0];
|
||||
|
||||
for (i = 0; i < natts;) {
|
||||
tuple = SearchSysCacheTuple(TYPOID,
|
||||
Int32GetDatum((*attributeP)->atttypid),
|
||||
0,0,0);
|
||||
if (!HeapTupleIsValid(tuple)) {
|
||||
elog(WARN, "fillatt: unknown atttypid %ld",
|
||||
(*attributeP)->atttypid);
|
||||
} else {
|
||||
(*attributeP)->attnum = (int16) ++i;
|
||||
/* Check if the attr is a set before messing with the length
|
||||
and byval, since those were already set in
|
||||
TupleDescInitEntry. In fact, this seems redundant
|
||||
here, but who knows what I'll break if I take it out...
|
||||
|
||||
same for char() and varchar() stuff. I share the same
|
||||
sentiments. This function is poorly written anyway. -ay 6/95
|
||||
*/
|
||||
if (!(*attributeP)->attisset &&
|
||||
(*attributeP)->atttypid!=BPCHAROID &&
|
||||
(*attributeP)->atttypid!=VARCHAROID) {
|
||||
|
||||
typp = (TypeTupleForm) GETSTRUCT(tuple); /* XXX */
|
||||
(*attributeP)->attlen = typp->typlen;
|
||||
(*attributeP)->attbyval = typp->typbyval;
|
||||
}
|
||||
if (natts < 0 || natts > MaxHeapAttributeNumber)
|
||||
elog(WARN, "fillatt: %d attributes is too large", natts);
|
||||
if (natts == 0)
|
||||
{
|
||||
elog(DEBUG, "fillatt: called with natts == 0");
|
||||
return;
|
||||
}
|
||||
|
||||
attributeP = &att[0];
|
||||
|
||||
for (i = 0; i < natts;)
|
||||
{
|
||||
tuple = SearchSysCacheTuple(TYPOID,
|
||||
Int32GetDatum((*attributeP)->atttypid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
{
|
||||
elog(WARN, "fillatt: unknown atttypid %ld",
|
||||
(*attributeP)->atttypid);
|
||||
}
|
||||
else
|
||||
{
|
||||
(*attributeP)->attnum = (int16)++ i;
|
||||
|
||||
/*
|
||||
* Check if the attr is a set before messing with the length
|
||||
* and byval, since those were already set in
|
||||
* TupleDescInitEntry. In fact, this seems redundant here,
|
||||
* but who knows what I'll break if I take it out...
|
||||
*
|
||||
* same for char() and varchar() stuff. I share the same
|
||||
* sentiments. This function is poorly written anyway. -ay
|
||||
* 6/95
|
||||
*/
|
||||
if (!(*attributeP)->attisset &&
|
||||
(*attributeP)->atttypid != BPCHAROID &&
|
||||
(*attributeP)->atttypid != VARCHAROID)
|
||||
{
|
||||
|
||||
typp = (TypeTupleForm) GETSTRUCT(tuple); /* XXX */
|
||||
(*attributeP)->attlen = typp->typlen;
|
||||
(*attributeP)->attbyval = typp->typbyval;
|
||||
}
|
||||
}
|
||||
attributeP += 1;
|
||||
}
|
||||
attributeP += 1;
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,14 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* indexing.c--
|
||||
* This file contains routines to support indices defined on system
|
||||
* catalogs.
|
||||
* This file contains routines to support indices defined on system
|
||||
* catalogs.
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.11 1997/08/31 09:56:18 vadim Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.12 1997/09/07 04:40:21 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -34,36 +34,37 @@
|
||||
/*
|
||||
* Names of indices on the following system catalogs:
|
||||
*
|
||||
* pg_attribute
|
||||
* pg_proc
|
||||
* pg_type
|
||||
* pg_naming
|
||||
* pg_class
|
||||
* pg_attrdef
|
||||
* pg_relcheck
|
||||
* pg_trigger
|
||||
* pg_attribute
|
||||
* pg_proc
|
||||
* pg_type
|
||||
* pg_naming
|
||||
* pg_class
|
||||
* pg_attrdef
|
||||
* pg_relcheck
|
||||
* pg_trigger
|
||||
*/
|
||||
|
||||
char *Name_pg_attr_indices[Num_pg_attr_indices] = {AttributeNameIndex,
|
||||
AttributeNumIndex,
|
||||
AttributeRelidIndex};
|
||||
char *Name_pg_proc_indices[Num_pg_proc_indices] = { ProcedureNameIndex,
|
||||
ProcedureOidIndex,
|
||||
ProcedureSrcIndex};
|
||||
char *Name_pg_type_indices[Num_pg_type_indices] = { TypeNameIndex,
|
||||
TypeOidIndex};
|
||||
char *Name_pg_class_indices[Num_pg_class_indices]= { ClassNameIndex,
|
||||
ClassOidIndex};
|
||||
char *Name_pg_attrdef_indices[Num_pg_attrdef_indices]= { AttrDefaultIndex };
|
||||
char *Name_pg_attr_indices[Num_pg_attr_indices] = {AttributeNameIndex,
|
||||
AttributeNumIndex,
|
||||
AttributeRelidIndex};
|
||||
char *Name_pg_proc_indices[Num_pg_proc_indices] = {ProcedureNameIndex,
|
||||
ProcedureOidIndex,
|
||||
ProcedureSrcIndex};
|
||||
char *Name_pg_type_indices[Num_pg_type_indices] = {TypeNameIndex,
|
||||
TypeOidIndex};
|
||||
char *Name_pg_class_indices[Num_pg_class_indices] = {ClassNameIndex,
|
||||
ClassOidIndex};
|
||||
char *Name_pg_attrdef_indices[Num_pg_attrdef_indices] = {AttrDefaultIndex};
|
||||
|
||||
char *Name_pg_relcheck_indices[Num_pg_relcheck_indices]= { RelCheckIndex };
|
||||
char *Name_pg_relcheck_indices[Num_pg_relcheck_indices] = {RelCheckIndex};
|
||||
|
||||
char *Name_pg_trigger_indices[Num_pg_trigger_indices]= { TriggerRelidIndex };
|
||||
char *Name_pg_trigger_indices[Num_pg_trigger_indices] = {TriggerRelidIndex};
|
||||
|
||||
|
||||
static HeapTuple CatalogIndexFetchTuple(Relation heapRelation,
|
||||
Relation idesc,
|
||||
ScanKey skey);
|
||||
static HeapTuple
|
||||
CatalogIndexFetchTuple(Relation heapRelation,
|
||||
Relation idesc,
|
||||
ScanKey skey);
|
||||
|
||||
|
||||
/*
|
||||
@@ -75,11 +76,11 @@ static HeapTuple CatalogIndexFetchTuple(Relation heapRelation,
|
||||
void
|
||||
CatalogOpenIndices(int nIndices, char *names[], Relation idescs[])
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<nIndices; i++)
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nIndices; i++)
|
||||
{
|
||||
idescs[i] = index_openr(names[i]);
|
||||
idescs[i] = index_openr(names[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,83 +88,84 @@ CatalogOpenIndices(int nIndices, char *names[], Relation idescs[])
|
||||
* This is the inverse routine to CatalogOpenIndices()
|
||||
*/
|
||||
void
|
||||
CatalogCloseIndices(int nIndices, Relation *idescs)
|
||||
CatalogCloseIndices(int nIndices, Relation * idescs)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<nIndices; i++)
|
||||
index_close(idescs[i]);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nIndices; i++)
|
||||
index_close(idescs[i]);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* For the same reasons outlined above CatalogOpenIndices() we need a routine
|
||||
* that takes a new catalog tuple and inserts an associated index tuple into
|
||||
* that takes a new catalog tuple and inserts an associated index tuple into
|
||||
* each catalog index.
|
||||
*/
|
||||
void
|
||||
CatalogIndexInsert(Relation *idescs,
|
||||
int nIndices,
|
||||
Relation heapRelation,
|
||||
HeapTuple heapTuple)
|
||||
CatalogIndexInsert(Relation * idescs,
|
||||
int nIndices,
|
||||
Relation heapRelation,
|
||||
HeapTuple heapTuple)
|
||||
{
|
||||
HeapTuple pgIndexTup;
|
||||
TupleDesc heapDescriptor;
|
||||
IndexTupleForm pgIndexP;
|
||||
Datum datum;
|
||||
int natts;
|
||||
AttrNumber *attnumP;
|
||||
FuncIndexInfo finfo, *finfoP;
|
||||
char nulls[INDEX_MAX_KEYS];
|
||||
int i;
|
||||
|
||||
heapDescriptor = RelationGetTupleDescriptor(heapRelation);
|
||||
|
||||
for (i=0; i<nIndices; i++)
|
||||
HeapTuple pgIndexTup;
|
||||
TupleDesc heapDescriptor;
|
||||
IndexTupleForm pgIndexP;
|
||||
Datum datum;
|
||||
int natts;
|
||||
AttrNumber *attnumP;
|
||||
FuncIndexInfo finfo,
|
||||
*finfoP;
|
||||
char nulls[INDEX_MAX_KEYS];
|
||||
int i;
|
||||
|
||||
heapDescriptor = RelationGetTupleDescriptor(heapRelation);
|
||||
|
||||
for (i = 0; i < nIndices; i++)
|
||||
{
|
||||
TupleDesc indexDescriptor;
|
||||
InsertIndexResult indexRes;
|
||||
|
||||
indexDescriptor = RelationGetTupleDescriptor(idescs[i]);
|
||||
pgIndexTup = SearchSysCacheTuple(INDEXRELID,
|
||||
Int32GetDatum(idescs[i]->rd_id),
|
||||
0,0,0);
|
||||
Assert(pgIndexTup);
|
||||
pgIndexP = (IndexTupleForm)GETSTRUCT(pgIndexTup);
|
||||
|
||||
/*
|
||||
* Compute the number of attributes we are indexing upon.
|
||||
* very important - can't assume one if this is a functional
|
||||
* index.
|
||||
*/
|
||||
for (attnumP=(&pgIndexP->indkey[0]), natts=0;
|
||||
*attnumP != InvalidAttrNumber;
|
||||
attnumP++, natts++)
|
||||
;
|
||||
|
||||
if (pgIndexP->indproc != InvalidOid)
|
||||
TupleDesc indexDescriptor;
|
||||
InsertIndexResult indexRes;
|
||||
|
||||
indexDescriptor = RelationGetTupleDescriptor(idescs[i]);
|
||||
pgIndexTup = SearchSysCacheTuple(INDEXRELID,
|
||||
Int32GetDatum(idescs[i]->rd_id),
|
||||
0, 0, 0);
|
||||
Assert(pgIndexTup);
|
||||
pgIndexP = (IndexTupleForm) GETSTRUCT(pgIndexTup);
|
||||
|
||||
/*
|
||||
* Compute the number of attributes we are indexing upon. very
|
||||
* important - can't assume one if this is a functional index.
|
||||
*/
|
||||
for (attnumP = (&pgIndexP->indkey[0]), natts = 0;
|
||||
*attnumP != InvalidAttrNumber;
|
||||
attnumP++, natts++)
|
||||
;
|
||||
|
||||
if (pgIndexP->indproc != InvalidOid)
|
||||
{
|
||||
FIgetnArgs(&finfo) = natts;
|
||||
natts = 1;
|
||||
FIgetProcOid(&finfo) = pgIndexP->indproc;
|
||||
*(FIgetname(&finfo)) = '\0';
|
||||
finfoP = &finfo;
|
||||
FIgetnArgs(&finfo) = natts;
|
||||
natts = 1;
|
||||
FIgetProcOid(&finfo) = pgIndexP->indproc;
|
||||
*(FIgetname(&finfo)) = '\0';
|
||||
finfoP = &finfo;
|
||||
}
|
||||
else
|
||||
finfoP = (FuncIndexInfo *)NULL;
|
||||
|
||||
FormIndexDatum(natts,
|
||||
(AttrNumber *)&pgIndexP->indkey[0],
|
||||
heapTuple,
|
||||
heapDescriptor,
|
||||
InvalidBuffer,
|
||||
&datum,
|
||||
nulls,
|
||||
finfoP);
|
||||
|
||||
indexRes = index_insert(idescs[i], &datum, nulls,
|
||||
&(heapTuple->t_ctid), heapRelation);
|
||||
if (indexRes) pfree(indexRes);
|
||||
else
|
||||
finfoP = (FuncIndexInfo *) NULL;
|
||||
|
||||
FormIndexDatum(natts,
|
||||
(AttrNumber *) & pgIndexP->indkey[0],
|
||||
heapTuple,
|
||||
heapDescriptor,
|
||||
InvalidBuffer,
|
||||
&datum,
|
||||
nulls,
|
||||
finfoP);
|
||||
|
||||
indexRes = index_insert(idescs[i], &datum, nulls,
|
||||
&(heapTuple->t_ctid), heapRelation);
|
||||
if (indexRes)
|
||||
pfree(indexRes);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,81 +176,88 @@ CatalogIndexInsert(Relation *idescs,
|
||||
bool
|
||||
CatalogHasIndex(char *catName, Oid catId)
|
||||
{
|
||||
Relation pg_class;
|
||||
HeapTuple htup;
|
||||
Form_pg_class pgRelP;
|
||||
int i;
|
||||
|
||||
Assert(IsSystemRelationName(catName));
|
||||
|
||||
/*
|
||||
* If we're bootstraping we don't have pg_class (or any indices).
|
||||
*/
|
||||
if (IsBootstrapProcessingMode())
|
||||
return false;
|
||||
|
||||
if (IsInitProcessingMode()) {
|
||||
for (i = 0; IndexedCatalogNames[i] != NULL; i++) {
|
||||
if ( strcmp(IndexedCatalogNames[i], catName) == 0)
|
||||
return (true);
|
||||
Relation pg_class;
|
||||
HeapTuple htup;
|
||||
Form_pg_class pgRelP;
|
||||
int i;
|
||||
|
||||
Assert(IsSystemRelationName(catName));
|
||||
|
||||
/*
|
||||
* If we're bootstraping we don't have pg_class (or any indices).
|
||||
*/
|
||||
if (IsBootstrapProcessingMode())
|
||||
return false;
|
||||
|
||||
if (IsInitProcessingMode())
|
||||
{
|
||||
for (i = 0; IndexedCatalogNames[i] != NULL; i++)
|
||||
{
|
||||
if (strcmp(IndexedCatalogNames[i], catName) == 0)
|
||||
return (true);
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
return (false);
|
||||
}
|
||||
|
||||
pg_class = heap_openr(RelationRelationName);
|
||||
htup = ClassOidIndexScan(pg_class, catId);
|
||||
heap_close(pg_class);
|
||||
|
||||
if (! HeapTupleIsValid(htup)) {
|
||||
elog(NOTICE, "CatalogHasIndex: no relation with oid %d", catId);
|
||||
return false;
|
||||
}
|
||||
|
||||
pgRelP = (Form_pg_class)GETSTRUCT(htup);
|
||||
return (pgRelP->relhasindex);
|
||||
|
||||
pg_class = heap_openr(RelationRelationName);
|
||||
htup = ClassOidIndexScan(pg_class, catId);
|
||||
heap_close(pg_class);
|
||||
|
||||
if (!HeapTupleIsValid(htup))
|
||||
{
|
||||
elog(NOTICE, "CatalogHasIndex: no relation with oid %d", catId);
|
||||
return false;
|
||||
}
|
||||
|
||||
pgRelP = (Form_pg_class) GETSTRUCT(htup);
|
||||
return (pgRelP->relhasindex);
|
||||
}
|
||||
|
||||
/*
|
||||
* CatalogIndexFetchTuple() -- Get a tuple that satisfies a scan key
|
||||
* from a catalog relation.
|
||||
* CatalogIndexFetchTuple() -- Get a tuple that satisfies a scan key
|
||||
* from a catalog relation.
|
||||
*
|
||||
* Since the index may contain pointers to dead tuples, we need to
|
||||
* iterate until we find a tuple that's valid and satisfies the scan
|
||||
* key.
|
||||
* Since the index may contain pointers to dead tuples, we need to
|
||||
* iterate until we find a tuple that's valid and satisfies the scan
|
||||
* key.
|
||||
*/
|
||||
static HeapTuple
|
||||
static HeapTuple
|
||||
CatalogIndexFetchTuple(Relation heapRelation,
|
||||
Relation idesc,
|
||||
ScanKey skey)
|
||||
Relation idesc,
|
||||
ScanKey skey)
|
||||
{
|
||||
IndexScanDesc sd;
|
||||
RetrieveIndexResult indexRes;
|
||||
HeapTuple tuple;
|
||||
Buffer buffer;
|
||||
|
||||
sd = index_beginscan(idesc, false, 1, skey);
|
||||
tuple = (HeapTuple)NULL;
|
||||
|
||||
do {
|
||||
indexRes = index_getnext(sd, ForwardScanDirection);
|
||||
if (indexRes) {
|
||||
ItemPointer iptr;
|
||||
|
||||
iptr = &indexRes->heap_iptr;
|
||||
tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer);
|
||||
pfree(indexRes);
|
||||
} else
|
||||
break;
|
||||
} while (!HeapTupleIsValid(tuple));
|
||||
|
||||
if (HeapTupleIsValid(tuple)) {
|
||||
tuple = heap_copytuple(tuple);
|
||||
ReleaseBuffer(buffer);
|
||||
}
|
||||
|
||||
index_endscan(sd);
|
||||
pfree(sd);
|
||||
return (tuple);
|
||||
IndexScanDesc sd;
|
||||
RetrieveIndexResult indexRes;
|
||||
HeapTuple tuple;
|
||||
Buffer buffer;
|
||||
|
||||
sd = index_beginscan(idesc, false, 1, skey);
|
||||
tuple = (HeapTuple) NULL;
|
||||
|
||||
do
|
||||
{
|
||||
indexRes = index_getnext(sd, ForwardScanDirection);
|
||||
if (indexRes)
|
||||
{
|
||||
ItemPointer iptr;
|
||||
|
||||
iptr = &indexRes->heap_iptr;
|
||||
tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer);
|
||||
pfree(indexRes);
|
||||
}
|
||||
else
|
||||
break;
|
||||
} while (!HeapTupleIsValid(tuple));
|
||||
|
||||
if (HeapTupleIsValid(tuple))
|
||||
{
|
||||
tuple = heap_copytuple(tuple);
|
||||
ReleaseBuffer(buffer);
|
||||
}
|
||||
|
||||
index_endscan(sd);
|
||||
pfree(sd);
|
||||
return (tuple);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -259,276 +268,295 @@ CatalogIndexFetchTuple(Relation heapRelation,
|
||||
*/
|
||||
HeapTuple
|
||||
AttributeNameIndexScan(Relation heapRelation,
|
||||
Oid relid,
|
||||
char *attname)
|
||||
Oid relid,
|
||||
char *attname)
|
||||
{
|
||||
Relation idesc;
|
||||
ScanKeyData skey;
|
||||
OidName keyarg;
|
||||
HeapTuple tuple;
|
||||
|
||||
keyarg = mkoidname(relid, attname);
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16)0x0,
|
||||
(AttrNumber)1,
|
||||
(RegProcedure)OidNameEqRegProcedure,
|
||||
(Datum)keyarg);
|
||||
|
||||
idesc = index_openr(AttributeNameIndex);
|
||||
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
||||
|
||||
index_close(idesc);
|
||||
pfree(keyarg);
|
||||
|
||||
return tuple;
|
||||
Relation idesc;
|
||||
ScanKeyData skey;
|
||||
OidName keyarg;
|
||||
HeapTuple tuple;
|
||||
|
||||
keyarg = mkoidname(relid, attname);
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16) 0x0,
|
||||
(AttrNumber) 1,
|
||||
(RegProcedure) OidNameEqRegProcedure,
|
||||
(Datum) keyarg);
|
||||
|
||||
idesc = index_openr(AttributeNameIndex);
|
||||
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
||||
|
||||
index_close(idesc);
|
||||
pfree(keyarg);
|
||||
|
||||
return tuple;
|
||||
}
|
||||
|
||||
HeapTuple
|
||||
AttributeNumIndexScan(Relation heapRelation,
|
||||
Oid relid,
|
||||
AttrNumber attnum)
|
||||
Oid relid,
|
||||
AttrNumber attnum)
|
||||
{
|
||||
Relation idesc;
|
||||
ScanKeyData skey;
|
||||
OidInt2 keyarg;
|
||||
HeapTuple tuple;
|
||||
|
||||
keyarg = mkoidint2(relid, (uint16)attnum);
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16)0x0,
|
||||
(AttrNumber)1,
|
||||
(RegProcedure)OidInt2EqRegProcedure,
|
||||
(Datum)keyarg);
|
||||
|
||||
idesc = index_openr(AttributeNumIndex);
|
||||
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
||||
|
||||
index_close(idesc);
|
||||
pfree(keyarg);
|
||||
|
||||
return tuple;
|
||||
Relation idesc;
|
||||
ScanKeyData skey;
|
||||
OidInt2 keyarg;
|
||||
HeapTuple tuple;
|
||||
|
||||
keyarg = mkoidint2(relid, (uint16) attnum);
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16) 0x0,
|
||||
(AttrNumber) 1,
|
||||
(RegProcedure) OidInt2EqRegProcedure,
|
||||
(Datum) keyarg);
|
||||
|
||||
idesc = index_openr(AttributeNumIndex);
|
||||
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
||||
|
||||
index_close(idesc);
|
||||
pfree(keyarg);
|
||||
|
||||
return tuple;
|
||||
}
|
||||
|
||||
HeapTuple
|
||||
ProcedureOidIndexScan(Relation heapRelation, Oid procId)
|
||||
{
|
||||
Relation idesc;
|
||||
ScanKeyData skey;
|
||||
HeapTuple tuple;
|
||||
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16)0x0,
|
||||
(AttrNumber)1,
|
||||
(RegProcedure)ObjectIdEqualRegProcedure,
|
||||
(Datum)procId);
|
||||
|
||||
idesc = index_openr(ProcedureOidIndex);
|
||||
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
||||
|
||||
index_close(idesc);
|
||||
|
||||
return tuple;
|
||||
Relation idesc;
|
||||
ScanKeyData skey;
|
||||
HeapTuple tuple;
|
||||
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16) 0x0,
|
||||
(AttrNumber) 1,
|
||||
(RegProcedure) ObjectIdEqualRegProcedure,
|
||||
(Datum) procId);
|
||||
|
||||
idesc = index_openr(ProcedureOidIndex);
|
||||
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
||||
|
||||
index_close(idesc);
|
||||
|
||||
return tuple;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HeapTuple
|
||||
ProcedureNameIndexScan(Relation heapRelation,
|
||||
char *procName,
|
||||
int nargs,
|
||||
Oid *argTypes)
|
||||
char *procName,
|
||||
int nargs,
|
||||
Oid * argTypes)
|
||||
{
|
||||
Relation idesc;
|
||||
ScanKeyData skey;
|
||||
HeapTuple tuple; /* tuple being tested */
|
||||
HeapTuple return_tuple; /* The tuple pointer we eventually return */
|
||||
IndexScanDesc sd;
|
||||
RetrieveIndexResult indexRes;
|
||||
Buffer buffer;
|
||||
Form_pg_proc pgProcP;
|
||||
bool ScanComplete;
|
||||
/* The index scan is complete, i.e. we've scanned everything there
|
||||
is to scan.
|
||||
*/
|
||||
bool FoundMatch;
|
||||
/* In scanning pg_proc, we have found a row that meets our search
|
||||
criteria.
|
||||
*/
|
||||
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16)0x0,
|
||||
(AttrNumber)1,
|
||||
(RegProcedure)NameEqualRegProcedure,
|
||||
(Datum)procName);
|
||||
|
||||
idesc = index_openr(ProcedureNameIndex);
|
||||
|
||||
sd = index_beginscan(idesc, false, 1, &skey);
|
||||
|
||||
/*
|
||||
* for now, we do the work usually done by CatalogIndexFetchTuple
|
||||
* by hand, so that we can check that the other keys match. when
|
||||
* multi-key indices are added, they will be used here.
|
||||
*/
|
||||
tuple = (HeapTuple) NULL; /* initial value */
|
||||
ScanComplete = false; /* Scan hasn't begun yet */
|
||||
FoundMatch = false; /* No match yet; haven't even looked. */
|
||||
while (!FoundMatch && !ScanComplete) {
|
||||
indexRes = index_getnext(sd, ForwardScanDirection);
|
||||
if (indexRes) {
|
||||
ItemPointer iptr;
|
||||
|
||||
iptr = &indexRes->heap_iptr;
|
||||
tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer);
|
||||
pfree(indexRes);
|
||||
if (HeapTupleIsValid(tuple)) {
|
||||
/* Here's a row for a procedure that has the sought procedure
|
||||
name. To be a match, though, we need it to have the
|
||||
right number and type of arguments too, so we check that
|
||||
now.
|
||||
*/
|
||||
pgProcP = (Form_pg_proc)GETSTRUCT(tuple);
|
||||
if (pgProcP->pronargs == nargs &&
|
||||
oid8eq(&(pgProcP->proargtypes[0]), argTypes))
|
||||
FoundMatch = true;
|
||||
else ReleaseBuffer(buffer);
|
||||
}
|
||||
} else ScanComplete = true;
|
||||
}
|
||||
Relation idesc;
|
||||
ScanKeyData skey;
|
||||
HeapTuple tuple; /* tuple being tested */
|
||||
HeapTuple return_tuple; /* The tuple pointer we eventually
|
||||
* return */
|
||||
IndexScanDesc sd;
|
||||
RetrieveIndexResult indexRes;
|
||||
Buffer buffer;
|
||||
Form_pg_proc pgProcP;
|
||||
bool ScanComplete;
|
||||
|
||||
if (FoundMatch) {
|
||||
Assert(HeapTupleIsValid(tuple));
|
||||
return_tuple = heap_copytuple(tuple);
|
||||
ReleaseBuffer(buffer);
|
||||
} else return_tuple = (HeapTuple)NULL;
|
||||
|
||||
index_endscan(sd);
|
||||
index_close(idesc);
|
||||
|
||||
return return_tuple;
|
||||
/*
|
||||
* The index scan is complete, i.e. we've scanned everything there is
|
||||
* to scan.
|
||||
*/
|
||||
bool FoundMatch;
|
||||
|
||||
/*
|
||||
* In scanning pg_proc, we have found a row that meets our search
|
||||
* criteria.
|
||||
*/
|
||||
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16) 0x0,
|
||||
(AttrNumber) 1,
|
||||
(RegProcedure) NameEqualRegProcedure,
|
||||
(Datum) procName);
|
||||
|
||||
idesc = index_openr(ProcedureNameIndex);
|
||||
|
||||
sd = index_beginscan(idesc, false, 1, &skey);
|
||||
|
||||
/*
|
||||
* for now, we do the work usually done by CatalogIndexFetchTuple by
|
||||
* hand, so that we can check that the other keys match. when
|
||||
* multi-key indices are added, they will be used here.
|
||||
*/
|
||||
tuple = (HeapTuple) NULL; /* initial value */
|
||||
ScanComplete = false; /* Scan hasn't begun yet */
|
||||
FoundMatch = false; /* No match yet; haven't even looked. */
|
||||
while (!FoundMatch && !ScanComplete)
|
||||
{
|
||||
indexRes = index_getnext(sd, ForwardScanDirection);
|
||||
if (indexRes)
|
||||
{
|
||||
ItemPointer iptr;
|
||||
|
||||
iptr = &indexRes->heap_iptr;
|
||||
tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer);
|
||||
pfree(indexRes);
|
||||
if (HeapTupleIsValid(tuple))
|
||||
{
|
||||
|
||||
/*
|
||||
* Here's a row for a procedure that has the sought
|
||||
* procedure name. To be a match, though, we need it to
|
||||
* have the right number and type of arguments too, so we
|
||||
* check that now.
|
||||
*/
|
||||
pgProcP = (Form_pg_proc) GETSTRUCT(tuple);
|
||||
if (pgProcP->pronargs == nargs &&
|
||||
oid8eq(&(pgProcP->proargtypes[0]), argTypes))
|
||||
FoundMatch = true;
|
||||
else
|
||||
ReleaseBuffer(buffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
ScanComplete = true;
|
||||
}
|
||||
|
||||
if (FoundMatch)
|
||||
{
|
||||
Assert(HeapTupleIsValid(tuple));
|
||||
return_tuple = heap_copytuple(tuple);
|
||||
ReleaseBuffer(buffer);
|
||||
}
|
||||
else
|
||||
return_tuple = (HeapTuple) NULL;
|
||||
|
||||
index_endscan(sd);
|
||||
index_close(idesc);
|
||||
|
||||
return return_tuple;
|
||||
}
|
||||
|
||||
|
||||
|
||||
HeapTuple
|
||||
ProcedureSrcIndexScan(Relation heapRelation, text *procSrc)
|
||||
ProcedureSrcIndexScan(Relation heapRelation, text * procSrc)
|
||||
{
|
||||
Relation idesc;
|
||||
IndexScanDesc sd;
|
||||
ScanKeyData skey;
|
||||
RetrieveIndexResult indexRes;
|
||||
HeapTuple tuple;
|
||||
Buffer buffer;
|
||||
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16)0x0,
|
||||
(AttrNumber)Anum_pg_proc_prosrc,
|
||||
(RegProcedure)TextEqualRegProcedure,
|
||||
(Datum)procSrc);
|
||||
|
||||
idesc = index_openr(ProcedureSrcIndex);
|
||||
sd = index_beginscan(idesc, false, 1, &skey);
|
||||
|
||||
indexRes = index_getnext(sd, ForwardScanDirection);
|
||||
if (indexRes) {
|
||||
ItemPointer iptr;
|
||||
|
||||
iptr = &indexRes->heap_iptr;
|
||||
tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer);
|
||||
pfree(indexRes);
|
||||
} else
|
||||
tuple = (HeapTuple)NULL;
|
||||
|
||||
if (HeapTupleIsValid(tuple)) {
|
||||
tuple = heap_copytuple(tuple);
|
||||
ReleaseBuffer(buffer);
|
||||
}
|
||||
|
||||
index_endscan(sd);
|
||||
|
||||
return tuple;
|
||||
Relation idesc;
|
||||
IndexScanDesc sd;
|
||||
ScanKeyData skey;
|
||||
RetrieveIndexResult indexRes;
|
||||
HeapTuple tuple;
|
||||
Buffer buffer;
|
||||
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16) 0x0,
|
||||
(AttrNumber) Anum_pg_proc_prosrc,
|
||||
(RegProcedure) TextEqualRegProcedure,
|
||||
(Datum) procSrc);
|
||||
|
||||
idesc = index_openr(ProcedureSrcIndex);
|
||||
sd = index_beginscan(idesc, false, 1, &skey);
|
||||
|
||||
indexRes = index_getnext(sd, ForwardScanDirection);
|
||||
if (indexRes)
|
||||
{
|
||||
ItemPointer iptr;
|
||||
|
||||
iptr = &indexRes->heap_iptr;
|
||||
tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer);
|
||||
pfree(indexRes);
|
||||
}
|
||||
else
|
||||
tuple = (HeapTuple) NULL;
|
||||
|
||||
if (HeapTupleIsValid(tuple))
|
||||
{
|
||||
tuple = heap_copytuple(tuple);
|
||||
ReleaseBuffer(buffer);
|
||||
}
|
||||
|
||||
index_endscan(sd);
|
||||
|
||||
return tuple;
|
||||
}
|
||||
|
||||
HeapTuple
|
||||
TypeOidIndexScan(Relation heapRelation, Oid typeId)
|
||||
{
|
||||
Relation idesc;
|
||||
ScanKeyData skey;
|
||||
HeapTuple tuple;
|
||||
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16)0x0,
|
||||
(AttrNumber)1,
|
||||
(RegProcedure)ObjectIdEqualRegProcedure,
|
||||
(Datum)typeId);
|
||||
|
||||
idesc = index_openr(TypeOidIndex);
|
||||
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
||||
|
||||
index_close(idesc);
|
||||
|
||||
return tuple;
|
||||
Relation idesc;
|
||||
ScanKeyData skey;
|
||||
HeapTuple tuple;
|
||||
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16) 0x0,
|
||||
(AttrNumber) 1,
|
||||
(RegProcedure) ObjectIdEqualRegProcedure,
|
||||
(Datum) typeId);
|
||||
|
||||
idesc = index_openr(TypeOidIndex);
|
||||
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
||||
|
||||
index_close(idesc);
|
||||
|
||||
return tuple;
|
||||
}
|
||||
|
||||
HeapTuple
|
||||
TypeNameIndexScan(Relation heapRelation, char *typeName)
|
||||
{
|
||||
Relation idesc;
|
||||
ScanKeyData skey;
|
||||
HeapTuple tuple;
|
||||
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16)0x0,
|
||||
(AttrNumber)1,
|
||||
(RegProcedure)NameEqualRegProcedure,
|
||||
(Datum)typeName);
|
||||
|
||||
idesc = index_openr(TypeNameIndex);
|
||||
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
||||
|
||||
index_close(idesc);
|
||||
|
||||
return tuple;
|
||||
Relation idesc;
|
||||
ScanKeyData skey;
|
||||
HeapTuple tuple;
|
||||
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16) 0x0,
|
||||
(AttrNumber) 1,
|
||||
(RegProcedure) NameEqualRegProcedure,
|
||||
(Datum) typeName);
|
||||
|
||||
idesc = index_openr(TypeNameIndex);
|
||||
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
||||
|
||||
index_close(idesc);
|
||||
|
||||
return tuple;
|
||||
}
|
||||
|
||||
HeapTuple
|
||||
ClassNameIndexScan(Relation heapRelation, char *relName)
|
||||
{
|
||||
Relation idesc;
|
||||
ScanKeyData skey;
|
||||
HeapTuple tuple;
|
||||
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16)0x0,
|
||||
(AttrNumber)1,
|
||||
(RegProcedure)NameEqualRegProcedure,
|
||||
(Datum)relName);
|
||||
|
||||
idesc = index_openr(ClassNameIndex);
|
||||
|
||||
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
||||
|
||||
index_close(idesc);
|
||||
return tuple;
|
||||
Relation idesc;
|
||||
ScanKeyData skey;
|
||||
HeapTuple tuple;
|
||||
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16) 0x0,
|
||||
(AttrNumber) 1,
|
||||
(RegProcedure) NameEqualRegProcedure,
|
||||
(Datum) relName);
|
||||
|
||||
idesc = index_openr(ClassNameIndex);
|
||||
|
||||
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
||||
|
||||
index_close(idesc);
|
||||
return tuple;
|
||||
}
|
||||
|
||||
HeapTuple
|
||||
ClassOidIndexScan(Relation heapRelation, Oid relId)
|
||||
{
|
||||
Relation idesc;
|
||||
ScanKeyData skey;
|
||||
HeapTuple tuple;
|
||||
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16)0x0,
|
||||
(AttrNumber)1,
|
||||
(RegProcedure)ObjectIdEqualRegProcedure,
|
||||
(Datum)relId);
|
||||
|
||||
idesc = index_openr(ClassOidIndex);
|
||||
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
||||
|
||||
index_close(idesc);
|
||||
|
||||
return tuple;
|
||||
Relation idesc;
|
||||
ScanKeyData skey;
|
||||
HeapTuple tuple;
|
||||
|
||||
ScanKeyEntryInitialize(&skey,
|
||||
(bits16) 0x0,
|
||||
(AttrNumber) 1,
|
||||
(RegProcedure) ObjectIdEqualRegProcedure,
|
||||
(Datum) relId);
|
||||
|
||||
idesc = index_openr(ClassOidIndex);
|
||||
tuple = CatalogIndexFetchTuple(heapRelation, idesc, &skey);
|
||||
|
||||
index_close(idesc);
|
||||
|
||||
return tuple;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pg_aggregate.c--
|
||||
* routines to support manipulation of the pg_aggregate relation
|
||||
* routines to support manipulation of the pg_aggregate relation
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.5 1997/07/24 20:11:47 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.6 1997/09/07 04:40:24 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -24,9 +24,9 @@
|
||||
#include <catalog/pg_aggregate.h>
|
||||
#include <miscadmin.h>
|
||||
#ifndef HAVE_MEMMOVE
|
||||
# include <regex/utils.h>
|
||||
#include <regex/utils.h>
|
||||
#else
|
||||
# include <string.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
/* ----------------
|
||||
@@ -34,288 +34,303 @@
|
||||
*
|
||||
* aggregates overloading has been added. Instead of the full
|
||||
* overload support we have for functions, aggregate overloading only
|
||||
* applies to exact basetype matches. That is, we don't check the
|
||||
* applies to exact basetype matches. That is, we don't check the
|
||||
* the inheritance hierarchy
|
||||
*
|
||||
* OLD COMMENTS:
|
||||
* Currently, redefining aggregates using the same name is not
|
||||
* supported. In such a case, a warning is printed that the
|
||||
* aggregate already exists. If such is not the case, a new tuple
|
||||
* is created and inserted in the aggregate relation. The fields
|
||||
* of this tuple are aggregate name, owner id, 2 transition functions
|
||||
* (called aggtransfn1 and aggtransfn2), final function (aggfinalfn),
|
||||
* type of data on which aggtransfn1 operates (aggbasetype), return
|
||||
* types of the two transition functions (aggtranstype1 and
|
||||
* aggtranstype2), final return type (aggfinaltype), and initial values
|
||||
* for the two state transition functions (agginitval1 and agginitval2).
|
||||
* All types and functions must have been defined
|
||||
* prior to defining the aggregate.
|
||||
*
|
||||
* Currently, redefining aggregates using the same name is not
|
||||
* supported. In such a case, a warning is printed that the
|
||||
* aggregate already exists. If such is not the case, a new tuple
|
||||
* is created and inserted in the aggregate relation. The fields
|
||||
* of this tuple are aggregate name, owner id, 2 transition functions
|
||||
* (called aggtransfn1 and aggtransfn2), final function (aggfinalfn),
|
||||
* type of data on which aggtransfn1 operates (aggbasetype), return
|
||||
* types of the two transition functions (aggtranstype1 and
|
||||
* aggtranstype2), final return type (aggfinaltype), and initial values
|
||||
* for the two state transition functions (agginitval1 and agginitval2).
|
||||
* All types and functions must have been defined
|
||||
* prior to defining the aggregate.
|
||||
*
|
||||
* ---------------
|
||||
*/
|
||||
void
|
||||
AggregateCreate(char *aggName,
|
||||
char *aggtransfn1Name,
|
||||
char *aggtransfn2Name,
|
||||
char *aggfinalfnName,
|
||||
char *aggbasetypeName,
|
||||
char *aggtransfn1typeName,
|
||||
char *aggtransfn2typeName,
|
||||
char *agginitval1,
|
||||
char *agginitval2)
|
||||
char *aggtransfn1Name,
|
||||
char *aggtransfn2Name,
|
||||
char *aggfinalfnName,
|
||||
char *aggbasetypeName,
|
||||
char *aggtransfn1typeName,
|
||||
char *aggtransfn2typeName,
|
||||
char *agginitval1,
|
||||
char *agginitval2)
|
||||
{
|
||||
register i;
|
||||
Relation aggdesc;
|
||||
HeapTuple tup;
|
||||
char nulls[Natts_pg_aggregate];
|
||||
Datum values[Natts_pg_aggregate];
|
||||
Form_pg_proc proc;
|
||||
Oid xfn1 = InvalidOid;
|
||||
Oid xfn2 = InvalidOid;
|
||||
Oid ffn = InvalidOid;
|
||||
Oid xbase = InvalidOid;
|
||||
Oid xret1 = InvalidOid;
|
||||
Oid xret2 = InvalidOid;
|
||||
Oid fret = InvalidOid;
|
||||
Oid fnArgs[8];
|
||||
TupleDesc tupDesc;
|
||||
|
||||
memset(fnArgs, 0, 8 * sizeof(Oid));
|
||||
|
||||
/* sanity checks */
|
||||
if (!aggName)
|
||||
elog(WARN, "AggregateCreate: no aggregate name supplied");
|
||||
|
||||
if (!aggtransfn1Name && !aggtransfn2Name)
|
||||
elog(WARN, "AggregateCreate: aggregate must have at least one transition function");
|
||||
|
||||
tup = SearchSysCacheTuple(TYPNAME,
|
||||
PointerGetDatum(aggbasetypeName),
|
||||
0,0,0);
|
||||
if(!HeapTupleIsValid(tup))
|
||||
elog(WARN, "AggregateCreate: Type '%s' undefined",aggbasetypeName);
|
||||
xbase = tup->t_oid;
|
||||
register i;
|
||||
Relation aggdesc;
|
||||
HeapTuple tup;
|
||||
char nulls[Natts_pg_aggregate];
|
||||
Datum values[Natts_pg_aggregate];
|
||||
Form_pg_proc proc;
|
||||
Oid xfn1 = InvalidOid;
|
||||
Oid xfn2 = InvalidOid;
|
||||
Oid ffn = InvalidOid;
|
||||
Oid xbase = InvalidOid;
|
||||
Oid xret1 = InvalidOid;
|
||||
Oid xret2 = InvalidOid;
|
||||
Oid fret = InvalidOid;
|
||||
Oid fnArgs[8];
|
||||
TupleDesc tupDesc;
|
||||
|
||||
if (aggtransfn1Name) {
|
||||
tup = SearchSysCacheTuple(TYPNAME,
|
||||
PointerGetDatum(aggtransfn1typeName),
|
||||
0,0,0);
|
||||
if(!HeapTupleIsValid(tup))
|
||||
elog(WARN, "AggregateCreate: Type '%s' undefined",
|
||||
aggtransfn1typeName);
|
||||
xret1 = tup->t_oid;
|
||||
|
||||
fnArgs[0] = xret1;
|
||||
fnArgs[1] = xbase;
|
||||
tup = SearchSysCacheTuple(PRONAME,
|
||||
PointerGetDatum(aggtransfn1Name),
|
||||
Int32GetDatum(2),
|
||||
PointerGetDatum(fnArgs),
|
||||
0);
|
||||
if(!HeapTupleIsValid(tup))
|
||||
elog(WARN, "AggregateCreate: '%s('%s', '%s') does not exist",
|
||||
aggtransfn1Name, aggtransfn1typeName, aggbasetypeName);
|
||||
if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret1)
|
||||
elog(WARN, "AggregateCreate: return type of '%s' is not '%s'",
|
||||
aggtransfn1Name,
|
||||
aggtransfn1typeName);
|
||||
xfn1 = tup->t_oid;
|
||||
if (!OidIsValid(xfn1) || !OidIsValid(xret1) ||
|
||||
!OidIsValid(xbase))
|
||||
elog(WARN, "AggregateCreate: bogus function '%s'", aggfinalfnName);
|
||||
}
|
||||
|
||||
if (aggtransfn2Name) {
|
||||
tup = SearchSysCacheTuple(TYPNAME,
|
||||
PointerGetDatum(aggtransfn2typeName),
|
||||
0,0,0);
|
||||
if(!HeapTupleIsValid(tup))
|
||||
elog(WARN, "AggregateCreate: Type '%s' undefined",
|
||||
aggtransfn2typeName);
|
||||
xret2 = tup->t_oid;
|
||||
|
||||
fnArgs[0] = xret2;
|
||||
fnArgs[1] = 0;
|
||||
tup = SearchSysCacheTuple(PRONAME,
|
||||
PointerGetDatum(aggtransfn2Name),
|
||||
Int32GetDatum(1),
|
||||
PointerGetDatum(fnArgs),
|
||||
0);
|
||||
if(!HeapTupleIsValid(tup))
|
||||
elog(WARN, "AggregateCreate: '%s'('%s') does not exist",
|
||||
aggtransfn2Name, aggtransfn2typeName);
|
||||
if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret2)
|
||||
elog(WARN, "AggregateCreate: return type of '%s' is not '%s'",
|
||||
aggtransfn2Name, aggtransfn2typeName);
|
||||
xfn2 = tup->t_oid;
|
||||
if (!OidIsValid(xfn2) || !OidIsValid(xret2))
|
||||
elog(WARN, "AggregateCreate: bogus function '%s'",aggfinalfnName);
|
||||
}
|
||||
|
||||
tup = SearchSysCacheTuple(AGGNAME, PointerGetDatum(aggName),
|
||||
ObjectIdGetDatum(xbase),
|
||||
0,0);
|
||||
if (HeapTupleIsValid(tup))
|
||||
elog(WARN,
|
||||
"AggregateCreate: aggregate '%s' with base type '%s' already exists",
|
||||
aggName, aggbasetypeName);
|
||||
memset(fnArgs, 0, 8 * sizeof(Oid));
|
||||
|
||||
/* more sanity checks */
|
||||
if (aggtransfn1Name && aggtransfn2Name && !aggfinalfnName)
|
||||
elog(WARN, "AggregateCreate: Aggregate must have final function with both transition functions");
|
||||
|
||||
if ((!aggtransfn1Name || !aggtransfn2Name) && aggfinalfnName)
|
||||
elog(WARN, "AggregateCreate: Aggregate cannot have final function without both transition functions");
|
||||
|
||||
if (aggfinalfnName) {
|
||||
fnArgs[0] = xret1;
|
||||
fnArgs[1] = xret2;
|
||||
tup = SearchSysCacheTuple(PRONAME,
|
||||
PointerGetDatum(aggfinalfnName),
|
||||
Int32GetDatum(2),
|
||||
PointerGetDatum(fnArgs),
|
||||
0);
|
||||
if(!HeapTupleIsValid(tup))
|
||||
elog(WARN, "AggregateCreate: '%s'('%s','%s') does not exist",
|
||||
aggfinalfnName, aggtransfn1typeName, aggtransfn2typeName);
|
||||
ffn = tup->t_oid;
|
||||
proc = (Form_pg_proc) GETSTRUCT(tup);
|
||||
fret = proc->prorettype;
|
||||
if (!OidIsValid(ffn) || !OidIsValid(fret))
|
||||
elog(WARN, "AggregateCreate: bogus function '%s'", aggfinalfnName);
|
||||
}
|
||||
|
||||
/*
|
||||
* If transition function 2 is defined, it must have an initial value,
|
||||
* whereas transition function 1 does not, which allows man and min
|
||||
* aggregates to return NULL if they are evaluated on empty sets.
|
||||
*/
|
||||
if (OidIsValid(xfn2) && !agginitval2)
|
||||
elog(WARN, "AggregateCreate: transition function 2 MUST have an initial value");
|
||||
|
||||
/* initialize nulls and values */
|
||||
for(i=0; i < Natts_pg_aggregate; i++) {
|
||||
nulls[i] = ' ';
|
||||
values[i] = (Datum)NULL;
|
||||
}
|
||||
values[Anum_pg_aggregate_aggname-1] = PointerGetDatum(aggName);
|
||||
values[Anum_pg_aggregate_aggowner-1] =
|
||||
Int32GetDatum(GetUserId());
|
||||
values[Anum_pg_aggregate_aggtransfn1-1] =
|
||||
ObjectIdGetDatum(xfn1);
|
||||
values[Anum_pg_aggregate_aggtransfn2-1] =
|
||||
ObjectIdGetDatum(xfn2);
|
||||
values[Anum_pg_aggregate_aggfinalfn-1] =
|
||||
ObjectIdGetDatum(ffn);
|
||||
|
||||
values[Anum_pg_aggregate_aggbasetype-1] =
|
||||
ObjectIdGetDatum(xbase);
|
||||
if (!OidIsValid(xfn1)) {
|
||||
values[Anum_pg_aggregate_aggtranstype1-1] =
|
||||
ObjectIdGetDatum(InvalidOid);
|
||||
values[Anum_pg_aggregate_aggtranstype2-1] =
|
||||
ObjectIdGetDatum(xret2);
|
||||
values[Anum_pg_aggregate_aggfinaltype-1] =
|
||||
ObjectIdGetDatum(xret2);
|
||||
}
|
||||
else if (!OidIsValid(xfn2)) {
|
||||
values[Anum_pg_aggregate_aggtranstype1-1] =
|
||||
ObjectIdGetDatum(xret1);
|
||||
values[Anum_pg_aggregate_aggtranstype2-1] =
|
||||
ObjectIdGetDatum(InvalidOid);
|
||||
values[Anum_pg_aggregate_aggfinaltype-1] =
|
||||
ObjectIdGetDatum(xret1);
|
||||
}
|
||||
else {
|
||||
values[Anum_pg_aggregate_aggtranstype1-1] =
|
||||
ObjectIdGetDatum(xret1);
|
||||
values[Anum_pg_aggregate_aggtranstype2-1] =
|
||||
ObjectIdGetDatum(xret2);
|
||||
values[Anum_pg_aggregate_aggfinaltype-1] =
|
||||
ObjectIdGetDatum(fret);
|
||||
}
|
||||
|
||||
if (agginitval1)
|
||||
values[Anum_pg_aggregate_agginitval1-1] = PointerGetDatum(textin(agginitval1));
|
||||
else
|
||||
nulls[Anum_pg_aggregate_agginitval1-1] = 'n';
|
||||
|
||||
if (agginitval2)
|
||||
values[Anum_pg_aggregate_agginitval2-1] = PointerGetDatum(textin(agginitval2));
|
||||
else
|
||||
nulls[Anum_pg_aggregate_agginitval2-1] = 'n';
|
||||
|
||||
if (!RelationIsValid(aggdesc = heap_openr(AggregateRelationName)))
|
||||
elog(WARN, "AggregateCreate: could not open '%s'",
|
||||
AggregateRelationName);
|
||||
/* sanity checks */
|
||||
if (!aggName)
|
||||
elog(WARN, "AggregateCreate: no aggregate name supplied");
|
||||
|
||||
tupDesc = aggdesc->rd_att;
|
||||
if (!HeapTupleIsValid(tup = heap_formtuple(tupDesc,
|
||||
values,
|
||||
nulls)))
|
||||
elog(WARN, "AggregateCreate: heap_formtuple failed");
|
||||
if (!OidIsValid(heap_insert(aggdesc, tup)))
|
||||
elog(WARN, "AggregateCreate: heap_insert failed");
|
||||
heap_close(aggdesc);
|
||||
if (!aggtransfn1Name && !aggtransfn2Name)
|
||||
elog(WARN, "AggregateCreate: aggregate must have at least one transition function");
|
||||
|
||||
tup = SearchSysCacheTuple(TYPNAME,
|
||||
PointerGetDatum(aggbasetypeName),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(WARN, "AggregateCreate: Type '%s' undefined", aggbasetypeName);
|
||||
xbase = tup->t_oid;
|
||||
|
||||
if (aggtransfn1Name)
|
||||
{
|
||||
tup = SearchSysCacheTuple(TYPNAME,
|
||||
PointerGetDatum(aggtransfn1typeName),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(WARN, "AggregateCreate: Type '%s' undefined",
|
||||
aggtransfn1typeName);
|
||||
xret1 = tup->t_oid;
|
||||
|
||||
fnArgs[0] = xret1;
|
||||
fnArgs[1] = xbase;
|
||||
tup = SearchSysCacheTuple(PRONAME,
|
||||
PointerGetDatum(aggtransfn1Name),
|
||||
Int32GetDatum(2),
|
||||
PointerGetDatum(fnArgs),
|
||||
0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(WARN, "AggregateCreate: '%s('%s', '%s') does not exist",
|
||||
aggtransfn1Name, aggtransfn1typeName, aggbasetypeName);
|
||||
if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret1)
|
||||
elog(WARN, "AggregateCreate: return type of '%s' is not '%s'",
|
||||
aggtransfn1Name,
|
||||
aggtransfn1typeName);
|
||||
xfn1 = tup->t_oid;
|
||||
if (!OidIsValid(xfn1) || !OidIsValid(xret1) ||
|
||||
!OidIsValid(xbase))
|
||||
elog(WARN, "AggregateCreate: bogus function '%s'", aggfinalfnName);
|
||||
}
|
||||
|
||||
if (aggtransfn2Name)
|
||||
{
|
||||
tup = SearchSysCacheTuple(TYPNAME,
|
||||
PointerGetDatum(aggtransfn2typeName),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(WARN, "AggregateCreate: Type '%s' undefined",
|
||||
aggtransfn2typeName);
|
||||
xret2 = tup->t_oid;
|
||||
|
||||
fnArgs[0] = xret2;
|
||||
fnArgs[1] = 0;
|
||||
tup = SearchSysCacheTuple(PRONAME,
|
||||
PointerGetDatum(aggtransfn2Name),
|
||||
Int32GetDatum(1),
|
||||
PointerGetDatum(fnArgs),
|
||||
0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(WARN, "AggregateCreate: '%s'('%s') does not exist",
|
||||
aggtransfn2Name, aggtransfn2typeName);
|
||||
if (((Form_pg_proc) GETSTRUCT(tup))->prorettype != xret2)
|
||||
elog(WARN, "AggregateCreate: return type of '%s' is not '%s'",
|
||||
aggtransfn2Name, aggtransfn2typeName);
|
||||
xfn2 = tup->t_oid;
|
||||
if (!OidIsValid(xfn2) || !OidIsValid(xret2))
|
||||
elog(WARN, "AggregateCreate: bogus function '%s'", aggfinalfnName);
|
||||
}
|
||||
|
||||
tup = SearchSysCacheTuple(AGGNAME, PointerGetDatum(aggName),
|
||||
ObjectIdGetDatum(xbase),
|
||||
0, 0);
|
||||
if (HeapTupleIsValid(tup))
|
||||
elog(WARN,
|
||||
"AggregateCreate: aggregate '%s' with base type '%s' already exists",
|
||||
aggName, aggbasetypeName);
|
||||
|
||||
/* more sanity checks */
|
||||
if (aggtransfn1Name && aggtransfn2Name && !aggfinalfnName)
|
||||
elog(WARN, "AggregateCreate: Aggregate must have final function with both transition functions");
|
||||
|
||||
if ((!aggtransfn1Name || !aggtransfn2Name) && aggfinalfnName)
|
||||
elog(WARN, "AggregateCreate: Aggregate cannot have final function without both transition functions");
|
||||
|
||||
if (aggfinalfnName)
|
||||
{
|
||||
fnArgs[0] = xret1;
|
||||
fnArgs[1] = xret2;
|
||||
tup = SearchSysCacheTuple(PRONAME,
|
||||
PointerGetDatum(aggfinalfnName),
|
||||
Int32GetDatum(2),
|
||||
PointerGetDatum(fnArgs),
|
||||
0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(WARN, "AggregateCreate: '%s'('%s','%s') does not exist",
|
||||
aggfinalfnName, aggtransfn1typeName, aggtransfn2typeName);
|
||||
ffn = tup->t_oid;
|
||||
proc = (Form_pg_proc) GETSTRUCT(tup);
|
||||
fret = proc->prorettype;
|
||||
if (!OidIsValid(ffn) || !OidIsValid(fret))
|
||||
elog(WARN, "AggregateCreate: bogus function '%s'", aggfinalfnName);
|
||||
}
|
||||
|
||||
/*
|
||||
* If transition function 2 is defined, it must have an initial value,
|
||||
* whereas transition function 1 does not, which allows man and min
|
||||
* aggregates to return NULL if they are evaluated on empty sets.
|
||||
*/
|
||||
if (OidIsValid(xfn2) && !agginitval2)
|
||||
elog(WARN, "AggregateCreate: transition function 2 MUST have an initial value");
|
||||
|
||||
/* initialize nulls and values */
|
||||
for (i = 0; i < Natts_pg_aggregate; i++)
|
||||
{
|
||||
nulls[i] = ' ';
|
||||
values[i] = (Datum) NULL;
|
||||
}
|
||||
values[Anum_pg_aggregate_aggname - 1] = PointerGetDatum(aggName);
|
||||
values[Anum_pg_aggregate_aggowner - 1] =
|
||||
Int32GetDatum(GetUserId());
|
||||
values[Anum_pg_aggregate_aggtransfn1 - 1] =
|
||||
ObjectIdGetDatum(xfn1);
|
||||
values[Anum_pg_aggregate_aggtransfn2 - 1] =
|
||||
ObjectIdGetDatum(xfn2);
|
||||
values[Anum_pg_aggregate_aggfinalfn - 1] =
|
||||
ObjectIdGetDatum(ffn);
|
||||
|
||||
values[Anum_pg_aggregate_aggbasetype - 1] =
|
||||
ObjectIdGetDatum(xbase);
|
||||
if (!OidIsValid(xfn1))
|
||||
{
|
||||
values[Anum_pg_aggregate_aggtranstype1 - 1] =
|
||||
ObjectIdGetDatum(InvalidOid);
|
||||
values[Anum_pg_aggregate_aggtranstype2 - 1] =
|
||||
ObjectIdGetDatum(xret2);
|
||||
values[Anum_pg_aggregate_aggfinaltype - 1] =
|
||||
ObjectIdGetDatum(xret2);
|
||||
}
|
||||
else if (!OidIsValid(xfn2))
|
||||
{
|
||||
values[Anum_pg_aggregate_aggtranstype1 - 1] =
|
||||
ObjectIdGetDatum(xret1);
|
||||
values[Anum_pg_aggregate_aggtranstype2 - 1] =
|
||||
ObjectIdGetDatum(InvalidOid);
|
||||
values[Anum_pg_aggregate_aggfinaltype - 1] =
|
||||
ObjectIdGetDatum(xret1);
|
||||
}
|
||||
else
|
||||
{
|
||||
values[Anum_pg_aggregate_aggtranstype1 - 1] =
|
||||
ObjectIdGetDatum(xret1);
|
||||
values[Anum_pg_aggregate_aggtranstype2 - 1] =
|
||||
ObjectIdGetDatum(xret2);
|
||||
values[Anum_pg_aggregate_aggfinaltype - 1] =
|
||||
ObjectIdGetDatum(fret);
|
||||
}
|
||||
|
||||
if (agginitval1)
|
||||
values[Anum_pg_aggregate_agginitval1 - 1] = PointerGetDatum(textin(agginitval1));
|
||||
else
|
||||
nulls[Anum_pg_aggregate_agginitval1 - 1] = 'n';
|
||||
|
||||
if (agginitval2)
|
||||
values[Anum_pg_aggregate_agginitval2 - 1] = PointerGetDatum(textin(agginitval2));
|
||||
else
|
||||
nulls[Anum_pg_aggregate_agginitval2 - 1] = 'n';
|
||||
|
||||
if (!RelationIsValid(aggdesc = heap_openr(AggregateRelationName)))
|
||||
elog(WARN, "AggregateCreate: could not open '%s'",
|
||||
AggregateRelationName);
|
||||
|
||||
tupDesc = aggdesc->rd_att;
|
||||
if (!HeapTupleIsValid(tup = heap_formtuple(tupDesc,
|
||||
values,
|
||||
nulls)))
|
||||
elog(WARN, "AggregateCreate: heap_formtuple failed");
|
||||
if (!OidIsValid(heap_insert(aggdesc, tup)))
|
||||
elog(WARN, "AggregateCreate: heap_insert failed");
|
||||
heap_close(aggdesc);
|
||||
|
||||
}
|
||||
|
||||
char *
|
||||
AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool *isNull)
|
||||
char *
|
||||
AggNameGetInitVal(char *aggName, Oid basetype, int xfuncno, bool * isNull)
|
||||
{
|
||||
HeapTuple tup;
|
||||
Relation aggRel;
|
||||
int initValAttno;
|
||||
Oid transtype;
|
||||
text *textInitVal;
|
||||
char *strInitVal, *initVal;
|
||||
|
||||
Assert(PointerIsValid(aggName));
|
||||
Assert(PointerIsValid(isNull));
|
||||
Assert(xfuncno == 1 || xfuncno == 2);
|
||||
HeapTuple tup;
|
||||
Relation aggRel;
|
||||
int initValAttno;
|
||||
Oid transtype;
|
||||
text *textInitVal;
|
||||
char *strInitVal,
|
||||
*initVal;
|
||||
|
||||
tup = SearchSysCacheTuple(AGGNAME,
|
||||
PointerGetDatum(aggName),
|
||||
PointerGetDatum(basetype),
|
||||
0,0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(WARN, "AggNameGetInitVal: cache lookup failed for aggregate '%s'",
|
||||
aggName);
|
||||
if (xfuncno == 1) {
|
||||
transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype1;
|
||||
initValAttno = Anum_pg_aggregate_agginitval1;
|
||||
}
|
||||
else /* can only be 1 or 2 */ {
|
||||
transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype2;
|
||||
initValAttno = Anum_pg_aggregate_agginitval2;
|
||||
}
|
||||
|
||||
aggRel = heap_openr(AggregateRelationName);
|
||||
if (!RelationIsValid(aggRel))
|
||||
elog(WARN, "AggNameGetInitVal: could not open \"%-.*s\"",
|
||||
AggregateRelationName);
|
||||
/*
|
||||
* must use fastgetattr in case one or other of the init values is NULL
|
||||
*/
|
||||
textInitVal = (text *) fastgetattr(tup, initValAttno,
|
||||
RelationGetTupleDescriptor(aggRel),
|
||||
isNull);
|
||||
if (!PointerIsValid(textInitVal))
|
||||
*isNull = true;
|
||||
if (*isNull) {
|
||||
Assert(PointerIsValid(aggName));
|
||||
Assert(PointerIsValid(isNull));
|
||||
Assert(xfuncno == 1 || xfuncno == 2);
|
||||
|
||||
tup = SearchSysCacheTuple(AGGNAME,
|
||||
PointerGetDatum(aggName),
|
||||
PointerGetDatum(basetype),
|
||||
0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(WARN, "AggNameGetInitVal: cache lookup failed for aggregate '%s'",
|
||||
aggName);
|
||||
if (xfuncno == 1)
|
||||
{
|
||||
transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype1;
|
||||
initValAttno = Anum_pg_aggregate_agginitval1;
|
||||
}
|
||||
else
|
||||
/* can only be 1 or 2 */
|
||||
{
|
||||
transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype2;
|
||||
initValAttno = Anum_pg_aggregate_agginitval2;
|
||||
}
|
||||
|
||||
aggRel = heap_openr(AggregateRelationName);
|
||||
if (!RelationIsValid(aggRel))
|
||||
elog(WARN, "AggNameGetInitVal: could not open \"%-.*s\"",
|
||||
AggregateRelationName);
|
||||
|
||||
/*
|
||||
* must use fastgetattr in case one or other of the init values is
|
||||
* NULL
|
||||
*/
|
||||
textInitVal = (text *) fastgetattr(tup, initValAttno,
|
||||
RelationGetTupleDescriptor(aggRel),
|
||||
isNull);
|
||||
if (!PointerIsValid(textInitVal))
|
||||
*isNull = true;
|
||||
if (*isNull)
|
||||
{
|
||||
heap_close(aggRel);
|
||||
return ((char *) NULL);
|
||||
}
|
||||
strInitVal = textout(textInitVal);
|
||||
heap_close(aggRel);
|
||||
return((char *) NULL);
|
||||
}
|
||||
strInitVal = textout(textInitVal);
|
||||
heap_close(aggRel);
|
||||
|
||||
tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(transtype),
|
||||
0,0,0);
|
||||
if (!HeapTupleIsValid(tup)) {
|
||||
|
||||
tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(transtype),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
{
|
||||
pfree(strInitVal);
|
||||
elog(WARN, "AggNameGetInitVal: cache lookup failed on aggregate transition function return type");
|
||||
}
|
||||
initVal = fmgr(((TypeTupleForm) GETSTRUCT(tup))->typinput, strInitVal, -1);
|
||||
pfree(strInitVal);
|
||||
elog(WARN, "AggNameGetInitVal: cache lookup failed on aggregate transition function return type");
|
||||
}
|
||||
initVal = fmgr(((TypeTupleForm) GETSTRUCT(tup))->typinput, strInitVal, -1);
|
||||
pfree(strInitVal);
|
||||
return(initVal);
|
||||
return (initVal);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,13 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pg_proc.c--
|
||||
* routines to support manipulation of the pg_proc relation
|
||||
* routines to support manipulation of the pg_proc relation
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.5 1996/11/08 00:44:34 scrappy Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.6 1997/09/07 04:40:30 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -30,231 +30,252 @@
|
||||
#include <utils/lsyscache.h>
|
||||
#include <miscadmin.h>
|
||||
#ifndef HAVE_MEMMOVE
|
||||
# include <regex/utils.h>
|
||||
#include <regex/utils.h>
|
||||
#else
|
||||
# include <string.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* ProcedureDefine
|
||||
* ProcedureDefine
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
Oid
|
||||
ProcedureCreate(char *procedureName,
|
||||
bool returnsSet,
|
||||
char *returnTypeName,
|
||||
char *languageName,
|
||||
char *prosrc,
|
||||
char *probin,
|
||||
bool canCache,
|
||||
bool trusted,
|
||||
int32 byte_pct,
|
||||
int32 perbyte_cpu,
|
||||
int32 percall_cpu,
|
||||
int32 outin_ratio,
|
||||
List *argList,
|
||||
CommandDest dest)
|
||||
bool returnsSet,
|
||||
char *returnTypeName,
|
||||
char *languageName,
|
||||
char *prosrc,
|
||||
char *probin,
|
||||
bool canCache,
|
||||
bool trusted,
|
||||
int32 byte_pct,
|
||||
int32 perbyte_cpu,
|
||||
int32 percall_cpu,
|
||||
int32 outin_ratio,
|
||||
List * argList,
|
||||
CommandDest dest)
|
||||
{
|
||||
register i;
|
||||
Relation rdesc;
|
||||
HeapTuple tup;
|
||||
bool defined;
|
||||
uint16 parameterCount;
|
||||
char nulls[ Natts_pg_proc ];
|
||||
Datum values[ Natts_pg_proc ];
|
||||
Oid languageObjectId;
|
||||
Oid typeObjectId;
|
||||
List *x;
|
||||
QueryTreeList *querytree_list;
|
||||
List *plan_list;
|
||||
Oid typev[8];
|
||||
Oid relid;
|
||||
Oid toid;
|
||||
text *prosrctext;
|
||||
TupleDesc tupDesc;
|
||||
|
||||
/* ----------------
|
||||
* sanity checks
|
||||
* ----------------
|
||||
*/
|
||||
Assert(PointerIsValid(prosrc));
|
||||
Assert(PointerIsValid(probin));
|
||||
|
||||
parameterCount = 0;
|
||||
memset(typev, 0, 8 * sizeof(Oid));
|
||||
foreach (x, argList) {
|
||||
Value *t = lfirst(x);
|
||||
|
||||
if (parameterCount == 8)
|
||||
elog(WARN, "Procedures cannot take more than 8 arguments");
|
||||
|
||||
if (strcmp(strVal(t), "opaque") == 0) {
|
||||
if (strcmp(languageName, "sql") == 0) {
|
||||
elog(WARN, "ProcedureDefine: sql functions cannot take type \"opaque\"");
|
||||
}
|
||||
toid = 0;
|
||||
} else {
|
||||
toid = TypeGet(strVal(t), &defined);
|
||||
|
||||
if (!OidIsValid(toid)) {
|
||||
elog(WARN, "ProcedureCreate: arg type '%s' is not defined",
|
||||
strVal(t));
|
||||
}
|
||||
|
||||
if (!defined) {
|
||||
elog(NOTICE, "ProcedureCreate: arg type '%s' is only a shell",
|
||||
strVal(t));
|
||||
}
|
||||
}
|
||||
|
||||
typev[parameterCount++] = toid;
|
||||
}
|
||||
|
||||
tup = SearchSysCacheTuple(PRONAME,
|
||||
PointerGetDatum(procedureName),
|
||||
UInt16GetDatum(parameterCount),
|
||||
PointerGetDatum(typev),
|
||||
0);
|
||||
|
||||
if (HeapTupleIsValid(tup))
|
||||
elog(WARN, "ProcedureCreate: procedure %s already exists with same arguments",
|
||||
procedureName);
|
||||
|
||||
if (!strcmp(languageName, "sql")) {
|
||||
/* If this call is defining a set, check if the set is already
|
||||
* defined by looking to see whether this call's function text
|
||||
* matches a function already in pg_proc. If so just return the
|
||||
* OID of the existing set.
|
||||
*/
|
||||
if (!strcmp(procedureName, GENERICSETNAME)) {
|
||||
prosrctext = textin(prosrc);
|
||||
tup = SearchSysCacheTuple(PROSRC,
|
||||
PointerGetDatum(prosrctext),
|
||||
0,0,0);
|
||||
if (HeapTupleIsValid(tup))
|
||||
return tup->t_oid;
|
||||
}
|
||||
}
|
||||
|
||||
tup = SearchSysCacheTuple(LANNAME,
|
||||
PointerGetDatum(languageName),
|
||||
0,0,0);
|
||||
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(WARN, "ProcedureCreate: no such language %s",
|
||||
languageName);
|
||||
|
||||
languageObjectId = tup->t_oid;
|
||||
|
||||
if (strcmp(returnTypeName, "opaque") == 0) {
|
||||
if (strcmp(languageName, "sql") == 0) {
|
||||
elog(WARN, "ProcedureCreate: sql functions cannot return type \"opaque\"");
|
||||
}
|
||||
typeObjectId = 0;
|
||||
}
|
||||
|
||||
else {
|
||||
typeObjectId = TypeGet(returnTypeName, &defined);
|
||||
|
||||
if (!OidIsValid(typeObjectId)) {
|
||||
elog(NOTICE, "ProcedureCreate: type '%s' is not yet defined",
|
||||
returnTypeName);
|
||||
#if 0
|
||||
elog(NOTICE, "ProcedureCreate: creating a shell for type '%s'",
|
||||
returnTypeName);
|
||||
#endif
|
||||
typeObjectId = TypeShellMake(returnTypeName);
|
||||
if (!OidIsValid(typeObjectId)) {
|
||||
elog(WARN, "ProcedureCreate: could not create type '%s'",
|
||||
returnTypeName);
|
||||
}
|
||||
}
|
||||
|
||||
else if (!defined) {
|
||||
elog(NOTICE, "ProcedureCreate: return type '%s' is only a shell",
|
||||
returnTypeName);
|
||||
}
|
||||
}
|
||||
|
||||
/* don't allow functions of complex types that have the same name as
|
||||
existing attributes of the type */
|
||||
if (parameterCount == 1 &&
|
||||
(toid = TypeGet(strVal(lfirst(argList)), &defined)) &&
|
||||
defined &&
|
||||
(relid = typeid_get_relid(toid)) != 0 &&
|
||||
get_attnum(relid, procedureName) != InvalidAttrNumber)
|
||||
elog(WARN, "method %s already an attribute of type %s",
|
||||
procedureName, strVal(lfirst(argList)));
|
||||
|
||||
|
||||
/*
|
||||
* If this is a postquel procedure, we parse it here in order to
|
||||
* be sure that it contains no syntax errors. We should store
|
||||
* the plan in an Inversion file for use later, but for now, we
|
||||
* just store the procedure's text in the prosrc attribute.
|
||||
*/
|
||||
|
||||
if (strcmp(languageName, "sql") == 0) {
|
||||
plan_list = pg_plan(prosrc, typev, parameterCount,
|
||||
&querytree_list, dest);
|
||||
|
||||
/* typecheck return value */
|
||||
pg_checkretval(typeObjectId, querytree_list);
|
||||
}
|
||||
|
||||
for (i = 0; i < Natts_pg_proc; ++i) {
|
||||
nulls[i] = ' ';
|
||||
values[i] = (Datum)NULL;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
values[i++] = PointerGetDatum(procedureName);
|
||||
values[i++] = Int32GetDatum(GetUserId());
|
||||
values[i++] = ObjectIdGetDatum(languageObjectId);
|
||||
|
||||
/* XXX isinherited is always false for now */
|
||||
|
||||
values[i++] = Int8GetDatum((bool) 0);
|
||||
|
||||
/* XXX istrusted is always false for now */
|
||||
|
||||
values[i++] = Int8GetDatum(trusted);
|
||||
values[i++] = Int8GetDatum(canCache);
|
||||
values[i++] = UInt16GetDatum(parameterCount);
|
||||
values[i++] = Int8GetDatum(returnsSet);
|
||||
values[i++] = ObjectIdGetDatum(typeObjectId);
|
||||
|
||||
values[i++] = (Datum) typev;
|
||||
/*
|
||||
* The following assignments of constants are made. The real values
|
||||
* will have to be extracted from the arglist someday soon.
|
||||
*/
|
||||
values[i++] = Int32GetDatum(byte_pct); /* probyte_pct */
|
||||
values[i++] = Int32GetDatum(perbyte_cpu); /* properbyte_cpu */
|
||||
values[i++] = Int32GetDatum(percall_cpu); /* propercall_cpu */
|
||||
values[i++] = Int32GetDatum(outin_ratio); /* prooutin_ratio */
|
||||
|
||||
values[i++] = (Datum)fmgr(TextInRegProcedure, prosrc); /* prosrc */
|
||||
values[i++] = (Datum)fmgr(TextInRegProcedure, probin); /* probin */
|
||||
|
||||
rdesc = heap_openr(ProcedureRelationName);
|
||||
|
||||
tupDesc = rdesc->rd_att;
|
||||
tup = heap_formtuple(tupDesc,
|
||||
values,
|
||||
nulls);
|
||||
|
||||
heap_insert(rdesc, tup);
|
||||
|
||||
if (RelationGetRelationTupleForm(rdesc)->relhasindex)
|
||||
{
|
||||
Relation idescs[Num_pg_proc_indices];
|
||||
|
||||
CatalogOpenIndices(Num_pg_proc_indices, Name_pg_proc_indices, idescs);
|
||||
CatalogIndexInsert(idescs, Num_pg_proc_indices, rdesc, tup);
|
||||
CatalogCloseIndices(Num_pg_proc_indices, idescs);
|
||||
}
|
||||
heap_close(rdesc);
|
||||
return tup->t_oid;
|
||||
}
|
||||
register i;
|
||||
Relation rdesc;
|
||||
HeapTuple tup;
|
||||
bool defined;
|
||||
uint16 parameterCount;
|
||||
char nulls[Natts_pg_proc];
|
||||
Datum values[Natts_pg_proc];
|
||||
Oid languageObjectId;
|
||||
Oid typeObjectId;
|
||||
List *x;
|
||||
QueryTreeList *querytree_list;
|
||||
List *plan_list;
|
||||
Oid typev[8];
|
||||
Oid relid;
|
||||
Oid toid;
|
||||
text *prosrctext;
|
||||
TupleDesc tupDesc;
|
||||
|
||||
/* ----------------
|
||||
* sanity checks
|
||||
* ----------------
|
||||
*/
|
||||
Assert(PointerIsValid(prosrc));
|
||||
Assert(PointerIsValid(probin));
|
||||
|
||||
parameterCount = 0;
|
||||
memset(typev, 0, 8 * sizeof(Oid));
|
||||
foreach(x, argList)
|
||||
{
|
||||
Value *t = lfirst(x);
|
||||
|
||||
if (parameterCount == 8)
|
||||
elog(WARN, "Procedures cannot take more than 8 arguments");
|
||||
|
||||
if (strcmp(strVal(t), "opaque") == 0)
|
||||
{
|
||||
if (strcmp(languageName, "sql") == 0)
|
||||
{
|
||||
elog(WARN, "ProcedureDefine: sql functions cannot take type \"opaque\"");
|
||||
}
|
||||
toid = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
toid = TypeGet(strVal(t), &defined);
|
||||
|
||||
if (!OidIsValid(toid))
|
||||
{
|
||||
elog(WARN, "ProcedureCreate: arg type '%s' is not defined",
|
||||
strVal(t));
|
||||
}
|
||||
|
||||
if (!defined)
|
||||
{
|
||||
elog(NOTICE, "ProcedureCreate: arg type '%s' is only a shell",
|
||||
strVal(t));
|
||||
}
|
||||
}
|
||||
|
||||
typev[parameterCount++] = toid;
|
||||
}
|
||||
|
||||
tup = SearchSysCacheTuple(PRONAME,
|
||||
PointerGetDatum(procedureName),
|
||||
UInt16GetDatum(parameterCount),
|
||||
PointerGetDatum(typev),
|
||||
0);
|
||||
|
||||
if (HeapTupleIsValid(tup))
|
||||
elog(WARN, "ProcedureCreate: procedure %s already exists with same arguments",
|
||||
procedureName);
|
||||
|
||||
if (!strcmp(languageName, "sql"))
|
||||
{
|
||||
|
||||
/*
|
||||
* If this call is defining a set, check if the set is already
|
||||
* defined by looking to see whether this call's function text
|
||||
* matches a function already in pg_proc. If so just return the
|
||||
* OID of the existing set.
|
||||
*/
|
||||
if (!strcmp(procedureName, GENERICSETNAME))
|
||||
{
|
||||
prosrctext = textin(prosrc);
|
||||
tup = SearchSysCacheTuple(PROSRC,
|
||||
PointerGetDatum(prosrctext),
|
||||
0, 0, 0);
|
||||
if (HeapTupleIsValid(tup))
|
||||
return tup->t_oid;
|
||||
}
|
||||
}
|
||||
|
||||
tup = SearchSysCacheTuple(LANNAME,
|
||||
PointerGetDatum(languageName),
|
||||
0, 0, 0);
|
||||
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(WARN, "ProcedureCreate: no such language %s",
|
||||
languageName);
|
||||
|
||||
languageObjectId = tup->t_oid;
|
||||
|
||||
if (strcmp(returnTypeName, "opaque") == 0)
|
||||
{
|
||||
if (strcmp(languageName, "sql") == 0)
|
||||
{
|
||||
elog(WARN, "ProcedureCreate: sql functions cannot return type \"opaque\"");
|
||||
}
|
||||
typeObjectId = 0;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
typeObjectId = TypeGet(returnTypeName, &defined);
|
||||
|
||||
if (!OidIsValid(typeObjectId))
|
||||
{
|
||||
elog(NOTICE, "ProcedureCreate: type '%s' is not yet defined",
|
||||
returnTypeName);
|
||||
#if 0
|
||||
elog(NOTICE, "ProcedureCreate: creating a shell for type '%s'",
|
||||
returnTypeName);
|
||||
#endif
|
||||
typeObjectId = TypeShellMake(returnTypeName);
|
||||
if (!OidIsValid(typeObjectId))
|
||||
{
|
||||
elog(WARN, "ProcedureCreate: could not create type '%s'",
|
||||
returnTypeName);
|
||||
}
|
||||
}
|
||||
|
||||
else if (!defined)
|
||||
{
|
||||
elog(NOTICE, "ProcedureCreate: return type '%s' is only a shell",
|
||||
returnTypeName);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* don't allow functions of complex types that have the same name as
|
||||
* existing attributes of the type
|
||||
*/
|
||||
if (parameterCount == 1 &&
|
||||
(toid = TypeGet(strVal(lfirst(argList)), &defined)) &&
|
||||
defined &&
|
||||
(relid = typeid_get_relid(toid)) != 0 &&
|
||||
get_attnum(relid, procedureName) != InvalidAttrNumber)
|
||||
elog(WARN, "method %s already an attribute of type %s",
|
||||
procedureName, strVal(lfirst(argList)));
|
||||
|
||||
|
||||
/*
|
||||
* If this is a postquel procedure, we parse it here in order to be
|
||||
* sure that it contains no syntax errors. We should store the plan
|
||||
* in an Inversion file for use later, but for now, we just store the
|
||||
* procedure's text in the prosrc attribute.
|
||||
*/
|
||||
|
||||
if (strcmp(languageName, "sql") == 0)
|
||||
{
|
||||
plan_list = pg_plan(prosrc, typev, parameterCount,
|
||||
&querytree_list, dest);
|
||||
|
||||
/* typecheck return value */
|
||||
pg_checkretval(typeObjectId, querytree_list);
|
||||
}
|
||||
|
||||
for (i = 0; i < Natts_pg_proc; ++i)
|
||||
{
|
||||
nulls[i] = ' ';
|
||||
values[i] = (Datum) NULL;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
values[i++] = PointerGetDatum(procedureName);
|
||||
values[i++] = Int32GetDatum(GetUserId());
|
||||
values[i++] = ObjectIdGetDatum(languageObjectId);
|
||||
|
||||
/* XXX isinherited is always false for now */
|
||||
|
||||
values[i++] = Int8GetDatum((bool) 0);
|
||||
|
||||
/* XXX istrusted is always false for now */
|
||||
|
||||
values[i++] = Int8GetDatum(trusted);
|
||||
values[i++] = Int8GetDatum(canCache);
|
||||
values[i++] = UInt16GetDatum(parameterCount);
|
||||
values[i++] = Int8GetDatum(returnsSet);
|
||||
values[i++] = ObjectIdGetDatum(typeObjectId);
|
||||
|
||||
values[i++] = (Datum) typev;
|
||||
|
||||
/*
|
||||
* The following assignments of constants are made. The real values
|
||||
* will have to be extracted from the arglist someday soon.
|
||||
*/
|
||||
values[i++] = Int32GetDatum(byte_pct); /* probyte_pct */
|
||||
values[i++] = Int32GetDatum(perbyte_cpu); /* properbyte_cpu */
|
||||
values[i++] = Int32GetDatum(percall_cpu); /* propercall_cpu */
|
||||
values[i++] = Int32GetDatum(outin_ratio); /* prooutin_ratio */
|
||||
|
||||
values[i++] = (Datum) fmgr(TextInRegProcedure, prosrc); /* prosrc */
|
||||
values[i++] = (Datum) fmgr(TextInRegProcedure, probin); /* probin */
|
||||
|
||||
rdesc = heap_openr(ProcedureRelationName);
|
||||
|
||||
tupDesc = rdesc->rd_att;
|
||||
tup = heap_formtuple(tupDesc,
|
||||
values,
|
||||
nulls);
|
||||
|
||||
heap_insert(rdesc, tup);
|
||||
|
||||
if (RelationGetRelationTupleForm(rdesc)->relhasindex)
|
||||
{
|
||||
Relation idescs[Num_pg_proc_indices];
|
||||
|
||||
CatalogOpenIndices(Num_pg_proc_indices, Name_pg_proc_indices, idescs);
|
||||
CatalogIndexInsert(idescs, Num_pg_proc_indices, rdesc, tup);
|
||||
CatalogCloseIndices(Num_pg_proc_indices, idescs);
|
||||
}
|
||||
heap_close(rdesc);
|
||||
return tup->t_oid;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user