1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-07 00:36:50 +03:00

Massive commit to run PGINDENT on all *.c and *.h files.

This commit is contained in:
Bruce Momjian
1997-09-07 05:04:48 +00:00
parent 8fecd4febf
commit 1ccd423235
687 changed files with 150775 additions and 136888 deletions

View File

@ -1,23 +1,23 @@
/*-------------------------------------------------------------------------
*
* version.c--
* This file contains all the rules that govern all version semantics.
* This file contains all the rules that govern all version semantics.
*
* Copyright (c) 1994, Regents of the University of California
*
* The version stuff has not been tested under postgres95 and probably doesn't
* work! - jolly 8/19/95
*
* The version stuff has not been tested under postgres95 and probably doesn't
* work! - jolly 8/19/95
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/_deadcode/Attic/version.c,v 1.5 1997/08/19 21:30:47 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/_deadcode/Attic/version.c,v 1.6 1997/09/07 04:41:04 momjian Exp $
*
* NOTES
* At the point the version is defined, 2 physical relations are created
* <vname>_added and <vname>_deleted.
* At the point the version is defined, 2 physical relations are created
* <vname>_added and <vname>_deleted.
*
* In addition, 4 rules are defined which govern the semantics of versions
* w.r.t retrieves, appends, replaces and deletes.
* In addition, 4 rules are defined which govern the semantics of versions
* w.r.t retrieves, appends, replaces and deletes.
*
*-------------------------------------------------------------------------
*/
@ -34,29 +34,31 @@
#define MAX_QUERY_LEN 1024
char rule_buf[MAX_QUERY_LEN];
char rule_buf[MAX_QUERY_LEN];
#ifdef NOT_USED
static char attr_list[MAX_QUERY_LEN];
static char attr_list[MAX_QUERY_LEN];
#endif
/*
* problem: the version system assumes that the rules it declares will
* be fired in the order of declaration, it also assumes
* goh's silly instead semantics. Unfortunately, it is a pain
* to make the version system work with the new semantics.
* However the whole problem can be solved, and some nice
* functionality can be achieved if we get multiple action rules
* to work. So thats what I did -- glass
* be fired in the order of declaration, it also assumes
* goh's silly instead semantics. Unfortunately, it is a pain
* to make the version system work with the new semantics.
* However the whole problem can be solved, and some nice
* functionality can be achieved if we get multiple action rules
* to work. So thats what I did -- glass
*
* Well, at least they've been working for about 20 minutes.
*
*
* So any comments in this code about 1 rule per transction are false...:)
*
*/
/*
* This is needed because the rule system only allows
* *1* rule to be defined per transaction.
* This is needed because the rule system only allows
* *1* rule to be defined per transaction.
*
* NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
* OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
@ -80,267 +82,282 @@ static char attr_list[MAX_QUERY_LEN];
* a strange memory bug instead of watching the "Get Smart" marathon
* in NICK !
* DO NOT COMMIT THE XACT, just increase the Cid counter!
* _sp.
* _sp.
*/
#ifdef NOT_USED
static void
eval_as_new_xact(char *query)
{
/* WARNING! do not uncomment the following lines WARNING!
* CommitTransactionCommand();
* StartTransactionCommand();
*/
CommandCounterIncrement();
pg_eval(query, (char **) NULL, (Oid *) NULL, 0);
/*
* WARNING! do not uncomment the following lines WARNING!
* CommitTransactionCommand(); StartTransactionCommand();
*/
CommandCounterIncrement();
pg_eval(query, (char **) NULL, (Oid *) NULL, 0);
}
#endif
/*
* Define a version.
* Define a version.
*/
#ifdef NOT_USED
void
DefineVersion(char *name, char *fromRelname, char *date)
{
char *bname;
static char saved_basename[512];
static char saved_snapshot[512];
char *bname;
static char saved_basename[512];
static char saved_snapshot[512];
if (date == NULL) {
/* no time ranges */
bname = fromRelname;
strcpy(saved_basename, (char *) bname);
*saved_snapshot = (char)NULL;
} else {
/* version is a snapshot */
bname = fromRelname;
strcpy(saved_basename, (char *) bname);
sprintf(saved_snapshot, "['%s']", date);
}
/*
* Calls the routine ``GetAttrList'' get the list of attributes
* from the base relation.
* Code is put here so that we only need to look up the attribute once for
* both appends and replaces.
*/
setAttrList(bname);
if (date == NULL)
{
/* no time ranges */
bname = fromRelname;
strcpy(saved_basename, (char *) bname);
*saved_snapshot = (char) NULL;
}
else
{
/* version is a snapshot */
bname = fromRelname;
strcpy(saved_basename, (char *) bname);
sprintf(saved_snapshot, "['%s']", date);
}
VersionCreate (name, saved_basename);
VersionAppend (name, saved_basename);
VersionDelete (name, saved_basename,saved_snapshot);
VersionReplace (name, saved_basename,saved_snapshot);
VersionRetrieve (name, saved_basename, saved_snapshot);
/*
* Calls the routine ``GetAttrList'' get the list of attributes from
* the base relation. Code is put here so that we only need to look up
* the attribute once for both appends and replaces.
*/
setAttrList(bname);
VersionCreate(name, saved_basename);
VersionAppend(name, saved_basename);
VersionDelete(name, saved_basename, saved_snapshot);
VersionReplace(name, saved_basename, saved_snapshot);
VersionRetrieve(name, saved_basename, saved_snapshot);
}
#endif
/*
* Creates the deltas.
* Creates the deltas.
*/
#ifdef NOT_USED
void
VersionCreate(char *vname, char *bname)
{
static char query_buf [MAX_QUERY_LEN];
/*
* Creating the dummy version relation for triggering rules.
*/
sprintf(query_buf, "SELECT * INTO TABLE %s from %s where 1 =2",
vname, bname);
pg_eval (query_buf, (char **) NULL, (Oid *) NULL, 0);
/*
* Creating the ``v_added'' relation
*/
sprintf (query_buf, "SELECT * INTO TABLE %s_added from %s where 1 = 2",
vname, bname);
eval_as_new_xact (query_buf);
/*
* Creating the ``v_deleted'' relation.
*/
sprintf (query_buf, "CREATE TABLE %s_del (DOID oid)", vname);
eval_as_new_xact (query_buf);
static char query_buf[MAX_QUERY_LEN];
/*
* Creating the dummy version relation for triggering rules.
*/
sprintf(query_buf, "SELECT * INTO TABLE %s from %s where 1 =2",
vname, bname);
pg_eval(query_buf, (char **) NULL, (Oid *) NULL, 0);
/*
* Creating the ``v_added'' relation
*/
sprintf(query_buf, "SELECT * INTO TABLE %s_added from %s where 1 = 2",
vname, bname);
eval_as_new_xact(query_buf);
/*
* Creating the ``v_deleted'' relation.
*/
sprintf(query_buf, "CREATE TABLE %s_del (DOID oid)", vname);
eval_as_new_xact(query_buf);
}
#endif
/*
* Given the relation name, does a catalog lookup for that relation and
* sets the global variable 'attr_list' with the list of attributes (names)
* for that relation.
* for that relation.
*/
#ifdef NOT_USED
static void
setAttrList(char *bname)
{
Relation rdesc;
int i = 0;
int maxattrs = 0;
char *attrname;
char temp_buf[512];
int notfirst = 0;
Relation rdesc;
int i = 0;
int maxattrs = 0;
char *attrname;
char temp_buf[512];
int notfirst = 0;
rdesc = heap_openr(bname);
if (rdesc == NULL ) {
elog(WARN,"Unable to expand all -- amopenr failed ");
return;
}
maxattrs = RelationGetNumberOfAttributes(rdesc);
attr_list[0] = '\0';
for ( i = maxattrs-1 ; i > -1 ; --i ) {
attrname = (rdesc->rd_att->attrs[i]->attname).data;
if (notfirst == 1) {
sprintf(temp_buf, ", %s = new.%s", attrname, attrname);
} else {
sprintf(temp_buf, "%s = new.%s", attrname, attrname);
notfirst = 1;
rdesc = heap_openr(bname);
if (rdesc == NULL)
{
elog(WARN, "Unable to expand all -- amopenr failed ");
return;
}
strcat(attr_list, temp_buf);
}
heap_close(rdesc);
return;
maxattrs = RelationGetNumberOfAttributes(rdesc);
attr_list[0] = '\0';
for (i = maxattrs - 1; i > -1; --i)
{
attrname = (rdesc->rd_att->attrs[i]->attname).data;
if (notfirst == 1)
{
sprintf(temp_buf, ", %s = new.%s", attrname, attrname);
}
else
{
sprintf(temp_buf, "%s = new.%s", attrname, attrname);
notfirst = 1;
}
strcat(attr_list, temp_buf);
}
heap_close(rdesc);
return;
}
#endif
/*
* This routine defines the rule governing the append semantics of
* versions. All tuples appended to a version gets appended to the
* versions. All tuples appended to a version gets appended to the
* <vname>_added relation.
*/
#ifdef NOT_USED
static void
VersionAppend(char *vname, char *bname)
{
sprintf(rule_buf,
"define rewrite rule %s_append is on INSERT to %s do instead append %s_added(%s)",
vname, vname, vname, attr_list);
eval_as_new_xact(rule_buf);
sprintf(rule_buf,
"define rewrite rule %s_append is on INSERT to %s do instead append %s_added(%s)",
vname, vname, vname, attr_list);
eval_as_new_xact(rule_buf);
}
#endif
/*
* This routine defines the rule governing the retrieval semantics of
* versions. To retrieve tuples from a version , we need to:
*
* 1. Retrieve all tuples in the <vname>_added relation.
* 2. Retrieve all tuples in the base relation which are not in
* the <vname>_del relation.
* 1. Retrieve all tuples in the <vname>_added relation.
* 2. Retrieve all tuples in the base relation which are not in
* the <vname>_del relation.
*/
#ifdef NOT_USED
void
VersionRetrieve(char *vname, char *bname, char *snapshot)
{
sprintf(rule_buf,
"define rewrite rule %s_retrieve is on SELECT to %s do instead\n\
sprintf(rule_buf,
"define rewrite rule %s_retrieve is on SELECT to %s do instead\n\
SELECT %s_1.oid, %s_1.* from _%s in %s%s, %s_1 in (%s_added | _%s) \
where _%s.oid !!= '%s_del.DOID'",
vname, vname, vname, vname, bname,
bname, snapshot,
vname, vname, bname, bname, vname);
eval_as_new_xact(rule_buf);
/* printf("%s\n",rule_buf); */
vname, vname, vname, vname, bname,
bname, snapshot,
vname, vname, bname, bname, vname);
eval_as_new_xact(rule_buf);
/* printf("%s\n",rule_buf); */
}
#endif
/*
* This routine defines the rules that govern the delete semantics of
* This routine defines the rules that govern the delete semantics of
* versions. Two things happens when we delete a tuple from a version:
*
* 1. If the tuple to be deleted was added to the version *after*
* the version was created, then we simply delete the tuple
* from the <vname>_added relation.
* 2. If the tuple to be deleted is actually in the base relation,
* then we have to mark that tuple as being deleted by adding
* it to the <vname>_del relation.
* 1. If the tuple to be deleted was added to the version *after*
* the version was created, then we simply delete the tuple
* from the <vname>_added relation.
* 2. If the tuple to be deleted is actually in the base relation,
* then we have to mark that tuple as being deleted by adding
* it to the <vname>_del relation.
*/
#ifdef NOT_USED
void
VersionDelete(char *vname, char *bname, char *snapshot)
{
sprintf(rule_buf,
"define rewrite rule %s_delete1 is on delete to %s do instead\n \
sprintf(rule_buf,
"define rewrite rule %s_delete1 is on delete to %s do instead\n \
[delete %s_added where current.oid = %s_added.oid\n \
append %s_del(DOID = current.oid) from _%s in %s%s \
where current.oid = _%s.oid] \n",
vname,vname,vname,vname,vname,
bname,bname,snapshot,bname);
vname, vname, vname, vname, vname,
bname, bname, snapshot, bname);
eval_as_new_xact(rule_buf);
eval_as_new_xact(rule_buf);
#ifdef OLD_REWRITE
sprintf(rule_buf,
"define rewrite rule %s_delete2 is on delete to %s do instead \n \
sprintf(rule_buf,
"define rewrite rule %s_delete2 is on delete to %s do instead \n \
append %s_del(DOID = current.oid) from _%s in %s%s \
where current.oid = _%s.oid \n",
vname,vname,vname,bname,bname,snapshot,bname);
vname, vname, vname, bname, bname, snapshot, bname);
eval_as_new_xact(rule_buf);
#endif /* OLD_REWRITE */
eval_as_new_xact(rule_buf);
#endif /* OLD_REWRITE */
}
#endif
/*
* This routine defines the rules that govern the update semantics
* of versions. To update a tuple in a version:
* This routine defines the rules that govern the update semantics
* of versions. To update a tuple in a version:
*
* 1. If the tuple is in <vname>_added, we simply ``replace''
* the tuple (as per postgres style).
* 2. if the tuple is in the base relation, then two things have to
* happen:
* 2.1 The tuple is marked ``deleted'' from the base relation by
* adding the tuple to the <vname>_del relation.
* 2.2 A copy of the tuple is appended to the <vname>_added relation
* 1. If the tuple is in <vname>_added, we simply ``replace''
* the tuple (as per postgres style).
* 2. if the tuple is in the base relation, then two things have to
* happen:
* 2.1 The tuple is marked ``deleted'' from the base relation by
* adding the tuple to the <vname>_del relation.
* 2.2 A copy of the tuple is appended to the <vname>_added relation
*/
#ifdef NOT_USED
void
VersionReplace(char *vname, char *bname, char *snapshot)
{
sprintf(rule_buf,
"define rewrite rule %s_replace1 is on replace to %s do instead \n\
sprintf(rule_buf,
"define rewrite rule %s_replace1 is on replace to %s do instead \n\
[replace %s_added(%s) where current.oid = %s_added.oid \n\
append %s_del(DOID = current.oid) from _%s in %s%s \
where current.oid = _%s.oid\n\
append %s_added(%s) from _%s in %s%s \
where current.oid !!= '%s_added.oid' and current.oid = _%s.oid]\n",
vname,vname,vname,attr_list,vname,
vname,bname,bname,snapshot,bname,
vname,attr_list,bname,bname,snapshot,vname,bname);
vname, vname, vname, attr_list, vname,
vname, bname, bname, snapshot, bname,
vname, attr_list, bname, bname, snapshot, vname, bname);
eval_as_new_xact(rule_buf);
eval_as_new_xact(rule_buf);
/* printf("%s\n",rule_buf); */
/* printf("%s\n",rule_buf); */
#ifdef OLD_REWRITE
sprintf(rule_buf,
"define rewrite rule %s_replace2 is on replace to %s do \n\
sprintf(rule_buf,
"define rewrite rule %s_replace2 is on replace to %s do \n\
append %s_del(DOID = current.oid) from _%s in %s%s \
where current.oid = _%s.oid\n",
vname,vname,vname,bname,bname,snapshot,bname);
vname, vname, vname, bname, bname, snapshot, bname);
eval_as_new_xact(rule_buf);
eval_as_new_xact(rule_buf);
sprintf(rule_buf,
"define rewrite rule %s_replace3 is on replace to %s do instead\n\
sprintf(rule_buf,
"define rewrite rule %s_replace3 is on replace to %s do instead\n\
append %s_added(%s) from _%s in %s%s \
where current.oid !!= '%s_added.oid' and current.oid = \
_%s.oid\n",
vname,vname, vname,attr_list,bname,bname,snapshot,vname,bname);
vname, vname, vname, attr_list, bname, bname, snapshot, vname, bname);
eval_as_new_xact(rule_buf);
#endif /* OLD_REWRITE */
/* printf("%s\n",rule_buf); */
eval_as_new_xact(rule_buf);
#endif /* OLD_REWRITE */
/* printf("%s\n",rule_buf); */
}

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,20 @@
/*-------------------------------------------------------------------------
*
* cluster.c--
* Paul Brown's implementation of cluster index.
* Paul Brown's implementation of cluster index.
*
* I am going to use the rename function as a model for this in the
* parser and executor, and the vacuum code as an example in this
* file. As I go - in contrast to the rest of postgres - there will
* be BUCKETS of comments. This is to allow reviewers to understand
* my (probably bogus) assumptions about the way this works.
* [pbrown '94]
* I am going to use the rename function as a model for this in the
* parser and executor, and the vacuum code as an example in this
* file. As I go - in contrast to the rest of postgres - there will
* be BUCKETS of comments. This is to allow reviewers to understand
* my (probably bogus) assumptions about the way this works.
* [pbrown '94]
*
* Copyright (c) 1994-5, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.13 1997/08/19 21:30:45 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.14 1997/09/07 04:40:36 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -47,307 +47,323 @@
#include <optimizer/internal.h>
#ifndef NO_SECURITY
#include <utils/acl.h>
#endif /* !NO_SECURITY */
#endif /* !NO_SECURITY */
static Relation copy_heap(Oid OIDOldHeap);
static void copy_index(Oid OIDOldIndex, Oid OIDNewHeap);
static void rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex);
static void copy_index(Oid OIDOldIndex, Oid OIDNewHeap);
static void rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex);
/*
* cluster
*
* Check that the relation is a relation in the appropriate user
* ACL. I will use the same security that limits users on the
* renamerel() function.
* Check that the relation is a relation in the appropriate user
* ACL. I will use the same security that limits users on the
* renamerel() function.
*
* Check that the index specified is appropriate for the task
* ( ie it's an index over this relation ). This is trickier.
* Check that the index specified is appropriate for the task
* ( ie it's an index over this relation ). This is trickier.
*
* Create a list of all the other indicies on this relation. Because
* the cluster will wreck all the tids, I'll need to destroy bogus
* indicies. The user will have to re-create them. Not nice, but
* I'm not a nice guy. The alternative is to try some kind of post
* destroy re-build. This may be possible. I'll check out what the
* index create functiond want in the way of paramaters. On the other
* hand, re-creating n indicies may blow out the space.
* Create a list of all the other indicies on this relation. Because
* the cluster will wreck all the tids, I'll need to destroy bogus
* indicies. The user will have to re-create them. Not nice, but
* I'm not a nice guy. The alternative is to try some kind of post
* destroy re-build. This may be possible. I'll check out what the
* index create functiond want in the way of paramaters. On the other
* hand, re-creating n indicies may blow out the space.
*
* Create new (temporary) relations for the base heap and the new
* index.
*
* Exclusively lock the relations.
*
* Create new clustered index and base heap relation.
* Create new (temporary) relations for the base heap and the new
* index.
*
* Exclusively lock the relations.
*
* Create new clustered index and base heap relation.
*
*/
void
cluster(char oldrelname[], char oldindexname[])
{
Oid OIDOldHeap, OIDOldIndex, OIDNewHeap;
Relation OldHeap, OldIndex;
Relation NewHeap;
char NewIndexName[NAMEDATALEN];
char NewHeapName[NAMEDATALEN];
char saveoldrelname[NAMEDATALEN];
char saveoldindexname[NAMEDATALEN];
Oid OIDOldHeap,
OIDOldIndex,
OIDNewHeap;
Relation OldHeap,
OldIndex;
Relation NewHeap;
char NewIndexName[NAMEDATALEN];
char NewHeapName[NAMEDATALEN];
char saveoldrelname[NAMEDATALEN];
char saveoldindexname[NAMEDATALEN];
/* Save the old names because they will get lost when the old relations
* are destroyed.
*/
strcpy(saveoldrelname, oldrelname);
strcpy(saveoldindexname, oldindexname);
/*
*
* I'm going to force all checking back into the commands.c function.
*
* Get the list if indicies for this relation. If the index we want
* is among them, do not add it to the 'kill' list, as it will be
* handled by the 'clean up' code which commits this transaction.
*
* I'm not using the SysCache, because this will happen but
* once, and the slow way is the sure way in this case.
*
*/
/*
* Like vacuum, cluster spans transactions, so I'm going to handle it in
* the same way.
*/
/* matches the StartTransaction in PostgresMain() */
OldHeap = heap_openr(oldrelname);
if (!RelationIsValid(OldHeap)) {
elog(WARN, "cluster: unknown relation: \"%s\"",
oldrelname);
}
OIDOldHeap = OldHeap->rd_id; /* Get OID for the index scan */
OldIndex=index_openr(oldindexname);/* Open old index relation */
if (!RelationIsValid(OldIndex)) {
elog(WARN, "cluster: unknown index: \"%s\"",
oldindexname);
}
OIDOldIndex = OldIndex->rd_id; /* OID for the index scan */
heap_close(OldHeap);
index_close(OldIndex);
/*
* I need to build the copies of the heap and the index. The Commit()
* between here is *very* bogus. If someone is appending stuff, they will
* get the lock after being blocked and add rows which won't be present in
* the new table. Bleagh! I'd be best to try and ensure that no-one's
* in the tables for the entire duration of this process with a pg_vlock.
*/
NewHeap = copy_heap(OIDOldHeap);
OIDNewHeap = NewHeap->rd_id;
strcpy(NewHeapName,NewHeap->rd_rel->relname.data);
/*
* Save the old names because they will get lost when the old
* relations are destroyed.
*/
strcpy(saveoldrelname, oldrelname);
strcpy(saveoldindexname, oldindexname);
/*
* I'm going to force all checking back into the commands.c function.
*
* Get the list if indicies for this relation. If the index we want is
* among them, do not add it to the 'kill' list, as it will be handled
* by the 'clean up' code which commits this transaction.
*
* I'm not using the SysCache, because this will happen but once, and the
* slow way is the sure way in this case.
*
*/
/*
* Like vacuum, cluster spans transactions, so I'm going to handle it
* in the same way.
*/
/* matches the StartTransaction in PostgresMain() */
OldHeap = heap_openr(oldrelname);
if (!RelationIsValid(OldHeap))
{
elog(WARN, "cluster: unknown relation: \"%s\"",
oldrelname);
}
OIDOldHeap = OldHeap->rd_id;/* Get OID for the index scan */
OldIndex = index_openr(oldindexname); /* Open old index relation */
if (!RelationIsValid(OldIndex))
{
elog(WARN, "cluster: unknown index: \"%s\"",
oldindexname);
}
OIDOldIndex = OldIndex->rd_id; /* OID for the index scan */
heap_close(OldHeap);
index_close(OldIndex);
/*
* I need to build the copies of the heap and the index. The Commit()
* between here is *very* bogus. If someone is appending stuff, they
* will get the lock after being blocked and add rows which won't be
* present in the new table. Bleagh! I'd be best to try and ensure
* that no-one's in the tables for the entire duration of this process
* with a pg_vlock.
*/
NewHeap = copy_heap(OIDOldHeap);
OIDNewHeap = NewHeap->rd_id;
strcpy(NewHeapName, NewHeap->rd_rel->relname.data);
/* To make the new heap visible (which is until now empty). */
CommandCounterIncrement();
rebuildheap(OIDNewHeap, OIDOldHeap, OIDOldIndex);
/* To flush the filled new heap (and the statistics about it). */
CommandCounterIncrement();
/* To make the new heap visible (which is until now empty). */
CommandCounterIncrement();
/* Create new index over the tuples of the new heap. */
copy_index(OIDOldIndex, OIDNewHeap);
sprintf(NewIndexName, "temp_%x", OIDOldIndex);
/*
* make this really happen. Flush all the buffers.
* (Believe me, it is necessary ... ended up in a mess without it.)
*/
CommitTransactionCommand();
StartTransactionCommand();
rebuildheap(OIDNewHeap, OIDOldHeap, OIDOldIndex);
/* To flush the filled new heap (and the statistics about it). */
CommandCounterIncrement();
/* Create new index over the tuples of the new heap. */
copy_index(OIDOldIndex, OIDNewHeap);
sprintf(NewIndexName, "temp_%x", OIDOldIndex);
/*
* make this really happen. Flush all the buffers. (Believe me, it is
* necessary ... ended up in a mess without it.)
*/
CommitTransactionCommand();
StartTransactionCommand();
/* Destroy old heap (along with its index) and rename new. */
heap_destroy(oldrelname);
renamerel(NewHeapName, saveoldrelname);
TypeRename(NewHeapName, saveoldrelname);
/* Destroy old heap (along with its index) and rename new. */
heap_destroy(oldrelname);
renamerel(NewIndexName, saveoldindexname);
renamerel(NewHeapName, saveoldrelname);
TypeRename(NewHeapName, saveoldrelname);
/*
* Again flush all the buffers.
*/
CommitTransactionCommand();
StartTransactionCommand();
renamerel(NewIndexName, saveoldindexname);
/*
* Again flush all the buffers.
*/
CommitTransactionCommand();
StartTransactionCommand();
}
static Relation
static Relation
copy_heap(Oid OIDOldHeap)
{
char NewName[NAMEDATALEN];
TupleDesc OldHeapDesc, tupdesc;
Oid OIDNewHeap;
Relation NewHeap, OldHeap;
char NewName[NAMEDATALEN];
TupleDesc OldHeapDesc,
tupdesc;
Oid OIDNewHeap;
Relation NewHeap,
OldHeap;
/*
* Create a new heap relation with a temporary name, which has the
* same tuple description as the old one.
*/
sprintf(NewName,"temp_%x", OIDOldHeap);
/*
* Create a new heap relation with a temporary name, which has the
* same tuple description as the old one.
*/
sprintf(NewName, "temp_%x", OIDOldHeap);
OldHeap= heap_open(OIDOldHeap);
OldHeapDesc= RelationGetTupleDescriptor(OldHeap);
OldHeap = heap_open(OIDOldHeap);
OldHeapDesc = RelationGetTupleDescriptor(OldHeap);
/*
* Need to make a copy of the tuple descriptor, heap_create modifies
* it.
*/
/*
* Need to make a copy of the tuple descriptor, heap_create modifies
* it.
*/
tupdesc = CreateTupleDescCopy(OldHeapDesc);
OIDNewHeap=heap_create(NewName,
NULL,
OldHeap->rd_rel->relarch,
OldHeap->rd_rel->relsmgr,
tupdesc);
tupdesc = CreateTupleDescCopy(OldHeapDesc);
if (!OidIsValid(OIDNewHeap))
elog(WARN,"clusterheap: cannot create temporary heap relation\n");
OIDNewHeap = heap_create(NewName,
NULL,
OldHeap->rd_rel->relarch,
OldHeap->rd_rel->relsmgr,
tupdesc);
NewHeap=heap_open(OIDNewHeap);
if (!OidIsValid(OIDNewHeap))
elog(WARN, "clusterheap: cannot create temporary heap relation\n");
heap_close(NewHeap);
heap_close(OldHeap);
NewHeap = heap_open(OIDNewHeap);
return NewHeap;
heap_close(NewHeap);
heap_close(OldHeap);
return NewHeap;
}
static void
copy_index(Oid OIDOldIndex, Oid OIDNewHeap)
{
Relation OldIndex, NewHeap;
HeapTuple Old_pg_index_Tuple, Old_pg_index_relation_Tuple, pg_proc_Tuple;
IndexTupleForm Old_pg_index_Form;
Form_pg_class Old_pg_index_relation_Form;
Form_pg_proc pg_proc_Form;
char *NewIndexName;
AttrNumber *attnumP;
int natts;
FuncIndexInfo * finfo;
Relation OldIndex,
NewHeap;
HeapTuple Old_pg_index_Tuple,
Old_pg_index_relation_Tuple,
pg_proc_Tuple;
IndexTupleForm Old_pg_index_Form;
Form_pg_class Old_pg_index_relation_Form;
Form_pg_proc pg_proc_Form;
char *NewIndexName;
AttrNumber *attnumP;
int natts;
FuncIndexInfo *finfo;
NewHeap = heap_open(OIDNewHeap);
OldIndex = index_open(OIDOldIndex);
NewHeap = heap_open(OIDNewHeap);
OldIndex = index_open(OIDOldIndex);
/*
* OK. Create a new (temporary) index for the one that's already
* here. To do this I get the info from pg_index, re-build the
* FunctInfo if I have to, and add a new index with a temporary
* name.
*/
Old_pg_index_Tuple =
SearchSysCacheTuple(INDEXRELID,
ObjectIdGetDatum(OldIndex->rd_id),
0,0,0);
/*
* OK. Create a new (temporary) index for the one that's already here.
* To do this I get the info from pg_index, re-build the FunctInfo if
* I have to, and add a new index with a temporary name.
*/
Old_pg_index_Tuple =
SearchSysCacheTuple(INDEXRELID,
ObjectIdGetDatum(OldIndex->rd_id),
0, 0, 0);
Assert(Old_pg_index_Tuple);
Old_pg_index_Form = (IndexTupleForm)GETSTRUCT(Old_pg_index_Tuple);
Assert(Old_pg_index_Tuple);
Old_pg_index_Form = (IndexTupleForm) GETSTRUCT(Old_pg_index_Tuple);
Old_pg_index_relation_Tuple =
SearchSysCacheTuple(RELOID,
ObjectIdGetDatum(OldIndex->rd_id),
0,0,0);
Old_pg_index_relation_Tuple =
SearchSysCacheTuple(RELOID,
ObjectIdGetDatum(OldIndex->rd_id),
0, 0, 0);
Assert(Old_pg_index_relation_Tuple);
Old_pg_index_relation_Form =
(Form_pg_class)GETSTRUCT(Old_pg_index_relation_Tuple);
Assert(Old_pg_index_relation_Tuple);
Old_pg_index_relation_Form =
(Form_pg_class) GETSTRUCT(Old_pg_index_relation_Tuple);
NewIndexName = palloc(NAMEDATALEN); /* XXX */
sprintf(NewIndexName, "temp_%x", OIDOldIndex); /* Set the name. */
NewIndexName = palloc(NAMEDATALEN); /* XXX */
sprintf(NewIndexName, "temp_%x", OIDOldIndex); /* Set the name. */
/*
* Ugly as it is, the only way I have of working out the number of
* attribues is to count them. Mostly there'll be just one but
* I've got to be sure.
*/
for (attnumP = &(Old_pg_index_Form->indkey[0]), natts = 0;
*attnumP != InvalidAttrNumber;
attnumP++, natts++);
/*
* Ugly as it is, the only way I have of working out the number of
* attribues is to count them. Mostly there'll be just one but I've
* got to be sure.
*/
for (attnumP = &(Old_pg_index_Form->indkey[0]), natts = 0;
*attnumP != InvalidAttrNumber;
attnumP++, natts++);
/*
* If this is a functional index, I need to rebuild the functional
* component to pass it to the defining procedure.
*/
if (Old_pg_index_Form->indproc != InvalidOid) {
finfo = (FuncIndexInfo *) palloc(sizeof(FuncIndexInfo));
FIgetnArgs(finfo) = natts;
FIgetProcOid(finfo) = Old_pg_index_Form->indproc;
/*
* If this is a functional index, I need to rebuild the functional
* component to pass it to the defining procedure.
*/
if (Old_pg_index_Form->indproc != InvalidOid)
{
finfo = (FuncIndexInfo *) palloc(sizeof(FuncIndexInfo));
FIgetnArgs(finfo) = natts;
FIgetProcOid(finfo) = Old_pg_index_Form->indproc;
pg_proc_Tuple =
SearchSysCacheTuple(PROOID,
ObjectIdGetDatum(Old_pg_index_Form->indproc),
0,0,0);
pg_proc_Tuple =
SearchSysCacheTuple(PROOID,
ObjectIdGetDatum(Old_pg_index_Form->indproc),
0, 0, 0);
Assert(pg_proc_Tuple);
pg_proc_Form = (Form_pg_proc)GETSTRUCT(pg_proc_Tuple);
namecpy(&(finfo->funcName), &(pg_proc_Form->proname));
} else {
finfo = (FuncIndexInfo *) NULL;
natts = 1;
}
Assert(pg_proc_Tuple);
pg_proc_Form = (Form_pg_proc) GETSTRUCT(pg_proc_Tuple);
namecpy(&(finfo->funcName), &(pg_proc_Form->proname));
}
else
{
finfo = (FuncIndexInfo *) NULL;
natts = 1;
}
index_create((NewHeap->rd_rel->relname).data,
NewIndexName,
finfo,
NULL, /* type info is in the old index */
Old_pg_index_relation_Form->relam,
natts,
Old_pg_index_Form->indkey,
Old_pg_index_Form->indclass,
(uint16)0, (Datum) NULL, NULL,
Old_pg_index_Form->indislossy,
Old_pg_index_Form->indisunique);
index_create((NewHeap->rd_rel->relname).data,
NewIndexName,
finfo,
NULL, /* type info is in the old index */
Old_pg_index_relation_Form->relam,
natts,
Old_pg_index_Form->indkey,
Old_pg_index_Form->indclass,
(uint16) 0, (Datum) NULL, NULL,
Old_pg_index_Form->indislossy,
Old_pg_index_Form->indisunique);
heap_close(OldIndex);
heap_close(NewHeap);
heap_close(OldIndex);
heap_close(NewHeap);
}
static void
rebuildheap(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex)
{
Relation LocalNewHeap, LocalOldHeap, LocalOldIndex;
IndexScanDesc ScanDesc;
RetrieveIndexResult ScanResult;
ItemPointer HeapTid;
HeapTuple LocalHeapTuple;
Buffer LocalBuffer;
Oid OIDNewHeapInsert;
Relation LocalNewHeap,
LocalOldHeap,
LocalOldIndex;
IndexScanDesc ScanDesc;
RetrieveIndexResult ScanResult;
ItemPointer HeapTid;
HeapTuple LocalHeapTuple;
Buffer LocalBuffer;
Oid OIDNewHeapInsert;
/*
* Open the relations I need. Scan through the OldHeap on the OldIndex and
* insert each tuple into the NewHeap.
*/
LocalNewHeap=(Relation)heap_open(OIDNewHeap);
LocalOldHeap=(Relation)heap_open(OIDOldHeap);
LocalOldIndex=(Relation)index_open(OIDOldIndex);
/*
* Open the relations I need. Scan through the OldHeap on the OldIndex
* and insert each tuple into the NewHeap.
*/
LocalNewHeap = (Relation) heap_open(OIDNewHeap);
LocalOldHeap = (Relation) heap_open(OIDOldHeap);
LocalOldIndex = (Relation) index_open(OIDOldIndex);
ScanDesc=index_beginscan(LocalOldIndex, false, 0, (ScanKey) NULL);
ScanDesc = index_beginscan(LocalOldIndex, false, 0, (ScanKey) NULL);
while ((ScanResult =
index_getnext(ScanDesc, ForwardScanDirection)) != NULL) {
while ((ScanResult =
index_getnext(ScanDesc, ForwardScanDirection)) != NULL)
{
HeapTid = &ScanResult->heap_iptr;
LocalHeapTuple = heap_fetch(LocalOldHeap, 0, HeapTid, &LocalBuffer);
OIDNewHeapInsert =
heap_insert(LocalNewHeap, LocalHeapTuple);
pfree(ScanResult);
ReleaseBuffer(LocalBuffer);
}
index_endscan(ScanDesc);
HeapTid = &ScanResult->heap_iptr;
LocalHeapTuple = heap_fetch(LocalOldHeap, 0, HeapTid, &LocalBuffer);
OIDNewHeapInsert =
heap_insert(LocalNewHeap, LocalHeapTuple);
pfree(ScanResult);
ReleaseBuffer(LocalBuffer);
}
index_endscan(ScanDesc);
index_close(LocalOldIndex);
heap_close(LocalOldHeap);
heap_close(LocalNewHeap);
index_close(LocalOldIndex);
heap_close(LocalOldHeap);
heap_close(LocalNewHeap);
}

