mirror of
https://github.com/postgres/postgres.git
synced 2025-11-10 17:42:29 +03:00
Further cleanups for relations in schemas: teach nextval and other
sequence functions how to cope with qualified names. Same code is also used for int4notin, currtid_byrelname, pgstattuple. Also, move TOAST tables into special pg_toast namespace.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/not_in.c,v 1.27 2001/10/25 05:49:45 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/not_in.c,v 1.28 2002/03/30 01:02:41 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -25,7 +25,9 @@
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/heapam.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "utils/builtins.h"
|
||||
|
||||
static int my_varattno(Relation rd, char *a);
|
||||
@@ -39,43 +41,39 @@ int4notin(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32 not_in_arg = PG_GETARG_INT32(0);
|
||||
text *relation_and_attr = PG_GETARG_TEXT_P(1);
|
||||
List *names;
|
||||
int nnames;
|
||||
RangeVar *relrv;
|
||||
char *attribute;
|
||||
Relation relation_to_scan;
|
||||
int32 integer_value;
|
||||
HeapTuple current_tuple;
|
||||
HeapScanDesc scan_descriptor;
|
||||
bool isNull,
|
||||
retval;
|
||||
int attrid,
|
||||
strlength;
|
||||
char *relation,
|
||||
*attribute;
|
||||
char my_copy[NAMEDATALEN * 2 + 2];
|
||||
int attrid;
|
||||
Datum value;
|
||||
|
||||
/* make a null-terminated copy of text */
|
||||
strlength = VARSIZE(relation_and_attr) - VARHDRSZ;
|
||||
if (strlength >= sizeof(my_copy))
|
||||
strlength = sizeof(my_copy) - 1;
|
||||
memcpy(my_copy, VARDATA(relation_and_attr), strlength);
|
||||
my_copy[strlength] = '\0';
|
||||
/* Parse the argument */
|
||||
|
||||
relation = (char *) strtok(my_copy, ".");
|
||||
attribute = (char *) strtok(NULL, ".");
|
||||
if (attribute == NULL)
|
||||
names = textToQualifiedNameList(relation_and_attr, "int4notin");
|
||||
nnames = length(names);
|
||||
if (nnames < 2)
|
||||
elog(ERROR, "int4notin: must provide relationname.attributename");
|
||||
attribute = strVal(nth(nnames-1, names));
|
||||
names = ltruncate(nnames-1, names);
|
||||
relrv = makeRangeVarFromNameList(names);
|
||||
|
||||
/* Open the relation and get a relation descriptor */
|
||||
|
||||
relation_to_scan = heap_openr(relation, AccessShareLock);
|
||||
relation_to_scan = heap_openrv(relrv, AccessShareLock);
|
||||
|
||||
/* Find the column to search */
|
||||
|
||||
attrid = my_varattno(relation_to_scan, attribute);
|
||||
if (attrid < 0)
|
||||
{
|
||||
elog(ERROR, "int4notin: unknown attribute %s for relation %s",
|
||||
attribute, relation);
|
||||
}
|
||||
attribute, RelationGetRelationName(relation_to_scan));
|
||||
|
||||
scan_descriptor = heap_beginscan(relation_to_scan, false, SnapshotNow,
|
||||
0, (ScanKey) NULL);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/tid.c,v 1.28 2001/10/25 05:49:45 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/tid.c,v 1.29 2002/03/30 01:02:41 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* input routine largely stolen from boxin().
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/heapam.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "utils/builtins.h"
|
||||
|
||||
#define DatumGetItemPointer(X) ((ItemPointer) DatumGetPointer(X))
|
||||
@@ -146,14 +147,13 @@ currtid_byreloid(PG_FUNCTION_ARGS)
|
||||
*result = Current_last_tid;
|
||||
PG_RETURN_ITEMPOINTER(result);
|
||||
}
|
||||
|
||||
rel = heap_open(reloid, AccessShareLock);
|
||||
|
||||
ItemPointerCopy(tid, result);
|
||||
if ((rel = heap_open(reloid, AccessShareLock)) != NULL)
|
||||
{
|
||||
heap_get_latest_tid(rel, SnapshotNow, result);
|
||||
heap_close(rel, AccessShareLock);
|
||||
}
|
||||
else
|
||||
elog(ERROR, "Relation %u not found", reloid);
|
||||
heap_get_latest_tid(rel, SnapshotNow, result);
|
||||
|
||||
heap_close(rel, AccessShareLock);
|
||||
|
||||
PG_RETURN_ITEMPOINTER(result);
|
||||
}
|
||||
@@ -164,23 +164,19 @@ currtid_byrelname(PG_FUNCTION_ARGS)
|
||||
text *relname = PG_GETARG_TEXT_P(0);
|
||||
ItemPointer tid = PG_GETARG_ITEMPOINTER(1);
|
||||
ItemPointer result;
|
||||
char *str;
|
||||
RangeVar *relrv;
|
||||
Relation rel;
|
||||
|
||||
str = DatumGetCString(DirectFunctionCall1(textout,
|
||||
PointerGetDatum(relname)));
|
||||
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname,
|
||||
"currtid_byrelname"));
|
||||
rel = heap_openrv(relrv, AccessShareLock);
|
||||
|
||||
result = (ItemPointer) palloc(sizeof(ItemPointerData));
|
||||
ItemPointerCopy(tid, result);
|
||||
if ((rel = heap_openr(str, AccessShareLock)) != NULL)
|
||||
{
|
||||
heap_get_latest_tid(rel, SnapshotNow, result);
|
||||
heap_close(rel, AccessShareLock);
|
||||
}
|
||||
else
|
||||
elog(ERROR, "Relation %s not found", str);
|
||||
|
||||
pfree(str);
|
||||
heap_get_latest_tid(rel, SnapshotNow, result);
|
||||
|
||||
heap_close(rel, AccessShareLock);
|
||||
|
||||
PG_RETURN_ITEMPOINTER(result);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.79 2002/03/05 05:33:19 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.80 2002/03/30 01:02:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1039,6 +1039,122 @@ name_text(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* textToQualifiedNameList - convert a text object to list of names
|
||||
*
|
||||
* This implements the input parsing needed by nextval() and other
|
||||
* functions that take a text parameter representing a qualified name.
|
||||
* We split the name at dots, downcase if not double-quoted, and
|
||||
* truncate names if they're too long.
|
||||
*
|
||||
* This is a kluge, really, and exists only for historical reasons.
|
||||
* A better notation for such functions would be nextval(relname).
|
||||
*/
|
||||
List *
|
||||
textToQualifiedNameList(text *textval, const char *caller)
|
||||
{
|
||||
char *rawname;
|
||||
char *nextp;
|
||||
List *result = NIL;
|
||||
|
||||
/* Convert to C string (handles possible detoasting). */
|
||||
/* Note we rely on being able to modify rawname below. */
|
||||
rawname = DatumGetCString(DirectFunctionCall1(textout,
|
||||
PointerGetDatum(textval)));
|
||||
nextp = rawname;
|
||||
|
||||
do
|
||||
{
|
||||
char *curname;
|
||||
char *endp;
|
||||
char *cp;
|
||||
int curlen;
|
||||
|
||||
if (*nextp == '\"')
|
||||
{
|
||||
/* Quoted name --- collapse quote-quote pairs, no downcasing */
|
||||
curname = nextp + 1;
|
||||
for (;;)
|
||||
{
|
||||
endp = strchr(nextp + 1, '\"');
|
||||
if (endp == NULL)
|
||||
elog(ERROR, "%s: invalid quoted name: mismatched quotes",
|
||||
caller);
|
||||
if (endp[1] != '\"')
|
||||
break; /* found end of quoted name */
|
||||
/* Collapse adjacent quotes into one quote, and look again */
|
||||
memmove(endp, endp+1, strlen(endp));
|
||||
nextp = endp;
|
||||
}
|
||||
*endp = '\0';
|
||||
nextp = endp + 1;
|
||||
if (*nextp)
|
||||
{
|
||||
if (*nextp != '.')
|
||||
elog(ERROR, "%s: invalid name syntax",
|
||||
caller);
|
||||
nextp++;
|
||||
if (*nextp == '\0')
|
||||
elog(ERROR, "%s: invalid name syntax",
|
||||
caller);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unquoted name --- extends to next dot */
|
||||
if (*nextp == '\0') /* empty name not okay here */
|
||||
elog(ERROR, "%s: invalid name syntax",
|
||||
caller);
|
||||
curname = nextp;
|
||||
endp = strchr(nextp, '.');
|
||||
if (endp)
|
||||
{
|
||||
*endp = '\0';
|
||||
nextp = endp + 1;
|
||||
if (*nextp == '\0')
|
||||
elog(ERROR, "%s: invalid name syntax",
|
||||
caller);
|
||||
}
|
||||
else
|
||||
nextp = nextp + strlen(nextp);
|
||||
/*
|
||||
* It's important that this match the identifier downcasing code
|
||||
* used by backend/parser/scan.l.
|
||||
*/
|
||||
for (cp = curname; *cp; cp++)
|
||||
{
|
||||
if (isupper((unsigned char) *cp))
|
||||
*cp = tolower((unsigned char) *cp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Truncate name if it's overlength; again, should match scan.l */
|
||||
curlen = strlen(curname);
|
||||
if (curlen >= NAMEDATALEN)
|
||||
{
|
||||
#ifdef MULTIBYTE
|
||||
curlen = pg_mbcliplen(curname, curlen, NAMEDATALEN - 1);
|
||||
curname[curlen] = '\0';
|
||||
#else
|
||||
curname[NAMEDATALEN - 1] = '\0';
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Finished isolating current name --- add it to list
|
||||
*/
|
||||
result = lappend(result, makeString(pstrdup(curname)));
|
||||
/*
|
||||
* Loop back if we found a dot
|
||||
*/
|
||||
} while (*nextp);
|
||||
|
||||
pfree(rawname);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* Comparison Functions used for bytea
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user