View File

@ -1,29 +1,29 @@
/*-------------------------------------------------------------------------
*
* command.c--
* random postgres portal and utility support code
* random postgres portal and utility support code
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.13 1997/08/22 14:22:07 vadim Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.14 1997/09/07 04:40:38 momjian Exp $
*
* NOTES
* The PortalExecutorHeapMemory crap needs to be eliminated
* by designing a better executor / portal processing memory
* interface.
*
* The PerformAddAttribute() code, like most of the relation
* manipulating code in the commands/ directory, should go
* someplace closer to the lib/catalog code.
*
* The PortalExecutorHeapMemory crap needs to be eliminated
* by designing a better executor / portal processing memory
* interface.
*
* The PerformAddAttribute() code, like most of the relation
* manipulating code in the commands/ directory, should go
* someplace closer to the lib/catalog code.
*
*-------------------------------------------------------------------------
*/
#include <postgres.h>
#include <access/relscan.h>
#include <utils/portal.h>
#include <utils/portal.h>
#include <commands/command.h>
#include <utils/mcxt.h>
#include <executor/executor.h>
@ -31,7 +31,7 @@
#include <catalog/indexing.h>
#include <utils/syscache.h>
#include <catalog/catalog.h>
#include <access/heapam.h>
#include <access/heapam.h>
#include <utils/array.h>
#include <utils/acl.h>
#include <optimizer/prep.h>
@ -41,443 +41,468 @@
#include <utils/builtins.h>
/* ----------------
* PortalExecutorHeapMemory stuff
* PortalExecutorHeapMemory stuff
*
* This is where the XXXSuperDuperHacky code was. -cim 3/15/90
* This is where the XXXSuperDuperHacky code was. -cim 3/15/90
* ----------------
*/
MemoryContext PortalExecutorHeapMemory = NULL;
MemoryContext PortalExecutorHeapMemory = NULL;
/* --------------------------------
* PortalCleanup
* PortalCleanup
* --------------------------------
*/
void
PortalCleanup(Portal portal)
{
MemoryContext context;
/* ----------------
* sanity checks
* ----------------
*/
AssertArg(PortalIsValid(portal));
AssertArg(portal->cleanup == PortalCleanup);
/* ----------------
* set proper portal-executor context before calling ExecMain.
* ----------------
*/
context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
PortalExecutorHeapMemory = (MemoryContext)
PortalGetHeapMemory(portal);
/* ----------------
* tell the executor to shutdown the query
* ----------------
*/
ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
/* ----------------
* switch back to previous context
* ----------------
*/
MemoryContextSwitchTo(context);
PortalExecutorHeapMemory = (MemoryContext) NULL;
MemoryContext context;
/* ----------------
* sanity checks
* ----------------
*/
AssertArg(PortalIsValid(portal));
AssertArg(portal->cleanup == PortalCleanup);
/* ----------------
* set proper portal-executor context before calling ExecMain.
* ----------------
*/
context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
PortalExecutorHeapMemory = (MemoryContext)
PortalGetHeapMemory(portal);
/* ----------------
* tell the executor to shutdown the query
* ----------------
*/
ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
/* ----------------
* switch back to previous context
* ----------------
*/
MemoryContextSwitchTo(context);
PortalExecutorHeapMemory = (MemoryContext) NULL;
}
/* --------------------------------
* PerformPortalFetch
* PerformPortalFetch
* --------------------------------
*/
void
PerformPortalFetch(char *name,
bool forward,
int count,
char *tag,
CommandDest dest)
bool forward,
int count,
char *tag,
CommandDest dest)
{
Portal portal;
int feature;
QueryDesc *queryDesc;
MemoryContext context;
/* ----------------
* sanity checks
* ----------------
*/
if (name == NULL) {
elog(NOTICE, "PerformPortalFetch: blank portal unsupported");
return;
}
/* ----------------
* get the portal from the portal name
* ----------------
*/
portal = GetPortalByName(name);
if (! PortalIsValid(portal)) {
elog(NOTICE, "PerformPortalFetch: portal \"%s\" not found",
name);
return;
}
/* ----------------
* switch into the portal context
* ----------------
*/
context= MemoryContextSwitchTo((MemoryContext)PortalGetHeapMemory(portal));
AssertState(context ==
(MemoryContext)PortalGetHeapMemory(GetPortalByName(NULL)));
/* ----------------
* setup "feature" to tell the executor what direction and
* how many tuples to fetch.
* ----------------
*/
if (forward)
feature = EXEC_FOR;
else
feature = EXEC_BACK;
/* ----------------
* tell the destination to prepare to recieve some tuples
* ----------------
*/
queryDesc = PortalGetQueryDesc(portal);
BeginCommand(name,
queryDesc->operation,
portal->attinfo,/* QueryDescGetTypeInfo(queryDesc), */
false, /* portal fetches don't end up in relations */
false, /* this is a portal fetch, not a "retrieve portal" */
tag,
dest);
/* ----------------
* execute the portal fetch operation
* ----------------
*/
PortalExecutorHeapMemory = (MemoryContext)
PortalGetHeapMemory(portal);
ExecutorRun(queryDesc, PortalGetState(portal), feature, count);
/* ----------------
* Note: the "end-of-command" tag is returned by higher-level
* utility code
*
* Return blank portal for now.
* Otherwise, this named portal will be cleaned.
* Note: portals will only be supported within a BEGIN...END
* block in the near future. Later, someone will fix it to
* do what is possible across transaction boundries.
* ----------------
*/
MemoryContextSwitchTo(
(MemoryContext)PortalGetHeapMemory(GetPortalByName(NULL)));
Portal portal;
int feature;
QueryDesc *queryDesc;
MemoryContext context;
/* ----------------
* sanity checks
* ----------------
*/
if (name == NULL)
{
elog(NOTICE, "PerformPortalFetch: blank portal unsupported");
return;
}
/* ----------------
* get the portal from the portal name
* ----------------
*/
portal = GetPortalByName(name);
if (!PortalIsValid(portal))
{
elog(NOTICE, "PerformPortalFetch: portal \"%s\" not found",
name);
return;
}
/* ----------------
* switch into the portal context
* ----------------
*/
context = MemoryContextSwitchTo((MemoryContext) PortalGetHeapMemory(portal));
AssertState(context ==
(MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
/* ----------------
* setup "feature" to tell the executor what direction and
* how many tuples to fetch.
* ----------------
*/
if (forward)
feature = EXEC_FOR;
else
feature = EXEC_BACK;
/* ----------------
* tell the destination to prepare to recieve some tuples
* ----------------
*/
queryDesc = PortalGetQueryDesc(portal);
BeginCommand(name,
queryDesc->operation,
portal->attinfo, /* QueryDescGetTypeInfo(queryDesc),
* */
false, /* portal fetches don't end up in
* relations */
false, /* this is a portal fetch, not a "retrieve
* portal" */
tag,
dest);
/* ----------------
* execute the portal fetch operation
* ----------------
*/
PortalExecutorHeapMemory = (MemoryContext)
PortalGetHeapMemory(portal);
ExecutorRun(queryDesc, PortalGetState(portal), feature, count);
/* ----------------
* Note: the "end-of-command" tag is returned by higher-level
* utility code
*
* Return blank portal for now.
* Otherwise, this named portal will be cleaned.
* Note: portals will only be supported within a BEGIN...END
* block in the near future. Later, someone will fix it to
* do what is possible across transaction boundries.
* ----------------
*/
MemoryContextSwitchTo(
(MemoryContext) PortalGetHeapMemory(GetPortalByName(NULL)));
}
/* --------------------------------
* PerformPortalClose
* PerformPortalClose
* --------------------------------
*/
void
PerformPortalClose(char *name, CommandDest dest)
{
Portal portal;
/* ----------------
* sanity checks
* ----------------
*/
if (name == NULL) {
elog(NOTICE, "PerformPortalClose: blank portal unsupported");
return;
}
/* ----------------
* get the portal from the portal name
* ----------------
*/
portal = GetPortalByName(name);
if (! PortalIsValid(portal)) {
elog(NOTICE, "PerformPortalClose: portal \"%s\" not found",
name);
return;
}
/* ----------------
* Note: PortalCleanup is called as a side-effect
* ----------------
*/
PortalDestroy(&portal);
Portal portal;
/* ----------------
* sanity checks
* ----------------
*/
if (name == NULL)
{
elog(NOTICE, "PerformPortalClose: blank portal unsupported");
return;
}
/* ----------------
* get the portal from the portal name
* ----------------
*/
portal = GetPortalByName(name);
if (!PortalIsValid(portal))
{
elog(NOTICE, "PerformPortalClose: portal \"%s\" not found",
name);
return;
}
/* ----------------
* Note: PortalCleanup is called as a side-effect
* ----------------
*/
PortalDestroy(&portal);
}
/* ----------------
* PerformAddAttribute
* PerformAddAttribute
*
* adds an additional attribute to a relation
* adds an additional attribute to a relation
*
* Adds attribute field(s) to a relation. Each new attribute
* is given attnums in sequential order and is added to the
* ATTRIBUTE relation. If the AMI fails, defunct tuples will
* remain in the ATTRIBUTE relation for later vacuuming.
* Later, there may be some reserved attribute names???
* Adds attribute field(s) to a relation. Each new attribute
* is given attnums in sequential order and is added to the
* ATTRIBUTE relation. If the AMI fails, defunct tuples will
* remain in the ATTRIBUTE relation for later vacuuming.
* Later, there may be some reserved attribute names???
*
* (If needed, can instead use elog to handle exceptions.)
* (If needed, can instead use elog to handle exceptions.)
*
* Note:
* Initial idea of ordering the tuple attributes so that all
* the variable length domains occured last was scratched. Doing
* so would not speed access too much (in general) and would create
* many complications in formtuple, amgetattr, and addattribute.
* Note:
* Initial idea of ordering the tuple attributes so that all
* the variable length domains occured last was scratched. Doing
* so would not speed access too much (in general) and would create
* many complications in formtuple, amgetattr, and addattribute.
*
* scan attribute catalog for name conflict (within rel)
* scan type catalog for absence of data type (if not arg)
* create attnum magically???
* create attribute tuple
* insert attribute in attribute catalog
* modify reldesc
* create new relation tuple
* insert new relation in relation catalog
* delete original relation from relation catalog
* scan attribute catalog for name conflict (within rel)
* scan type catalog for absence of data type (if not arg)
* create attnum magically???
* create attribute tuple
* insert attribute in attribute catalog
* modify reldesc
* create new relation tuple
* insert new relation in relation catalog
* delete original relation from relation catalog
* ----------------
*/
void
PerformAddAttribute(char *relationName,
char *userName,
bool inherits,
ColumnDef *colDef)
{
Relation relrdesc, attrdesc;
HeapScanDesc attsdesc;
HeapTuple reltup;
HeapTuple attributeTuple;
AttributeTupleForm attribute;
FormData_pg_attribute attributeD;
int i;
int minattnum, maxatts;
HeapTuple tup;
ScanKeyData key[2];
ItemPointerData oldTID;
Relation idescs[Num_pg_attr_indices];
Relation ridescs[Num_pg_class_indices];
bool hasindex;
/*
* permissions checking. this would normally be done in utility.c,
* but this particular routine is recursive.
*
* normally, only the owner of a class can change its schema.
*/
if (IsSystemRelationName(relationName))
elog(WARN, "PerformAddAttribute: class \"%s\" is a system catalog",
relationName);
char *userName,
bool inherits,
ColumnDef * colDef)
{
Relation relrdesc,
attrdesc;
HeapScanDesc attsdesc;
HeapTuple reltup;
HeapTuple attributeTuple;
AttributeTupleForm attribute;
FormData_pg_attribute attributeD;
int i;
int minattnum,
maxatts;
HeapTuple tup;
ScanKeyData key[2];
ItemPointerData oldTID;
Relation idescs[Num_pg_attr_indices];
Relation ridescs[Num_pg_class_indices];
bool hasindex;
/*
* permissions checking. this would normally be done in utility.c,
* but this particular routine is recursive.
*
* normally, only the owner of a class can change its schema.
*/
if (IsSystemRelationName(relationName))
elog(WARN, "PerformAddAttribute: class \"%s\" is a system catalog",
relationName);
#ifndef NO_SECURITY
if (!pg_ownercheck(userName, relationName, RELNAME))
elog(WARN, "PerformAddAttribute: you do not own class \"%s\"",
relationName);
if (!pg_ownercheck(userName, relationName, RELNAME))
elog(WARN, "PerformAddAttribute: you do not own class \"%s\"",
relationName);
#endif
/*
* we can't add a not null attribute
*/
if (colDef->is_not_null)
elog(WARN,"Can't add a not null attribute to a existent relation");
if (colDef->defval)
elog(WARN,"ADD ATTRIBUTE: DEFAULT is not implemented, yet");
/*
* if the first element in the 'schema' list is a "*" then we are
* supposed to add this attribute to all classes that inherit from
* 'relationName' (as well as to 'relationName').
*
* any permissions or problems with duplicate attributes will cause
* the whole transaction to abort, which is what we want -- all or
* nothing.
*/
if (colDef != NULL) {
if (inherits) {
Oid myrelid, childrelid;
List *child, *children;
relrdesc = heap_openr(relationName);
if (!RelationIsValid(relrdesc)) {
elog(WARN, "PerformAddAttribute: unknown relation: \"%s\"",
relationName);
}
myrelid = relrdesc->rd_id;
heap_close(relrdesc);
/* this routine is actually in the planner */
children = find_all_inheritors(lconsi(myrelid,NIL), NIL);
/*
* find_all_inheritors does the recursive search of the
* inheritance hierarchy, so all we have to do is process
* all of the relids in the list that it returns.
*/
foreach (child, children) {
childrelid = lfirsti(child);
if (childrelid == myrelid)
continue;
relrdesc = heap_open(childrelid);
if (!RelationIsValid(relrdesc)) {
elog(WARN, "PerformAddAttribute: can't find catalog entry for inheriting class with oid %d",
childrelid);
/*
* we can't add a not null attribute
*/
if (colDef->is_not_null)
elog(WARN, "Can't add a not null attribute to a existent relation");
if (colDef->defval)
elog(WARN, "ADD ATTRIBUTE: DEFAULT is not implemented, yet");
/*
* if the first element in the 'schema' list is a "*" then we are
* supposed to add this attribute to all classes that inherit from
* 'relationName' (as well as to 'relationName').
*
* any permissions or problems with duplicate attributes will cause the
* whole transaction to abort, which is what we want -- all or
* nothing.
*/
if (colDef != NULL)
{
if (inherits)
{
Oid myrelid,
childrelid;
List *child,
*children;
relrdesc = heap_openr(relationName);
if (!RelationIsValid(relrdesc))
{
elog(WARN, "PerformAddAttribute: unknown relation: \"%s\"",
relationName);
}
myrelid = relrdesc->rd_id;
heap_close(relrdesc);
/* this routine is actually in the planner */
children = find_all_inheritors(lconsi(myrelid, NIL), NIL);
/*
* find_all_inheritors does the recursive search of the
* inheritance hierarchy, so all we have to do is process all
* of the relids in the list that it returns.
*/
foreach(child, children)
{
childrelid = lfirsti(child);
if (childrelid == myrelid)
continue;
relrdesc = heap_open(childrelid);
if (!RelationIsValid(relrdesc))
{
elog(WARN, "PerformAddAttribute: can't find catalog entry for inheriting class with oid %d",
childrelid);
}
PerformAddAttribute((relrdesc->rd_rel->relname).data,
userName, false, colDef);
heap_close(relrdesc);
}
}
PerformAddAttribute((relrdesc->rd_rel->relname).data,
userName, false, colDef);
}
relrdesc = heap_openr(RelationRelationName);
reltup = ClassNameIndexScan(relrdesc, relationName);
if (!PointerIsValid(reltup))
{
heap_close(relrdesc);
}
elog(WARN, "PerformAddAttribute: relation \"%s\" not found",
relationName);
}
}
relrdesc = heap_openr(RelationRelationName);
reltup = ClassNameIndexScan(relrdesc, relationName);
if (!PointerIsValid(reltup)) {
heap_close(relrdesc);
elog(WARN, "PerformAddAttribute: relation \"%s\" not found",
relationName);
}
/*
* XXX is the following check sufficient?
*/
if (((Form_pg_class) GETSTRUCT(reltup))->relkind == RELKIND_INDEX) {
elog(WARN, "PerformAddAttribute: index relation \"%s\" not changed",
relationName);
return;
}
minattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts;
maxatts = minattnum + 1;
if (maxatts > MaxHeapAttributeNumber) {
pfree(reltup); /* XXX temp */
heap_close(relrdesc); /* XXX temp */
elog(WARN, "PerformAddAttribute: relations limited to %d attributes",
MaxHeapAttributeNumber);
return;
}
attrdesc = heap_openr(AttributeRelationName);
Assert(attrdesc);
Assert(RelationGetRelationTupleForm(attrdesc));
/*
* Open all (if any) pg_attribute indices
*/
hasindex = RelationGetRelationTupleForm(attrdesc)->relhasindex;
if (hasindex)
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
ScanKeyEntryInitialize(&key[0],
(bits16) NULL,
(AttrNumber) Anum_pg_attribute_attrelid,
(RegProcedure)ObjectIdEqualRegProcedure,
(Datum) reltup->t_oid);
ScanKeyEntryInitialize(&key[1],
(bits16) NULL,
(AttrNumber) Anum_pg_attribute_attname,
(RegProcedure)NameEqualRegProcedure,
(Datum) NULL);
attributeD.attrelid = reltup->t_oid;
attributeD.attdisbursion = 0; /* XXX temporary */
attributeD.attcacheoff = -1;
attributeTuple = heap_addheader(Natts_pg_attribute,
sizeof attributeD,
(char *)&attributeD);
attribute = (AttributeTupleForm)GETSTRUCT(attributeTuple);
i = 1 + minattnum;
{
HeapTuple typeTuple;
TypeTupleForm form;
char *p;
int attnelems;
/*
* XXX use syscache here as an optimization
* XXX is the following check sufficient?
*/
key[1].sk_argument = (Datum)colDef->colname;
attsdesc = heap_beginscan(attrdesc, 0, NowTimeQual, 2, key);
tup = heap_getnext(attsdesc, 0, (Buffer *) NULL);
if (HeapTupleIsValid(tup)) {
pfree(reltup); /* XXX temp */
heap_endscan(attsdesc); /* XXX temp */
heap_close(attrdesc); /* XXX temp */
heap_close(relrdesc); /* XXX temp */
elog(WARN, "PerformAddAttribute: attribute \"%s\" already exists in class \"%s\"",
key[1].sk_argument,
relationName);
return;
if (((Form_pg_class) GETSTRUCT(reltup))->relkind == RELKIND_INDEX)
{
elog(WARN, "PerformAddAttribute: index relation \"%s\" not changed",
relationName);
return;
}
heap_endscan(attsdesc);
minattnum = ((Form_pg_class) GETSTRUCT(reltup))->relnatts;
maxatts = minattnum + 1;
if (maxatts > MaxHeapAttributeNumber)
{
pfree(reltup); /* XXX temp */
heap_close(relrdesc); /* XXX temp */
elog(WARN, "PerformAddAttribute: relations limited to %d attributes",
MaxHeapAttributeNumber);
return;
}
attrdesc = heap_openr(AttributeRelationName);
Assert(attrdesc);
Assert(RelationGetRelationTupleForm(attrdesc));
/*
* check to see if it is an array attribute.
* Open all (if any) pg_attribute indices
*/
p = colDef->typename->name;
if (colDef->typename->arrayBounds)
{
attnelems = length(colDef->typename->arrayBounds);
p = makeArrayTypeName(colDef->typename->name);
}
else
attnelems = 0;
typeTuple = SearchSysCacheTuple(TYPNAME,
PointerGetDatum(p),
0,0,0);
form = (TypeTupleForm)GETSTRUCT(typeTuple);
if (!HeapTupleIsValid(typeTuple)) {
elog(WARN, "Add: type \"%s\" nonexistent", p);
}
namestrcpy(&(attribute->attname), (char*) key[1].sk_argument);
attribute->atttypid = typeTuple->t_oid;
if (colDef->typename->typlen > 0)
attribute->attlen = colDef->typename->typlen;
else /* bpchar, varchar, text */
attribute->attlen = form->typlen;
attribute->attnum = i;
attribute->attbyval = form->typbyval;
attribute->attnelems = attnelems;
attribute->attcacheoff = -1;
attribute->attisset = (bool) (form->typtype == 'c');
attribute->attalign = form->typalign;
attribute->attnotnull = false;
heap_insert(attrdesc, attributeTuple);
hasindex = RelationGetRelationTupleForm(attrdesc)->relhasindex;
if (hasindex)
CatalogIndexInsert(idescs,
Num_pg_attr_indices,
attrdesc,
attributeTuple);
}
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
if (hasindex)
CatalogCloseIndices(Num_pg_attr_indices, idescs);
heap_close(attrdesc);
((Form_pg_class) GETSTRUCT(reltup))->relnatts = maxatts;
oldTID = reltup->t_ctid;
heap_replace(relrdesc, &oldTID, reltup);
/* keep catalog indices current */
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
CatalogIndexInsert(ridescs, Num_pg_class_indices, relrdesc, reltup);
CatalogCloseIndices(Num_pg_class_indices, ridescs);
pfree(reltup);
heap_close(relrdesc);
ScanKeyEntryInitialize(&key[0],
(bits16) NULL,
(AttrNumber) Anum_pg_attribute_attrelid,
(RegProcedure) ObjectIdEqualRegProcedure,
(Datum) reltup->t_oid);
ScanKeyEntryInitialize(&key[1],
(bits16) NULL,
(AttrNumber) Anum_pg_attribute_attname,
(RegProcedure) NameEqualRegProcedure,
(Datum) NULL);
attributeD.attrelid = reltup->t_oid;
attributeD.attdisbursion = 0; /* XXX temporary */
attributeD.attcacheoff = -1;
attributeTuple = heap_addheader(Natts_pg_attribute,
sizeof attributeD,
(char *) &attributeD);
attribute = (AttributeTupleForm) GETSTRUCT(attributeTuple);
i = 1 + minattnum;
{
HeapTuple typeTuple;
TypeTupleForm form;
char *p;
int attnelems;
/*
* XXX use syscache here as an optimization
*/
key[1].sk_argument = (Datum) colDef->colname;
attsdesc = heap_beginscan(attrdesc, 0, NowTimeQual, 2, key);
tup = heap_getnext(attsdesc, 0, (Buffer *) NULL);
if (HeapTupleIsValid(tup))
{
pfree(reltup); /* XXX temp */
heap_endscan(attsdesc); /* XXX temp */
heap_close(attrdesc); /* XXX temp */
heap_close(relrdesc); /* XXX temp */
elog(WARN, "PerformAddAttribute: attribute \"%s\" already exists in class \"%s\"",
key[1].sk_argument,
relationName);
return;
}
heap_endscan(attsdesc);
/*
* check to see if it is an array attribute.
*/
p = colDef->typename->name;
if (colDef->typename->arrayBounds)
{
attnelems = length(colDef->typename->arrayBounds);
p = makeArrayTypeName(colDef->typename->name);
}
else
attnelems = 0;
typeTuple = SearchSysCacheTuple(TYPNAME,
PointerGetDatum(p),
0, 0, 0);
form = (TypeTupleForm) GETSTRUCT(typeTuple);
if (!HeapTupleIsValid(typeTuple))
{
elog(WARN, "Add: type \"%s\" nonexistent", p);
}
namestrcpy(&(attribute->attname), (char *) key[1].sk_argument);
attribute->atttypid = typeTuple->t_oid;
if (colDef->typename->typlen > 0)
attribute->attlen = colDef->typename->typlen;
else
/* bpchar, varchar, text */
attribute->attlen = form->typlen;
attribute->attnum = i;
attribute->attbyval = form->typbyval;
attribute->attnelems = attnelems;
attribute->attcacheoff = -1;
attribute->attisset = (bool) (form->typtype == 'c');
attribute->attalign = form->typalign;
attribute->attnotnull = false;
heap_insert(attrdesc, attributeTuple);
if (hasindex)
CatalogIndexInsert(idescs,
Num_pg_attr_indices,
attrdesc,
attributeTuple);
}
if (hasindex)
CatalogCloseIndices(Num_pg_attr_indices, idescs);
heap_close(attrdesc);
((Form_pg_class) GETSTRUCT(reltup))->relnatts = maxatts;
oldTID = reltup->t_ctid;
heap_replace(relrdesc, &oldTID, reltup);
/* keep catalog indices current */
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
CatalogIndexInsert(ridescs, Num_pg_class_indices, relrdesc, reltup);
CatalogCloseIndices(Num_pg_class_indices, ridescs);
pfree(reltup);
heap_close(relrdesc);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* explain.c--
* Explain the query execution plan
* Explain the query execution plan
*
* Copyright (c) 1994-5, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.10 1997/08/18 20:52:17 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.11 1997/09/07 04:40:49 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -17,7 +17,7 @@
#include <postgres.h>
#include <parser/catalog_utils.h>
#include <parser/parse_query.h> /* for MakeTimeRange() */
#include <parser/parse_query.h> /* for MakeTimeRange() */
#include <nodes/plannodes.h>
#include <tcop/tcopprot.h>
#include <lib/stringinfo.h>
@ -25,79 +25,86 @@
#include <optimizer/planner.h>
#include <access/xact.h>
typedef struct ExplainState {
/* options */
bool printCost; /* print cost */
bool printNodes; /* do nodeToString() instead */
/* other states */
List *rtable; /* range table */
} ExplainState;
typedef struct ExplainState
{
/* options */
bool printCost; /* print cost */
bool printNodes; /* do nodeToString() instead */
/* other states */
List *rtable; /* range table */
} ExplainState;
static char *Explain_PlanToString(Plan *plan, ExplainState *es);
static char *Explain_PlanToString(Plan * plan, ExplainState * es);
/*
* ExplainQuery -
* print out the execution plan for a given query
* print out the execution plan for a given query
*
*/
void
ExplainQuery(Query *query, bool verbose, CommandDest dest)
ExplainQuery(Query * query, bool verbose, CommandDest dest)
{
char *s = NULL, *s2;
Plan *plan;
ExplainState *es;
int len;
char *s = NULL,
*s2;
Plan *plan;
ExplainState *es;
int len;
if (IsAbortedTransactionBlockState()) {
char *tag = "*ABORT STATE*";
EndCommand(tag, dest);
elog(NOTICE, "(transaction aborted): %s",
"queries ignored until END");
return;
}
if (IsAbortedTransactionBlockState())
{
char *tag = "*ABORT STATE*";
/* plan the queries (XXX we've ignored rewrite!!) */
plan = planner(query);
EndCommand(tag, dest);
/* pg_plan could have failed */
if (plan == NULL)
return;
elog(NOTICE, "(transaction aborted): %s",
"queries ignored until END");
es = (ExplainState*)malloc(sizeof(ExplainState));
memset(es, 0, sizeof(ExplainState));
es->printCost = true; /* default */
if (verbose)
es->printNodes = true;
es->rtable = query->rtable;
if (es->printNodes)
s = nodeToString(plan);
if (es->printCost) {
s2 = Explain_PlanToString(plan, es);
if (s == NULL)
s = s2;
else {
strcat(s, "\n\n");
strcat(s, s2);
return;
}
}
/* output the plan */
len = strlen(s);
elog(NOTICE, "QUERY PLAN:\n\n%.*s", ELOG_MAXLEN-64, s);
len -= ELOG_MAXLEN-64;
while (len > 0) {
s += ELOG_MAXLEN-64;
elog(NOTICE, "%.*s", ELOG_MAXLEN-64, s);
len -= ELOG_MAXLEN-64;
}
free(es);
/* plan the queries (XXX we've ignored rewrite!!) */
plan = planner(query);
/* pg_plan could have failed */
if (plan == NULL)
return;
es = (ExplainState *) malloc(sizeof(ExplainState));
memset(es, 0, sizeof(ExplainState));
es->printCost = true; /* default */
if (verbose)
es->printNodes = true;
es->rtable = query->rtable;
if (es->printNodes)
s = nodeToString(plan);
if (es->printCost)
{
s2 = Explain_PlanToString(plan, es);
if (s == NULL)
s = s2;
else
{
strcat(s, "\n\n");
strcat(s, s2);
}
}
/* output the plan */
len = strlen(s);
elog(NOTICE, "QUERY PLAN:\n\n%.*s", ELOG_MAXLEN - 64, s);
len -= ELOG_MAXLEN - 64;
while (len > 0)
{
s += ELOG_MAXLEN - 64;
elog(NOTICE, "%.*s", ELOG_MAXLEN - 64, s);
len -= ELOG_MAXLEN - 64;
}
free(es);
}
/*****************************************************************************
@ -106,122 +113,130 @@ ExplainQuery(Query *query, bool verbose, CommandDest dest)
/*
* explain_outNode -
* converts a Node into ascii string and append it to 'str'
* converts a Node into ascii string and append it to 'str'
*/
static void
explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
explain_outNode(StringInfo str, Plan * plan, int indent, ExplainState * es)
{
char *pname;
char buf[1000];
int i;
if (plan==NULL) {
appendStringInfo(str, "\n");
return;
}
char *pname;
char buf[1000];
int i;
switch(nodeTag(plan)) {
case T_Result:
pname = "Result";
break;
case T_Append:
pname = "Append";
break;
case T_NestLoop:
pname = "Nested Loop";
break;
case T_MergeJoin:
pname = "Merge Join";
break;
case T_HashJoin:
pname = "Hash Join";
break;
case T_SeqScan:
pname = "Seq Scan";
break;
case T_IndexScan:
pname = "Index Scan";
break;
case T_Temp:
pname = "Temp Scan";
break;
case T_Sort:
pname = "Sort";
break;
case T_Group:
pname = "Group";
break;
case T_Agg:
pname = "Aggregate";
break;
case T_Unique:
pname = "Unique";
break;
case T_Hash:
pname = "Hash";
break;
case T_Tee:
pname = "Tee";
break;
default:
pname = "";
break;
}
for(i=0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, pname);
switch(nodeTag(plan)) {
case T_SeqScan:
case T_IndexScan:
if (((Scan*)plan)->scanrelid > 0) {
RangeTblEntry *rte = nth(((Scan*)plan)->scanrelid-1, es->rtable);
sprintf(buf, " on %s", rte->refname);
appendStringInfo(str, buf);
if (plan == NULL)
{
appendStringInfo(str, "\n");
return;
}
break;
default:
break;
}
if (es->printCost) {
sprintf(buf, " (cost=%.2f size=%d width=%d)",
plan->cost, plan->plan_size, plan->plan_width);
appendStringInfo(str, buf);
}
appendStringInfo(str, "\n");
/* lefttree */
if (outerPlan(plan)) {
for(i=0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
explain_outNode(str, outerPlan(plan), indent+1, es);
}
switch (nodeTag(plan))
{
case T_Result:
pname = "Result";
break;
case T_Append:
pname = "Append";
break;
case T_NestLoop:
pname = "Nested Loop";
break;
case T_MergeJoin:
pname = "Merge Join";
break;
case T_HashJoin:
pname = "Hash Join";
break;
case T_SeqScan:
pname = "Seq Scan";
break;
case T_IndexScan:
pname = "Index Scan";
break;
case T_Temp:
pname = "Temp Scan";
break;
case T_Sort:
pname = "Sort";
break;
case T_Group:
pname = "Group";
break;
case T_Agg:
pname = "Aggregate";
break;
case T_Unique:
pname = "Unique";
break;
case T_Hash:
pname = "Hash";
break;
case T_Tee:
pname = "Tee";
break;
default:
pname = "";
break;
}
/* righttree */
if (innerPlan(plan)) {
for(i=0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
explain_outNode(str, innerPlan(plan), indent+1, es);
}
return;
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, pname);
switch (nodeTag(plan))
{
case T_SeqScan:
case T_IndexScan:
if (((Scan *) plan)->scanrelid > 0)
{
RangeTblEntry *rte = nth(((Scan *) plan)->scanrelid - 1, es->rtable);
sprintf(buf, " on %s", rte->refname);
appendStringInfo(str, buf);
}
break;
default:
break;
}
if (es->printCost)
{
sprintf(buf, " (cost=%.2f size=%d width=%d)",
plan->cost, plan->plan_size, plan->plan_width);
appendStringInfo(str, buf);
}
appendStringInfo(str, "\n");
/* lefttree */
if (outerPlan(plan))
{
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
explain_outNode(str, outerPlan(plan), indent + 1, es);
}
/* righttree */
if (innerPlan(plan))
{
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
explain_outNode(str, innerPlan(plan), indent + 1, es);
}
return;
}
static char *
Explain_PlanToString(Plan *plan, ExplainState *es)
static char *
Explain_PlanToString(Plan * plan, ExplainState * es)
{
StringInfo str;
char *s;
if (plan==NULL)
return "";
Assert(plan!=NULL);
str = makeStringInfo();
explain_outNode(str, plan, 0, es);
s = str->data;
pfree(str);
StringInfo str;
char *s;
return s;
if (plan == NULL)
return "";
Assert(plan != NULL);
str = makeStringInfo();
explain_outNode(str, plan, 0, es);
s = str->data;
pfree(str);
return s;
}

View File

@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* purge.c--
* the POSTGRES purge command.
* the POSTGRES purge command.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/purge.c,v 1.6 1997/08/12 22:52:25 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/purge.c,v 1.7 1997/09/07 04:40:51 momjian Exp $
*
* Note:
* XXX There are many instances of int32 instead of ...Time. These
* should be changed once it is decided the signed'ness will be.
* XXX There are many instances of int32 instead of ...Time. These
* should be changed once it is decided the signed'ness will be.
*
*-------------------------------------------------------------------------
*/
@ -21,145 +21,156 @@
#include <access/heapam.h>
#include <access/xact.h>
#include <utils/tqual.h> /* for NowTimeQual */
#include <utils/tqual.h> /* for NowTimeQual */
#include <catalog/catname.h>
#include <catalog/indexing.h>
#include <fmgr.h>
#include <commands/purge.h>
#include <utils/builtins.h> /* for isreltime() */
#include <utils/builtins.h> /* for isreltime() */
static char cmdname[] = "RelationPurge";
static char cmdname[] = "RelationPurge";
#define RELATIVE 01
#define ABSOLUTE 02
#define RELATIVE 01
#define ABSOLUTE 02
int32
RelationPurge(char *relationName,
char *absoluteTimeString,
char *relativeTimeString)
char *absoluteTimeString,
char *relativeTimeString)
{
register i;
AbsoluteTime absoluteTime = INVALID_ABSTIME;
RelativeTime relativeTime = INVALID_RELTIME;
bits8 dateTag;
Relation relation;
HeapScanDesc scan;
static ScanKeyData key[1] = {
{ 0, Anum_pg_class_relname, F_NAMEEQ }
};
Buffer buffer;
HeapTuple newTuple, oldTuple;
AbsoluteTime currentTime;
char *values[Natts_pg_class];
char nulls[Natts_pg_class];
char replace[Natts_pg_class];
Relation idescs[Num_pg_class_indices];
/*
* XXX for some reason getmyrelids (in inval.c) barfs when
* you heap_replace tuples from these classes. i thought
* setheapoverride would fix it but it didn't. for now,
* just disallow purge on these classes.
*/
if (strcmp(RelationRelationName, relationName) == 0 ||
strcmp(AttributeRelationName, relationName) == 0 ||
strcmp(AccessMethodRelationName, relationName) == 0 ||
strcmp(AccessMethodOperatorRelationName, relationName) == 0) {
elog(WARN, "%s: cannot purge catalog \"%s\"",
cmdname, relationName);
}
if (PointerIsValid(absoluteTimeString)) {
absoluteTime = (int32) nabstimein(absoluteTimeString);
absoluteTimeString[0] = '\0';
if (absoluteTime == INVALID_ABSTIME) {
elog(NOTICE, "%s: bad absolute time string \"%s\"",
cmdname, absoluteTimeString);
elog(WARN, "purge not executed");
register i;
AbsoluteTime absoluteTime = INVALID_ABSTIME;
RelativeTime relativeTime = INVALID_RELTIME;
bits8 dateTag;
Relation relation;
HeapScanDesc scan;
static ScanKeyData key[1] = {
{0, Anum_pg_class_relname, F_NAMEEQ}
};
Buffer buffer;
HeapTuple newTuple,
oldTuple;
AbsoluteTime currentTime;
char *values[Natts_pg_class];
char nulls[Natts_pg_class];
char replace[Natts_pg_class];
Relation idescs[Num_pg_class_indices];
/*
* XXX for some reason getmyrelids (in inval.c) barfs when you
* heap_replace tuples from these classes. i thought setheapoverride
* would fix it but it didn't. for now, just disallow purge on these
* classes.
*/
if (strcmp(RelationRelationName, relationName) == 0 ||
strcmp(AttributeRelationName, relationName) == 0 ||
strcmp(AccessMethodRelationName, relationName) == 0 ||
strcmp(AccessMethodOperatorRelationName, relationName) == 0)
{
elog(WARN, "%s: cannot purge catalog \"%s\"",
cmdname, relationName);
}
}
#ifdef PURGEDEBUG
elog(DEBUG, "%s: absolute time `%s' is %d.",
cmdname, absoluteTimeString, absoluteTime);
#endif /* defined(PURGEDEBUG) */
if (PointerIsValid(relativeTimeString)) {
if (isreltime(relativeTimeString) != 1) {
elog(WARN, "%s: bad relative time string \"%s\"",
cmdname, relativeTimeString);
if (PointerIsValid(absoluteTimeString))
{
absoluteTime = (int32) nabstimein(absoluteTimeString);
absoluteTimeString[0] = '\0';
if (absoluteTime == INVALID_ABSTIME)
{
elog(NOTICE, "%s: bad absolute time string \"%s\"",
cmdname, absoluteTimeString);
elog(WARN, "purge not executed");
}
}
relativeTime = reltimein(relativeTimeString);
#ifdef PURGEDEBUG
elog(DEBUG, "%s: relative time `%s' is %d.",
cmdname, relativeTimeString, relativeTime);
#endif /* defined(PURGEDEBUG) */
}
/*
* Find the RELATION relation tuple for the given relation.
*/
relation = heap_openr(RelationRelationName);
key[0].sk_argument = PointerGetDatum(relationName);
fmgr_info(key[0].sk_procedure, &key[0].sk_func, &key[0].sk_nargs);
scan = heap_beginscan(relation, 0, NowTimeQual, 1, key);
oldTuple = heap_getnext(scan, 0, &buffer);
if (!HeapTupleIsValid(oldTuple)) {
elog(DEBUG, "%s: absolute time `%s' is %d.",
cmdname, absoluteTimeString, absoluteTime);
#endif /* defined(PURGEDEBUG) */
if (PointerIsValid(relativeTimeString))
{
if (isreltime(relativeTimeString) != 1)
{
elog(WARN, "%s: bad relative time string \"%s\"",
cmdname, relativeTimeString);
}
relativeTime = reltimein(relativeTimeString);
#ifdef PURGEDEBUG
elog(DEBUG, "%s: relative time `%s' is %d.",
cmdname, relativeTimeString, relativeTime);
#endif /* defined(PURGEDEBUG) */
}
/*
* Find the RELATION relation tuple for the given relation.
*/
relation = heap_openr(RelationRelationName);
key[0].sk_argument = PointerGetDatum(relationName);
fmgr_info(key[0].sk_procedure, &key[0].sk_func, &key[0].sk_nargs);
scan = heap_beginscan(relation, 0, NowTimeQual, 1, key);
oldTuple = heap_getnext(scan, 0, &buffer);
if (!HeapTupleIsValid(oldTuple))
{
heap_endscan(scan);
heap_close(relation);
elog(WARN, "%s: no such relation: %s", cmdname, relationName);
return (0);
}
/*
* Dig around in the tuple.
*/
currentTime = GetCurrentTransactionStartTime();
if (!RelativeTimeIsValid(relativeTime))
{
dateTag = ABSOLUTE;
if (!AbsoluteTimeIsValid(absoluteTime))
absoluteTime = currentTime;
}
else if (!AbsoluteTimeIsValid(absoluteTime))
dateTag = RELATIVE;
else
dateTag = ABSOLUTE | RELATIVE;
for (i = 0; i < Natts_pg_class; ++i)
{
nulls[i] = heap_attisnull(oldTuple, i + 1) ? 'n' : ' ';
values[i] = NULL;
replace[i] = ' ';
}
if (dateTag & ABSOLUTE)
{
values[Anum_pg_class_relexpires - 1] =
(char *) UInt32GetDatum(absoluteTime);
replace[Anum_pg_class_relexpires - 1] = 'r';
}
if (dateTag & RELATIVE)
{
values[Anum_pg_class_relpreserved - 1] =
(char *) UInt32GetDatum(relativeTime);
replace[Anum_pg_class_relpreserved - 1] = 'r';
}
/*
* Change the RELATION relation tuple for the given relation.
*/
newTuple = heap_modifytuple(oldTuple, buffer, relation, (Datum *) values,
nulls, replace);
/* XXX How do you detect an insertion error?? */
heap_replace(relation, &newTuple->t_ctid, newTuple);
/* keep the system catalog indices current */
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
CatalogIndexInsert(idescs, Num_pg_class_indices, relation, newTuple);
CatalogCloseIndices(Num_pg_class_indices, idescs);
pfree(newTuple);
heap_endscan(scan);
heap_close(relation);
elog(WARN, "%s: no such relation: %s", cmdname, relationName);
return(0);
}
/*
* Dig around in the tuple.
*/
currentTime = GetCurrentTransactionStartTime();
if (!RelativeTimeIsValid(relativeTime)) {
dateTag = ABSOLUTE;
if (!AbsoluteTimeIsValid(absoluteTime))
absoluteTime = currentTime;
} else if (!AbsoluteTimeIsValid(absoluteTime))
dateTag = RELATIVE;
else
dateTag = ABSOLUTE | RELATIVE;
for (i = 0; i < Natts_pg_class; ++i) {
nulls[i] = heap_attisnull(oldTuple, i+1) ? 'n' : ' ';
values[i] = NULL;
replace[i] = ' ';
}
if (dateTag & ABSOLUTE) {
values[Anum_pg_class_relexpires-1] =
(char *) UInt32GetDatum(absoluteTime);
replace[Anum_pg_class_relexpires-1] = 'r';
}
if (dateTag & RELATIVE) {
values[Anum_pg_class_relpreserved-1] =
(char *) UInt32GetDatum(relativeTime);
replace[Anum_pg_class_relpreserved-1] = 'r';
}
/*
* Change the RELATION relation tuple for the given relation.
*/
newTuple = heap_modifytuple(oldTuple, buffer, relation, (Datum*)values,
nulls, replace);
/* XXX How do you detect an insertion error?? */
heap_replace(relation, &newTuple->t_ctid, newTuple);
/* keep the system catalog indices current */
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
CatalogIndexInsert(idescs, Num_pg_class_indices, relation, newTuple);
CatalogCloseIndices(Num_pg_class_indices, idescs);
pfree(newTuple);
heap_endscan(scan);
heap_close(relation);
return(1);
return (1);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* remove.c--
* POSTGRES remove (function | type | operator ) utilty code.
* POSTGRES remove (function | type | operator ) utilty code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.10 1997/08/18 20:52:17 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.11 1997/09/07 04:40:54 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -28,100 +28,112 @@
#include <storage/bufmgr.h>
#include <fmgr.h>
#ifndef HAVE_MEMMOVE
# include <regex/utils.h>
#include <regex/utils.h>
#else
# include <string.h>
#include <string.h>
#endif
/*
* RemoveOperator --
* Deletes an operator.
* Deletes an operator.
*
* Exceptions:
* BadArg if name is invalid.
* BadArg if type1 is invalid.
* "WARN" if operator nonexistent.
* ...
* BadArg if name is invalid.
* BadArg if type1 is invalid.
* "WARN" if operator nonexistent.
* ...
*/
void
RemoveOperator(char *operatorName, /* operator name */
char *typeName1, /* first type name */
char *typeName2) /* optional second type name */
RemoveOperator(char *operatorName, /* operator name */
char *typeName1, /* first type name */
char *typeName2) /* optional second type name */
{
Relation relation;
HeapScanDesc scan;
HeapTuple tup;
Oid typeId1 = InvalidOid;
Oid typeId2 = InvalidOid;
bool defined;
ItemPointerData itemPointerData;
Buffer buffer;
ScanKeyData operatorKey[3];
char *userName;
if (typeName1) {
typeId1 = TypeGet(typeName1, &defined);
if (!OidIsValid(typeId1)) {
elog(WARN, "RemoveOperator: type '%s' does not exist", typeName1);
return;
Relation relation;
HeapScanDesc scan;
HeapTuple tup;
Oid typeId1 = InvalidOid;
Oid typeId2 = InvalidOid;
bool defined;
ItemPointerData itemPointerData;
Buffer buffer;
ScanKeyData operatorKey[3];
char *userName;
if (typeName1)
{
typeId1 = TypeGet(typeName1, &defined);
if (!OidIsValid(typeId1))
{
elog(WARN, "RemoveOperator: type '%s' does not exist", typeName1);
return;
}
}
}
if (typeName2) {
typeId2 = TypeGet(typeName2, &defined);
if (!OidIsValid(typeId2)) {
elog(WARN, "RemoveOperator: type '%s' does not exist", typeName2);
return;
if (typeName2)
{
typeId2 = TypeGet(typeName2, &defined);
if (!OidIsValid(typeId2))
{
elog(WARN, "RemoveOperator: type '%s' does not exist", typeName2);
return;
}
}
}
ScanKeyEntryInitialize(&operatorKey[0], 0x0,
Anum_pg_operator_oprname,
NameEqualRegProcedure,
PointerGetDatum(operatorName));
ScanKeyEntryInitialize(&operatorKey[1], 0x0,
Anum_pg_operator_oprleft,
ObjectIdEqualRegProcedure,
ObjectIdGetDatum(typeId1));
ScanKeyEntryInitialize(&operatorKey[2], 0x0,
Anum_pg_operator_oprright,
ObjectIdEqualRegProcedure,
ObjectIdGetDatum(typeId2));
relation = heap_openr(OperatorRelationName);
scan = heap_beginscan(relation, 0, NowTimeQual, 3, operatorKey);
tup = heap_getnext(scan, 0, &buffer);
if (HeapTupleIsValid(tup)) {
ScanKeyEntryInitialize(&operatorKey[0], 0x0,
Anum_pg_operator_oprname,
NameEqualRegProcedure,
PointerGetDatum(operatorName));
ScanKeyEntryInitialize(&operatorKey[1], 0x0,
Anum_pg_operator_oprleft,
ObjectIdEqualRegProcedure,
ObjectIdGetDatum(typeId1));
ScanKeyEntryInitialize(&operatorKey[2], 0x0,
Anum_pg_operator_oprright,
ObjectIdEqualRegProcedure,
ObjectIdGetDatum(typeId2));
relation = heap_openr(OperatorRelationName);
scan = heap_beginscan(relation, 0, NowTimeQual, 3, operatorKey);
tup = heap_getnext(scan, 0, &buffer);
if (HeapTupleIsValid(tup))
{
#ifndef NO_SECURITY
userName = GetPgUserName();
if (!pg_ownercheck(userName,
(char *) ObjectIdGetDatum(tup->t_oid),
OPROID))
elog(WARN, "RemoveOperator: operator '%s': permission denied",
operatorName);
userName = GetPgUserName();
if (!pg_ownercheck(userName,
(char *) ObjectIdGetDatum(tup->t_oid),
OPROID))
elog(WARN, "RemoveOperator: operator '%s': permission denied",
operatorName);
#endif
ItemPointerCopy(&tup->t_ctid, &itemPointerData);
heap_delete(relation, &itemPointerData);
} else {
if (OidIsValid(typeId1) && OidIsValid(typeId2)) {
elog(WARN, "RemoveOperator: binary operator '%s' taking '%s' and '%s' does not exist",
operatorName,
typeName1,
typeName2);
} else if (OidIsValid(typeId1)) {
elog(WARN, "RemoveOperator: right unary operator '%s' taking '%s' does not exist",
operatorName,
typeName1);
} else {
elog(WARN, "RemoveOperator: left unary operator '%s' taking '%s' does not exist",
operatorName,
typeName2);
ItemPointerCopy(&tup->t_ctid, &itemPointerData);
heap_delete(relation, &itemPointerData);
}
}
heap_endscan(scan);
heap_close(relation);
else
{
if (OidIsValid(typeId1) && OidIsValid(typeId2))
{
elog(WARN, "RemoveOperator: binary operator '%s' taking '%s' and '%s' does not exist",
operatorName,
typeName1,
typeName2);
}
else if (OidIsValid(typeId1))
{
elog(WARN, "RemoveOperator: right unary operator '%s' taking '%s' does not exist",
operatorName,
typeName1);
}
else
{
elog(WARN, "RemoveOperator: left unary operator '%s' taking '%s' does not exist",
operatorName,
typeName2);
}
}
heap_endscan(scan);
heap_close(relation);
}
#ifdef NOTYET
@ -130,353 +142,379 @@ RemoveOperator(char *operatorName, /* operator name */
* don't use it - pma 2/1/94
*/
/*
* SingleOpOperatorRemove
* Removes all operators that have operands or a result of type 'typeOid'.
* SingleOpOperatorRemove
* Removes all operators that have operands or a result of type 'typeOid'.
*/
static void
SingleOpOperatorRemove(Oid typeOid)
{
Relation rdesc;
ScanKeyData key[3];
HeapScanDesc sdesc;
HeapTuple tup;
ItemPointerData itemPointerData;
Buffer buffer;
static attnums[3] = { 7, 8, 9 }; /* left, right, return */
register i;
ScanKeyEntryInitialize(&key[0],
0, 0, ObjectIdEqualRegProcedure, (Datum)typeOid);
rdesc = heap_openr(OperatorRelationName);
for (i = 0; i < 3; ++i) {
key[0].sk_attno = attnums[i];
sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 1, key);
while (PointerIsValid(tup = heap_getnext(sdesc, 0, &buffer))) {
ItemPointerCopy(&tup->t_ctid, &itemPointerData);
/* XXX LOCK not being passed */
heap_delete(rdesc, &itemPointerData);
Relation rdesc;
ScanKeyData key[3];
HeapScanDesc sdesc;
HeapTuple tup;
ItemPointerData itemPointerData;
Buffer buffer;
static attnums[3] = {7, 8, 9}; /* left, right, return */
register i;
ScanKeyEntryInitialize(&key[0],
0, 0, ObjectIdEqualRegProcedure, (Datum) typeOid);
rdesc = heap_openr(OperatorRelationName);
for (i = 0; i < 3; ++i)
{
key[0].sk_attno = attnums[i];
sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 1, key);
while (PointerIsValid(tup = heap_getnext(sdesc, 0, &buffer)))
{
ItemPointerCopy(&tup->t_ctid, &itemPointerData);
/* XXX LOCK not being passed */
heap_delete(rdesc, &itemPointerData);
}
heap_endscan(sdesc);
}
heap_endscan(sdesc);
}
heap_close(rdesc);
heap_close(rdesc);
}
/*
* AttributeAndRelationRemove
* Removes all entries in the attribute and relation relations
* that contain entries of type 'typeOid'.
* Currently nothing calls this code, it is untested.
* AttributeAndRelationRemove
* Removes all entries in the attribute and relation relations
* that contain entries of type 'typeOid'.
* Currently nothing calls this code, it is untested.
*/
static void
AttributeAndRelationRemove(Oid typeOid)
{
struct oidlist {
Oid reloid;
struct oidlist *next;
};
struct oidlist *oidptr, *optr;
Relation rdesc;
ScanKeyData key[1];
HeapScanDesc sdesc;
HeapTuple tup;
ItemPointerData itemPointerData;
Buffer buffer;
/*
* Get the oid's of the relations to be removed by scanning the
* entire attribute relation.
* We don't need to remove the attributes here,
* because amdestroy will remove all attributes of the relation.
* XXX should check for duplicate relations
*/
ScanKeyEntryInitialize(&key[0],
0, 3, ObjectIdEqualRegProcedure, (Datum)typeOid);
oidptr = (struct oidlist *) palloc(sizeof(*oidptr));
oidptr->next = NULL;
optr = oidptr;
rdesc = heap_openr(AttributeRelationName);
sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 1, key);
while (PointerIsValid(tup = heap_getnext(sdesc, 0, &buffer))) {
ItemPointerCopy(&tup->t_ctid, &itemPointerData);
optr->reloid = ((AttributeTupleForm)GETSTRUCT(tup))->attrelid;
optr->next = (struct oidlist *) palloc(sizeof(*oidptr));
optr = optr->next;
}
optr->next = NULL;
heap_endscan(sdesc);
heap_close(rdesc);
ScanKeyEntryInitialize(&key[0], 0,
ObjectIdAttributeNumber,
ObjectIdEqualRegProcedure, (Datum)0);
optr = oidptr;
rdesc = heap_openr(RelationRelationName);
while (PointerIsValid((char *) optr->next)) {
key[0].sk_argument = (Datum) (optr++)->reloid;
struct oidlist
{
Oid reloid;
struct oidlist *next;
};
struct oidlist *oidptr,
*optr;
Relation rdesc;
ScanKeyData key[1];
HeapScanDesc sdesc;
HeapTuple tup;
ItemPointerData itemPointerData;
Buffer buffer;
/*
* Get the oid's of the relations to be removed by scanning the entire
* attribute relation. We don't need to remove the attributes here,
* because amdestroy will remove all attributes of the relation. XXX
* should check for duplicate relations
*/
ScanKeyEntryInitialize(&key[0],
0, 3, ObjectIdEqualRegProcedure, (Datum) typeOid);
oidptr = (struct oidlist *) palloc(sizeof(*oidptr));
oidptr->next = NULL;
optr = oidptr;
rdesc = heap_openr(AttributeRelationName);
sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 1, key);
tup = heap_getnext(sdesc, 0, &buffer);
if (PointerIsValid(tup)) {
char *name;
name = (((Form_pg_class)GETSTRUCT(tup))->relname).data;
heap_destroy(name);
while (PointerIsValid(tup = heap_getnext(sdesc, 0, &buffer)))
{
ItemPointerCopy(&tup->t_ctid, &itemPointerData);
optr->reloid = ((AttributeTupleForm) GETSTRUCT(tup))->attrelid;
optr->next = (struct oidlist *) palloc(sizeof(*oidptr));
optr = optr->next;
}
}
heap_endscan(sdesc);
heap_close(rdesc);
optr->next = NULL;
heap_endscan(sdesc);
heap_close(rdesc);
ScanKeyEntryInitialize(&key[0], 0,
ObjectIdAttributeNumber,
ObjectIdEqualRegProcedure, (Datum) 0);
optr = oidptr;
rdesc = heap_openr(RelationRelationName);
while (PointerIsValid((char *) optr->next))
{
key[0].sk_argument = (Datum) (optr++)->reloid;
sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 1, key);
tup = heap_getnext(sdesc, 0, &buffer);
if (PointerIsValid(tup))
{
char *name;
name = (((Form_pg_class) GETSTRUCT(tup))->relname).data;
heap_destroy(name);
}
}
heap_endscan(sdesc);
heap_close(rdesc);
}
#endif /* NOTYET */
#endif /* NOTYET */
/*
* TypeRemove
* Removes the type 'typeName' and all attributes and relations that
* use it.
* TypeRemove
* Removes the type 'typeName' and all attributes and relations that
* use it.
*/
void
RemoveType(char *typeName) /* type name to be removed */
RemoveType(char *typeName) /* type name to be removed */
{
Relation relation;
HeapScanDesc scan;
HeapTuple tup;
Oid typeOid;
ItemPointerData itemPointerData;
static ScanKeyData typeKey[1] = {
{ 0, Anum_pg_type_typname, NameEqualRegProcedure }
};
char *shadow_type;
char *userName;
Relation relation;
HeapScanDesc scan;
HeapTuple tup;
Oid typeOid;
ItemPointerData itemPointerData;
static ScanKeyData typeKey[1] = {
{0, Anum_pg_type_typname, NameEqualRegProcedure}
};
char *shadow_type;
char *userName;
#ifndef NO_SECURITY
userName = GetPgUserName();
if (!pg_ownercheck(userName, typeName, TYPNAME))
elog(WARN, "RemoveType: type '%s': permission denied",
typeName);
userName = GetPgUserName();
if (!pg_ownercheck(userName, typeName, TYPNAME))
elog(WARN, "RemoveType: type '%s': permission denied",
typeName);
#endif
relation = heap_openr(TypeRelationName);
fmgr_info(typeKey[0].sk_procedure, &typeKey[0].sk_func,
&typeKey[0].sk_nargs);
/* Delete the primary type */
typeKey[0].sk_argument = PointerGetDatum(typeName);
scan = heap_beginscan(relation, 0, NowTimeQual, 1, typeKey);
tup = heap_getnext(scan, 0, (Buffer *) 0);
if (!HeapTupleIsValid(tup)) {
heap_endscan(scan);
heap_close(relation);
elog(WARN, "RemoveType: type '%s' does not exist",
typeName);
}
typeOid = tup->t_oid;
ItemPointerCopy(&tup->t_ctid, &itemPointerData);
heap_delete(relation, &itemPointerData);
heap_endscan(scan);
/* Now, Delete the "array of" that type */
shadow_type = makeArrayTypeName(typeName);
typeKey[0].sk_argument = NameGetDatum(shadow_type);
scan = heap_beginscan(relation, 0, NowTimeQual,
1, (ScanKey) typeKey);
tup = heap_getnext(scan, 0, (Buffer *) 0);
if (!HeapTupleIsValid(tup))
relation = heap_openr(TypeRelationName);
fmgr_info(typeKey[0].sk_procedure, &typeKey[0].sk_func,
&typeKey[0].sk_nargs);
/* Delete the primary type */
typeKey[0].sk_argument = PointerGetDatum(typeName);
scan = heap_beginscan(relation, 0, NowTimeQual, 1, typeKey);
tup = heap_getnext(scan, 0, (Buffer *) 0);
if (!HeapTupleIsValid(tup))
{
elog(WARN, "RemoveType: type '%s': array stub not found",
typeName);
heap_endscan(scan);
heap_close(relation);
elog(WARN, "RemoveType: type '%s' does not exist",
typeName);
}
typeOid = tup->t_oid;
ItemPointerCopy(&tup->t_ctid, &itemPointerData);
heap_delete(relation, &itemPointerData);
heap_endscan(scan);
heap_close(relation);
typeOid = tup->t_oid;
ItemPointerCopy(&tup->t_ctid, &itemPointerData);
heap_delete(relation, &itemPointerData);
heap_endscan(scan);
/* Now, Delete the "array of" that type */
shadow_type = makeArrayTypeName(typeName);
typeKey[0].sk_argument = NameGetDatum(shadow_type);
scan = heap_beginscan(relation, 0, NowTimeQual,
1, (ScanKey) typeKey);
tup = heap_getnext(scan, 0, (Buffer *) 0);
if (!HeapTupleIsValid(tup))
{
elog(WARN, "RemoveType: type '%s': array stub not found",
typeName);
}
typeOid = tup->t_oid;
ItemPointerCopy(&tup->t_ctid, &itemPointerData);
heap_delete(relation, &itemPointerData);
heap_endscan(scan);
heap_close(relation);
}
/*
* RemoveFunction --
* Deletes a function.
* Deletes a function.
*
* Exceptions:
* BadArg if name is invalid.
* "WARN" if function nonexistent.
* ...
* BadArg if name is invalid.
* "WARN" if function nonexistent.
* ...
*/
void
RemoveFunction(char *functionName, /* function name to be removed */
int nargs,
List *argNameList /* list of TypeNames */)
RemoveFunction(char *functionName, /* function name to be removed */
int nargs,
List * argNameList /* list of TypeNames */ )
{
Relation relation;
HeapScanDesc scan;
HeapTuple tup;
Buffer buffer = InvalidBuffer;
bool bufferUsed = FALSE;
Oid argList[8];
Form_pg_proc the_proc = NULL;
ItemPointerData itemPointerData;
static ScanKeyData key[3] = {
{ 0, Anum_pg_proc_proname, NameEqualRegProcedure }
};
char *userName;
char *typename;
int i;
memset(argList, 0, 8 * sizeof(Oid));
for (i=0; i<nargs; i++) {
/* typename = ((TypeName*)(lfirst(argNameList)))->name; */
typename = strVal(lfirst(argNameList));
argNameList = lnext(argNameList);
if (strcmp(typename, "opaque") == 0)
argList[i] = 0;
else {
tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(typename),
0,0,0);
if (!HeapTupleIsValid(tup)) {
elog(WARN, "RemoveFunction: type '%s' not found",typename);
}
argList[i] = tup->t_oid;
Relation relation;
HeapScanDesc scan;
HeapTuple tup;
Buffer buffer = InvalidBuffer;
bool bufferUsed = FALSE;
Oid argList[8];
Form_pg_proc the_proc = NULL;
ItemPointerData itemPointerData;
static ScanKeyData key[3] = {
{0, Anum_pg_proc_proname, NameEqualRegProcedure}
};
char *userName;
char *typename;
int i;
memset(argList, 0, 8 * sizeof(Oid));
for (i = 0; i < nargs; i++)
{
/* typename = ((TypeName*)(lfirst(argNameList)))->name; */
typename = strVal(lfirst(argNameList));
argNameList = lnext(argNameList);
if (strcmp(typename, "opaque") == 0)
argList[i] = 0;
else
{
tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(typename),
0, 0, 0);
if (!HeapTupleIsValid(tup))
{
elog(WARN, "RemoveFunction: type '%s' not found", typename);
}
argList[i] = tup->t_oid;
}
}
}
tup = SearchSysCacheTuple(PRONAME, PointerGetDatum(functionName),
Int32GetDatum(nargs),
PointerGetDatum(argList),0);
if (!HeapTupleIsValid(tup))
func_error("RemoveFunction", functionName, nargs, argList);
#ifndef NO_SECURITY
userName = GetPgUserName();
if (!pg_func_ownercheck(userName, functionName, nargs, argList)) {
elog(WARN, "RemoveFunction: function '%s': permission denied",
functionName);
}
#endif
key[0].sk_argument = PointerGetDatum(functionName);
fmgr_info(key[0].sk_procedure, &key[0].sk_func, &key[0].sk_nargs);
relation = heap_openr(ProcedureRelationName);
scan = heap_beginscan(relation, 0, NowTimeQual, 1, key);
do { /* hope this is ok because it's indexed */
if (bufferUsed) {
ReleaseBuffer(buffer);
bufferUsed = FALSE;
}
tup = heap_getnext(scan, 0, (Buffer *) &buffer);
tup = SearchSysCacheTuple(PRONAME, PointerGetDatum(functionName),
Int32GetDatum(nargs),
PointerGetDatum(argList), 0);
if (!HeapTupleIsValid(tup))
break;
bufferUsed = TRUE;
the_proc = (Form_pg_proc) GETSTRUCT(tup);
} while ( (namestrcmp(&(the_proc->proname), functionName) == 0) &&
(the_proc->pronargs != nargs ||
!oid8eq(&(the_proc->proargtypes[0]), &argList[0])));
if (!HeapTupleIsValid(tup) || namestrcmp(&(the_proc->proname),
functionName) != 0)
{
heap_endscan(scan);
heap_close(relation);
func_error("RemoveFunction", functionName,nargs, argList);
func_error("RemoveFunction", functionName, nargs, argList);
#ifndef NO_SECURITY
userName = GetPgUserName();
if (!pg_func_ownercheck(userName, functionName, nargs, argList))
{
elog(WARN, "RemoveFunction: function '%s': permission denied",
functionName);
}
/* ok, function has been found */
if (the_proc->prolang == INTERNALlanguageId)
elog(WARN, "RemoveFunction: function \"%s\" is built-in",
functionName);
ItemPointerCopy(&tup->t_ctid, &itemPointerData);
heap_delete(relation, &itemPointerData);
heap_endscan(scan);
heap_close(relation);
#endif
key[0].sk_argument = PointerGetDatum(functionName);
fmgr_info(key[0].sk_procedure, &key[0].sk_func, &key[0].sk_nargs);
relation = heap_openr(ProcedureRelationName);
scan = heap_beginscan(relation, 0, NowTimeQual, 1, key);
do
{ /* hope this is ok because it's indexed */
if (bufferUsed)
{
ReleaseBuffer(buffer);
bufferUsed = FALSE;
}
tup = heap_getnext(scan, 0, (Buffer *) & buffer);
if (!HeapTupleIsValid(tup))
break;
bufferUsed = TRUE;
the_proc = (Form_pg_proc) GETSTRUCT(tup);
} while ((namestrcmp(&(the_proc->proname), functionName) == 0) &&
(the_proc->pronargs != nargs ||
!oid8eq(&(the_proc->proargtypes[0]), &argList[0])));
if (!HeapTupleIsValid(tup) || namestrcmp(&(the_proc->proname),
functionName) != 0)
{
heap_endscan(scan);
heap_close(relation);
func_error("RemoveFunction", functionName, nargs, argList);
}
/* ok, function has been found */
if (the_proc->prolang == INTERNALlanguageId)
elog(WARN, "RemoveFunction: function \"%s\" is built-in",
functionName);
ItemPointerCopy(&tup->t_ctid, &itemPointerData);
heap_delete(relation, &itemPointerData);
heap_endscan(scan);
heap_close(relation);
}
void
RemoveAggregate(char *aggName, char *aggType)
{
Relation relation;
HeapScanDesc scan;
HeapTuple tup;
ItemPointerData itemPointerData;
char *userName;
Oid basetypeID = InvalidOid;
bool defined;
ScanKeyData aggregateKey[3];
Relation relation;
HeapScanDesc scan;
HeapTuple tup;
ItemPointerData itemPointerData;
char *userName;
Oid basetypeID = InvalidOid;
bool defined;
ScanKeyData aggregateKey[3];
/*
* if a basetype is passed in, then attempt to find an aggregate for that
* specific type.
*
* else if the basetype is blank, then attempt to find an aggregate with a
* basetype of zero. This is valid. It means that the aggregate is to apply
* to all basetypes. ie, a counter of some sort.
*
*/
if (aggType) {
basetypeID = TypeGet(aggType, &defined);
if (!OidIsValid(basetypeID)) {
elog(WARN, "RemoveAggregate: type '%s' does not exist", aggType);
}
} else {
basetypeID = 0;
}
/*
* if a basetype is passed in, then attempt to find an aggregate for
* that specific type.
*
* else if the basetype is blank, then attempt to find an aggregate with
* a basetype of zero. This is valid. It means that the aggregate is
* to apply to all basetypes. ie, a counter of some sort.
*
*/
if (aggType)
{
basetypeID = TypeGet(aggType, &defined);
if (!OidIsValid(basetypeID))
{
elog(WARN, "RemoveAggregate: type '%s' does not exist", aggType);
}
}
else
{
basetypeID = 0;
}
/*
#ifndef NO_SECURITY
*/
userName = GetPgUserName();
if (!pg_aggr_ownercheck(userName, aggName, basetypeID)) {
if (aggType) {
elog(WARN, "RemoveAggregate: aggregate '%s' on type '%s': permission denied",
aggName, aggType);
} else {
elog(WARN, "RemoveAggregate: aggregate '%s': permission denied",
aggName);
}
}
userName = GetPgUserName();
if (!pg_aggr_ownercheck(userName, aggName, basetypeID))
{
if (aggType)
{
elog(WARN, "RemoveAggregate: aggregate '%s' on type '%s': permission denied",
aggName, aggType);
}
else
{
elog(WARN, "RemoveAggregate: aggregate '%s': permission denied",
aggName);
}
}
/*
#endif
*/
ScanKeyEntryInitialize(&aggregateKey[0], 0x0,
Anum_pg_aggregate_aggname,
NameEqualRegProcedure,
PointerGetDatum(aggName));
ScanKeyEntryInitialize(&aggregateKey[1], 0x0,
Anum_pg_aggregate_aggbasetype,
ObjectIdEqualRegProcedure,
ObjectIdGetDatum(basetypeID));
relation = heap_openr(AggregateRelationName);
scan = heap_beginscan(relation, 0, NowTimeQual, 2, aggregateKey);
tup = heap_getnext(scan, 0, (Buffer *) 0);
if (!HeapTupleIsValid(tup)) {
heap_endscan(scan);
heap_close(relation);
if (aggType) {
elog(WARN, "RemoveAggregate: aggregate '%s' for '%s' does not exist",
aggName, aggType);
} else {
elog(WARN, "RemoveAggregate: aggregate '%s' for all types does not exist",
aggName);
}
}
ItemPointerCopy(&tup->t_ctid, &itemPointerData);
heap_delete(relation, &itemPointerData);
heap_endscan(scan);
heap_close(relation);
ScanKeyEntryInitialize(&aggregateKey[0], 0x0,
Anum_pg_aggregate_aggname,
NameEqualRegProcedure,
PointerGetDatum(aggName));
ScanKeyEntryInitialize(&aggregateKey[1], 0x0,
Anum_pg_aggregate_aggbasetype,
ObjectIdEqualRegProcedure,
ObjectIdGetDatum(basetypeID));
relation = heap_openr(AggregateRelationName);
scan = heap_beginscan(relation, 0, NowTimeQual, 2, aggregateKey);
tup = heap_getnext(scan, 0, (Buffer *) 0);
if (!HeapTupleIsValid(tup))
{
heap_endscan(scan);
heap_close(relation);
if (aggType)
{
elog(WARN, "RemoveAggregate: aggregate '%s' for '%s' does not exist",
aggName, aggType);
}
else
{
elog(WARN, "RemoveAggregate: aggregate '%s' for all types does not exist",
aggName);
}
}
ItemPointerCopy(&tup->t_ctid, &itemPointerData);
heap_delete(relation, &itemPointerData);
heap_endscan(scan);
heap_close(relation);
}

View File

@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* rename.c--
* renameatt() and renamerel() reside here.
* renameatt() and renamerel() reside here.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.7 1997/08/18 20:52:18 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/rename.c,v 1.8 1997/09/07 04:40:55 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -32,227 +32,246 @@
#include <catalog/pg_proc.h>
#include <catalog/pg_class.h>
#include <optimizer/internal.h>
#include <optimizer/prep.h> /* for find_all_inheritors */
#include <optimizer/prep.h> /* for find_all_inheritors */
#ifndef NO_SECURITY
# include <utils/acl.h>
#endif /* !NO_SECURITY */
#include <utils/acl.h>
#endif /* !NO_SECURITY */
#ifndef HAVE_MEMMOVE
# include <regex/utils.h>
#include <regex/utils.h>
#else
# include <string.h>
#include <string.h>
#endif
/*
* renameatt - changes the name of a attribute in a relation
* renameatt - changes the name of a attribute in a relation
*
* Attname attribute is changed in attribute catalog.
* No record of the previous attname is kept (correct?).
* Attname attribute is changed in attribute catalog.
* No record of the previous attname is kept (correct?).
*
* get proper reldesc from relation catalog (if not arg)
* scan attribute catalog
* for name conflict (within rel)
* for original attribute (if not arg)
* modify attname in attribute tuple
* insert modified attribute in attribute catalog
* delete original attribute from attribute catalog
* get proper reldesc from relation catalog (if not arg)
* scan attribute catalog
* for name conflict (within rel)
* for original attribute (if not arg)
* modify attname in attribute tuple
* insert modified attribute in attribute catalog
* delete original attribute from attribute catalog
*
* XXX Renaming an indexed attribute must (eventually) also change
* the attribute name in the associated indexes.
* XXX Renaming an indexed attribute must (eventually) also change
* the attribute name in the associated indexes.
*/
void
renameatt(char *relname,
char *oldattname,
char *newattname,
char *userName,
int recurse)
char *oldattname,
char *newattname,
char *userName,
int recurse)
{
Relation relrdesc, attrdesc;
HeapTuple reltup, oldatttup, newatttup;
ItemPointerData oldTID;
Relation idescs[Num_pg_attr_indices];
/*
* permissions checking. this would normally be done in utility.c,
* but this particular routine is recursive.
*
* normally, only the owner of a class can change its schema.
*/
if (IsSystemRelationName(relname))
elog(WARN, "renameatt: class \"%s\" is a system catalog",
relname);
#ifndef NO_SECURITY
if (!IsBootstrapProcessingMode() &&
!pg_ownercheck(userName, relname, RELNAME))
elog(WARN, "renameatt: you do not own class \"%s\"",
relname);
#endif
/*
* if the 'recurse' flag is set then we are supposed to rename this
* attribute in all classes that inherit from 'relname' (as well as
* in 'relname').
*
* any permissions or problems with duplicate attributes will cause
* the whole transaction to abort, which is what we want -- all or
* nothing.
*/
if (recurse) {
Oid myrelid, childrelid;
List *child, *children;
relrdesc = heap_openr(relname);
if (!RelationIsValid(relrdesc)) {
elog(WARN, "renameatt: unknown relation: \"%s\"",
relname);
}
myrelid = relrdesc->rd_id;
heap_close(relrdesc);
/* this routine is actually in the planner */
children = find_all_inheritors(lconsi(myrelid, NIL), NIL);
Relation relrdesc,
attrdesc;
HeapTuple reltup,
oldatttup,
newatttup;
ItemPointerData oldTID;
Relation idescs[Num_pg_attr_indices];
/*
* find_all_inheritors does the recursive search of the
* inheritance hierarchy, so all we have to do is process
* all of the relids in the list that it returns.
* permissions checking. this would normally be done in utility.c,
* but this particular routine is recursive.
*
* normally, only the owner of a class can change its schema.
*/
foreach (child, children) {
char *childname;
childrelid = lfirsti(child);
if (childrelid == myrelid)
continue;
relrdesc = heap_open(childrelid);
if (!RelationIsValid(relrdesc)) {
elog(WARN, "renameatt: can't find catalog entry for inheriting class with oid %d",
childrelid);
}
childname = (relrdesc->rd_rel->relname).data;
heap_close(relrdesc);
renameatt(childname, oldattname, newattname,
userName, 0); /* no more recursion! */
if (IsSystemRelationName(relname))
elog(WARN, "renameatt: class \"%s\" is a system catalog",
relname);
#ifndef NO_SECURITY
if (!IsBootstrapProcessingMode() &&
!pg_ownercheck(userName, relname, RELNAME))
elog(WARN, "renameatt: you do not own class \"%s\"",
relname);
#endif
/*
* if the 'recurse' flag is set then we are supposed to rename this
* attribute in all classes that inherit from 'relname' (as well as in
* 'relname').
*
* any permissions or problems with duplicate attributes will cause the
* whole transaction to abort, which is what we want -- all or
* nothing.
*/
if (recurse)
{
Oid myrelid,
childrelid;
List *child,
*children;
relrdesc = heap_openr(relname);
if (!RelationIsValid(relrdesc))
{
elog(WARN, "renameatt: unknown relation: \"%s\"",
relname);
}
myrelid = relrdesc->rd_id;
heap_close(relrdesc);
/* this routine is actually in the planner */
children = find_all_inheritors(lconsi(myrelid, NIL), NIL);
/*
* find_all_inheritors does the recursive search of the
* inheritance hierarchy, so all we have to do is process all of
* the relids in the list that it returns.
*/
foreach(child, children)
{
char *childname;
childrelid = lfirsti(child);
if (childrelid == myrelid)
continue;
relrdesc = heap_open(childrelid);
if (!RelationIsValid(relrdesc))
{
elog(WARN, "renameatt: can't find catalog entry for inheriting class with oid %d",
childrelid);
}
childname = (relrdesc->rd_rel->relname).data;
heap_close(relrdesc);
renameatt(childname, oldattname, newattname,
userName, 0); /* no more recursion! */
}
}
relrdesc = heap_openr(RelationRelationName);
reltup = ClassNameIndexScan(relrdesc, relname);
if (!PointerIsValid(reltup))
{
heap_close(relrdesc);
elog(WARN, "renameatt: relation \"%s\" nonexistent",
relname);
return;
}
}
relrdesc = heap_openr(RelationRelationName);
reltup = ClassNameIndexScan(relrdesc, relname);
if (!PointerIsValid(reltup)) {
heap_close(relrdesc);
elog(WARN, "renameatt: relation \"%s\" nonexistent",
relname);
return;
}
heap_close(relrdesc);
attrdesc = heap_openr(AttributeRelationName);
oldatttup = AttributeNameIndexScan(attrdesc, reltup->t_oid, oldattname);
if (!PointerIsValid(oldatttup)) {
attrdesc = heap_openr(AttributeRelationName);
oldatttup = AttributeNameIndexScan(attrdesc, reltup->t_oid, oldattname);
if (!PointerIsValid(oldatttup))
{
heap_close(attrdesc);
elog(WARN, "renameatt: attribute \"%s\" nonexistent",
oldattname);
}
if (((AttributeTupleForm) GETSTRUCT(oldatttup))->attnum < 0)
{
elog(WARN, "renameatt: system attribute \"%s\" not renamed",
oldattname);
}
newatttup = AttributeNameIndexScan(attrdesc, reltup->t_oid, newattname);
if (PointerIsValid(newatttup))
{
pfree(oldatttup);
heap_close(attrdesc);
elog(WARN, "renameatt: attribute \"%s\" exists",
newattname);
}
namestrcpy(&(((AttributeTupleForm) (GETSTRUCT(oldatttup)))->attname),
newattname);
oldTID = oldatttup->t_ctid;
/* insert "fixed" tuple */
heap_replace(attrdesc, &oldTID, oldatttup);
/* keep system catalog indices current */
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
CatalogIndexInsert(idescs, Num_pg_attr_indices, attrdesc, oldatttup);
CatalogCloseIndices(Num_pg_attr_indices, idescs);
heap_close(attrdesc);
elog(WARN, "renameatt: attribute \"%s\" nonexistent",
oldattname);
}
if (((AttributeTupleForm ) GETSTRUCT(oldatttup))->attnum < 0) {
elog(WARN, "renameatt: system attribute \"%s\" not renamed",
oldattname);
}
newatttup = AttributeNameIndexScan(attrdesc, reltup->t_oid, newattname);
if (PointerIsValid(newatttup)) {
pfree(oldatttup);
heap_close(attrdesc);
elog(WARN, "renameatt: attribute \"%s\" exists",
newattname);
}
namestrcpy(&(((AttributeTupleForm)(GETSTRUCT(oldatttup)))->attname),
newattname);
oldTID = oldatttup->t_ctid;
/* insert "fixed" tuple */
heap_replace(attrdesc, &oldTID, oldatttup);
/* keep system catalog indices current */
CatalogOpenIndices(Num_pg_attr_indices, Name_pg_attr_indices, idescs);
CatalogIndexInsert(idescs, Num_pg_attr_indices, attrdesc, oldatttup);
CatalogCloseIndices(Num_pg_attr_indices, idescs);
heap_close(attrdesc);
pfree(oldatttup);
}
/*
* renamerel - change the name of a relation
* renamerel - change the name of a relation
*
* Relname attribute is changed in relation catalog.
* No record of the previous relname is kept (correct?).
* Relname attribute is changed in relation catalog.
* No record of the previous relname is kept (correct?).
*
* scan relation catalog
* for name conflict
* for original relation (if not arg)
* modify relname in relation tuple
* insert modified relation in relation catalog
* delete original relation from relation catalog
* scan relation catalog
* for name conflict
* for original relation (if not arg)
* modify relname in relation tuple
* insert modified relation in relation catalog
* delete original relation from relation catalog
*
* XXX Will currently lose track of a relation if it is unable to
* properly replace the new relation tuple.
* XXX Will currently lose track of a relation if it is unable to
* properly replace the new relation tuple.
*/
void
renamerel(char oldrelname[], char newrelname[])
{
Relation relrdesc; /* for RELATION relation */
HeapTuple oldreltup, newreltup;
ItemPointerData oldTID;
char oldpath[MAXPGPATH], newpath[MAXPGPATH];
Relation idescs[Num_pg_class_indices];
if (IsSystemRelationName(oldrelname)) {
elog(WARN, "renamerel: system relation \"%s\" not renamed",
oldrelname);
return;
}
if (IsSystemRelationName(newrelname)) {
elog(WARN, "renamerel: Illegal class name: \"%s\" -- pg_ is reserved for system catalogs",
newrelname);
return;
}
relrdesc = heap_openr(RelationRelationName);
oldreltup = ClassNameIndexScan(relrdesc, oldrelname);
if (!PointerIsValid(oldreltup)) {
heap_close(relrdesc);
elog(WARN, "renamerel: relation \"%s\" does not exist",
oldrelname);
}
newreltup = ClassNameIndexScan(relrdesc, newrelname);
if (PointerIsValid(newreltup)) {
Relation relrdesc; /* for RELATION relation */
HeapTuple oldreltup,
newreltup;
ItemPointerData oldTID;
char oldpath[MAXPGPATH],
newpath[MAXPGPATH];
Relation idescs[Num_pg_class_indices];
if (IsSystemRelationName(oldrelname))
{
elog(WARN, "renamerel: system relation \"%s\" not renamed",
oldrelname);
return;
}
if (IsSystemRelationName(newrelname))
{
elog(WARN, "renamerel: Illegal class name: \"%s\" -- pg_ is reserved for system catalogs",
newrelname);
return;
}
relrdesc = heap_openr(RelationRelationName);
oldreltup = ClassNameIndexScan(relrdesc, oldrelname);
if (!PointerIsValid(oldreltup))
{
heap_close(relrdesc);
elog(WARN, "renamerel: relation \"%s\" does not exist",
oldrelname);
}
newreltup = ClassNameIndexScan(relrdesc, newrelname);
if (PointerIsValid(newreltup))
{
pfree(oldreltup);
heap_close(relrdesc);
elog(WARN, "renamerel: relation \"%s\" exists",
newrelname);
}
/* rename the directory first, so if this fails the rename's not done */
strcpy(oldpath, relpath(oldrelname));
strcpy(newpath, relpath(newrelname));
if (rename(oldpath, newpath) < 0)
elog(WARN, "renamerel: unable to rename file: %m");
memmove((char *) (((Form_pg_class) GETSTRUCT(oldreltup))->relname.data),
newrelname,
NAMEDATALEN);
oldTID = oldreltup->t_ctid;
/* insert fixed rel tuple */
heap_replace(relrdesc, &oldTID, oldreltup);
/* keep the system catalog indices current */
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
CatalogIndexInsert(idescs, Num_pg_class_indices, relrdesc, oldreltup);
CatalogCloseIndices(Num_pg_class_indices, idescs);
pfree(oldreltup);
heap_close(relrdesc);
elog(WARN, "renamerel: relation \"%s\" exists",
newrelname);
}
/* rename the directory first, so if this fails the rename's not done */
strcpy(oldpath, relpath(oldrelname));
strcpy(newpath, relpath(newrelname));
if (rename(oldpath, newpath) < 0)
elog(WARN, "renamerel: unable to rename file: %m");
memmove((char *) (((Form_pg_class) GETSTRUCT(oldreltup))->relname.data),
newrelname,
NAMEDATALEN);
oldTID = oldreltup->t_ctid;
/* insert fixed rel tuple */
heap_replace(relrdesc, &oldTID, oldreltup);
/* keep the system catalog indices current */
CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, idescs);
CatalogIndexInsert(idescs, Num_pg_class_indices, relrdesc, oldreltup);
CatalogCloseIndices(Num_pg_class_indices, idescs);
pfree(oldreltup);
heap_close(relrdesc);
}

View File

@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* sequence.c--
* PostgreSQL sequences support code.
* PostgreSQL sequences support code.
*
*-------------------------------------------------------------------------
*/
@ -19,523 +19,539 @@
#include <commands/sequence.h>
#include <utils/builtins.h>
#define SEQ_MAGIC 0x1717
#define SEQ_MAGIC 0x1717
#define SEQ_MAXVALUE ((int4)0x7FFFFFFF)
#define SEQ_MINVALUE -(SEQ_MAXVALUE)
bool ItsSequenceCreation = false;
bool ItsSequenceCreation = false;
typedef struct FormData_pg_sequence {
NameData sequence_name;
int4 last_value;
int4 increment_by;
int4 max_value;
int4 min_value;
int4 cache_value;
char is_cycled;
char is_called;
} FormData_pg_sequence;
typedef struct FormData_pg_sequence
{
NameData sequence_name;
int4 last_value;
int4 increment_by;
int4 max_value;
int4 min_value;
int4 cache_value;
char is_cycled;
char is_called;
} FormData_pg_sequence;
typedef FormData_pg_sequence *SequenceTupleForm;
typedef FormData_pg_sequence *SequenceTupleForm;
typedef struct sequence_magic {
uint32 magic;
} sequence_magic;
typedef struct sequence_magic
{
uint32 magic;
} sequence_magic;
typedef struct SeqTableData {
char *name;
Oid relid;
typedef struct SeqTableData
{
char *name;
Oid relid;
Relation rel;
int4 cached;
int4 last;
int4 increment;
struct SeqTableData *next;
} SeqTableData;
struct SeqTableData *next;
} SeqTableData;
typedef SeqTableData *SeqTable;
static SeqTable seqtab = NULL;
static SeqTable init_sequence (char *caller, char *name);
static SequenceTupleForm read_info (char * caller, SeqTable elm, Buffer * buf);
static void init_params (CreateSeqStmt *seq, SequenceTupleForm new);
static int get_param (DefElem *def);
static SeqTable init_sequence(char *caller, char *name);
static SequenceTupleForm read_info(char *caller, SeqTable elm, Buffer * buf);
static void init_params(CreateSeqStmt * seq, SequenceTupleForm new);
static int get_param(DefElem * def);
/*
* DefineSequence --
* Creates a new sequence relation
* Creates a new sequence relation
*/
void
DefineSequence (CreateSeqStmt *seq)
DefineSequence(CreateSeqStmt * seq)
{
FormData_pg_sequence new;
CreateStmt *stmt = makeNode (CreateStmt);
ColumnDef *coldef;
TypeName *typnam;
Relation rel;
Buffer buf;
PageHeader page;
sequence_magic *sm;
HeapTuple tuple;
TupleDesc tupDesc;
Datum value[SEQ_COL_LASTCOL];
char null[SEQ_COL_LASTCOL];
int i;
FormData_pg_sequence new;
CreateStmt *stmt = makeNode(CreateStmt);
ColumnDef *coldef;
TypeName *typnam;
Relation rel;
Buffer buf;
PageHeader page;
sequence_magic *sm;
HeapTuple tuple;
TupleDesc tupDesc;
Datum value[SEQ_COL_LASTCOL];
char null[SEQ_COL_LASTCOL];
int i;
/* Check and set values */
init_params (seq, &new);
/* Check and set values */
init_params(seq, &new);
/*
* Create relation (and fill null[] & value[])
*/
stmt->tableElts = NIL;
for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
{
typnam = makeNode(TypeName);
typnam->setof = FALSE;
typnam->arrayBounds = NULL;
coldef = makeNode(ColumnDef);
coldef->typename = typnam;
coldef->defval = NULL;
coldef->is_not_null = false;
null[i-1] = ' ';
switch (i)
/*
* Create relation (and fill null[] & value[])
*/
stmt->tableElts = NIL;
for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
{
case SEQ_COL_NAME:
typnam->name = "name";
coldef->colname = "sequence_name";
value[i-1] = PointerGetDatum (seq->seqname);
break;
case SEQ_COL_LASTVAL:
typnam->name = "int4";
coldef->colname = "last_value";
value[i-1] = Int32GetDatum (new.last_value);
break;
case SEQ_COL_INCBY:
typnam->name = "int4";
coldef->colname = "increment_by";
value[i-1] = Int32GetDatum (new.increment_by);
break;
case SEQ_COL_MAXVALUE:
typnam->name = "int4";
coldef->colname = "max_value";
value[i-1] = Int32GetDatum (new.max_value);
break;
case SEQ_COL_MINVALUE:
typnam->name = "int4";
coldef->colname = "min_value";
value[i-1] = Int32GetDatum (new.min_value);
break;
case SEQ_COL_CACHE:
typnam->name = "int4";
coldef->colname = "cache_value";
value[i-1] = Int32GetDatum (new.cache_value);
break;
case SEQ_COL_CYCLE:
typnam->name = "char";
coldef->colname = "is_cycled";
value[i-1] = CharGetDatum (new.is_cycled);
break;
case SEQ_COL_CALLED:
typnam->name = "char";
coldef->colname = "is_called";
value[i-1] = CharGetDatum ('f');
break;
}
stmt->tableElts = lappend (stmt->tableElts, coldef);
}
stmt->relname = seq->seqname;
stmt->archiveLoc = -1; /* default */
stmt->archiveType = ARCH_NONE;
stmt->inhRelnames = NIL;
stmt->constraints = NIL;
ItsSequenceCreation = true; /* hack */
typnam = makeNode(TypeName);
typnam->setof = FALSE;
typnam->arrayBounds = NULL;
coldef = makeNode(ColumnDef);
coldef->typename = typnam;
coldef->defval = NULL;
coldef->is_not_null = false;
null[i - 1] = ' ';
DefineRelation (stmt);
/* Xact abort calls CloseSequences, which turns ItsSequenceCreation off */
ItsSequenceCreation = false; /* hack */
rel = heap_openr (seq->seqname);
Assert ( RelationIsValid (rel) );
RelationSetLockForWrite (rel);
tupDesc = RelationGetTupleDescriptor(rel);
Assert ( RelationGetNumberOfBlocks (rel) == 0 );
buf = ReadBuffer (rel, P_NEW);
if ( !BufferIsValid (buf) )
elog (WARN, "DefineSequence: ReadBuffer failed");
page = (PageHeader) BufferGetPage (buf);
PageInit((Page)page, BufferGetPageSize(buf), sizeof(sequence_magic));
sm = (sequence_magic *) PageGetSpecialPointer (page);
sm->magic = SEQ_MAGIC;
/* Now - form & insert sequence tuple */
tuple = heap_formtuple (tupDesc, value, null);
heap_insert (rel, tuple);
if ( WriteBuffer (buf) == STATUS_ERROR )
elog (WARN, "DefineSequence: WriteBuffer failed");
RelationUnsetLockForWrite (rel);
heap_close (rel);
return;
}
int4
nextval (struct varlena * seqin)
{
char *seqname = textout(seqin);
SeqTable elm;
Buffer buf;
SequenceTupleForm seq;
ItemPointerData iptr;
int4 incby, maxv, minv, cache;
int4 result, next, rescnt = 0;
/* open and WIntentLock sequence */
elm = init_sequence ("nextval", seqname);
pfree (seqname);
if ( elm->last != elm->cached ) /* some numbers were cached */
{
elm->last += elm->increment;
return (elm->last);
}
seq = read_info ("nextval", elm, &buf); /* lock page and read tuple */
next = result = seq->last_value;
incby = seq->increment_by;
maxv = seq->max_value;
minv = seq->min_value;
cache = seq->cache_value;
if ( seq->is_called != 't' )
rescnt++; /* last_value if not called */
while ( rescnt < cache ) /* try to fetch cache numbers */
{
/*
* Check MAXVALUE for ascending sequences
* and MINVALUE for descending sequences
*/
if ( incby > 0 ) /* ascending sequence */
{
if ( ( maxv >= 0 && next > maxv - incby) ||
( maxv < 0 && next + incby > maxv ) )
{
if ( rescnt > 0 )
break; /* stop caching */
if ( seq->is_cycled != 't' )
elog (WARN, "%s.nextval: got MAXVALUE (%d)",
elm->name, maxv);
next = minv;
}
else
next += incby;
switch (i)
{
case SEQ_COL_NAME:
typnam->name = "name";
coldef->colname = "sequence_name";
value[i - 1] = PointerGetDatum(seq->seqname);
break;
case SEQ_COL_LASTVAL:
typnam->name = "int4";
coldef->colname = "last_value";
value[i - 1] = Int32GetDatum(new.last_value);
break;
case SEQ_COL_INCBY:
typnam->name = "int4";
coldef->colname = "increment_by";
value[i - 1] = Int32GetDatum(new.increment_by);
break;
case SEQ_COL_MAXVALUE:
typnam->name = "int4";
coldef->colname = "max_value";
value[i - 1] = Int32GetDatum(new.max_value);
break;
case SEQ_COL_MINVALUE:
typnam->name = "int4";
coldef->colname = "min_value";
value[i - 1] = Int32GetDatum(new.min_value);
break;
case SEQ_COL_CACHE:
typnam->name = "int4";
coldef->colname = "cache_value";
value[i - 1] = Int32GetDatum(new.cache_value);
break;
case SEQ_COL_CYCLE:
typnam->name = "char";
coldef->colname = "is_cycled";
value[i - 1] = CharGetDatum(new.is_cycled);
break;
case SEQ_COL_CALLED:
typnam->name = "char";
coldef->colname = "is_called";
value[i - 1] = CharGetDatum('f');
break;
}
stmt->tableElts = lappend(stmt->tableElts, coldef);
}
else /* descending sequence */
{
if ( ( minv < 0 && next < minv - incby ) ||
( minv >= 0 && next + incby < minv ) )
{
if ( rescnt > 0 )
break; /* stop caching */
if ( seq->is_cycled != 't' )
elog (WARN, "%s.nextval: got MINVALUE (%d)",
elm->name, minv);
next = maxv;
}
else
next += incby;
}
rescnt++; /* got result */
if ( rescnt == 1 ) /* if it's first one - */
result = next; /* it's what to return */
}
/* save info in local cache */
elm->last = result; /* last returned number */
elm->cached = next; /* last cached number */
stmt->relname = seq->seqname;
stmt->archiveLoc = -1; /* default */
stmt->archiveType = ARCH_NONE;
stmt->inhRelnames = NIL;
stmt->constraints = NIL;
/* save info in sequence relation */
seq->last_value = next; /* last fetched number */
seq->is_called = 't';
if ( WriteBuffer (buf) == STATUS_ERROR )
elog (WARN, "%s.nextval: WriteBuffer failed", elm->name);
ItsSequenceCreation = true; /* hack */
ItemPointerSet(&iptr, 0, FirstOffsetNumber);
RelationUnsetSingleWLockPage (elm->rel, &iptr);
DefineRelation(stmt);
/*
* Xact abort calls CloseSequences, which turns ItsSequenceCreation
* off
*/
ItsSequenceCreation = false;/* hack */
rel = heap_openr(seq->seqname);
Assert(RelationIsValid(rel));
RelationSetLockForWrite(rel);
tupDesc = RelationGetTupleDescriptor(rel);
Assert(RelationGetNumberOfBlocks(rel) == 0);
buf = ReadBuffer(rel, P_NEW);
if (!BufferIsValid(buf))
elog(WARN, "DefineSequence: ReadBuffer failed");
page = (PageHeader) BufferGetPage(buf);
PageInit((Page) page, BufferGetPageSize(buf), sizeof(sequence_magic));
sm = (sequence_magic *) PageGetSpecialPointer(page);
sm->magic = SEQ_MAGIC;
/* Now - form & insert sequence tuple */
tuple = heap_formtuple(tupDesc, value, null);
heap_insert(rel, tuple);
if (WriteBuffer(buf) == STATUS_ERROR)
elog(WARN, "DefineSequence: WriteBuffer failed");
RelationUnsetLockForWrite(rel);
heap_close(rel);
return;
return (result);
}
int4
currval (struct varlena * seqin)
nextval(struct varlena * seqin)
{
char *seqname = textout(seqin);
SeqTable elm;
int4 result;
char *seqname = textout(seqin);
SeqTable elm;
Buffer buf;
SequenceTupleForm seq;
ItemPointerData iptr;
int4 incby,
maxv,
minv,
cache;
int4 result,
next,
rescnt = 0;
/* open and WIntentLock sequence */
elm = init_sequence ("currval", seqname);
pfree (seqname);
if ( elm->increment == 0 ) /* nextval/read_info were not called */
{
elog (WARN, "%s.currval is not yet defined in this session", elm->name);
}
result = elm->last;
return (result);
}
/* open and WIntentLock sequence */
elm = init_sequence("nextval", seqname);
pfree(seqname);
static SequenceTupleForm
read_info (char * caller, SeqTable elm, Buffer * buf)
{
ItemPointerData iptr;
PageHeader page;
ItemId lp;
HeapTuple tuple;
sequence_magic *sm;
SequenceTupleForm seq;
if (elm->last != elm->cached) /* some numbers were cached */
{
elm->last += elm->increment;
return (elm->last);
}
ItemPointerSet(&iptr, 0, FirstOffsetNumber);
RelationSetSingleWLockPage (elm->rel, &iptr);
seq = read_info("nextval", elm, &buf); /* lock page and read
* tuple */
if ( RelationGetNumberOfBlocks (elm->rel) != 1 )
elog (WARN, "%s.%s: invalid number of blocks in sequence",
elm->name, caller);
*buf = ReadBuffer (elm->rel, 0);
if ( !BufferIsValid (*buf) )
elog (WARN, "%s.%s: ReadBuffer failed", elm->name, caller);
next = result = seq->last_value;
incby = seq->increment_by;
maxv = seq->max_value;
minv = seq->min_value;
cache = seq->cache_value;
page = (PageHeader) BufferGetPage (*buf);
sm = (sequence_magic *) PageGetSpecialPointer (page);
if ( sm->magic != SEQ_MAGIC )
elog (WARN, "%s.%s: bad magic (%08X)", elm->name, caller, sm->magic);
if (seq->is_called != 't')
rescnt++; /* last_value if not called */
lp = PageGetItemId (page, FirstOffsetNumber);
Assert (ItemIdIsUsed (lp));
tuple = (HeapTuple) PageGetItem ((Page) page, lp);
seq = (SequenceTupleForm) GETSTRUCT(tuple);
elm->increment = seq->increment_by;
while (rescnt < cache) /* try to fetch cache numbers */
{
return (seq);
/*
* Check MAXVALUE for ascending sequences and MINVALUE for
* descending sequences
*/
if (incby > 0) /* ascending sequence */
{
if ((maxv >= 0 && next > maxv - incby) ||
(maxv < 0 && next + incby > maxv))
{
if (rescnt > 0)
break; /* stop caching */
if (seq->is_cycled != 't')
elog(WARN, "%s.nextval: got MAXVALUE (%d)",
elm->name, maxv);
next = minv;
}
else
next += incby;
}
else
/* descending sequence */
{
if ((minv < 0 && next < minv - incby) ||
(minv >= 0 && next + incby < minv))
{
if (rescnt > 0)
break; /* stop caching */
if (seq->is_cycled != 't')
elog(WARN, "%s.nextval: got MINVALUE (%d)",
elm->name, minv);
next = maxv;
}
else
next += incby;
}
rescnt++; /* got result */
if (rescnt == 1) /* if it's first one - */
result = next; /* it's what to return */
}
/* save info in local cache */
elm->last = result; /* last returned number */
elm->cached = next; /* last cached number */
/* save info in sequence relation */
seq->last_value = next; /* last fetched number */
seq->is_called = 't';
if (WriteBuffer(buf) == STATUS_ERROR)
elog(WARN, "%s.nextval: WriteBuffer failed", elm->name);
ItemPointerSet(&iptr, 0, FirstOffsetNumber);
RelationUnsetSingleWLockPage(elm->rel, &iptr);
return (result);
}
static SeqTable
init_sequence (char * caller, char * name)
int4
currval(struct varlena * seqin)
{
SeqTable elm, priv = (SeqTable) NULL;
SeqTable temp;
for (elm = seqtab; elm != (SeqTable) NULL; )
{
if ( strcmp (elm->name, name) == 0 )
break;
priv = elm;
elm = elm->next;
}
if ( elm == (SeqTable) NULL ) /* not found */
{
temp = (SeqTable) malloc (sizeof(SeqTableData));
temp->name = malloc (strlen(name) + 1);
strcpy (temp->name, name);
temp->rel = (Relation) NULL;
temp->cached = temp->last = temp->increment = 0;
temp->next = (SeqTable) NULL;
}
else /* found */
{
if ( elm->rel != (Relation) NULL) /* already opened */
return (elm);
temp = elm;
}
temp->rel = heap_openr (name);
char *seqname = textout(seqin);
SeqTable elm;
int4 result;
if ( ! RelationIsValid (temp->rel) )
elog (WARN, "%s.%s: sequence does not exist", name, caller);
/* open and WIntentLock sequence */
elm = init_sequence("currval", seqname);
pfree(seqname);
RelationSetWIntentLock (temp->rel);
if ( temp->rel->rd_rel->relkind != RELKIND_SEQUENCE )
elog (WARN, "%s.%s: %s is not sequence !", name, caller, name);
if (elm->increment == 0) /* nextval/read_info were not called */
{
elog(WARN, "%s.currval is not yet defined in this session", elm->name);
}
result = elm->last;
return (result);
}
static SequenceTupleForm
read_info(char *caller, SeqTable elm, Buffer * buf)
{
ItemPointerData iptr;
PageHeader page;
ItemId lp;
HeapTuple tuple;
sequence_magic *sm;
SequenceTupleForm seq;
ItemPointerSet(&iptr, 0, FirstOffsetNumber);
RelationSetSingleWLockPage(elm->rel, &iptr);
if (RelationGetNumberOfBlocks(elm->rel) != 1)
elog(WARN, "%s.%s: invalid number of blocks in sequence",
elm->name, caller);
*buf = ReadBuffer(elm->rel, 0);
if (!BufferIsValid(*buf))
elog(WARN, "%s.%s: ReadBuffer failed", elm->name, caller);
page = (PageHeader) BufferGetPage(*buf);
sm = (sequence_magic *) PageGetSpecialPointer(page);
if (sm->magic != SEQ_MAGIC)
elog(WARN, "%s.%s: bad magic (%08X)", elm->name, caller, sm->magic);
lp = PageGetItemId(page, FirstOffsetNumber);
Assert(ItemIdIsUsed(lp));
tuple = (HeapTuple) PageGetItem((Page) page, lp);
seq = (SequenceTupleForm) GETSTRUCT(tuple);
elm->increment = seq->increment_by;
return (seq);
}
static SeqTable
init_sequence(char *caller, char *name)
{
SeqTable elm,
priv = (SeqTable) NULL;
SeqTable temp;
for (elm = seqtab; elm != (SeqTable) NULL;)
{
if (strcmp(elm->name, name) == 0)
break;
priv = elm;
elm = elm->next;
}
if (elm == (SeqTable) NULL) /* not found */
{
temp = (SeqTable) malloc(sizeof(SeqTableData));
temp->name = malloc(strlen(name) + 1);
strcpy(temp->name, name);
temp->rel = (Relation) NULL;
temp->cached = temp->last = temp->increment = 0;
temp->next = (SeqTable) NULL;
}
else
/* found */
{
if (elm->rel != (Relation) NULL) /* already opened */
return (elm);
temp = elm;
}
temp->rel = heap_openr(name);
if (!RelationIsValid(temp->rel))
elog(WARN, "%s.%s: sequence does not exist", name, caller);
RelationSetWIntentLock(temp->rel);
if (temp->rel->rd_rel->relkind != RELKIND_SEQUENCE)
elog(WARN, "%s.%s: %s is not sequence !", name, caller, name);
if (elm != (SeqTable) NULL) /* we opened sequence from our */
{ /* SeqTable - check relid ! */
if (RelationGetRelationId(elm->rel) != elm->relid)
{
elog(NOTICE, "%s.%s: sequence was re-created",
name, caller, name);
elm->cached = elm->last = elm->increment = 0;
elm->relid = RelationGetRelationId(elm->rel);
}
}
else
{
elm = temp;
elm->relid = RelationGetRelationId(elm->rel);
if (seqtab == (SeqTable) NULL)
seqtab = elm;
else
priv->next = elm;
}
return (elm);
if ( elm != (SeqTable) NULL ) /* we opened sequence from our */
{ /* SeqTable - check relid ! */
if ( RelationGetRelationId (elm->rel) != elm->relid )
{
elog (NOTICE, "%s.%s: sequence was re-created",
name, caller, name);
elm->cached = elm->last = elm->increment = 0;
elm->relid = RelationGetRelationId (elm->rel);
}
}
else
{
elm = temp;
elm->relid = RelationGetRelationId (elm->rel);
if ( seqtab == (SeqTable) NULL )
seqtab = elm;
else
priv->next = elm;
}
return (elm);
}
/*
* CloseSequences --
* is calling by xact mgr at commit/abort.
* is calling by xact mgr at commit/abort.
*/
void
CloseSequences (void)
CloseSequences(void)
{
SeqTable elm;
Relation rel;
ItsSequenceCreation = false;
for (elm = seqtab; elm != (SeqTable) NULL; )
{
if ( elm->rel != (Relation) NULL ) /* opened in current xact */
{
rel = elm->rel;
elm->rel = (Relation) NULL;
RelationUnsetWIntentLock (rel);
heap_close (rel);
}
elm = elm->next;
}
SeqTable elm;
Relation rel;
ItsSequenceCreation = false;
for (elm = seqtab; elm != (SeqTable) NULL;)
{
if (elm->rel != (Relation) NULL) /* opened in current xact */
{
rel = elm->rel;
elm->rel = (Relation) NULL;
RelationUnsetWIntentLock(rel);
heap_close(rel);
}
elm = elm->next;
}
return;
return;
}
static void
init_params (CreateSeqStmt *seq, SequenceTupleForm new)
static void
init_params(CreateSeqStmt * seq, SequenceTupleForm new)
{
DefElem *last_value = NULL;
DefElem *increment_by = NULL;
DefElem *max_value = NULL;
DefElem *min_value = NULL;
DefElem *cache_value = NULL;
List *option;
new->is_cycled = 'f';
foreach (option, seq->options)
{
DefElem *defel = (DefElem *)lfirst(option);
if ( !strcasecmp(defel->defname, "increment") )
increment_by = defel;
else if ( !strcasecmp(defel->defname, "start") )
last_value = defel;
else if ( !strcasecmp(defel->defname, "maxvalue") )
max_value = defel;
else if ( !strcasecmp(defel->defname, "minvalue") )
min_value = defel;
else if ( !strcasecmp(defel->defname, "cache") )
cache_value = defel;
else if ( !strcasecmp(defel->defname, "cycle") )
{
if ( defel->arg != (Node*) NULL )
elog (WARN, "DefineSequence: CYCLE ??");
new->is_cycled = 't';
}
else
elog (WARN, "DefineSequence: option \"%s\" not recognized",
defel->defname);
}
DefElem *last_value = NULL;
DefElem *increment_by = NULL;
DefElem *max_value = NULL;
DefElem *min_value = NULL;
DefElem *cache_value = NULL;
List *option;
if ( increment_by == (DefElem*) NULL ) /* INCREMENT BY */
new->increment_by = 1;
else if ( ( new->increment_by = get_param (increment_by) ) == 0 )
elog (WARN, "DefineSequence: can't INCREMENT by 0");
new->is_cycled = 'f';
foreach(option, seq->options)
{
DefElem *defel = (DefElem *) lfirst(option);
if ( max_value == (DefElem*) NULL ) /* MAXVALUE */
if ( new->increment_by > 0 )
new->max_value = SEQ_MAXVALUE; /* ascending seq */
if (!strcasecmp(defel->defname, "increment"))
increment_by = defel;
else if (!strcasecmp(defel->defname, "start"))
last_value = defel;
else if (!strcasecmp(defel->defname, "maxvalue"))
max_value = defel;
else if (!strcasecmp(defel->defname, "minvalue"))
min_value = defel;
else if (!strcasecmp(defel->defname, "cache"))
cache_value = defel;
else if (!strcasecmp(defel->defname, "cycle"))
{
if (defel->arg != (Node *) NULL)
elog(WARN, "DefineSequence: CYCLE ??");
new->is_cycled = 't';
}
else
elog(WARN, "DefineSequence: option \"%s\" not recognized",
defel->defname);
}
if (increment_by == (DefElem *) NULL) /* INCREMENT BY */
new->increment_by = 1;
else if ((new->increment_by = get_param(increment_by)) == 0)
elog(WARN, "DefineSequence: can't INCREMENT by 0");
if (max_value == (DefElem *) NULL) /* MAXVALUE */
if (new->increment_by > 0)
new->max_value = SEQ_MAXVALUE; /* ascending seq */
else
new->max_value = -1;/* descending seq */
else
new->max_value = -1; /* descending seq */
else
new->max_value = get_param (max_value);
new->max_value = get_param(max_value);
if ( min_value == (DefElem*) NULL ) /* MINVALUE */
if ( new->increment_by > 0 )
new->min_value = 1; /* ascending seq */
if (min_value == (DefElem *) NULL) /* MINVALUE */
if (new->increment_by > 0)
new->min_value = 1; /* ascending seq */
else
new->min_value = SEQ_MINVALUE; /* descending seq */
else
new->min_value = SEQ_MINVALUE; /* descending seq */
else
new->min_value = get_param (min_value);
if ( new->min_value >= new->max_value )
elog (WARN, "DefineSequence: MINVALUE (%d) can't be >= MAXVALUE (%d)",
new->min_value, new->max_value);
new->min_value = get_param(min_value);
if ( last_value == (DefElem*) NULL ) /* START WITH */
if ( new->increment_by > 0 )
new->last_value = new->min_value; /* ascending seq */
if (new->min_value >= new->max_value)
elog(WARN, "DefineSequence: MINVALUE (%d) can't be >= MAXVALUE (%d)",
new->min_value, new->max_value);
if (last_value == (DefElem *) NULL) /* START WITH */
if (new->increment_by > 0)
new->last_value = new->min_value; /* ascending seq */
else
new->last_value = new->max_value; /* descending seq */
else
new->last_value = new->max_value; /* descending seq */
else
new->last_value = get_param (last_value);
new->last_value = get_param(last_value);
if ( new->last_value < new->min_value )
elog (WARN, "DefineSequence: START value (%d) can't be < MINVALUE (%d)",
new->last_value, new->min_value);
if ( new->last_value > new->max_value )
elog (WARN, "DefineSequence: START value (%d) can't be > MAXVALUE (%d)",
new->last_value, new->max_value);
if (new->last_value < new->min_value)
elog(WARN, "DefineSequence: START value (%d) can't be < MINVALUE (%d)",
new->last_value, new->min_value);
if (new->last_value > new->max_value)
elog(WARN, "DefineSequence: START value (%d) can't be > MAXVALUE (%d)",
new->last_value, new->max_value);
if ( cache_value == (DefElem*) NULL ) /* CACHE */
new->cache_value = 1;
else if ( ( new->cache_value = get_param (cache_value) ) <= 0 )
elog (WARN, "DefineSequence: CACHE (%d) can't be <= 0",
new->cache_value);
if (cache_value == (DefElem *) NULL) /* CACHE */
new->cache_value = 1;
else if ((new->cache_value = get_param(cache_value)) <= 0)
elog(WARN, "DefineSequence: CACHE (%d) can't be <= 0",
new->cache_value);
}
static int
get_param (DefElem *def)
get_param(DefElem * def)
{
if ( def->arg == (Node*) NULL )
elog (WARN, "DefineSequence: \"%s\" value unspecified", def->defname);
if (def->arg == (Node *) NULL)
elog(WARN, "DefineSequence: \"%s\" value unspecified", def->defname);
if ( nodeTag (def->arg) == T_Integer )
return (intVal (def->arg));
elog (WARN, "DefineSequence: \"%s\" is to be integer", def->defname);
return (-1);
if (nodeTag(def->arg) == T_Integer)
return (intVal(def->arg));
elog(WARN, "DefineSequence: \"%s\" is to be integer", def->defname);
return (-1);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* view.c--
* use rewrite rules to construct views
* use rewrite rules to construct views
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.8 1997/08/22 14:22:14 vadim Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/view.c,v 1.9 1997/09/07 04:41:06 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h> /* for sprintf() */
#include <stdio.h> /* for sprintf() */
#include <string.h>
#include <postgres.h>
@ -42,69 +42,74 @@
*---------------------------------------------------------------------
*/
static void
DefineVirtualRelation(char *relname, List *tlist)
DefineVirtualRelation(char *relname, List * tlist)
{
CreateStmt createStmt;
List *attrList, *t;
TargetEntry *entry;
Resdom *res;
char *resname;
char *restypename;
/*
* create a list with one entry per attribute of this relation.
* Each entry is a two element list. The first element is the
* name of the attribute (a string) and the second the name of the type
* (NOTE: a string, not a type id!).
*/
attrList = NIL;
if (tlist!=NIL) {
foreach (t, tlist ) {
ColumnDef *def = makeNode(ColumnDef);
TypeName *typename;
CreateStmt createStmt;
List *attrList,
*t;
TargetEntry *entry;
Resdom *res;
char *resname;
char *restypename;
/*
* find the names of the attribute & its type
*/
entry = lfirst(t);
res = entry->resdom;
resname = res->resname;
restypename = tname(get_id_type(res->restype));
/*
* create a list with one entry per attribute of this relation. Each
* entry is a two element list. The first element is the name of the
* attribute (a string) and the second the name of the type (NOTE: a
* string, not a type id!).
*/
attrList = NIL;
if (tlist != NIL)
{
foreach(t, tlist)
{
ColumnDef *def = makeNode(ColumnDef);
TypeName *typename;
typename = makeNode(TypeName);
/*
* find the names of the attribute & its type
*/
entry = lfirst(t);
res = entry->resdom;
resname = res->resname;
restypename = tname(get_id_type(res->restype));
typename->name = pstrdup(restypename);
def->colname = pstrdup(resname);
typename = makeNode(TypeName);
def->typename = typename;
def->is_not_null = false;
def->defval = (char*) NULL;
typename->name = pstrdup(restypename);
def->colname = pstrdup(resname);
attrList = lappend(attrList, def);
def->typename = typename;
def->is_not_null = false;
def->defval = (char *) NULL;
attrList = lappend(attrList, def);
}
}
else
{
elog(WARN, "attempted to define virtual relation with no attrs");
}
} else {
elog ( WARN, "attempted to define virtual relation with no attrs");
}
/*
* now create the parametesr for keys/inheritance etc.
* All of them are nil...
*/
createStmt.relname = relname;
createStmt.tableElts = attrList;
/* createStmt.tableType = NULL;*/
createStmt.inhRelnames = NIL;
createStmt.archiveType = ARCH_NONE;
createStmt.location = -1;
createStmt.archiveLoc = -1;
createStmt.constraints = NIL;
/*
* finally create the relation...
*/
DefineRelation(&createStmt);
}
/*
* now create the parametesr for keys/inheritance etc. All of them are
* nil...
*/
createStmt.relname = relname;
createStmt.tableElts = attrList;
/* createStmt.tableType = NULL;*/
createStmt.inhRelnames = NIL;
createStmt.archiveType = ARCH_NONE;
createStmt.location = -1;
createStmt.archiveLoc = -1;
createStmt.constraints = NIL;
/*
* finally create the relation...
*/
DefineRelation(&createStmt);
}
/*------------------------------------------------------------------
* makeViewRetrieveRuleName
@ -118,84 +123,87 @@ DefineVirtualRelation(char *relname, List *tlist)
* XXX it also means viewName cannot be 16 chars long! - ay 11/94
*------------------------------------------------------------------
*/
char *
char *
MakeRetrieveViewRuleName(char *viewName)
{
/*
char buf[100];
char buf[100];
memset(buf, 0, sizeof(buf));
sprintf(buf, "_RET%.*s", NAMEDATALEN, viewName->data);
buf[15] = '\0';
namestrcpy(rule_name, buf);
memset(buf, 0, sizeof(buf));
sprintf(buf, "_RET%.*s", NAMEDATALEN, viewName->data);
buf[15] = '\0';
namestrcpy(rule_name, buf);
*/
char *buf;
buf = palloc(strlen(viewName) + 5);
sprintf(buf, "_RET%s",viewName);
return buf;
char *buf;
buf = palloc(strlen(viewName) + 5);
sprintf(buf, "_RET%s", viewName);
return buf;
}
static RuleStmt *
FormViewRetrieveRule(char *viewName, Query *viewParse)
FormViewRetrieveRule(char *viewName, Query * viewParse)
{
RuleStmt *rule;
char *rname;
Attr *attr;
/*
* Create a RuleStmt that corresponds to the suitable
* rewrite rule args for DefineQueryRewrite();
*/
rule = makeNode(RuleStmt);
rname = MakeRetrieveViewRuleName(viewName);
RuleStmt *rule;
char *rname;
Attr *attr;
attr = makeNode(Attr);
attr->relname = pstrdup(viewName);
/* attr->refname = pstrdup(viewName);*/
rule->rulename = pstrdup(rname);
rule->whereClause = NULL;
rule->event = CMD_SELECT;
rule->object = attr;
rule->instead = true;
rule->actions = lcons(viewParse, NIL);
return rule;
/*
* Create a RuleStmt that corresponds to the suitable rewrite rule
* args for DefineQueryRewrite();
*/
rule = makeNode(RuleStmt);
rname = MakeRetrieveViewRuleName(viewName);
attr = makeNode(Attr);
attr->relname = pstrdup(viewName);
/* attr->refname = pstrdup(viewName);*/
rule->rulename = pstrdup(rname);
rule->whereClause = NULL;
rule->event = CMD_SELECT;
rule->object = attr;
rule->instead = true;
rule->actions = lcons(viewParse, NIL);
return rule;
}
static void
DefineViewRules(char *viewName, Query *viewParse)
DefineViewRules(char *viewName, Query * viewParse)
{
RuleStmt *retrieve_rule = NULL;
#ifdef NOTYET
RuleStmt *replace_rule = NULL;
RuleStmt *append_rule = NULL;
RuleStmt *delete_rule = NULL;
#endif
retrieve_rule =
FormViewRetrieveRule(viewName, viewParse);
#ifdef NOTYET
replace_rule =
FormViewReplaceRule(viewName, viewParse);
append_rule =
FormViewAppendRule(viewName, viewParse);
delete_rule =
FormViewDeleteRule(viewName, viewParse);
#endif
DefineQueryRewrite(retrieve_rule);
RuleStmt *retrieve_rule = NULL;
#ifdef NOTYET
DefineQueryRewrite(replace_rule);
DefineQueryRewrite(append_rule);
DefineQueryRewrite(delete_rule);
RuleStmt *replace_rule = NULL;
RuleStmt *append_rule = NULL;
RuleStmt *delete_rule = NULL;
#endif
}
retrieve_rule =
FormViewRetrieveRule(viewName, viewParse);
#ifdef NOTYET
replace_rule =
FormViewReplaceRule(viewName, viewParse);
append_rule =
FormViewAppendRule(viewName, viewParse);
delete_rule =
FormViewDeleteRule(viewName, viewParse);
#endif
DefineQueryRewrite(retrieve_rule);
#ifdef NOTYET
DefineQueryRewrite(replace_rule);
DefineQueryRewrite(append_rule);
DefineQueryRewrite(delete_rule);
#endif
}
/*---------------------------------------------------------------
* UpdateRangeTableOfViewParse
@ -216,88 +224,84 @@ DefineViewRules(char *viewName, Query *viewParse)
*---------------------------------------------------------------
*/
static void
UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
UpdateRangeTableOfViewParse(char *viewName, Query * viewParse)
{
List *old_rt;
List *new_rt;
RangeTblEntry *rt_entry1, *rt_entry2;
/*
* first offset all var nodes by 2
*/
OffsetVarNodes((Node*)viewParse->targetList, 2);
OffsetVarNodes(viewParse->qual, 2);
/*
* find the old range table...
*/
old_rt = viewParse->rtable;
List *old_rt;
List *new_rt;
RangeTblEntry *rt_entry1,
*rt_entry2;
/*
* create the 2 new range table entries and form the new
* range table...
* CURRENT first, then NEW....
*/
rt_entry1 =
addRangeTableEntry(NULL, (char*)viewName, "*CURRENT*",
FALSE, FALSE, NULL);
rt_entry2 =
addRangeTableEntry(NULL, (char*)viewName, "*NEW*",
FALSE, FALSE, NULL);
new_rt = lcons(rt_entry2, old_rt);
new_rt = lcons(rt_entry1, new_rt);
/*
* Now the tricky part....
* Update the range table in place... Be careful here, or
* hell breaks loooooooooooooOOOOOOOOOOOOOOOOOOSE!
*/
viewParse->rtable = new_rt;
/*
* first offset all var nodes by 2
*/
OffsetVarNodes((Node *) viewParse->targetList, 2);
OffsetVarNodes(viewParse->qual, 2);
/*
* find the old range table...
*/
old_rt = viewParse->rtable;
/*
* create the 2 new range table entries and form the new range
* table... CURRENT first, then NEW....
*/
rt_entry1 =
addRangeTableEntry(NULL, (char *) viewName, "*CURRENT*",
FALSE, FALSE, NULL);
rt_entry2 =
addRangeTableEntry(NULL, (char *) viewName, "*NEW*",
FALSE, FALSE, NULL);
new_rt = lcons(rt_entry2, old_rt);
new_rt = lcons(rt_entry1, new_rt);
/*
* Now the tricky part.... Update the range table in place... Be
* careful here, or hell breaks loooooooooooooOOOOOOOOOOOOOOOOOOSE!
*/
viewParse->rtable = new_rt;
}
/*-------------------------------------------------------------------
* DefineView
*
* - takes a "viewname", "parsetree" pair and then
* 1) construct the "virtual" relation
* 2) commit the command but NOT the transaction,
* so that the relation exists
* before the rules are defined.
* 2) define the "n" rules specified in the PRS2 paper
* over the "virtual" relation
* - takes a "viewname", "parsetree" pair and then
* 1) construct the "virtual" relation
* 2) commit the command but NOT the transaction,
* so that the relation exists
* before the rules are defined.
* 2) define the "n" rules specified in the PRS2 paper
* over the "virtual" relation
*-------------------------------------------------------------------
*/
void
DefineView(char *viewName, Query *viewParse)
DefineView(char *viewName, Query * viewParse)
{
List *viewTlist;
List *viewTlist;
viewTlist = viewParse->targetList;
/*
* Create the "view" relation
* NOTE: if it already exists, the xaxt will be aborted.
*/
DefineVirtualRelation(viewName, viewTlist);
/*
* The relation we have just created is not visible
* to any other commands running with the same transaction &
* command id.
* So, increment the command id counter (but do NOT pfree any
* memory!!!!)
*/
CommandCounterIncrement();
/*
* The range table of 'viewParse' does not contain entries
* for the "CURRENT" and "NEW" relations.
* So... add them!
* NOTE: we make the update in place! After this call 'viewParse'
* will never be what it used to be...
*/
UpdateRangeTableOfViewParse(viewName, viewParse);
DefineViewRules(viewName, viewParse);
viewTlist = viewParse->targetList;
/*
* Create the "view" relation NOTE: if it already exists, the xaxt
* will be aborted.
*/
DefineVirtualRelation(viewName, viewTlist);
/*
* The relation we have just created is not visible to any other
* commands running with the same transaction & command id. So,
* increment the command id counter (but do NOT pfree any memory!!!!)
*/
CommandCounterIncrement();
/*
* The range table of 'viewParse' does not contain entries for the
* "CURRENT" and "NEW" relations. So... add them! NOTE: we make the
* update in place! After this call 'viewParse' will never be what it
* used to be...
*/
UpdateRangeTableOfViewParse(viewName, viewParse);
DefineViewRules(viewName, viewParse);
}
/*------------------------------------------------------------------
@ -309,23 +313,22 @@ DefineView(char *viewName, Query *viewParse)
void
RemoveView(char *viewName)
{
char* rname;
/*
* first remove all the "view" rules...
* Currently we only have one!
*/
rname = MakeRetrieveViewRuleName(viewName);
RemoveRewriteRule(rname);
char *rname;
/*
* we don't really need that, but just in case...
*/
CommandCounterIncrement();
/*
* now remove the relation.
*/
heap_destroy(viewName);
pfree(rname);
/*
* first remove all the "view" rules... Currently we only have one!
*/
rname = MakeRetrieveViewRuleName(viewName);
RemoveRewriteRule(rname);
/*
* we don't really need that, but just in case...
*/
CommandCounterIncrement();
/*
* now remove the relation.
*/
heap_destroy(viewName);
pfree(rname);
}