aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands')
-rw-r--r--src/backend/commands/_deadcode/version.c369
-rw-r--r--src/backend/commands/async.c831
-rw-r--r--src/backend/commands/cluster.c580
-rw-r--r--src/backend/commands/command.c827
-rw-r--r--src/backend/commands/copy.c1884
-rw-r--r--src/backend/commands/creatinh.c1112
-rw-r--r--src/backend/commands/defind.c899
-rw-r--r--src/backend/commands/define.c1113
-rw-r--r--src/backend/commands/explain.c353
-rw-r--r--src/backend/commands/purge.c271
-rw-r--r--src/backend/commands/recipe.c2130
-rw-r--r--src/backend/commands/remove.c796
-rw-r--r--src/backend/commands/rename.c401
-rw-r--r--src/backend/commands/sequence.c924
-rw-r--r--src/backend/commands/trigger.c1050
-rw-r--r--src/backend/commands/vacuum.c3920
-rw-r--r--src/backend/commands/view.c427
17 files changed, 9402 insertions, 8485 deletions
diff --git a/src/backend/commands/_deadcode/version.c b/src/backend/commands/_deadcode/version.c
index bac35cd4f87..c3eb6f47797 100644
--- a/src/backend/commands/_deadcode/version.c
+++ b/src/backend/commands/_deadcode/version.c
@@ -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];
-
- 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);
-
- 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);
+ 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);
+
+ 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;
-
- 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;
+ 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;
+ }
+ strcat(attr_list, temp_buf);
}
- strcat(attr_list, temp_buf);
- }
-
- heap_close(rdesc);
-
- return;
+
+ 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); */
}
diff --git a/src/backend/commands/async.c b/src/backend/commands/async.c
index 8a1e6d59b57..42d440a8676 100644
--- a/src/backend/commands/async.c
+++ b/src/backend/commands/async.c
@@ -1,35 +1,35 @@
/*-------------------------------------------------------------------------
*
* async.c--
- * Asynchronous notification
+ * Asynchronous notification
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.17 1997/08/19 21:30:42 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.18 1997/09/07 04:40:35 momjian Exp $
*
*-------------------------------------------------------------------------
*/
/* New Async Notification Model:
* 1. Multiple backends on same machine. Multiple backends listening on
- * one relation.
+ * one relation.
*
* 2. One of the backend does a 'notify <relname>'. For all backends that
- * are listening to this relation (all notifications take place at the
- * end of commit),
- * 2.a If the process is the same as the backend process that issued
- * notification (we are notifying something that we are listening),
- * signal the corresponding frontend over the comm channel using the
- * out-of-band channel.
- * 2.b For all other listening processes, we send kill(2) to wake up
- * the listening backend.
+ * are listening to this relation (all notifications take place at the
+ * end of commit),
+ * 2.a If the process is the same as the backend process that issued
+ * notification (we are notifying something that we are listening),
+ * signal the corresponding frontend over the comm channel using the
+ * out-of-band channel.
+ * 2.b For all other listening processes, we send kill(2) to wake up
+ * the listening backend.
* 3. Upon receiving a kill(2) signal from another backend process notifying
- * that one of the relation that we are listening is being notified,
- * we can be in either of two following states:
- * 3.a We are sleeping, wake up and signal our frontend.
- * 3.b We are in middle of another transaction, wait until the end of
- * of the current transaction and signal our frontend.
+ * that one of the relation that we are listening is being notified,
+ * we can be in either of two following states:
+ * 3.a We are sleeping, wake up and signal our frontend.
+ * 3.b We are in middle of another transaction, wait until the end of
+ * of the current transaction and signal our frontend.
* 4. Each frontend receives this notification and prcesses accordingly.
*
* -- jw, 12/28/93
@@ -42,16 +42,16 @@
* Model is:
* 1. Multiple backends on same machine.
*
- * 2. Query on one backend sends stuff over an asynchronous portal by
- * appending to a relation, and then doing an async. notification
- * (which takes place after commit) to all listeners on this relation.
+ * 2. Query on one backend sends stuff over an asynchronous portal by
+ * appending to a relation, and then doing an async. notification
+ * (which takes place after commit) to all listeners on this relation.
*
- * 3. Async. notification results in all backends listening on relation
- * to be woken up, by a process signal kill(2), with name of relation
- * passed in shared memory.
+ * 3. Async. notification results in all backends listening on relation
+ * to be woken up, by a process signal kill(2), with name of relation
+ * passed in shared memory.
*
* 4. Each backend notifies its respective frontend over the comm
- * channel using the out-of-band channel.
+ * channel using the out-of-band channel.
*
* 5. Each frontend receives this notification and processes accordingly.
*
@@ -62,7 +62,7 @@
#include <signal.h>
#include <string.h>
#include <errno.h>
-#include <sys/types.h> /* Needed by in.h on Ultrix */
+#include <sys/types.h> /* Needed by in.h on Ultrix */
#include <netinet/in.h>
#include <postgres.h>
@@ -75,546 +75,585 @@
#include <catalog/pg_proc.h>
#include <catalog/catname.h>
#include <catalog/pg_listener.h>
-#include <access/heapam.h>
+#include <access/heapam.h>
#include <storage/bufmgr.h>
#include <nodes/memnodes.h>
#include <utils/mcxt.h>
#include <commands/async.h>
#include <libpq/libpq.h>
-#include <port-protos.h> /* for strdup() */
+#include <port-protos.h> /* for strdup() */
#include <storage/lmgr.h>
-static int notifyFrontEndPending = 0;
-static int notifyIssued = 0;
-static Dllist *pendingNotifies = NULL;
+static int notifyFrontEndPending = 0;
+static int notifyIssued = 0;
+static Dllist *pendingNotifies = NULL;
-static int AsyncExistsPendingNotify(char *);
-static void ClearPendingNotify(void);
-static void Async_NotifyFrontEnd(void);
-static void Async_Unlisten(char *relname, int pid);
-static void Async_UnlistenOnExit(int code, char *relname);
-
+static int AsyncExistsPendingNotify(char *);
+static void ClearPendingNotify(void);
+static void Async_NotifyFrontEnd(void);
+static void Async_Unlisten(char *relname, int pid);
+static void Async_UnlistenOnExit(int code, char *relname);
+
/*
*--------------------------------------------------------------
* Async_NotifyHandler --
*
- * This is the signal handler for SIGUSR2. When the backend
- * is signaled, the backend can be in two states.
- * 1. If the backend is in the middle of another transaction,
- * we set the flag, notifyFrontEndPending, and wait until
- * the end of the transaction to notify the front end.
- * 2. If the backend is not in the middle of another transaction,
- * we notify the front end immediately.
+ * This is the signal handler for SIGUSR2. When the backend
+ * is signaled, the backend can be in two states.
+ * 1. If the backend is in the middle of another transaction,
+ * we set the flag, notifyFrontEndPending, and wait until
+ * the end of the transaction to notify the front end.
+ * 2. If the backend is not in the middle of another transaction,
+ * we notify the front end immediately.
*
- * -- jw, 12/28/93
+ * -- jw, 12/28/93
* Results:
- * none
+ * none
*
* Side effects:
- * none
+ * none
*/
void
Async_NotifyHandler(SIGNAL_ARGS)
{
- extern TransactionState CurrentTransactionState;
-
- if ((CurrentTransactionState->state == TRANS_DEFAULT) &&
- (CurrentTransactionState->blockState == TRANS_DEFAULT)) {
+ extern TransactionState CurrentTransactionState;
+
+ if ((CurrentTransactionState->state == TRANS_DEFAULT) &&
+ (CurrentTransactionState->blockState == TRANS_DEFAULT))
+ {
#ifdef ASYNC_DEBUG
- elog(DEBUG, "Waking up sleeping backend process");
+ elog(DEBUG, "Waking up sleeping backend process");
#endif
- Async_NotifyFrontEnd();
+ Async_NotifyFrontEnd();
- }else {
+ }
+ else
+ {
#ifdef ASYNC_DEBUG
- elog(DEBUG, "Process is in the middle of another transaction, state = %d, block state = %d",
- CurrentTransactionState->state,
- CurrentTransactionState->blockState);
+ elog(DEBUG, "Process is in the middle of another transaction, state = %d, block state = %d",
+ CurrentTransactionState->state,
+ CurrentTransactionState->blockState);
#endif
- notifyFrontEndPending = 1;
- }
+ notifyFrontEndPending = 1;
+ }
}
/*
*--------------------------------------------------------------
* Async_Notify --
*
- * Adds the relation to the list of pending notifies.
- * All notification happens at end of commit.
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ * Adds the relation to the list of pending notifies.
+ * All notification happens at end of commit.
+ * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
*
- * All notification of backend processes happens here,
- * then each backend notifies its corresponding front end at
- * the end of commit.
+ * All notification of backend processes happens here,
+ * then each backend notifies its corresponding front end at
+ * the end of commit.
*
- * This correspond to 'notify <relname>' command
- * -- jw, 12/28/93
+ * This correspond to 'notify <relname>' command
+ * -- jw, 12/28/93
*
* Results:
- * XXX
+ * XXX
*
* Side effects:
- * All tuples for relname in pg_listener are updated.
+ * All tuples for relname in pg_listener are updated.
*
*--------------------------------------------------------------
*/
void
Async_Notify(char *relname)
{
-
- HeapTuple lTuple, rTuple;
- Relation lRel;
- HeapScanDesc sRel;
- TupleDesc tdesc;
- ScanKeyData key;
- Buffer b;
- Datum d, value[3];
- bool isnull;
- char repl[3], nulls[3];
-
- char *notifyName;
-
+
+ HeapTuple lTuple,
+ rTuple;
+ Relation lRel;
+ HeapScanDesc sRel;
+ TupleDesc tdesc;
+ ScanKeyData key;
+ Buffer b;
+ Datum d,
+ value[3];
+ bool isnull;
+ char repl[3],
+ nulls[3];
+
+ char *notifyName;
+
#ifdef ASYNC_DEBUG
- elog(DEBUG,"Async_Notify: %s",relname);
+ elog(DEBUG, "Async_Notify: %s", relname);
#endif
-
- if (!pendingNotifies)
- pendingNotifies = DLNewList();
-
- /*
- * Allocate memory from the global malloc pool because it needs to be
- * referenced also when the transaction is finished. DZ - 26-08-1996
- */
- notifyName = strdup(relname);
- DLAddHead(pendingNotifies, DLNewElem(notifyName));
-
- ScanKeyEntryInitialize(&key, 0,
- Anum_pg_listener_relname,
- NameEqualRegProcedure,
- PointerGetDatum(notifyName));
-
- lRel = heap_openr(ListenerRelationName);
- tdesc = RelationGetTupleDescriptor(lRel);
- RelationSetLockForWrite(lRel);
- sRel = heap_beginscan(lRel, 0, NowTimeQual, 1, &key);
-
- nulls[0] = nulls[1] = nulls[2] = ' ';
- repl[0] = repl[1] = repl[2] = ' ';
- repl[Anum_pg_listener_notify - 1] = 'r';
- value[0] = value[1] = value[2] = (Datum) 0;
- value[Anum_pg_listener_notify - 1] = Int32GetDatum(1);
-
- while (HeapTupleIsValid(lTuple = heap_getnext(sRel, 0, &b))) {
- d = (Datum) heap_getattr(lTuple, b, Anum_pg_listener_notify,
- tdesc, &isnull);
- if (!DatumGetInt32(d)) {
- rTuple = heap_modifytuple(lTuple, b, lRel, value, nulls, repl);
- heap_replace(lRel, &lTuple->t_ctid, rTuple);
+
+ if (!pendingNotifies)
+ pendingNotifies = DLNewList();
+
+ /*
+ * Allocate memory from the global malloc pool because it needs to be
+ * referenced also when the transaction is finished. DZ - 26-08-1996
+ */
+ notifyName = strdup(relname);
+ DLAddHead(pendingNotifies, DLNewElem(notifyName));
+
+ ScanKeyEntryInitialize(&key, 0,
+ Anum_pg_listener_relname,
+ NameEqualRegProcedure,
+ PointerGetDatum(notifyName));
+
+ lRel = heap_openr(ListenerRelationName);
+ tdesc = RelationGetTupleDescriptor(lRel);
+ RelationSetLockForWrite(lRel);
+ sRel = heap_beginscan(lRel, 0, NowTimeQual, 1, &key);
+
+ nulls[0] = nulls[1] = nulls[2] = ' ';
+ repl[0] = repl[1] = repl[2] = ' ';
+ repl[Anum_pg_listener_notify - 1] = 'r';
+ value[0] = value[1] = value[2] = (Datum) 0;
+ value[Anum_pg_listener_notify - 1] = Int32GetDatum(1);
+
+ while (HeapTupleIsValid(lTuple = heap_getnext(sRel, 0, &b)))
+ {
+ d = (Datum) heap_getattr(lTuple, b, Anum_pg_listener_notify,
+ tdesc, &isnull);
+ if (!DatumGetInt32(d))
+ {
+ rTuple = heap_modifytuple(lTuple, b, lRel, value, nulls, repl);
+ heap_replace(lRel, &lTuple->t_ctid, rTuple);
+ }
+ ReleaseBuffer(b);
}
- ReleaseBuffer(b);
- }
- heap_endscan(sRel);
- RelationUnsetLockForWrite(lRel);
- heap_close(lRel);
- notifyIssued = 1;
+ heap_endscan(sRel);
+ RelationUnsetLockForWrite(lRel);
+ heap_close(lRel);
+ notifyIssued = 1;
}
/*
*--------------------------------------------------------------
* Async_NotifyAtCommit --
*
- * Signal our corresponding frontend process on relations that
- * were notified. Signal all other backend process that
- * are listening also.
+ * Signal our corresponding frontend process on relations that
+ * were notified. Signal all other backend process that
+ * are listening also.
*
- * -- jw, 12/28/93
+ * -- jw, 12/28/93
*
* Results:
- * XXX
+ * XXX
*
* Side effects:
- * Tuples in pg_listener that has our listenerpid are updated so
- * that the notification is 0. We do not want to notify frontend
- * more than once.
+ * Tuples in pg_listener that has our listenerpid are updated so
+ * that the notification is 0. We do not want to notify frontend
+ * more than once.
*
- * -- jw, 12/28/93
+ * -- jw, 12/28/93
*
*--------------------------------------------------------------
*/
void
Async_NotifyAtCommit()
{
- HeapTuple lTuple;
- Relation lRel;
- HeapScanDesc sRel;
- TupleDesc tdesc;
- ScanKeyData key;
- Datum d;
- int ourpid;
- bool isnull;
- Buffer b;
- extern TransactionState CurrentTransactionState;
-
- if (!pendingNotifies)
- pendingNotifies = DLNewList();
-
- if ((CurrentTransactionState->state == TRANS_DEFAULT) &&
- (CurrentTransactionState->blockState == TRANS_DEFAULT)) {
-
- if (notifyIssued) { /* 'notify <relname>' issued by us */
- notifyIssued = 0;
- StartTransactionCommand();
+ HeapTuple lTuple;
+ Relation lRel;
+ HeapScanDesc sRel;
+ TupleDesc tdesc;
+ ScanKeyData key;
+ Datum d;
+ int ourpid;
+ bool isnull;
+ Buffer b;
+ extern TransactionState CurrentTransactionState;
+
+ if (!pendingNotifies)
+ pendingNotifies = DLNewList();
+
+ if ((CurrentTransactionState->state == TRANS_DEFAULT) &&
+ (CurrentTransactionState->blockState == TRANS_DEFAULT))
+ {
+
+ if (notifyIssued)
+ { /* 'notify <relname>' issued by us */
+ notifyIssued = 0;
+ StartTransactionCommand();
#ifdef ASYNC_DEBUG
- elog(DEBUG, "Async_NotifyAtCommit.");
+ elog(DEBUG, "Async_NotifyAtCommit.");
#endif
- ScanKeyEntryInitialize(&key, 0,
- Anum_pg_listener_notify,
- Integer32EqualRegProcedure,
- Int32GetDatum(1));
- lRel = heap_openr(ListenerRelationName);
- RelationSetLockForWrite(lRel);
- sRel = heap_beginscan(lRel, 0, NowTimeQual, 1, &key);
- tdesc = RelationGetTupleDescriptor(lRel);
- ourpid = getpid();
-
- while (HeapTupleIsValid(lTuple = heap_getnext(sRel,0, &b))) {
- d = (Datum) heap_getattr(lTuple, b, Anum_pg_listener_relname,
- tdesc, &isnull);
-
- if (AsyncExistsPendingNotify((char *) DatumGetPointer(d))) {
- d = (Datum) heap_getattr(lTuple, b, Anum_pg_listener_pid,
- tdesc, &isnull);
-
- if (ourpid == DatumGetInt32(d)) {
+ ScanKeyEntryInitialize(&key, 0,
+ Anum_pg_listener_notify,
+ Integer32EqualRegProcedure,
+ Int32GetDatum(1));
+ lRel = heap_openr(ListenerRelationName);
+ RelationSetLockForWrite(lRel);
+ sRel = heap_beginscan(lRel, 0, NowTimeQual, 1, &key);
+ tdesc = RelationGetTupleDescriptor(lRel);
+ ourpid = getpid();
+
+ while (HeapTupleIsValid(lTuple = heap_getnext(sRel, 0, &b)))
+ {
+ d = (Datum) heap_getattr(lTuple, b, Anum_pg_listener_relname,
+ tdesc, &isnull);
+
+ if (AsyncExistsPendingNotify((char *) DatumGetPointer(d)))
+ {
+ d = (Datum) heap_getattr(lTuple, b, Anum_pg_listener_pid,
+ tdesc, &isnull);
+
+ if (ourpid == DatumGetInt32(d))
+ {
#ifdef ASYNC_DEBUG
- elog(DEBUG, "Notifying self, setting notifyFronEndPending to 1");
+ elog(DEBUG, "Notifying self, setting notifyFronEndPending to 1");
#endif
- notifyFrontEndPending = 1;
- } else {
+ notifyFrontEndPending = 1;
+ }
+ else
+ {
#ifdef ASYNC_DEBUG
- elog(DEBUG, "Notifying others");
+ elog(DEBUG, "Notifying others");
#endif
#ifdef HAVE_KILL
- if (kill(DatumGetInt32(d), SIGUSR2) < 0) {
- if (errno == ESRCH) {
- heap_delete(lRel, &lTuple->t_ctid);
- }
+ if (kill(DatumGetInt32(d), SIGUSR2) < 0)
+ {
+ if (errno == ESRCH)
+ {
+ heap_delete(lRel, &lTuple->t_ctid);
+ }
+ }
+#endif
+ }
+ }
+ ReleaseBuffer(b);
}
-#endif
- }
+ heap_endscan(sRel);
+ RelationUnsetLockForWrite(lRel);
+ heap_close(lRel);
+
+ CommitTransactionCommand();
+ ClearPendingNotify();
}
- ReleaseBuffer(b);
- }
- heap_endscan(sRel);
- RelationUnsetLockForWrite(lRel);
- heap_close(lRel);
- CommitTransactionCommand();
- ClearPendingNotify();
- }
-
- if (notifyFrontEndPending) { /* we need to notify the frontend of
- all pending notifies. */
- notifyFrontEndPending = 1;
- Async_NotifyFrontEnd();
+ if (notifyFrontEndPending)
+ { /* we need to notify the frontend of all
+ * pending notifies. */
+ notifyFrontEndPending = 1;
+ Async_NotifyFrontEnd();
+ }
}
- }
}
/*
*--------------------------------------------------------------
* Async_NotifyAtAbort --
*
- * Gets rid of pending notifies. List elements are automatically
- * freed through memory context.
- *
+ * Gets rid of pending notifies. List elements are automatically
+ * freed through memory context.
+ *
*
* Results:
- * XXX
+ * XXX
*
* Side effects:
- * XXX
+ * XXX
*
*--------------------------------------------------------------
*/
void
Async_NotifyAtAbort()
{
- extern TransactionState CurrentTransactionState;
-
- if (notifyIssued) {
- ClearPendingNotify();
- }
- notifyIssued = 0;
- if (pendingNotifies)
- DLFreeList(pendingNotifies);
- pendingNotifies = DLNewList();
-
- if ((CurrentTransactionState->state == TRANS_DEFAULT) &&
- (CurrentTransactionState->blockState == TRANS_DEFAULT)) {
- if (notifyFrontEndPending) { /* don't forget to notify front end */
- Async_NotifyFrontEnd();
+ extern TransactionState CurrentTransactionState;
+
+ if (notifyIssued)
+ {
+ ClearPendingNotify();
+ }
+ notifyIssued = 0;
+ if (pendingNotifies)
+ DLFreeList(pendingNotifies);
+ pendingNotifies = DLNewList();
+
+ if ((CurrentTransactionState->state == TRANS_DEFAULT) &&
+ (CurrentTransactionState->blockState == TRANS_DEFAULT))
+ {
+ if (notifyFrontEndPending)
+ { /* don't forget to notify front end */
+ Async_NotifyFrontEnd();
+ }
}
- }
}
/*
*--------------------------------------------------------------
* Async_Listen --
*
- * Register a backend (identified by its Unix PID) as listening
- * on the specified relation.
+ * Register a backend (identified by its Unix PID) as listening
+ * on the specified relation.
*
- * This corresponds to the 'listen <relation>' command in SQL
+ * This corresponds to the 'listen <relation>' command in SQL
*
- * One listener per relation, pg_listener relation is keyed
- * on (relname,pid) to provide multiple listeners in future.
+ * One listener per relation, pg_listener relation is keyed
+ * on (relname,pid) to provide multiple listeners in future.
*
* Results:
- * pg_listeners is updated.
+ * pg_listeners is updated.
*
* Side effects:
- * XXX
+ * XXX
*
*--------------------------------------------------------------
*/
void
Async_Listen(char *relname, int pid)
{
- Datum values[Natts_pg_listener];
- char nulls[Natts_pg_listener];
- TupleDesc tdesc;
- HeapScanDesc s;
- HeapTuple htup,tup;
- Relation lDesc;
- Buffer b;
- Datum d;
- int i;
- bool isnull;
- int alreadyListener = 0;
- int ourPid = getpid();
- char *relnamei;
- TupleDesc tupDesc;
-
+ Datum values[Natts_pg_listener];
+ char nulls[Natts_pg_listener];
+ TupleDesc tdesc;
+ HeapScanDesc s;
+ HeapTuple htup,
+ tup;
+ Relation lDesc;
+ Buffer b;
+ Datum d;
+ int i;
+ bool isnull;
+ int alreadyListener = 0;
+ int ourPid = getpid();
+ char *relnamei;
+ TupleDesc tupDesc;
+
#ifdef ASYNC_DEBUG
- elog(DEBUG,"Async_Listen: %s",relname);
+ elog(DEBUG, "Async_Listen: %s", relname);
#endif
- for (i = 0 ; i < Natts_pg_listener; i++) {
- nulls[i] = ' ';
- values[i] = PointerGetDatum(NULL);
- }
-
- i = 0;
- values[i++] = (Datum) relname;
- values[i++] = (Datum) pid;
- values[i++] = (Datum) 0; /* no notifies pending */
-
- lDesc = heap_openr(ListenerRelationName);
- RelationSetLockForWrite(lDesc);
-
- /* is someone already listening. One listener per relation */
- tdesc = RelationGetTupleDescriptor(lDesc);
- s = heap_beginscan(lDesc,0,NowTimeQual,0,(ScanKey)NULL);
- while (HeapTupleIsValid(htup = heap_getnext(s,0,&b))) {
- d = (Datum) heap_getattr(htup,b,Anum_pg_listener_relname,tdesc,
- &isnull);
- relnamei = DatumGetPointer(d);
- if (!strncmp(relnamei,relname, NAMEDATALEN)) {
- d = (Datum) heap_getattr(htup,b,Anum_pg_listener_pid,tdesc,&isnull);
- pid = DatumGetInt32(d);
- if (pid == ourPid) {
- alreadyListener = 1;
- }
+ for (i = 0; i < Natts_pg_listener; i++)
+ {
+ nulls[i] = ' ';
+ values[i] = PointerGetDatum(NULL);
}
- ReleaseBuffer(b);
- }
- heap_endscan(s);
-
- if (alreadyListener) {
- elog(NOTICE, "Async_Listen: We are already listening on %s",
- relname);
- return;
- }
-
- tupDesc = lDesc->rd_att;
- tup = heap_formtuple(tupDesc,
- values,
- nulls);
- heap_insert(lDesc, tup);
-
- pfree(tup);
- /* if (alreadyListener) {
- elog(NOTICE,"Async_Listen: already one listener on %s (possibly dead)",relname);
- }*/
-
- RelationUnsetLockForWrite(lDesc);
- heap_close(lDesc);
-
- /*
- * now that we are listening, we should make a note to ourselves
- * to unlisten prior to dying.
- */
- relnamei = malloc(NAMEDATALEN); /* persists to process exit */
- strNcpy(relnamei, relname, NAMEDATALEN-1);
- on_exitpg(Async_UnlistenOnExit, (caddr_t) relnamei);
+
+ i = 0;
+ values[i++] = (Datum) relname;
+ values[i++] = (Datum) pid;
+ values[i++] = (Datum) 0; /* no notifies pending */
+
+ lDesc = heap_openr(ListenerRelationName);
+ RelationSetLockForWrite(lDesc);
+
+ /* is someone already listening. One listener per relation */
+ tdesc = RelationGetTupleDescriptor(lDesc);
+ s = heap_beginscan(lDesc, 0, NowTimeQual, 0, (ScanKey) NULL);
+ while (HeapTupleIsValid(htup = heap_getnext(s, 0, &b)))
+ {
+ d = (Datum) heap_getattr(htup, b, Anum_pg_listener_relname, tdesc,
+ &isnull);
+ relnamei = DatumGetPointer(d);
+ if (!strncmp(relnamei, relname, NAMEDATALEN))
+ {
+ d = (Datum) heap_getattr(htup, b, Anum_pg_listener_pid, tdesc, &isnull);
+ pid = DatumGetInt32(d);
+ if (pid == ourPid)
+ {
+ alreadyListener = 1;
+ }
+ }
+ ReleaseBuffer(b);
+ }
+ heap_endscan(s);
+
+ if (alreadyListener)
+ {
+ elog(NOTICE, "Async_Listen: We are already listening on %s",
+ relname);
+ return;
+ }
+
+ tupDesc = lDesc->rd_att;
+ tup = heap_formtuple(tupDesc,
+ values,
+ nulls);
+ heap_insert(lDesc, tup);
+
+ pfree(tup);
+
+ /*
+ * if (alreadyListener) { elog(NOTICE,"Async_Listen: already one
+ * listener on %s (possibly dead)",relname); }
+ */
+
+ RelationUnsetLockForWrite(lDesc);
+ heap_close(lDesc);
+
+ /*
+ * now that we are listening, we should make a note to ourselves to
+ * unlisten prior to dying.
+ */
+ relnamei = malloc(NAMEDATALEN); /* persists to process exit */
+ strNcpy(relnamei, relname, NAMEDATALEN - 1);
+ on_exitpg(Async_UnlistenOnExit, (caddr_t) relnamei);
}
/*
*--------------------------------------------------------------
* Async_Unlisten --
*
- * Remove the backend from the list of listening backends
- * for the specified relation.
- *
- * This would correspond to the 'unlisten <relation>'
- * command, but there isn't one yet.
+ * Remove the backend from the list of listening backends
+ * for the specified relation.
+ *
+ * This would correspond to the 'unlisten <relation>'
+ * command, but there isn't one yet.
*
* Results:
- * pg_listeners is updated.
+ * pg_listeners is updated.
*
* Side effects:
- * XXX
+ * XXX
*
*--------------------------------------------------------------
*/
static void
Async_Unlisten(char *relname, int pid)
{
- Relation lDesc;
- HeapTuple lTuple;
-
- lTuple = SearchSysCacheTuple(LISTENREL, PointerGetDatum(relname),
- Int32GetDatum(pid),
- 0,0);
- lDesc = heap_openr(ListenerRelationName);
- RelationSetLockForWrite(lDesc);
-
- if (lTuple != NULL) {
- heap_delete(lDesc,&lTuple->t_ctid);
- }
-
- RelationUnsetLockForWrite(lDesc);
- heap_close(lDesc);
+ Relation lDesc;
+ HeapTuple lTuple;
+
+ lTuple = SearchSysCacheTuple(LISTENREL, PointerGetDatum(relname),
+ Int32GetDatum(pid),
+ 0, 0);
+ lDesc = heap_openr(ListenerRelationName);
+ RelationSetLockForWrite(lDesc);
+
+ if (lTuple != NULL)
+ {
+ heap_delete(lDesc, &lTuple->t_ctid);
+ }
+
+ RelationUnsetLockForWrite(lDesc);
+ heap_close(lDesc);
}
static void
Async_UnlistenOnExit(int code, /* from exitpg */
- char *relname)
+ char *relname)
{
- Async_Unlisten((char *) relname, getpid());
+ Async_Unlisten((char *) relname, getpid());
}
/*
* --------------------------------------------------------------
* Async_NotifyFrontEnd --
*
- * Perform an asynchronous notification to front end over
- * portal comm channel. The name of the relation which contains the
- * data is sent to the front end.
+ * Perform an asynchronous notification to front end over
+ * portal comm channel. The name of the relation which contains the
+ * data is sent to the front end.
*
- * We remove the notification flag from the pg_listener tuple
- * associated with our process.
+ * We remove the notification flag from the pg_listener tuple
+ * associated with our process.
*
* Results:
- * XXX
+ * XXX
*
* Side effects:
*
- * We make use of the out-of-band channel to transmit the
- * notification to the front end. The actual data transfer takes
- * place at the front end's request.
+ * We make use of the out-of-band channel to transmit the
+ * notification to the front end. The actual data transfer takes
+ * place at the front end's request.
*
* --------------------------------------------------------------
*/
-GlobalMemory notifyContext = NULL;
+GlobalMemory notifyContext = NULL;
static void
Async_NotifyFrontEnd()
{
- extern CommandDest whereToSendOutput;
- HeapTuple lTuple, rTuple;
- Relation lRel;
- HeapScanDesc sRel;
- TupleDesc tdesc;
- ScanKeyData key[2];
- Datum d, value[3];
- char repl[3], nulls[3];
- Buffer b;
- int ourpid;
- bool isnull;
-
- notifyFrontEndPending = 0;
-
+ extern CommandDest whereToSendOutput;
+ HeapTuple lTuple,
+ rTuple;
+ Relation lRel;
+ HeapScanDesc sRel;
+ TupleDesc tdesc;
+ ScanKeyData key[2];
+ Datum d,
+ value[3];
+ char repl[3],
+ nulls[3];
+ Buffer b;
+ int ourpid;
+ bool isnull;
+
+ notifyFrontEndPending = 0;
+
#ifdef ASYNC_DEBUG
- elog(DEBUG, "Async_NotifyFrontEnd: notifying front end.");
+ elog(DEBUG, "Async_NotifyFrontEnd: notifying front end.");
#endif
-
- StartTransactionCommand();
- ourpid = getpid();
- ScanKeyEntryInitialize(&key[0], 0,
- Anum_pg_listener_notify,
- Integer32EqualRegProcedure,
- Int32GetDatum(1));
- ScanKeyEntryInitialize(&key[1], 0,
- Anum_pg_listener_pid,
- Integer32EqualRegProcedure,
- Int32GetDatum(ourpid));
- lRel = heap_openr(ListenerRelationName);
- RelationSetLockForWrite(lRel);
- tdesc = RelationGetTupleDescriptor(lRel);
- sRel = heap_beginscan(lRel, 0, NowTimeQual, 2, key);
-
- nulls[0] = nulls[1] = nulls[2] = ' ';
- repl[0] = repl[1] = repl[2] = ' ';
- repl[Anum_pg_listener_notify - 1] = 'r';
- value[0] = value[1] = value[2] = (Datum) 0;
- value[Anum_pg_listener_notify - 1] = Int32GetDatum(0);
-
- while (HeapTupleIsValid(lTuple = heap_getnext(sRel, 0,&b))) {
- d = (Datum) heap_getattr(lTuple, b, Anum_pg_listener_relname,
- tdesc, &isnull);
- rTuple = heap_modifytuple(lTuple, b, lRel, value, nulls, repl);
- heap_replace(lRel, &lTuple->t_ctid, rTuple);
-
- /* notifying the front end */
-
- if (whereToSendOutput == Remote) {
- pq_putnchar("A", 1);
- pq_putint(ourpid, 4);
- pq_putstr(DatumGetName(d)->data);
- pq_flush();
- } else {
- elog(NOTICE, "Async_NotifyFrontEnd: no asynchronous notification to frontend on interactive sessions");
+
+ StartTransactionCommand();
+ ourpid = getpid();
+ ScanKeyEntryInitialize(&key[0], 0,
+ Anum_pg_listener_notify,
+ Integer32EqualRegProcedure,
+ Int32GetDatum(1));
+ ScanKeyEntryInitialize(&key[1], 0,
+ Anum_pg_listener_pid,
+ Integer32EqualRegProcedure,
+ Int32GetDatum(ourpid));
+ lRel = heap_openr(ListenerRelationName);
+ RelationSetLockForWrite(lRel);
+ tdesc = RelationGetTupleDescriptor(lRel);
+ sRel = heap_beginscan(lRel, 0, NowTimeQual, 2, key);
+
+ nulls[0] = nulls[1] = nulls[2] = ' ';
+ repl[0] = repl[1] = repl[2] = ' ';
+ repl[Anum_pg_listener_notify - 1] = 'r';
+ value[0] = value[1] = value[2] = (Datum) 0;
+ value[Anum_pg_listener_notify - 1] = Int32GetDatum(0);
+
+ while (HeapTupleIsValid(lTuple = heap_getnext(sRel, 0, &b)))
+ {
+ d = (Datum) heap_getattr(lTuple, b, Anum_pg_listener_relname,
+ tdesc, &isnull);
+ rTuple = heap_modifytuple(lTuple, b, lRel, value, nulls, repl);
+ heap_replace(lRel, &lTuple->t_ctid, rTuple);
+
+ /* notifying the front end */
+
+ if (whereToSendOutput == Remote)
+ {
+ pq_putnchar("A", 1);
+ pq_putint(ourpid, 4);
+ pq_putstr(DatumGetName(d)->data);
+ pq_flush();
+ }
+ else
+ {
+ elog(NOTICE, "Async_NotifyFrontEnd: no asynchronous notification to frontend on interactive sessions");
+ }
+ ReleaseBuffer(b);
}
- ReleaseBuffer(b);
- }
- CommitTransactionCommand();
+ CommitTransactionCommand();
}
static int
AsyncExistsPendingNotify(char *relname)
{
- Dlelem* p;
- for (p = DLGetHead(pendingNotifies);
- p != NULL;
- p = DLGetSucc(p)) {
- /* Use NAMEDATALEN for relname comparison. DZ - 26-08-1996 */
- if (!strncmp(DLE_VAL(p), relname, NAMEDATALEN))
- return 1;
- }
-
- return 0;
+ Dlelem *p;
+
+ for (p = DLGetHead(pendingNotifies);
+ p != NULL;
+ p = DLGetSucc(p))
+ {
+ /* Use NAMEDATALEN for relname comparison. DZ - 26-08-1996 */
+ if (!strncmp(DLE_VAL(p), relname, NAMEDATALEN))
+ return 1;
+ }
+
+ return 0;
}
static void
ClearPendingNotify()
{
- Dlelem* p;
- while ( (p = DLRemHead(pendingNotifies)) != NULL)
- free(DLE_VAL(p));
-}
+ Dlelem *p;
+ while ((p = DLRemHead(pendingNotifies)) != NULL)
+ free(DLE_VAL(p));
+}
diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c
index 65a9c041643..2b18cb46df0 100644
--- a/src/backend/commands/cluster.c
+++ b/src/backend/commands/cluster.c
@@ -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];
-
-
- /* 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();
-
- /* 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);
-
- renamerel(NewIndexName, saveoldindexname);
-
- /*
- * Again flush all the buffers.
- */
- CommitTransactionCommand();
- StartTransactionCommand();
+ 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);
+
+
+ /* 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();
+
+ /* 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);
+
+ 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;
-
- /*
- * 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);
-
- /*
- * 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);
-
- if (!OidIsValid(OIDNewHeap))
- elog(WARN,"clusterheap: cannot create temporary heap relation\n");
-
- NewHeap=heap_open(OIDNewHeap);
-
- heap_close(NewHeap);
- heap_close(OldHeap);
-
- return NewHeap;
+ 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);
+
+ OldHeap = heap_open(OIDOldHeap);
+ OldHeapDesc = RelationGetTupleDescriptor(OldHeap);
+
+ /*
+ * 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);
+
+ if (!OidIsValid(OIDNewHeap))
+ elog(WARN, "clusterheap: cannot create temporary heap relation\n");
+
+ NewHeap = heap_open(OIDNewHeap);
+
+ 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;
-
- 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);
-
- 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);
-
- 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. */
-
- /*
- * 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;
-
- 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;
- }
-
- 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);
+ 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);
+
+ /*
+ * 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);
+
+ 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);
+
+ 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++);
+
+ /*
+ * 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);
+
+ 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);
+
+ 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;
-
- /*
- * 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);
-
- 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);
-
- index_close(LocalOldIndex);
- heap_close(LocalOldHeap);
- heap_close(LocalNewHeap);
+ 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);
+
+ ScanDesc = index_beginscan(LocalOldIndex, false, 0, (ScanKey) 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);
+
+ index_close(LocalOldIndex);
+ heap_close(LocalOldHeap);
+ heap_close(LocalNewHeap);
}
-
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c
index 376bd3ae5fa..7af9b37c072 100644
--- a/src/backend/commands/command.c
+++ b/src/backend/commands/command.c
@@ -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;
+ }
+
+ 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;
}
- heap_endscan(attsdesc);
-
+
+ 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);
+ 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
+ */
+ 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);
}
- 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);
+ 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);
}
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 687cd1eb12e..795e9f5584f 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -6,7 +6,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.29 1997/09/04 13:18:59 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.30 1997/09/07 04:40:40 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -42,736 +42,857 @@
/* non-export function prototypes */
-static void CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim);
-static void CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim);
-static Oid GetOutputFunction(Oid type);
-static Oid GetTypeElement(Oid type);
-static Oid GetInputFunction(Oid type);
-static Oid IsTypeByVal(Oid type);
-static void GetIndexRelations(Oid main_relation_oid,
- int *n_indices,
- Relation **index_rels);
+static void CopyTo(Relation rel, bool binary, bool oids, FILE * fp, char *delim);
+static void CopyFrom(Relation rel, bool binary, bool oids, FILE * fp, char *delim);
+static Oid GetOutputFunction(Oid type);
+static Oid GetTypeElement(Oid type);
+static Oid GetInputFunction(Oid type);
+static Oid IsTypeByVal(Oid type);
+static void
+GetIndexRelations(Oid main_relation_oid,
+ int *n_indices,
+ Relation ** index_rels);
+
#ifdef COPY_PATCH
-static void CopyReadNewline(FILE *fp, int *newline);
-static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline);
+static void CopyReadNewline(FILE * fp, int *newline);
+static char *CopyReadAttribute(FILE * fp, bool * isnull, char *delim, int *newline);
+
#else
-static char *CopyReadAttribute(FILE *fp, bool *isnull, char *delim);
+static char *CopyReadAttribute(FILE * fp, bool * isnull, char *delim);
+
#endif
-static void CopyAttributeOut(FILE *fp, char *string, char *delim);
-static int CountTuples(Relation relation);
+static void CopyAttributeOut(FILE * fp, char *string, char *delim);
+static int CountTuples(Relation relation);
-extern FILE *Pfout, *Pfin;
+extern FILE *Pfout,
+ *Pfin;
#ifdef COPY_DEBUG
-static int lineno;
+static int lineno;
+
#endif
-
+
/*
- * DoCopy executes a the SQL COPY statement.
+ * DoCopy executes a the SQL COPY statement.
*/
void
-DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
- char *filename, char *delim) {
+DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
+ char *filename, char *delim)
+{
/*----------------------------------------------------------------------------
Either unload or reload contents of class <relname>, depending on <from>.
If <pipe> is false, transfer is between the class and the file named
<filename>. Otherwise, transfer is between the class and our regular
- input/output stream. The latter could be either stdin/stdout or a
+ input/output stream. The latter could be either stdin/stdout or a
socket, depending on whether we're running under Postmaster control.
Iff <binary>, unload or reload in the binary format, as opposed to the
- more wasteful but more robust and portable text format.
+ more wasteful but more robust and portable text format.
- If in the text format, delimit columns with delimiter <delim>.
+ If in the text format, delimit columns with delimiter <delim>.
When loading in the text format from an input stream (as opposed to
- a file), recognize a "." on a line by itself as EOF. Also recognize
+ a file), recognize a "." on a line by itself as EOF. Also recognize
a stream EOF. When unloading in the text format to an output stream,
write a "." on a line by itself at the end of the data.
Iff <oids>, unload or reload the format that includes OID information.
Do not allow a Postgres user without superuser privilege to read from
- or write to a file.
+ or write to a file.
Do not allow the copy if user doesn't have proper permission to access
the class.
----------------------------------------------------------------------------*/
- FILE *fp;
- Relation rel;
- extern char *UserName; /* defined in global.c */
- const AclMode required_access = from ? ACL_WR : ACL_RD;
- int result;
-
- rel = heap_openr(relname);
- if (rel == NULL) elog(WARN, "COPY command failed. Class %s "
- "does not exist.", relname);
-
- result = pg_aclcheck(relname, UserName, required_access);
- if(result != ACLCHECK_OK)
- elog(WARN, "%s: %s", relname, aclcheck_error_strings[result]);
- /* Above should not return */
- else if (!superuser() && !pipe)
- elog(WARN, "You must have Postgres superuser privilege to do a COPY "
- "directly to or from a file. Anyone can COPY to stdout or "
- "from stdin. Psql's \\copy command also works for anyone.");
- /* Above should not return. */
- else {
- if (from) { /* copy from file to database */
- if ( rel->rd_rel->relkind == RELKIND_SEQUENCE )
- elog (WARN, "You can't change sequence relation %s", relname);
- if (pipe) {
- if (IsUnderPostmaster) {
- ReceiveCopyBegin();
- fp = Pfin;
- } else fp = stdin;
- } else {
- fp = AllocateFile(filename, "r");
- if (fp == NULL)
- elog(WARN, "COPY command, running in backend with "
- "effective uid %d, could not open file '%s' for "
- "reading. Errno = %s (%d).",
- geteuid(), filename, strerror(errno), errno);
- /* Above should not return */
- }
- CopyFrom(rel, binary, oids, fp, delim);
- } else { /* copy from database to file */
- if (pipe) {
- if (IsUnderPostmaster) {
- SendCopyBegin();
- fp = Pfout;
- } else fp = stdout;
- } else {
- mode_t oumask; /* Pre-existing umask value */
- oumask = umask((mode_t) 0);
- fp = AllocateFile(filename, "w");
- umask(oumask);
- if (fp == NULL)
- elog(WARN, "COPY command, running in backend with "
- "effective uid %d, could not open file '%s' for "
- "writing. Errno = %s (%d).",
- geteuid(), filename, strerror(errno), errno);
- /* Above should not return */
- }
- CopyTo(rel, binary, oids, fp, delim);
- }
- if (!pipe)
- FreeFile(fp);
- else if (!from && !binary) {
- fputs("\\.\n", fp);
- if (IsUnderPostmaster) fflush(Pfout);
- }
- }
+ FILE *fp;
+ Relation rel;
+ extern char *UserName; /* defined in global.c */
+ const AclMode required_access = from ? ACL_WR : ACL_RD;
+ int result;
+
+ rel = heap_openr(relname);
+ if (rel == NULL)
+ elog(WARN, "COPY command failed. Class %s "
+ "does not exist.", relname);
+
+ result = pg_aclcheck(relname, UserName, required_access);
+ if (result != ACLCHECK_OK)
+ elog(WARN, "%s: %s", relname, aclcheck_error_strings[result]);
+ /* Above should not return */
+ else if (!superuser() && !pipe)
+ elog(WARN, "You must have Postgres superuser privilege to do a COPY "
+ "directly to or from a file. Anyone can COPY to stdout or "
+ "from stdin. Psql's \\copy command also works for anyone.");
+ /* Above should not return. */
+ else
+ {
+ if (from)
+ { /* copy from file to database */
+ if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
+ elog(WARN, "You can't change sequence relation %s", relname);
+ if (pipe)
+ {
+ if (IsUnderPostmaster)
+ {
+ ReceiveCopyBegin();
+ fp = Pfin;
+ }
+ else
+ fp = stdin;
+ }
+ else
+ {
+ fp = AllocateFile(filename, "r");
+ if (fp == NULL)
+ elog(WARN, "COPY command, running in backend with "
+ "effective uid %d, could not open file '%s' for "
+ "reading. Errno = %s (%d).",
+ geteuid(), filename, strerror(errno), errno);
+ /* Above should not return */
+ }
+ CopyFrom(rel, binary, oids, fp, delim);
+ }
+ else
+ { /* copy from database to file */
+ if (pipe)
+ {
+ if (IsUnderPostmaster)
+ {
+ SendCopyBegin();
+ fp = Pfout;
+ }
+ else
+ fp = stdout;
+ }
+ else
+ {
+ mode_t oumask; /* Pre-existing umask value */
+
+ oumask = umask((mode_t) 0);
+ fp = AllocateFile(filename, "w");
+ umask(oumask);
+ if (fp == NULL)
+ elog(WARN, "COPY command, running in backend with "
+ "effective uid %d, could not open file '%s' for "
+ "writing. Errno = %s (%d).",
+ geteuid(), filename, strerror(errno), errno);
+ /* Above should not return */
+ }
+ CopyTo(rel, binary, oids, fp, delim);
+ }
+ if (!pipe)
+ FreeFile(fp);
+ else if (!from && !binary)
+ {
+ fputs("\\.\n", fp);
+ if (IsUnderPostmaster)
+ fflush(Pfout);
+ }
+ }
}
static void
-CopyTo(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
+CopyTo(Relation rel, bool binary, bool oids, FILE * fp, char *delim)
{
- HeapTuple tuple;
- HeapScanDesc scandesc;
-
- int32 attr_count, i;
- AttributeTupleForm *attr;
- func_ptr *out_functions;
- int dummy;
- Oid out_func_oid;
- Oid *elements;
- Datum value;
- bool isnull; /* The attribute we are copying is null */
- char *nulls;
- /* <nulls> is a (dynamically allocated) array with one character
- per attribute in the instance being copied. nulls[I-1] is
- 'n' if Attribute Number I is null, and ' ' otherwise.
-
- <nulls> is meaningful only if we are doing a binary copy.
- */
- char *string;
- int32 ntuples;
- TupleDesc tupDesc;
-
- scandesc = heap_beginscan(rel, 0, NULL, 0, NULL);
-
- attr_count = rel->rd_att->natts;
- attr = rel->rd_att->attrs;
- tupDesc = rel->rd_att;
-
- if (!binary) {
- out_functions = (func_ptr *) palloc(attr_count * sizeof(func_ptr));
- elements = (Oid *) palloc(attr_count * sizeof(Oid));
- for (i = 0; i < attr_count; i++) {
- out_func_oid = (Oid) GetOutputFunction(attr[i]->atttypid);
- fmgr_info(out_func_oid, &out_functions[i], &dummy);
- elements[i] = GetTypeElement(attr[i]->atttypid);
- }
- nulls = NULL; /* meaningless, but compiler doesn't know that */
- }else {
- elements = NULL;
- out_functions = NULL;
- nulls = (char *) palloc(attr_count);
- for (i = 0; i < attr_count; i++) nulls[i] = ' ';
-
- /* XXX expensive */
-
- ntuples = CountTuples(rel);
- fwrite(&ntuples, sizeof(int32), 1, fp);
- }
-
- for (tuple = heap_getnext(scandesc, 0, NULL);
- tuple != NULL;
- tuple = heap_getnext(scandesc, 0, NULL)) {
-
- if (oids && !binary) {
- fputs(oidout(tuple->t_oid),fp);
- fputc(delim[0], fp);
- }
-
- for (i = 0; i < attr_count; i++) {
- value = (Datum)
- heap_getattr(tuple, InvalidBuffer, i+1, tupDesc, &isnull);
- if (!binary) {
- if (!isnull) {
- string = (char *) (out_functions[i]) (value, elements[i]);
- CopyAttributeOut(fp, string, delim);
- pfree(string);
- }
- else
- fputs("\\N", fp); /* null indicator */
-
- if (i == attr_count - 1) {
- fputc('\n', fp);
- }else {
- /* when copying out, only use the first char of the delim
- string */
- fputc(delim[0], fp);
- }
- }else {
- /*
- * only interesting thing heap_getattr tells us in this case
- * is if we have a null attribute or not.
- */
- if (isnull) nulls[i] = 'n';
- }
- }
-
- if (binary) {
- int32 null_ct = 0, length;
-
- for (i = 0; i < attr_count; i++) {
- if (nulls[i] == 'n') null_ct++;
- }
-
- length = tuple->t_len - tuple->t_hoff;
- fwrite(&length, sizeof(int32), 1, fp);
- if (oids)
- fwrite((char *) &tuple->t_oid, sizeof(int32), 1, fp);
-
- fwrite(&null_ct, sizeof(int32), 1, fp);
- if (null_ct > 0) {
- for (i = 0; i < attr_count; i++) {
- if (nulls[i] == 'n') {
- fwrite(&i, sizeof(int32), 1, fp);
- nulls[i] = ' ';
- }
- }
- }
- fwrite((char *) tuple + tuple->t_hoff, length, 1, fp);
- }
- }
-
- heap_endscan(scandesc);
- if (binary) {
- pfree(nulls);
- }else {
- pfree(out_functions);
- pfree(elements);
- }
-
- heap_close(rel);
+ HeapTuple tuple;
+ HeapScanDesc scandesc;
+
+ int32 attr_count,
+ i;
+ AttributeTupleForm *attr;
+ func_ptr *out_functions;
+ int dummy;
+ Oid out_func_oid;
+ Oid *elements;
+ Datum value;
+ bool isnull; /* The attribute we are copying is null */
+ char *nulls;
+
+ /*
+ * <nulls> is a (dynamically allocated) array with one character per
+ * attribute in the instance being copied. nulls[I-1] is 'n' if
+ * Attribute Number I is null, and ' ' otherwise.
+ *
+ * <nulls> is meaningful only if we are doing a binary copy.
+ */
+ char *string;
+ int32 ntuples;
+ TupleDesc tupDesc;
+
+ scandesc = heap_beginscan(rel, 0, NULL, 0, NULL);
+
+ attr_count = rel->rd_att->natts;
+ attr = rel->rd_att->attrs;
+ tupDesc = rel->rd_att;
+
+ if (!binary)
+ {
+ out_functions = (func_ptr *) palloc(attr_count * sizeof(func_ptr));
+ elements = (Oid *) palloc(attr_count * sizeof(Oid));
+ for (i = 0; i < attr_count; i++)
+ {
+ out_func_oid = (Oid) GetOutputFunction(attr[i]->atttypid);
+ fmgr_info(out_func_oid, &out_functions[i], &dummy);
+ elements[i] = GetTypeElement(attr[i]->atttypid);
+ }
+ nulls = NULL; /* meaningless, but compiler doesn't know
+ * that */
+ }
+ else
+ {
+ elements = NULL;
+ out_functions = NULL;
+ nulls = (char *) palloc(attr_count);
+ for (i = 0; i < attr_count; i++)
+ nulls[i] = ' ';
+
+ /* XXX expensive */
+
+ ntuples = CountTuples(rel);
+ fwrite(&ntuples, sizeof(int32), 1, fp);
+ }
+
+ for (tuple = heap_getnext(scandesc, 0, NULL);
+ tuple != NULL;
+ tuple = heap_getnext(scandesc, 0, NULL))
+ {
+
+ if (oids && !binary)
+ {
+ fputs(oidout(tuple->t_oid), fp);
+ fputc(delim[0], fp);
+ }
+
+ for (i = 0; i < attr_count; i++)
+ {
+ value = (Datum)
+ heap_getattr(tuple, InvalidBuffer, i + 1, tupDesc, &isnull);
+ if (!binary)
+ {
+ if (!isnull)
+ {
+ string = (char *) (out_functions[i]) (value, elements[i]);
+ CopyAttributeOut(fp, string, delim);
+ pfree(string);
+ }
+ else
+ fputs("\\N", fp); /* null indicator */
+
+ if (i == attr_count - 1)
+ {
+ fputc('\n', fp);
+ }
+ else
+ {
+
+ /*
+ * when copying out, only use the first char of the
+ * delim string
+ */
+ fputc(delim[0], fp);
+ }
+ }
+ else
+ {
+
+ /*
+ * only interesting thing heap_getattr tells us in this
+ * case is if we have a null attribute or not.
+ */
+ if (isnull)
+ nulls[i] = 'n';
+ }
+ }
+
+ if (binary)
+ {
+ int32 null_ct = 0,
+ length;
+
+ for (i = 0; i < attr_count; i++)
+ {
+ if (nulls[i] == 'n')
+ null_ct++;
+ }
+
+ length = tuple->t_len - tuple->t_hoff;
+ fwrite(&length, sizeof(int32), 1, fp);
+ if (oids)
+ fwrite((char *) &tuple->t_oid, sizeof(int32), 1, fp);
+
+ fwrite(&null_ct, sizeof(int32), 1, fp);
+ if (null_ct > 0)
+ {
+ for (i = 0; i < attr_count; i++)
+ {
+ if (nulls[i] == 'n')
+ {
+ fwrite(&i, sizeof(int32), 1, fp);
+ nulls[i] = ' ';
+ }
+ }
+ }
+ fwrite((char *) tuple + tuple->t_hoff, length, 1, fp);
+ }
+ }
+
+ heap_endscan(scandesc);
+ if (binary)
+ {
+ pfree(nulls);
+ }
+ else
+ {
+ pfree(out_functions);
+ pfree(elements);
+ }
+
+ heap_close(rel);
}
static void
-CopyFrom(Relation rel, bool binary, bool oids, FILE *fp, char *delim)
+CopyFrom(Relation rel, bool binary, bool oids, FILE * fp, char *delim)
{
- HeapTuple tuple;
- AttrNumber attr_count;
- AttributeTupleForm *attr;
- func_ptr *in_functions;
- int i, dummy;
- Oid in_func_oid;
- Datum *values;
- char *nulls, *index_nulls;
- bool *byval;
- bool isnull;
- bool has_index;
- int done = 0;
- char *string = NULL, *ptr;
- Relation *index_rels;
- int32 len, null_ct, null_id;
- int32 ntuples, tuples_read = 0;
- bool reading_to_eof = true;
- Oid *elements;
- FuncIndexInfo *finfo, **finfoP = NULL;
- TupleDesc *itupdescArr;
- HeapTuple pgIndexTup;
- IndexTupleForm *pgIndexP = NULL;
- int *indexNatts = NULL;
- char *predString;
- Node **indexPred = NULL;
- TupleDesc rtupdesc;
- ExprContext *econtext = NULL;
+ HeapTuple tuple;
+ AttrNumber attr_count;
+ AttributeTupleForm *attr;
+ func_ptr *in_functions;
+ int i,
+ dummy;
+ Oid in_func_oid;
+ Datum *values;
+ char *nulls,
+ *index_nulls;
+ bool *byval;
+ bool isnull;
+ bool has_index;
+ int done = 0;
+ char *string = NULL,
+ *ptr;
+ Relation *index_rels;
+ int32 len,
+ null_ct,
+ null_id;
+ int32 ntuples,
+ tuples_read = 0;
+ bool reading_to_eof = true;
+ Oid *elements;
+ FuncIndexInfo *finfo,
+ **finfoP = NULL;
+ TupleDesc *itupdescArr;
+ HeapTuple pgIndexTup;
+ IndexTupleForm *pgIndexP = NULL;
+ int *indexNatts = NULL;
+ char *predString;
+ Node **indexPred = NULL;
+ TupleDesc rtupdesc;
+ ExprContext *econtext = NULL;
+
#ifndef OMIT_PARTIAL_INDEX
- TupleTable tupleTable;
- TupleTableSlot *slot = NULL;
+ TupleTable tupleTable;
+ TupleTableSlot *slot = NULL;
+
#endif
- int natts;
- AttrNumber *attnumP;
- Datum *idatum;
- int n_indices;
- InsertIndexResult indexRes;
- TupleDesc tupDesc;
- Oid loaded_oid;
- bool skip_tuple = false;
-
- tupDesc = RelationGetTupleDescriptor(rel);
- attr = tupDesc->attrs;
- attr_count = tupDesc->natts;
-
- has_index = false;
-
- /*
- * This may be a scalar or a functional index. We initialize all
- * kinds of arrays here to avoid doing extra work at every tuple
- * copy.
- */
-
- if (rel->rd_rel->relhasindex) {
- GetIndexRelations(rel->rd_id, &n_indices, &index_rels);
- if (n_indices > 0) {
- has_index = true;
- itupdescArr =
- (TupleDesc *)palloc(n_indices * sizeof(TupleDesc));
- pgIndexP =
- (IndexTupleForm *)palloc(n_indices * sizeof(IndexTupleForm));
- indexNatts = (int *) palloc(n_indices * sizeof(int));
- finfo = (FuncIndexInfo *) palloc(n_indices * sizeof(FuncIndexInfo));
- finfoP = (FuncIndexInfo **) palloc(n_indices * sizeof(FuncIndexInfo *));
- indexPred = (Node **) palloc(n_indices * sizeof(Node*));
- econtext = NULL;
- for (i = 0; i < n_indices; i++) {
- itupdescArr[i] = RelationGetTupleDescriptor(index_rels[i]);
- pgIndexTup =
- SearchSysCacheTuple(INDEXRELID,
- ObjectIdGetDatum(index_rels[i]->rd_id),
- 0,0,0);
- Assert(pgIndexTup);
- pgIndexP[i] = (IndexTupleForm)GETSTRUCT(pgIndexTup);
- for (attnumP = &(pgIndexP[i]->indkey[0]), natts = 0;
- *attnumP != InvalidAttrNumber;
- attnumP++, natts++);
- if (pgIndexP[i]->indproc != InvalidOid) {
- FIgetnArgs(&finfo[i]) = natts;
- natts = 1;
- FIgetProcOid(&finfo[i]) = pgIndexP[i]->indproc;
- *(FIgetname(&finfo[i])) = '\0';
- finfoP[i] = &finfo[i];
- } else
- finfoP[i] = (FuncIndexInfo *) NULL;
- indexNatts[i] = natts;
- if (VARSIZE(&pgIndexP[i]->indpred) != 0) {
- predString = fmgr(F_TEXTOUT, &pgIndexP[i]->indpred);
- indexPred[i] = stringToNode(predString);
- pfree(predString);
- /* make dummy ExprContext for use by ExecQual */
- if (econtext == NULL) {
+ int natts;
+ AttrNumber *attnumP;
+ Datum *idatum;
+ int n_indices;
+ InsertIndexResult indexRes;
+ TupleDesc tupDesc;
+ Oid loaded_oid;
+ bool skip_tuple = false;
+
+ tupDesc = RelationGetTupleDescriptor(rel);
+ attr = tupDesc->attrs;
+ attr_count = tupDesc->natts;
+
+ has_index = false;
+
+ /*
+ * This may be a scalar or a functional index. We initialize all
+ * kinds of arrays here to avoid doing extra work at every tuple copy.
+ */
+
+ if (rel->rd_rel->relhasindex)
+ {
+ GetIndexRelations(rel->rd_id, &n_indices, &index_rels);
+ if (n_indices > 0)
+ {
+ has_index = true;
+ itupdescArr =
+ (TupleDesc *) palloc(n_indices * sizeof(TupleDesc));
+ pgIndexP =
+ (IndexTupleForm *) palloc(n_indices * sizeof(IndexTupleForm));
+ indexNatts = (int *) palloc(n_indices * sizeof(int));
+ finfo = (FuncIndexInfo *) palloc(n_indices * sizeof(FuncIndexInfo));
+ finfoP = (FuncIndexInfo **) palloc(n_indices * sizeof(FuncIndexInfo *));
+ indexPred = (Node **) palloc(n_indices * sizeof(Node *));
+ econtext = NULL;
+ for (i = 0; i < n_indices; i++)
+ {
+ itupdescArr[i] = RelationGetTupleDescriptor(index_rels[i]);
+ pgIndexTup =
+ SearchSysCacheTuple(INDEXRELID,
+ ObjectIdGetDatum(index_rels[i]->rd_id),
+ 0, 0, 0);
+ Assert(pgIndexTup);
+ pgIndexP[i] = (IndexTupleForm) GETSTRUCT(pgIndexTup);
+ for (attnumP = &(pgIndexP[i]->indkey[0]), natts = 0;
+ *attnumP != InvalidAttrNumber;
+ attnumP++, natts++);
+ if (pgIndexP[i]->indproc != InvalidOid)
+ {
+ FIgetnArgs(&finfo[i]) = natts;
+ natts = 1;
+ FIgetProcOid(&finfo[i]) = pgIndexP[i]->indproc;
+ *(FIgetname(&finfo[i])) = '\0';
+ finfoP[i] = &finfo[i];
+ }
+ else
+ finfoP[i] = (FuncIndexInfo *) NULL;
+ indexNatts[i] = natts;
+ if (VARSIZE(&pgIndexP[i]->indpred) != 0)
+ {
+ predString = fmgr(F_TEXTOUT, &pgIndexP[i]->indpred);
+ indexPred[i] = stringToNode(predString);
+ pfree(predString);
+ /* make dummy ExprContext for use by ExecQual */
+ if (econtext == NULL)
+ {
#ifndef OMIT_PARTIAL_INDEX
- tupleTable = ExecCreateTupleTable(1);
- slot = ExecAllocTableSlot(tupleTable);
- econtext = makeNode(ExprContext);
- econtext->ecxt_scantuple = slot;
- rtupdesc = RelationGetTupleDescriptor(rel);
- slot->ttc_tupleDescriptor = rtupdesc;
- /*
- * There's no buffer associated with heap tuples here,
- * so I set the slot's buffer to NULL. Currently, it
- * appears that the only way a buffer could be needed
- * would be if the partial index predicate referred to
- * the "lock" system attribute. If it did, then
- * heap_getattr would call HeapTupleGetRuleLock, which
- * uses the buffer's descriptor to get the relation id.
- * Rather than try to fix this, I'll just disallow
- * partial indexes on "lock", which wouldn't be useful
- * anyway. --Nels, Nov '92
- */
- /* SetSlotBuffer(slot, (Buffer) NULL); */
- /* SetSlotShouldFree(slot, false); */
- slot->ttc_buffer = (Buffer)NULL;
- slot->ttc_shouldFree = false;
-#endif /* OMIT_PARTIAL_INDEX */
- }
- } else {
- indexPred[i] = NULL;
- }
- }
- }
- }
-
- if (!binary)
- {
- in_functions = (func_ptr *) palloc(attr_count * sizeof(func_ptr));
- elements = (Oid *) palloc(attr_count * sizeof(Oid));
- for (i = 0; i < attr_count; i++)
- {
- in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid);
- fmgr_info(in_func_oid, &in_functions[i], &dummy);
- elements[i] = GetTypeElement(attr[i]->atttypid);
- }
- }
- else
- {
- in_functions = NULL;
- elements = NULL;
- fread(&ntuples, sizeof(int32), 1, fp);
- if (ntuples != 0) reading_to_eof = false;
- }
-
- values = (Datum *) palloc(sizeof(Datum) * attr_count);
- nulls = (char *) palloc(attr_count);
- index_nulls = (char *) palloc(attr_count);
- idatum = (Datum *) palloc(sizeof(Datum) * attr_count);
- byval = (bool *) palloc(attr_count * sizeof(bool));
-
- for (i = 0; i < attr_count; i++) {
- nulls[i] = ' ';
- index_nulls[i] = ' ';
- byval[i] = (bool) IsTypeByVal(attr[i]->atttypid);
- }
-
+ tupleTable = ExecCreateTupleTable(1);
+ slot = ExecAllocTableSlot(tupleTable);
+ econtext = makeNode(ExprContext);
+ econtext->ecxt_scantuple = slot;
+ rtupdesc = RelationGetTupleDescriptor(rel);
+ slot->ttc_tupleDescriptor = rtupdesc;
+
+ /*
+ * There's no buffer associated with heap tuples
+ * here, so I set the slot's buffer to NULL.
+ * Currently, it appears that the only way a
+ * buffer could be needed would be if the partial
+ * index predicate referred to the "lock" system
+ * attribute. If it did, then heap_getattr would
+ * call HeapTupleGetRuleLock, which uses the
+ * buffer's descriptor to get the relation id.
+ * Rather than try to fix this, I'll just disallow
+ * partial indexes on "lock", which wouldn't be
+ * useful anyway. --Nels, Nov '92
+ */
+ /* SetSlotBuffer(slot, (Buffer) NULL); */
+ /* SetSlotShouldFree(slot, false); */
+ slot->ttc_buffer = (Buffer) NULL;
+ slot->ttc_shouldFree = false;
+#endif /* OMIT_PARTIAL_INDEX */
+ }
+ }
+ else
+ {
+ indexPred[i] = NULL;
+ }
+ }
+ }
+ }
+
+ if (!binary)
+ {
+ in_functions = (func_ptr *) palloc(attr_count * sizeof(func_ptr));
+ elements = (Oid *) palloc(attr_count * sizeof(Oid));
+ for (i = 0; i < attr_count; i++)
+ {
+ in_func_oid = (Oid) GetInputFunction(attr[i]->atttypid);
+ fmgr_info(in_func_oid, &in_functions[i], &dummy);
+ elements[i] = GetTypeElement(attr[i]->atttypid);
+ }
+ }
+ else
+ {
+ in_functions = NULL;
+ elements = NULL;
+ fread(&ntuples, sizeof(int32), 1, fp);
+ if (ntuples != 0)
+ reading_to_eof = false;
+ }
+
+ values = (Datum *) palloc(sizeof(Datum) * attr_count);
+ nulls = (char *) palloc(attr_count);
+ index_nulls = (char *) palloc(attr_count);
+ idatum = (Datum *) palloc(sizeof(Datum) * attr_count);
+ byval = (bool *) palloc(attr_count * sizeof(bool));
+
+ for (i = 0; i < attr_count; i++)
+ {
+ nulls[i] = ' ';
+ index_nulls[i] = ' ';
+ byval[i] = (bool) IsTypeByVal(attr[i]->atttypid);
+ }
+
#ifdef COPY_DEBUG
- lineno = 0;
+ lineno = 0;
#endif
- while (!done) {
- if (!binary) {
+ while (!done)
+ {
+ if (!binary)
+ {
#ifdef COPY_PATCH
- int newline = 0;
+ int newline = 0;
+
#endif
#ifdef COPY_DEBUG
- lineno++;
- elog(DEBUG, "line %d", lineno);
+ lineno++;
+ elog(DEBUG, "line %d", lineno);
#endif
- if (oids) {
+ if (oids)
+ {
#ifdef COPY_PATCH
- string = CopyReadAttribute(fp, &isnull, delim, &newline);
+ string = CopyReadAttribute(fp, &isnull, delim, &newline);
#else
- string = CopyReadAttribute(fp, &isnull, delim);
+ string = CopyReadAttribute(fp, &isnull, delim);
#endif
- if (string == NULL)
- done = 1;
- else {
- loaded_oid = oidin(string);
- if (loaded_oid < BootstrapObjectIdData)
- elog(WARN, "COPY TEXT: Invalid Oid");
- }
- }
- for (i = 0; i < attr_count && !done; i++) {
+ if (string == NULL)
+ done = 1;
+ else
+ {
+ loaded_oid = oidin(string);
+ if (loaded_oid < BootstrapObjectIdData)
+ elog(WARN, "COPY TEXT: Invalid Oid");
+ }
+ }
+ for (i = 0; i < attr_count && !done; i++)
+ {
#ifdef COPY_PATCH
- string = CopyReadAttribute(fp, &isnull, delim, &newline);
+ string = CopyReadAttribute(fp, &isnull, delim, &newline);
#else
- string = CopyReadAttribute(fp, &isnull, delim);
+ string = CopyReadAttribute(fp, &isnull, delim);
#endif
- if (isnull) {
- values[i] = PointerGetDatum(NULL);
- nulls[i] = 'n';
- }else if (string == NULL) {
- done = 1;
- }else {
- values[i] =
- (Datum)(in_functions[i])(string,
- elements[i],
- attr[i]->attlen);
- /*
- * Sanity check - by reference attributes cannot return
- * NULL
- */
- if (!PointerIsValid(values[i]) &&
- !(rel->rd_att->attrs[i]->attbyval)) {
+ if (isnull)
+ {
+ values[i] = PointerGetDatum(NULL);
+ nulls[i] = 'n';
+ }
+ else if (string == NULL)
+ {
+ done = 1;
+ }
+ else
+ {
+ values[i] =
+ (Datum) (in_functions[i]) (string,
+ elements[i],
+ attr[i]->attlen);
+
+ /*
+ * Sanity check - by reference attributes cannot
+ * return NULL
+ */
+ if (!PointerIsValid(values[i]) &&
+ !(rel->rd_att->attrs[i]->attbyval))
+ {
#ifdef COPY_DEBUG
- elog(WARN,
- "copy from: line %d - Bad file format", lineno);
+ elog(WARN,
+ "copy from: line %d - Bad file format", lineno);
#else
- elog(WARN, "copy from: Bad file format");
+ elog(WARN, "copy from: Bad file format");
#endif
- }
- }
- }
+ }
+ }
+ }
#ifdef COPY_PATCH
- if (!done) {
- CopyReadNewline(fp, &newline);
- }
+ if (!done)
+ {
+ CopyReadNewline(fp, &newline);
+ }
#endif
- }else { /* binary */
- fread(&len, sizeof(int32), 1, fp);
- if (feof(fp)) {
- done = 1;
- }else {
- if (oids) {
- fread(&loaded_oid, sizeof(int32), 1, fp);
- if (loaded_oid < BootstrapObjectIdData)
- elog(WARN, "COPY BINARY: Invalid Oid");
- }
- fread(&null_ct, sizeof(int32), 1, fp);
- if (null_ct > 0) {
- for (i = 0; i < null_ct; i++) {
- fread(&null_id, sizeof(int32), 1, fp);
- nulls[null_id] = 'n';
- }
- }
-
- string = (char *) palloc(len);
- fread(string, len, 1, fp);
-
- ptr = string;
-
- for (i = 0; i < attr_count; i++) {
- if (byval[i] && nulls[i] != 'n') {
-
- switch(attr[i]->attlen) {
- case sizeof(char):
- values[i] = (Datum) *(unsigned char *) ptr;
- ptr += sizeof(char);
- break;
- case sizeof(short):
- ptr = (char *) SHORTALIGN(ptr);
- values[i] = (Datum) *(unsigned short *) ptr;
- ptr += sizeof(short);
- break;
- case sizeof(int32):
- ptr = (char *) INTALIGN(ptr);
- values[i] = (Datum) *(uint32 *) ptr;
- ptr += sizeof(int32);
- break;
- default:
- elog(WARN, "COPY BINARY: impossible size!");
- break;
- }
- }else if (nulls[i] != 'n') {
- switch (attr[i]->attlen) {
- case -1:
- if (attr[i]->attalign == 'd')
- ptr = (char *)DOUBLEALIGN(ptr);
- else
- ptr = (char *)INTALIGN(ptr);
- values[i] = (Datum) ptr;
- ptr += * (uint32 *) ptr;
- break;
- case sizeof(char):
- values[i] = (Datum)ptr;
- ptr += attr[i]->attlen;
- break;
- case sizeof(short):
- ptr = (char*)SHORTALIGN(ptr);
- values[i] = (Datum)ptr;
- ptr += attr[i]->attlen;
- break;
- case sizeof(int32):
- ptr = (char*)INTALIGN(ptr);
- values[i] = (Datum)ptr;
- ptr += attr[i]->attlen;
- break;
- default:
- if (attr[i]->attalign == 'd')
- ptr = (char *)DOUBLEALIGN(ptr);
- else
- ptr = (char *)LONGALIGN(ptr);
- values[i] = (Datum) ptr;
- ptr += attr[i]->attlen;
- }
- }
- }
- }
- }
- if (done) continue;
+ }
+ else
+ { /* binary */
+ fread(&len, sizeof(int32), 1, fp);
+ if (feof(fp))
+ {
+ done = 1;
+ }
+ else
+ {
+ if (oids)
+ {
+ fread(&loaded_oid, sizeof(int32), 1, fp);
+ if (loaded_oid < BootstrapObjectIdData)
+ elog(WARN, "COPY BINARY: Invalid Oid");
+ }
+ fread(&null_ct, sizeof(int32), 1, fp);
+ if (null_ct > 0)
+ {
+ for (i = 0; i < null_ct; i++)
+ {
+ fread(&null_id, sizeof(int32), 1, fp);
+ nulls[null_id] = 'n';
+ }
+ }
- /*
- * Does it have any sence ? - vadim 12/14/96
- *
- tupDesc = CreateTupleDesc(attr_count, attr);
- */
- tuple = heap_formtuple(tupDesc, values, nulls);
- if (oids)
- tuple->t_oid = loaded_oid;
-
- skip_tuple = false;
- /* BEFORE ROW INSERT Triggers */
- if ( rel->trigdesc &&
- rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0 )
- {
- HeapTuple newtuple;
-
- newtuple = ExecBRInsertTriggers (rel, tuple);
-
- if ( newtuple == NULL ) /* "do nothing" */
- skip_tuple = true;
- else if ( newtuple != tuple ) /* modified by Trigger(s) */
- {
- pfree (tuple);
- tuple = newtuple;
- }
- }
-
- if ( !skip_tuple )
- {
- /* ----------------
- * Check the constraints of a tuple
- * ----------------
- */
-
- if ( rel->rd_att->constr )
- {
- HeapTuple newtuple;
-
- newtuple = ExecConstraints ("CopyFrom", rel, tuple);
-
- if ( newtuple != tuple )
- {
- pfree (tuple);
- tuple = newtuple;
- }
- }
-
- heap_insert(rel, tuple);
-
- if (has_index)
- {
- for (i = 0; i < n_indices; i++)
- {
- if (indexPred[i] != NULL)
- {
+ string = (char *) palloc(len);
+ fread(string, len, 1, fp);
+
+ ptr = string;
+
+ for (i = 0; i < attr_count; i++)
+ {
+ if (byval[i] && nulls[i] != 'n')
+ {
+
+ switch (attr[i]->attlen)
+ {
+ case sizeof(char):
+ values[i] = (Datum) * (unsigned char *) ptr;
+ ptr += sizeof(char);
+ break;
+ case sizeof(short):
+ ptr = (char *) SHORTALIGN(ptr);
+ values[i] = (Datum) * (unsigned short *) ptr;
+ ptr += sizeof(short);
+ break;
+ case sizeof(int32):
+ ptr = (char *) INTALIGN(ptr);
+ values[i] = (Datum) * (uint32 *) ptr;
+ ptr += sizeof(int32);
+ break;
+ default:
+ elog(WARN, "COPY BINARY: impossible size!");
+ break;
+ }
+ }
+ else if (nulls[i] != 'n')
+ {
+ switch (attr[i]->attlen)
+ {
+ case -1:
+ if (attr[i]->attalign == 'd')
+ ptr = (char *) DOUBLEALIGN(ptr);
+ else
+ ptr = (char *) INTALIGN(ptr);
+ values[i] = (Datum) ptr;
+ ptr += *(uint32 *) ptr;
+ break;
+ case sizeof(char):
+ values[i] = (Datum) ptr;
+ ptr += attr[i]->attlen;
+ break;
+ case sizeof(short):
+ ptr = (char *) SHORTALIGN(ptr);
+ values[i] = (Datum) ptr;
+ ptr += attr[i]->attlen;
+ break;
+ case sizeof(int32):
+ ptr = (char *) INTALIGN(ptr);
+ values[i] = (Datum) ptr;
+ ptr += attr[i]->attlen;
+ break;
+ default:
+ if (attr[i]->attalign == 'd')
+ ptr = (char *) DOUBLEALIGN(ptr);
+ else
+ ptr = (char *) LONGALIGN(ptr);
+ values[i] = (Datum) ptr;
+ ptr += attr[i]->attlen;
+ }
+ }
+ }
+ }
+ }
+ if (done)
+ continue;
+
+ /*
+ * Does it have any sence ? - vadim 12/14/96
+ *
+ * tupDesc = CreateTupleDesc(attr_count, attr);
+ */
+ tuple = heap_formtuple(tupDesc, values, nulls);
+ if (oids)
+ tuple->t_oid = loaded_oid;
+
+ skip_tuple = false;
+ /* BEFORE ROW INSERT Triggers */
+ if (rel->trigdesc &&
+ rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)
+ {
+ HeapTuple newtuple;
+
+ newtuple = ExecBRInsertTriggers(rel, tuple);
+
+ if (newtuple == NULL) /* "do nothing" */
+ skip_tuple = true;
+ else if (newtuple != tuple) /* modified by Trigger(s) */
+ {
+ pfree(tuple);
+ tuple = newtuple;
+ }
+ }
+
+ if (!skip_tuple)
+ {
+ /* ----------------
+ * Check the constraints of a tuple
+ * ----------------
+ */
+
+ if (rel->rd_att->constr)
+ {
+ HeapTuple newtuple;
+
+ newtuple = ExecConstraints("CopyFrom", rel, tuple);
+
+ if (newtuple != tuple)
+ {
+ pfree(tuple);
+ tuple = newtuple;
+ }
+ }
+
+ heap_insert(rel, tuple);
+
+ if (has_index)
+ {
+ for (i = 0; i < n_indices; i++)
+ {
+ if (indexPred[i] != NULL)
+ {
#ifndef OMIT_PARTIAL_INDEX
- /*
- * if tuple doesn't satisfy predicate,
- * don't update index
- */
- slot->val = tuple;
- /*SetSlotContents(slot, tuple); */
- if (ExecQual((List*)indexPred[i], econtext) == false)
- continue;
-#endif /* OMIT_PARTIAL_INDEX */
- }
- FormIndexDatum(indexNatts[i],
- (AttrNumber *)&(pgIndexP[i]->indkey[0]),
- tuple,
- tupDesc,
- InvalidBuffer,
- idatum,
- index_nulls,
- finfoP[i]);
- indexRes = index_insert(index_rels[i], idatum, index_nulls,
- &(tuple->t_ctid), rel);
- if (indexRes) pfree(indexRes);
- }
- }
- /* AFTER ROW INSERT Triggers */
- if ( rel->trigdesc &&
- rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0 )
- ExecARInsertTriggers (rel, tuple);
- }
-
- if (binary) pfree(string);
-
- for (i = 0; i < attr_count; i++) {
- if (!byval[i] && nulls[i] != 'n') {
- if (!binary) pfree((void*)values[i]);
- }else if (nulls[i] == 'n') {
- nulls[i] = ' ';
- }
- }
-
- pfree(tuple);
- tuples_read++;
-
- if (!reading_to_eof && ntuples == tuples_read) done = true;
- }
- pfree(values);
- if (!binary) pfree(in_functions);
- pfree(nulls);
- pfree(byval);
- heap_close(rel);
+
+ /*
+ * if tuple doesn't satisfy predicate, don't
+ * update index
+ */
+ slot->val = tuple;
+ /* SetSlotContents(slot, tuple); */
+ if (ExecQual((List *) indexPred[i], econtext) == false)
+ continue;
+#endif /* OMIT_PARTIAL_INDEX */
+ }
+ FormIndexDatum(indexNatts[i],
+ (AttrNumber *) & (pgIndexP[i]->indkey[0]),
+ tuple,
+ tupDesc,
+ InvalidBuffer,
+ idatum,
+ index_nulls,
+ finfoP[i]);
+ indexRes = index_insert(index_rels[i], idatum, index_nulls,
+ &(tuple->t_ctid), rel);
+ if (indexRes)
+ pfree(indexRes);
+ }
+ }
+ /* AFTER ROW INSERT Triggers */
+ if (rel->trigdesc &&
+ rel->trigdesc->n_after_row[TRIGGER_EVENT_INSERT] > 0)
+ ExecARInsertTriggers(rel, tuple);
+ }
+
+ if (binary)
+ pfree(string);
+
+ for (i = 0; i < attr_count; i++)
+ {
+ if (!byval[i] && nulls[i] != 'n')
+ {
+ if (!binary)
+ pfree((void *) values[i]);
+ }
+ else if (nulls[i] == 'n')
+ {
+ nulls[i] = ' ';
+ }
+ }
+
+ pfree(tuple);
+ tuples_read++;
+
+ if (!reading_to_eof && ntuples == tuples_read)
+ done = true;
+ }
+ pfree(values);
+ if (!binary)
+ pfree(in_functions);
+ pfree(nulls);
+ pfree(byval);
+ heap_close(rel);
}
-static Oid
+static Oid
GetOutputFunction(Oid type)
{
- HeapTuple typeTuple;
-
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type),
- 0,0,0);
-
- if (HeapTupleIsValid(typeTuple))
- return((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typoutput);
-
- elog(WARN, "GetOutputFunction: Cache lookup of type %d failed", type);
- return(InvalidOid);
+ HeapTuple typeTuple;
+
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+
+ if (HeapTupleIsValid(typeTuple))
+ return ((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typoutput);
+
+ elog(WARN, "GetOutputFunction: Cache lookup of type %d failed", type);
+ return (InvalidOid);
}
-static Oid
+static Oid
GetTypeElement(Oid type)
{
- HeapTuple typeTuple;
-
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type),
- 0,0,0);
-
-
- if (HeapTupleIsValid(typeTuple))
- return((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typelem);
-
- elog(WARN, "GetOutputFunction: Cache lookup of type %d failed", type);
- return(InvalidOid);
+ HeapTuple typeTuple;
+
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+
+
+ if (HeapTupleIsValid(typeTuple))
+ return ((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typelem);
+
+ elog(WARN, "GetOutputFunction: Cache lookup of type %d failed", type);
+ return (InvalidOid);
}
-static Oid
+static Oid
GetInputFunction(Oid type)
{
- HeapTuple typeTuple;
-
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type),
- 0,0,0);
-
- if (HeapTupleIsValid(typeTuple))
- return((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typinput);
-
- elog(WARN, "GetInputFunction: Cache lookup of type %d failed", type);
- return(InvalidOid);
+ HeapTuple typeTuple;
+
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+
+ if (HeapTupleIsValid(typeTuple))
+ return ((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typinput);
+
+ elog(WARN, "GetInputFunction: Cache lookup of type %d failed", type);
+ return (InvalidOid);
}
-static Oid
+static Oid
IsTypeByVal(Oid type)
{
- HeapTuple typeTuple;
-
- typeTuple = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(type),
- 0,0,0);
-
- if (HeapTupleIsValid(typeTuple))
- return((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typbyval);
-
- elog(WARN, "GetInputFunction: Cache lookup of type %d failed", type);
-
- return(InvalidOid);
+ HeapTuple typeTuple;
+
+ typeTuple = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(type),
+ 0, 0, 0);
+
+ if (HeapTupleIsValid(typeTuple))
+ return ((int) ((TypeTupleForm) GETSTRUCT(typeTuple))->typbyval);
+
+ elog(WARN, "GetInputFunction: Cache lookup of type %d failed", type);
+
+ return (InvalidOid);
}
-/*
+/*
* Given the OID of a relation, return an array of index relation descriptors
* and the number of index relations. These relation descriptors are open
* using heap_open().
@@ -779,71 +900,77 @@ IsTypeByVal(Oid type)
* Space for the array itself is palloc'ed.
*/
-typedef struct rel_list {
- Oid index_rel_oid;
- struct rel_list *next;
-} RelationList;
+typedef struct rel_list
+{
+ Oid index_rel_oid;
+ struct rel_list *next;
+} RelationList;
static void
GetIndexRelations(Oid main_relation_oid,
- int *n_indices,
- Relation **index_rels)
+ int *n_indices,
+ Relation ** index_rels)
{
- RelationList *head, *scan;
- Relation pg_index_rel;
- HeapScanDesc scandesc;
- Oid index_relation_oid;
- HeapTuple tuple;
- TupleDesc tupDesc;
- int i;
- bool isnull;
-
- pg_index_rel = heap_openr(IndexRelationName);
- scandesc = heap_beginscan(pg_index_rel, 0, NULL, 0, NULL);
- tupDesc = RelationGetTupleDescriptor(pg_index_rel);
-
- *n_indices = 0;
-
- head = (RelationList *) palloc(sizeof(RelationList));
- scan = head;
- head->next = NULL;
-
- for (tuple = heap_getnext(scandesc, 0, NULL);
- tuple != NULL;
- tuple = heap_getnext(scandesc, 0, NULL)) {
-
- index_relation_oid =
- (Oid) DatumGetInt32(heap_getattr(tuple, InvalidBuffer, 2,
- tupDesc, &isnull));
- if (index_relation_oid == main_relation_oid) {
- scan->index_rel_oid =
- (Oid) DatumGetInt32(heap_getattr(tuple, InvalidBuffer,
- Anum_pg_index_indexrelid,
- tupDesc, &isnull));
- (*n_indices)++;
- scan->next = (RelationList *) palloc(sizeof(RelationList));
- scan = scan->next;
- }
- }
-
- heap_endscan(scandesc);
- heap_close(pg_index_rel);
-
- /* We cannot trust to relhasindex of the main_relation now, so... */
- if ( *n_indices == 0 )
- return;
-
- *index_rels = (Relation *) palloc(*n_indices * sizeof(Relation));
-
- for (i = 0, scan = head; i < *n_indices; i++, scan = scan->next) {
- (*index_rels)[i] = index_open(scan->index_rel_oid);
- }
-
- for (i = 0, scan = head; i < *n_indices + 1; i++) {
- scan = head->next;
- pfree(head);
- head = scan;
- }
+ RelationList *head,
+ *scan;
+ Relation pg_index_rel;
+ HeapScanDesc scandesc;
+ Oid index_relation_oid;
+ HeapTuple tuple;
+ TupleDesc tupDesc;
+ int i;
+ bool isnull;
+
+ pg_index_rel = heap_openr(IndexRelationName);
+ scandesc = heap_beginscan(pg_index_rel, 0, NULL, 0, NULL);
+ tupDesc = RelationGetTupleDescriptor(pg_index_rel);
+
+ *n_indices = 0;
+
+ head = (RelationList *) palloc(sizeof(RelationList));
+ scan = head;
+ head->next = NULL;
+
+ for (tuple = heap_getnext(scandesc, 0, NULL);
+ tuple != NULL;
+ tuple = heap_getnext(scandesc, 0, NULL))
+ {
+
+ index_relation_oid =
+ (Oid) DatumGetInt32(heap_getattr(tuple, InvalidBuffer, 2,
+ tupDesc, &isnull));
+ if (index_relation_oid == main_relation_oid)
+ {
+ scan->index_rel_oid =
+ (Oid) DatumGetInt32(heap_getattr(tuple, InvalidBuffer,
+ Anum_pg_index_indexrelid,
+ tupDesc, &isnull));
+ (*n_indices)++;
+ scan->next = (RelationList *) palloc(sizeof(RelationList));
+ scan = scan->next;
+ }
+ }
+
+ heap_endscan(scandesc);
+ heap_close(pg_index_rel);
+
+ /* We cannot trust to relhasindex of the main_relation now, so... */
+ if (*n_indices == 0)
+ return;
+
+ *index_rels = (Relation *) palloc(*n_indices * sizeof(Relation));
+
+ for (i = 0, scan = head; i < *n_indices; i++, scan = scan->next)
+ {
+ (*index_rels)[i] = index_open(scan->index_rel_oid);
+ }
+
+ for (i = 0, scan = head; i < *n_indices + 1; i++)
+ {
+ scan = head->next;
+ pfree(head);
+ head = scan;
+ }
}
#define EXT_ATTLEN 5*8192
@@ -851,20 +978,22 @@ GetIndexRelations(Oid main_relation_oid,
/*
returns 1 is c is in s
*/
-static bool
-inString(char c, char* s)
+static bool
+inString(char c, char *s)
{
- int i;
-
- if (s) {
- i = 0;
- while (s[i] != '\0') {
- if (s[i] == c)
- return 1;
- i++;
- }
- }
- return 0;
+ int i;
+
+ if (s)
+ {
+ i = 0;
+ while (s[i] != '\0')
+ {
+ if (s[i] == c)
+ return 1;
+ i++;
+ }
+ }
+ return 0;
}
#ifdef COPY_PATCH
@@ -873,19 +1002,21 @@ inString(char c, char* s)
*/
void
-CopyReadNewline(FILE *fp, int *newline)
+CopyReadNewline(FILE * fp, int *newline)
{
- if (!*newline) {
+ if (!*newline)
+ {
#ifdef COPY_DEBUG
- elog(NOTICE, "CopyReadNewline: line %d - extra fields ignored",
- lineno);
+ elog(NOTICE, "CopyReadNewline: line %d - extra fields ignored",
+ lineno);
#else
- elog(NOTICE, "CopyReadNewline: line - extra fields ignored");
+ elog(NOTICE, "CopyReadNewline: line - extra fields ignored");
#endif
- while (!feof(fp) && (getc(fp) != '\n'));
- }
- *newline = 0;
+ while (!feof(fp) && (getc(fp) != '\n'));
+ }
+ *newline = 0;
}
+
#endif
/*
@@ -895,148 +1026,167 @@ CopyReadNewline(FILE *fp, int *newline)
* can be used as standard input.
*/
-static char *
+static char *
#ifdef COPY_PATCH
-CopyReadAttribute(FILE *fp, bool *isnull, char *delim, int *newline)
+CopyReadAttribute(FILE * fp, bool * isnull, char *delim, int *newline)
#else
-CopyReadAttribute(FILE *fp, bool *isnull, char *delim)
+CopyReadAttribute(FILE * fp, bool * isnull, char *delim)
#endif
{
- static char attribute[EXT_ATTLEN];
- char c;
- int done = 0;
- int i = 0;
-
+ static char attribute[EXT_ATTLEN];
+ char c;
+ int done = 0;
+ int i = 0;
+
#ifdef COPY_PATCH
- /* if last delimiter was a newline return a NULL attribute */
- if (*newline) {
- *isnull = (bool) true;
- return(NULL);
- }
+ /* if last delimiter was a newline return a NULL attribute */
+ if (*newline)
+ {
+ *isnull = (bool) true;
+ return (NULL);
+ }
#endif
- *isnull = (bool) false; /* set default */
- if (feof(fp))
- return(NULL);
-
- while (!done) {
- c = getc(fp);
-
- if (feof(fp))
- return(NULL);
- else if (c == '\\') {
- c = getc(fp);
- if (feof(fp))
- return(NULL);
- switch (c) {
- case '0':
- case '1':
- case '2':
- case '3':
- case '4':
- case '5':
- case '6':
- case '7': {
- int val;
- val = VALUE(c);
- c = getc(fp);
- if (ISOCTAL(c)) {
- val = (val<<3) + VALUE(c);
- c = getc(fp);
- if (ISOCTAL(c)) {
- val = (val<<3) + VALUE(c);
- } else {
- if (feof(fp))
- return(NULL);
- ungetc(c, fp);
- }
- } else {
- if (feof(fp))
- return(NULL);
- ungetc(c, fp);
- }
- c = val & 0377;
- }
- break;
- case 'b':
- c = '\b';
- break;
- case 'f':
- c = '\f';
- break;
- case 'n':
- c = '\n';
- break;
- case 'r':
- c = '\r';
- break;
- case 't':
- c = '\t';
- break;
- case 'v':
- c = '\v';
- break;
- case 'N':
- attribute[0] = '\0'; /* just to be safe */
- *isnull = (bool) true;
- break;
- case '.':
- c = getc(fp);
- if (c != '\n')
- elog(WARN, "CopyReadAttribute - end of record marker corrupted");
- return(NULL);
- break;
- }
- }else if (inString(c,delim) || c == '\n') {
+ *isnull = (bool) false; /* set default */
+ if (feof(fp))
+ return (NULL);
+
+ while (!done)
+ {
+ c = getc(fp);
+
+ if (feof(fp))
+ return (NULL);
+ else if (c == '\\')
+ {
+ c = getc(fp);
+ if (feof(fp))
+ return (NULL);
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ {
+ int val;
+
+ val = VALUE(c);
+ c = getc(fp);
+ if (ISOCTAL(c))
+ {
+ val = (val << 3) + VALUE(c);
+ c = getc(fp);
+ if (ISOCTAL(c))
+ {
+ val = (val << 3) + VALUE(c);
+ }
+ else
+ {
+ if (feof(fp))
+ return (NULL);
+ ungetc(c, fp);
+ }
+ }
+ else
+ {
+ if (feof(fp))
+ return (NULL);
+ ungetc(c, fp);
+ }
+ c = val & 0377;
+ }
+ break;
+ case 'b':
+ c = '\b';
+ break;
+ case 'f':
+ c = '\f';
+ break;
+ case 'n':
+ c = '\n';
+ break;
+ case 'r':
+ c = '\r';
+ break;
+ case 't':
+ c = '\t';
+ break;
+ case 'v':
+ c = '\v';
+ break;
+ case 'N':
+ attribute[0] = '\0'; /* just to be safe */
+ *isnull = (bool) true;
+ break;
+ case '.':
+ c = getc(fp);
+ if (c != '\n')
+ elog(WARN, "CopyReadAttribute - end of record marker corrupted");
+ return (NULL);
+ break;
+ }
+ }
+ else if (inString(c, delim) || c == '\n')
+ {
#ifdef COPY_PATCH
- if (c == '\n') {
- *newline = 1;
- }
+ if (c == '\n')
+ {
+ *newline = 1;
+ }
#endif
- done = 1;
- }
- if (!done) attribute[i++] = c;
- if (i == EXT_ATTLEN - 1)
- elog(WARN, "CopyReadAttribute - attribute length too long");
- }
- attribute[i] = '\0';
- return(&attribute[0]);
+ done = 1;
+ }
+ if (!done)
+ attribute[i++] = c;
+ if (i == EXT_ATTLEN - 1)
+ elog(WARN, "CopyReadAttribute - attribute length too long");
+ }
+ attribute[i] = '\0';
+ return (&attribute[0]);
}
static void
-CopyAttributeOut(FILE *fp, char *string, char *delim)
+CopyAttributeOut(FILE * fp, char *string, char *delim)
{
- char c;
- int is_array = false;
- int len = strlen(string);
-
- /* XXX - This is a kludge, we should check the data type */
- if (len && (string[0] == '{') && (string[len-1] == '}'))
- is_array = true;
-
- for ( ; (c = *string) != '\0'; string++) {
- if (c == delim[0] || c == '\n' ||
- (c == '\\' && !is_array))
- fputc('\\', fp);
- else
- if (c == '\\' && is_array)
- if (*(string+1) == '\\') {
- /* translate \\ to \\\\ */
- fputc('\\', fp);
- fputc('\\', fp);
- fputc('\\', fp);
- string++;
- } else if (*(string+1) == '"') {
- /* translate \" to \\\" */
- fputc('\\', fp);
- fputc('\\', fp);
- }
- fputc(*string, fp);
- }
+ char c;
+ int is_array = false;
+ int len = strlen(string);
+
+ /* XXX - This is a kludge, we should check the data type */
+ if (len && (string[0] == '{') && (string[len - 1] == '}'))
+ is_array = true;
+
+ for (; (c = *string) != '\0'; string++)
+ {
+ if (c == delim[0] || c == '\n' ||
+ (c == '\\' && !is_array))
+ fputc('\\', fp);
+ else if (c == '\\' && is_array)
+ if (*(string + 1) == '\\')
+ {
+ /* translate \\ to \\\\ */
+ fputc('\\', fp);
+ fputc('\\', fp);
+ fputc('\\', fp);
+ string++;
+ }
+ else if (*(string + 1) == '"')
+ {
+ /* translate \" to \\\" */
+ fputc('\\', fp);
+ fputc('\\', fp);
+ }
+ fputc(*string, fp);
+ }
}
/*
- * Returns the number of tuples in a relation. Unfortunately, currently
+ * Returns the number of tuples in a relation. Unfortunately, currently
* must do a scan of the entire relation to determine this.
*
* relation is expected to be an open relation descriptor.
@@ -1044,17 +1194,17 @@ CopyAttributeOut(FILE *fp, char *string, char *delim)
static int
CountTuples(Relation relation)
{
- HeapScanDesc scandesc;
- HeapTuple tuple;
-
- int i;
-
- scandesc = heap_beginscan(relation, 0, NULL, 0, NULL);
-
- for (tuple = heap_getnext(scandesc, 0, NULL), i = 0;
- tuple != NULL;
- tuple = heap_getnext(scandesc, 0, NULL), i++)
- ;
- heap_endscan(scandesc);
- return(i);
+ HeapScanDesc scandesc;
+ HeapTuple tuple;
+
+ int i;
+
+ scandesc = heap_beginscan(relation, 0, NULL, 0, NULL);
+
+ for (tuple = heap_getnext(scandesc, 0, NULL), i = 0;
+ tuple != NULL;
+ tuple = heap_getnext(scandesc, 0, NULL), i++)
+ ;
+ heap_endscan(scandesc);
+ return (i);
}
diff --git a/src/backend/commands/creatinh.c b/src/backend/commands/creatinh.c
index 248aaa3e768..92641ca70d6 100644
--- a/src/backend/commands/creatinh.c
+++ b/src/backend/commands/creatinh.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* creatinh.c--
- * POSTGRES create/destroy relation with inheritance utility code.
+ * POSTGRES create/destroy relation with inheritance utility code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.14 1997/08/22 03:03:56 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/creatinh.c,v 1.15 1997/09/07 04:40:42 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -29,623 +29,661 @@
#include <catalog/pg_ipl.h>
/* ----------------
- * local stuff
+ * local stuff
* ----------------
*/
-static int checkAttrExists(char *attributeName,
- char *attributeType, List *schema);
-static List *MergeAttributes(List *schema, List *supers, List **supconstr);
-static void StoreCatalogInheritance(Oid relationId, List *supers);
+static int
+checkAttrExists(char *attributeName,
+ char *attributeType, List * schema);
+static List *MergeAttributes(List * schema, List * supers, List ** supconstr);
+static void StoreCatalogInheritance(Oid relationId, List * supers);
/* ----------------------------------------------------------------
- * DefineRelation --
- * Creates a new relation.
+ * DefineRelation --
+ * Creates a new relation.
* ----------------------------------------------------------------
*/
void
-DefineRelation(CreateStmt *stmt)
+DefineRelation(CreateStmt * stmt)
{
- char *relname = palloc(NAMEDATALEN);
- List *schema = stmt->tableElts;
- int numberOfAttributes;
- Oid relationId;
- char archChar;
- List *inheritList = NULL;
- char *archiveName = NULL;
- TupleDesc descriptor;
- List *constraints;
- int heaploc, archloc;
-
- char* typename = NULL; /* the typename of this relation. not useod for now */
-
- if ( strlen(stmt->relname) >= NAMEDATALEN)
- elog(WARN, "the relation name %s is >= %d characters long", stmt->relname,
- NAMEDATALEN);
- strNcpy(relname,stmt->relname,NAMEDATALEN-1); /* make full length for copy */
-
- /* ----------------
- * Handle parameters
- * XXX parameter handling missing below.
- * ----------------
- */
- inheritList = stmt->inhRelnames;
-
- /* ----------------
- * determine archive mode
- * XXX use symbolic constants...
- * ----------------
- */
- archChar = 'n';
-
- switch (stmt->archiveType) {
- case ARCH_NONE:
+ char *relname = palloc(NAMEDATALEN);
+ List *schema = stmt->tableElts;
+ int numberOfAttributes;
+ Oid relationId;
+ char archChar;
+ List *inheritList = NULL;
+ char *archiveName = NULL;
+ TupleDesc descriptor;
+ List *constraints;
+ int heaploc,
+ archloc;
+
+ char *typename = NULL; /* the typename of this relation.
+ * not useod for now */
+
+ if (strlen(stmt->relname) >= NAMEDATALEN)
+ elog(WARN, "the relation name %s is >= %d characters long", stmt->relname,
+ NAMEDATALEN);
+ strNcpy(relname, stmt->relname, NAMEDATALEN - 1); /* make full length for
+ * copy */
+
+ /* ----------------
+ * Handle parameters
+ * XXX parameter handling missing below.
+ * ----------------
+ */
+ inheritList = stmt->inhRelnames;
+
+ /* ----------------
+ * determine archive mode
+ * XXX use symbolic constants...
+ * ----------------
+ */
archChar = 'n';
- break;
- case ARCH_LIGHT:
- archChar = 'l';
- break;
- case ARCH_HEAVY:
- archChar = 'h';
- break;
- default:
- elog(WARN, "Botched archive mode %d, ignoring",
- stmt->archiveType);
- break;
- }
-
- if (stmt->location == -1)
- heaploc = 0;
- else
- heaploc = stmt->location;
-
- /*
- * For now, any user-defined relation defaults to the magnetic
- * disk storgage manager. --mao 2 july 91
- */
- if (stmt->archiveLoc == -1) {
- archloc = 0;
- } else {
- if (archChar == 'n') {
- elog(WARN, "Set archive location, but not mode, for %s",
- relname);
+
+ switch (stmt->archiveType)
+ {
+ case ARCH_NONE:
+ archChar = 'n';
+ break;
+ case ARCH_LIGHT:
+ archChar = 'l';
+ break;
+ case ARCH_HEAVY:
+ archChar = 'h';
+ break;
+ default:
+ elog(WARN, "Botched archive mode %d, ignoring",
+ stmt->archiveType);
+ break;
+ }
+
+ if (stmt->location == -1)
+ heaploc = 0;
+ else
+ heaploc = stmt->location;
+
+ /*
+ * For now, any user-defined relation defaults to the magnetic disk
+ * storgage manager. --mao 2 july 91
+ */
+ if (stmt->archiveLoc == -1)
+ {
+ archloc = 0;
+ }
+ else
+ {
+ if (archChar == 'n')
+ {
+ elog(WARN, "Set archive location, but not mode, for %s",
+ relname);
+ }
+ archloc = stmt->archiveLoc;
+ }
+
+ /* ----------------
+ * generate relation schema, including inherited attributes.
+ * ----------------
+ */
+ schema = MergeAttributes(schema, inheritList, &constraints);
+ constraints = nconc(constraints, stmt->constraints);
+
+ numberOfAttributes = length(schema);
+ if (numberOfAttributes <= 0)
+ {
+ elog(WARN, "DefineRelation: %s",
+ "please inherit from a relation or define an attribute");
}
- archloc = stmt->archiveLoc;
- }
-
- /* ----------------
- * generate relation schema, including inherited attributes.
- * ----------------
- */
- schema = MergeAttributes(schema, inheritList, &constraints);
- constraints = nconc (constraints, stmt->constraints);
-
- numberOfAttributes = length(schema);
- if (numberOfAttributes <= 0) {
- elog(WARN, "DefineRelation: %s",
- "please inherit from a relation or define an attribute");
- }
-
- /* ----------------
- * create a relation descriptor from the relation schema
- * and create the relation.
- * ----------------
- */
- descriptor = BuildDescForRelation(schema, relname);
-
- if ( constraints != NIL )
- {
- List *entry;
- int nconstr = length (constraints);
- ConstrCheck *check = (ConstrCheck *) palloc (nconstr * sizeof (ConstrCheck));
- int ncheck = 0;
- int i;
-
- foreach (entry, constraints)
- {
- ConstraintDef *cdef = (ConstraintDef *) lfirst (entry);
-
- if ( cdef->type == CONSTR_CHECK )
- {
- if ( cdef->name != NULL )
- {
- for (i = 0; i < ncheck; i++)
- {
- if ( strcmp (check[i].ccname, cdef->name) == 0 )
- elog (WARN, "DefineRelation: name (%s) of CHECK constraint duplicated", cdef->name);
- }
- check[ncheck].ccname = cdef->name;
- }
- else
- {
- check[ncheck].ccname = (char*) palloc (NAMEDATALEN);
- sprintf (check[ncheck].ccname, "$%d", ncheck + 1);
- }
- check[ncheck].ccbin = NULL;
- check[ncheck].ccsrc = (char*) cdef->def;
- ncheck++;
- }
- }
- if ( ncheck > 0 )
- {
- if ( ncheck < nconstr )
- check = (ConstrCheck *) repalloc (check, ncheck * sizeof (ConstrCheck));
- if ( descriptor->constr == NULL )
- {
- descriptor->constr = (TupleConstr *) palloc(sizeof(TupleConstr));
- descriptor->constr->num_defval = 0;
- descriptor->constr->has_not_null = false;
- }
- descriptor->constr->num_check = ncheck;
- descriptor->constr->check = check;
- }
- }
-
- relationId = heap_create(relname,
- typename,
- archChar,
- heaploc,
- descriptor);
-
- StoreCatalogInheritance(relationId, inheritList);
-
- /*
- * create an archive relation if necessary
- */
- if (archChar != 'n')
- {
- TupleDesc tupdesc;
+
+ /* ----------------
+ * create a relation descriptor from the relation schema
+ * and create the relation.
+ * ----------------
+ */
+ descriptor = BuildDescForRelation(schema, relname);
+
+ if (constraints != NIL)
+ {
+ List *entry;
+ int nconstr = length(constraints);
+ ConstrCheck *check = (ConstrCheck *) palloc(nconstr * sizeof(ConstrCheck));
+ int ncheck = 0;
+ int i;
+
+ foreach(entry, constraints)
+ {
+ ConstraintDef *cdef = (ConstraintDef *) lfirst(entry);
+
+ if (cdef->type == CONSTR_CHECK)
+ {
+ if (cdef->name != NULL)
+ {
+ for (i = 0; i < ncheck; i++)
+ {
+ if (strcmp(check[i].ccname, cdef->name) == 0)
+ elog(WARN, "DefineRelation: name (%s) of CHECK constraint duplicated", cdef->name);
+ }
+ check[ncheck].ccname = cdef->name;
+ }
+ else
+ {
+ check[ncheck].ccname = (char *) palloc(NAMEDATALEN);
+ sprintf(check[ncheck].ccname, "$%d", ncheck + 1);
+ }
+ check[ncheck].ccbin = NULL;
+ check[ncheck].ccsrc = (char *) cdef->def;
+ ncheck++;
+ }
+ }
+ if (ncheck > 0)
+ {
+ if (ncheck < nconstr)
+ check = (ConstrCheck *) repalloc(check, ncheck * sizeof(ConstrCheck));
+ if (descriptor->constr == NULL)
+ {
+ descriptor->constr = (TupleConstr *) palloc(sizeof(TupleConstr));
+ descriptor->constr->num_defval = 0;
+ descriptor->constr->has_not_null = false;
+ }
+ descriptor->constr->num_check = ncheck;
+ descriptor->constr->check = check;
+ }
+ }
+
+ relationId = heap_create(relname,
+ typename,
+ archChar,
+ heaploc,
+ descriptor);
+
+ StoreCatalogInheritance(relationId, inheritList);
+
/*
- * Need to create an archive relation for this heap relation.
- * We cobble up the command by hand, and increment the command
- * counter ourselves.
+ * create an archive relation if necessary
*/
-
- CommandCounterIncrement();
- archiveName = MakeArchiveName(relationId);
-
- tupdesc = CreateTupleDescCopy (descriptor); /* get rid of constraints */
- (void) heap_create(archiveName,
- typename,
- 'n', /* archive isn't archived */
- archloc,
- tupdesc);
-
- FreeTupleDesc (tupdesc);
- FreeTupleDesc (descriptor);
- pfree(archiveName);
- }
+ if (archChar != 'n')
+ {
+ TupleDesc tupdesc;
+
+ /*
+ * Need to create an archive relation for this heap relation. We
+ * cobble up the command by hand, and increment the command
+ * counter ourselves.
+ */
+
+ CommandCounterIncrement();
+ archiveName = MakeArchiveName(relationId);
+
+ tupdesc = CreateTupleDescCopy(descriptor); /* get rid of
+ * constraints */
+ (void) heap_create(archiveName,
+ typename,
+ 'n', /* archive isn't archived */
+ archloc,
+ tupdesc);
+
+ FreeTupleDesc(tupdesc);
+ FreeTupleDesc(descriptor);
+ pfree(archiveName);
+ }
}
/*
* RemoveRelation --
- * Deletes a new relation.
+ * Deletes a new relation.
*
* Exceptions:
- * BadArg if name is invalid.
+ * BadArg if name is invalid.
*
* Note:
- * If the relation has indices defined on it, then the index relations
+ * If the relation has indices defined on it, then the index relations
* themselves will be destroyed, too.
*/
void
RemoveRelation(char *name)
{
- AssertArg(name);
- heap_destroy(name);
+ AssertArg(name);
+ heap_destroy(name);
}
/*
* MergeAttributes --
- * Returns new schema given initial schema and supers.
+ * Returns new schema given initial schema and supers.
*
*
* 'schema' is the column/attribute definition for the table. (It's a list
- * of ColumnDef's.) It is destructively changed.
+ * of ColumnDef's.) It is destructively changed.
* 'inheritList' is the list of inherited relations (a list of Value(str)'s).
*
* Notes:
- * The order in which the attributes are inherited is very important.
- * Intuitively, the inherited attributes should come first. If a table
- * inherits from multiple parents, the order of those attributes are
- * according to the order of the parents specified in CREATE TABLE.
+ * The order in which the attributes are inherited is very important.
+ * Intuitively, the inherited attributes should come first. If a table
+ * inherits from multiple parents, the order of those attributes are
+ * according to the order of the parents specified in CREATE TABLE.
*
- * Here's an example:
+ * Here's an example:
*
- * create table person (name text, age int4, location point);
- * create table emp (salary int4, manager char16) inherits(person);
- * create table student (gpa float8) inherits (person);
- * create table stud_emp (percent int4) inherits (emp, student);
+ * create table person (name text, age int4, location point);
+ * create table emp (salary int4, manager char16) inherits(person);
+ * create table student (gpa float8) inherits (person);
+ * create table stud_emp (percent int4) inherits (emp, student);
*
- * the order of the attributes of stud_emp is as follow:
+ * the order of the attributes of stud_emp is as follow:
*
*
- * person {1:name, 2:age, 3:location}
- * / \
- * {6:gpa} student emp {4:salary, 5:manager}
- * \ /
- * stud_emp {7:percent}
+ * person {1:name, 2:age, 3:location}
+ * / \
+ * {6:gpa} student emp {4:salary, 5:manager}
+ * \ /
+ * stud_emp {7:percent}
*/
-static List *
-MergeAttributes(List *schema, List *supers, List **supconstr)
+static List *
+MergeAttributes(List * schema, List * supers, List ** supconstr)
{
- List *entry;
- List *inhSchema = NIL;
- List *constraints = NIL;
-
- /*
- * Validates that there are no duplications.
- * Validity checking of types occurs later.
- */
- foreach (entry, schema) {
- List *rest;
- ColumnDef *coldef = lfirst(entry);
-
- foreach (rest, lnext(entry)) {
- /*
- * check for duplicated relation names
- */
- ColumnDef *restdef = lfirst(rest);
-
- if (!strcmp(coldef->colname, restdef->colname)) {
- elog(WARN, "attribute \"%s\" duplicated",
- coldef->colname);
- }
- }
- }
- foreach (entry, supers) {
- List *rest;
-
- foreach (rest, lnext(entry)) {
- if (!strcmp(strVal(lfirst(entry)), strVal(lfirst(rest)))) {
- elog(WARN, "relation \"%s\" duplicated",
- strVal(lfirst(entry)));
- }
- }
- }
-
- /*
- * merge the inherited attributes into the schema
- */
- foreach (entry, supers) {
- char *name = strVal(lfirst(entry));
- Relation relation;
- List *partialResult = NIL;
- AttrNumber attrno;
- TupleDesc tupleDesc;
- TupleConstr *constr;
-
- relation = heap_openr(name);
- if (relation==NULL) {
- elog(WARN,
- "MergeAttr: Can't inherit from non-existent superclass '%s'",
- name);
- }
- if ( relation->rd_rel->relkind == 'S' )
+ List *entry;
+ List *inhSchema = NIL;
+ List *constraints = NIL;
+
+ /*
+ * Validates that there are no duplications. Validity checking of
+ * types occurs later.
+ */
+ foreach(entry, schema)
{
- elog(WARN, "MergeAttr: Can't inherit from sequence superclass '%s'",
- name);
- }
- tupleDesc = RelationGetTupleDescriptor(relation);
- constr = tupleDesc->constr;
-
- for (attrno = relation->rd_rel->relnatts - 1; attrno >= 0; attrno--) {
- AttributeTupleForm attribute = tupleDesc->attrs[attrno];
- char *attributeName;
- char *attributeType;
- HeapTuple tuple;
- ColumnDef *def;
- TypeName *typename;
-
- /*
- * form name, type and constraints
- */
- attributeName = (attribute->attname).data;
- tuple =
- SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(attribute->atttypid),
- 0,0,0);
- AssertState(HeapTupleIsValid(tuple));
- attributeType =
- (((TypeTupleForm)GETSTRUCT(tuple))->typname).data;
- /*
- * check validity
- *
- */
- if (checkAttrExists(attributeName, attributeType, inhSchema) ||
- checkAttrExists(attributeName, attributeType, schema)) {
- /*
- * this entry already exists
- */
- continue;
- }
-
- /*
- * add an entry to the schema
- */
- def = makeNode(ColumnDef);
- typename = makeNode(TypeName);
- def->colname = pstrdup(attributeName);
- typename->name = pstrdup(attributeType);
- def->typename = typename;
- def->is_not_null = attribute->attnotnull;
- def->defval = NULL;
- if ( attribute->atthasdef )
- {
- AttrDefault *attrdef = constr->defval;
- int i;
-
- Assert ( constr != NULL && constr->num_defval > 0 );
-
- for (i = 0; i < constr->num_defval; i++)
- {
- if ( attrdef[i].adnum != attrno + 1 )
- continue;
- def->defval = pstrdup (attrdef[i].adsrc);
- break;
- }
- Assert ( def->defval != NULL );
- }
- partialResult = lcons(def, partialResult);
+ List *rest;
+ ColumnDef *coldef = lfirst(entry);
+
+ foreach(rest, lnext(entry))
+ {
+
+ /*
+ * check for duplicated relation names
+ */
+ ColumnDef *restdef = lfirst(rest);
+
+ if (!strcmp(coldef->colname, restdef->colname))
+ {
+ elog(WARN, "attribute \"%s\" duplicated",
+ coldef->colname);
+ }
+ }
}
-
- if ( constr && constr->num_check > 0 )
+ foreach(entry, supers)
{
- ConstrCheck *check = constr->check;
- int i;
-
- for (i = 0; i < constr->num_check; i++)
- {
- ConstraintDef *cdef = (ConstraintDef *) palloc (sizeof (ConstraintDef));
-
- cdef->type = CONSTR_CHECK;
- if ( check[i].ccname[0] == '$' )
- cdef->name = NULL;
- else
- cdef->name = pstrdup (check[i].ccname);
- cdef->def = (void*) pstrdup (check[i].ccsrc);
- constraints = lappend (constraints, cdef);
- }
+ List *rest;
+
+ foreach(rest, lnext(entry))
+ {
+ if (!strcmp(strVal(lfirst(entry)), strVal(lfirst(rest))))
+ {
+ elog(WARN, "relation \"%s\" duplicated",
+ strVal(lfirst(entry)));
+ }
+ }
}
-
+
/*
- * iteration cleanup and result collection
+ * merge the inherited attributes into the schema
*/
- heap_close(relation);
+ foreach(entry, supers)
+ {
+ char *name = strVal(lfirst(entry));
+ Relation relation;
+ List *partialResult = NIL;
+ AttrNumber attrno;
+ TupleDesc tupleDesc;
+ TupleConstr *constr;
+
+ relation = heap_openr(name);
+ if (relation == NULL)
+ {
+ elog(WARN,
+ "MergeAttr: Can't inherit from non-existent superclass '%s'",
+ name);
+ }
+ if (relation->rd_rel->relkind == 'S')
+ {
+ elog(WARN, "MergeAttr: Can't inherit from sequence superclass '%s'",
+ name);
+ }
+ tupleDesc = RelationGetTupleDescriptor(relation);
+ constr = tupleDesc->constr;
+
+ for (attrno = relation->rd_rel->relnatts - 1; attrno >= 0; attrno--)
+ {
+ AttributeTupleForm attribute = tupleDesc->attrs[attrno];
+ char *attributeName;
+ char *attributeType;
+ HeapTuple tuple;
+ ColumnDef *def;
+ TypeName *typename;
+
+ /*
+ * form name, type and constraints
+ */
+ attributeName = (attribute->attname).data;
+ tuple =
+ SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(attribute->atttypid),
+ 0, 0, 0);
+ AssertState(HeapTupleIsValid(tuple));
+ attributeType =
+ (((TypeTupleForm) GETSTRUCT(tuple))->typname).data;
+
+ /*
+ * check validity
+ *
+ */
+ if (checkAttrExists(attributeName, attributeType, inhSchema) ||
+ checkAttrExists(attributeName, attributeType, schema))
+ {
+
+ /*
+ * this entry already exists
+ */
+ continue;
+ }
+
+ /*
+ * add an entry to the schema
+ */
+ def = makeNode(ColumnDef);
+ typename = makeNode(TypeName);
+ def->colname = pstrdup(attributeName);
+ typename->name = pstrdup(attributeType);
+ def->typename = typename;
+ def->is_not_null = attribute->attnotnull;
+ def->defval = NULL;
+ if (attribute->atthasdef)
+ {
+ AttrDefault *attrdef = constr->defval;
+ int i;
+
+ Assert(constr != NULL && constr->num_defval > 0);
+
+ for (i = 0; i < constr->num_defval; i++)
+ {
+ if (attrdef[i].adnum != attrno + 1)
+ continue;
+ def->defval = pstrdup(attrdef[i].adsrc);
+ break;
+ }
+ Assert(def->defval != NULL);
+ }
+ partialResult = lcons(def, partialResult);
+ }
+
+ if (constr && constr->num_check > 0)
+ {
+ ConstrCheck *check = constr->check;
+ int i;
+
+ for (i = 0; i < constr->num_check; i++)
+ {
+ ConstraintDef *cdef = (ConstraintDef *) palloc(sizeof(ConstraintDef));
+
+ cdef->type = CONSTR_CHECK;
+ if (check[i].ccname[0] == '$')
+ cdef->name = NULL;
+ else
+ cdef->name = pstrdup(check[i].ccname);
+ cdef->def = (void *) pstrdup(check[i].ccsrc);
+ constraints = lappend(constraints, cdef);
+ }
+ }
+
+ /*
+ * iteration cleanup and result collection
+ */
+ heap_close(relation);
+
+ /*
+ * wants the inherited schema to appear in the order they are
+ * specified in CREATE TABLE
+ */
+ inhSchema = nconc(inhSchema, partialResult);
+ }
/*
- * wants the inherited schema to appear in the order they are
- * specified in CREATE TABLE
+ * put the inherited schema before our the schema for this table
*/
- inhSchema = nconc(inhSchema, partialResult);
- }
-
- /*
- * put the inherited schema before our the schema for this table
- */
- schema = nconc(inhSchema, schema);
- *supconstr = constraints;
- return (schema);
+ schema = nconc(inhSchema, schema);
+ *supconstr = constraints;
+ return (schema);
}
/*
* StoreCatalogInheritance --
- * Updates the system catalogs with proper inheritance information.
+ * Updates the system catalogs with proper inheritance information.
*/
static void
-StoreCatalogInheritance(Oid relationId, List *supers)
+StoreCatalogInheritance(Oid relationId, List * supers)
{
- Relation relation;
- TupleDesc desc;
- int16 seqNumber;
- List *entry;
- List *idList;
- HeapTuple tuple;
-
- /* ----------------
- * sanity checks
- * ----------------
- */
- AssertArg(OidIsValid(relationId));
-
- if (supers==NIL)
- return;
-
- /* ----------------
- * Catalog INHERITS information.
- * ----------------
- */
- relation = heap_openr( InheritsRelationName );
- desc = RelationGetTupleDescriptor(relation);
-
- seqNumber = 1;
- idList = NIL;
- foreach (entry, supers) {
- Datum datum[ Natts_pg_inherits ];
- char nullarr[ Natts_pg_inherits ];
-
- tuple = SearchSysCacheTuple(RELNAME,
- PointerGetDatum(strVal(lfirst(entry))),
- 0,0,0);
- AssertArg(HeapTupleIsValid(tuple));
-
- /*
- * build idList for use below
- */
- idList = lappendi(idList, tuple->t_oid);
-
- datum[0] = ObjectIdGetDatum(relationId); /* inhrel */
- datum[1] = ObjectIdGetDatum(tuple->t_oid); /* inhparent */
- datum[2] = Int16GetDatum(seqNumber); /* inhseqno */
-
- nullarr[0] = ' ';
- nullarr[1] = ' ';
- nullarr[2] = ' ';
-
- tuple = heap_formtuple(desc,datum, nullarr);
-
- heap_insert(relation, tuple);
- pfree(tuple);
-
- seqNumber += 1;
- }
-
- heap_close(relation);
-
- /* ----------------
- * Catalog IPL information.
- *
- * Algorithm:
- * 0. list superclasses (by Oid) in order given (see idList).
- * 1. append after each relationId, its superclasses, recursively.
- * 3. remove all but last of duplicates.
- * 4. store result.
- * ----------------
- */
-
- /* ----------------
- * 1.
- * ----------------
- */
- foreach (entry, idList) {
+ Relation relation;
+ TupleDesc desc;
+ int16 seqNumber;
+ List *entry;
+ List *idList;
HeapTuple tuple;
- Oid id;
- int16 number;
- List *next;
- List *current;
-
- id = (Oid)lfirsti(entry);
- current = entry;
- next = lnext(entry);
-
- for (number = 1; ; number += 1) {
- tuple = SearchSysCacheTuple(INHRELID,
- ObjectIdGetDatum(id),
- Int16GetDatum(number),
- 0,0);
-
- if (! HeapTupleIsValid(tuple))
- break;
-
- lnext(current) =
- lconsi(((InheritsTupleForm)
- GETSTRUCT(tuple))->inhparent,
- NIL);
-
- current = lnext(current);
+
+ /* ----------------
+ * sanity checks
+ * ----------------
+ */
+ AssertArg(OidIsValid(relationId));
+
+ if (supers == NIL)
+ return;
+
+ /* ----------------
+ * Catalog INHERITS information.
+ * ----------------
+ */
+ relation = heap_openr(InheritsRelationName);
+ desc = RelationGetTupleDescriptor(relation);
+
+ seqNumber = 1;
+ idList = NIL;
+ foreach(entry, supers)
+ {
+ Datum datum[Natts_pg_inherits];
+ char nullarr[Natts_pg_inherits];
+
+ tuple = SearchSysCacheTuple(RELNAME,
+ PointerGetDatum(strVal(lfirst(entry))),
+ 0, 0, 0);
+ AssertArg(HeapTupleIsValid(tuple));
+
+ /*
+ * build idList for use below
+ */
+ idList = lappendi(idList, tuple->t_oid);
+
+ datum[0] = ObjectIdGetDatum(relationId); /* inhrel */
+ datum[1] = ObjectIdGetDatum(tuple->t_oid); /* inhparent */
+ datum[2] = Int16GetDatum(seqNumber); /* inhseqno */
+
+ nullarr[0] = ' ';
+ nullarr[1] = ' ';
+ nullarr[2] = ' ';
+
+ tuple = heap_formtuple(desc, datum, nullarr);
+
+ heap_insert(relation, tuple);
+ pfree(tuple);
+
+ seqNumber += 1;
}
- lnext(current) = next;
- }
-
- /* ----------------
- * 2.
- * ----------------
- */
- foreach (entry, idList) {
- Oid name;
- List *rest;
- bool found = false;
-
- again:
- name = lfirsti(entry);
- foreach (rest, lnext(entry)) {
- if (name == lfirsti(rest)) {
- found = true;
- break;
- }
+
+ heap_close(relation);
+
+ /* ----------------
+ * Catalog IPL information.
+ *
+ * Algorithm:
+ * 0. list superclasses (by Oid) in order given (see idList).
+ * 1. append after each relationId, its superclasses, recursively.
+ * 3. remove all but last of duplicates.
+ * 4. store result.
+ * ----------------
+ */
+
+ /* ----------------
+ * 1.
+ * ----------------
+ */
+ foreach(entry, idList)
+ {
+ HeapTuple tuple;
+ Oid id;
+ int16 number;
+ List *next;
+ List *current;
+
+ id = (Oid) lfirsti(entry);
+ current = entry;
+ next = lnext(entry);
+
+ for (number = 1;; number += 1)
+ {
+ tuple = SearchSysCacheTuple(INHRELID,
+ ObjectIdGetDatum(id),
+ Int16GetDatum(number),
+ 0, 0);
+
+ if (!HeapTupleIsValid(tuple))
+ break;
+
+ lnext(current) =
+ lconsi(((InheritsTupleForm)
+ GETSTRUCT(tuple))->inhparent,
+ NIL);
+
+ current = lnext(current);
+ }
+ lnext(current) = next;
}
- if (found) {
- /*
- * entry list must be of length >= 2 or else no match
- *
- * so, remove this entry.
- */
- lfirst(entry) = lfirst(lnext(entry));
- lnext(entry) = lnext(lnext(entry));
-
- found = false;
- goto again;
+
+ /* ----------------
+ * 2.
+ * ----------------
+ */
+ foreach(entry, idList)
+ {
+ Oid name;
+ List *rest;
+ bool found = false;
+
+again:
+ name = lfirsti(entry);
+ foreach(rest, lnext(entry))
+ {
+ if (name == lfirsti(rest))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ {
+
+ /*
+ * entry list must be of length >= 2 or else no match
+ *
+ * so, remove this entry.
+ */
+ lfirst(entry) = lfirst(lnext(entry));
+ lnext(entry) = lnext(lnext(entry));
+
+ found = false;
+ goto again;
+ }
}
- }
-
- /* ----------------
- * 3.
- * ----------------
- */
- relation = heap_openr( InheritancePrecidenceListRelationName );
- desc = RelationGetTupleDescriptor(relation);
-
- seqNumber = 1;
-
- foreach (entry, idList) {
- Datum datum[ Natts_pg_ipl ];
- char nullarr[ Natts_pg_ipl ];
-
- datum[0] = ObjectIdGetDatum(relationId); /* iplrel */
- datum[1] = ObjectIdGetDatum(lfirsti(entry));
- /*iplinherits*/
- datum[2] = Int16GetDatum(seqNumber); /* iplseqno */
-
- nullarr[0] = ' ';
- nullarr[1] = ' ';
- nullarr[2] = ' ';
-
- tuple = heap_formtuple( desc, datum, nullarr);
-
- heap_insert(relation, tuple);
- pfree(tuple);
-
- seqNumber += 1;
- }
-
- heap_close(relation);
+
+ /* ----------------
+ * 3.
+ * ----------------
+ */
+ relation = heap_openr(InheritancePrecidenceListRelationName);
+ desc = RelationGetTupleDescriptor(relation);
+
+ seqNumber = 1;
+
+ foreach(entry, idList)
+ {
+ Datum datum[Natts_pg_ipl];
+ char nullarr[Natts_pg_ipl];
+
+ datum[0] = ObjectIdGetDatum(relationId); /* iplrel */
+ datum[1] = ObjectIdGetDatum(lfirsti(entry));
+ /* iplinherits */
+ datum[2] = Int16GetDatum(seqNumber); /* iplseqno */
+
+ nullarr[0] = ' ';
+ nullarr[1] = ' ';
+ nullarr[2] = ' ';
+
+ tuple = heap_formtuple(desc, datum, nullarr);
+
+ heap_insert(relation, tuple);
+ pfree(tuple);
+
+ seqNumber += 1;
+ }
+
+ heap_close(relation);
}
/*
* returns 1 if attribute already exists in schema, 0 otherwise.
*/
static int
-checkAttrExists(char *attributeName, char *attributeType, List *schema)
+checkAttrExists(char *attributeName, char *attributeType, List * schema)
{
- List *s;
-
- foreach (s, schema) {
- ColumnDef *def = lfirst(s);
-
- if (!strcmp(attributeName, def->colname)) {
- /*
- * attribute exists. Make sure the types are the same.
- */
- if (strcmp(attributeType, def->typename->name) != 0) {
- elog(WARN, "%s and %s conflict for %s",
- attributeType, def->typename->name, attributeName);
- }
- return 1;
+ List *s;
+
+ foreach(s, schema)
+ {
+ ColumnDef *def = lfirst(s);
+
+ if (!strcmp(attributeName, def->colname))
+ {
+
+ /*
+ * attribute exists. Make sure the types are the same.
+ */
+ if (strcmp(attributeType, def->typename->name) != 0)
+ {
+ elog(WARN, "%s and %s conflict for %s",
+ attributeType, def->typename->name, attributeName);
+ }
+ return 1;
+ }
}
- }
- return 0;
+ return 0;
}
/*
* MakeArchiveName
- * make an archive rel name out of a regular rel name
+ * make an archive rel name out of a regular rel name
*
* the CALLER is responsible for freeing the memory allocated
*/
-char*
+char *
MakeArchiveName(Oid relationId)
{
- char *arch;
+ char *arch;
- /*
- * Archive relations are named a,XXXXX where XXXXX == the OID
- * of the relation they archive. Create a string containing
- * this name and find the reldesc for the archive relation.
- */
- arch = palloc(NAMEDATALEN);
- sprintf(arch, "a,%d",relationId);
+ /*
+ * Archive relations are named a,XXXXX where XXXXX == the OID of the
+ * relation they archive. Create a string containing this name and
+ * find the reldesc for the archive relation.
+ */
+ arch = palloc(NAMEDATALEN);
+ sprintf(arch, "a,%d", relationId);
- return arch;
+ return arch;
}
diff --git a/src/backend/commands/defind.c b/src/backend/commands/defind.c
index c6b293fec68..9b8c5a0218a 100644
--- a/src/backend/commands/defind.c
+++ b/src/backend/commands/defind.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* defind.c--
- * POSTGRES define, extend and remove index code.
+ * POSTGRES define, extend and remove index code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/defind.c,v 1.12 1997/03/26 03:05:28 vadim Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/defind.c,v 1.13 1997/09/07 04:40:43 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -30,7 +30,7 @@
#include <utils/relcache.h>
#include <utils/lsyscache.h>
#include <commands/defrem.h>
-#include <parser/parsetree.h> /* for getrelid() */
+#include <parser/parsetree.h> /* for getrelid() */
#include <optimizer/prep.h>
#include <optimizer/clauses.h>
#include <storage/lmgr.h>
@@ -39,508 +39,543 @@
#define IsFuncIndex(ATTR_LIST) (((IndexElem*)lfirst(ATTR_LIST))->args!=NULL)
/* non-export function prototypes */
-static void CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid);
-static void CheckPredExpr(Node *predicate, List *rangeTable,
+static void CheckPredicate(List * predList, List * rangeTable, Oid baseRelOid);
+static void
+CheckPredExpr(Node * predicate, List * rangeTable,
Oid baseRelOid);
static void
-CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid);
-static void FuncIndexArgs(IndexElem *funcIndex, AttrNumber *attNumP,
- Oid *argTypes, Oid *opOidP, Oid relId);
-static void NormIndexAttrs(List *attList, AttrNumber *attNumP,
- Oid *opOidP, Oid relId);
-static char *GetDefaultOpClass(Oid atttypid);
+ CheckPredClause(Expr * predicate, List * rangeTable, Oid baseRelOid);
+static void
+FuncIndexArgs(IndexElem * funcIndex, AttrNumber * attNumP,
+ Oid * argTypes, Oid * opOidP, Oid relId);
+static void
+NormIndexAttrs(List * attList, AttrNumber * attNumP,
+ Oid * opOidP, Oid relId);
+static char *GetDefaultOpClass(Oid atttypid);
/*
* DefineIndex --
- * Creates a new index.
+ * Creates a new index.
*
* 'attributeList' is a list of IndexElem specifying either a functional
- * index or a list of attributes to index on.
+ * index or a list of attributes to index on.
* 'parameterList' is a list of ParamString specified in the with clause.
* 'predicate' is the qual specified in the where clause.
* 'rangetable' is for the predicate
*
* Exceptions:
- * XXX
+ * XXX
*/
void
DefineIndex(char *heapRelationName,
- char *indexRelationName,
- char *accessMethodName,
- List *attributeList,
- List *parameterList,
- bool unique,
- Expr *predicate,
- List *rangetable)
+ char *indexRelationName,
+ char *accessMethodName,
+ List * attributeList,
+ List * parameterList,
+ bool unique,
+ Expr * predicate,
+ List * rangetable)
{
- Oid *classObjectId;
- Oid accessMethodId;
- Oid relationId;
- int numberOfAttributes;
- AttrNumber *attributeNumberA;
- HeapTuple tuple;
- uint16 parameterCount = 0;
- Datum *parameterA = NULL;
- FuncIndexInfo fInfo;
- List *cnfPred = NULL;
- bool lossy = FALSE;
- List *pl;
-
- /*
- * Handle attributes
- */
- numberOfAttributes = length(attributeList);
- if (numberOfAttributes <= 0) {
- elog(WARN, "DefineIndex: must specify at least one attribute");
- }
-
- /*
- * compute heap relation id
- */
- tuple = SearchSysCacheTuple(RELNAME,
- PointerGetDatum(heapRelationName),
- 0,0,0);
- if (!HeapTupleIsValid(tuple)) {
- elog(WARN, "DefineIndex: %s relation not found",
- heapRelationName);
- }
- relationId = tuple->t_oid;
-
- if (unique && strcmp(accessMethodName,"btree") != 0)
- elog(WARN, "DefineIndex: unique indices are only available with the btree access method");
-
- if (numberOfAttributes > 1 && strcmp(accessMethodName,"btree") != 0)
- elog(WARN, "DefineIndex: multi-column indices are only available with the btree access method");
-
- /*
- * compute access method id
- */
- tuple = SearchSysCacheTuple(AMNAME, PointerGetDatum(accessMethodName),
- 0,0,0);
- if (!HeapTupleIsValid(tuple)) {
- elog(WARN, "DefineIndex: %s access method not found",
- accessMethodName);
- }
- accessMethodId = tuple->t_oid;
-
-
- /*
- * Handle parameters
- * [param list is now different (NOT USED, really) - ay 10/94]
- *
- * WITH clause reinstated to handle lossy indices.
- * -- JMH, 7/22/96
- */
- foreach(pl, parameterList) {
- ParamString *param = (ParamString*)lfirst(pl);
-
- if (!strcasecmp(param->name, "islossy"))
- lossy = TRUE;
- }
-
-
- /*
- * Convert the partial-index predicate from parsetree form to plan
- * form, so it can be readily evaluated during index creation.
- * Note: "predicate" comes in as a list containing (1) the predicate
- * itself (a where_clause), and (2) a corresponding range table.
- *
- * [(1) is 'predicate' and (2) is 'rangetable' now. - ay 10/94]
- */
- if (predicate != NULL && rangetable != NIL) {
- cnfPred = cnfify((Expr*)copyObject(predicate), true);
- fix_opids(cnfPred);
- CheckPredicate(cnfPred, rangetable, relationId);
- }
-
- if (IsFuncIndex(attributeList)) {
- IndexElem *funcIndex= lfirst(attributeList);
- int nargs;
-
- nargs = length(funcIndex->args);
- if (nargs > INDEX_MAX_KEYS) {
- elog(WARN,
- "Too many args to function, limit of %d",
- INDEX_MAX_KEYS);
+ Oid *classObjectId;
+ Oid accessMethodId;
+ Oid relationId;
+ int numberOfAttributes;
+ AttrNumber *attributeNumberA;
+ HeapTuple tuple;
+ uint16 parameterCount = 0;
+ Datum *parameterA = NULL;
+ FuncIndexInfo fInfo;
+ List *cnfPred = NULL;
+ bool lossy = FALSE;
+ List *pl;
+
+ /*
+ * Handle attributes
+ */
+ numberOfAttributes = length(attributeList);
+ if (numberOfAttributes <= 0)
+ {
+ elog(WARN, "DefineIndex: must specify at least one attribute");
+ }
+
+ /*
+ * compute heap relation id
+ */
+ tuple = SearchSysCacheTuple(RELNAME,
+ PointerGetDatum(heapRelationName),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN, "DefineIndex: %s relation not found",
+ heapRelationName);
}
-
- FIsetnArgs(&fInfo,nargs);
+ relationId = tuple->t_oid;
- strcpy(FIgetname(&fInfo), funcIndex->name);
+ if (unique && strcmp(accessMethodName, "btree") != 0)
+ elog(WARN, "DefineIndex: unique indices are only available with the btree access method");
- attributeNumberA =
- (AttrNumber *)palloc(nargs * sizeof attributeNumberA[0]);
-
- classObjectId = (Oid *)palloc(sizeof classObjectId[0]);
-
-
- FuncIndexArgs(funcIndex, attributeNumberA,
- &(FIgetArg(&fInfo, 0)),
- classObjectId, relationId);
-
- index_create(heapRelationName,
- indexRelationName,
- &fInfo, NULL, accessMethodId,
- numberOfAttributes, attributeNumberA,
- classObjectId, parameterCount, parameterA, (Node*)cnfPred,
- lossy, unique);
- }else {
- attributeNumberA =
- (AttrNumber *)palloc(numberOfAttributes *
- sizeof attributeNumberA[0]);
-
- classObjectId =
- (Oid *)palloc(numberOfAttributes * sizeof classObjectId[0]);
-
- NormIndexAttrs(attributeList, attributeNumberA,
- classObjectId, relationId);
-
- index_create(heapRelationName, indexRelationName, NULL,
- attributeList,
- accessMethodId, numberOfAttributes, attributeNumberA,
- classObjectId, parameterCount, parameterA, (Node*)cnfPred,
- lossy, unique);
- }
+ if (numberOfAttributes > 1 && strcmp(accessMethodName, "btree") != 0)
+ elog(WARN, "DefineIndex: multi-column indices are only available with the btree access method");
+
+ /*
+ * compute access method id
+ */
+ tuple = SearchSysCacheTuple(AMNAME, PointerGetDatum(accessMethodName),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN, "DefineIndex: %s access method not found",
+ accessMethodName);
+ }
+ accessMethodId = tuple->t_oid;
+
+
+ /*
+ * Handle parameters [param list is now different (NOT USED, really) -
+ * ay 10/94]
+ *
+ * WITH clause reinstated to handle lossy indices. -- JMH, 7/22/96
+ */
+ foreach(pl, parameterList)
+ {
+ ParamString *param = (ParamString *) lfirst(pl);
+
+ if (!strcasecmp(param->name, "islossy"))
+ lossy = TRUE;
+ }
+
+
+ /*
+ * Convert the partial-index predicate from parsetree form to plan
+ * form, so it can be readily evaluated during index creation. Note:
+ * "predicate" comes in as a list containing (1) the predicate itself
+ * (a where_clause), and (2) a corresponding range table.
+ *
+ * [(1) is 'predicate' and (2) is 'rangetable' now. - ay 10/94]
+ */
+ if (predicate != NULL && rangetable != NIL)
+ {
+ cnfPred = cnfify((Expr *) copyObject(predicate), true);
+ fix_opids(cnfPred);
+ CheckPredicate(cnfPred, rangetable, relationId);
+ }
+
+ if (IsFuncIndex(attributeList))
+ {
+ IndexElem *funcIndex = lfirst(attributeList);
+ int nargs;
+
+ nargs = length(funcIndex->args);
+ if (nargs > INDEX_MAX_KEYS)
+ {
+ elog(WARN,
+ "Too many args to function, limit of %d",
+ INDEX_MAX_KEYS);
+ }
+
+ FIsetnArgs(&fInfo, nargs);
+
+ strcpy(FIgetname(&fInfo), funcIndex->name);
+
+ attributeNumberA =
+ (AttrNumber *) palloc(nargs * sizeof attributeNumberA[0]);
+
+ classObjectId = (Oid *) palloc(sizeof classObjectId[0]);
+
+
+ FuncIndexArgs(funcIndex, attributeNumberA,
+ &(FIgetArg(&fInfo, 0)),
+ classObjectId, relationId);
+
+ index_create(heapRelationName,
+ indexRelationName,
+ &fInfo, NULL, accessMethodId,
+ numberOfAttributes, attributeNumberA,
+ classObjectId, parameterCount, parameterA, (Node *) cnfPred,
+ lossy, unique);
+ }
+ else
+ {
+ attributeNumberA =
+ (AttrNumber *) palloc(numberOfAttributes *
+ sizeof attributeNumberA[0]);
+
+ classObjectId =
+ (Oid *) palloc(numberOfAttributes * sizeof classObjectId[0]);
+
+ NormIndexAttrs(attributeList, attributeNumberA,
+ classObjectId, relationId);
+
+ index_create(heapRelationName, indexRelationName, NULL,
+ attributeList,
+ accessMethodId, numberOfAttributes, attributeNumberA,
+ classObjectId, parameterCount, parameterA, (Node *) cnfPred,
+ lossy, unique);
+ }
}
/*
* ExtendIndex --
- * Extends a partial index.
+ * Extends a partial index.
*
* Exceptions:
- * XXX
+ * XXX
*/
void
-ExtendIndex(char *indexRelationName, Expr *predicate, List *rangetable)
+ExtendIndex(char *indexRelationName, Expr * predicate, List * rangetable)
{
- Oid *classObjectId;
- Oid accessMethodId;
- Oid indexId, relationId;
- Oid indproc;
- int numberOfAttributes;
- AttrNumber *attributeNumberA;
- HeapTuple tuple;
- FuncIndexInfo fInfo;
- FuncIndexInfo *funcInfo = NULL;
- IndexTupleForm index;
- Node *oldPred = NULL;
- List *cnfPred = NULL;
- PredInfo *predInfo;
- Relation heapRelation;
- Relation indexRelation;
- int i;
-
- /*
- * compute index relation id and access method id
- */
- tuple = SearchSysCacheTuple(RELNAME, PointerGetDatum(indexRelationName),
- 0,0,0);
- if (!HeapTupleIsValid(tuple)) {
- elog(WARN, "ExtendIndex: %s index not found",
- indexRelationName);
- }
- indexId = tuple->t_oid;
- accessMethodId = ((Form_pg_class) GETSTRUCT(tuple))->relam;
-
- /*
- * find pg_index tuple
- */
- tuple = SearchSysCacheTuple(INDEXRELID,
- ObjectIdGetDatum(indexId),
- 0,0,0);
- if (!HeapTupleIsValid(tuple)) {
- elog(WARN, "ExtendIndex: %s is not an index",
- indexRelationName);
- }
-
- /*
- * Extract info from the pg_index tuple
- */
- index = (IndexTupleForm)GETSTRUCT(tuple);
- Assert(index->indexrelid == indexId);
- relationId = index->indrelid;
- indproc = index->indproc;
-
- for (i=0; i<INDEX_MAX_KEYS; i++)
- if (index->indkey[i] == 0) break;
- numberOfAttributes = i;
-
- if (VARSIZE(&index->indpred) != 0) {
- char *predString;
-
- predString = fmgr(F_TEXTOUT, &index->indpred);
- oldPred = stringToNode(predString);
- pfree(predString);
- }
- if (oldPred == NULL)
- elog(WARN, "ExtendIndex: %s is not a partial index",
- indexRelationName);
-
- /*
- * Convert the extension predicate from parsetree form to plan
- * form, so it can be readily evaluated during index creation.
- * Note: "predicate" comes in as a list containing (1) the predicate
- * itself (a where_clause), and (2) a corresponding range table.
- */
- if (rangetable != NIL) {
- cnfPred = cnfify((Expr*)copyObject(predicate), true);
- fix_opids(cnfPred);
- CheckPredicate(cnfPred, rangetable, relationId);
- }
-
- /* make predInfo list to pass to index_build */
- predInfo = (PredInfo*)palloc(sizeof(PredInfo));
- predInfo->pred = (Node*)cnfPred;
- predInfo->oldPred = oldPred;
-
- attributeNumberA =
- (AttrNumber *)palloc(numberOfAttributes*
- sizeof attributeNumberA[0]);
- classObjectId =
- (Oid *)palloc(numberOfAttributes * sizeof classObjectId[0]);
-
-
- for (i=0; i<numberOfAttributes; i++) {
- attributeNumberA[i] = index->indkey[i];
- classObjectId[i] = index->indclass[i];
- }
-
- if (indproc != InvalidOid) {
- funcInfo = &fInfo;
-/* FIgetnArgs(funcInfo) = numberOfAttributes; */
- FIsetnArgs(funcInfo,numberOfAttributes);
-
- tuple = SearchSysCacheTuple(PROOID,
- ObjectIdGetDatum(indproc),
- 0,0,0);
+ Oid *classObjectId;
+ Oid accessMethodId;
+ Oid indexId,
+ relationId;
+ Oid indproc;
+ int numberOfAttributes;
+ AttrNumber *attributeNumberA;
+ HeapTuple tuple;
+ FuncIndexInfo fInfo;
+ FuncIndexInfo *funcInfo = NULL;
+ IndexTupleForm index;
+ Node *oldPred = NULL;
+ List *cnfPred = NULL;
+ PredInfo *predInfo;
+ Relation heapRelation;
+ Relation indexRelation;
+ int i;
+
+ /*
+ * compute index relation id and access method id
+ */
+ tuple = SearchSysCacheTuple(RELNAME, PointerGetDatum(indexRelationName),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN, "ExtendIndex: %s index not found",
+ indexRelationName);
+ }
+ indexId = tuple->t_oid;
+ accessMethodId = ((Form_pg_class) GETSTRUCT(tuple))->relam;
+
+ /*
+ * find pg_index tuple
+ */
+ tuple = SearchSysCacheTuple(INDEXRELID,
+ ObjectIdGetDatum(indexId),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
- elog(WARN, "ExtendIndex: index procedure not found");
-
- namecpy(&(funcInfo->funcName),
- &(((Form_pg_proc) GETSTRUCT(tuple))->proname));
-
- FIsetProcOid(funcInfo,tuple->t_oid);
- }
-
- heapRelation = heap_open(relationId);
- indexRelation = index_open(indexId);
-
- RelationSetLockForWrite(heapRelation);
-
- InitIndexStrategy(numberOfAttributes, indexRelation, accessMethodId);
-
- index_build(heapRelation, indexRelation, numberOfAttributes,
- attributeNumberA, 0, NULL, funcInfo, predInfo);
+ {
+ elog(WARN, "ExtendIndex: %s is not an index",
+ indexRelationName);
+ }
+
+ /*
+ * Extract info from the pg_index tuple
+ */
+ index = (IndexTupleForm) GETSTRUCT(tuple);
+ Assert(index->indexrelid == indexId);
+ relationId = index->indrelid;
+ indproc = index->indproc;
+
+ for (i = 0; i < INDEX_MAX_KEYS; i++)
+ if (index->indkey[i] == 0)
+ break;
+ numberOfAttributes = i;
+
+ if (VARSIZE(&index->indpred) != 0)
+ {
+ char *predString;
+
+ predString = fmgr(F_TEXTOUT, &index->indpred);
+ oldPred = stringToNode(predString);
+ pfree(predString);
+ }
+ if (oldPred == NULL)
+ elog(WARN, "ExtendIndex: %s is not a partial index",
+ indexRelationName);
+
+ /*
+ * Convert the extension predicate from parsetree form to plan form,
+ * so it can be readily evaluated during index creation. Note:
+ * "predicate" comes in as a list containing (1) the predicate itself
+ * (a where_clause), and (2) a corresponding range table.
+ */
+ if (rangetable != NIL)
+ {
+ cnfPred = cnfify((Expr *) copyObject(predicate), true);
+ fix_opids(cnfPred);
+ CheckPredicate(cnfPred, rangetable, relationId);
+ }
+
+ /* make predInfo list to pass to index_build */
+ predInfo = (PredInfo *) palloc(sizeof(PredInfo));
+ predInfo->pred = (Node *) cnfPred;
+ predInfo->oldPred = oldPred;
+
+ attributeNumberA =
+ (AttrNumber *) palloc(numberOfAttributes *
+ sizeof attributeNumberA[0]);
+ classObjectId =
+ (Oid *) palloc(numberOfAttributes * sizeof classObjectId[0]);
+
+
+ for (i = 0; i < numberOfAttributes; i++)
+ {
+ attributeNumberA[i] = index->indkey[i];
+ classObjectId[i] = index->indclass[i];
+ }
+
+ if (indproc != InvalidOid)
+ {
+ funcInfo = &fInfo;
+/* FIgetnArgs(funcInfo) = numberOfAttributes; */
+ FIsetnArgs(funcInfo, numberOfAttributes);
+
+ tuple = SearchSysCacheTuple(PROOID,
+ ObjectIdGetDatum(indproc),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(WARN, "ExtendIndex: index procedure not found");
+
+ namecpy(&(funcInfo->funcName),
+ &(((Form_pg_proc) GETSTRUCT(tuple))->proname));
+
+ FIsetProcOid(funcInfo, tuple->t_oid);
+ }
+
+ heapRelation = heap_open(relationId);
+ indexRelation = index_open(indexId);
+
+ RelationSetLockForWrite(heapRelation);
+
+ InitIndexStrategy(numberOfAttributes, indexRelation, accessMethodId);
+
+ index_build(heapRelation, indexRelation, numberOfAttributes,
+ attributeNumberA, 0, NULL, funcInfo, predInfo);
}
/*
* CheckPredicate
- * Checks that the given list of partial-index predicates refer
- * (via the given range table) only to the given base relation oid,
- * and that they're in a form the planner can handle, i.e.,
- * boolean combinations of "ATTR OP CONST" (yes, for now, the ATTR
- * has to be on the left).
+ * Checks that the given list of partial-index predicates refer
+ * (via the given range table) only to the given base relation oid,
+ * and that they're in a form the planner can handle, i.e.,
+ * boolean combinations of "ATTR OP CONST" (yes, for now, the ATTR
+ * has to be on the left).
*/
static void
-CheckPredicate(List *predList, List *rangeTable, Oid baseRelOid)
+CheckPredicate(List * predList, List * rangeTable, Oid baseRelOid)
{
- List *item;
-
- foreach (item, predList) {
- CheckPredExpr(lfirst(item), rangeTable, baseRelOid);
- }
+ List *item;
+
+ foreach(item, predList)
+ {
+ CheckPredExpr(lfirst(item), rangeTable, baseRelOid);
+ }
}
static void
-CheckPredExpr(Node *predicate, List *rangeTable, Oid baseRelOid)
+CheckPredExpr(Node * predicate, List * rangeTable, Oid baseRelOid)
{
- List *clauses = NIL, *clause;
-
- if (is_opclause(predicate)) {
- CheckPredClause((Expr*)predicate, rangeTable, baseRelOid);
- return;
- } else if (or_clause(predicate))
- clauses = ((Expr*)predicate)->args;
- else if (and_clause(predicate))
- clauses = ((Expr*)predicate)->args;
- else
- elog(WARN, "Unsupported partial-index predicate expression type");
-
- foreach (clause, clauses) {
- CheckPredExpr(lfirst(clause), rangeTable, baseRelOid);
- }
+ List *clauses = NIL,
+ *clause;
+
+ if (is_opclause(predicate))
+ {
+ CheckPredClause((Expr *) predicate, rangeTable, baseRelOid);
+ return;
+ }
+ else if (or_clause(predicate))
+ clauses = ((Expr *) predicate)->args;
+ else if (and_clause(predicate))
+ clauses = ((Expr *) predicate)->args;
+ else
+ elog(WARN, "Unsupported partial-index predicate expression type");
+
+ foreach(clause, clauses)
+ {
+ CheckPredExpr(lfirst(clause), rangeTable, baseRelOid);
+ }
}
static void
-CheckPredClause(Expr *predicate, List *rangeTable, Oid baseRelOid)
+CheckPredClause(Expr * predicate, List * rangeTable, Oid baseRelOid)
{
- Var *pred_var;
- Const *pred_const;
-
- pred_var = (Var *)get_leftop(predicate);
- pred_const = (Const *)get_rightop(predicate);
-
- if (!IsA(predicate->oper,Oper) ||
- !IsA(pred_var,Var) ||
- !IsA(pred_const,Const)) {
- elog(WARN, "Unsupported partial-index predicate clause type");
- }
-
- if (getrelid(pred_var->varno, rangeTable) != baseRelOid)
- elog(WARN,
- "Partial-index predicates may refer only to the base relation");
+ Var *pred_var;
+ Const *pred_const;
+
+ pred_var = (Var *) get_leftop(predicate);
+ pred_const = (Const *) get_rightop(predicate);
+
+ if (!IsA(predicate->oper, Oper) ||
+ !IsA(pred_var, Var) ||
+ !IsA(pred_const, Const))
+ {
+ elog(WARN, "Unsupported partial-index predicate clause type");
+ }
+
+ if (getrelid(pred_var->varno, rangeTable) != baseRelOid)
+ elog(WARN,
+ "Partial-index predicates may refer only to the base relation");
}
-static void
-FuncIndexArgs(IndexElem *funcIndex,
- AttrNumber *attNumP,
- Oid *argTypes,
- Oid *opOidP,
- Oid relId)
+static void
+FuncIndexArgs(IndexElem * funcIndex,
+ AttrNumber * attNumP,
+ Oid * argTypes,
+ Oid * opOidP,
+ Oid relId)
{
- List *rest;
- HeapTuple tuple;
- AttributeTupleForm att;
-
- tuple = SearchSysCacheTuple(CLANAME,
- PointerGetDatum(funcIndex->class),
- 0,0,0);
-
- if (!HeapTupleIsValid(tuple))
+ List *rest;
+ HeapTuple tuple;
+ AttributeTupleForm att;
+
+ tuple = SearchSysCacheTuple(CLANAME,
+ PointerGetDatum(funcIndex->class),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tuple))
{
- elog(WARN, "DefineIndex: %s class not found",
- funcIndex->class);
+ elog(WARN, "DefineIndex: %s class not found",
+ funcIndex->class);
}
- *opOidP = tuple->t_oid;
-
- memset(argTypes, 0, 8 * sizeof(Oid));
-
- /*
- * process the function arguments
- */
- for (rest=funcIndex->args; rest != NIL; rest = lnext(rest)) {
- char *arg;
-
- arg = strVal(lfirst(rest));
-
- tuple = SearchSysCacheTuple(ATTNAME,
- ObjectIdGetDatum(relId),
- PointerGetDatum(arg),0,0);
-
- if (!HeapTupleIsValid(tuple)) {
- elog(WARN,
- "DefineIndex: attribute \"%s\" not found",
- arg);
+ *opOidP = tuple->t_oid;
+
+ memset(argTypes, 0, 8 * sizeof(Oid));
+
+ /*
+ * process the function arguments
+ */
+ for (rest = funcIndex->args; rest != NIL; rest = lnext(rest))
+ {
+ char *arg;
+
+ arg = strVal(lfirst(rest));
+
+ tuple = SearchSysCacheTuple(ATTNAME,
+ ObjectIdGetDatum(relId),
+ PointerGetDatum(arg), 0, 0);
+
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN,
+ "DefineIndex: attribute \"%s\" not found",
+ arg);
+ }
+ att = (AttributeTupleForm) GETSTRUCT(tuple);
+ *attNumP++ = att->attnum;
+ *argTypes++ = att->atttypid;
}
- att = (AttributeTupleForm)GETSTRUCT(tuple);
- *attNumP++ = att->attnum;
- *argTypes++ = att->atttypid;
- }
}
-static void
-NormIndexAttrs(List *attList, /* list of IndexElem's */
- AttrNumber *attNumP,
- Oid *opOidP,
- Oid relId)
+static void
+NormIndexAttrs(List * attList, /* list of IndexElem's */
+ AttrNumber * attNumP,
+ Oid * opOidP,
+ Oid relId)
{
- List *rest;
- HeapTuple tuple;
-
- /*
- * process attributeList
- */
-
- for (rest=attList; rest != NIL; rest = lnext(rest)) {
- IndexElem *attribute;
- AttributeTupleForm attform;
-
- attribute = lfirst(rest);
-
- if (attribute->name == NULL)
- elog(WARN, "missing attribute for define index");
-
- tuple = SearchSysCacheTuple(ATTNAME,
- ObjectIdGetDatum(relId),
- PointerGetDatum(attribute->name),
- 0,0);
- if (!HeapTupleIsValid(tuple)) {
- elog(WARN,
- "DefineIndex: attribute \"%s\" not found",
- attribute->name);
- }
+ List *rest;
+ HeapTuple tuple;
- attform = (AttributeTupleForm)GETSTRUCT(tuple);
- *attNumP++ = attform->attnum;
-
- if (attribute->class == NULL) {
- /* no operator class specified, so find the default */
- attribute->class = GetDefaultOpClass(attform->atttypid);
- if(attribute->class == NULL) {
- elog(WARN,
- "Can't find a default operator class for type %d.",
- attform->atttypid);
- }
- }
-
- tuple = SearchSysCacheTuple(CLANAME,
- PointerGetDatum(attribute->class),
- 0,0,0);
-
- if (!HeapTupleIsValid(tuple)) {
- elog(WARN, "DefineIndex: %s class not found",
- attribute->class);
+ /*
+ * process attributeList
+ */
+
+ for (rest = attList; rest != NIL; rest = lnext(rest))
+ {
+ IndexElem *attribute;
+ AttributeTupleForm attform;
+
+ attribute = lfirst(rest);
+
+ if (attribute->name == NULL)
+ elog(WARN, "missing attribute for define index");
+
+ tuple = SearchSysCacheTuple(ATTNAME,
+ ObjectIdGetDatum(relId),
+ PointerGetDatum(attribute->name),
+ 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN,
+ "DefineIndex: attribute \"%s\" not found",
+ attribute->name);
+ }
+
+ attform = (AttributeTupleForm) GETSTRUCT(tuple);
+ *attNumP++ = attform->attnum;
+
+ if (attribute->class == NULL)
+ {
+ /* no operator class specified, so find the default */
+ attribute->class = GetDefaultOpClass(attform->atttypid);
+ if (attribute->class == NULL)
+ {
+ elog(WARN,
+ "Can't find a default operator class for type %d.",
+ attform->atttypid);
+ }
+ }
+
+ tuple = SearchSysCacheTuple(CLANAME,
+ PointerGetDatum(attribute->class),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN, "DefineIndex: %s class not found",
+ attribute->class);
+ }
+ *opOidP++ = tuple->t_oid;
}
- *opOidP++ = tuple->t_oid;
- }
}
-static char *
+static char *
GetDefaultOpClass(Oid atttypid)
{
- HeapTuple tuple;
+ HeapTuple tuple;
- tuple = SearchSysCacheTuple(CLADEFTYPE,
- ObjectIdGetDatum(atttypid),
- 0, 0, 0);
- if(!HeapTupleIsValid(tuple)) {
- return 0;
- }
+ tuple = SearchSysCacheTuple(CLADEFTYPE,
+ ObjectIdGetDatum(atttypid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ {
+ return 0;
+ }
- return nameout(&(((Form_pg_opclass)GETSTRUCT(tuple))->opcname));
+ return nameout(&(((Form_pg_opclass) GETSTRUCT(tuple))->opcname));
}
/*
* RemoveIndex --
- * Deletes an index.
+ * Deletes an index.
*
* Exceptions:
- * BadArg if name is invalid.
- * "WARN" if index nonexistent.
- * ...
+ * BadArg if name is invalid.
+ * "WARN" if index nonexistent.
+ * ...
*/
void
RemoveIndex(char *name)
{
- HeapTuple tuple;
-
- tuple = SearchSysCacheTuple(RELNAME,
- PointerGetDatum(name),
- 0,0,0);
-
- if (!HeapTupleIsValid(tuple)) {
- elog(WARN, "index \"%s\" nonexistent", name);
- }
-
- if (((Form_pg_class)GETSTRUCT(tuple))->relkind != RELKIND_INDEX) {
- elog(WARN, "relation \"%s\" is of type \"%c\"",
- name,
- ((Form_pg_class)GETSTRUCT(tuple))->relkind);
- }
-
- index_destroy(tuple->t_oid);
+ HeapTuple tuple;
+
+ tuple = SearchSysCacheTuple(RELNAME,
+ PointerGetDatum(name),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tuple))
+ {
+ elog(WARN, "index \"%s\" nonexistent", name);
+ }
+
+ if (((Form_pg_class) GETSTRUCT(tuple))->relkind != RELKIND_INDEX)
+ {
+ elog(WARN, "relation \"%s\" is of type \"%c\"",
+ name,
+ ((Form_pg_class) GETSTRUCT(tuple))->relkind);
+ }
+
+ index_destroy(tuple->t_oid);
}
diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c
index 800d85a48b8..fb1df213cec 100644
--- a/src/backend/commands/define.c
+++ b/src/backend/commands/define.c
@@ -2,33 +2,33 @@
*
* define.c--
*
- * These routines execute some of the CREATE statements. In an earlier
- * version of Postgres, these were "define" statements.
+ * These routines execute some of the CREATE statements. In an earlier
+ * version of Postgres, these were "define" statements.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.13 1997/08/12 22:52:23 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.14 1997/09/07 04:40:46 momjian Exp $
*
* DESCRIPTION
- * The "DefineFoo" routines take the parse tree and pick out the
- * appropriate arguments/flags, passing the results to the
- * corresponding "FooDefine" routines (in src/catalog) that do
- * the actual catalog-munging. These routines also verify permission
- * of the user to execute the command.
+ * The "DefineFoo" routines take the parse tree and pick out the
+ * appropriate arguments/flags, passing the results to the
+ * corresponding "FooDefine" routines (in src/catalog) that do
+ * the actual catalog-munging. These routines also verify permission
+ * of the user to execute the command.
*
* NOTES
- * These things must be defined and committed in the following order:
- * "create function":
- * input/output, recv/send procedures
- * "create type":
- * type
- * "create operator":
- * operators
+ * These things must be defined and committed in the following order:
+ * "create function":
+ * input/output, recv/send procedures
+ * "create type":
+ * type
+ * "create operator":
+ * operators
*
- * Most of the parse-tree manipulation routines are defined in
- * commands/manip.c.
+ * Most of the parse-tree manipulation routines are defined in
+ * commands/manip.c.
*
*-------------------------------------------------------------------------
*/
@@ -46,209 +46,259 @@
#include <catalog/pg_proc.h>
#include <catalog/pg_type.h>
#include <utils/syscache.h>
-#include <fmgr.h> /* for fmgr */
-#include <utils/builtins.h> /* prototype for textin() */
+#include <fmgr.h> /* for fmgr */
+#include <utils/builtins.h> /* prototype for textin() */
#include <commands/defrem.h>
#include <optimizer/xfunc.h>
#include <tcop/dest.h>
#include <catalog/pg_user.h>
-static char *defGetString(DefElem *def);
-static int defGetTypeLength(DefElem *def);
+static char *defGetString(DefElem * def);
+static int defGetTypeLength(DefElem * def);
-#define DEFAULT_TYPDELIM ','
+#define DEFAULT_TYPDELIM ','
static void
-case_translate_language_name(const char *input, char *output) {
+case_translate_language_name(const char *input, char *output)
+{
/*-------------------------------------------------------------------------
Translate the input language name to lower case, except if it's C,
- translate to upper case.
+ translate to upper case.
--------------------------------------------------------------------------*/
- int i;
+ int i;
- for (i = 0; i < NAMEDATALEN && input[i] != '\0'; ++i)
- output[i] = tolower(input[i]);
+ for (i = 0; i < NAMEDATALEN && input[i] != '\0'; ++i)
+ output[i] = tolower(input[i]);
- output[i] = '\0';
+ output[i] = '\0';
- if (strcmp(output, "c") == 0) output[0] = 'C';
-}
+ if (strcmp(output, "c") == 0)
+ output[0] = 'C';
+}
static void
-compute_return_type(const Node *returnType,
- char **prorettype_p, bool *returnsSet_p) {
+compute_return_type(const Node * returnType,
+ char **prorettype_p, bool * returnsSet_p)
+{
/*---------------------------------------------------------------------------
- Examine the "returns" clause returnType of the CREATE FUNCTION statement
+ Examine the "returns" clause returnType of the CREATE FUNCTION statement
and return information about it as **prorettype_p and **returnsSet.
----------------------------------------------------------------------------*/
- if (nodeTag(returnType) == T_TypeName) {
- /* a set of values */
- TypeName *setType = (TypeName *)returnType;
- *prorettype_p = setType->name;
- *returnsSet_p = true;
- }else {
- /* singleton */
- *prorettype_p = strVal(returnType);
- *returnsSet_p = false;
- }
+ if (nodeTag(returnType) == T_TypeName)
+ {
+ /* a set of values */
+ TypeName *setType = (TypeName *) returnType;
+
+ *prorettype_p = setType->name;
+ *returnsSet_p = true;
+ }
+ else
+ {
+ /* singleton */
+ *prorettype_p = strVal(returnType);
+ *returnsSet_p = false;
+ }
}
-
-static void
-compute_full_attributes(const List *parameters, int32 *byte_pct_p,
- int32 *perbyte_cpu_p, int32 *percall_cpu_p,
- int32 *outin_ratio_p, bool *canCache_p) {
+
+static void
+compute_full_attributes(const List * parameters, int32 * byte_pct_p,
+ int32 * perbyte_cpu_p, int32 * percall_cpu_p,
+ int32 * outin_ratio_p, bool * canCache_p)
+{
/*--------------------------------------------------------------------------
Interpret the parameters *parameters and return their contents as
*byte_pct_p, etc.
These are the full parameters of a C or internal function.
---------------------------------------------------------------------------*/
- List *pl;
-
- /* the defaults */
- *byte_pct_p = BYTE_PCT;
- *perbyte_cpu_p = PERBYTE_CPU;
- *percall_cpu_p = PERCALL_CPU;
- *outin_ratio_p = OUTIN_RATIO;
-
- foreach(pl, (List *)parameters) {
- ParamString *param = (ParamString*)lfirst(pl);
-
- if (strcasecmp(param->name, "iscachable") == 0) {
- *canCache_p = true;
- } else if (strcasecmp(param->name, "trusted") == 0) {
- /*
- * we don't have untrusted functions any more. The 4.2
- * implementation is lousy anyway so I took it out.
- * -ay 10/94
- */
- elog(WARN, "untrusted function has been decommissioned.");
- } else if (strcasecmp(param->name, "byte_pct") == 0) {
- /*
- ** handle expensive function parameters
- */
- *byte_pct_p = atoi(param->val);
- } else if (strcasecmp(param->name, "perbyte_cpu") == 0) {
- if (sscanf(param->val, "%d", perbyte_cpu_p) == 0) {
- int count;
- char *ptr;
- for (count = 0, ptr = param->val; *ptr != '\0'; ptr++)
- if (*ptr == '!') count++;
- *perbyte_cpu_p = (int) pow(10.0, (double) count);
- }
- } else if (strcasecmp(param->name, "percall_cpu") == 0) {
- if (sscanf(param->val, "%d", percall_cpu_p) == 0) {
- int count;
- char *ptr;
- for (count = 0, ptr = param->val; *ptr != '\0'; ptr++)
- if (*ptr == '!') count++;
- *percall_cpu_p = (int) pow(10.0, (double) count);
- }
- } else if (strcasecmp(param->name, "outin_ratio") == 0) {
- *outin_ratio_p = atoi(param->val);
- }
- }
+ List *pl;
+
+ /* the defaults */
+ *byte_pct_p = BYTE_PCT;
+ *perbyte_cpu_p = PERBYTE_CPU;
+ *percall_cpu_p = PERCALL_CPU;
+ *outin_ratio_p = OUTIN_RATIO;
+
+ foreach(pl, (List *) parameters)
+ {
+ ParamString *param = (ParamString *) lfirst(pl);
+
+ if (strcasecmp(param->name, "iscachable") == 0)
+ {
+ *canCache_p = true;
+ }
+ else if (strcasecmp(param->name, "trusted") == 0)
+ {
+
+ /*
+ * we don't have untrusted functions any more. The 4.2
+ * implementation is lousy anyway so I took it out. -ay 10/94
+ */
+ elog(WARN, "untrusted function has been decommissioned.");
+ }
+ else if (strcasecmp(param->name, "byte_pct") == 0)
+ {
+
+ /*
+ * * handle expensive function parameters
+ */
+ *byte_pct_p = atoi(param->val);
+ }
+ else if (strcasecmp(param->name, "perbyte_cpu") == 0)
+ {
+ if (sscanf(param->val, "%d", perbyte_cpu_p) == 0)
+ {
+ int count;
+ char *ptr;
+
+ for (count = 0, ptr = param->val; *ptr != '\0'; ptr++)
+ if (*ptr == '!')
+ count++;
+ *perbyte_cpu_p = (int) pow(10.0, (double) count);
+ }
+ }
+ else if (strcasecmp(param->name, "percall_cpu") == 0)
+ {
+ if (sscanf(param->val, "%d", percall_cpu_p) == 0)
+ {
+ int count;
+ char *ptr;
+
+ for (count = 0, ptr = param->val; *ptr != '\0'; ptr++)
+ if (*ptr == '!')
+ count++;
+ *percall_cpu_p = (int) pow(10.0, (double) count);
+ }
+ }
+ else if (strcasecmp(param->name, "outin_ratio") == 0)
+ {
+ *outin_ratio_p = atoi(param->val);
+ }
+ }
}
static void
interpret_AS_clause(const char languageName[], const char as[],
- char **prosrc_str_p, char **probin_str_p) {
-
- if ( strcmp(languageName, "C") == 0 ||
- strcmp(languageName, "internal") == 0 ) {
- *prosrc_str_p = "-";
- *probin_str_p = (char *)as;
- } else {
- *prosrc_str_p = (char *)as;
- *probin_str_p = "-";
- }
+ char **prosrc_str_p, char **probin_str_p)
+{
+
+ if (strcmp(languageName, "C") == 0 ||
+ strcmp(languageName, "internal") == 0)
+ {
+ *prosrc_str_p = "-";
+ *probin_str_p = (char *) as;
+ }
+ else
+ {
+ *prosrc_str_p = (char *) as;
+ *probin_str_p = "-";
+ }
}
/*
* CreateFunction --
- * Execute a CREATE FUNCTION utility statement.
+ * Execute a CREATE FUNCTION utility statement.
*
*/
void
-CreateFunction(ProcedureStmt *stmt, CommandDest dest)
+CreateFunction(ProcedureStmt * stmt, CommandDest dest)
{
- char *probin_str;
- /* pathname of executable file that executes this function, if any */
- char *prosrc_str;
- /* SQL that executes this function, if any */
- char *prorettype;
- /* Type of return value (or member of set of values) from function */
- char languageName[NAMEDATALEN];
- /* name of language of function, with case adjusted:
- "C", "internal", or "SQL"
- */
- /* The following are attributes of the function, as expressed in the
- CREATE FUNCTION statement, where applicable.
- */
- int32 byte_pct, perbyte_cpu, percall_cpu, outin_ratio;
- bool canCache;
- bool returnsSet;
- /* The function returns a set of values, as opposed to a singleton. */
-
-
- case_translate_language_name(stmt->language, languageName);
-
- compute_return_type(stmt->returnType, &prorettype, &returnsSet);
-
- if ( strcmp(languageName, "C") == 0 ||
- strcmp(languageName, "internal") == 0 ) {
- compute_full_attributes(stmt->withClause,
- &byte_pct, &perbyte_cpu, &percall_cpu,
- &outin_ratio, &canCache);
- } else if (strcmp(languageName, "sql") == 0) {
- /* query optimizer groks sql, these are meaningless */
- perbyte_cpu = percall_cpu = 0;
- byte_pct = outin_ratio = 100;
- canCache = false;
- } else {
- elog(WARN,
- "Unrecognized language specified in a CREATE FUNCTION: "
- "'%s'. Recognized languages are sql, C, and internal.",
- languageName);
- }
-
- interpret_AS_clause(languageName, stmt->as, &prosrc_str, &probin_str);
-
- if (strcmp(languageName, "sql") != 0 && !superuser())
- elog(WARN,
- "Only users with Postgres superuser privilege are permitted "
- "to create a function "
- "in the '%s' language. Others may use the 'sql' language.",
- languageName);
- /* Above does not return. */
- else {
- /* And now that we have all the parameters, and know we're permitted
- to do so, go ahead and create the function.
- */
- ProcedureCreate(stmt->funcname,
- returnsSet,
- prorettype,
- languageName,
- prosrc_str, /* converted to text later */
- probin_str, /* converted to text later */
- canCache,
- true, /* (obsolete "trusted") */
- byte_pct,
- perbyte_cpu,
- percall_cpu,
- outin_ratio,
- stmt->defArgs,
- dest);
- }
+ char *probin_str;
+
+ /* pathname of executable file that executes this function, if any */
+ char *prosrc_str;
+
+ /* SQL that executes this function, if any */
+ char *prorettype;
+
+ /* Type of return value (or member of set of values) from function */
+ char languageName[NAMEDATALEN];
+
+ /*
+ * name of language of function, with case adjusted: "C", "internal",
+ * or "SQL"
+ */
+
+ /*
+ * The following are attributes of the function, as expressed in the
+ * CREATE FUNCTION statement, where applicable.
+ */
+ int32 byte_pct,
+ perbyte_cpu,
+ percall_cpu,
+ outin_ratio;
+ bool canCache;
+ bool returnsSet;
+
+ /* The function returns a set of values, as opposed to a singleton. */
+
+
+ case_translate_language_name(stmt->language, languageName);
+
+ compute_return_type(stmt->returnType, &prorettype, &returnsSet);
+
+ if (strcmp(languageName, "C") == 0 ||
+ strcmp(languageName, "internal") == 0)
+ {
+ compute_full_attributes(stmt->withClause,
+ &byte_pct, &perbyte_cpu, &percall_cpu,
+ &outin_ratio, &canCache);
+ }
+ else if (strcmp(languageName, "sql") == 0)
+ {
+ /* query optimizer groks sql, these are meaningless */
+ perbyte_cpu = percall_cpu = 0;
+ byte_pct = outin_ratio = 100;
+ canCache = false;
+ }
+ else
+ {
+ elog(WARN,
+ "Unrecognized language specified in a CREATE FUNCTION: "
+ "'%s'. Recognized languages are sql, C, and internal.",
+ languageName);
+ }
+
+ interpret_AS_clause(languageName, stmt->as, &prosrc_str, &probin_str);
+
+ if (strcmp(languageName, "sql") != 0 && !superuser())
+ elog(WARN,
+ "Only users with Postgres superuser privilege are permitted "
+ "to create a function "
+ "in the '%s' language. Others may use the 'sql' language.",
+ languageName);
+ /* Above does not return. */
+ else
+ {
+
+ /*
+ * And now that we have all the parameters, and know we're
+ * permitted to do so, go ahead and create the function.
+ */
+ ProcedureCreate(stmt->funcname,
+ returnsSet,
+ prorettype,
+ languageName,
+ prosrc_str, /* converted to text later */
+ probin_str, /* converted to text later */
+ canCache,
+ true, /* (obsolete "trusted") */
+ byte_pct,
+ perbyte_cpu,
+ percall_cpu,
+ outin_ratio,
+ stmt->defArgs,
+ dest);
+ }
}
@@ -256,344 +306,437 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
/* --------------------------------
* DefineOperator--
*
- * this function extracts all the information from the
- * parameter list generated by the parser and then has
- * OperatorCreate() do all the actual work.
+ * this function extracts all the information from the
+ * parameter list generated by the parser and then has
+ * OperatorCreate() do all the actual work.
*
* 'parameters' is a list of DefElem
* --------------------------------
*/
void
-DefineOperator(char *oprName,
- List *parameters)
+DefineOperator(char *oprName,
+ List * parameters)
{
- uint16 precedence=0; /* operator precedence */
- bool canHash=false; /* operator hashes */
- bool isLeftAssociative=true; /* operator is left associative */
- char *functionName=NULL; /* function for operator */
- char *typeName1=NULL; /* first type name */
- char *typeName2=NULL; /* second type name */
- char *commutatorName=NULL; /* optional commutator operator name */
- char *negatorName=NULL; /* optional negator operator name */
- char *restrictionName=NULL; /* optional restrict. sel. procedure */
- char *joinName=NULL; /* optional join sel. procedure name */
- char *sortName1=NULL; /* optional first sort operator */
- char *sortName2=NULL; /* optional second sort operator */
- List *pl;
-
- /*
- * loop over the definition list and extract the information we need.
- */
- foreach (pl, parameters) {
- DefElem *defel = (DefElem *)lfirst(pl);
-
- if (!strcasecmp(defel->defname, "leftarg")) {
- /* see gram.y, must be setof */
- if (nodeTag(defel->arg)==T_TypeName)
- elog(WARN, "setof type not implemented for leftarg");
-
- if (nodeTag(defel->arg)==T_String) {
- typeName1 = defGetString(defel);
- }else {
- elog(WARN, "type for leftarg is malformed.");
- }
- } else if (!strcasecmp(defel->defname, "rightarg")) {
- /* see gram.y, must be setof */
- if (nodeTag(defel->arg)==T_TypeName)
- elog(WARN, "setof type not implemented for rightarg");
-
- if (nodeTag(defel->arg)==T_String) {
- typeName2 = defGetString(defel);
- }else {
- elog(WARN, "type for rightarg is malformed.");
- }
- } else if (!strcasecmp(defel->defname, "procedure")) {
- functionName = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "precedence")) {
- /* NOT IMPLEMENTED (never worked in v4.2) */
- elog(NOTICE, "CREATE OPERATOR: precedence not implemented");
- } else if (!strcasecmp(defel->defname, "associativity")) {
- /* NOT IMPLEMENTED (never worked in v4.2) */
- elog(NOTICE, "CREATE OPERATOR: associativity not implemented");
- } else if (!strcasecmp(defel->defname, "commutator")) {
- commutatorName = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "negator")) {
- negatorName = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "restrict")) {
- restrictionName = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "join")) {
- joinName = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "hashes")) {
- canHash = TRUE;
- } else if (!strcasecmp(defel->defname, "sort1")) {
- /* ----------------
- * XXX ( ... [ , sort1 = oprname ] [ , sort2 = oprname ] ... )
- * XXX is undocumented in the reference manual source as of
- * 89/8/22.
- * ----------------
- */
- sortName1 = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "sort2")) {
- sortName2 = defGetString(defel);
- } else {
- elog(NOTICE, "DefineOperator: attribute \"%s\" not recognized",
- defel->defname);
- }
- }
-
- /*
- * make sure we have our required definitions
- */
- if (functionName==NULL) {
- elog(WARN, "Define: \"procedure\" unspecified");
- }
-
- /* ----------------
- * now have OperatorCreate do all the work..
- * ----------------
- */
- OperatorCreate(oprName, /* operator name */
- typeName1, /* first type name */
- typeName2, /* second type name */
- functionName, /* function for operator */
- precedence, /* operator precedence */
- isLeftAssociative, /* operator is left associative */
- commutatorName, /* optional commutator operator name */
- negatorName, /* optional negator operator name */
- restrictionName, /* optional restrict. sel. procedure */
- joinName, /* optional join sel. procedure name */
- canHash, /* operator hashes */
- sortName1, /* optional first sort operator */
- sortName2); /* optional second sort operator */
-
+ uint16 precedence = 0; /* operator precedence */
+ bool canHash = false; /* operator hashes */
+ bool isLeftAssociative = true; /* operator is left
+ * associative */
+ char *functionName = NULL; /* function for operator */
+ char *typeName1 = NULL; /* first type name */
+ char *typeName2 = NULL; /* second type name */
+ char *commutatorName = NULL; /* optional commutator
+ * operator name */
+ char *negatorName = NULL; /* optional negator operator name */
+ char *restrictionName = NULL; /* optional restrict. sel.
+ * procedure */
+ char *joinName = NULL; /* optional join sel. procedure
+ * name */
+ char *sortName1 = NULL; /* optional first sort operator */
+ char *sortName2 = NULL; /* optional second sort operator */
+ List *pl;
+
+ /*
+ * loop over the definition list and extract the information we need.
+ */
+ foreach(pl, parameters)
+ {
+ DefElem *defel = (DefElem *) lfirst(pl);
+
+ if (!strcasecmp(defel->defname, "leftarg"))
+ {
+ /* see gram.y, must be setof */
+ if (nodeTag(defel->arg) == T_TypeName)
+ elog(WARN, "setof type not implemented for leftarg");
+
+ if (nodeTag(defel->arg) == T_String)
+ {
+ typeName1 = defGetString(defel);
+ }
+ else
+ {
+ elog(WARN, "type for leftarg is malformed.");
+ }
+ }
+ else if (!strcasecmp(defel->defname, "rightarg"))
+ {
+ /* see gram.y, must be setof */
+ if (nodeTag(defel->arg) == T_TypeName)
+ elog(WARN, "setof type not implemented for rightarg");
+
+ if (nodeTag(defel->arg) == T_String)
+ {
+ typeName2 = defGetString(defel);
+ }
+ else
+ {
+ elog(WARN, "type for rightarg is malformed.");
+ }
+ }
+ else if (!strcasecmp(defel->defname, "procedure"))
+ {
+ functionName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "precedence"))
+ {
+ /* NOT IMPLEMENTED (never worked in v4.2) */
+ elog(NOTICE, "CREATE OPERATOR: precedence not implemented");
+ }
+ else if (!strcasecmp(defel->defname, "associativity"))
+ {
+ /* NOT IMPLEMENTED (never worked in v4.2) */
+ elog(NOTICE, "CREATE OPERATOR: associativity not implemented");
+ }
+ else if (!strcasecmp(defel->defname, "commutator"))
+ {
+ commutatorName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "negator"))
+ {
+ negatorName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "restrict"))
+ {
+ restrictionName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "join"))
+ {
+ joinName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "hashes"))
+ {
+ canHash = TRUE;
+ }
+ else if (!strcasecmp(defel->defname, "sort1"))
+ {
+ /* ----------------
+ * XXX ( ... [ , sort1 = oprname ] [ , sort2 = oprname ] ... )
+ * XXX is undocumented in the reference manual source as of
+ * 89/8/22.
+ * ----------------
+ */
+ sortName1 = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "sort2"))
+ {
+ sortName2 = defGetString(defel);
+ }
+ else
+ {
+ elog(NOTICE, "DefineOperator: attribute \"%s\" not recognized",
+ defel->defname);
+ }
+ }
+
+ /*
+ * make sure we have our required definitions
+ */
+ if (functionName == NULL)
+ {
+ elog(WARN, "Define: \"procedure\" unspecified");
+ }
+
+ /* ----------------
+ * now have OperatorCreate do all the work..
+ * ----------------
+ */
+ OperatorCreate(oprName, /* operator name */
+ typeName1, /* first type name */
+ typeName2, /* second type name */
+ functionName,/* function for operator */
+ precedence, /* operator precedence */
+ isLeftAssociative, /* operator is left associative */
+ commutatorName, /* optional commutator operator
+ * name */
+ negatorName, /* optional negator operator name */
+ restrictionName, /* optional restrict. sel.
+ * procedure */
+ joinName, /* optional join sel. procedure name */
+ canHash, /* operator hashes */
+ sortName1, /* optional first sort operator */
+ sortName2); /* optional second sort operator */
+
}
/* -------------------
- * DefineAggregate
+ * DefineAggregate
* ------------------
*/
void
-DefineAggregate(char *aggName, List *parameters)
+DefineAggregate(char *aggName, List * parameters)
{
- char *stepfunc1Name = NULL;
- char *stepfunc2Name = NULL;
- char *finalfuncName = NULL;
- char *baseType = NULL;
- char *stepfunc1Type = NULL;
- char *stepfunc2Type = NULL;
- char *init1 = NULL;
- char *init2 = NULL;
- List *pl;
-
- foreach (pl, parameters) {
- DefElem *defel = (DefElem *)lfirst(pl);
-
- /*
- * sfunc1
- */
- if (!strcasecmp(defel->defname, "sfunc1")) {
- stepfunc1Name = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "basetype")) {
- baseType = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "stype1")) {
- stepfunc1Type = defGetString(defel);
-
- /*
- * sfunc2
- */
- } else if (!strcasecmp(defel->defname, "sfunc2")) {
- stepfunc2Name = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "stype2")) {
- stepfunc2Type = defGetString(defel);
- /*
- * final
- */
- } else if (!strcasecmp(defel->defname, "finalfunc")) {
- finalfuncName = defGetString(defel);
- /*
- * initial conditions
- */
- } else if (!strcasecmp(defel->defname, "initcond1")) {
- init1 = defGetString(defel);
- } else if (!strcasecmp(defel->defname, "initcond2")) {
- init2 = defGetString(defel);
- } else {
- elog(NOTICE, "DefineAggregate: attribute \"%s\" not recognized",
- defel->defname);
- }
- }
-
- /*
- * make sure we have our required definitions
- */
- if (baseType==NULL)
- elog(WARN, "Define: \"basetype\" unspecified");
- if (stepfunc1Name!=NULL) {
- if (stepfunc1Type==NULL)
- elog(WARN, "Define: \"stype1\" unspecified");
- }
- if (stepfunc2Name!=NULL) {
- if (stepfunc2Type==NULL)
- elog(WARN, "Define: \"stype2\" unspecified");
- }
-
- /*
- * Most of the argument-checking is done inside of AggregateCreate
- */
- AggregateCreate(aggName, /* aggregate name */
- stepfunc1Name, /* first step function name */
- stepfunc2Name, /* second step function name */
- finalfuncName, /* final function name */
- baseType, /* type of object being aggregated */
- stepfunc1Type, /* return type of first function */
- stepfunc2Type, /* return type of second function */
- init1, /* first initial condition */
- init2); /* second initial condition */
-
- /* XXX free palloc'd memory */
+ char *stepfunc1Name = NULL;
+ char *stepfunc2Name = NULL;
+ char *finalfuncName = NULL;
+ char *baseType = NULL;
+ char *stepfunc1Type = NULL;
+ char *stepfunc2Type = NULL;
+ char *init1 = NULL;
+ char *init2 = NULL;
+ List *pl;
+
+ foreach(pl, parameters)
+ {
+ DefElem *defel = (DefElem *) lfirst(pl);
+
+ /*
+ * sfunc1
+ */
+ if (!strcasecmp(defel->defname, "sfunc1"))
+ {
+ stepfunc1Name = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "basetype"))
+ {
+ baseType = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "stype1"))
+ {
+ stepfunc1Type = defGetString(defel);
+
+ /*
+ * sfunc2
+ */
+ }
+ else if (!strcasecmp(defel->defname, "sfunc2"))
+ {
+ stepfunc2Name = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "stype2"))
+ {
+ stepfunc2Type = defGetString(defel);
+
+ /*
+ * final
+ */
+ }
+ else if (!strcasecmp(defel->defname, "finalfunc"))
+ {
+ finalfuncName = defGetString(defel);
+
+ /*
+ * initial conditions
+ */
+ }
+ else if (!strcasecmp(defel->defname, "initcond1"))
+ {
+ init1 = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "initcond2"))
+ {
+ init2 = defGetString(defel);
+ }
+ else
+ {
+ elog(NOTICE, "DefineAggregate: attribute \"%s\" not recognized",
+ defel->defname);
+ }
+ }
+
+ /*
+ * make sure we have our required definitions
+ */
+ if (baseType == NULL)
+ elog(WARN, "Define: \"basetype\" unspecified");
+ if (stepfunc1Name != NULL)
+ {
+ if (stepfunc1Type == NULL)
+ elog(WARN, "Define: \"stype1\" unspecified");
+ }
+ if (stepfunc2Name != NULL)
+ {
+ if (stepfunc2Type == NULL)
+ elog(WARN, "Define: \"stype2\" unspecified");
+ }
+
+ /*
+ * Most of the argument-checking is done inside of AggregateCreate
+ */
+ AggregateCreate(aggName, /* aggregate name */
+ stepfunc1Name, /* first step function name */
+ stepfunc2Name, /* second step function name */
+ finalfuncName, /* final function name */
+ baseType, /* type of object being aggregated */
+ stepfunc1Type, /* return type of first function */
+ stepfunc2Type, /* return type of second function */
+ init1, /* first initial condition */
+ init2); /* second initial condition */
+
+ /* XXX free palloc'd memory */
}
/*
* DefineType --
- * Registers a new type.
+ * Registers a new type.
*
*/
void
-DefineType(char *typeName, List *parameters)
+DefineType(char *typeName, List * parameters)
{
- int16 internalLength= 0; /* int2 */
- int16 externalLength= 0; /* int2 */
- char *elemName = NULL;
- char *inputName = NULL;
- char *outputName = NULL;
- char *sendName = NULL;
- char *receiveName = NULL;
- char *defaultValue = NULL; /* Datum */
- bool byValue = false;
- char delimiter = DEFAULT_TYPDELIM;
- char *shadow_type;
- List *pl;
- char alignment = 'i'; /* default alignment */
-
- /*
- * Type names can only be 15 characters long, so that the shadow type
- * can be created using the 16th character as necessary.
- */
- if (strlen(typeName) >= (NAMEDATALEN - 1)) {
- elog(WARN, "DefineType: type names must be %d characters or less",
- NAMEDATALEN - 1);
- }
-
- foreach(pl, parameters) {
- DefElem *defel = (DefElem*)lfirst(pl);
-
- if (!strcasecmp(defel->defname, "internallength")) {
- internalLength = defGetTypeLength(defel);
- }else if (!strcasecmp(defel->defname, "externallength")) {
- externalLength = defGetTypeLength(defel);
- }else if (!strcasecmp(defel->defname, "input")) {
- inputName = defGetString(defel);
- }else if (!strcasecmp(defel->defname, "output")) {
- outputName = defGetString(defel);
- }else if (!strcasecmp(defel->defname, "send")) {
- sendName = defGetString(defel);
- }else if (!strcasecmp(defel->defname, "delimiter")) {
- char *p = defGetString(defel);
- delimiter = p[0];
- }else if (!strcasecmp(defel->defname, "receive")) {
- receiveName = defGetString(defel);
- }else if (!strcasecmp(defel->defname, "element")) {
- elemName = defGetString(defel);
- }else if (!strcasecmp(defel->defname, "default")) {
- defaultValue = defGetString(defel);
- }else if (!strcasecmp(defel->defname, "passedbyvalue")) {
- byValue = true;
- }else if (!strcasecmp(defel->defname, "alignment")) {
- char *a = defGetString(defel);
- if (!strcasecmp(a, "double")) {
- alignment = 'd';
- } else if (!strcasecmp(a, "int")) {
- alignment = 'i';
- } else {
- elog(WARN, "DefineType: \"%s\" alignment not recognized",
- a);
- }
- }else {
- elog(NOTICE, "DefineType: attribute \"%s\" not recognized",
- defel->defname);
- }
- }
-
- /*
- * make sure we have our required definitions
- */
- if (inputName==NULL)
- elog(WARN, "Define: \"input\" unspecified");
- if (outputName==NULL)
- elog(WARN, "Define: \"output\" unspecified");
-
- /* ----------------
- * now have TypeCreate do all the real work.
- * ----------------
- */
- TypeCreate(typeName, /* type name */
- InvalidOid, /* relation oid (n/a here) */
- internalLength, /* internal size */
- externalLength, /* external size */
- 'b', /* type-type (base type) */
- delimiter, /* array element delimiter */
- inputName, /* input procedure */
- outputName, /* output procedure */
- sendName, /* send procedure */
- receiveName, /* receive procedure */
- elemName, /* element type name */
- defaultValue, /* default type value */
- byValue, /* passed by value */
- alignment);
-
- /* ----------------
- * When we create a true type (as opposed to a complex type)
- * we need to have an shadow array entry for it in pg_type as well.
- * ----------------
- */
- shadow_type = makeArrayTypeName(typeName);
-
- TypeCreate(shadow_type, /* type name */
- InvalidOid, /* relation oid (n/a here) */
- -1, /* internal size */
- -1, /* external size */
- 'b', /* type-type (base type) */
- DEFAULT_TYPDELIM, /* array element delimiter */
- "array_in", /* input procedure */
- "array_out", /* output procedure */
- "array_out", /* send procedure */
- "array_in", /* receive procedure */
- typeName, /* element type name */
- defaultValue, /* default type value */
- false, /* never passed by value */
- alignment);
-
- pfree(shadow_type);
+ int16 internalLength = 0; /* int2 */
+ int16 externalLength = 0; /* int2 */
+ char *elemName = NULL;
+ char *inputName = NULL;
+ char *outputName = NULL;
+ char *sendName = NULL;
+ char *receiveName = NULL;
+ char *defaultValue = NULL; /* Datum */
+ bool byValue = false;
+ char delimiter = DEFAULT_TYPDELIM;
+ char *shadow_type;
+ List *pl;
+ char alignment = 'i'; /* default alignment */
+
+ /*
+ * Type names can only be 15 characters long, so that the shadow type
+ * can be created using the 16th character as necessary.
+ */
+ if (strlen(typeName) >= (NAMEDATALEN - 1))
+ {
+ elog(WARN, "DefineType: type names must be %d characters or less",
+ NAMEDATALEN - 1);
+ }
+
+ foreach(pl, parameters)
+ {
+ DefElem *defel = (DefElem *) lfirst(pl);
+
+ if (!strcasecmp(defel->defname, "internallength"))
+ {
+ internalLength = defGetTypeLength(defel);
+ }
+ else if (!strcasecmp(defel->defname, "externallength"))
+ {
+ externalLength = defGetTypeLength(defel);
+ }
+ else if (!strcasecmp(defel->defname, "input"))
+ {
+ inputName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "output"))
+ {
+ outputName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "send"))
+ {
+ sendName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "delimiter"))
+ {
+ char *p = defGetString(defel);
+
+ delimiter = p[0];
+ }
+ else if (!strcasecmp(defel->defname, "receive"))
+ {
+ receiveName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "element"))
+ {
+ elemName = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "default"))
+ {
+ defaultValue = defGetString(defel);
+ }
+ else if (!strcasecmp(defel->defname, "passedbyvalue"))
+ {
+ byValue = true;
+ }
+ else if (!strcasecmp(defel->defname, "alignment"))
+ {
+ char *a = defGetString(defel);
+
+ if (!strcasecmp(a, "double"))
+ {
+ alignment = 'd';
+ }
+ else if (!strcasecmp(a, "int"))
+ {
+ alignment = 'i';
+ }
+ else
+ {
+ elog(WARN, "DefineType: \"%s\" alignment not recognized",
+ a);
+ }
+ }
+ else
+ {
+ elog(NOTICE, "DefineType: attribute \"%s\" not recognized",
+ defel->defname);
+ }
+ }
+
+ /*
+ * make sure we have our required definitions
+ */
+ if (inputName == NULL)
+ elog(WARN, "Define: \"input\" unspecified");
+ if (outputName == NULL)
+ elog(WARN, "Define: \"output\" unspecified");
+
+ /* ----------------
+ * now have TypeCreate do all the real work.
+ * ----------------
+ */
+ TypeCreate(typeName, /* type name */
+ InvalidOid, /* relation oid (n/a here) */
+ internalLength, /* internal size */
+ externalLength, /* external size */
+ 'b', /* type-type (base type) */
+ delimiter, /* array element delimiter */
+ inputName, /* input procedure */
+ outputName, /* output procedure */
+ sendName, /* send procedure */
+ receiveName, /* receive procedure */
+ elemName, /* element type name */
+ defaultValue, /* default type value */
+ byValue, /* passed by value */
+ alignment);
+
+ /* ----------------
+ * When we create a true type (as opposed to a complex type)
+ * we need to have an shadow array entry for it in pg_type as well.
+ * ----------------
+ */
+ shadow_type = makeArrayTypeName(typeName);
+
+ TypeCreate(shadow_type, /* type name */
+ InvalidOid, /* relation oid (n/a here) */
+ -1, /* internal size */
+ -1, /* external size */
+ 'b', /* type-type (base type) */
+ DEFAULT_TYPDELIM,/* array element delimiter */
+ "array_in", /* input procedure */
+ "array_out", /* output procedure */
+ "array_out", /* send procedure */
+ "array_in", /* receive procedure */
+ typeName, /* element type name */
+ defaultValue, /* default type value */
+ false, /* never passed by value */
+ alignment);
+
+ pfree(shadow_type);
}
-static char *
-defGetString(DefElem *def)
+static char *
+defGetString(DefElem * def)
{
- if (nodeTag(def->arg)!=T_String)
- elog(WARN, "Define: \"%s\" = what?", def->defname);
- return (strVal(def->arg));
+ if (nodeTag(def->arg) != T_String)
+ elog(WARN, "Define: \"%s\" = what?", def->defname);
+ return (strVal(def->arg));
}
-static int
-defGetTypeLength(DefElem *def)
+static int
+defGetTypeLength(DefElem * def)
{
- if (nodeTag(def->arg)==T_Integer)
- return (intVal(def->arg));
- else if (nodeTag(def->arg)==T_String &&
- !strcasecmp(strVal(def->arg),"variable"))
- return -1; /* variable length */
-
- elog(WARN, "Define: \"%s\" = what?", def->defname);
- return -1;
+ if (nodeTag(def->arg) == T_Integer)
+ return (intVal(def->arg));
+ else if (nodeTag(def->arg) == T_String &&
+ !strcasecmp(strVal(def->arg), "variable"))
+ return -1; /* variable length */
+
+ elog(WARN, "Define: \"%s\" = what?", def->defname);
+ return -1;
}
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 7d1f34d0327..192076e3911 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -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;
-
- if (IsAbortedTransactionBlockState()) {
- char *tag = "*ABORT STATE*";
- EndCommand(tag, dest);
-
- elog(NOTICE, "(transaction aborted): %s",
- "queries ignored until END");
-
- return;
- }
+ char *s = NULL,
+ *s2;
+ Plan *plan;
+ ExplainState *es;
+ int len;
- /* plan the queries (XXX we've ignored rewrite!!) */
- plan = planner(query);
+ if (IsAbortedTransactionBlockState())
+ {
+ char *tag = "*ABORT STATE*";
- /* pg_plan could have failed */
- if (plan == NULL)
- return;
+ EndCommand(tag, dest);
+
+ elog(NOTICE, "(transaction aborted): %s",
+ "queries ignored until END");
+
+ return;
+ }
- es = (ExplainState*)malloc(sizeof(ExplainState));
- memset(es, 0, sizeof(ExplainState));
+ /* plan the queries (XXX we've ignored rewrite!!) */
+ plan = planner(query);
- es->printCost = true; /* default */
+ /* pg_plan could have failed */
+ if (plan == NULL)
+ return;
- if (verbose)
- es->printNodes = true;
+ es = (ExplainState *) malloc(sizeof(ExplainState));
+ memset(es, 0, sizeof(ExplainState));
- es->rtable = query->rtable;
+ es->printCost = true; /* default */
- if (es->printNodes)
- s = nodeToString(plan);
+ if (verbose)
+ es->printNodes = true;
- if (es->printCost) {
- s2 = Explain_PlanToString(plan, es);
- if (s == NULL)
- s = s2;
- else {
- strcat(s, "\n\n");
- strcat(s, s2);
+ 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);
+
+ /* 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) {
+ char *pname;
+ char buf[1000];
+ int i;
+
+ if (plan == NULL)
+ {
+ appendStringInfo(str, "\n");
+ return;
+ }
+
+ 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);
+ }
+ 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");
- return;
- }
-
- 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);
+
+ /* lefttree */
+ if (outerPlan(plan))
+ {
+ for (i = 0; i < indent; i++)
+ appendStringInfo(str, " ");
+ appendStringInfo(str, " -> ");
+ explain_outNode(str, outerPlan(plan), indent + 1, es);
}
- 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;
+
+ /* 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);
-
- return s;
+ StringInfo str;
+ char *s;
+
+ if (plan == NULL)
+ return "";
+ Assert(plan != NULL);
+ str = makeStringInfo();
+ explain_outNode(str, plan, 0, es);
+ s = str->data;
+ pfree(str);
+
+ return s;
}
diff --git a/src/backend/commands/purge.c b/src/backend/commands/purge.c
index 5c514fc8675..8000bbc7352 100644
--- a/src/backend/commands/purge.c
+++ b/src/backend/commands/purge.c
@@ -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: 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)) {
+ 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);
}
-
diff --git a/src/backend/commands/recipe.c b/src/backend/commands/recipe.c
index e6aa009bd33..bf05c293d13 100644
--- a/src/backend/commands/recipe.c
+++ b/src/backend/commands/recipe.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* recipe.c--
- * routines for handling execution of Tioga recipes
+ * routines for handling execution of Tioga recipes
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/Attic/recipe.c,v 1.6 1997/08/12 20:15:11 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/Attic/recipe.c,v 1.7 1997/09/07 04:40:53 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,7 +21,7 @@
#include <commands/recipe.h>
#include <libpq/libpq-be.h>
#include <utils/builtins.h>
-#include <utils/relcache.h> /* for RelationNameGetRelation*/
+#include <utils/relcache.h> /* for RelationNameGetRelation */
#include <parser/parse_query.h>
#include <rewrite/rewriteHandler.h>
#include <rewrite/rewriteManip.h>
@@ -35,9 +35,12 @@ extern CommandDest whereToSendOutput;
#ifndef TIOGA
-void beginRecipe(RecipeStmt *stmt) {
- elog(NOTICE,"You must compile with TIOGA defined in order to use recipes\n");
+void
+beginRecipe(RecipeStmt * stmt)
+{
+ elog(NOTICE, "You must compile with TIOGA defined in order to use recipes\n");
}
+
#else
#include <tioga/tgRecipe.h>
@@ -45,49 +48,59 @@ void beginRecipe(RecipeStmt *stmt) {
#define DEBUG_RECIPE 1
/* structure to keep track of the tee node plans */
-typedef struct _teePlanInfo {
- char* tpi_relName;
- Query* tpi_parsetree;
- Plan* tpi_plan;
-} TeePlanInfo;
-
-typedef struct _teeInfo {
- int num;
- TeePlanInfo *val;
-} TeeInfo;
-
-QueryTreeList *appendQlist(QueryTreeList *q1, QueryTreeList *q2);
-void OffsetVarAttno(Node* node, int varno, int offset);
-
-static void appendTeeQuery(TeeInfo *teeInfo,
- QueryTreeList *q,
- char* teeNodeName);
-
-static Plan* replaceTeeScans(Plan* plan,
- Query* parsetree,
- TeeInfo *teeInfo);
-static void replaceSeqScan(Plan* plan,
- Plan* parent,
- int rt_ind,
- Plan* tplan);
-
-static void tg_rewriteQuery(TgRecipe* r, TgNode *n,
- QueryTreeList *q,
- QueryTreeList *inputQlist);
-static Node *tg_replaceNumberedParam(Node* expression,
- int pnum,
- int rt_ind,
- char *teeRelName);
-static Node *tg_rewriteParamsInExpr(Node *expression,
- QueryTreeList *inputQlist);
-static QueryTreeList *tg_parseSubQuery(TgRecipe* r,
- TgNode* n,
- TeeInfo* teeInfo);
-static QueryTreeList* tg_parseTeeNode(TgRecipe *r,
- TgNode *n,
- int i,
- QueryTreeList *qList,
- TeeInfo* teeInfo);
+typedef struct _teePlanInfo
+{
+ char *tpi_relName;
+ Query *tpi_parsetree;
+ Plan *tpi_plan;
+} TeePlanInfo;
+
+typedef struct _teeInfo
+{
+ int num;
+ TeePlanInfo *val;
+} TeeInfo;
+
+QueryTreeList *appendQlist(QueryTreeList * q1, QueryTreeList * q2);
+void OffsetVarAttno(Node * node, int varno, int offset);
+
+static void
+appendTeeQuery(TeeInfo * teeInfo,
+ QueryTreeList * q,
+ char *teeNodeName);
+
+static Plan *
+replaceTeeScans(Plan * plan,
+ Query * parsetree,
+ TeeInfo * teeInfo);
+static void
+replaceSeqScan(Plan * plan,
+ Plan * parent,
+ int rt_ind,
+ Plan * tplan);
+
+static void
+tg_rewriteQuery(TgRecipe * r, TgNode * n,
+ QueryTreeList * q,
+ QueryTreeList * inputQlist);
+static Node *
+tg_replaceNumberedParam(Node * expression,
+ int pnum,
+ int rt_ind,
+ char *teeRelName);
+static Node *
+tg_rewriteParamsInExpr(Node * expression,
+ QueryTreeList * inputQlist);
+static QueryTreeList *
+tg_parseSubQuery(TgRecipe * r,
+ TgNode * n,
+ TeeInfo * teeInfo);
+static QueryTreeList *
+tg_parseTeeNode(TgRecipe * r,
+ TgNode * n,
+ int i,
+ QueryTreeList * qList,
+ TeeInfo * teeInfo);
/*
@@ -96,172 +109,192 @@ static QueryTreeList* tg_parseTeeNode(TgRecipe *r,
To parse a Tioga recipe, we start from an eye node and go backwards through
its input nodes. To rewrite a Tioga node, we do the following:
- 1) parse the node we're at in the standard way (calling parser() )
- 2) rewrite its input nodes recursively using Tioga rewrite
- 3) now, with the rewritten input parse trees and the original parse tree
- of the node, we rewrite the the node.
- To do the rewrite, we use the target lists, range tables, and
- qualifications of the input parse trees
+ 1) parse the node we're at in the standard way (calling parser() )
+ 2) rewrite its input nodes recursively using Tioga rewrite
+ 3) now, with the rewritten input parse trees and the original parse tree
+ of the node, we rewrite the the node.
+ To do the rewrite, we use the target lists, range tables, and
+ qualifications of the input parse trees
*/
/*
* beginRecipe:
- * this is the main function to recipe execution
- * this function is invoked for EXECUTE RECIPE ... statements
- *
- * takes in a RecipeStmt structure from the parser
+ * this is the main function to recipe execution
+ * this function is invoked for EXECUTE RECIPE ... statements
+ *
+ * takes in a RecipeStmt structure from the parser
* and returns a list of cursor names
*/
void
-beginRecipe(RecipeStmt* stmt)
+beginRecipe(RecipeStmt * stmt)
{
- TgRecipe* r;
- int i;
- QueryTreeList *qList;
- char portalName[1024];
-
- Plan *plan;
- TupleDesc attinfo;
- QueryDesc *queryDesc;
- Query *parsetree;
-
- int numTees;
- TeeInfo* teeInfo;
-
- /* retrieveRecipe() reads the recipe from the database
- and returns a TgRecipe* structure we can work with */
-
- r = retrieveRecipe(stmt->recipeName);
-
- if (r == NULL) return;
-
- /* find the number of tees in the recipe */
- numTees = r->tees->num;
-
- if (numTees > 0) {
- /* allocate a teePlan structure */
- teeInfo = (TeeInfo*)malloc(sizeof(TeeInfo));
- teeInfo->num = numTees;
- teeInfo->val = (TeePlanInfo*)malloc(numTees * sizeof(TeePlanInfo));
- for (i=0;i<numTees;i++) {
- teeInfo->val[i].tpi_relName = r->tees->val[i]->nodeName;
- teeInfo->val[i].tpi_parsetree = NULL;
- teeInfo->val[i].tpi_plan = NULL;
- }
- } else
- teeInfo = NULL;
-
- /*
- * for each viewer in the recipe, go backwards from each viewer input
- * and generate a plan. Attach the plan to cursors.
- **/
- for (i=0;i<r->eyes->num;i++) {
- TgNodePtr e;
-
- e = r->eyes->val[i];
- if (e->inNodes->num > 1) {
- elog(NOTICE,
- "beginRecipe: Currently eyes cannot have more than one input");
- }
- if (e->inNodes->num == 0) {
- /* no input to this eye, skip it */
- continue;
- }
+ TgRecipe *r;
+ int i;
+ QueryTreeList *qList;
+ char portalName[1024];
+
+ Plan *plan;
+ TupleDesc attinfo;
+ QueryDesc *queryDesc;
+ Query *parsetree;
+
+ int numTees;
+ TeeInfo *teeInfo;
+
+ /*
+ * retrieveRecipe() reads the recipe from the database and returns a
+ * TgRecipe* structure we can work with
+ */
+
+ r = retrieveRecipe(stmt->recipeName);
+
+ if (r == NULL)
+ return;
+
+ /* find the number of tees in the recipe */
+ numTees = r->tees->num;
+
+ if (numTees > 0)
+ {
+ /* allocate a teePlan structure */
+ teeInfo = (TeeInfo *) malloc(sizeof(TeeInfo));
+ teeInfo->num = numTees;
+ teeInfo->val = (TeePlanInfo *) malloc(numTees * sizeof(TeePlanInfo));
+ for (i = 0; i < numTees; i++)
+ {
+ teeInfo->val[i].tpi_relName = r->tees->val[i]->nodeName;
+ teeInfo->val[i].tpi_parsetree = NULL;
+ teeInfo->val[i].tpi_plan = NULL;
+ }
+ }
+ else
+ teeInfo = NULL;
+
+ /*
+ * for each viewer in the recipe, go backwards from each viewer input
+ * and generate a plan. Attach the plan to cursors.
+ */
+ for (i = 0; i < r->eyes->num; i++)
+ {
+ TgNodePtr e;
+
+ e = r->eyes->val[i];
+ if (e->inNodes->num > 1)
+ {
+ elog(NOTICE,
+ "beginRecipe: Currently eyes cannot have more than one input");
+ }
+ if (e->inNodes->num == 0)
+ {
+ /* no input to this eye, skip it */
+ continue;
+ }
#ifdef DEBUG_RECIPE
- elog(NOTICE,"beginRecipe: eyes[%d] = %s\n", i, e->nodeName);
-#endif /* DEBUG_RECIPE */
-
- qList = tg_parseSubQuery(r,e->inNodes->val[0], teeInfo);
-
- if (qList == NULL) {
- /* eye is directly connected to a tee node */
- /* XXX TODO: handle this case */
- }
-
- /* now, plan the queries */
- /* should really do everything pg_plan() does, but for now,
- we skip the rule rewrite and time qual stuff */
-
- /* ----------------------------------------------------------
- * 1) plan the main query, everything from an eye node back to
- a Tee
- * ---------------------------------------------------------- */
- parsetree = qList->qtrees[0];
-
- /* before we plan, we want to see all the changes
- we did, during the rewrite phase, such as
- creating the tee tables,
- setheapoverride() allows us to see the changes */
- setheapoverride(true);
- plan = planner(parsetree);
-
- /* ----------------------------------------------------------
- * 2) plan the tee queries, (subgraphs rooted from a Tee)
- by the time the eye is processed, all tees that contribute
- to that eye will have been included in the teeInfo list
- * ---------------------------------------------------------- */
- if (teeInfo) {
- int t;
- Plan* tplan;
- Tee* newplan;
-
- for (t=0; t<teeInfo->num;t++) {
- if (teeInfo->val[t].tpi_plan == NULL) {
- /* plan it in the usual fashion */
- tplan = planner(teeInfo->val[t].tpi_parsetree);
-
- /* now add a tee node to the root of the plan */
-elog(NOTICE, "adding tee plan node to the root of the %s\n",
- teeInfo->val[t].tpi_relName);
- newplan = (Tee*)makeNode(Tee);
- newplan->plan.targetlist = tplan->targetlist;
- newplan->plan.qual = NULL; /* tplan->qual; */
- newplan->plan.lefttree = tplan;
- newplan->plan.righttree = NULL;
- newplan->leftParent = NULL;
- newplan->rightParent = NULL;
- /* the range table of the tee is the range table
- of the tplan */
- newplan->rtentries = teeInfo->val[t].tpi_parsetree->rtable;
- strcpy(newplan->teeTableName,
- teeInfo->val[t].tpi_relName);
- teeInfo->val[t].tpi_plan = (Plan*)newplan;
- }
- }
-
- /* ----------------------------------------------------------
- * 3) replace the tee table scans in the main plan with
- actual tee plannodes
- * ---------------------------------------------------------- */
-
- plan = replaceTeeScans(plan, parsetree, teeInfo);
-
- } /* if (teeInfo) */
-
- setheapoverride(false);
-
- /* define a portal for this viewer input */
- /* for now, eyes can only have one input */
- sprintf(portalName, "%s%d",e->nodeName,0);
-
- queryDesc = CreateQueryDesc(parsetree,
- plan,
- whereToSendOutput);
- /* ----------------
- * call ExecStart to prepare the plan for execution
- * ----------------
- */
- attinfo = ExecutorStart(queryDesc,NULL);
-
- ProcessPortal(portalName,
- parsetree,
- plan,
- attinfo,
- whereToSendOutput);
-elog(NOTICE, "beginRecipe: cursor named %s is now available", portalName);
- }
+ elog(NOTICE, "beginRecipe: eyes[%d] = %s\n", i, e->nodeName);
+#endif /* DEBUG_RECIPE */
+
+ qList = tg_parseSubQuery(r, e->inNodes->val[0], teeInfo);
+
+ if (qList == NULL)
+ {
+ /* eye is directly connected to a tee node */
+ /* XXX TODO: handle this case */
+ }
+
+ /* now, plan the queries */
+
+ /*
+ * should really do everything pg_plan() does, but for now, we
+ * skip the rule rewrite and time qual stuff
+ */
+
+ /* ----------------------------------------------------------
+ * 1) plan the main query, everything from an eye node back to
+ a Tee
+ * ---------------------------------------------------------- */
+ parsetree = qList->qtrees[0];
+
+ /*
+ * before we plan, we want to see all the changes we did, during
+ * the rewrite phase, such as creating the tee tables,
+ * setheapoverride() allows us to see the changes
+ */
+ setheapoverride(true);
+ plan = planner(parsetree);
+
+ /* ----------------------------------------------------------
+ * 2) plan the tee queries, (subgraphs rooted from a Tee)
+ by the time the eye is processed, all tees that contribute
+ to that eye will have been included in the teeInfo list
+ * ---------------------------------------------------------- */
+ if (teeInfo)
+ {
+ int t;
+ Plan *tplan;
+ Tee *newplan;
+
+ for (t = 0; t < teeInfo->num; t++)
+ {
+ if (teeInfo->val[t].tpi_plan == NULL)
+ {
+ /* plan it in the usual fashion */
+ tplan = planner(teeInfo->val[t].tpi_parsetree);
+
+ /* now add a tee node to the root of the plan */
+ elog(NOTICE, "adding tee plan node to the root of the %s\n",
+ teeInfo->val[t].tpi_relName);
+ newplan = (Tee *) makeNode(Tee);
+ newplan->plan.targetlist = tplan->targetlist;
+ newplan->plan.qual = NULL; /* tplan->qual; */
+ newplan->plan.lefttree = tplan;
+ newplan->plan.righttree = NULL;
+ newplan->leftParent = NULL;
+ newplan->rightParent = NULL;
+
+ /*
+ * the range table of the tee is the range table of
+ * the tplan
+ */
+ newplan->rtentries = teeInfo->val[t].tpi_parsetree->rtable;
+ strcpy(newplan->teeTableName,
+ teeInfo->val[t].tpi_relName);
+ teeInfo->val[t].tpi_plan = (Plan *) newplan;
+ }
+ }
+
+ /* ----------------------------------------------------------
+ * 3) replace the tee table scans in the main plan with
+ actual tee plannodes
+ * ---------------------------------------------------------- */
+
+ plan = replaceTeeScans(plan, parsetree, teeInfo);
+
+ } /* if (teeInfo) */
+
+ setheapoverride(false);
+
+ /* define a portal for this viewer input */
+ /* for now, eyes can only have one input */
+ sprintf(portalName, "%s%d", e->nodeName, 0);
+
+ queryDesc = CreateQueryDesc(parsetree,
+ plan,
+ whereToSendOutput);
+ /* ----------------
+ * call ExecStart to prepare the plan for execution
+ * ----------------
+ */
+ attinfo = ExecutorStart(queryDesc, NULL);
+
+ ProcessPortal(portalName,
+ parsetree,
+ plan,
+ attinfo,
+ whereToSendOutput);
+ elog(NOTICE, "beginRecipe: cursor named %s is now available", portalName);
+ }
}
@@ -269,109 +302,122 @@ elog(NOTICE, "beginRecipe: cursor named %s is now available", portalName);
/*
* tg_rewriteQuery -
- * r - the recipe being rewritten
- * n - the node that we're current at
- * q - a QueryTree List containing the parse tree of the node
- * inputQlist - the parsetrees of its input nodes,
- * the size of inputQlist must be the same as the
- * number of input nodes. Some elements in the inpuQlist
- * may be null if the inputs to those nodes are unconnected
+ * r - the recipe being rewritten
+ * n - the node that we're current at
+ * q - a QueryTree List containing the parse tree of the node
+ * inputQlist - the parsetrees of its input nodes,
+ * the size of inputQlist must be the same as the
+ * number of input nodes. Some elements in the inpuQlist
+ * may be null if the inputs to those nodes are unconnected
*
- * this is the main routine for rewriting the recipe queries
- * the original query tree 'q' is modified
+ * this is the main routine for rewriting the recipe queries
+ * the original query tree 'q' is modified
*/
-static void
-tg_rewriteQuery(TgRecipe* r,
- TgNode *n,
- QueryTreeList *q,
- QueryTreeList *inputQlist)
+static void
+tg_rewriteQuery(TgRecipe * r,
+ TgNode * n,
+ QueryTreeList * q,
+ QueryTreeList * inputQlist)
{
- Query* orig;
- Query* inputQ;
- int i;
- List *rtable;
- List *input_rtable;
- int rt_length;
-
- /* orig is the original parse tree of the node */
- orig = q->qtrees[0];
-
-
- /*-------------------------------------------------------------------
- step 1:
-
- form a combined range table from all the range tables in the original
- query as well as the input nodes
-
- form a combined qualification from the qual in the original plus
- the quals of the input nodes
- -------------------------------------------------------------------
- */
-
- /* start with the original range table */
- rtable = orig->rtable;
- rt_length = length(rtable);
-
- for (i=0;i<n->inNodes->num;i++) {
- if (n->inNodes->val[i] != NULL &&
- n->inNodes->val[i]->nodeType != TG_TEE_NODE) {
- inputQ = inputQlist->qtrees[i];
- input_rtable = inputQ->rtable;
-
- /* need to offset the var nodes in the qual and targetlist
- because they are indexed off the original rtable */
- OffsetVarNodes((Node*)inputQ->qual, rt_length);
- OffsetVarNodes((Node*)inputQ->targetList, rt_length);
-
- /* append the range tables from the children nodes */
- rtable = nconc (rtable, input_rtable);
-
- /* append the qualifications of the child node into the
- original qual list */
- AddQual(orig, inputQ->qual);
+ Query *orig;
+ Query *inputQ;
+ int i;
+ List *rtable;
+ List *input_rtable;
+ int rt_length;
+
+ /* orig is the original parse tree of the node */
+ orig = q->qtrees[0];
+
+
+ /*-------------------------------------------------------------------
+ step 1:
+
+ form a combined range table from all the range tables in the original
+ query as well as the input nodes
+
+ form a combined qualification from the qual in the original plus
+ the quals of the input nodes
+ -------------------------------------------------------------------
+ */
+
+ /* start with the original range table */
+ rtable = orig->rtable;
+ rt_length = length(rtable);
+
+ for (i = 0; i < n->inNodes->num; i++)
+ {
+ if (n->inNodes->val[i] != NULL &&
+ n->inNodes->val[i]->nodeType != TG_TEE_NODE)
+ {
+ inputQ = inputQlist->qtrees[i];
+ input_rtable = inputQ->rtable;
+
+ /*
+ * need to offset the var nodes in the qual and targetlist
+ * because they are indexed off the original rtable
+ */
+ OffsetVarNodes((Node *) inputQ->qual, rt_length);
+ OffsetVarNodes((Node *) inputQ->targetList, rt_length);
+
+ /* append the range tables from the children nodes */
+ rtable = nconc(rtable, input_rtable);
+
+ /*
+ * append the qualifications of the child node into the
+ * original qual list
+ */
+ AddQual(orig, inputQ->qual);
+ }
}
- }
- orig->rtable = rtable;
-
- /* step 2:
- rewrite the target list of the original parse tree
- if there are any references to params, replace them with
- the appropriate target list entry of the children node
- */
- if (orig->targetList != NIL) {
- List *tl;
- TargetEntry *tle;
-
- foreach (tl, orig->targetList) {
- tle = lfirst(tl);
- if (tle->resdom != NULL) {
- tle->expr = tg_rewriteParamsInExpr(tle->expr, inputQlist);
- }
- }
- }
-
- /* step 3:
- rewrite the qual of the original parse tree
- if there are any references to params, replace them with
- the appropriate target list entry of the children node
- */
- if (orig->qual) {
- if (nodeTag(orig->qual) == T_List) {
- elog(WARN, "tg_rewriteQuery: Whoa! why is my qual a List???");
+ orig->rtable = rtable;
+
+ /*
+ * step 2: rewrite the target list of the original parse tree if there
+ * are any references to params, replace them with the appropriate
+ * target list entry of the children node
+ */
+ if (orig->targetList != NIL)
+ {
+ List *tl;
+ TargetEntry *tle;
+
+ foreach(tl, orig->targetList)
+ {
+ tle = lfirst(tl);
+ if (tle->resdom != NULL)
+ {
+ tle->expr = tg_rewriteParamsInExpr(tle->expr, inputQlist);
+ }
+ }
+ }
+
+ /*
+ * step 3: rewrite the qual of the original parse tree if there are
+ * any references to params, replace them with the appropriate target
+ * list entry of the children node
+ */
+ if (orig->qual)
+ {
+ if (nodeTag(orig->qual) == T_List)
+ {
+ elog(WARN, "tg_rewriteQuery: Whoa! why is my qual a List???");
+ }
+ orig->qual = tg_rewriteParamsInExpr(orig->qual, inputQlist);
}
- orig->qual = tg_rewriteParamsInExpr(orig->qual, inputQlist);
- }
- /* at this point, we're done with the rewrite, the querytreelist q
- has been modified */
+ /*
+ * at this point, we're done with the rewrite, the querytreelist q has
+ * been modified
+ */
}
/* tg_replaceNumberedParam:
- this procedure replaces the specified numbered param with a
+ this procedure replaces the specified numbered param with a
reference to a range table
this procedure recursively calls itself
@@ -379,104 +425,137 @@ tg_rewriteQuery(TgRecipe* r,
it returns a (possibly modified) Node*.
*/
-static Node*
-tg_replaceNumberedParam(Node *expression,
- int pnum, /* the number of the parameter */
- int rt_ind, /* the range table index */
- char *teeRelName) /* the relname of the tee table */
+static Node *
+tg_replaceNumberedParam(Node * expression,
+ int pnum, /* the number of the parameter */
+ int rt_ind, /* the range table index */
+ char *teeRelName) /* the relname of the tee
+ * table */
{
- TargetEntry *param_tle;
- Param* p;
- Var *newVar,*oldVar;
-
- if (expression == NULL) return NULL;
-
- switch (nodeTag(expression)) {
- case T_Param:
- {
- /* the node is a parameter,
- substitute the entry from the target list of the child that
- corresponds to the parameter number*/
- p = (Param*)expression;
-
- /* we only deal with the case of numbered parameters */
- if (p->paramkind == PARAM_NUM && p->paramid == pnum) {
-
- if (p->param_tlist) {
- /* we have a parameter with an attribute like $N.foo
- so replace it with a new var node */
-
- /* param tlist can only have one entry in them! */
- param_tle = (TargetEntry*)(lfirst(p->param_tlist));
- oldVar = (Var*)param_tle->expr;
- oldVar->varno = rt_ind;
- oldVar->varnoold = rt_ind;
- return (Node*)oldVar;
- } else {
- /* we have $N without the .foo */
- bool defined;
- bool isRel;
- /* TODO here, we need to check to see whether the type of the
- tee is a complex type (relation) or a simple type */
- /* if it is a simple type, then we need to get the "result"
- attribute from the tee relation */
-
- isRel = (typeid_get_relid(p->paramtype) != 0);
- if (isRel) {
- newVar = makeVar(rt_ind,
- 0, /* the whole tuple */
- TypeGet(teeRelName,&defined),
- rt_ind,
- 0);
- return (Node*)newVar;
- } else
- newVar = makeVar(rt_ind,
- 1, /* just the first field, which is 'result' */
- TypeGet(teeRelName,&defined),
- rt_ind,
- 0);
- return (Node*)newVar;
-
- }
- }
- else {
- elog(NOTICE, "tg_replaceNumberedParam: unexpected paramkind value of %d", p->paramkind);
- }
- }
- break;
- case T_Expr:
- {
- /* the node is an expression, we need to recursively
- call ourselves until we find parameter nodes */
- List *l;
- Expr *expr = (Expr*)expression;
- List *newArgs;
-
- /* we have to make a new args lists because Params
- can be replaced by Var nodes in tg_replaceNumberedParam()*/
- newArgs = NIL;
-
- /* we only care about argument to expressions,
- it doesn't matter when the opType is */
- /* recursively rewrite the arguments of this expression */
- foreach (l, expr->args) {
- newArgs = lappend(newArgs,
- tg_replaceNumberedParam(lfirst(l),
- pnum,
- rt_ind,
- teeRelName));
- }
- /* change the arguments of the expression */
- expr->args = newArgs;
- }
- break;
- default:
- {
- /* ignore other expr types */
- }
- }
-
- return expression;
+ TargetEntry *param_tle;
+ Param *p;
+ Var *newVar,
+ *oldVar;
+
+ if (expression == NULL)
+ return NULL;
+
+ switch (nodeTag(expression))
+ {
+ case T_Param:
+ {
+
+ /*
+ * the node is a parameter, substitute the entry from the
+ * target list of the child that corresponds to the parameter
+ * number
+ */
+ p = (Param *) expression;
+
+ /* we only deal with the case of numbered parameters */
+ if (p->paramkind == PARAM_NUM && p->paramid == pnum)
+ {
+
+ if (p->param_tlist)
+ {
+
+ /*
+ * we have a parameter with an attribute like $N.foo
+ * so replace it with a new var node
+ */
+
+ /* param tlist can only have one entry in them! */
+ param_tle = (TargetEntry *) (lfirst(p->param_tlist));
+ oldVar = (Var *) param_tle->expr;
+ oldVar->varno = rt_ind;
+ oldVar->varnoold = rt_ind;
+ return (Node *) oldVar;
+ }
+ else
+ {
+ /* we have $N without the .foo */
+ bool defined;
+ bool isRel;
+
+ /*
+ * TODO here, we need to check to see whether the type
+ * of the tee is a complex type (relation) or a simple
+ * type
+ */
+
+ /*
+ * if it is a simple type, then we need to get the
+ * "result" attribute from the tee relation
+ */
+
+ isRel = (typeid_get_relid(p->paramtype) != 0);
+ if (isRel)
+ {
+ newVar = makeVar(rt_ind,
+ 0, /* the whole tuple */
+ TypeGet(teeRelName, &defined),
+ rt_ind,
+ 0);
+ return (Node *) newVar;
+ }
+ else
+ newVar = makeVar(rt_ind,
+ 1, /* just the first field,
+ * which is 'result' */
+ TypeGet(teeRelName, &defined),
+ rt_ind,
+ 0);
+ return (Node *) newVar;
+
+ }
+ }
+ else
+ {
+ elog(NOTICE, "tg_replaceNumberedParam: unexpected paramkind value of %d", p->paramkind);
+ }
+ }
+ break;
+ case T_Expr:
+ {
+
+ /*
+ * the node is an expression, we need to recursively call
+ * ourselves until we find parameter nodes
+ */
+ List *l;
+ Expr *expr = (Expr *) expression;
+ List *newArgs;
+
+ /*
+ * we have to make a new args lists because Params can be
+ * replaced by Var nodes in tg_replaceNumberedParam()
+ */
+ newArgs = NIL;
+
+ /*
+ * we only care about argument to expressions, it doesn't
+ * matter when the opType is
+ */
+ /* recursively rewrite the arguments of this expression */
+ foreach(l, expr->args)
+ {
+ newArgs = lappend(newArgs,
+ tg_replaceNumberedParam(lfirst(l),
+ pnum,
+ rt_ind,
+ teeRelName));
+ }
+ /* change the arguments of the expression */
+ expr->args = newArgs;
+ }
+ break;
+ default:
+ {
+ /* ignore other expr types */
+ }
+ }
+
+ return expression;
}
@@ -485,694 +564,817 @@ tg_replaceNumberedParam(Node *expression,
/* tg_rewriteParamsInExpr:
- rewrite the params in expressions by using the targetlist entries
- from the input parsetrees
+ rewrite the params in expressions by using the targetlist entries
+ from the input parsetrees
this procedure recursively calls itself
it returns a (possibly modified) Node*.
*/
-static Node*
-tg_rewriteParamsInExpr(Node *expression, QueryTreeList *inputQlist)
+static Node *
+tg_rewriteParamsInExpr(Node * expression, QueryTreeList * inputQlist)
{
- List *tl;
- TargetEntry *param_tle, *tle;
- Param* p;
- int childno;
- char *resname;
-
- if (expression == NULL) return NULL;
-
- switch (nodeTag(expression)) {
- case T_Param:
- {
- /* the node is a parameter,
- substitute the entry from the target list of the child that
- corresponds to the parameter number*/
- p = (Param*)expression;
-
- /* we only deal with the case of numbered parameters */
- if (p->paramkind == PARAM_NUM) {
- /* paramid's start from 1*/
- childno = p->paramid - 1;
-
- if (p->param_tlist) {
- /* we have a parameter with an attribute like $N.foo
- so match the resname "foo" against the target list
- of the (N-1)th inputQlist */
-
- /* param tlist can only have one entry in them! */
- param_tle = (TargetEntry*)(lfirst(p->param_tlist));
- resname = param_tle->resdom->resname;
-
- if (inputQlist->qtrees[childno]) {
- foreach (tl, inputQlist->qtrees[childno]->targetList) {
- tle = lfirst(tl);
- if (strcmp(resname, tle->resdom->resname) == 0) {
- return tle->expr;
- }
- }
- }
- else {
- elog(WARN,"tg_rewriteParamsInExpr:can't substitute for parameter %d when that input is unconnected", p->paramid);
- }
-
- } else {
- /* we have $N without the .foo */
- /* use the first resdom in the targetlist of the */
- /* appropriate child query */
- tl = inputQlist->qtrees[childno]->targetList;
- tle = lfirst(tl);
- return tle->expr;
- }
- }
- else {
- elog(NOTICE, "tg_rewriteParamsInExpr: unexpected paramkind value of %d", p->paramkind);
- }
- }
- break;
- case T_Expr:
- {
- /* the node is an expression, we need to recursively
- call ourselves until we find parameter nodes */
- List *l;
- Expr *expr = (Expr*)expression;
- List *newArgs;
-
- /* we have to make a new args lists because Params
- can be replaced by Var nodes in tg_rewriteParamsInExpr()*/
- newArgs = NIL;
-
- /* we only care about argument to expressions,
- it doesn't matter when the opType is */
- /* recursively rewrite the arguments of this expression */
- foreach (l, expr->args) {
- newArgs = lappend(newArgs,
- tg_rewriteParamsInExpr(lfirst(l), inputQlist));
- }
- /* change the arguments of the expression */
- expr->args = newArgs;
- }
- break;
- default:
- {
- /* ignore other expr types */
- }
- }
-
- return expression;
+ List *tl;
+ TargetEntry *param_tle,
+ *tle;
+ Param *p;
+ int childno;
+ char *resname;
+
+ if (expression == NULL)
+ return NULL;
+
+ switch (nodeTag(expression))
+ {
+ case T_Param:
+ {
+
+ /*
+ * the node is a parameter, substitute the entry from the
+ * target list of the child that corresponds to the parameter
+ * number
+ */
+ p = (Param *) expression;
+
+ /* we only deal with the case of numbered parameters */
+ if (p->paramkind == PARAM_NUM)
+ {
+ /* paramid's start from 1 */
+ childno = p->paramid - 1;
+
+ if (p->param_tlist)
+ {
+
+ /*
+ * we have a parameter with an attribute like $N.foo
+ * so match the resname "foo" against the target list
+ * of the (N-1)th inputQlist
+ */
+
+ /* param tlist can only have one entry in them! */
+ param_tle = (TargetEntry *) (lfirst(p->param_tlist));
+ resname = param_tle->resdom->resname;
+
+ if (inputQlist->qtrees[childno])
+ {
+ foreach(tl, inputQlist->qtrees[childno]->targetList)
+ {
+ tle = lfirst(tl);
+ if (strcmp(resname, tle->resdom->resname) == 0)
+ {
+ return tle->expr;
+ }
+ }
+ }
+ else
+ {
+ elog(WARN, "tg_rewriteParamsInExpr:can't substitute for parameter %d when that input is unconnected", p->paramid);
+ }
+
+ }
+ else
+ {
+ /* we have $N without the .foo */
+ /* use the first resdom in the targetlist of the */
+ /* appropriate child query */
+ tl = inputQlist->qtrees[childno]->targetList;
+ tle = lfirst(tl);
+ return tle->expr;
+ }
+ }
+ else
+ {
+ elog(NOTICE, "tg_rewriteParamsInExpr: unexpected paramkind value of %d", p->paramkind);
+ }
+ }
+ break;
+ case T_Expr:
+ {
+
+ /*
+ * the node is an expression, we need to recursively call
+ * ourselves until we find parameter nodes
+ */
+ List *l;
+ Expr *expr = (Expr *) expression;
+ List *newArgs;
+
+ /*
+ * we have to make a new args lists because Params can be
+ * replaced by Var nodes in tg_rewriteParamsInExpr()
+ */
+ newArgs = NIL;
+
+ /*
+ * we only care about argument to expressions, it doesn't
+ * matter when the opType is
+ */
+ /* recursively rewrite the arguments of this expression */
+ foreach(l, expr->args)
+ {
+ newArgs = lappend(newArgs,
+ tg_rewriteParamsInExpr(lfirst(l), inputQlist));
+ }
+ /* change the arguments of the expression */
+ expr->args = newArgs;
+ }
+ break;
+ default:
+ {
+ /* ignore other expr types */
+ }
+ }
+
+ return expression;
}
/*
getParamTypes:
- given an element, finds its parameter types.
- the typev array argument is set to the parameter types.
- the parameterCount is returned
-
- this code is very similar to ProcedureDefine() in pg_proc.c
+ given an element, finds its parameter types.
+ the typev array argument is set to the parameter types.
+ the parameterCount is returned
+
+ this code is very similar to ProcedureDefine() in pg_proc.c
*/
static int
-getParamTypes (TgElement *elem, Oid typev[])
+getParamTypes(TgElement * elem, Oid typev[])
{
- /* this code is similar to ProcedureDefine() */
- int16 parameterCount;
- bool defined;
- Oid toid;
- char *t;
- int i,j;
-
- parameterCount = 0;
- for (i=0;i<8;i++) {
- typev[i] = 0;
- }
- for (j=0;j<elem->inTypes->num;j++) {
- if (parameterCount == 8) {
- elog(WARN,
- "getParamTypes: Ingredients cannot take > 8 arguments");
+ /* this code is similar to ProcedureDefine() */
+ int16 parameterCount;
+ bool defined;
+ Oid toid;
+ char *t;
+ int i,
+ j;
+
+ parameterCount = 0;
+ for (i = 0; i < 8; i++)
+ {
+ typev[i] = 0;
}
- t = elem->inTypes->val[j];
- if (strcmp(t,"opaque") == 0) {
- elog(WARN,
- "getParamTypes: Ingredient functions cannot take type 'opaque'");
- } else {
- toid = TypeGet(elem->inTypes->val[j], &defined);
- if (!OidIsValid(toid)) {
- elog(WARN, "getParamTypes: arg type '%s' is not defined",t);
- }
- if (!defined) {
- elog(NOTICE, "getParamTypes: arg type '%s' is only a shell",t);
- }
+ for (j = 0; j < elem->inTypes->num; j++)
+ {
+ if (parameterCount == 8)
+ {
+ elog(WARN,
+ "getParamTypes: Ingredients cannot take > 8 arguments");
+ }
+ t = elem->inTypes->val[j];
+ if (strcmp(t, "opaque") == 0)
+ {
+ elog(WARN,
+ "getParamTypes: Ingredient functions cannot take type 'opaque'");
+ }
+ else
+ {
+ toid = TypeGet(elem->inTypes->val[j], &defined);
+ if (!OidIsValid(toid))
+ {
+ elog(WARN, "getParamTypes: arg type '%s' is not defined", t);
+ }
+ if (!defined)
+ {
+ elog(NOTICE, "getParamTypes: arg type '%s' is only a shell", t);
+ }
+ }
+ typev[parameterCount++] = toid;
}
- typev[parameterCount++] = toid;
- }
- return parameterCount;
+ return parameterCount;
}
/*
* tg_parseTeeNode
- *
- * handles the parsing of the tee node
- *
+ *
+ * handles the parsing of the tee node
+ *
*
*/
-static QueryTreeList*
-tg_parseTeeNode(TgRecipe *r,
- TgNode *n, /* the tee node */
- int i, /* which input this node is to its parent */
- QueryTreeList *qList,
- TeeInfo* teeInfo)
+static QueryTreeList *
+tg_parseTeeNode(TgRecipe * r,
+ TgNode * n, /* the tee node */
+ int i, /* which input this node is to its parent */
+ QueryTreeList * qList,
+ TeeInfo * teeInfo)
{
- QueryTreeList *q;
- char* tt;
- int rt_ind;
- Query* orig;
-
- /* the input Node is a tee node, so we need to do the following:
- * we need to parse the child of the tee node,
- we add that to our query tree list
- * we need the name of the tee node table
- the tee node table is the table into which the tee node
- may materialize results. Call it TT
- * we add a range table to our existing query with TT in it
- * we need to replace the parameter $i with TT
- (otherwise the optimizer won't know to use the table
- on expression containining $i)
- After that rewrite, the optimizer will generate
- sequential scans of TT
-
- Later, in the glue phase, we replace all instances of TT
- sequential scans with the actual Tee node
- */
- q = tg_parseSubQuery(r,n, teeInfo);
-
- /* tt is the name of the tee node table */
- tt = n->nodeName;
-
- if (q)
- appendTeeQuery(teeInfo,q,tt);
-
- orig = qList->qtrees[0];
- rt_ind = RangeTablePosn(orig->rtable,tt);
- /* check to see that this table is not part of
- the range table already. This usually only
- happens if multiple inputs are connected to the
- same Tee. */
- if (rt_ind == 0) {
- orig->rtable = lappend(orig->rtable,
- addRangeTableEntry(NULL,
- tt,
- tt,
- FALSE,
- FALSE,
- NULL));
- rt_ind = length(orig->rtable);
- }
-
- orig->qual = tg_replaceNumberedParam(orig->qual,
- i+1, /* params start at 1*/
- rt_ind,
- tt);
- return qList;
+ QueryTreeList *q;
+ char *tt;
+ int rt_ind;
+ Query *orig;
+
+ /*
+ * the input Node is a tee node, so we need to do the following: we
+ * need to parse the child of the tee node, we add that to our query
+ * tree list we need the name of the tee node table the tee node table
+ * is the table into which the tee node may materialize results. Call
+ * it TT we add a range table to our existing query with TT in it we
+ * need to replace the parameter $i with TT (otherwise the optimizer
+ * won't know to use the table on expression containining $i) After
+ * that rewrite, the optimizer will generate sequential scans of TT
+ *
+ * Later, in the glue phase, we replace all instances of TT sequential
+ * scans with the actual Tee node
+ */
+ q = tg_parseSubQuery(r, n, teeInfo);
+
+ /* tt is the name of the tee node table */
+ tt = n->nodeName;
+
+ if (q)
+ appendTeeQuery(teeInfo, q, tt);
+
+ orig = qList->qtrees[0];
+ rt_ind = RangeTablePosn(orig->rtable, tt);
+
+ /*
+ * check to see that this table is not part of the range table
+ * already. This usually only happens if multiple inputs are
+ * connected to the same Tee.
+ */
+ if (rt_ind == 0)
+ {
+ orig->rtable = lappend(orig->rtable,
+ addRangeTableEntry(NULL,
+ tt,
+ tt,
+ FALSE,
+ FALSE,
+ NULL));
+ rt_ind = length(orig->rtable);
+ }
+
+ orig->qual = tg_replaceNumberedParam(orig->qual,
+ i + 1, /* params start at 1 */
+ rt_ind,
+ tt);
+ return qList;
}
/*
* tg_parseSubQuery:
- * go backwards from a node and parse the query
+ * go backwards from a node and parse the query
*
- * the result parse tree is passed back
- *
- * could return NULL if trying to parse a teeNode
+ * the result parse tree is passed back
+ *
+ * could return NULL if trying to parse a teeNode
* that's already been processed by another parent
- *
+ *
*/
-static QueryTreeList*
-tg_parseSubQuery(TgRecipe* r, TgNode* n, TeeInfo* teeInfo)
+static QueryTreeList *
+tg_parseSubQuery(TgRecipe * r, TgNode * n, TeeInfo * teeInfo)
{
- TgElement *elem;
- char* funcName;
- Oid typev[8]; /* eight arguments maximum */
- int i;
- int parameterCount;
-
- QueryTreeList *qList; /* the parse tree of the nodeElement */
- QueryTreeList *inputQlist; /* the list of parse trees for the
- inputs to this node */
- QueryTreeList *q;
- Oid relid;
- TgNode* child;
- Relation rel;
- unsigned int len;
- TupleDesc tupdesc;
-
- qList = NULL;
-
- if (n->nodeType == TG_INGRED_NODE) {
- /* parse each ingredient node in turn */
-
- elem = n->nodeElem;
- switch (elem->srcLang) {
- case TG_SQL:
- {
- /* for SQL ingredients, the SQL query is contained in the
- 'src' field */
+ TgElement *elem;
+ char *funcName;
+ Oid typev[8]; /* eight arguments maximum */
+ int i;
+ int parameterCount;
+
+ QueryTreeList *qList; /* the parse tree of the nodeElement */
+ QueryTreeList *inputQlist; /* the list of parse trees for the inputs
+ * to this node */
+ QueryTreeList *q;
+ Oid relid;
+ TgNode *child;
+ Relation rel;
+ unsigned int len;
+ TupleDesc tupdesc;
+
+ qList = NULL;
+
+ if (n->nodeType == TG_INGRED_NODE)
+ {
+ /* parse each ingredient node in turn */
+
+ elem = n->nodeElem;
+ switch (elem->srcLang)
+ {
+ case TG_SQL:
+ {
+
+ /*
+ * for SQL ingredients, the SQL query is contained in the
+ * 'src' field
+ */
#ifdef DEBUG_RECIPE
-elog(NOTICE,"calling parser with %s",elem->src);
-#endif /* DEBUG_RECIPE */
+ elog(NOTICE, "calling parser with %s", elem->src);
+#endif /* DEBUG_RECIPE */
- parameterCount = getParamTypes(elem,typev);
+ parameterCount = getParamTypes(elem, typev);
- qList = parser(elem->src,typev,parameterCount);
+ qList = parser(elem->src, typev, parameterCount);
- if (qList->len > 1) {
- elog(NOTICE,
- "tg_parseSubQuery: parser produced > 1 query tree");
- }
- }
- break;
- case TG_C:
- {
- /* C ingredients are registered functions in postgres */
- /* we create a new query string by using the function name
- (found in the 'src' field) and adding parameters to it
- so if the function was FOOBAR and took in two arguments,
- we would create a string
- select FOOBAR($1,$2)
- */
- char newquery[1000];
-
- funcName = elem->src;
- parameterCount = getParamTypes(elem,typev);
-
- if (parameterCount > 0) {
- int i;
- sprintf(newquery,"select %s($1",funcName);
- for (i=1;i<parameterCount;i++) {
- sprintf(newquery,"%s,$%d",newquery,i);
- }
- sprintf(newquery,"%s)",newquery);
- } else
- sprintf(newquery,"select %s()",funcName);
+ if (qList->len > 1)
+ {
+ elog(NOTICE,
+ "tg_parseSubQuery: parser produced > 1 query tree");
+ }
+ }
+ break;
+ case TG_C:
+ {
+ /* C ingredients are registered functions in postgres */
+
+ /*
+ * we create a new query string by using the function name
+ * (found in the 'src' field) and adding parameters to it
+ * so if the function was FOOBAR and took in two
+ * arguments, we would create a string select
+ * FOOBAR($1,$2)
+ */
+ char newquery[1000];
+
+ funcName = elem->src;
+ parameterCount = getParamTypes(elem, typev);
+
+ if (parameterCount > 0)
+ {
+ int i;
+
+ sprintf(newquery, "select %s($1", funcName);
+ for (i = 1; i < parameterCount; i++)
+ {
+ sprintf(newquery, "%s,$%d", newquery, i);
+ }
+ sprintf(newquery, "%s)", newquery);
+ }
+ else
+ sprintf(newquery, "select %s()", funcName);
#ifdef DEBUG_RECIPE
-elog(NOTICE,"calling parser with %s", newquery);
-#endif /* DEBUG_RECIPE */
+ elog(NOTICE, "calling parser with %s", newquery);
+#endif /* DEBUG_RECIPE */
+
+ qList = parser(newquery, typev, parameterCount);
+ if (qList->len > 1)
+ {
+ elog(NOTICE,
+ "tg_parseSubQuery: parser produced > 1 query tree");
+ }
+ }
+ break;
+ case TG_RECIPE_GRAPH:
+ elog(NOTICE, "tg_parseSubQuery: can't parse recipe graph ingredients yet!");
+ break;
+ case TG_COMPILED:
+ elog(NOTICE, "tg_parseSubQuery: can't parse compiled ingredients yet!");
+ break;
+ default:
+ elog(NOTICE, "tg_parseSubQuery: unknown srcLang: %d", elem->srcLang);
+ }
+
+ /* parse each of the subrecipes that are input to this node */
+
+ if (n->inNodes->num > 0)
+ {
+ inputQlist = malloc(sizeof(QueryTreeList));
+ inputQlist->len = n->inNodes->num + 1;
+ inputQlist->qtrees = (Query **) malloc(inputQlist->len * sizeof(Query *));
+ for (i = 0; i < n->inNodes->num; i++)
+ {
+
+ inputQlist->qtrees[i] = NULL;
+ if (n->inNodes->val[i])
+ {
+ if (n->inNodes->val[i]->nodeType == TG_TEE_NODE)
+ {
+ qList = tg_parseTeeNode(r, n->inNodes->val[i],
+ i, qList, teeInfo);
+ }
+ else
+ { /* input node is not a Tee */
+ q = tg_parseSubQuery(r, n->inNodes->val[i],
+ teeInfo);
+ Assert(q->len == 1);
+ inputQlist->qtrees[i] = q->qtrees[0];
+ }
+ }
+ }
- qList = parser(newquery,typev,parameterCount);
- if (qList->len > 1) {
- elog(NOTICE,
- "tg_parseSubQuery: parser produced > 1 query tree");
+ /* now, we have all the query trees from our input nodes */
+ /* transform the original parse tree appropriately */
+ tg_rewriteQuery(r, n, qList, inputQlist);
}
- }
- break;
- case TG_RECIPE_GRAPH:
- elog(NOTICE,"tg_parseSubQuery: can't parse recipe graph ingredients yet!");
- break;
- case TG_COMPILED:
- elog(NOTICE,"tg_parseSubQuery: can't parse compiled ingredients yet!");
- break;
- default:
- elog(NOTICE,"tg_parseSubQuery: unknown srcLang: %d",elem->srcLang);
}
+ else if (n->nodeType == TG_EYE_NODE)
+ {
- /* parse each of the subrecipes that are input to this node*/
-
- if (n->inNodes->num > 0) {
- inputQlist = malloc(sizeof(QueryTreeList));
- inputQlist->len = n->inNodes->num + 1 ;
- inputQlist->qtrees = (Query**)malloc(inputQlist->len * sizeof(Query*));
- for (i=0;i<n->inNodes->num;i++) {
-
- inputQlist->qtrees[i] = NULL;
- if (n->inNodes->val[i]) {
- if (n->inNodes->val[i]->nodeType == TG_TEE_NODE) {
- qList = tg_parseTeeNode(r,n->inNodes->val[i],
- i,qList,teeInfo);
- }
- else
- { /* input node is not a Tee */
- q = tg_parseSubQuery(r,n->inNodes->val[i],
- teeInfo);
- Assert (q->len == 1);
- inputQlist->qtrees[i] = q->qtrees[0];
- }
+ /*
+ * if we hit an eye, we need to stop and make what we have into a
+ * subrecipe query block
+ */
+ elog(NOTICE, "tg_parseSubQuery: can't handle eye nodes yet");
+ }
+ else if (n->nodeType == TG_TEE_NODE)
+ {
+
+ /*
+ * if we hit a tee, check to see if the parsing has been done for
+ * this tee already by the other parent
+ */
+
+ rel = RelationNameGetRelation(n->nodeName);
+ if (RelationIsValid(rel))
+ {
+
+ /*
+ * this tee has already been visited, no need to do any
+ * further processing
+ */
+ return NULL;
}
- }
+ else
+ {
+ /* we need to process the child of the tee first, */
+ child = n->inNodes->val[0];
+
+ if (child->nodeType == TG_TEE_NODE)
+ {
+ /* nested Tee nodes */
+ qList = tg_parseTeeNode(r, child, 0, qList, teeInfo);
+ return qList;
+ }
- /* now, we have all the query trees from our input nodes */
- /* transform the original parse tree appropriately */
- tg_rewriteQuery(r,n,qList,inputQlist);
+ Assert(child != NULL);
+
+ /* parse the input node */
+ q = tg_parseSubQuery(r, child, teeInfo);
+ Assert(q->len == 1);
+
+ /* add the parsed query to the main list of queries */
+ qList = appendQlist(qList, q);
+
+ /* need to create the tee table here */
+
+ /*
+ * the tee table created is used both for materializing the
+ * values at the tee node, and for parsing and optimization.
+ * The optimization needs to have a real table before it will
+ * consider scans on it
+ */
+
+ /*
+ * first, find the type of the tuples being produced by the
+ * tee. The type is the same as the output type of the child
+ * node.
+ *
+ * NOTE: we are assuming that the child node only has a single
+ * output here!
+ */
+ getParamTypes(child->nodeElem, typev);
+
+ /*
+ * the output type is either a complex type, (and is thus a
+ * relation) or is a simple type
+ */
+
+ rel = RelationNameGetRelation(child->nodeElem->outTypes->val[0]);
+
+ if (RelationIsValid(rel))
+ {
+
+ /*
+ * for complex types, create new relation with the same
+ * tuple descriptor as the output table type
+ */
+ len = length(q->qtrees[0]->targetList);
+ tupdesc = rel->rd_att;
+
+ relid = heap_create(child->nodeElem->outTypes->val[0],
+ NULL, /* XXX */
+ 'n',
+ DEFAULT_SMGR,
+ tupdesc);
+ }
+ else
+ {
+
+ /*
+ * we have to create a relation with one attribute of the
+ * simple base type. That attribute will have an attr
+ * name of "result"
+ */
+ /* NOTE: ignore array types for the time being */
+
+ len = 1;
+ tupdesc = CreateTemplateTupleDesc(len);
+
+ if (!TupleDescInitEntry(tupdesc, 1,
+ "result",
+ NULL,
+ 0, false))
+ {
+ elog(NOTICE, "tg_parseSubQuery: unexpected result from TupleDescInitEntry");
+ }
+ else
+ {
+ relid = heap_create(child->nodeElem->outTypes->val[0],
+ NULL, /* XXX */
+ 'n',
+ DEFAULT_SMGR,
+ tupdesc);
+ }
+ }
+ }
}
- }
- else if (n->nodeType == TG_EYE_NODE) {
- /* if we hit an eye, we need to stop and make what we have
- into a subrecipe query block*/
- elog(NOTICE,"tg_parseSubQuery: can't handle eye nodes yet");
- }
- else if (n->nodeType == TG_TEE_NODE) {
- /* if we hit a tee, check to see if the parsing has been done
- for this tee already by the other parent */
-
- rel = RelationNameGetRelation(n->nodeName);
- if (RelationIsValid(rel)) {
- /* this tee has already been visited,
- no need to do any further processing */
- return NULL;
- } else {
- /* we need to process the child of the tee first, */
- child = n->inNodes->val[0];
-
- if (child->nodeType == TG_TEE_NODE) {
- /* nested Tee nodes */
- qList = tg_parseTeeNode(r,child,0,qList,teeInfo);
- return qList;
- }
-
- Assert (child != NULL);
-
- /* parse the input node */
- q = tg_parseSubQuery(r,child, teeInfo);
- Assert (q->len == 1);
-
- /* add the parsed query to the main list of queries */
- qList = appendQlist(qList,q);
-
- /* need to create the tee table here */
- /* the tee table created is used both for materializing the values
- at the tee node, and for parsing and optimization.
- The optimization needs to have a real table before it will
- consider scans on it */
-
- /* first, find the type of the tuples being produced by the
- tee. The type is the same as the output type of
- the child node.
-
- NOTE: we are assuming that the child node only has a single
- output here! */
- getParamTypes(child->nodeElem,typev);
-
- /* the output type is either a complex type,
- (and is thus a relation) or is a simple type */
-
- rel = RelationNameGetRelation(child->nodeElem->outTypes->val[0]);
-
- if (RelationIsValid(rel)) {
- /* for complex types, create new relation with the same
- tuple descriptor as the output table type*/
- len = length(q->qtrees[0]->targetList);
- tupdesc = rel->rd_att;
-
- relid = heap_create(child->nodeElem->outTypes->val[0],
- NULL, /* XXX */
- 'n',
- DEFAULT_SMGR,
- tupdesc);
- }
- else {
- /* we have to create a relation with one attribute of
- the simple base type. That attribute will have
- an attr name of "result" */
- /*NOTE: ignore array types for the time being */
-
- len = 1;
- tupdesc = CreateTemplateTupleDesc(len);
-
- if ( !TupleDescInitEntry(tupdesc,1,
- "result",
- NULL,
- 0, false)) {
- elog(NOTICE,"tg_parseSubQuery: unexpected result from TupleDescInitEntry");
- } else {
- relid = heap_create(child->nodeElem->outTypes->val[0],
- NULL, /* XXX */
- 'n',
- DEFAULT_SMGR,
- tupdesc);
- }
- }
+ else if (n->nodeType == TG_RECIPE_NODE)
+ {
+ elog(NOTICE, "tg_parseSubQuery: can't handle embedded recipes yet!");
}
- }
- else if (n->nodeType == TG_RECIPE_NODE) {
- elog(NOTICE,"tg_parseSubQuery: can't handle embedded recipes yet!");
- } else
- elog (NOTICE, "unknown nodeType: %d", n->nodeType);
+ else
+ elog(NOTICE, "unknown nodeType: %d", n->nodeType);
- return qList;
+ return qList;
}
/*
* OffsetVarAttno -
- * recursively find all the var nodes with the specified varno
+ * recursively find all the var nodes with the specified varno
* and offset their varattno with the offset
- *
- * code is similar to OffsetVarNodes in rewriteManip.c
+ *
+ * code is similar to OffsetVarNodes in rewriteManip.c
*/
void
-OffsetVarAttno(Node* node, int varno, int offset)
+OffsetVarAttno(Node * node, int varno, int offset)
{
- if (node == NULL) return;
- switch (nodeTag(node)) {
- case T_TargetEntry:
- {
- TargetEntry *tle = (TargetEntry *)node;
- OffsetVarAttno(tle->expr, varno, offset);
- }
- break;
- case T_Expr:
- {
- Expr *expr = (Expr*)node;
- OffsetVarAttno((Node*)expr->args, varno, offset);
- }
- break;
- case T_Var:
+ if (node == NULL)
+ return;
+ switch (nodeTag(node))
{
- Var *var = (Var*)node;
- if (var->varno == varno)
- var->varattno += offset;
- }
- break;
- case T_List:
- {
- List *l;
+ case T_TargetEntry:
+ {
+ TargetEntry *tle = (TargetEntry *) node;
+
+ OffsetVarAttno(tle->expr, varno, offset);
+ }
+ break;
+ case T_Expr:
+ {
+ Expr *expr = (Expr *) node;
+
+ OffsetVarAttno((Node *) expr->args, varno, offset);
+ }
+ break;
+ case T_Var:
+ {
+ Var *var = (Var *) node;
- foreach(l, (List*)node) {
- OffsetVarAttno(lfirst(l), varno, offset);
- }
+ if (var->varno == varno)
+ var->varattno += offset;
+ }
+ break;
+ case T_List:
+ {
+ List *l;
+
+ foreach(l, (List *) node)
+ {
+ OffsetVarAttno(lfirst(l), varno, offset);
+ }
+ }
+ break;
+ default:
+ /* ignore the others */
+ break;
}
- break;
- default:
- /* ignore the others */
- break;
- }
}
/*
- * appendQlist
- * add the contents of a QueryTreeList q2 to the end of the QueryTreeList
- * q1
+ * appendQlist
+ * add the contents of a QueryTreeList q2 to the end of the QueryTreeList
+ * q1
*
- * returns a new querytree list
+ * returns a new querytree list
*/
-QueryTreeList*
-appendQlist(QueryTreeList *q1, QueryTreeList *q2)
+QueryTreeList *
+appendQlist(QueryTreeList * q1, QueryTreeList * q2)
{
- QueryTreeList* newq;
- int i,j;
- int newlen;
-
- if (q1 == NULL)
- return q2;
-
- if (q2 == NULL)
- return q1;
-
- newlen = q1->len + q2->len;
- newq = (QueryTreeList*)malloc(sizeof(QueryTreeList));
- newq->len = newlen;
- newq->qtrees = (Query**)malloc(newlen * sizeof(Query*));
- for (i=0;i<q1->len;i++)
- newq->qtrees[i] = q1->qtrees[i];
- for (j=0;j<q2->len;j++) {
- newq->qtrees[i + j] = q2->qtrees[j];
- }
- return newq;
+ QueryTreeList *newq;
+ int i,
+ j;
+ int newlen;
+
+ if (q1 == NULL)
+ return q2;
+
+ if (q2 == NULL)
+ return q1;
+
+ newlen = q1->len + q2->len;
+ newq = (QueryTreeList *) malloc(sizeof(QueryTreeList));
+ newq->len = newlen;
+ newq->qtrees = (Query **) malloc(newlen * sizeof(Query *));
+ for (i = 0; i < q1->len; i++)
+ newq->qtrees[i] = q1->qtrees[i];
+ for (j = 0; j < q2->len; j++)
+ {
+ newq->qtrees[i + j] = q2->qtrees[j];
+ }
+ return newq;
}
/*
- * appendTeeQuery
- *
- * modify the query field of the teeInfo list of the particular tee node
+ * appendTeeQuery
+ *
+ * modify the query field of the teeInfo list of the particular tee node
*/
static void
-appendTeeQuery(TeeInfo *teeInfo, QueryTreeList *q, char* teeNodeName)
+appendTeeQuery(TeeInfo * teeInfo, QueryTreeList * q, char *teeNodeName)
{
- int i;
-
- Assert(teeInfo);
+ int i;
- for (i=0;i<teeInfo->num;i++) {
- if ( strcmp(teeInfo->val[i].tpi_relName, teeNodeName) == 0) {
+ Assert(teeInfo);
+
+ for (i = 0; i < teeInfo->num; i++)
+ {
+ if (strcmp(teeInfo->val[i].tpi_relName, teeNodeName) == 0)
+ {
- Assert(q->len == 1);
- teeInfo->val[i].tpi_parsetree = q->qtrees[0];
- return;
+ Assert(q->len == 1);
+ teeInfo->val[i].tpi_parsetree = q->qtrees[0];
+ return;
+ }
}
- }
- elog(NOTICE, "appendTeeQuery: teeNodeName '%s' not found in teeInfo");
+ elog(NOTICE, "appendTeeQuery: teeNodeName '%s' not found in teeInfo");
}
/*
- * replaceSeqScan
- * replaces sequential scans of a specified relation with the tee plan
- * the relation is specified by its index in the range table, rt_ind
+ * replaceSeqScan
+ * replaces sequential scans of a specified relation with the tee plan
+ * the relation is specified by its index in the range table, rt_ind
*
* returns the modified plan
* the offset_attno is the offset that needs to be added to the parent's
* qual or targetlist because the child plan has been replaced with a tee node
*/
static void
-replaceSeqScan(Plan* plan, Plan* parent,
- int rt_ind, Plan* tplan)
+replaceSeqScan(Plan * plan, Plan * parent,
+ int rt_ind, Plan * tplan)
{
- Scan* snode;
- Tee* teePlan;
- Result* newPlan;
-
- if (plan == NULL) {
- return;
- }
-
- if (plan->type == T_SeqScan) {
- snode = (Scan*)plan;
- if (snode->scanrelid == rt_ind) {
- /* found the sequential scan that should be replaced
- with the tplan. */
- /* we replace the plan, but we also need to modify its parent*/
-
- /* replace the sequential scan with a Result node
- the reason we use a result node is so that we get the proper
- projection behavior. The Result node is simply (ab)used as
- a projection node */
-
- newPlan = makeNode(Result);
- newPlan->plan.cost = 0.0;
- newPlan->plan.state = (EState*)NULL;
- newPlan->plan.targetlist = plan->targetlist;
- newPlan->plan.lefttree = tplan;
- newPlan->plan.righttree = NULL;
- newPlan->resconstantqual = NULL;
- newPlan->resstate = NULL;
-
- /* change all the varno's to 1*/
- ChangeVarNodes((Node*)newPlan->plan.targetlist,
- snode->scanrelid, 1);
-
- if (parent) {
- teePlan = (Tee*)tplan;
-
- if (parent->lefttree == plan)
- parent->lefttree = (Plan*)newPlan;
- else
- parent->righttree = (Plan*)newPlan;
-
+ Scan *snode;
+ Tee *teePlan;
+ Result *newPlan;
- if (teePlan->leftParent == NULL)
- teePlan->leftParent = (Plan*)newPlan;
- else
- teePlan->rightParent = (Plan*)newPlan;
+ if (plan == NULL)
+ {
+ return;
+ }
+
+ if (plan->type == T_SeqScan)
+ {
+ snode = (Scan *) plan;
+ if (snode->scanrelid == rt_ind)
+ {
+
+ /*
+ * found the sequential scan that should be replaced with the
+ * tplan.
+ */
+ /* we replace the plan, but we also need to modify its parent */
+
+ /*
+ * replace the sequential scan with a Result node the reason
+ * we use a result node is so that we get the proper
+ * projection behavior. The Result node is simply (ab)used as
+ * a projection node
+ */
+
+ newPlan = makeNode(Result);
+ newPlan->plan.cost = 0.0;
+ newPlan->plan.state = (EState *) NULL;
+ newPlan->plan.targetlist = plan->targetlist;
+ newPlan->plan.lefttree = tplan;
+ newPlan->plan.righttree = NULL;
+ newPlan->resconstantqual = NULL;
+ newPlan->resstate = NULL;
+
+ /* change all the varno's to 1 */
+ ChangeVarNodes((Node *) newPlan->plan.targetlist,
+ snode->scanrelid, 1);
+
+ if (parent)
+ {
+ teePlan = (Tee *) tplan;
+
+ if (parent->lefttree == plan)
+ parent->lefttree = (Plan *) newPlan;
+ else
+ parent->righttree = (Plan *) newPlan;
+
+
+ if (teePlan->leftParent == NULL)
+ teePlan->leftParent = (Plan *) newPlan;
+ else
+ teePlan->rightParent = (Plan *) newPlan;
/* comment for now to test out executor-stuff
- if (parent->state) {
- ExecInitNode((Plan*)newPlan, parent->state, (Plan*)newPlan);
- }
+ if (parent->state) {
+ ExecInitNode((Plan*)newPlan, parent->state, (Plan*)newPlan);
+ }
*/
- }
- }
+ }
+ }
- } else {
- if (plan->lefttree) {
- replaceSeqScan(plan->lefttree, plan, rt_ind, tplan);
}
- if (plan->righttree) {
- replaceSeqScan(plan->righttree, plan, rt_ind, tplan);
+ else
+ {
+ if (plan->lefttree)
+ {
+ replaceSeqScan(plan->lefttree, plan, rt_ind, tplan);
+ }
+ if (plan->righttree)
+ {
+ replaceSeqScan(plan->righttree, plan, rt_ind, tplan);
+ }
}
- }
}
/*
- * replaceTeeScans
- * places the sequential scans of the Tee table with
+ * replaceTeeScans
+ * places the sequential scans of the Tee table with
* a connection to the actual tee plan node
*/
-static Plan*
-replaceTeeScans(Plan* plan, Query* parsetree, TeeInfo *teeInfo)
+static Plan *
+replaceTeeScans(Plan * plan, Query * parsetree, TeeInfo * teeInfo)
{
- int i;
- List* rtable;
- RangeTblEntry *rte;
- char prefix[5];
- int rt_ind;
- Plan* tplan;
-
- rtable = parsetree->rtable;
- if (rtable == NULL)
- return plan;
+ int i;
+ List *rtable;
+ RangeTblEntry *rte;
+ char prefix[5];
+ int rt_ind;
+ Plan *tplan;
+
+ rtable = parsetree->rtable;
+ if (rtable == NULL)
+ return plan;
+
+ /*
+ * look through the range table for the tee relation entry, that will
+ * give use the varno we need to detect which sequential scans need to
+ * be replaced with tee nodes
+ */
+
+ rt_ind = 0;
+ while (rtable != NIL)
+ {
+ rte = lfirst(rtable);
+ rtable = lnext(rtable);
+ rt_ind++; /* range table references in varno fields
+ * start w/ 1 */
+
+ /*
+ * look for the "tee_" prefix in the refname, also check to see
+ * that the relname and the refname are the same this should
+ * eliminate any user-specified table and leave us with the tee
+ * table entries only
+ */
+ if ((strlen(rte->refname) < 4) ||
+ (strcmp(rte->relname, rte->refname) != 0))
+ continue;
+ strNcpy(prefix, rte->refname, 4);
+ if (strcmp(prefix, "tee_") == 0)
+ {
+ /* okay, we found a tee node entry in the range table */
+
+ /* find the appropriate plan in the teeInfo list */
+ tplan = NULL;
+ for (i = 0; i < teeInfo->num; i++)
+ {
+ if (strcmp(teeInfo->val[i].tpi_relName,
+ rte->refname) == 0)
+ {
+ tplan = teeInfo->val[i].tpi_plan;
+ }
+ }
+ if (tplan == NULL)
+ {
+ elog(NOTICE, "replaceTeeScans didn't find the corresponding tee plan");
+ }
- /* look through the range table for the tee relation entry,
- that will give use the varno we need to detect which
- sequential scans need to be replaced with tee nodes*/
-
- rt_ind = 0;
- while (rtable != NIL) {
- rte = lfirst(rtable);
- rtable = lnext(rtable);
- rt_ind++; /* range table references in varno fields start w/ 1 */
-
- /* look for the "tee_" prefix in the refname,
- also check to see that the relname and the refname are the same
- this should eliminate any user-specified table and leave
- us with the tee table entries only*/
- if ((strlen(rte->refname) < 4) ||
- (strcmp (rte->relname, rte->refname) != 0))
- continue;
- strNcpy(prefix,rte->refname,4);
- if (strcmp(prefix,"tee_") == 0) {
- /* okay, we found a tee node entry in the range table */
-
- /* find the appropriate plan in the teeInfo list */
- tplan = NULL;
- for (i=0;i<teeInfo->num;i++) {
- if (strcmp(teeInfo->val[i].tpi_relName,
- rte->refname) == 0) {
- tplan = teeInfo->val[i].tpi_plan;
+ /*
+ * replace the sequential scan node with that var number with
+ * the tee plan node
+ */
+ replaceSeqScan(plan, NULL, rt_ind, tplan);
}
- }
- if (tplan == NULL) {
- elog(NOTICE, "replaceTeeScans didn't find the corresponding tee plan"); }
-
- /* replace the sequential scan node with that var number
- with the tee plan node */
- replaceSeqScan(plan, NULL, rt_ind, tplan);
}
- }
- return plan;
+ return plan;
}
-#endif /* TIOGA */
+#endif /* TIOGA */
diff --git a/src/backend/commands/remove.c b/src/backend/commands/remove.c
index 7f0198a10b7..cafe4d09710 100644
--- a/src/backend/commands/remove.c
+++ b/src/backend/commands/remove.c
@@ -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)) {
+
+ 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);
- 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))
+
+ /* 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);
+ 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);
+ 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);
-
+
+ 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;
+ userName = GetPgUserName();
+ if (!pg_func_ownercheck(userName, functionName, nargs, argList))
+ {
+ elog(WARN, "RemoveFunction: function '%s': permission denied",
+ functionName);
}
- 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);
+#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);
+
+ /* 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];
-
-
- /*
- * 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;
- }
+ 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;
+ }
/*
#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);
}
diff --git a/src/backend/commands/rename.c b/src/backend/commands/rename.c
index 5d4e4ab2bb8..9b8df698346 100644
--- a/src/backend/commands/rename.c
+++ b/src/backend/commands/rename.c
@@ -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);
+ 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);
+ 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.
+ * 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.
*/
- 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 (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);
}
diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c
index 5d35f7b60f5..c4bd8c40dcf 100644
--- a/src/backend/commands/sequence.c
+++ b/src/backend/commands/sequence.c
@@ -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 FormData_pg_sequence *SequenceTupleForm;
-
-typedef struct sequence_magic {
- uint32 magic;
-} sequence_magic;
+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 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;
-
- /* 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)
+ 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);
+
+ /*
+ * 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 */
-
- 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;
+ 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)
+ {
+ 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 */
+
+ 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)
+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;
+ 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);
}
- else /* descending sequence */
+
+ 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 */
{
- 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);
-
+
+ /*
+ * 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);
+
}
int4
-currval (struct varlena * seqin)
+currval(struct varlena * seqin)
{
- char *seqname = textout(seqin);
- SeqTable elm;
- int4 result;
-
- /* 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);
-
+ char *seqname = textout(seqin);
+ SeqTable elm;
+ int4 result;
+
+ /* 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);
+
}
-static SequenceTupleForm
-read_info (char * caller, SeqTable elm, Buffer * buf)
+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);
+ 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)
+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);
-
+ 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);
+
}
/*
* 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 */
+ SeqTable elm;
+ Relation rel;
+
+ ItsSequenceCreation = false;
+
+ for (elm = seqtab; elm != (SeqTable) NULL;)
{
- rel = elm->rel;
- elm->rel = (Relation) NULL;
- RelationUnsetWIntentLock (rel);
- heap_close (rel);
- }
- elm = elm->next;
- }
-
- return;
-
+ 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;
+
}
-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);
- }
-
- 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 */
+ 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);
+ }
+
+ 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);
-
- if ( last_value == (DefElem*) NULL ) /* START WITH */
- if ( new->increment_by > 0 )
- new->last_value = new->min_value; /* ascending seq */
+ 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);
+
+ 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);
-
- 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);
+ 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 (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 ( nodeTag (def->arg) == T_Integer )
- return (intVal (def->arg));
-
- elog (WARN, "DefineSequence: \"%s\" is to be integer", def->defname);
- return (-1);
+ 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);
}
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 2919df473fd..53ab1838cfe 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -1,7 +1,7 @@
/*-------------------------------------------------------------------------
*
* trigger.c--
- * PostgreSQL TRIGGERs support code.
+ * PostgreSQL TRIGGERs support code.
*
*-------------------------------------------------------------------------
*/
@@ -32,581 +32,587 @@
#include "utils/syscache.h"
#endif
-TriggerData *CurrentTriggerData = NULL;
+TriggerData *CurrentTriggerData = NULL;
-void RelationBuildTriggers (Relation relation);
-void FreeTriggerDesc (Relation relation);
+void RelationBuildTriggers(Relation relation);
+void FreeTriggerDesc(Relation relation);
-static void DescribeTrigger (TriggerDesc *trigdesc, Trigger *trigger);
+static void DescribeTrigger(TriggerDesc * trigdesc, Trigger * trigger);
-extern void fmgr_info(Oid procedureId, func_ptr *function, int *nargs);
+extern void fmgr_info(Oid procedureId, func_ptr * function, int *nargs);
extern GlobalMemory CacheCxt;
void
-CreateTrigger (CreateTrigStmt *stmt)
+CreateTrigger(CreateTrigStmt * stmt)
{
- int16 tgtype;
- int16 tgattr[8] = {0};
- Datum values[Natts_pg_trigger];
- char nulls[Natts_pg_trigger];
- Relation rel;
- Relation tgrel;
- HeapScanDesc tgscan;
- ScanKeyData key;
- Relation relrdesc;
- HeapTuple tuple;
- ItemPointerData oldTID;
- Relation idescs[Num_pg_trigger_indices];
- Relation ridescs[Num_pg_class_indices];
- MemoryContext oldcxt;
- Oid fargtypes[8];
- int found = 0;
- int i;
-
- if ( IsSystemRelationName (stmt->relname) )
- elog(WARN, "CreateTrigger: can't create trigger for system relation %s", stmt->relname);
+ int16 tgtype;
+ int16 tgattr[8] = {0};
+ Datum values[Natts_pg_trigger];
+ char nulls[Natts_pg_trigger];
+ Relation rel;
+ Relation tgrel;
+ HeapScanDesc tgscan;
+ ScanKeyData key;
+ Relation relrdesc;
+ HeapTuple tuple;
+ ItemPointerData oldTID;
+ Relation idescs[Num_pg_trigger_indices];
+ Relation ridescs[Num_pg_class_indices];
+ MemoryContext oldcxt;
+ Oid fargtypes[8];
+ int found = 0;
+ int i;
+
+ if (IsSystemRelationName(stmt->relname))
+ elog(WARN, "CreateTrigger: can't create trigger for system relation %s", stmt->relname);
#ifndef NO_SECURITY
- if ( !pg_ownercheck (GetPgUserName (), stmt->relname, RELNAME))
- elog(WARN, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
+ if (!pg_ownercheck(GetPgUserName(), stmt->relname, RELNAME))
+ elog(WARN, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
#endif
-
- rel = heap_openr (stmt->relname);
- if ( !RelationIsValid (rel) )
- elog (WARN, "CreateTrigger: there is no relation %s", stmt->relname);
-
- RelationSetLockForWrite (rel);
-
- TRIGGER_CLEAR_TYPE (tgtype);
- if ( stmt->before )
- TRIGGER_SETT_BEFORE (tgtype);
- if ( stmt->row )
- TRIGGER_SETT_ROW (tgtype);
- for (i = 0; i < 3 && stmt->actions[i]; i++)
- {
- switch ( stmt->actions[i] )
- {
- case 'i':
- if ( TRIGGER_FOR_INSERT (tgtype) )
- elog (WARN, "CreateTrigger: double INSERT event specified");
- TRIGGER_SETT_INSERT (tgtype);
- break;
- case 'd':
- if ( TRIGGER_FOR_DELETE (tgtype) )
- elog (WARN, "CreateTrigger: double DELETE event specified");
- TRIGGER_SETT_DELETE (tgtype);
- break;
- case 'u':
- if ( TRIGGER_FOR_UPDATE (tgtype) )
- elog (WARN, "CreateTrigger: double UPDATE event specified");
- TRIGGER_SETT_UPDATE (tgtype);
- break;
- default:
- elog (WARN, "CreateTrigger: unknown event specified");
- break;
- }
- }
-
- /* Scan pg_trigger */
- tgrel = heap_openr (TriggerRelationName);
- RelationSetLockForWrite (tgrel);
- ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
- ObjectIdEqualRegProcedure, rel->rd_id);
- tgscan = heap_beginscan (tgrel, 0, NowTimeQual, 1, &key);
- while (tuple = heap_getnext (tgscan, 0, (Buffer *)NULL), PointerIsValid(tuple))
- {
- Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT (tuple);
- if ( namestrcmp (&(pg_trigger->tgname), stmt->trigname) == 0 )
- elog (WARN, "CreateTrigger: trigger %s already defined on relation %s",
- stmt->trigname, stmt->relname);
- else
- found++;
- }
- heap_endscan (tgscan);
-
- memset (fargtypes, 0, 8 * sizeof(Oid));
- tuple = SearchSysCacheTuple (PRONAME,
- PointerGetDatum (stmt->funcname),
- 0, PointerGetDatum (fargtypes), 0);
- if ( !HeapTupleIsValid (tuple) ||
- ((Form_pg_proc)GETSTRUCT(tuple))->prorettype != 0 ||
- ((Form_pg_proc)GETSTRUCT(tuple))->pronargs != 0 )
- elog (WARN, "CreateTrigger: function %s () does not exist", stmt->funcname);
-
- if ( ((Form_pg_proc)GETSTRUCT(tuple))->prolang != ClanguageId )
- elog (WARN, "CreateTrigger: only C functions are supported");
-
- memset (nulls, ' ', Natts_pg_trigger * sizeof (char));
-
- values[Anum_pg_trigger_tgrelid - 1] = ObjectIdGetDatum (rel->rd_id);
- values[Anum_pg_trigger_tgname - 1] = NameGetDatum (namein (stmt->trigname));
- values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum (tuple->t_oid);
- values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum (tgtype);
- if ( stmt->args )
- {
- List *le;
- char *args;
- int16 nargs = length (stmt->args);
- int len = 0;
-
- foreach (le, stmt->args)
- {
- char *ar = (char *) lfirst (le);
- len += strlen (ar) + 4;
- }
- args = (char *) palloc (len + 1);
- args[0] = 0;
- foreach (le, stmt->args)
- sprintf (args + strlen (args), "%s\\000", (char *)lfirst (le));
- values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum (nargs);
- values[Anum_pg_trigger_tgargs - 1] = PointerGetDatum (byteain (args));
- }
- else
- {
- values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum (0);
- values[Anum_pg_trigger_tgargs - 1] = PointerGetDatum (byteain (""));
- }
- values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum (tgattr);
-
- tuple = heap_formtuple (tgrel->rd_att, values, nulls);
- heap_insert (tgrel, tuple);
- CatalogOpenIndices (Num_pg_trigger_indices, Name_pg_trigger_indices, idescs);
- CatalogIndexInsert (idescs, Num_pg_trigger_indices, tgrel, tuple);
- CatalogCloseIndices (Num_pg_trigger_indices, idescs);
- pfree (tuple);
- RelationUnsetLockForWrite (tgrel);
- heap_close (tgrel);
-
- pfree (DatumGetPointer(values[Anum_pg_trigger_tgname - 1]));
- pfree (DatumGetPointer(values[Anum_pg_trigger_tgargs - 1]));
-
- /* update pg_class */
- relrdesc = heap_openr (RelationRelationName);
- tuple = ClassNameIndexScan (relrdesc, stmt->relname);
- if ( !PointerIsValid (tuple) )
- {
+
+ rel = heap_openr(stmt->relname);
+ if (!RelationIsValid(rel))
+ elog(WARN, "CreateTrigger: there is no relation %s", stmt->relname);
+
+ RelationSetLockForWrite(rel);
+
+ TRIGGER_CLEAR_TYPE(tgtype);
+ if (stmt->before)
+ TRIGGER_SETT_BEFORE(tgtype);
+ if (stmt->row)
+ TRIGGER_SETT_ROW(tgtype);
+ for (i = 0; i < 3 && stmt->actions[i]; i++)
+ {
+ switch (stmt->actions[i])
+ {
+ case 'i':
+ if (TRIGGER_FOR_INSERT(tgtype))
+ elog(WARN, "CreateTrigger: double INSERT event specified");
+ TRIGGER_SETT_INSERT(tgtype);
+ break;
+ case 'd':
+ if (TRIGGER_FOR_DELETE(tgtype))
+ elog(WARN, "CreateTrigger: double DELETE event specified");
+ TRIGGER_SETT_DELETE(tgtype);
+ break;
+ case 'u':
+ if (TRIGGER_FOR_UPDATE(tgtype))
+ elog(WARN, "CreateTrigger: double UPDATE event specified");
+ TRIGGER_SETT_UPDATE(tgtype);
+ break;
+ default:
+ elog(WARN, "CreateTrigger: unknown event specified");
+ break;
+ }
+ }
+
+ /* Scan pg_trigger */
+ tgrel = heap_openr(TriggerRelationName);
+ RelationSetLockForWrite(tgrel);
+ ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
+ ObjectIdEqualRegProcedure, rel->rd_id);
+ tgscan = heap_beginscan(tgrel, 0, NowTimeQual, 1, &key);
+ while (tuple = heap_getnext(tgscan, 0, (Buffer *) NULL), PointerIsValid(tuple))
+ {
+ Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
+
+ if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
+ elog(WARN, "CreateTrigger: trigger %s already defined on relation %s",
+ stmt->trigname, stmt->relname);
+ else
+ found++;
+ }
+ heap_endscan(tgscan);
+
+ memset(fargtypes, 0, 8 * sizeof(Oid));
+ tuple = SearchSysCacheTuple(PRONAME,
+ PointerGetDatum(stmt->funcname),
+ 0, PointerGetDatum(fargtypes), 0);
+ if (!HeapTupleIsValid(tuple) ||
+ ((Form_pg_proc) GETSTRUCT(tuple))->prorettype != 0 ||
+ ((Form_pg_proc) GETSTRUCT(tuple))->pronargs != 0)
+ elog(WARN, "CreateTrigger: function %s () does not exist", stmt->funcname);
+
+ if (((Form_pg_proc) GETSTRUCT(tuple))->prolang != ClanguageId)
+ elog(WARN, "CreateTrigger: only C functions are supported");
+
+ memset(nulls, ' ', Natts_pg_trigger * sizeof(char));
+
+ values[Anum_pg_trigger_tgrelid - 1] = ObjectIdGetDatum(rel->rd_id);
+ values[Anum_pg_trigger_tgname - 1] = NameGetDatum(namein(stmt->trigname));
+ values[Anum_pg_trigger_tgfoid - 1] = ObjectIdGetDatum(tuple->t_oid);
+ values[Anum_pg_trigger_tgtype - 1] = Int16GetDatum(tgtype);
+ if (stmt->args)
+ {
+ List *le;
+ char *args;
+ int16 nargs = length(stmt->args);
+ int len = 0;
+
+ foreach(le, stmt->args)
+ {
+ char *ar = (char *) lfirst(le);
+
+ len += strlen(ar) + 4;
+ }
+ args = (char *) palloc(len + 1);
+ args[0] = 0;
+ foreach(le, stmt->args)
+ sprintf(args + strlen(args), "%s\\000", (char *) lfirst(le));
+ values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(nargs);
+ values[Anum_pg_trigger_tgargs - 1] = PointerGetDatum(byteain(args));
+ }
+ else
+ {
+ values[Anum_pg_trigger_tgnargs - 1] = Int16GetDatum(0);
+ values[Anum_pg_trigger_tgargs - 1] = PointerGetDatum(byteain(""));
+ }
+ values[Anum_pg_trigger_tgattr - 1] = PointerGetDatum(tgattr);
+
+ tuple = heap_formtuple(tgrel->rd_att, values, nulls);
+ heap_insert(tgrel, tuple);
+ CatalogOpenIndices(Num_pg_trigger_indices, Name_pg_trigger_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_trigger_indices, tgrel, tuple);
+ CatalogCloseIndices(Num_pg_trigger_indices, idescs);
+ pfree(tuple);
+ RelationUnsetLockForWrite(tgrel);
+ heap_close(tgrel);
+
+ pfree(DatumGetPointer(values[Anum_pg_trigger_tgname - 1]));
+ pfree(DatumGetPointer(values[Anum_pg_trigger_tgargs - 1]));
+
+ /* update pg_class */
+ relrdesc = heap_openr(RelationRelationName);
+ tuple = ClassNameIndexScan(relrdesc, stmt->relname);
+ if (!PointerIsValid(tuple))
+ {
+ heap_close(relrdesc);
+ elog(WARN, "CreateTrigger: relation %s not found in pg_class", stmt->relname);
+ }
+ ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found + 1;
+ RelationInvalidateHeapTuple(relrdesc, tuple);
+ oldTID = tuple->t_ctid;
+ heap_replace(relrdesc, &oldTID, tuple);
+ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
+ CatalogIndexInsert(ridescs, Num_pg_class_indices, relrdesc, tuple);
+ CatalogCloseIndices(Num_pg_class_indices, ridescs);
+ pfree(tuple);
heap_close(relrdesc);
- elog(WARN, "CreateTrigger: relation %s not found in pg_class", stmt->relname);
- }
- ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found + 1;
- RelationInvalidateHeapTuple (relrdesc, tuple);
- oldTID = tuple->t_ctid;
- heap_replace (relrdesc, &oldTID, tuple);
- CatalogOpenIndices (Num_pg_class_indices, Name_pg_class_indices, ridescs);
- CatalogIndexInsert (ridescs, Num_pg_class_indices, relrdesc, tuple);
- CatalogCloseIndices (Num_pg_class_indices, ridescs);
- pfree(tuple);
- heap_close(relrdesc);
-
- CommandCounterIncrement ();
- oldcxt = MemoryContextSwitchTo ((MemoryContext)CacheCxt);
- FreeTriggerDesc (rel);
- rel->rd_rel->reltriggers = found + 1;
- RelationBuildTriggers (rel);
- MemoryContextSwitchTo (oldcxt);
- heap_close (rel);
- return;
+
+ CommandCounterIncrement();
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ FreeTriggerDesc(rel);
+ rel->rd_rel->reltriggers = found + 1;
+ RelationBuildTriggers(rel);
+ MemoryContextSwitchTo(oldcxt);
+ heap_close(rel);
+ return;
}
void
-DropTrigger (DropTrigStmt *stmt)
+DropTrigger(DropTrigStmt * stmt)
{
- Relation rel;
- Relation tgrel;
- HeapScanDesc tgscan;
- ScanKeyData key;
- Relation relrdesc;
- HeapTuple tuple;
- ItemPointerData oldTID;
- Relation ridescs[Num_pg_class_indices];
- MemoryContext oldcxt;
- int found = 0;
- int tgfound = 0;
-
+ Relation rel;
+ Relation tgrel;
+ HeapScanDesc tgscan;
+ ScanKeyData key;
+ Relation relrdesc;
+ HeapTuple tuple;
+ ItemPointerData oldTID;
+ Relation ridescs[Num_pg_class_indices];
+ MemoryContext oldcxt;
+ int found = 0;
+ int tgfound = 0;
+
#ifndef NO_SECURITY
- if ( !pg_ownercheck (GetPgUserName (), stmt->relname, RELNAME))
- elog(WARN, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
+ if (!pg_ownercheck(GetPgUserName(), stmt->relname, RELNAME))
+ elog(WARN, "%s: %s", stmt->relname, aclcheck_error_strings[ACLCHECK_NOT_OWNER]);
#endif
-
- rel = heap_openr (stmt->relname);
- if ( !RelationIsValid (rel) )
- elog (WARN, "DropTrigger: there is no relation %s", stmt->relname);
-
- RelationSetLockForWrite (rel);
-
- tgrel = heap_openr (TriggerRelationName);
- RelationSetLockForWrite (tgrel);
- ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
- ObjectIdEqualRegProcedure, rel->rd_id);
- tgscan = heap_beginscan (tgrel, 0, NowTimeQual, 1, &key);
- while (tuple = heap_getnext (tgscan, 0, (Buffer *)NULL), PointerIsValid(tuple))
- {
- Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT (tuple);
- if ( namestrcmp (&(pg_trigger->tgname), stmt->trigname) == 0 )
- {
- heap_delete (tgrel, &tuple->t_ctid);
- tgfound++;
- }
- else
- found++;
- }
- if ( tgfound == 0 )
- elog (WARN, "DropTrigger: there is no trigger %s on relation %s",
- stmt->trigname, stmt->relname);
- if ( tgfound > 1 )
- elog (NOTICE, "DropTrigger: found (and deleted) %d trigger %s on relation %s",
- tgfound, stmt->trigname, stmt->relname);
- heap_endscan (tgscan);
- RelationUnsetLockForWrite (tgrel);
- heap_close (tgrel);
-
- /* update pg_class */
- relrdesc = heap_openr (RelationRelationName);
- tuple = ClassNameIndexScan (relrdesc, stmt->relname);
- if ( !PointerIsValid (tuple) )
- {
+
+ rel = heap_openr(stmt->relname);
+ if (!RelationIsValid(rel))
+ elog(WARN, "DropTrigger: there is no relation %s", stmt->relname);
+
+ RelationSetLockForWrite(rel);
+
+ tgrel = heap_openr(TriggerRelationName);
+ RelationSetLockForWrite(tgrel);
+ ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
+ ObjectIdEqualRegProcedure, rel->rd_id);
+ tgscan = heap_beginscan(tgrel, 0, NowTimeQual, 1, &key);
+ while (tuple = heap_getnext(tgscan, 0, (Buffer *) NULL), PointerIsValid(tuple))
+ {
+ Form_pg_trigger pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
+
+ if (namestrcmp(&(pg_trigger->tgname), stmt->trigname) == 0)
+ {
+ heap_delete(tgrel, &tuple->t_ctid);
+ tgfound++;
+ }
+ else
+ found++;
+ }
+ if (tgfound == 0)
+ elog(WARN, "DropTrigger: there is no trigger %s on relation %s",
+ stmt->trigname, stmt->relname);
+ if (tgfound > 1)
+ elog(NOTICE, "DropTrigger: found (and deleted) %d trigger %s on relation %s",
+ tgfound, stmt->trigname, stmt->relname);
+ heap_endscan(tgscan);
+ RelationUnsetLockForWrite(tgrel);
+ heap_close(tgrel);
+
+ /* update pg_class */
+ relrdesc = heap_openr(RelationRelationName);
+ tuple = ClassNameIndexScan(relrdesc, stmt->relname);
+ if (!PointerIsValid(tuple))
+ {
+ heap_close(relrdesc);
+ elog(WARN, "DropTrigger: relation %s not found in pg_class", stmt->relname);
+ }
+ ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found;
+ RelationInvalidateHeapTuple(relrdesc, tuple);
+ oldTID = tuple->t_ctid;
+ heap_replace(relrdesc, &oldTID, tuple);
+ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices, ridescs);
+ CatalogIndexInsert(ridescs, Num_pg_class_indices, relrdesc, tuple);
+ CatalogCloseIndices(Num_pg_class_indices, ridescs);
+ pfree(tuple);
heap_close(relrdesc);
- elog(WARN, "DropTrigger: relation %s not found in pg_class", stmt->relname);
- }
- ((Form_pg_class) GETSTRUCT(tuple))->reltriggers = found;
- RelationInvalidateHeapTuple (relrdesc, tuple);
- oldTID = tuple->t_ctid;
- heap_replace (relrdesc, &oldTID, tuple);
- CatalogOpenIndices (Num_pg_class_indices, Name_pg_class_indices, ridescs);
- CatalogIndexInsert (ridescs, Num_pg_class_indices, relrdesc, tuple);
- CatalogCloseIndices (Num_pg_class_indices, ridescs);
- pfree(tuple);
- heap_close(relrdesc);
-
- CommandCounterIncrement ();
- oldcxt = MemoryContextSwitchTo ((MemoryContext)CacheCxt);
- FreeTriggerDesc (rel);
- rel->rd_rel->reltriggers = found;
- if ( found > 0 )
- RelationBuildTriggers (rel);
- MemoryContextSwitchTo (oldcxt);
- heap_close (rel);
- return;
+
+ CommandCounterIncrement();
+ oldcxt = MemoryContextSwitchTo((MemoryContext) CacheCxt);
+ FreeTriggerDesc(rel);
+ rel->rd_rel->reltriggers = found;
+ if (found > 0)
+ RelationBuildTriggers(rel);
+ MemoryContextSwitchTo(oldcxt);
+ heap_close(rel);
+ return;
}
-void
-RelationRemoveTriggers (Relation rel)
+void
+RelationRemoveTriggers(Relation rel)
{
- Relation tgrel;
- HeapScanDesc tgscan;
- ScanKeyData key;
- HeapTuple tup;
-
- tgrel = heap_openr (TriggerRelationName);
- RelationSetLockForWrite (tgrel);
- ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
- ObjectIdEqualRegProcedure, rel->rd_id);
-
- tgscan = heap_beginscan (tgrel, 0, NowTimeQual, 1, &key);
-
- while (tup = heap_getnext (tgscan, 0, (Buffer *)NULL), PointerIsValid(tup))
- heap_delete (tgrel, &tup->t_ctid);
-
- heap_endscan (tgscan);
- RelationUnsetLockForWrite (tgrel);
- heap_close (tgrel);
+ Relation tgrel;
+ HeapScanDesc tgscan;
+ ScanKeyData key;
+ HeapTuple tup;
+
+ tgrel = heap_openr(TriggerRelationName);
+ RelationSetLockForWrite(tgrel);
+ ScanKeyEntryInitialize(&key, 0, Anum_pg_trigger_tgrelid,
+ ObjectIdEqualRegProcedure, rel->rd_id);
+
+ tgscan = heap_beginscan(tgrel, 0, NowTimeQual, 1, &key);
+
+ while (tup = heap_getnext(tgscan, 0, (Buffer *) NULL), PointerIsValid(tup))
+ heap_delete(tgrel, &tup->t_ctid);
+
+ heap_endscan(tgscan);
+ RelationUnsetLockForWrite(tgrel);
+ heap_close(tgrel);
}
void
-RelationBuildTriggers (Relation relation)
+RelationBuildTriggers(Relation relation)
{
- TriggerDesc *trigdesc = (TriggerDesc *) palloc (sizeof (TriggerDesc));
- int ntrigs = relation->rd_rel->reltriggers;
- Trigger *triggers = NULL;
- Trigger *build;
- Relation tgrel;
- Form_pg_trigger pg_trigger;
- Relation irel;
- ScanKeyData skey;
- HeapTuple tuple;
- IndexScanDesc sd;
- RetrieveIndexResult indexRes;
- Buffer buffer;
- ItemPointer iptr;
- struct varlena *val;
- bool isnull;
- int found;
-
- memset (trigdesc, 0, sizeof (TriggerDesc));
-
- ScanKeyEntryInitialize(&skey,
- (bits16)0x0,
- (AttrNumber)1,
- (RegProcedure)ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(relation->rd_id));
-
- tgrel = heap_openr(TriggerRelationName);
- RelationSetLockForRead (tgrel);
- irel = index_openr(TriggerRelidIndex);
- sd = index_beginscan(irel, false, 1, &skey);
-
- for (found = 0; ; )
- {
- indexRes = index_getnext(sd, ForwardScanDirection);
- if (!indexRes)
- break;
-
- iptr = &indexRes->heap_iptr;
- tuple = heap_fetch(tgrel, NowTimeQual, iptr, &buffer);
- pfree(indexRes);
- if (!HeapTupleIsValid(tuple))
- continue;
- if ( found == ntrigs )
- elog (WARN, "RelationBuildTriggers: unexpected record found for rel %.*s",
- NAMEDATALEN, relation->rd_rel->relname.data);
-
- pg_trigger = (Form_pg_trigger) GETSTRUCT (tuple);
-
- if ( triggers == NULL )
- triggers = (Trigger *) palloc (sizeof (Trigger));
- else
- triggers = (Trigger *) repalloc (triggers, (found + 1) * sizeof (Trigger));
- build = &(triggers[found]);
-
- build->tgname = nameout (&(pg_trigger->tgname));
- build->tgfoid = pg_trigger->tgfoid;
- build->tgfunc = NULL;
- build->tgtype = pg_trigger->tgtype;
- build->tgnargs = pg_trigger->tgnargs;
- memcpy (build->tgattr, &(pg_trigger->tgattr), 8 * sizeof (int16));
- val = (struct varlena*) fastgetattr (tuple,
- Anum_pg_trigger_tgargs,
- tgrel->rd_att, &isnull);
- if ( isnull )
- elog (WARN, "RelationBuildTriggers: tgargs IS NULL for rel %.*s",
- NAMEDATALEN, relation->rd_rel->relname.data);
- if ( build->tgnargs > 0 )
- {
- char *p;
- int i;
-
- val = (struct varlena*) fastgetattr (tuple,
- Anum_pg_trigger_tgargs,
- tgrel->rd_att, &isnull);
- if ( isnull )
- elog (WARN, "RelationBuildTriggers: tgargs IS NULL for rel %.*s",
- NAMEDATALEN, relation->rd_rel->relname.data);
- p = (char *) VARDATA (val);
- build->tgargs = (char**) palloc (build->tgnargs * sizeof (char*));
- for (i = 0; i < build->tgnargs; i++)
- {
- build->tgargs[i] = (char*) palloc (strlen (p) + 1);
- strcpy (build->tgargs[i], p);
- p += strlen (p) + 1;
- }
- }
- else
- build->tgargs = NULL;
-
- found++;
- ReleaseBuffer(buffer);
- }
-
- if ( found < ntrigs )
- elog (WARN, "RelationBuildTriggers: %d record not found for rel %.*s",
- ntrigs - found,
- NAMEDATALEN, relation->rd_rel->relname.data);
-
- index_endscan (sd);
- pfree (sd);
- index_close (irel);
- RelationUnsetLockForRead (tgrel);
- heap_close (tgrel);
-
- /* Build trigdesc */
- trigdesc->triggers = triggers;
- for (found = 0; found < ntrigs; found++)
- {
- build = &(triggers[found]);
- DescribeTrigger (trigdesc, build);
- }
-
- relation->trigdesc = trigdesc;
-
+ TriggerDesc *trigdesc = (TriggerDesc *) palloc(sizeof(TriggerDesc));
+ int ntrigs = relation->rd_rel->reltriggers;
+ Trigger *triggers = NULL;
+ Trigger *build;
+ Relation tgrel;
+ Form_pg_trigger pg_trigger;
+ Relation irel;
+ ScanKeyData skey;
+ HeapTuple tuple;
+ IndexScanDesc sd;
+ RetrieveIndexResult indexRes;
+ Buffer buffer;
+ ItemPointer iptr;
+ struct varlena *val;
+ bool isnull;
+ int found;
+
+ memset(trigdesc, 0, sizeof(TriggerDesc));
+
+ ScanKeyEntryInitialize(&skey,
+ (bits16) 0x0,
+ (AttrNumber) 1,
+ (RegProcedure) ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(relation->rd_id));
+
+ tgrel = heap_openr(TriggerRelationName);
+ RelationSetLockForRead(tgrel);
+ irel = index_openr(TriggerRelidIndex);
+ sd = index_beginscan(irel, false, 1, &skey);
+
+ for (found = 0;;)
+ {
+ indexRes = index_getnext(sd, ForwardScanDirection);
+ if (!indexRes)
+ break;
+
+ iptr = &indexRes->heap_iptr;
+ tuple = heap_fetch(tgrel, NowTimeQual, iptr, &buffer);
+ pfree(indexRes);
+ if (!HeapTupleIsValid(tuple))
+ continue;
+ if (found == ntrigs)
+ elog(WARN, "RelationBuildTriggers: unexpected record found for rel %.*s",
+ NAMEDATALEN, relation->rd_rel->relname.data);
+
+ pg_trigger = (Form_pg_trigger) GETSTRUCT(tuple);
+
+ if (triggers == NULL)
+ triggers = (Trigger *) palloc(sizeof(Trigger));
+ else
+ triggers = (Trigger *) repalloc(triggers, (found + 1) * sizeof(Trigger));
+ build = &(triggers[found]);
+
+ build->tgname = nameout(&(pg_trigger->tgname));
+ build->tgfoid = pg_trigger->tgfoid;
+ build->tgfunc = NULL;
+ build->tgtype = pg_trigger->tgtype;
+ build->tgnargs = pg_trigger->tgnargs;
+ memcpy(build->tgattr, &(pg_trigger->tgattr), 8 * sizeof(int16));
+ val = (struct varlena *) fastgetattr(tuple,
+ Anum_pg_trigger_tgargs,
+ tgrel->rd_att, &isnull);
+ if (isnull)
+ elog(WARN, "RelationBuildTriggers: tgargs IS NULL for rel %.*s",
+ NAMEDATALEN, relation->rd_rel->relname.data);
+ if (build->tgnargs > 0)
+ {
+ char *p;
+ int i;
+
+ val = (struct varlena *) fastgetattr(tuple,
+ Anum_pg_trigger_tgargs,
+ tgrel->rd_att, &isnull);
+ if (isnull)
+ elog(WARN, "RelationBuildTriggers: tgargs IS NULL for rel %.*s",
+ NAMEDATALEN, relation->rd_rel->relname.data);
+ p = (char *) VARDATA(val);
+ build->tgargs = (char **) palloc(build->tgnargs * sizeof(char *));
+ for (i = 0; i < build->tgnargs; i++)
+ {
+ build->tgargs[i] = (char *) palloc(strlen(p) + 1);
+ strcpy(build->tgargs[i], p);
+ p += strlen(p) + 1;
+ }
+ }
+ else
+ build->tgargs = NULL;
+
+ found++;
+ ReleaseBuffer(buffer);
+ }
+
+ if (found < ntrigs)
+ elog(WARN, "RelationBuildTriggers: %d record not found for rel %.*s",
+ ntrigs - found,
+ NAMEDATALEN, relation->rd_rel->relname.data);
+
+ index_endscan(sd);
+ pfree(sd);
+ index_close(irel);
+ RelationUnsetLockForRead(tgrel);
+ heap_close(tgrel);
+
+ /* Build trigdesc */
+ trigdesc->triggers = triggers;
+ for (found = 0; found < ntrigs; found++)
+ {
+ build = &(triggers[found]);
+ DescribeTrigger(trigdesc, build);
+ }
+
+ relation->trigdesc = trigdesc;
+
}
-void
-FreeTriggerDesc (Relation relation)
+void
+FreeTriggerDesc(Relation relation)
{
- TriggerDesc *trigdesc = relation->trigdesc;
- Trigger ***t;
- Trigger *trigger;
- int i;
-
- if ( trigdesc == NULL )
- return;
-
- t = trigdesc->tg_before_statement;
- for (i = 0; i < 3; i++)
- if ( t[i] != NULL )
- pfree (t[i]);
- t = trigdesc->tg_before_row;
- for (i = 0; i < 3; i++)
- if ( t[i] != NULL )
- pfree (t[i]);
- t = trigdesc->tg_after_row;
- for (i = 0; i < 3; i++)
- if ( t[i] != NULL )
- pfree (t[i]);
- t = trigdesc->tg_after_statement;
- for (i = 0; i < 3; i++)
- if ( t[i] != NULL )
- pfree (t[i]);
-
- trigger = trigdesc->triggers;
- for (i = 0; i < relation->rd_rel->reltriggers; i++)
- {
- pfree (trigger->tgname);
- if ( trigger->tgnargs > 0 )
- {
- while ( --(trigger->tgnargs) >= 0 )
- pfree (trigger->tgargs[trigger->tgnargs]);
- pfree (trigger->tgargs);
- }
- trigger++;
- }
- pfree (trigdesc->triggers);
- pfree (trigdesc);
- relation->trigdesc = NULL;
- return;
+ TriggerDesc *trigdesc = relation->trigdesc;
+ Trigger ***t;
+ Trigger *trigger;
+ int i;
+
+ if (trigdesc == NULL)
+ return;
+
+ t = trigdesc->tg_before_statement;
+ for (i = 0; i < 3; i++)
+ if (t[i] != NULL)
+ pfree(t[i]);
+ t = trigdesc->tg_before_row;
+ for (i = 0; i < 3; i++)
+ if (t[i] != NULL)
+ pfree(t[i]);
+ t = trigdesc->tg_after_row;
+ for (i = 0; i < 3; i++)
+ if (t[i] != NULL)
+ pfree(t[i]);
+ t = trigdesc->tg_after_statement;
+ for (i = 0; i < 3; i++)
+ if (t[i] != NULL)
+ pfree(t[i]);
+
+ trigger = trigdesc->triggers;
+ for (i = 0; i < relation->rd_rel->reltriggers; i++)
+ {
+ pfree(trigger->tgname);
+ if (trigger->tgnargs > 0)
+ {
+ while (--(trigger->tgnargs) >= 0)
+ pfree(trigger->tgargs[trigger->tgnargs]);
+ pfree(trigger->tgargs);
+ }
+ trigger++;
+ }
+ pfree(trigdesc->triggers);
+ pfree(trigdesc);
+ relation->trigdesc = NULL;
+ return;
}
static void
-DescribeTrigger (TriggerDesc *trigdesc, Trigger *trigger)
+DescribeTrigger(TriggerDesc * trigdesc, Trigger * trigger)
{
- uint16 *n;
- Trigger ***t, ***tp;
-
- if ( TRIGGER_FOR_ROW (trigger->tgtype) ) /* Is ROW/STATEMENT trigger */
- {
- if ( TRIGGER_FOR_BEFORE (trigger->tgtype) )
- {
- n = trigdesc->n_before_row;
- t = trigdesc->tg_before_row;
- }
- else
- {
- n = trigdesc->n_after_row;
- t = trigdesc->tg_after_row;
- }
- }
- else /* STATEMENT (NI) */
- {
- if ( TRIGGER_FOR_BEFORE (trigger->tgtype) )
- {
- n = trigdesc->n_before_statement;
- t = trigdesc->tg_before_statement;
- }
- else
- {
- n = trigdesc->n_after_statement;
- t = trigdesc->tg_after_statement;
- }
- }
-
- if ( TRIGGER_FOR_INSERT (trigger->tgtype) )
- {
- tp = &(t[TRIGGER_EVENT_INSERT]);
- if ( *tp == NULL )
- *tp = (Trigger **) palloc (sizeof (Trigger *));
- else
- *tp = (Trigger **) repalloc (*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
- sizeof (Trigger *));
- (*tp)[n[TRIGGER_EVENT_INSERT]] = trigger;
- (n[TRIGGER_EVENT_INSERT])++;
- }
-
- if ( TRIGGER_FOR_DELETE (trigger->tgtype) )
- {
- tp = &(t[TRIGGER_EVENT_DELETE]);
- if ( *tp == NULL )
- *tp = (Trigger **) palloc (sizeof (Trigger *));
- else
- *tp = (Trigger **) repalloc (*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
- sizeof (Trigger *));
- (*tp)[n[TRIGGER_EVENT_DELETE]] = trigger;
- (n[TRIGGER_EVENT_DELETE])++;
- }
-
- if ( TRIGGER_FOR_UPDATE (trigger->tgtype) )
- {
- tp = &(t[TRIGGER_EVENT_UPDATE]);
- if ( *tp == NULL )
- *tp = (Trigger **) palloc (sizeof (Trigger *));
- else
- *tp = (Trigger **) repalloc (*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
- sizeof (Trigger *));
- (*tp)[n[TRIGGER_EVENT_UPDATE]] = trigger;
- (n[TRIGGER_EVENT_UPDATE])++;
- }
-
+ uint16 *n;
+ Trigger ***t,
+ ***tp;
+
+ if (TRIGGER_FOR_ROW(trigger->tgtype)) /* Is ROW/STATEMENT
+ * trigger */
+ {
+ if (TRIGGER_FOR_BEFORE(trigger->tgtype))
+ {
+ n = trigdesc->n_before_row;
+ t = trigdesc->tg_before_row;
+ }
+ else
+ {
+ n = trigdesc->n_after_row;
+ t = trigdesc->tg_after_row;
+ }
+ }
+ else
+/* STATEMENT (NI) */
+ {
+ if (TRIGGER_FOR_BEFORE(trigger->tgtype))
+ {
+ n = trigdesc->n_before_statement;
+ t = trigdesc->tg_before_statement;
+ }
+ else
+ {
+ n = trigdesc->n_after_statement;
+ t = trigdesc->tg_after_statement;
+ }
+ }
+
+ if (TRIGGER_FOR_INSERT(trigger->tgtype))
+ {
+ tp = &(t[TRIGGER_EVENT_INSERT]);
+ if (*tp == NULL)
+ *tp = (Trigger **) palloc(sizeof(Trigger *));
+ else
+ *tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_INSERT] + 1) *
+ sizeof(Trigger *));
+ (*tp)[n[TRIGGER_EVENT_INSERT]] = trigger;
+ (n[TRIGGER_EVENT_INSERT])++;
+ }
+
+ if (TRIGGER_FOR_DELETE(trigger->tgtype))
+ {
+ tp = &(t[TRIGGER_EVENT_DELETE]);
+ if (*tp == NULL)
+ *tp = (Trigger **) palloc(sizeof(Trigger *));
+ else
+ *tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_DELETE] + 1) *
+ sizeof(Trigger *));
+ (*tp)[n[TRIGGER_EVENT_DELETE]] = trigger;
+ (n[TRIGGER_EVENT_DELETE])++;
+ }
+
+ if (TRIGGER_FOR_UPDATE(trigger->tgtype))
+ {
+ tp = &(t[TRIGGER_EVENT_UPDATE]);
+ if (*tp == NULL)
+ *tp = (Trigger **) palloc(sizeof(Trigger *));
+ else
+ *tp = (Trigger **) repalloc(*tp, (n[TRIGGER_EVENT_UPDATE] + 1) *
+ sizeof(Trigger *));
+ (*tp)[n[TRIGGER_EVENT_UPDATE]] = trigger;
+ (n[TRIGGER_EVENT_UPDATE])++;
+ }
+
}
-HeapTuple
-ExecBRInsertTriggers (Relation rel, HeapTuple tuple)
+HeapTuple
+ExecBRInsertTriggers(Relation rel, HeapTuple tuple)
{
- int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
- Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
- HeapTuple newtuple = tuple;
- int nargs;
- int i;
-
- CurrentTriggerData = (TriggerData *) palloc (sizeof (TriggerData));
- CurrentTriggerData->tg_event = TRIGGER_EVENT_INSERT|TRIGGER_EVENT_ROW;
- CurrentTriggerData->tg_relation = rel;
- CurrentTriggerData->tg_newtuple = NULL;
- for (i = 0; i < ntrigs; i++)
- {
- CurrentTriggerData->tg_trigtuple = newtuple;
- CurrentTriggerData->tg_trigger = trigger[i];
- if ( trigger[i]->tgfunc == NULL )
- fmgr_info (trigger[i]->tgfoid, &(trigger[i]->tgfunc), &nargs);
- newtuple = (HeapTuple) ( (*(trigger[i]->tgfunc)) () );
- if ( newtuple == NULL )
- break;
- }
- pfree (CurrentTriggerData);
- CurrentTriggerData = NULL;
- return (newtuple);
+ int ntrigs = rel->trigdesc->n_before_row[TRIGGER_EVENT_INSERT];
+ Trigger **trigger = rel->trigdesc->tg_before_row[TRIGGER_EVENT_INSERT];
+ HeapTuple newtuple = tuple;
+ int nargs;
+ int i;
+
+ CurrentTriggerData = (TriggerData *) palloc(sizeof(TriggerData));
+ CurrentTriggerData->tg_event = TRIGGER_EVENT_INSERT | TRIGGER_EVENT_ROW;
+ CurrentTriggerData->tg_relation = rel;
+ CurrentTriggerData->tg_newtuple = NULL;
+ for (i = 0; i < ntrigs; i++)
+ {
+ CurrentTriggerData->tg_trigtuple = newtuple;
+ CurrentTriggerData->tg_trigger = trigger[i];
+ if (trigger[i]->tgfunc == NULL)
+ fmgr_info(trigger[i]->tgfoid, &(trigger[i]->tgfunc), &nargs);
+ newtuple = (HeapTuple) ((*(trigger[i]->tgfunc)) ());
+ if (newtuple == NULL)
+ break;
+ }
+ pfree(CurrentTriggerData);
+ CurrentTriggerData = NULL;
+ return (newtuple);
}
void
-ExecARInsertTriggers (Relation rel, HeapTuple tuple)
+ExecARInsertTriggers(Relation rel, HeapTuple tuple)
{
-
- return;
+
+ return;
}
bool
-ExecBRDeleteTriggers (Relation rel, ItemPointer tupleid)
+ExecBRDeleteTriggers(Relation rel, ItemPointer tupleid)
{
-
- return (true);
+
+ return (true);
}
void
-ExecARDeleteTriggers (Relation rel, ItemPointer tupleid)
+ExecARDeleteTriggers(Relation rel, ItemPointer tupleid)
{
-
- return;
+
+ return;
}
HeapTuple
-ExecBRUpdateTriggers (Relation rel, ItemPointer tupleid, HeapTuple tuple)
+ExecBRUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple tuple)
{
-
- return (tuple);
+
+ return (tuple);
}
void
-ExecARUpdateTriggers (Relation rel, ItemPointer tupleid, HeapTuple tuple)
+ExecARUpdateTriggers(Relation rel, ItemPointer tupleid, HeapTuple tuple)
{
-
- return;
+
+ return;
}
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index 0c480581179..30690f0f32b 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* vacuum.c--
- * the postgres vacuum cleaner
+ * the postgres vacuum cleaner
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.42 1997/08/22 04:13:08 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/vacuum.c,v 1.43 1997/09/07 04:41:02 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -48,2220 +48,2364 @@
#include <storage/bufpage.h>
#include "storage/shmem.h"
#ifndef HAVE_GETRUSAGE
-# include <rusagestub.h>
-#else
-# include <sys/time.h>
-# include <sys/resource.h>
-#endif
+#include <rusagestub.h>
+#else
+#include <sys/time.h>
+#include <sys/resource.h>
+#endif
#include <port-protos.h>
-bool VacuumRunning = false;
+bool VacuumRunning = false;
-static Portal vc_portal;
+static Portal vc_portal;
-static int MESSAGE_LEVEL; /* message level */
+static int MESSAGE_LEVEL; /* message level */
#define swapLong(a,b) {long tmp; tmp=a; a=b; b=tmp;}
#define swapInt(a,b) {int tmp; tmp=a; a=b; b=tmp;}
#define swapDatum(a,b) {Datum tmp; tmp=a; a=b; b=tmp;}
#define VacAttrStatsEqValid(stats) ( stats->f_cmpeq != NULL )
#define VacAttrStatsLtGtValid(stats) ( stats->f_cmplt != NULL && \
- stats->f_cmpgt != NULL && \
- RegProcedureIsValid(stats->outfunc) )
-
+ stats->f_cmpgt != NULL && \
+ RegProcedureIsValid(stats->outfunc) )
+
/* non-export function prototypes */
-static void vc_init(void);
-static void vc_shutdown(void);
-static void vc_vacuum(NameData *VacRelP, bool analyze, List *va_cols);
-static VRelList vc_getrels(NameData *VacRelP);
-static void vc_vacone (Oid relid, bool analyze, List *va_cols);
-static void vc_scanheap (VRelStats *vacrelstats, Relation onerel, VPageList Vvpl, VPageList Fvpl);
-static void vc_rpfheap (VRelStats *vacrelstats, Relation onerel, VPageList Vvpl, VPageList Fvpl, int nindices, Relation *Irel);
-static void vc_vacheap (VRelStats *vacrelstats, Relation onerel, VPageList vpl);
-static void vc_vacpage (Page page, VPageDescr vpd, Relation archrel);
-static void vc_vaconeind (VPageList vpl, Relation indrel, int nhtups);
-static void vc_scanoneind (Relation indrel, int nhtups);
-static void vc_attrstats(Relation onerel, VRelStats *vacrelstats, HeapTuple htup);
-static void vc_bucketcpy(AttributeTupleForm attr, Datum value, Datum *bucket, int16 *bucket_len);
-static void vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VRelStats *vacrelstats);
-static void vc_delhilowstats (Oid relid, int attcnt, int *attnums);
-static void vc_setpagelock(Relation rel, BlockNumber blkno);
-static VPageDescr vc_tidreapped (ItemPointer itemptr, VPageList vpl);
-static void vc_reappage (VPageList vpl, VPageDescr vpc);
-static void vc_vpinsert (VPageList vpl, VPageDescr vpnew);
-static void vc_free(VRelList vrl);
-static void vc_getindices (Oid relid, int *nindices, Relation **Irel);
-static void vc_clsindices (int nindices, Relation *Irel);
+static void vc_init(void);
+static void vc_shutdown(void);
+static void vc_vacuum(NameData * VacRelP, bool analyze, List * va_cols);
+static VRelList vc_getrels(NameData * VacRelP);
+static void vc_vacone(Oid relid, bool analyze, List * va_cols);
+static void vc_scanheap(VRelStats * vacrelstats, Relation onerel, VPageList Vvpl, VPageList Fvpl);
+static void vc_rpfheap(VRelStats * vacrelstats, Relation onerel, VPageList Vvpl, VPageList Fvpl, int nindices, Relation * Irel);
+static void vc_vacheap(VRelStats * vacrelstats, Relation onerel, VPageList vpl);
+static void vc_vacpage(Page page, VPageDescr vpd, Relation archrel);
+static void vc_vaconeind(VPageList vpl, Relation indrel, int nhtups);
+static void vc_scanoneind(Relation indrel, int nhtups);
+static void vc_attrstats(Relation onerel, VRelStats * vacrelstats, HeapTuple htup);
+static void vc_bucketcpy(AttributeTupleForm attr, Datum value, Datum * bucket, int16 * bucket_len);
+static void vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VRelStats * vacrelstats);
+static void vc_delhilowstats(Oid relid, int attcnt, int *attnums);
+static void vc_setpagelock(Relation rel, BlockNumber blkno);
+static VPageDescr vc_tidreapped(ItemPointer itemptr, VPageList vpl);
+static void vc_reappage(VPageList vpl, VPageDescr vpc);
+static void vc_vpinsert(VPageList vpl, VPageDescr vpnew);
+static void vc_free(VRelList vrl);
+static void vc_getindices(Oid relid, int *nindices, Relation ** Irel);
+static void vc_clsindices(int nindices, Relation * Irel);
static Relation vc_getarchrel(Relation heaprel);
-static void vc_archive(Relation archrel, HeapTuple htup);
-static bool vc_isarchrel(char *rname);
-static void vc_mkindesc (Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc);
-static char * vc_find_eq (char *bot, int nelem, int size, char *elm, int (*compar)(char *, char *));
-static int vc_cmp_blk (char *left, char *right);
-static int vc_cmp_offno (char *left, char *right);
-static bool vc_enough_space (VPageDescr vpd, Size len);
+static void vc_archive(Relation archrel, HeapTuple htup);
+static bool vc_isarchrel(char *rname);
+static void vc_mkindesc(Relation onerel, int nindices, Relation * Irel, IndDesc ** Idesc);
+static char *vc_find_eq(char *bot, int nelem, int size, char *elm, int (*compar) (char *, char *));
+static int vc_cmp_blk(char *left, char *right);
+static int vc_cmp_offno(char *left, char *right);
+static bool vc_enough_space(VPageDescr vpd, Size len);
void
-vacuum(char *vacrel, bool verbose, bool analyze, List *va_spec)
+vacuum(char *vacrel, bool verbose, bool analyze, List * va_spec)
{
- char *pname;
- MemoryContext old;
- PortalVariableMemory pmem;
- NameData VacRel;
- List *le;
- List *va_cols = NIL;
-
- /*
- * Create a portal for safe memory across transctions. We need to
- * palloc the name space for it because our hash function expects
- * the name to be on a longword boundary. CreatePortal copies the
- * name to safe storage for us.
- */
- pname = (char *) palloc(strlen(VACPNAME) + 1);
- strcpy(pname, VACPNAME);
- vc_portal = CreatePortal(pname);
- pfree(pname);
-
- if (verbose)
- MESSAGE_LEVEL = NOTICE;
- else
- MESSAGE_LEVEL = DEBUG;
-
- /* vacrel gets de-allocated on transaction commit */
- if (vacrel)
- strcpy(VacRel.data,vacrel);
-
- pmem = PortalGetVariableMemory(vc_portal);
- old = MemoryContextSwitchTo((MemoryContext)pmem);
-
- Assert ( va_spec == NIL || analyze );
- foreach (le, va_spec)
- {
- char *col = (char*)lfirst(le);
- char *dest;
-
- dest = (char*) palloc (strlen (col) + 1);
- strcpy (dest, col);
- va_cols = lappend (va_cols, dest);
- }
- MemoryContextSwitchTo(old);
-
- /* initialize vacuum cleaner */
- vc_init();
-
- /* vacuum the database */
- if (vacrel)
- vc_vacuum (&VacRel, analyze, va_cols);
- else
- vc_vacuum (NULL, analyze, NIL);
-
- PortalDestroy (&vc_portal);
-
- /* clean up */
- vc_shutdown();
+ char *pname;
+ MemoryContext old;
+ PortalVariableMemory pmem;
+ NameData VacRel;
+ List *le;
+ List *va_cols = NIL;
+
+ /*
+ * Create a portal for safe memory across transctions. We need to
+ * palloc the name space for it because our hash function expects the
+ * name to be on a longword boundary. CreatePortal copies the name to
+ * safe storage for us.
+ */
+ pname = (char *) palloc(strlen(VACPNAME) + 1);
+ strcpy(pname, VACPNAME);
+ vc_portal = CreatePortal(pname);
+ pfree(pname);
+
+ if (verbose)
+ MESSAGE_LEVEL = NOTICE;
+ else
+ MESSAGE_LEVEL = DEBUG;
+
+ /* vacrel gets de-allocated on transaction commit */
+ if (vacrel)
+ strcpy(VacRel.data, vacrel);
+
+ pmem = PortalGetVariableMemory(vc_portal);
+ old = MemoryContextSwitchTo((MemoryContext) pmem);
+
+ Assert(va_spec == NIL || analyze);
+ foreach(le, va_spec)
+ {
+ char *col = (char *) lfirst(le);
+ char *dest;
+
+ dest = (char *) palloc(strlen(col) + 1);
+ strcpy(dest, col);
+ va_cols = lappend(va_cols, dest);
+ }
+ MemoryContextSwitchTo(old);
+
+ /* initialize vacuum cleaner */
+ vc_init();
+
+ /* vacuum the database */
+ if (vacrel)
+ vc_vacuum(&VacRel, analyze, va_cols);
+ else
+ vc_vacuum(NULL, analyze, NIL);
+
+ PortalDestroy(&vc_portal);
+
+ /* clean up */
+ vc_shutdown();
}
/*
- * vc_init(), vc_shutdown() -- start up and shut down the vacuum cleaner.
+ * vc_init(), vc_shutdown() -- start up and shut down the vacuum cleaner.
*
- * We run exactly one vacuum cleaner at a time. We use the file system
- * to guarantee an exclusive lock on vacuuming, since a single vacuum
- * cleaner instantiation crosses transaction boundaries, and we'd lose
- * postgres-style locks at the end of every transaction.
+ * We run exactly one vacuum cleaner at a time. We use the file system
+ * to guarantee an exclusive lock on vacuuming, since a single vacuum
+ * cleaner instantiation crosses transaction boundaries, and we'd lose
+ * postgres-style locks at the end of every transaction.
*
- * The strangeness with committing and starting transactions in the
- * init and shutdown routines is due to the fact that the vacuum cleaner
- * is invoked via a sql command, and so is already executing inside
- * a transaction. We need to leave ourselves in a predictable state
- * on entry and exit to the vacuum cleaner. We commit the transaction
- * started in PostgresMain() inside vc_init(), and start one in
- * vc_shutdown() to match the commit waiting for us back in
- * PostgresMain().
+ * The strangeness with committing and starting transactions in the
+ * init and shutdown routines is due to the fact that the vacuum cleaner
+ * is invoked via a sql command, and so is already executing inside
+ * a transaction. We need to leave ourselves in a predictable state
+ * on entry and exit to the vacuum cleaner. We commit the transaction
+ * started in PostgresMain() inside vc_init(), and start one in
+ * vc_shutdown() to match the commit waiting for us back in
+ * PostgresMain().
*/
static void
vc_init()
{
- int fd;
+ int fd;
- if ((fd = open("pg_vlock", O_CREAT|O_EXCL, 0600)) < 0)
- elog(WARN, "can't create lock file -- another vacuum cleaner running?");
+ if ((fd = open("pg_vlock", O_CREAT | O_EXCL, 0600)) < 0)
+ elog(WARN, "can't create lock file -- another vacuum cleaner running?");
- close(fd);
+ close(fd);
- /*
- * By here, exclusive open on the lock file succeeded. If we abort
- * for any reason during vacuuming, we need to remove the lock file.
- * This global variable is checked in the transaction manager on xact
- * abort, and the routine vc_abort() is called if necessary.
- */
+ /*
+ * By here, exclusive open on the lock file succeeded. If we abort
+ * for any reason during vacuuming, we need to remove the lock file.
+ * This global variable is checked in the transaction manager on xact
+ * abort, and the routine vc_abort() is called if necessary.
+ */
- VacuumRunning = true;
+ VacuumRunning = true;
- /* matches the StartTransaction in PostgresMain() */
- CommitTransactionCommand();
+ /* matches the StartTransaction in PostgresMain() */
+ CommitTransactionCommand();
}
static void
vc_shutdown()
{
- /* on entry, not in a transaction */
- if (unlink("pg_vlock") < 0)
- elog(WARN, "vacuum: can't destroy lock file!");
+ /* on entry, not in a transaction */
+ if (unlink("pg_vlock") < 0)
+ elog(WARN, "vacuum: can't destroy lock file!");
- /* okay, we're done */
- VacuumRunning = false;
+ /* okay, we're done */
+ VacuumRunning = false;
- /* matches the CommitTransaction in PostgresMain() */
- StartTransactionCommand();
+ /* matches the CommitTransaction in PostgresMain() */
+ StartTransactionCommand();
}
void
vc_abort()
{
- /* on abort, remove the vacuum cleaner lock file */
- unlink("pg_vlock");
+ /* on abort, remove the vacuum cleaner lock file */
+ unlink("pg_vlock");
- VacuumRunning = false;
+ VacuumRunning = false;
}
/*
- * vc_vacuum() -- vacuum the database.
+ * vc_vacuum() -- vacuum the database.
*
- * This routine builds a list of relations to vacuum, and then calls
- * code that vacuums them one at a time. We are careful to vacuum each
- * relation in a separate transaction in order to avoid holding too many
- * locks at one time.
+ * This routine builds a list of relations to vacuum, and then calls
+ * code that vacuums them one at a time. We are careful to vacuum each
+ * relation in a separate transaction in order to avoid holding too many
+ * locks at one time.
*/
static void
-vc_vacuum(NameData *VacRelP, bool analyze, List *va_cols)
+vc_vacuum(NameData * VacRelP, bool analyze, List * va_cols)
{
- VRelList vrl, cur;
+ VRelList vrl,
+ cur;
+
+ /* get list of relations */
+ vrl = vc_getrels(VacRelP);
- /* get list of relations */
- vrl = vc_getrels(VacRelP);
+ if (analyze && VacRelP == NULL && vrl != NULL)
+ vc_delhilowstats(InvalidOid, 0, NULL);
- if ( analyze && VacRelP == NULL && vrl != NULL )
- vc_delhilowstats (InvalidOid, 0, NULL);
-
- /* vacuum each heap relation */
- for (cur = vrl; cur != (VRelList) NULL; cur = cur->vrl_next)
- vc_vacone (cur->vrl_relid, analyze, va_cols);
+ /* vacuum each heap relation */
+ for (cur = vrl; cur != (VRelList) NULL; cur = cur->vrl_next)
+ vc_vacone(cur->vrl_relid, analyze, va_cols);
- vc_free(vrl);
+ vc_free(vrl);
}
-static VRelList
-vc_getrels(NameData *VacRelP)
+static VRelList
+vc_getrels(NameData * VacRelP)
{
- Relation pgclass;
- TupleDesc pgcdesc;
- HeapScanDesc pgcscan;
- HeapTuple pgctup;
- Buffer buf;
- PortalVariableMemory portalmem;
- MemoryContext old;
- VRelList vrl, cur;
- Datum d;
- char *rname;
- char rkind;
- int16 smgrno;
- bool n;
- ScanKeyData pgckey;
- bool found = false;
-
- StartTransactionCommand();
-
- if (VacRelP->data) {
- ScanKeyEntryInitialize(&pgckey, 0x0, Anum_pg_class_relname,
- NameEqualRegProcedure,
- PointerGetDatum(VacRelP->data));
- } else {
- ScanKeyEntryInitialize(&pgckey, 0x0, Anum_pg_class_relkind,
- CharacterEqualRegProcedure, CharGetDatum('r'));
- }
-
- portalmem = PortalGetVariableMemory(vc_portal);
- vrl = cur = (VRelList) NULL;
-
- pgclass = heap_openr(RelationRelationName);
- pgcdesc = RelationGetTupleDescriptor(pgclass);
-
- pgcscan = heap_beginscan(pgclass, false, NowTimeQual, 1, &pgckey);
-
- while (HeapTupleIsValid(pgctup = heap_getnext(pgcscan, 0, &buf))) {
-
- found = true;
-
- /*
- * We have to be careful not to vacuum the archive (since it
- * already contains vacuumed tuples), and not to vacuum
- * relations on write-once storage managers like the Sony
- * jukebox at Berkeley.
- */
+ Relation pgclass;
+ TupleDesc pgcdesc;
+ HeapScanDesc pgcscan;
+ HeapTuple pgctup;
+ Buffer buf;
+ PortalVariableMemory portalmem;
+ MemoryContext old;
+ VRelList vrl,
+ cur;
+ Datum d;
+ char *rname;
+ char rkind;
+ int16 smgrno;
+ bool n;
+ ScanKeyData pgckey;
+ bool found = false;
+
+ StartTransactionCommand();
+
+ if (VacRelP->data)
+ {
+ ScanKeyEntryInitialize(&pgckey, 0x0, Anum_pg_class_relname,
+ NameEqualRegProcedure,
+ PointerGetDatum(VacRelP->data));
+ }
+ else
+ {
+ ScanKeyEntryInitialize(&pgckey, 0x0, Anum_pg_class_relkind,
+ CharacterEqualRegProcedure, CharGetDatum('r'));
+ }
- d = (Datum) heap_getattr(pgctup, buf, Anum_pg_class_relname,
- pgcdesc, &n);
- rname = (char*)d;
+ portalmem = PortalGetVariableMemory(vc_portal);
+ vrl = cur = (VRelList) NULL;
- /* skip archive relations */
- if (vc_isarchrel(rname)) {
- ReleaseBuffer(buf);
- continue;
- }
+ pgclass = heap_openr(RelationRelationName);
+ pgcdesc = RelationGetTupleDescriptor(pgclass);
+
+ pgcscan = heap_beginscan(pgclass, false, NowTimeQual, 1, &pgckey);
- /* don't vacuum large objects for now - something breaks when we do */
- if ( (strlen(rname) >= 5) && rname[0] == 'x' &&
- rname[1] == 'i' && rname[2] == 'n' &&
- (rname[3] == 'v' || rname[3] == 'x') &&
- rname[4] >= '0' && rname[4] <= '9')
+ while (HeapTupleIsValid(pgctup = heap_getnext(pgcscan, 0, &buf)))
{
- elog (NOTICE, "Rel %s: can't vacuum LargeObjects now",
- rname);
- ReleaseBuffer(buf);
- continue;
- }
- d = (Datum) heap_getattr(pgctup, buf, Anum_pg_class_relsmgr,
- pgcdesc, &n);
- smgrno = DatumGetInt16(d);
+ found = true;
- /* skip write-once storage managers */
- if (smgriswo(smgrno)) {
- ReleaseBuffer(buf);
- continue;
- }
+ /*
+ * We have to be careful not to vacuum the archive (since it
+ * already contains vacuumed tuples), and not to vacuum relations
+ * on write-once storage managers like the Sony jukebox at
+ * Berkeley.
+ */
- d = (Datum) heap_getattr(pgctup, buf, Anum_pg_class_relkind,
- pgcdesc, &n);
+ d = (Datum) heap_getattr(pgctup, buf, Anum_pg_class_relname,
+ pgcdesc, &n);
+ rname = (char *) d;
- rkind = DatumGetChar(d);
+ /* skip archive relations */
+ if (vc_isarchrel(rname))
+ {
+ ReleaseBuffer(buf);
+ continue;
+ }
- /* skip system relations */
- if (rkind != 'r') {
- ReleaseBuffer(buf);
- elog(NOTICE, "Vacuum: can not process index and certain system tables" );
- continue;
- }
-
- /* get a relation list entry for this guy */
- old = MemoryContextSwitchTo((MemoryContext)portalmem);
- if (vrl == (VRelList) NULL) {
- vrl = cur = (VRelList) palloc(sizeof(VRelListData));
- } else {
- cur->vrl_next = (VRelList) palloc(sizeof(VRelListData));
- cur = cur->vrl_next;
- }
- MemoryContextSwitchTo(old);
+ /*
+ * don't vacuum large objects for now - something breaks when we
+ * do
+ */
+ if ((strlen(rname) >= 5) && rname[0] == 'x' &&
+ rname[1] == 'i' && rname[2] == 'n' &&
+ (rname[3] == 'v' || rname[3] == 'x') &&
+ rname[4] >= '0' && rname[4] <= '9')
+ {
+ elog(NOTICE, "Rel %s: can't vacuum LargeObjects now",
+ rname);
+ ReleaseBuffer(buf);
+ continue;
+ }
+
+ d = (Datum) heap_getattr(pgctup, buf, Anum_pg_class_relsmgr,
+ pgcdesc, &n);
+ smgrno = DatumGetInt16(d);
+
+ /* skip write-once storage managers */
+ if (smgriswo(smgrno))
+ {
+ ReleaseBuffer(buf);
+ continue;
+ }
+
+ d = (Datum) heap_getattr(pgctup, buf, Anum_pg_class_relkind,
+ pgcdesc, &n);
+
+ rkind = DatumGetChar(d);
+
+ /* skip system relations */
+ if (rkind != 'r')
+ {
+ ReleaseBuffer(buf);
+ elog(NOTICE, "Vacuum: can not process index and certain system tables");
+ continue;
+ }
- cur->vrl_relid = pgctup->t_oid;
- cur->vrl_next = (VRelList) NULL;
+ /* get a relation list entry for this guy */
+ old = MemoryContextSwitchTo((MemoryContext) portalmem);
+ if (vrl == (VRelList) NULL)
+ {
+ vrl = cur = (VRelList) palloc(sizeof(VRelListData));
+ }
+ else
+ {
+ cur->vrl_next = (VRelList) palloc(sizeof(VRelListData));
+ cur = cur->vrl_next;
+ }
+ MemoryContextSwitchTo(old);
- /* wei hates it if you forget to do this */
- ReleaseBuffer(buf);
- }
- if (found == false)
- elog(NOTICE, "Vacuum: table not found" );
+ cur->vrl_relid = pgctup->t_oid;
+ cur->vrl_next = (VRelList) NULL;
-
- heap_endscan(pgcscan);
- heap_close(pgclass);
+ /* wei hates it if you forget to do this */
+ ReleaseBuffer(buf);
+ }
+ if (found == false)
+ elog(NOTICE, "Vacuum: table not found");
+
+
+ heap_endscan(pgcscan);
+ heap_close(pgclass);
- CommitTransactionCommand();
+ CommitTransactionCommand();
- return (vrl);
+ return (vrl);
}
/*
- * vc_vacone() -- vacuum one heap relation
+ * vc_vacone() -- vacuum one heap relation
*
- * This routine vacuums a single heap, cleans out its indices, and
- * updates its statistics npages and ntups statistics.
+ * This routine vacuums a single heap, cleans out its indices, and
+ * updates its statistics npages and ntups statistics.
*
- * Doing one heap at a time incurs extra overhead, since we need to
- * check that the heap exists again just before we vacuum it. The
- * reason that we do this is so that vacuuming can be spread across
- * many small transactions. Otherwise, two-phase locking would require
- * us to lock the entire database during one pass of the vacuum cleaner.
+ * Doing one heap at a time incurs extra overhead, since we need to
+ * check that the heap exists again just before we vacuum it. The
+ * reason that we do this is so that vacuuming can be spread across
+ * many small transactions. Otherwise, two-phase locking would require
+ * us to lock the entire database during one pass of the vacuum cleaner.
*/
static void
-vc_vacone (Oid relid, bool analyze, List *va_cols)
+vc_vacone(Oid relid, bool analyze, List * va_cols)
{
- Relation pgclass;
- TupleDesc pgcdesc;
- HeapTuple pgctup, pgttup;
- Buffer pgcbuf;
- HeapScanDesc pgcscan;
- Relation onerel;
- ScanKeyData pgckey;
- VPageListData Vvpl; /* List of pages to vacuum and/or clean indices */
- VPageListData Fvpl; /* List of pages with space enough for re-using */
- VPageDescr *vpp;
- Relation *Irel;
- int32 nindices, i;
- VRelStats *vacrelstats;
-
- StartTransactionCommand();
-
- ScanKeyEntryInitialize(&pgckey, 0x0, ObjectIdAttributeNumber,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(relid));
-
- pgclass = heap_openr(RelationRelationName);
- pgcdesc = RelationGetTupleDescriptor(pgclass);
- pgcscan = heap_beginscan(pgclass, false, NowTimeQual, 1, &pgckey);
-
- /*
- * Race condition -- if the pg_class tuple has gone away since the
- * last time we saw it, we don't need to vacuum it.
- */
-
- if (!HeapTupleIsValid(pgctup = heap_getnext(pgcscan, 0, &pgcbuf))) {
+ Relation pgclass;
+ TupleDesc pgcdesc;
+ HeapTuple pgctup,
+ pgttup;
+ Buffer pgcbuf;
+ HeapScanDesc pgcscan;
+ Relation onerel;
+ ScanKeyData pgckey;
+ VPageListData Vvpl; /* List of pages to vacuum and/or clean
+ * indices */
+ VPageListData Fvpl; /* List of pages with space enough for
+ * re-using */
+ VPageDescr *vpp;
+ Relation *Irel;
+ int32 nindices,
+ i;
+ VRelStats *vacrelstats;
+
+ StartTransactionCommand();
+
+ ScanKeyEntryInitialize(&pgckey, 0x0, ObjectIdAttributeNumber,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(relid));
+
+ pgclass = heap_openr(RelationRelationName);
+ pgcdesc = RelationGetTupleDescriptor(pgclass);
+ pgcscan = heap_beginscan(pgclass, false, NowTimeQual, 1, &pgckey);
+
+ /*
+ * Race condition -- if the pg_class tuple has gone away since the
+ * last time we saw it, we don't need to vacuum it.
+ */
+
+ if (!HeapTupleIsValid(pgctup = heap_getnext(pgcscan, 0, &pgcbuf)))
+ {
+ heap_endscan(pgcscan);
+ heap_close(pgclass);
+ CommitTransactionCommand();
+ return;
+ }
+
+ /* now open the class and vacuum it */
+ onerel = heap_open(relid);
+
+ vacrelstats = (VRelStats *) palloc(sizeof(VRelStats));
+ vacrelstats->relid = relid;
+ vacrelstats->npages = vacrelstats->ntups = 0;
+ vacrelstats->hasindex = false;
+ if (analyze && !IsSystemRelationName((RelationGetRelationName(onerel))->data))
+ {
+ int attr_cnt,
+ *attnums = NULL;
+ AttributeTupleForm *attr;
+
+ attr_cnt = onerel->rd_att->natts;
+ attr = onerel->rd_att->attrs;
+
+ if (va_cols != NIL)
+ {
+ int tcnt = 0;
+ List *le;
+
+ if (length(va_cols) > attr_cnt)
+ elog(WARN, "vacuum: too many attributes specified for relation %s",
+ (RelationGetRelationName(onerel))->data);
+ attnums = (int *) palloc(attr_cnt * sizeof(int));
+ foreach(le, va_cols)
+ {
+ char *col = (char *) lfirst(le);
+
+ for (i = 0; i < attr_cnt; i++)
+ {
+ if (namestrcmp(&(attr[i]->attname), col) == 0)
+ break;
+ }
+ if (i < attr_cnt) /* found */
+ attnums[tcnt++] = i;
+ else
+ {
+ elog(WARN, "vacuum: there is no attribute %s in %s",
+ col, (RelationGetRelationName(onerel))->data);
+ }
+ }
+ attr_cnt = tcnt;
+ }
+
+ vacrelstats->vacattrstats =
+ (VacAttrStats *) palloc(attr_cnt * sizeof(VacAttrStats));
+
+ for (i = 0; i < attr_cnt; i++)
+ {
+ Operator func_operator;
+ OperatorTupleForm pgopform;
+ VacAttrStats *stats;
+
+ stats = &vacrelstats->vacattrstats[i];
+ stats->attr = palloc(ATTRIBUTE_TUPLE_SIZE);
+ memmove(stats->attr, attr[((attnums) ? attnums[i] : i)], ATTRIBUTE_TUPLE_SIZE);
+ stats->best = stats->guess1 = stats->guess2 = 0;
+ stats->max = stats->min = 0;
+ stats->best_len = stats->guess1_len = stats->guess2_len = 0;
+ stats->max_len = stats->min_len = 0;
+ stats->initialized = false;
+ stats->best_cnt = stats->guess1_cnt = stats->guess1_hits = stats->guess2_hits = 0;
+ stats->max_cnt = stats->min_cnt = stats->null_cnt = stats->nonnull_cnt = 0;
+
+ func_operator = oper("=", stats->attr->atttypid, stats->attr->atttypid, true);
+ if (func_operator != NULL)
+ {
+ int nargs;
+
+ pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
+ fmgr_info(pgopform->oprcode, &(stats->f_cmpeq), &nargs);
+ }
+ else
+ stats->f_cmpeq = NULL;
+
+ func_operator = oper("<", stats->attr->atttypid, stats->attr->atttypid, true);
+ if (func_operator != NULL)
+ {
+ int nargs;
+
+ pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
+ fmgr_info(pgopform->oprcode, &(stats->f_cmplt), &nargs);
+ }
+ else
+ stats->f_cmplt = NULL;
+
+ func_operator = oper(">", stats->attr->atttypid, stats->attr->atttypid, true);
+ if (func_operator != NULL)
+ {
+ int nargs;
+
+ pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
+ fmgr_info(pgopform->oprcode, &(stats->f_cmpgt), &nargs);
+ }
+ else
+ stats->f_cmpgt = NULL;
+
+ pgttup = SearchSysCacheTuple(TYPOID,
+ ObjectIdGetDatum(stats->attr->atttypid),
+ 0, 0, 0);
+ if (HeapTupleIsValid(pgttup))
+ stats->outfunc = ((TypeTupleForm) GETSTRUCT(pgttup))->typoutput;
+ else
+ stats->outfunc = InvalidOid;
+ }
+ vacrelstats->va_natts = attr_cnt;
+ vc_delhilowstats(relid, ((attnums) ? attr_cnt : 0), attnums);
+ if (attnums)
+ pfree(attnums);
+ }
+ else
+ {
+ vacrelstats->va_natts = 0;
+ vacrelstats->vacattrstats = (VacAttrStats *) NULL;
+ }
+
+ /* we require the relation to be locked until the indices are cleaned */
+ RelationSetLockForWrite(onerel);
+
+ /* scan it */
+ Vvpl.vpl_npages = Fvpl.vpl_npages = 0;
+ vc_scanheap(vacrelstats, onerel, &Vvpl, &Fvpl);
+
+ /* Now open indices */
+ Irel = (Relation *) NULL;
+ vc_getindices(vacrelstats->relid, &nindices, &Irel);
+
+ if (nindices > 0)
+ vacrelstats->hasindex = true;
+ else
+ vacrelstats->hasindex = false;
+
+ /* Clean/scan index relation(s) */
+ if (Irel != (Relation *) NULL)
+ {
+ if (Vvpl.vpl_npages > 0)
+ {
+ for (i = 0; i < nindices; i++)
+ vc_vaconeind(&Vvpl, Irel[i], vacrelstats->ntups);
+ }
+ else
+/* just scan indices to update statistic */
+ {
+ for (i = 0; i < nindices; i++)
+ vc_scanoneind(Irel[i], vacrelstats->ntups);
+ }
+ }
+
+ if (Fvpl.vpl_npages > 0) /* Try to shrink heap */
+ vc_rpfheap(vacrelstats, onerel, &Vvpl, &Fvpl, nindices, Irel);
+ else
+ {
+ if (Irel != (Relation *) NULL)
+ vc_clsindices(nindices, Irel);
+ if (Vvpl.vpl_npages > 0)/* Clean pages from Vvpl list */
+ vc_vacheap(vacrelstats, onerel, &Vvpl);
+ }
+
+ /* ok - free Vvpl list of reapped pages */
+ if (Vvpl.vpl_npages > 0)
+ {
+ vpp = Vvpl.vpl_pgdesc;
+ for (i = 0; i < Vvpl.vpl_npages; i++, vpp++)
+ pfree(*vpp);
+ pfree(Vvpl.vpl_pgdesc);
+ if (Fvpl.vpl_npages > 0)
+ pfree(Fvpl.vpl_pgdesc);
+ }
+
+ /* all done with this class */
+ heap_close(onerel);
heap_endscan(pgcscan);
heap_close(pgclass);
- CommitTransactionCommand();
- return;
- }
-
- /* now open the class and vacuum it */
- onerel = heap_open(relid);
-
- vacrelstats = (VRelStats *) palloc(sizeof(VRelStats));
- vacrelstats->relid = relid;
- vacrelstats->npages = vacrelstats->ntups = 0;
- vacrelstats->hasindex = false;
- if ( analyze && !IsSystemRelationName ((RelationGetRelationName (onerel))->data) )
- {
- int attr_cnt, *attnums = NULL;
- AttributeTupleForm *attr;
-
- attr_cnt = onerel->rd_att->natts;
- attr = onerel->rd_att->attrs;
-
- if ( va_cols != NIL )
- {
- int tcnt = 0;
- List *le;
-
- if ( length (va_cols) > attr_cnt )
- elog (WARN, "vacuum: too many attributes specified for relation %s",
- (RelationGetRelationName(onerel))->data);
- attnums = (int*) palloc (attr_cnt * sizeof (int));
- foreach (le, va_cols)
- {
- char *col = (char*) lfirst(le);
-
- for (i = 0; i < attr_cnt; i++)
- {
- if ( namestrcmp (&(attr[i]->attname), col) == 0 )
- break;
- }
- if ( i < attr_cnt ) /* found */
- attnums[tcnt++] = i;
- else
- {
- elog (WARN, "vacuum: there is no attribute %s in %s",
- col, (RelationGetRelationName(onerel))->data);
- }
- }
- attr_cnt = tcnt;
- }
-
- vacrelstats->vacattrstats =
- (VacAttrStats *) palloc (attr_cnt * sizeof(VacAttrStats));
-
- for (i = 0; i < attr_cnt; i++)
- {
- Operator func_operator;
- OperatorTupleForm pgopform;
- VacAttrStats *stats;
-
- stats = &vacrelstats->vacattrstats[i];
- stats->attr = palloc(ATTRIBUTE_TUPLE_SIZE);
- memmove (stats->attr, attr[((attnums) ? attnums[i] : i)], ATTRIBUTE_TUPLE_SIZE);
- stats->best = stats->guess1 = stats->guess2 = 0;
- stats->max = stats->min = 0;
- stats->best_len = stats->guess1_len = stats->guess2_len = 0;
- stats->max_len = stats->min_len = 0;
- stats->initialized = false;
- stats->best_cnt = stats->guess1_cnt = stats->guess1_hits = stats->guess2_hits = 0;
- stats->max_cnt = stats->min_cnt = stats->null_cnt = stats->nonnull_cnt = 0;
-
- func_operator = oper("=",stats->attr->atttypid,stats->attr->atttypid,true);
- if (func_operator != NULL)
- {
- int nargs;
-
- pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
- fmgr_info (pgopform->oprcode, &(stats->f_cmpeq), &nargs);
- }
- else
- stats->f_cmpeq = NULL;
-
- func_operator = oper("<",stats->attr->atttypid,stats->attr->atttypid,true);
- if (func_operator != NULL)
- {
- int nargs;
-
- pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
- fmgr_info (pgopform->oprcode, &(stats->f_cmplt), &nargs);
- }
- else
- stats->f_cmplt = NULL;
-
- func_operator = oper(">",stats->attr->atttypid,stats->attr->atttypid,true);
- if (func_operator != NULL)
- {
- int nargs;
-
- pgopform = (OperatorTupleForm) GETSTRUCT(func_operator);
- fmgr_info (pgopform->oprcode, &(stats->f_cmpgt), &nargs);
- }
- else
- stats->f_cmpgt = NULL;
-
- pgttup = SearchSysCacheTuple(TYPOID,
- ObjectIdGetDatum(stats->attr->atttypid),
- 0,0,0);
- if (HeapTupleIsValid(pgttup))
- stats->outfunc = ((TypeTupleForm) GETSTRUCT(pgttup))->typoutput;
- else
- stats->outfunc = InvalidOid;
- }
- vacrelstats->va_natts = attr_cnt;
- vc_delhilowstats (relid, ((attnums) ? attr_cnt : 0), attnums);
- if ( attnums )
- pfree (attnums);
- }
- else
- {
- vacrelstats->va_natts = 0;
- vacrelstats->vacattrstats = (VacAttrStats *) NULL;
- }
-
- /* we require the relation to be locked until the indices are cleaned */
- RelationSetLockForWrite(onerel);
-
- /* scan it */
- Vvpl.vpl_npages = Fvpl.vpl_npages = 0;
- vc_scanheap(vacrelstats, onerel, &Vvpl, &Fvpl);
-
- /* Now open indices */
- Irel = (Relation *) NULL;
- vc_getindices(vacrelstats->relid, &nindices, &Irel);
-
- if ( nindices > 0 )
- vacrelstats->hasindex = true;
- else
- vacrelstats->hasindex = false;
- /* Clean/scan index relation(s) */
- if ( Irel != (Relation*) NULL )
- {
- if ( Vvpl.vpl_npages > 0 )
- {
- for (i = 0; i < nindices; i++)
- vc_vaconeind (&Vvpl, Irel[i], vacrelstats->ntups);
- }
- else /* just scan indices to update statistic */
- {
- for (i = 0; i < nindices; i++)
- vc_scanoneind (Irel[i], vacrelstats->ntups);
- }
- }
-
- if ( Fvpl.vpl_npages > 0 ) /* Try to shrink heap */
- vc_rpfheap (vacrelstats, onerel, &Vvpl, &Fvpl, nindices, Irel);
- else
- {
- if ( Irel != (Relation*) NULL )
- vc_clsindices (nindices, Irel);
- if ( Vvpl.vpl_npages > 0 ) /* Clean pages from Vvpl list */
- vc_vacheap (vacrelstats, onerel, &Vvpl);
- }
-
- /* ok - free Vvpl list of reapped pages */
- if ( Vvpl.vpl_npages > 0 )
- {
- vpp = Vvpl.vpl_pgdesc;
- for (i = 0; i < Vvpl.vpl_npages; i++, vpp++)
- pfree(*vpp);
- pfree (Vvpl.vpl_pgdesc);
- if ( Fvpl.vpl_npages > 0 )
- pfree (Fvpl.vpl_pgdesc);
- }
-
- /* all done with this class */
- heap_close(onerel);
- heap_endscan(pgcscan);
- heap_close(pgclass);
-
- /* update statistics in pg_class */
- vc_updstats(vacrelstats->relid, vacrelstats->npages, vacrelstats->ntups,
- vacrelstats->hasindex, vacrelstats);
-
- /* next command frees attribute stats */
-
- CommitTransactionCommand();
+ /* update statistics in pg_class */
+ vc_updstats(vacrelstats->relid, vacrelstats->npages, vacrelstats->ntups,
+ vacrelstats->hasindex, vacrelstats);
+
+ /* next command frees attribute stats */
+
+ CommitTransactionCommand();
}
/*
- * vc_scanheap() -- scan an open heap relation
+ * vc_scanheap() -- scan an open heap relation
*
- * This routine sets commit times, constructs Vvpl list of
- * empty/uninitialized pages and pages with dead tuples and
- * ~LP_USED line pointers, constructs Fvpl list of pages
- * appropriate for purposes of shrinking and maintains statistics
- * on the number of live tuples in a heap.
+ * This routine sets commit times, constructs Vvpl list of
+ * empty/uninitialized pages and pages with dead tuples and
+ * ~LP_USED line pointers, constructs Fvpl list of pages
+ * appropriate for purposes of shrinking and maintains statistics
+ * on the number of live tuples in a heap.
*/
static void
-vc_scanheap (VRelStats *vacrelstats, Relation onerel,
+vc_scanheap(VRelStats * vacrelstats, Relation onerel,
VPageList Vvpl, VPageList Fvpl)
{
- int nblocks, blkno;
- ItemId itemid;
- ItemPointer itemptr;
- HeapTuple htup;
- Buffer buf;
- Page page, tempPage = NULL;
- OffsetNumber offnum, maxoff;
- bool pgchanged, tupgone, dobufrel, notup;
- char *relname;
- VPageDescr vpc, vp;
- uint32 nvac, ntups, nunused, ncrash, nempg, nnepg, nchpg, nemend;
- Size frsize, frsusf;
- Size min_tlen = MAXTUPLEN;
- Size max_tlen = 0;
- int32 i/*, attr_cnt*/;
- struct rusage ru0, ru1;
- bool do_shrinking = true;
-
- getrusage(RUSAGE_SELF, &ru0);
-
- nvac = ntups = nunused = ncrash = nempg = nnepg = nchpg = nemend = 0;
- frsize = frsusf = 0;
-
- relname = (RelationGetRelationName(onerel))->data;
-
- nblocks = RelationGetNumberOfBlocks(onerel);
-
- vpc = (VPageDescr) palloc (sizeof(VPageDescrData) + MaxOffsetNumber*sizeof(OffsetNumber));
- vpc->vpd_nusd = 0;
-
- for (blkno = 0; blkno < nblocks; blkno++) {
- buf = ReadBuffer(onerel, blkno);
- page = BufferGetPage(buf);
- vpc->vpd_blkno = blkno;
- vpc->vpd_noff = 0;
-
- if (PageIsNew(page)) {
- elog (NOTICE, "Rel %s: Uninitialized page %u - fixing",
- relname, blkno);
- PageInit (page, BufferGetPageSize (buf), 0);
- vpc->vpd_free = ((PageHeader)page)->pd_upper - ((PageHeader)page)->pd_lower;
- frsize += (vpc->vpd_free - sizeof (ItemIdData));
- nnepg++;
- nemend++;
- vc_reappage (Vvpl, vpc);
- WriteBuffer(buf);
- continue;
- }
-
- if (PageIsEmpty(page)) {
- vpc->vpd_free = ((PageHeader)page)->pd_upper - ((PageHeader)page)->pd_lower;
- frsize += (vpc->vpd_free - sizeof (ItemIdData));
- nempg++;
- nemend++;
- vc_reappage (Vvpl, vpc);
- ReleaseBuffer(buf);
- continue;
- }
+ int nblocks,
+ blkno;
+ ItemId itemid;
+ ItemPointer itemptr;
+ HeapTuple htup;
+ Buffer buf;
+ Page page,
+ tempPage = NULL;
+ OffsetNumber offnum,
+ maxoff;
+ bool pgchanged,
+ tupgone,
+ dobufrel,
+ notup;
+ char *relname;
+ VPageDescr vpc,
+ vp;
+ uint32 nvac,
+ ntups,
+ nunused,
+ ncrash,
+ nempg,
+ nnepg,
+ nchpg,
+ nemend;
+ Size frsize,
+ frsusf;
+ Size min_tlen = MAXTUPLEN;
+ Size max_tlen = 0;
+ int32 i /* , attr_cnt */ ;
+ struct rusage ru0,
+ ru1;
+ bool do_shrinking = true;
+
+ getrusage(RUSAGE_SELF, &ru0);
+
+ nvac = ntups = nunused = ncrash = nempg = nnepg = nchpg = nemend = 0;
+ frsize = frsusf = 0;
+
+ relname = (RelationGetRelationName(onerel))->data;
+
+ nblocks = RelationGetNumberOfBlocks(onerel);
+
+ vpc = (VPageDescr) palloc(sizeof(VPageDescrData) + MaxOffsetNumber * sizeof(OffsetNumber));
+ vpc->vpd_nusd = 0;
+
+ for (blkno = 0; blkno < nblocks; blkno++)
+ {
+ buf = ReadBuffer(onerel, blkno);
+ page = BufferGetPage(buf);
+ vpc->vpd_blkno = blkno;
+ vpc->vpd_noff = 0;
- pgchanged = false;
- notup = true;
- maxoff = PageGetMaxOffsetNumber(page);
- for (offnum = FirstOffsetNumber;
- offnum <= maxoff;
- offnum = OffsetNumberNext(offnum)) {
- itemid = PageGetItemId(page, offnum);
-
- /*
- * Collect un-used items too - it's possible to have
- * indices pointing here after crash.
- */
- if (!ItemIdIsUsed(itemid)) {
- vpc->vpd_voff[vpc->vpd_noff++] = offnum;
- nunused++;
- continue;
- }
-
- htup = (HeapTuple) PageGetItem(page, itemid);
- tupgone = false;
-
- if (!AbsoluteTimeIsBackwardCompatiblyValid(htup->t_tmin) &&
- TransactionIdIsValid((TransactionId)htup->t_xmin)) {
-
- if (TransactionIdDidAbort(htup->t_xmin)) {
- tupgone = true;
- } else if (TransactionIdDidCommit(htup->t_xmin)) {
- htup->t_tmin = TransactionIdGetCommitTime(htup->t_xmin);
- pgchanged = true;
- } else if ( !TransactionIdIsInProgress (htup->t_xmin) ) {
- /*
- * Not Aborted, Not Committed, Not in Progress -
- * so it from crashed process. - vadim 11/26/96
- */
- ncrash++;
- tupgone = true;
+ if (PageIsNew(page))
+ {
+ elog(NOTICE, "Rel %s: Uninitialized page %u - fixing",
+ relname, blkno);
+ PageInit(page, BufferGetPageSize(buf), 0);
+ vpc->vpd_free = ((PageHeader) page)->pd_upper - ((PageHeader) page)->pd_lower;
+ frsize += (vpc->vpd_free - sizeof(ItemIdData));
+ nnepg++;
+ nemend++;
+ vc_reappage(Vvpl, vpc);
+ WriteBuffer(buf);
+ continue;
}
- else
+
+ if (PageIsEmpty(page))
{
- elog (NOTICE, "Rel %s: TID %u/%u: InsertTransactionInProgress %u - can't shrink relation",
- relname, blkno, offnum, htup->t_xmin);
- do_shrinking = false;
+ vpc->vpd_free = ((PageHeader) page)->pd_upper - ((PageHeader) page)->pd_lower;
+ frsize += (vpc->vpd_free - sizeof(ItemIdData));
+ nempg++;
+ nemend++;
+ vc_reappage(Vvpl, vpc);
+ ReleaseBuffer(buf);
+ continue;
}
- }
- if (TransactionIdIsValid((TransactionId)htup->t_xmax))
- {
- if (TransactionIdDidAbort(htup->t_xmax))
+ pgchanged = false;
+ notup = true;
+ maxoff = PageGetMaxOffsetNumber(page);
+ for (offnum = FirstOffsetNumber;
+ offnum <= maxoff;
+ offnum = OffsetNumberNext(offnum))
{
- StoreInvalidTransactionId(&(htup->t_xmax));
- pgchanged = true;
+ itemid = PageGetItemId(page, offnum);
+
+ /*
+ * Collect un-used items too - it's possible to have indices
+ * pointing here after crash.
+ */
+ if (!ItemIdIsUsed(itemid))
+ {
+ vpc->vpd_voff[vpc->vpd_noff++] = offnum;
+ nunused++;
+ continue;
+ }
+
+ htup = (HeapTuple) PageGetItem(page, itemid);
+ tupgone = false;
+
+ if (!AbsoluteTimeIsBackwardCompatiblyValid(htup->t_tmin) &&
+ TransactionIdIsValid((TransactionId) htup->t_xmin))
+ {
+
+ if (TransactionIdDidAbort(htup->t_xmin))
+ {
+ tupgone = true;
+ }
+ else if (TransactionIdDidCommit(htup->t_xmin))
+ {
+ htup->t_tmin = TransactionIdGetCommitTime(htup->t_xmin);
+ pgchanged = true;
+ }
+ else if (!TransactionIdIsInProgress(htup->t_xmin))
+ {
+
+ /*
+ * Not Aborted, Not Committed, Not in Progress - so it
+ * from crashed process. - vadim 11/26/96
+ */
+ ncrash++;
+ tupgone = true;
+ }
+ else
+ {
+ elog(NOTICE, "Rel %s: TID %u/%u: InsertTransactionInProgress %u - can't shrink relation",
+ relname, blkno, offnum, htup->t_xmin);
+ do_shrinking = false;
+ }
+ }
+
+ if (TransactionIdIsValid((TransactionId) htup->t_xmax))
+ {
+ if (TransactionIdDidAbort(htup->t_xmax))
+ {
+ StoreInvalidTransactionId(&(htup->t_xmax));
+ pgchanged = true;
+ }
+ else if (TransactionIdDidCommit(htup->t_xmax))
+ tupgone = true;
+ else if (!TransactionIdIsInProgress(htup->t_xmax))
+ {
+
+ /*
+ * Not Aborted, Not Committed, Not in Progress - so it
+ * from crashed process. - vadim 06/02/97
+ */
+ StoreInvalidTransactionId(&(htup->t_xmax));
+ pgchanged = true;
+ }
+ else
+ {
+ elog(NOTICE, "Rel %s: TID %u/%u: DeleteTransactionInProgress %u - can't shrink relation",
+ relname, blkno, offnum, htup->t_xmax);
+ do_shrinking = false;
+ }
+ }
+
+ /*
+ * Is it possible at all ? - vadim 11/26/96
+ */
+ if (!TransactionIdIsValid((TransactionId) htup->t_xmin))
+ {
+ elog(NOTICE, "Rel %s: TID %u/%u: INSERT_TRANSACTION_ID IS INVALID. \
+DELETE_TRANSACTION_ID_VALID %d, TUPGONE %d.",
+ relname, blkno, offnum,
+ TransactionIdIsValid((TransactionId) htup->t_xmax),
+ tupgone);
+ }
+
+ /*
+ * It's possibly! But from where it comes ? And should we fix
+ * it ? - vadim 11/28/96
+ */
+ itemptr = &(htup->t_ctid);
+ if (!ItemPointerIsValid(itemptr) ||
+ BlockIdGetBlockNumber(&(itemptr->ip_blkid)) != blkno)
+ {
+ elog(NOTICE, "Rel %s: TID %u/%u: TID IN TUPLEHEADER %u/%u IS NOT THE SAME. TUPGONE %d.",
+ relname, blkno, offnum,
+ BlockIdGetBlockNumber(&(itemptr->ip_blkid)),
+ itemptr->ip_posid, tupgone);
+ }
+
+ /*
+ * Other checks...
+ */
+ if (htup->t_len != itemid->lp_len)
+ {
+ elog(NOTICE, "Rel %s: TID %u/%u: TUPLE_LEN IN PAGEHEADER %u IS NOT THE SAME AS IN TUPLEHEADER %u. TUPGONE %d.",
+ relname, blkno, offnum,
+ itemid->lp_len, htup->t_len, tupgone);
+ }
+ if (!OidIsValid(htup->t_oid))
+ {
+ elog(NOTICE, "Rel %s: TID %u/%u: OID IS INVALID. TUPGONE %d.",
+ relname, blkno, offnum, tupgone);
+ }
+
+ if (tupgone)
+ {
+ ItemId lpp;
+
+ if (tempPage == (Page) NULL)
+ {
+ Size pageSize;
+
+ pageSize = PageGetPageSize(page);
+ tempPage = (Page) palloc(pageSize);
+ memmove(tempPage, page, pageSize);
+ }
+
+ lpp = &(((PageHeader) tempPage)->pd_linp[offnum - 1]);
+
+ /* mark it unused */
+ lpp->lp_flags &= ~LP_USED;
+
+ vpc->vpd_voff[vpc->vpd_noff++] = offnum;
+ nvac++;
+
+ }
+ else
+ {
+ ntups++;
+ notup = false;
+ if (htup->t_len < min_tlen)
+ min_tlen = htup->t_len;
+ if (htup->t_len > max_tlen)
+ max_tlen = htup->t_len;
+ vc_attrstats(onerel, vacrelstats, htup);
+ }
}
- else if (TransactionIdDidCommit(htup->t_xmax))
- tupgone = true;
- else if ( !TransactionIdIsInProgress (htup->t_xmax) ) {
- /*
- * Not Aborted, Not Committed, Not in Progress -
- * so it from crashed process. - vadim 06/02/97
- */
- StoreInvalidTransactionId(&(htup->t_xmax));
- pgchanged = true;
+
+ if (pgchanged)
+ {
+ WriteBuffer(buf);
+ dobufrel = false;
+ nchpg++;
}
else
- {
- elog (NOTICE, "Rel %s: TID %u/%u: DeleteTransactionInProgress %u - can't shrink relation",
- relname, blkno, offnum, htup->t_xmax);
- do_shrinking = false;
+ dobufrel = true;
+ if (tempPage != (Page) NULL)
+ { /* Some tuples are gone */
+ PageRepairFragmentation(tempPage);
+ vpc->vpd_free = ((PageHeader) tempPage)->pd_upper - ((PageHeader) tempPage)->pd_lower;
+ frsize += vpc->vpd_free;
+ vc_reappage(Vvpl, vpc);
+ pfree(tempPage);
+ tempPage = (Page) NULL;
}
- }
-
- /*
- * Is it possible at all ? - vadim 11/26/96
- */
- if ( !TransactionIdIsValid((TransactionId)htup->t_xmin) )
- {
- elog (NOTICE, "Rel %s: TID %u/%u: INSERT_TRANSACTION_ID IS INVALID. \
-DELETE_TRANSACTION_ID_VALID %d, TUPGONE %d.",
- relname, blkno, offnum,
- TransactionIdIsValid((TransactionId)htup->t_xmax),
- tupgone);
- }
-
- /*
- * It's possibly! But from where it comes ?
- * And should we fix it ? - vadim 11/28/96
- */
- itemptr = &(htup->t_ctid);
- if ( !ItemPointerIsValid (itemptr) ||
- BlockIdGetBlockNumber(&(itemptr->ip_blkid)) != blkno )
- {
- elog (NOTICE, "Rel %s: TID %u/%u: TID IN TUPLEHEADER %u/%u IS NOT THE SAME. TUPGONE %d.",
- relname, blkno, offnum,
- BlockIdGetBlockNumber(&(itemptr->ip_blkid)),
- itemptr->ip_posid, tupgone);
- }
-
- /*
- * Other checks...
- */
- if ( htup->t_len != itemid->lp_len )
- {
- elog (NOTICE, "Rel %s: TID %u/%u: TUPLE_LEN IN PAGEHEADER %u IS NOT THE SAME AS IN TUPLEHEADER %u. TUPGONE %d.",
- relname, blkno, offnum,
- itemid->lp_len, htup->t_len, tupgone);
- }
- if ( !OidIsValid(htup->t_oid) )
- {
- elog (NOTICE, "Rel %s: TID %u/%u: OID IS INVALID. TUPGONE %d.",
- relname, blkno, offnum, tupgone);
- }
-
- if (tupgone) {
- ItemId lpp;
-
- if ( tempPage == (Page) NULL )
- {
- Size pageSize;
-
- pageSize = PageGetPageSize(page);
- tempPage = (Page) palloc(pageSize);
- memmove (tempPage, page, pageSize);
+ else if (vpc->vpd_noff > 0)
+ { /* there are only ~LP_USED line pointers */
+ vpc->vpd_free = ((PageHeader) page)->pd_upper - ((PageHeader) page)->pd_lower;
+ frsize += vpc->vpd_free;
+ vc_reappage(Vvpl, vpc);
}
-
- lpp = &(((PageHeader) tempPage)->pd_linp[offnum - 1]);
-
- /* mark it unused */
- lpp->lp_flags &= ~LP_USED;
-
- vpc->vpd_voff[vpc->vpd_noff++] = offnum;
- nvac++;
-
- } else {
- ntups++;
- notup = false;
- if ( htup->t_len < min_tlen )
- min_tlen = htup->t_len;
- if ( htup->t_len > max_tlen )
- max_tlen = htup->t_len;
- vc_attrstats(onerel, vacrelstats, htup);
- }
+ if (dobufrel)
+ ReleaseBuffer(buf);
+ if (notup)
+ nemend++;
+ else
+ nemend = 0;
}
- if (pgchanged) {
- WriteBuffer(buf);
- dobufrel = false;
- nchpg++;
- }
- else
- dobufrel = true;
- if ( tempPage != (Page) NULL )
- { /* Some tuples are gone */
- PageRepairFragmentation(tempPage);
- vpc->vpd_free = ((PageHeader)tempPage)->pd_upper - ((PageHeader)tempPage)->pd_lower;
- frsize += vpc->vpd_free;
- vc_reappage (Vvpl, vpc);
- pfree (tempPage);
- tempPage = (Page) NULL;
- }
- else if ( vpc->vpd_noff > 0 )
- { /* there are only ~LP_USED line pointers */
- vpc->vpd_free = ((PageHeader)page)->pd_upper - ((PageHeader)page)->pd_lower;
- frsize += vpc->vpd_free;
- vc_reappage (Vvpl, vpc);
- }
- if ( dobufrel )
- ReleaseBuffer(buf);
- if ( notup )
- nemend++;
- else
- nemend = 0;
- }
-
- pfree (vpc);
-
- /* save stats in the rel list for use later */
- vacrelstats->ntups = ntups;
- vacrelstats->npages = nblocks;
-/* vacrelstats->natts = attr_cnt;*/
- if ( ntups == 0 )
- min_tlen = max_tlen = 0;
- vacrelstats->min_tlen = min_tlen;
- vacrelstats->max_tlen = max_tlen;
-
- Vvpl->vpl_nemend = nemend;
- Fvpl->vpl_nemend = nemend;
-
- /*
- * Try to make Fvpl keeping in mind that we can't use free space
- * of "empty" end-pages and last page if it reapped.
- */
- if ( do_shrinking && Vvpl->vpl_npages - nemend > 0 )
- {
- int nusf; /* blocks usefull for re-using */
-
- nusf = Vvpl->vpl_npages - nemend;
- if ( (Vvpl->vpl_pgdesc[nusf-1])->vpd_blkno == nblocks - nemend - 1 )
- nusf--;
-
- for (i = 0; i < nusf; i++)
- {
- vp = Vvpl->vpl_pgdesc[i];
- if ( vc_enough_space (vp, min_tlen) )
- {
- vc_vpinsert (Fvpl, vp);
- frsusf += vp->vpd_free;
- }
+ pfree(vpc);
+
+ /* save stats in the rel list for use later */
+ vacrelstats->ntups = ntups;
+ vacrelstats->npages = nblocks;
+/* vacrelstats->natts = attr_cnt;*/
+ if (ntups == 0)
+ min_tlen = max_tlen = 0;
+ vacrelstats->min_tlen = min_tlen;
+ vacrelstats->max_tlen = max_tlen;
+
+ Vvpl->vpl_nemend = nemend;
+ Fvpl->vpl_nemend = nemend;
+
+ /*
+ * Try to make Fvpl keeping in mind that we can't use free space of
+ * "empty" end-pages and last page if it reapped.
+ */
+ if (do_shrinking && Vvpl->vpl_npages - nemend > 0)
+ {
+ int nusf; /* blocks usefull for re-using */
+
+ nusf = Vvpl->vpl_npages - nemend;
+ if ((Vvpl->vpl_pgdesc[nusf - 1])->vpd_blkno == nblocks - nemend - 1)
+ nusf--;
+
+ for (i = 0; i < nusf; i++)
+ {
+ vp = Vvpl->vpl_pgdesc[i];
+ if (vc_enough_space(vp, min_tlen))
+ {
+ vc_vpinsert(Fvpl, vp);
+ frsusf += vp->vpd_free;
+ }
+ }
}
- }
- getrusage(RUSAGE_SELF, &ru1);
-
- elog (MESSAGE_LEVEL, "Rel %s: Pages %u: Changed %u, Reapped %u, Empty %u, New %u; \
+ getrusage(RUSAGE_SELF, &ru1);
+
+ elog(MESSAGE_LEVEL, "Rel %s: Pages %u: Changed %u, Reapped %u, Empty %u, New %u; \
Tup %u: Vac %u, Crash %u, UnUsed %u, MinLen %u, MaxLen %u; Re-using: Free/Avail. Space %u/%u; EndEmpty/Avail. Pages %u/%u. Elapsed %u/%u sec.",
- relname,
- nblocks, nchpg, Vvpl->vpl_npages, nempg, nnepg,
- ntups, nvac, ncrash, nunused, min_tlen, max_tlen,
- frsize, frsusf, nemend, Fvpl->vpl_npages,
- ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
- ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
+ relname,
+ nblocks, nchpg, Vvpl->vpl_npages, nempg, nnepg,
+ ntups, nvac, ncrash, nunused, min_tlen, max_tlen,
+ frsize, frsusf, nemend, Fvpl->vpl_npages,
+ ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
+ ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
-} /* vc_scanheap */
+} /* vc_scanheap */
/*
- * vc_rpfheap() -- try to repaire relation' fragmentation
+ * vc_rpfheap() -- try to repaire relation' fragmentation
*
- * This routine marks dead tuples as unused and tries re-use dead space
- * by moving tuples (and inserting indices if needed). It constructs
- * Nvpl list of free-ed pages (moved tuples) and clean indices
- * for them after committing (in hack-manner - without losing locks
- * and freeing memory!) current transaction. It truncates relation
- * if some end-blocks are gone away.
+ * This routine marks dead tuples as unused and tries re-use dead space
+ * by moving tuples (and inserting indices if needed). It constructs
+ * Nvpl list of free-ed pages (moved tuples) and clean indices
+ * for them after committing (in hack-manner - without losing locks
+ * and freeing memory!) current transaction. It truncates relation
+ * if some end-blocks are gone away.
*/
static void
-vc_rpfheap (VRelStats *vacrelstats, Relation onerel,
- VPageList Vvpl, VPageList Fvpl, int nindices, Relation *Irel)
+vc_rpfheap(VRelStats * vacrelstats, Relation onerel,
+ VPageList Vvpl, VPageList Fvpl, int nindices, Relation * Irel)
{
- TransactionId myXID;
- CommandId myCID;
- AbsoluteTime myCTM = 0;
- Buffer buf, ToBuf;
- int nblocks, blkno;
- Page page, ToPage = NULL;
- OffsetNumber offnum = 0, maxoff = 0, newoff, moff;
- ItemId itemid, newitemid;
- HeapTuple htup, newtup;
- TupleDesc tupdesc = NULL;
- Datum *idatum = NULL;
- char *inulls = NULL;
- InsertIndexResult iresult;
- VPageListData Nvpl;
- VPageDescr ToVpd = NULL, Fvplast, Vvplast, vpc, *vpp;
- int ToVpI = 0;
- IndDesc *Idesc, *idcur;
- int Fblklast, Vblklast, i;
- Size tlen;
- int nmoved, Fnpages, Vnpages;
- int nchkmvd, ntups;
- bool isempty, dowrite;
- Relation archrel;
- struct rusage ru0, ru1;
-
- getrusage(RUSAGE_SELF, &ru0);
-
- myXID = GetCurrentTransactionId();
- myCID = GetCurrentCommandId();
-
- if ( Irel != (Relation*) NULL ) /* preparation for index' inserts */
- {
- vc_mkindesc (onerel, nindices, Irel, &Idesc);
- tupdesc = RelationGetTupleDescriptor(onerel);
- idatum = (Datum *) palloc(INDEX_MAX_KEYS * sizeof (*idatum));
- inulls = (char *) palloc(INDEX_MAX_KEYS * sizeof (*inulls));
- }
-
- /* if the relation has an archive, open it */
- if (onerel->rd_rel->relarch != 'n')
- {
- archrel = vc_getarchrel(onerel);
- /* Archive tuples from "empty" end-pages */
- for ( vpp = Vvpl->vpl_pgdesc + Vvpl->vpl_npages - 1,
- i = Vvpl->vpl_nemend; i > 0; i--, vpp-- )
+ TransactionId myXID;
+ CommandId myCID;
+ AbsoluteTime myCTM = 0;
+ Buffer buf,
+ ToBuf;
+ int nblocks,
+ blkno;
+ Page page,
+ ToPage = NULL;
+ OffsetNumber offnum = 0,
+ maxoff = 0,
+ newoff,
+ moff;
+ ItemId itemid,
+ newitemid;
+ HeapTuple htup,
+ newtup;
+ TupleDesc tupdesc = NULL;
+ Datum *idatum = NULL;
+ char *inulls = NULL;
+ InsertIndexResult iresult;
+ VPageListData Nvpl;
+ VPageDescr ToVpd = NULL,
+ Fvplast,
+ Vvplast,
+ vpc,
+ *vpp;
+ int ToVpI = 0;
+ IndDesc *Idesc,
+ *idcur;
+ int Fblklast,
+ Vblklast,
+ i;
+ Size tlen;
+ int nmoved,
+ Fnpages,
+ Vnpages;
+ int nchkmvd,
+ ntups;
+ bool isempty,
+ dowrite;
+ Relation archrel;
+ struct rusage ru0,
+ ru1;
+
+ getrusage(RUSAGE_SELF, &ru0);
+
+ myXID = GetCurrentTransactionId();
+ myCID = GetCurrentCommandId();
+
+ if (Irel != (Relation *) NULL) /* preparation for index' inserts */
{
- if ( (*vpp)->vpd_noff > 0 )
- {
- buf = ReadBuffer(onerel, (*vpp)->vpd_blkno);
- page = BufferGetPage(buf);
- Assert ( !PageIsEmpty(page) );
- vc_vacpage (page, *vpp, archrel);
- WriteBuffer (buf);
- }
+ vc_mkindesc(onerel, nindices, Irel, &Idesc);
+ tupdesc = RelationGetTupleDescriptor(onerel);
+ idatum = (Datum *) palloc(INDEX_MAX_KEYS * sizeof(*idatum));
+ inulls = (char *) palloc(INDEX_MAX_KEYS * sizeof(*inulls));
}
- }
- else
- archrel = (Relation) NULL;
-
- Nvpl.vpl_npages = 0;
- Fnpages = Fvpl->vpl_npages;
- Fvplast = Fvpl->vpl_pgdesc[Fnpages - 1];
- Fblklast = Fvplast->vpd_blkno;
- Assert ( Vvpl->vpl_npages > Vvpl->vpl_nemend );
- Vnpages = Vvpl->vpl_npages - Vvpl->vpl_nemend;
- Vvplast = Vvpl->vpl_pgdesc[Vnpages - 1];
- Vblklast = Vvplast->vpd_blkno;
- Assert ( Vblklast >= Fblklast );
- ToBuf = InvalidBuffer;
- nmoved = 0;
-
- vpc = (VPageDescr) palloc (sizeof(VPageDescrData) + MaxOffsetNumber*sizeof(OffsetNumber));
- vpc->vpd_nusd = vpc->vpd_noff = 0;
-
- nblocks = vacrelstats->npages;
- for (blkno = nblocks - Vvpl->vpl_nemend - 1; ; blkno--)
- {
- /* if it's reapped page and it was used by me - quit */
- if ( blkno == Fblklast && Fvplast->vpd_nusd > 0 )
- break;
-
- buf = ReadBuffer(onerel, blkno);
- page = BufferGetPage(buf);
-
- vpc->vpd_noff = 0;
-
- isempty = PageIsEmpty(page);
-
- dowrite = false;
- if ( blkno == Vblklast ) /* it's reapped page */
+
+ /* if the relation has an archive, open it */
+ if (onerel->rd_rel->relarch != 'n')
{
- if ( Vvplast->vpd_noff > 0 ) /* there are dead tuples */
- { /* on this page - clean */
- Assert ( ! isempty );
- vc_vacpage (page, Vvplast, archrel);
- dowrite = true;
- }
- else
- {
- Assert ( isempty );
- }
- --Vnpages;
- Assert ( Vnpages > 0 );
- /* get prev reapped page from Vvpl */
- Vvplast = Vvpl->vpl_pgdesc[Vnpages - 1];
- Vblklast = Vvplast->vpd_blkno;
- if ( blkno == Fblklast ) /* this page in Fvpl too */
- {
- --Fnpages;
- Assert ( Fnpages > 0 );
- Assert ( Fvplast->vpd_nusd == 0 );
- /* get prev reapped page from Fvpl */
- Fvplast = Fvpl->vpl_pgdesc[Fnpages - 1];
- Fblklast = Fvplast->vpd_blkno;
- }
- Assert ( Fblklast <= Vblklast );
- if ( isempty )
- {
- ReleaseBuffer(buf);
- continue;
- }
+ archrel = vc_getarchrel(onerel);
+ /* Archive tuples from "empty" end-pages */
+ for (vpp = Vvpl->vpl_pgdesc + Vvpl->vpl_npages - 1,
+ i = Vvpl->vpl_nemend; i > 0; i--, vpp--)
+ {
+ if ((*vpp)->vpd_noff > 0)
+ {
+ buf = ReadBuffer(onerel, (*vpp)->vpd_blkno);
+ page = BufferGetPage(buf);
+ Assert(!PageIsEmpty(page));
+ vc_vacpage(page, *vpp, archrel);
+ WriteBuffer(buf);
+ }
+ }
}
else
+ archrel = (Relation) NULL;
+
+ Nvpl.vpl_npages = 0;
+ Fnpages = Fvpl->vpl_npages;
+ Fvplast = Fvpl->vpl_pgdesc[Fnpages - 1];
+ Fblklast = Fvplast->vpd_blkno;
+ Assert(Vvpl->vpl_npages > Vvpl->vpl_nemend);
+ Vnpages = Vvpl->vpl_npages - Vvpl->vpl_nemend;
+ Vvplast = Vvpl->vpl_pgdesc[Vnpages - 1];
+ Vblklast = Vvplast->vpd_blkno;
+ Assert(Vblklast >= Fblklast);
+ ToBuf = InvalidBuffer;
+ nmoved = 0;
+
+ vpc = (VPageDescr) palloc(sizeof(VPageDescrData) + MaxOffsetNumber * sizeof(OffsetNumber));
+ vpc->vpd_nusd = vpc->vpd_noff = 0;
+
+ nblocks = vacrelstats->npages;
+ for (blkno = nblocks - Vvpl->vpl_nemend - 1;; blkno--)
{
- Assert ( ! isempty );
- }
+ /* if it's reapped page and it was used by me - quit */
+ if (blkno == Fblklast && Fvplast->vpd_nusd > 0)
+ break;
- vpc->vpd_blkno = blkno;
- maxoff = PageGetMaxOffsetNumber(page);
- for (offnum = FirstOffsetNumber;
- offnum <= maxoff;
- offnum = OffsetNumberNext(offnum))
- {
- itemid = PageGetItemId(page, offnum);
-
- if (!ItemIdIsUsed(itemid))
- continue;
-
- htup = (HeapTuple) PageGetItem(page, itemid);
- tlen = htup->t_len;
-
- /* try to find new page for this tuple */
- if ( ToBuf == InvalidBuffer ||
- ! vc_enough_space (ToVpd, tlen) )
- {
- if ( ToBuf != InvalidBuffer )
+ buf = ReadBuffer(onerel, blkno);
+ page = BufferGetPage(buf);
+
+ vpc->vpd_noff = 0;
+
+ isempty = PageIsEmpty(page);
+
+ dowrite = false;
+ if (blkno == Vblklast) /* it's reapped page */
{
- WriteBuffer(ToBuf);
- ToBuf = InvalidBuffer;
- /*
- * If no one tuple can't be added to this page -
- * remove page from Fvpl. - vadim 11/27/96
- */
- if ( !vc_enough_space (ToVpd, vacrelstats->min_tlen) )
- {
- if ( ToVpd != Fvplast )
- {
- Assert ( Fnpages > ToVpI + 1 );
- memmove (Fvpl->vpl_pgdesc + ToVpI,
- Fvpl->vpl_pgdesc + ToVpI + 1,
- sizeof (VPageDescr*) * (Fnpages - ToVpI - 1));
- }
- Assert ( Fnpages >= 1 );
- Fnpages--;
- if ( Fnpages == 0 )
- break;
- /* get prev reapped page from Fvpl */
- Fvplast = Fvpl->vpl_pgdesc[Fnpages - 1];
- Fblklast = Fvplast->vpd_blkno;
- }
- }
- for (i=0; i < Fnpages; i++)
+ if (Vvplast->vpd_noff > 0) /* there are dead tuples */
+ { /* on this page - clean */
+ Assert(!isempty);
+ vc_vacpage(page, Vvplast, archrel);
+ dowrite = true;
+ }
+ else
+ {
+ Assert(isempty);
+ }
+ --Vnpages;
+ Assert(Vnpages > 0);
+ /* get prev reapped page from Vvpl */
+ Vvplast = Vvpl->vpl_pgdesc[Vnpages - 1];
+ Vblklast = Vvplast->vpd_blkno;
+ if (blkno == Fblklast) /* this page in Fvpl too */
+ {
+ --Fnpages;
+ Assert(Fnpages > 0);
+ Assert(Fvplast->vpd_nusd == 0);
+ /* get prev reapped page from Fvpl */
+ Fvplast = Fvpl->vpl_pgdesc[Fnpages - 1];
+ Fblklast = Fvplast->vpd_blkno;
+ }
+ Assert(Fblklast <= Vblklast);
+ if (isempty)
+ {
+ ReleaseBuffer(buf);
+ continue;
+ }
+ }
+ else
{
- if ( vc_enough_space (Fvpl->vpl_pgdesc[i], tlen) )
- break;
+ Assert(!isempty);
}
- if ( i == Fnpages )
- break; /* can't move item anywhere */
- ToVpI = i;
- ToVpd = Fvpl->vpl_pgdesc[ToVpI];
- ToBuf = ReadBuffer(onerel, ToVpd->vpd_blkno);
- ToPage = BufferGetPage(ToBuf);
- /* if this page was not used before - clean it */
- if ( ! PageIsEmpty(ToPage) && ToVpd->vpd_nusd == 0 )
- vc_vacpage (ToPage, ToVpd, archrel);
- }
-
- /* copy tuple */
- newtup = (HeapTuple) palloc (tlen);
- memmove((char *) newtup, (char *) htup, tlen);
-
- /* store transaction information */
- TransactionIdStore(myXID, &(newtup->t_xmin));
- newtup->t_cmin = myCID;
- StoreInvalidTransactionId(&(newtup->t_xmax));
- newtup->t_tmin = INVALID_ABSTIME;
- newtup->t_tmax = CURRENT_ABSTIME;
- ItemPointerSetInvalid(&newtup->t_chain);
-
- /* add tuple to the page */
- newoff = PageAddItem (ToPage, (Item)newtup, tlen,
- InvalidOffsetNumber, LP_USED);
- if ( newoff == InvalidOffsetNumber )
- {
- elog (WARN, "\
+
+ vpc->vpd_blkno = blkno;
+ maxoff = PageGetMaxOffsetNumber(page);
+ for (offnum = FirstOffsetNumber;
+ offnum <= maxoff;
+ offnum = OffsetNumberNext(offnum))
+ {
+ itemid = PageGetItemId(page, offnum);
+
+ if (!ItemIdIsUsed(itemid))
+ continue;
+
+ htup = (HeapTuple) PageGetItem(page, itemid);
+ tlen = htup->t_len;
+
+ /* try to find new page for this tuple */
+ if (ToBuf == InvalidBuffer ||
+ !vc_enough_space(ToVpd, tlen))
+ {
+ if (ToBuf != InvalidBuffer)
+ {
+ WriteBuffer(ToBuf);
+ ToBuf = InvalidBuffer;
+
+ /*
+ * If no one tuple can't be added to this page -
+ * remove page from Fvpl. - vadim 11/27/96
+ */
+ if (!vc_enough_space(ToVpd, vacrelstats->min_tlen))
+ {
+ if (ToVpd != Fvplast)
+ {
+ Assert(Fnpages > ToVpI + 1);
+ memmove(Fvpl->vpl_pgdesc + ToVpI,
+ Fvpl->vpl_pgdesc + ToVpI + 1,
+ sizeof(VPageDescr *) * (Fnpages - ToVpI - 1));
+ }
+ Assert(Fnpages >= 1);
+ Fnpages--;
+ if (Fnpages == 0)
+ break;
+ /* get prev reapped page from Fvpl */
+ Fvplast = Fvpl->vpl_pgdesc[Fnpages - 1];
+ Fblklast = Fvplast->vpd_blkno;
+ }
+ }
+ for (i = 0; i < Fnpages; i++)
+ {
+ if (vc_enough_space(Fvpl->vpl_pgdesc[i], tlen))
+ break;
+ }
+ if (i == Fnpages)
+ break; /* can't move item anywhere */
+ ToVpI = i;
+ ToVpd = Fvpl->vpl_pgdesc[ToVpI];
+ ToBuf = ReadBuffer(onerel, ToVpd->vpd_blkno);
+ ToPage = BufferGetPage(ToBuf);
+ /* if this page was not used before - clean it */
+ if (!PageIsEmpty(ToPage) && ToVpd->vpd_nusd == 0)
+ vc_vacpage(ToPage, ToVpd, archrel);
+ }
+
+ /* copy tuple */
+ newtup = (HeapTuple) palloc(tlen);
+ memmove((char *) newtup, (char *) htup, tlen);
+
+ /* store transaction information */
+ TransactionIdStore(myXID, &(newtup->t_xmin));
+ newtup->t_cmin = myCID;
+ StoreInvalidTransactionId(&(newtup->t_xmax));
+ newtup->t_tmin = INVALID_ABSTIME;
+ newtup->t_tmax = CURRENT_ABSTIME;
+ ItemPointerSetInvalid(&newtup->t_chain);
+
+ /* add tuple to the page */
+ newoff = PageAddItem(ToPage, (Item) newtup, tlen,
+ InvalidOffsetNumber, LP_USED);
+ if (newoff == InvalidOffsetNumber)
+ {
+ elog(WARN, "\
failed to add item with len = %u to page %u (free space %u, nusd %u, noff %u)",
- tlen, ToVpd->vpd_blkno, ToVpd->vpd_free,
- ToVpd->vpd_nusd, ToVpd->vpd_noff);
- }
- newitemid = PageGetItemId(ToPage, newoff);
- pfree (newtup);
- newtup = (HeapTuple) PageGetItem(ToPage, newitemid);
- ItemPointerSet(&(newtup->t_ctid), ToVpd->vpd_blkno, newoff);
-
- /* now logically delete end-tuple */
- TransactionIdStore(myXID, &(htup->t_xmax));
- htup->t_cmax = myCID;
- memmove ((char*)&(htup->t_chain), (char*)&(newtup->t_ctid), sizeof (newtup->t_ctid));
-
- ToVpd->vpd_nusd++;
- nmoved++;
- ToVpd->vpd_free = ((PageHeader)ToPage)->pd_upper - ((PageHeader)ToPage)->pd_lower;
- vpc->vpd_voff[vpc->vpd_noff++] = offnum;
-
- /* insert index' tuples if needed */
- if ( Irel != (Relation*) NULL )
- {
- for (i = 0, idcur = Idesc; i < nindices; i++, idcur++)
+ tlen, ToVpd->vpd_blkno, ToVpd->vpd_free,
+ ToVpd->vpd_nusd, ToVpd->vpd_noff);
+ }
+ newitemid = PageGetItemId(ToPage, newoff);
+ pfree(newtup);
+ newtup = (HeapTuple) PageGetItem(ToPage, newitemid);
+ ItemPointerSet(&(newtup->t_ctid), ToVpd->vpd_blkno, newoff);
+
+ /* now logically delete end-tuple */
+ TransactionIdStore(myXID, &(htup->t_xmax));
+ htup->t_cmax = myCID;
+ memmove((char *) &(htup->t_chain), (char *) &(newtup->t_ctid), sizeof(newtup->t_ctid));
+
+ ToVpd->vpd_nusd++;
+ nmoved++;
+ ToVpd->vpd_free = ((PageHeader) ToPage)->pd_upper - ((PageHeader) ToPage)->pd_lower;
+ vpc->vpd_voff[vpc->vpd_noff++] = offnum;
+
+ /* insert index' tuples if needed */
+ if (Irel != (Relation *) NULL)
+ {
+ for (i = 0, idcur = Idesc; i < nindices; i++, idcur++)
+ {
+ FormIndexDatum(
+ idcur->natts,
+ (AttrNumber *) & (idcur->tform->indkey[0]),
+ newtup,
+ tupdesc,
+ InvalidBuffer,
+ idatum,
+ inulls,
+ idcur->finfoP);
+ iresult = index_insert(
+ Irel[i],
+ idatum,
+ inulls,
+ &(newtup->t_ctid),
+ onerel);
+ if (iresult)
+ pfree(iresult);
+ }
+ }
+
+ } /* walk along page */
+
+ if (vpc->vpd_noff > 0) /* some tuples were moved */
{
- FormIndexDatum (
- idcur->natts,
- (AttrNumber *)&(idcur->tform->indkey[0]),
- newtup,
- tupdesc,
- InvalidBuffer,
- idatum,
- inulls,
- idcur->finfoP);
- iresult = index_insert (
- Irel[i],
- idatum,
- inulls,
- &(newtup->t_ctid),
- onerel);
- if (iresult) pfree(iresult);
+ vc_reappage(&Nvpl, vpc);
+ WriteBuffer(buf);
}
- }
-
- } /* walk along page */
+ else if (dowrite)
+ WriteBuffer(buf);
+ else
+ ReleaseBuffer(buf);
- if ( vpc->vpd_noff > 0 ) /* some tuples were moved */
+ if (offnum <= maxoff)
+ break; /* some item(s) left */
+
+ } /* walk along relation */
+
+ blkno++; /* new number of blocks */
+
+ if (ToBuf != InvalidBuffer)
{
- vc_reappage (&Nvpl, vpc);
- WriteBuffer(buf);
+ Assert(nmoved > 0);
+ WriteBuffer(ToBuf);
}
- else if ( dowrite )
- WriteBuffer(buf);
- else
- ReleaseBuffer(buf);
-
- if ( offnum <= maxoff )
- break; /* some item(s) left */
-
- } /* walk along relation */
-
- blkno++; /* new number of blocks */
-
- if ( ToBuf != InvalidBuffer )
- {
- Assert (nmoved > 0);
- WriteBuffer(ToBuf);
- }
-
- if ( nmoved > 0 )
- {
- /*
- * We have to commit our tuple' movings before we'll truncate
- * relation, but we shouldn't lose our locks. And so - quick hack:
- * flush buffers and record status of current transaction
- * as committed, and continue. - vadim 11/13/96
- */
- FlushBufferPool(!TransactionFlushEnabled());
- TransactionIdCommit(myXID);
- FlushBufferPool(!TransactionFlushEnabled());
- myCTM = TransactionIdGetCommitTime(myXID);
- }
-
- /*
- * Clean uncleaned reapped pages from Vvpl list
- * and set commit' times for inserted tuples
- */
- nchkmvd = 0;
- for (i = 0, vpp = Vvpl->vpl_pgdesc; i < Vnpages; i++, vpp++)
- {
- Assert ( (*vpp)->vpd_blkno < blkno );
- buf = ReadBuffer(onerel, (*vpp)->vpd_blkno);
- page = BufferGetPage(buf);
- if ( (*vpp)->vpd_nusd == 0 ) /* this page was not used */
+
+ if (nmoved > 0)
{
- /* noff == 0 in empty pages only - such pages should be re-used */
- Assert ( (*vpp)->vpd_noff > 0 );
- vc_vacpage (page, *vpp, archrel);
+
+ /*
+ * We have to commit our tuple' movings before we'll truncate
+ * relation, but we shouldn't lose our locks. And so - quick hack:
+ * flush buffers and record status of current transaction as
+ * committed, and continue. - vadim 11/13/96
+ */
+ FlushBufferPool(!TransactionFlushEnabled());
+ TransactionIdCommit(myXID);
+ FlushBufferPool(!TransactionFlushEnabled());
+ myCTM = TransactionIdGetCommitTime(myXID);
}
- else /* this page was used */
+
+ /*
+ * Clean uncleaned reapped pages from Vvpl list and set commit' times
+ * for inserted tuples
+ */
+ nchkmvd = 0;
+ for (i = 0, vpp = Vvpl->vpl_pgdesc; i < Vnpages; i++, vpp++)
{
- ntups = 0;
- moff = PageGetMaxOffsetNumber(page);
- for (newoff = FirstOffsetNumber;
- newoff <= moff;
- newoff = OffsetNumberNext(newoff))
- {
- itemid = PageGetItemId(page, newoff);
- if (!ItemIdIsUsed(itemid))
- continue;
- htup = (HeapTuple) PageGetItem(page, itemid);
- if ( TransactionIdEquals((TransactionId)htup->t_xmin, myXID) )
- {
- htup->t_tmin = myCTM;
- ntups++;
- }
- }
- Assert ( (*vpp)->vpd_nusd == ntups );
- nchkmvd += ntups;
+ Assert((*vpp)->vpd_blkno < blkno);
+ buf = ReadBuffer(onerel, (*vpp)->vpd_blkno);
+ page = BufferGetPage(buf);
+ if ((*vpp)->vpd_nusd == 0) /* this page was not used */
+ {
+
+ /*
+ * noff == 0 in empty pages only - such pages should be
+ * re-used
+ */
+ Assert((*vpp)->vpd_noff > 0);
+ vc_vacpage(page, *vpp, archrel);
+ }
+ else
+/* this page was used */
+ {
+ ntups = 0;
+ moff = PageGetMaxOffsetNumber(page);
+ for (newoff = FirstOffsetNumber;
+ newoff <= moff;
+ newoff = OffsetNumberNext(newoff))
+ {
+ itemid = PageGetItemId(page, newoff);
+ if (!ItemIdIsUsed(itemid))
+ continue;
+ htup = (HeapTuple) PageGetItem(page, itemid);
+ if (TransactionIdEquals((TransactionId) htup->t_xmin, myXID))
+ {
+ htup->t_tmin = myCTM;
+ ntups++;
+ }
+ }
+ Assert((*vpp)->vpd_nusd == ntups);
+ nchkmvd += ntups;
+ }
+ WriteBuffer(buf);
}
- WriteBuffer (buf);
- }
- Assert ( nmoved == nchkmvd );
+ Assert(nmoved == nchkmvd);
+
+ getrusage(RUSAGE_SELF, &ru1);
- getrusage(RUSAGE_SELF, &ru1);
-
- elog (MESSAGE_LEVEL, "Rel %s: Pages: %u --> %u; Tuple(s) moved: %u. \
+ elog(MESSAGE_LEVEL, "Rel %s: Pages: %u --> %u; Tuple(s) moved: %u. \
Elapsed %u/%u sec.",
- (RelationGetRelationName(onerel))->data,
- nblocks, blkno, nmoved,
- ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
- ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
-
- if ( Nvpl.vpl_npages > 0 )
- {
- /* vacuum indices again if needed */
- if ( Irel != (Relation*) NULL )
+ (RelationGetRelationName(onerel))->data,
+ nblocks, blkno, nmoved,
+ ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
+ ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
+
+ if (Nvpl.vpl_npages > 0)
{
- VPageDescr *vpleft, *vpright, vpsave;
-
- /* re-sort Nvpl.vpl_pgdesc */
- for (vpleft = Nvpl.vpl_pgdesc,
- vpright = Nvpl.vpl_pgdesc + Nvpl.vpl_npages - 1;
- vpleft < vpright; vpleft++, vpright--)
- {
- vpsave = *vpleft; *vpleft = *vpright; *vpright = vpsave;
- }
- for (i = 0; i < nindices; i++)
- vc_vaconeind (&Nvpl, Irel[i], vacrelstats->ntups);
+ /* vacuum indices again if needed */
+ if (Irel != (Relation *) NULL)
+ {
+ VPageDescr *vpleft,
+ *vpright,
+ vpsave;
+
+ /* re-sort Nvpl.vpl_pgdesc */
+ for (vpleft = Nvpl.vpl_pgdesc,
+ vpright = Nvpl.vpl_pgdesc + Nvpl.vpl_npages - 1;
+ vpleft < vpright; vpleft++, vpright--)
+ {
+ vpsave = *vpleft;
+ *vpleft = *vpright;
+ *vpright = vpsave;
+ }
+ for (i = 0; i < nindices; i++)
+ vc_vaconeind(&Nvpl, Irel[i], vacrelstats->ntups);
+ }
+
+ /*
+ * clean moved tuples from last page in Nvpl list if some tuples
+ * left there
+ */
+ if (vpc->vpd_noff > 0 && offnum <= maxoff)
+ {
+ Assert(vpc->vpd_blkno == blkno - 1);
+ buf = ReadBuffer(onerel, vpc->vpd_blkno);
+ page = BufferGetPage(buf);
+ ntups = 0;
+ maxoff = offnum;
+ for (offnum = FirstOffsetNumber;
+ offnum < maxoff;
+ offnum = OffsetNumberNext(offnum))
+ {
+ itemid = PageGetItemId(page, offnum);
+ if (!ItemIdIsUsed(itemid))
+ continue;
+ htup = (HeapTuple) PageGetItem(page, itemid);
+ Assert(TransactionIdEquals((TransactionId) htup->t_xmax, myXID));
+ itemid->lp_flags &= ~LP_USED;
+ ntups++;
+ }
+ Assert(vpc->vpd_noff == ntups);
+ PageRepairFragmentation(page);
+ WriteBuffer(buf);
+ }
+
+ /* now - free new list of reapped pages */
+ vpp = Nvpl.vpl_pgdesc;
+ for (i = 0; i < Nvpl.vpl_npages; i++, vpp++)
+ pfree(*vpp);
+ pfree(Nvpl.vpl_pgdesc);
}
- /*
- * clean moved tuples from last page in Nvpl list
- * if some tuples left there
- */
- if ( vpc->vpd_noff > 0 && offnum <= maxoff )
+ /* truncate relation */
+ if (blkno < nblocks)
{
- Assert (vpc->vpd_blkno == blkno - 1);
- buf = ReadBuffer(onerel, vpc->vpd_blkno);
- page = BufferGetPage (buf);
- ntups = 0;
- maxoff = offnum;
- for (offnum = FirstOffsetNumber;
- offnum < maxoff;
- offnum = OffsetNumberNext(offnum))
- {
- itemid = PageGetItemId(page, offnum);
- if (!ItemIdIsUsed(itemid))
- continue;
- htup = (HeapTuple) PageGetItem(page, itemid);
- Assert ( TransactionIdEquals((TransactionId)htup->t_xmax, myXID) );
- itemid->lp_flags &= ~LP_USED;
- ntups++;
- }
- Assert ( vpc->vpd_noff == ntups );
- PageRepairFragmentation(page);
- WriteBuffer (buf);
+ blkno = smgrtruncate(onerel->rd_rel->relsmgr, onerel, blkno);
+ Assert(blkno >= 0);
+ vacrelstats->npages = blkno; /* set new number of blocks */
+ }
+
+ if (archrel != (Relation) NULL)
+ heap_close(archrel);
+
+ if (Irel != (Relation *) NULL) /* pfree index' allocations */
+ {
+ pfree(Idesc);
+ pfree(idatum);
+ pfree(inulls);
+ vc_clsindices(nindices, Irel);
}
- /* now - free new list of reapped pages */
- vpp = Nvpl.vpl_pgdesc;
- for (i = 0; i < Nvpl.vpl_npages; i++, vpp++)
- pfree(*vpp);
- pfree (Nvpl.vpl_pgdesc);
- }
-
- /* truncate relation */
- if ( blkno < nblocks )
- {
- blkno = smgrtruncate (onerel->rd_rel->relsmgr, onerel, blkno);
- Assert ( blkno >= 0 );
- vacrelstats->npages = blkno; /* set new number of blocks */
- }
-
- if ( archrel != (Relation) NULL )
- heap_close(archrel);
-
- if ( Irel != (Relation*) NULL ) /* pfree index' allocations */
- {
- pfree (Idesc);
- pfree (idatum);
- pfree (inulls);
- vc_clsindices (nindices, Irel);
- }
-
- pfree (vpc);
-
-} /* vc_rpfheap */
+ pfree(vpc);
+
+} /* vc_rpfheap */
/*
- * vc_vacheap() -- free dead tuples
+ * vc_vacheap() -- free dead tuples
*
- * This routine marks dead tuples as unused and truncates relation
- * if there are "empty" end-blocks.
+ * This routine marks dead tuples as unused and truncates relation
+ * if there are "empty" end-blocks.
*/
static void
-vc_vacheap (VRelStats *vacrelstats, Relation onerel, VPageList Vvpl)
+vc_vacheap(VRelStats * vacrelstats, Relation onerel, VPageList Vvpl)
{
- Buffer buf;
- Page page;
- VPageDescr *vpp;
- Relation archrel;
- int nblocks;
- int i;
-
- nblocks = Vvpl->vpl_npages;
- /* if the relation has an archive, open it */
- if (onerel->rd_rel->relarch != 'n')
- archrel = vc_getarchrel(onerel);
- else
- {
- archrel = (Relation) NULL;
- nblocks -= Vvpl->vpl_nemend; /* nothing to do with them */
- }
-
- for (i = 0, vpp = Vvpl->vpl_pgdesc; i < nblocks; i++, vpp++)
- {
- if ( (*vpp)->vpd_noff > 0 )
+ Buffer buf;
+ Page page;
+ VPageDescr *vpp;
+ Relation archrel;
+ int nblocks;
+ int i;
+
+ nblocks = Vvpl->vpl_npages;
+ /* if the relation has an archive, open it */
+ if (onerel->rd_rel->relarch != 'n')
+ archrel = vc_getarchrel(onerel);
+ else
{
- buf = ReadBuffer(onerel, (*vpp)->vpd_blkno);
- page = BufferGetPage (buf);
- vc_vacpage (page, *vpp, archrel);
- WriteBuffer (buf);
+ archrel = (Relation) NULL;
+ nblocks -= Vvpl->vpl_nemend; /* nothing to do with them */
+ }
+
+ for (i = 0, vpp = Vvpl->vpl_pgdesc; i < nblocks; i++, vpp++)
+ {
+ if ((*vpp)->vpd_noff > 0)
+ {
+ buf = ReadBuffer(onerel, (*vpp)->vpd_blkno);
+ page = BufferGetPage(buf);
+ vc_vacpage(page, *vpp, archrel);
+ WriteBuffer(buf);
+ }
}
- }
-
- /* truncate relation if there are some empty end-pages */
- if ( Vvpl->vpl_nemend > 0 )
- {
- Assert ( vacrelstats->npages >= Vvpl->vpl_nemend );
- nblocks = vacrelstats->npages - Vvpl->vpl_nemend;
- elog (MESSAGE_LEVEL, "Rel %s: Pages: %u --> %u.",
- (RelationGetRelationName(onerel))->data,
- vacrelstats->npages, nblocks);
-
- /*
- * we have to flush "empty" end-pages (if changed, but who knows it)
- * before truncation
- */
- FlushBufferPool(!TransactionFlushEnabled());
- nblocks = smgrtruncate (onerel->rd_rel->relsmgr, onerel, nblocks);
- Assert ( nblocks >= 0 );
- vacrelstats->npages = nblocks; /* set new number of blocks */
- }
+ /* truncate relation if there are some empty end-pages */
+ if (Vvpl->vpl_nemend > 0)
+ {
+ Assert(vacrelstats->npages >= Vvpl->vpl_nemend);
+ nblocks = vacrelstats->npages - Vvpl->vpl_nemend;
+ elog(MESSAGE_LEVEL, "Rel %s: Pages: %u --> %u.",
+ (RelationGetRelationName(onerel))->data,
+ vacrelstats->npages, nblocks);
+
+ /*
+ * we have to flush "empty" end-pages (if changed, but who knows
+ * it) before truncation
+ */
+ FlushBufferPool(!TransactionFlushEnabled());
+
+ nblocks = smgrtruncate(onerel->rd_rel->relsmgr, onerel, nblocks);
+ Assert(nblocks >= 0);
+ vacrelstats->npages = nblocks; /* set new number of blocks */
+ }
- if ( archrel != (Relation) NULL )
- heap_close(archrel);
+ if (archrel != (Relation) NULL)
+ heap_close(archrel);
-} /* vc_vacheap */
+} /* vc_vacheap */
/*
- * vc_vacpage() -- free (and archive if needed) dead tuples on a page
- * and repaire its fragmentation.
+ * vc_vacpage() -- free (and archive if needed) dead tuples on a page
+ * and repaire its fragmentation.
*/
static void
-vc_vacpage (Page page, VPageDescr vpd, Relation archrel)
+vc_vacpage(Page page, VPageDescr vpd, Relation archrel)
{
- ItemId itemid;
- HeapTuple htup;
- int i;
-
- Assert ( vpd->vpd_nusd == 0 );
- for (i=0; i < vpd->vpd_noff; i++)
- {
- itemid = &(((PageHeader) page)->pd_linp[vpd->vpd_voff[i] - 1]);
- if ( archrel != (Relation) NULL && ItemIdIsUsed(itemid) )
+ ItemId itemid;
+ HeapTuple htup;
+ int i;
+
+ Assert(vpd->vpd_nusd == 0);
+ for (i = 0; i < vpd->vpd_noff; i++)
{
- htup = (HeapTuple) PageGetItem (page, itemid);
- vc_archive (archrel, htup);
+ itemid = &(((PageHeader) page)->pd_linp[vpd->vpd_voff[i] - 1]);
+ if (archrel != (Relation) NULL && ItemIdIsUsed(itemid))
+ {
+ htup = (HeapTuple) PageGetItem(page, itemid);
+ vc_archive(archrel, htup);
+ }
+ itemid->lp_flags &= ~LP_USED;
}
- itemid->lp_flags &= ~LP_USED;
- }
- PageRepairFragmentation(page);
+ PageRepairFragmentation(page);
-} /* vc_vacpage */
+} /* vc_vacpage */
/*
- * _vc_scanoneind() -- scan one index relation to update statistic.
+ * _vc_scanoneind() -- scan one index relation to update statistic.
*
*/
static void
-vc_scanoneind (Relation indrel, int nhtups)
+vc_scanoneind(Relation indrel, int nhtups)
{
- RetrieveIndexResult res;
- IndexScanDesc iscan;
- int nitups;
- int nipages;
- struct rusage ru0, ru1;
+ RetrieveIndexResult res;
+ IndexScanDesc iscan;
+ int nitups;
+ int nipages;
+ struct rusage ru0,
+ ru1;
- getrusage(RUSAGE_SELF, &ru0);
+ getrusage(RUSAGE_SELF, &ru0);
- /* walk through the entire index */
- iscan = index_beginscan(indrel, false, 0, (ScanKey) NULL);
- nitups = 0;
+ /* walk through the entire index */
+ iscan = index_beginscan(indrel, false, 0, (ScanKey) NULL);
+ nitups = 0;
- while ((res = index_getnext(iscan, ForwardScanDirection))
- != (RetrieveIndexResult) NULL)
- {
- nitups++;
- pfree(res);
- }
+ while ((res = index_getnext(iscan, ForwardScanDirection))
+ != (RetrieveIndexResult) NULL)
+ {
+ nitups++;
+ pfree(res);
+ }
- index_endscan(iscan);
+ index_endscan(iscan);
- /* now update statistics in pg_class */
- nipages = RelationGetNumberOfBlocks(indrel);
- vc_updstats(indrel->rd_id, nipages, nitups, false, NULL);
+ /* now update statistics in pg_class */
+ nipages = RelationGetNumberOfBlocks(indrel);
+ vc_updstats(indrel->rd_id, nipages, nitups, false, NULL);
- getrusage(RUSAGE_SELF, &ru1);
+ getrusage(RUSAGE_SELF, &ru1);
- elog (MESSAGE_LEVEL, "Ind %s: Pages %u; Tuples %u. Elapsed %u/%u sec.",
- indrel->rd_rel->relname.data, nipages, nitups,
- ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
- ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
+ elog(MESSAGE_LEVEL, "Ind %s: Pages %u; Tuples %u. Elapsed %u/%u sec.",
+ indrel->rd_rel->relname.data, nipages, nitups,
+ ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
+ ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
- if ( nitups != nhtups )
- elog (NOTICE, "Ind %s: NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)",
- indrel->rd_rel->relname.data, nitups, nhtups);
+ if (nitups != nhtups)
+ elog(NOTICE, "Ind %s: NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)",
+ indrel->rd_rel->relname.data, nitups, nhtups);
-} /* vc_scanoneind */
+} /* vc_scanoneind */
/*
- * vc_vaconeind() -- vacuum one index relation.
+ * vc_vaconeind() -- vacuum one index relation.
*
- * Vpl is the VPageList of the heap we're currently vacuuming.
- * It's locked. Indrel is an index relation on the vacuumed heap.
- * We don't set locks on the index relation here, since the indexed
- * access methods support locking at different granularities.
- * We let them handle it.
+ * Vpl is the VPageList of the heap we're currently vacuuming.
+ * It's locked. Indrel is an index relation on the vacuumed heap.
+ * We don't set locks on the index relation here, since the indexed
+ * access methods support locking at different granularities.
+ * We let them handle it.
*
- * Finally, we arrange to update the index relation's statistics in
- * pg_class.
+ * Finally, we arrange to update the index relation's statistics in
+ * pg_class.
*/
static void
vc_vaconeind(VPageList vpl, Relation indrel, int nhtups)
{
- RetrieveIndexResult res;
- IndexScanDesc iscan;
- ItemPointer heapptr;
- int nvac;
- int nitups;
- int nipages;
- VPageDescr vp;
- struct rusage ru0, ru1;
-
- getrusage(RUSAGE_SELF, &ru0);
-
- /* walk through the entire index */
- iscan = index_beginscan(indrel, false, 0, (ScanKey) NULL);
- nvac = 0;
- nitups = 0;
-
- while ((res = index_getnext(iscan, ForwardScanDirection))
- != (RetrieveIndexResult) NULL) {
- heapptr = &res->heap_iptr;
-
- if ( (vp = vc_tidreapped (heapptr, vpl)) != (VPageDescr) NULL)
+ RetrieveIndexResult res;
+ IndexScanDesc iscan;
+ ItemPointer heapptr;
+ int nvac;
+ int nitups;
+ int nipages;
+ VPageDescr vp;
+ struct rusage ru0,
+ ru1;
+
+ getrusage(RUSAGE_SELF, &ru0);
+
+ /* walk through the entire index */
+ iscan = index_beginscan(indrel, false, 0, (ScanKey) NULL);
+ nvac = 0;
+ nitups = 0;
+
+ while ((res = index_getnext(iscan, ForwardScanDirection))
+ != (RetrieveIndexResult) NULL)
{
+ heapptr = &res->heap_iptr;
+
+ if ((vp = vc_tidreapped(heapptr, vpl)) != (VPageDescr) NULL)
+ {
#if 0
- elog(DEBUG, "<%x,%x> -> <%x,%x>",
- ItemPointerGetBlockNumber(&(res->index_iptr)),
- ItemPointerGetOffsetNumber(&(res->index_iptr)),
- ItemPointerGetBlockNumber(&(res->heap_iptr)),
- ItemPointerGetOffsetNumber(&(res->heap_iptr)));
+ elog(DEBUG, "<%x,%x> -> <%x,%x>",
+ ItemPointerGetBlockNumber(&(res->index_iptr)),
+ ItemPointerGetOffsetNumber(&(res->index_iptr)),
+ ItemPointerGetBlockNumber(&(res->heap_iptr)),
+ ItemPointerGetOffsetNumber(&(res->heap_iptr)));
#endif
- if ( vp->vpd_noff == 0 )
- { /* this is EmptyPage !!! */
- elog (NOTICE, "Ind %s: pointer to EmptyPage (blk %u off %u) - fixing",
- indrel->rd_rel->relname.data,
- vp->vpd_blkno, ItemPointerGetOffsetNumber(heapptr));
- }
- ++nvac;
- index_delete(indrel, &res->index_iptr);
- } else {
- nitups++;
- }
+ if (vp->vpd_noff == 0)
+ { /* this is EmptyPage !!! */
+ elog(NOTICE, "Ind %s: pointer to EmptyPage (blk %u off %u) - fixing",
+ indrel->rd_rel->relname.data,
+ vp->vpd_blkno, ItemPointerGetOffsetNumber(heapptr));
+ }
+ ++nvac;
+ index_delete(indrel, &res->index_iptr);
+ }
+ else
+ {
+ nitups++;
+ }
- /* be tidy */
- pfree(res);
- }
+ /* be tidy */
+ pfree(res);
+ }
- index_endscan(iscan);
+ index_endscan(iscan);
- /* now update statistics in pg_class */
- nipages = RelationGetNumberOfBlocks(indrel);
- vc_updstats(indrel->rd_id, nipages, nitups, false, NULL);
+ /* now update statistics in pg_class */
+ nipages = RelationGetNumberOfBlocks(indrel);
+ vc_updstats(indrel->rd_id, nipages, nitups, false, NULL);
- getrusage(RUSAGE_SELF, &ru1);
+ getrusage(RUSAGE_SELF, &ru1);
- elog (MESSAGE_LEVEL, "Ind %s: Pages %u; Tuples %u: Deleted %u. Elapsed %u/%u sec.",
- indrel->rd_rel->relname.data, nipages, nitups, nvac,
- ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
- ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
+ elog(MESSAGE_LEVEL, "Ind %s: Pages %u; Tuples %u: Deleted %u. Elapsed %u/%u sec.",
+ indrel->rd_rel->relname.data, nipages, nitups, nvac,
+ ru1.ru_stime.tv_sec - ru0.ru_stime.tv_sec,
+ ru1.ru_utime.tv_sec - ru0.ru_utime.tv_sec);
- if ( nitups != nhtups )
- elog (NOTICE, "Ind %s: NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)",
- indrel->rd_rel->relname.data, nitups, nhtups);
+ if (nitups != nhtups)
+ elog(NOTICE, "Ind %s: NUMBER OF INDEX' TUPLES (%u) IS NOT THE SAME AS HEAP' (%u)",
+ indrel->rd_rel->relname.data, nitups, nhtups);
-} /* vc_vaconeind */
+} /* vc_vaconeind */
/*
- * vc_tidreapped() -- is a particular tid reapped?
+ * vc_tidreapped() -- is a particular tid reapped?
*
- * vpl->VPageDescr_array is sorted in right order.
+ * vpl->VPageDescr_array is sorted in right order.
*/
-static VPageDescr
+static VPageDescr
vc_tidreapped(ItemPointer itemptr, VPageList vpl)
{
- OffsetNumber ioffno;
- OffsetNumber *voff;
- VPageDescr vp, *vpp;
- VPageDescrData vpd;
-
- vpd.vpd_blkno = ItemPointerGetBlockNumber(itemptr);
- ioffno = ItemPointerGetOffsetNumber(itemptr);
-
- vp = &vpd;
- vpp = (VPageDescr*) vc_find_eq ((char*)(vpl->vpl_pgdesc),
- vpl->vpl_npages, sizeof (VPageDescr), (char*)&vp,
- vc_cmp_blk);
-
- if ( vpp == (VPageDescr*) NULL )
- return ((VPageDescr)NULL);
- vp = *vpp;
-
- /* ok - we are on true page */
-
- if ( vp->vpd_noff == 0 ) { /* this is EmptyPage !!! */
- return (vp);
- }
-
- voff = (OffsetNumber*) vc_find_eq ((char*)(vp->vpd_voff),
- vp->vpd_noff, sizeof (OffsetNumber), (char*)&ioffno,
- vc_cmp_offno);
+ OffsetNumber ioffno;
+ OffsetNumber *voff;
+ VPageDescr vp,
+ *vpp;
+ VPageDescrData vpd;
- if ( voff == (OffsetNumber*) NULL )
- return ((VPageDescr)NULL);
+ vpd.vpd_blkno = ItemPointerGetBlockNumber(itemptr);
+ ioffno = ItemPointerGetOffsetNumber(itemptr);
- return (vp);
+ vp = &vpd;
+ vpp = (VPageDescr *) vc_find_eq((char *) (vpl->vpl_pgdesc),
+ vpl->vpl_npages, sizeof(VPageDescr), (char *) &vp,
+ vc_cmp_blk);
-} /* vc_tidreapped */
+ if (vpp == (VPageDescr *) NULL)
+ return ((VPageDescr) NULL);
+ vp = *vpp;
+
+ /* ok - we are on true page */
+
+ if (vp->vpd_noff == 0)
+ { /* this is EmptyPage !!! */
+ return (vp);
+ }
+
+ voff = (OffsetNumber *) vc_find_eq((char *) (vp->vpd_voff),
+ vp->vpd_noff, sizeof(OffsetNumber), (char *) &ioffno,
+ vc_cmp_offno);
+
+ if (voff == (OffsetNumber *) NULL)
+ return ((VPageDescr) NULL);
+
+ return (vp);
+
+} /* vc_tidreapped */
/*
- * vc_attrstats() -- compute column statistics used by the optimzer
+ * vc_attrstats() -- compute column statistics used by the optimzer
*
- * We compute the column min, max, null and non-null counts.
- * Plus we attempt to find the count of the value that occurs most
- * frequently in each column
- * These figures are used to compute the selectivity of the column
+ * We compute the column min, max, null and non-null counts.
+ * Plus we attempt to find the count of the value that occurs most
+ * frequently in each column
+ * These figures are used to compute the selectivity of the column
*
- * We use a three-bucked cache to get the most frequent item
- * The 'guess' buckets count hits. A cache miss causes guess1
- * to get the most hit 'guess' item in the most recent cycle, and
- * the new item goes into guess2. Whenever the total count of hits
- * of a 'guess' entry is larger than 'best', 'guess' becomes 'best'.
+ * We use a three-bucked cache to get the most frequent item
+ * The 'guess' buckets count hits. A cache miss causes guess1
+ * to get the most hit 'guess' item in the most recent cycle, and
+ * the new item goes into guess2. Whenever the total count of hits
+ * of a 'guess' entry is larger than 'best', 'guess' becomes 'best'.
*
- * This method works perfectly for columns with unique values, and columns
- * with only two unique values, plus nulls.
+ * This method works perfectly for columns with unique values, and columns
+ * with only two unique values, plus nulls.
*
- * It becomes less perfect as the number of unique values increases and
- * their distribution in the table becomes more random.
+ * It becomes less perfect as the number of unique values increases and
+ * their distribution in the table becomes more random.
*
*/
static void
-vc_attrstats(Relation onerel, VRelStats *vacrelstats, HeapTuple htup)
+vc_attrstats(Relation onerel, VRelStats * vacrelstats, HeapTuple htup)
{
- int i, attr_cnt = vacrelstats->va_natts;
- VacAttrStats *vacattrstats = vacrelstats->vacattrstats;
- TupleDesc tupDesc = onerel->rd_att;
- Datum value;
- bool isnull;
-
- for (i = 0; i < attr_cnt; i++) {
- VacAttrStats *stats = &vacattrstats[i];
- bool value_hit = true;
-
- value = (Datum) heap_getattr (htup, InvalidBuffer,
- stats->attr->attnum, tupDesc, &isnull);
-
- if (!VacAttrStatsEqValid(stats))
- continue;
-
- if (isnull)
- stats->null_cnt++;
- else {
- stats->nonnull_cnt++;
- if (stats->initialized == false) {
- vc_bucketcpy(stats->attr, value, &stats->best, &stats->best_len);
- /* best_cnt gets incremented later */
- vc_bucketcpy(stats->attr, value, &stats->guess1, &stats->guess1_len);
- stats->guess1_cnt = stats->guess1_hits = 1;
- vc_bucketcpy(stats->attr, value, &stats->guess2, &stats->guess2_len);
- stats->guess2_hits = 1;
- if (VacAttrStatsLtGtValid(stats)) {
- vc_bucketcpy(stats->attr, value, &stats->max , &stats->max_len);
- vc_bucketcpy(stats->attr, value, &stats->min, &stats->min_len);
+ int i,
+ attr_cnt = vacrelstats->va_natts;
+ VacAttrStats *vacattrstats = vacrelstats->vacattrstats;
+ TupleDesc tupDesc = onerel->rd_att;
+ Datum value;
+ bool isnull;
+
+ for (i = 0; i < attr_cnt; i++)
+ {
+ VacAttrStats *stats = &vacattrstats[i];
+ bool value_hit = true;
+
+ value = (Datum) heap_getattr(htup, InvalidBuffer,
+ stats->attr->attnum, tupDesc, &isnull);
+
+ if (!VacAttrStatsEqValid(stats))
+ continue;
+
+ if (isnull)
+ stats->null_cnt++;
+ else
+ {
+ stats->nonnull_cnt++;
+ if (stats->initialized == false)
+ {
+ vc_bucketcpy(stats->attr, value, &stats->best, &stats->best_len);
+ /* best_cnt gets incremented later */
+ vc_bucketcpy(stats->attr, value, &stats->guess1, &stats->guess1_len);
+ stats->guess1_cnt = stats->guess1_hits = 1;
+ vc_bucketcpy(stats->attr, value, &stats->guess2, &stats->guess2_len);
+ stats->guess2_hits = 1;
+ if (VacAttrStatsLtGtValid(stats))
+ {
+ vc_bucketcpy(stats->attr, value, &stats->max, &stats->max_len);
+ vc_bucketcpy(stats->attr, value, &stats->min, &stats->min_len);
+ }
+ stats->initialized = true;
+ }
+ if (VacAttrStatsLtGtValid(stats))
+ {
+ if ((*(stats->f_cmplt)) (value, stats->min))
+ {
+ vc_bucketcpy(stats->attr, value, &stats->min, &stats->min_len);
+ stats->min_cnt = 0;
+ }
+ if ((*(stats->f_cmpgt)) (value, stats->max))
+ {
+ vc_bucketcpy(stats->attr, value, &stats->max, &stats->max_len);
+ stats->max_cnt = 0;
+ }
+ if ((*(stats->f_cmpeq)) (value, stats->min))
+ stats->min_cnt++;
+ else if ((*(stats->f_cmpeq)) (value, stats->max))
+ stats->max_cnt++;
+ }
+ if ((*(stats->f_cmpeq)) (value, stats->best))
+ stats->best_cnt++;
+ else if ((*(stats->f_cmpeq)) (value, stats->guess1))
+ {
+ stats->guess1_cnt++;
+ stats->guess1_hits++;
+ }
+ else if ((*(stats->f_cmpeq)) (value, stats->guess2))
+ stats->guess2_hits++;
+ else
+ value_hit = false;
+
+ if (stats->guess2_hits > stats->guess1_hits)
+ {
+ swapDatum(stats->guess1, stats->guess2);
+ swapInt(stats->guess1_len, stats->guess2_len);
+ stats->guess1_cnt = stats->guess2_hits;
+ swapLong(stats->guess1_hits, stats->guess2_hits);
+ }
+ if (stats->guess1_cnt > stats->best_cnt)
+ {
+ swapDatum(stats->best, stats->guess1);
+ swapInt(stats->best_len, stats->guess1_len);
+ swapLong(stats->best_cnt, stats->guess1_cnt);
+ stats->guess1_hits = 1;
+ stats->guess2_hits = 1;
+ }
+ if (!value_hit)
+ {
+ vc_bucketcpy(stats->attr, value, &stats->guess2, &stats->guess2_len);
+ stats->guess1_hits = 1;
+ stats->guess2_hits = 1;
+ }
}
- stats->initialized = true;
- }
- if (VacAttrStatsLtGtValid(stats)) {
- if ( (*(stats->f_cmplt)) (value,stats->min) ) {
- vc_bucketcpy(stats->attr, value, &stats->min, &stats->min_len);
- stats->min_cnt = 0;
- }
- if ( (*(stats->f_cmpgt)) (value,stats->max) ) {
- vc_bucketcpy(stats->attr, value, &stats->max, &stats->max_len);
- stats->max_cnt = 0;
- }
- if ( (*(stats->f_cmpeq)) (value,stats->min) )
- stats->min_cnt++;
- else if ( (*(stats->f_cmpeq)) (value,stats->max) )
- stats->max_cnt++;
- }
- if ( (*(stats->f_cmpeq)) (value,stats->best) )
- stats->best_cnt++;
- else if ( (*(stats->f_cmpeq)) (value,stats->guess1) ) {
- stats->guess1_cnt++;
- stats->guess1_hits++;
- }
- else if ( (*(stats->f_cmpeq)) (value,stats->guess2) )
- stats->guess2_hits++;
- else value_hit = false;
-
- if (stats->guess2_hits > stats->guess1_hits) {
- swapDatum(stats->guess1,stats->guess2);
- swapInt(stats->guess1_len,stats->guess2_len);
- stats->guess1_cnt = stats->guess2_hits;
- swapLong(stats->guess1_hits, stats->guess2_hits);
- }
- if (stats->guess1_cnt > stats->best_cnt) {
- swapDatum(stats->best,stats->guess1);
- swapInt(stats->best_len,stats->guess1_len);
- swapLong(stats->best_cnt,stats->guess1_cnt);
- stats->guess1_hits = 1;
- stats->guess2_hits = 1;
- }
- if (!value_hit) {
- vc_bucketcpy(stats->attr, value, &stats->guess2, &stats->guess2_len);
- stats->guess1_hits = 1;
- stats->guess2_hits = 1;
- }
}
- }
- return;
+ return;
}
/*
- * vc_bucketcpy() -- update pg_class statistics for one relation
+ * vc_bucketcpy() -- update pg_class statistics for one relation
*
*/
static void
-vc_bucketcpy(AttributeTupleForm attr, Datum value, Datum *bucket, int16 *bucket_len)
+vc_bucketcpy(AttributeTupleForm attr, Datum value, Datum * bucket, int16 * bucket_len)
{
- if (attr->attbyval && attr->attlen != -1)
- *bucket = value;
- else {
- int len = (attr->attlen != -1 ? attr->attlen : VARSIZE(value));
-
- if (len > *bucket_len)
- {
- if (*bucket_len != 0)
- pfree(DatumGetPointer(*bucket));
- *bucket = PointerGetDatum(palloc(len));
- *bucket_len = len;
+ if (attr->attbyval && attr->attlen != -1)
+ *bucket = value;
+ else
+ {
+ int len = (attr->attlen != -1 ? attr->attlen : VARSIZE(value));
+
+ if (len > *bucket_len)
+ {
+ if (*bucket_len != 0)
+ pfree(DatumGetPointer(*bucket));
+ *bucket = PointerGetDatum(palloc(len));
+ *bucket_len = len;
+ }
+ memmove(DatumGetPointer(*bucket), DatumGetPointer(value), len);
}
- memmove(DatumGetPointer(*bucket), DatumGetPointer(value), len);
- }
}
/*
- * vc_updstats() -- update pg_class statistics for one relation
+ * vc_updstats() -- update pg_class statistics for one relation
*
- * This routine works for both index and heap relation entries in
- * pg_class. We violate no-overwrite semantics here by storing new
- * values for ntups, npages, and hasindex directly in the pg_class
- * tuple that's already on the page. The reason for this is that if
- * we updated these tuples in the usual way, then every tuple in pg_class
- * would be replaced every day. This would make planning and executing
- * historical queries very expensive.
+ * This routine works for both index and heap relation entries in
+ * pg_class. We violate no-overwrite semantics here by storing new
+ * values for ntups, npages, and hasindex directly in the pg_class
+ * tuple that's already on the page. The reason for this is that if
+ * we updated these tuples in the usual way, then every tuple in pg_class
+ * would be replaced every day. This would make planning and executing
+ * historical queries very expensive.
*/
static void
-vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VRelStats *vacrelstats)
+vc_updstats(Oid relid, int npages, int ntups, bool hasindex, VRelStats * vacrelstats)
{
- Relation rd, ad, sd;
- HeapScanDesc rsdesc, asdesc;
- TupleDesc sdesc;
- HeapTuple rtup, atup, stup;
- Buffer rbuf, abuf;
- Form_pg_class pgcform;
- ScanKeyData rskey, askey;
- AttributeTupleForm attp;
-
- /*
- * update number of tuples and number of pages in pg_class
- */
- ScanKeyEntryInitialize(&rskey, 0x0, ObjectIdAttributeNumber,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(relid));
-
- rd = heap_openr(RelationRelationName);
- rsdesc = heap_beginscan(rd, false, NowTimeQual, 1, &rskey);
-
- if (!HeapTupleIsValid(rtup = heap_getnext(rsdesc, 0, &rbuf)))
- elog(WARN, "pg_class entry for relid %d vanished during vacuuming",
- relid);
-
- /* overwrite the existing statistics in the tuple */
- vc_setpagelock(rd, BufferGetBlockNumber(rbuf));
- pgcform = (Form_pg_class) GETSTRUCT(rtup);
- pgcform->reltuples = ntups;
- pgcform->relpages = npages;
- pgcform->relhasindex = hasindex;
-
- if ( vacrelstats != NULL && vacrelstats->va_natts > 0 )
- {
- VacAttrStats *vacattrstats = vacrelstats->vacattrstats;
- int natts = vacrelstats->va_natts;
-
- ad = heap_openr(AttributeRelationName);
- sd = heap_openr(StatisticRelationName);
- ScanKeyEntryInitialize(&askey, 0, Anum_pg_attribute_attrelid,
- F_INT4EQ, relid);
-
- asdesc = heap_beginscan(ad, false, NowTimeQual, 1, &askey);
-
- while (HeapTupleIsValid(atup = heap_getnext(asdesc, 0, &abuf)))
+ Relation rd,
+ ad,
+ sd;
+ HeapScanDesc rsdesc,
+ asdesc;
+ TupleDesc sdesc;
+ HeapTuple rtup,
+ atup,
+ stup;
+ Buffer rbuf,
+ abuf;
+ Form_pg_class pgcform;
+ ScanKeyData rskey,
+ askey;
+ AttributeTupleForm attp;
+
+ /*
+ * update number of tuples and number of pages in pg_class
+ */
+ ScanKeyEntryInitialize(&rskey, 0x0, ObjectIdAttributeNumber,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(relid));
+
+ rd = heap_openr(RelationRelationName);
+ rsdesc = heap_beginscan(rd, false, NowTimeQual, 1, &rskey);
+
+ if (!HeapTupleIsValid(rtup = heap_getnext(rsdesc, 0, &rbuf)))
+ elog(WARN, "pg_class entry for relid %d vanished during vacuuming",
+ relid);
+
+ /* overwrite the existing statistics in the tuple */
+ vc_setpagelock(rd, BufferGetBlockNumber(rbuf));
+ pgcform = (Form_pg_class) GETSTRUCT(rtup);
+ pgcform->reltuples = ntups;
+ pgcform->relpages = npages;
+ pgcform->relhasindex = hasindex;
+
+ if (vacrelstats != NULL && vacrelstats->va_natts > 0)
{
- int i;
- float32data selratio; /* average ratio of rows selected for a random constant */
- VacAttrStats *stats;
- Datum values[ Natts_pg_statistic ];
- char nulls[ Natts_pg_statistic ];
-
- attp = (AttributeTupleForm) GETSTRUCT(atup);
- if ( attp->attnum <= 0) /* skip system attributes for now, */
- /* they are unique anyway */
- continue;
-
- for (i = 0; i < natts; i++)
- {
- if ( attp->attnum == vacattrstats[i].attr->attnum )
- break;
- }
- if ( i >= natts )
- continue;
- stats = &(vacattrstats[i]);
-
- /* overwrite the existing statistics in the tuple */
- if (VacAttrStatsEqValid(stats)) {
-
- vc_setpagelock(ad, BufferGetBlockNumber(abuf));
-
- if (stats->nonnull_cnt + stats->null_cnt == 0 ||
- (stats->null_cnt <= 1 && stats->best_cnt == 1))
- selratio = 0;
- else if (VacAttrStatsLtGtValid(stats) && stats->min_cnt + stats->max_cnt == stats->nonnull_cnt)
+ VacAttrStats *vacattrstats = vacrelstats->vacattrstats;
+ int natts = vacrelstats->va_natts;
+
+ ad = heap_openr(AttributeRelationName);
+ sd = heap_openr(StatisticRelationName);
+ ScanKeyEntryInitialize(&askey, 0, Anum_pg_attribute_attrelid,
+ F_INT4EQ, relid);
+
+ asdesc = heap_beginscan(ad, false, NowTimeQual, 1, &askey);
+
+ while (HeapTupleIsValid(atup = heap_getnext(asdesc, 0, &abuf)))
{
- double min_cnt_d = stats->min_cnt,
- max_cnt_d = stats->max_cnt,
- null_cnt_d = stats->null_cnt,
- nonnullcnt_d = stats->nonnull_cnt; /* prevent overflow */
- selratio = (min_cnt_d*min_cnt_d+max_cnt_d*max_cnt_d+null_cnt_d*null_cnt_d)/
- (nonnullcnt_d+null_cnt_d)/(nonnullcnt_d+null_cnt_d);
+ int i;
+ float32data selratio; /* average ratio of rows selected
+ * for a random constant */
+ VacAttrStats *stats;
+ Datum values[Natts_pg_statistic];
+ char nulls[Natts_pg_statistic];
+
+ attp = (AttributeTupleForm) GETSTRUCT(atup);
+ if (attp->attnum <= 0) /* skip system attributes for now, */
+ /* they are unique anyway */
+ continue;
+
+ for (i = 0; i < natts; i++)
+ {
+ if (attp->attnum == vacattrstats[i].attr->attnum)
+ break;
+ }
+ if (i >= natts)
+ continue;
+ stats = &(vacattrstats[i]);
+
+ /* overwrite the existing statistics in the tuple */
+ if (VacAttrStatsEqValid(stats))
+ {
+
+ vc_setpagelock(ad, BufferGetBlockNumber(abuf));
+
+ if (stats->nonnull_cnt + stats->null_cnt == 0 ||
+ (stats->null_cnt <= 1 && stats->best_cnt == 1))
+ selratio = 0;
+ else if (VacAttrStatsLtGtValid(stats) && stats->min_cnt + stats->max_cnt == stats->nonnull_cnt)
+ {
+ double min_cnt_d = stats->min_cnt,
+ max_cnt_d = stats->max_cnt,
+ null_cnt_d = stats->null_cnt,
+ nonnullcnt_d = stats->nonnull_cnt; /* prevent overflow */
+
+ selratio = (min_cnt_d * min_cnt_d + max_cnt_d * max_cnt_d + null_cnt_d * null_cnt_d) /
+ (nonnullcnt_d + null_cnt_d) / (nonnullcnt_d + null_cnt_d);
+ }
+ else
+ {
+ double most = (double) (stats->best_cnt > stats->null_cnt ? stats->best_cnt : stats->null_cnt);
+ double total = ((double) stats->nonnull_cnt) + ((double) stats->null_cnt);
+
+ /*
+ * we assume count of other values are 20% of best
+ * count in table
+ */
+ selratio = (most * most + 0.20 * most * (total - most)) / total / total;
+ }
+ if (selratio > 1.0)
+ selratio = 1.0;
+ attp->attdisbursion = selratio;
+ WriteNoReleaseBuffer(abuf);
+
+ /* DO PG_STATISTIC INSERTS */
+
+ /*
+ * doing system relations, especially pg_statistic is a
+ * problem
+ */
+ if (VacAttrStatsLtGtValid(stats) && stats->initialized /* &&
+ * !IsSystemRelationName(
+ * pgcform->relname.data)
+ */ )
+ {
+ func_ptr out_function;
+ char *out_string;
+ int dummy;
+
+ for (i = 0; i < Natts_pg_statistic; ++i)
+ nulls[i] = ' ';
+
+ /* ----------------
+ * initialize values[]
+ * ----------------
+ */
+ i = 0;
+ values[i++] = (Datum) relid; /* 1 */
+ values[i++] = (Datum) attp->attnum; /* 2 */
+ values[i++] = (Datum) InvalidOid; /* 3 */
+ fmgr_info(stats->outfunc, &out_function, &dummy);
+ out_string = (*out_function) (stats->min, stats->attr->atttypid);
+ values[i++] = (Datum) fmgr(TextInRegProcedure, out_string);
+ pfree(out_string);
+ out_string = (char *) (*out_function) (stats->max, stats->attr->atttypid);
+ values[i++] = (Datum) fmgr(TextInRegProcedure, out_string);
+ pfree(out_string);
+
+ sdesc = sd->rd_att;
+
+ stup = heap_formtuple(sdesc, values, nulls);
+
+ /* ----------------
+ * insert the tuple in the relation and get the tuple's oid.
+ * ----------------
+ */
+ heap_insert(sd, stup);
+ pfree(DatumGetPointer(values[3]));
+ pfree(DatumGetPointer(values[4]));
+ pfree(stup);
+ }
+ }
}
- else {
- double most = (double)(stats->best_cnt > stats->null_cnt ? stats->best_cnt : stats->null_cnt);
- double total = ((double)stats->nonnull_cnt)+((double)stats->null_cnt);
- /* we assume count of other values are 20%
- of best count in table */
- selratio = (most*most + 0.20*most*(total-most))/total/total;
- }
- if (selratio > 1.0)
- selratio = 1.0;
- attp->attdisbursion = selratio;
- WriteNoReleaseBuffer(abuf);
-
- /* DO PG_STATISTIC INSERTS */
-
- /* doing system relations, especially pg_statistic is a problem */
- if (VacAttrStatsLtGtValid(stats) && stats->initialized /* &&
- !IsSystemRelationName(pgcform->relname.data)*/) {
- func_ptr out_function;
- char *out_string;
- int dummy;
-
- for (i = 0; i < Natts_pg_statistic; ++i) nulls[i] = ' ';
-
- /* ----------------
- * initialize values[]
- * ----------------
- */
- i = 0;
- values[i++] = (Datum) relid; /* 1 */
- values[i++] = (Datum) attp->attnum; /* 2 */
- values[i++] = (Datum) InvalidOid; /* 3 */
- fmgr_info(stats->outfunc, &out_function, &dummy);
- out_string = (*out_function)(stats->min, stats->attr->atttypid);
- values[i++] = (Datum) fmgr(TextInRegProcedure,out_string);
- pfree(out_string);
- out_string = (char *)(*out_function)(stats->max, stats->attr->atttypid);
- values[i++] = (Datum) fmgr(TextInRegProcedure,out_string);
- pfree(out_string);
-
- sdesc = sd->rd_att;
-
- stup = heap_formtuple(sdesc, values, nulls);
-
- /* ----------------
- * insert the tuple in the relation and get the tuple's oid.
- * ----------------
- */
- heap_insert(sd, stup);
- pfree(DatumGetPointer(values[3]));
- pfree(DatumGetPointer(values[4]));
- pfree(stup);
- }
- }
+ heap_endscan(asdesc);
+ heap_close(ad);
+ heap_close(sd);
}
- heap_endscan(asdesc);
- heap_close(ad);
- heap_close(sd);
- }
-
- /* XXX -- after write, should invalidate relcache in other backends */
- WriteNoReleaseBuffer(rbuf); /* heap_endscan release scan' buffers ? */
-
- /* invalidating system relations confuses the function cache
- of pg_operator and pg_opclass */
- if ( !IsSystemRelationName(pgcform->relname.data))
- RelationInvalidateHeapTuple(rd, rtup);
-
- /* that's all, folks */
- heap_endscan(rsdesc);
- heap_close(rd);
+
+ /* XXX -- after write, should invalidate relcache in other backends */
+ WriteNoReleaseBuffer(rbuf); /* heap_endscan release scan' buffers ? */
+
+ /*
+ * invalidating system relations confuses the function cache of
+ * pg_operator and pg_opclass
+ */
+ if (!IsSystemRelationName(pgcform->relname.data))
+ RelationInvalidateHeapTuple(rd, rtup);
+
+ /* that's all, folks */
+ heap_endscan(rsdesc);
+ heap_close(rd);
}
/*
- * vc_delhilowstats() -- delete pg_statistics rows
+ * vc_delhilowstats() -- delete pg_statistics rows
*
*/
static void
vc_delhilowstats(Oid relid, int attcnt, int *attnums)
{
- Relation pgstatistic;
- HeapScanDesc pgsscan;
- HeapTuple pgstup;
- ScanKeyData pgskey;
-
- pgstatistic = heap_openr(StatisticRelationName);
-
- if (relid != InvalidOid ) {
- ScanKeyEntryInitialize(&pgskey, 0x0, Anum_pg_statistic_starelid,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(relid));
- pgsscan = heap_beginscan(pgstatistic, false, NowTimeQual, 1, &pgskey);
- }
- else
- pgsscan = heap_beginscan(pgstatistic, false, NowTimeQual, 0, NULL);
-
- while (HeapTupleIsValid(pgstup = heap_getnext(pgsscan, 0, NULL)))
- {
- if ( attcnt > 0 )
- {
- Form_pg_statistic pgs = (Form_pg_statistic) GETSTRUCT (pgstup);
- int i;
-
- for (i = 0; i < attcnt; i++)
- {
- if ( pgs->staattnum == attnums[i] + 1 )
- break;
- }
- if ( i >= attcnt )
- continue; /* don't delete it */
- }
- heap_delete(pgstatistic, &pgstup->t_ctid);
- }
-
- heap_endscan(pgsscan);
- heap_close(pgstatistic);
+ Relation pgstatistic;
+ HeapScanDesc pgsscan;
+ HeapTuple pgstup;
+ ScanKeyData pgskey;
+
+ pgstatistic = heap_openr(StatisticRelationName);
+
+ if (relid != InvalidOid)
+ {
+ ScanKeyEntryInitialize(&pgskey, 0x0, Anum_pg_statistic_starelid,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(relid));
+ pgsscan = heap_beginscan(pgstatistic, false, NowTimeQual, 1, &pgskey);
+ }
+ else
+ pgsscan = heap_beginscan(pgstatistic, false, NowTimeQual, 0, NULL);
+
+ while (HeapTupleIsValid(pgstup = heap_getnext(pgsscan, 0, NULL)))
+ {
+ if (attcnt > 0)
+ {
+ Form_pg_statistic pgs = (Form_pg_statistic) GETSTRUCT(pgstup);
+ int i;
+
+ for (i = 0; i < attcnt; i++)
+ {
+ if (pgs->staattnum == attnums[i] + 1)
+ break;
+ }
+ if (i >= attcnt)
+ continue; /* don't delete it */
+ }
+ heap_delete(pgstatistic, &pgstup->t_ctid);
+ }
+
+ heap_endscan(pgsscan);
+ heap_close(pgstatistic);
}
-static void vc_setpagelock(Relation rel, BlockNumber blkno)
+static void
+vc_setpagelock(Relation rel, BlockNumber blkno)
{
- ItemPointerData itm;
+ ItemPointerData itm;
- ItemPointerSet(&itm, blkno, 1);
+ ItemPointerSet(&itm, blkno, 1);
- RelationSetLockForWritePage(rel, &itm);
+ RelationSetLockForWritePage(rel, &itm);
}
/*
- * vc_reappage() -- save a page on the array of reapped pages.
+ * vc_reappage() -- save a page on the array of reapped pages.
*
- * As a side effect of the way that the vacuuming loop for a given
- * relation works, higher pages come after lower pages in the array
- * (and highest tid on a page is last).
+ * As a side effect of the way that the vacuuming loop for a given
+ * relation works, higher pages come after lower pages in the array
+ * (and highest tid on a page is last).
*/
-static void
+static void
vc_reappage(VPageList vpl, VPageDescr vpc)
{
- VPageDescr newvpd;
+ VPageDescr newvpd;
- /* allocate a VPageDescrData entry */
- newvpd = (VPageDescr) palloc(sizeof(VPageDescrData) + vpc->vpd_noff*sizeof(OffsetNumber));
+ /* allocate a VPageDescrData entry */
+ newvpd = (VPageDescr) palloc(sizeof(VPageDescrData) + vpc->vpd_noff * sizeof(OffsetNumber));
- /* fill it in */
- if ( vpc->vpd_noff > 0 )
- memmove (newvpd->vpd_voff, vpc->vpd_voff, vpc->vpd_noff*sizeof(OffsetNumber));
- newvpd->vpd_blkno = vpc->vpd_blkno;
- newvpd->vpd_free = vpc->vpd_free;
- newvpd->vpd_nusd = vpc->vpd_nusd;
- newvpd->vpd_noff = vpc->vpd_noff;
+ /* fill it in */
+ if (vpc->vpd_noff > 0)
+ memmove(newvpd->vpd_voff, vpc->vpd_voff, vpc->vpd_noff * sizeof(OffsetNumber));
+ newvpd->vpd_blkno = vpc->vpd_blkno;
+ newvpd->vpd_free = vpc->vpd_free;
+ newvpd->vpd_nusd = vpc->vpd_nusd;
+ newvpd->vpd_noff = vpc->vpd_noff;
- /* insert this page into vpl list */
- vc_vpinsert (vpl, newvpd);
-
-} /* vc_reappage */
+ /* insert this page into vpl list */
+ vc_vpinsert(vpl, newvpd);
+
+} /* vc_reappage */
static void
-vc_vpinsert (VPageList vpl, VPageDescr vpnew)
+vc_vpinsert(VPageList vpl, VPageDescr vpnew)
{
- /* allocate a VPageDescr entry if needed */
- if ( vpl->vpl_npages == 0 )
- vpl->vpl_pgdesc = (VPageDescr*) palloc(100*sizeof(VPageDescr));
- else if ( vpl->vpl_npages % 100 == 0 )
- vpl->vpl_pgdesc = (VPageDescr*) repalloc(vpl->vpl_pgdesc, (vpl->vpl_npages+100)*sizeof(VPageDescr));
- vpl->vpl_pgdesc[vpl->vpl_npages] = vpnew;
- (vpl->vpl_npages)++;
-
+ /* allocate a VPageDescr entry if needed */
+ if (vpl->vpl_npages == 0)
+ vpl->vpl_pgdesc = (VPageDescr *) palloc(100 * sizeof(VPageDescr));
+ else if (vpl->vpl_npages % 100 == 0)
+ vpl->vpl_pgdesc = (VPageDescr *) repalloc(vpl->vpl_pgdesc, (vpl->vpl_npages + 100) * sizeof(VPageDescr));
+ vpl->vpl_pgdesc[vpl->vpl_npages] = vpnew;
+ (vpl->vpl_npages)++;
+
}
static void
vc_free(VRelList vrl)
{
- VRelList p_vrl;
- MemoryContext old;
- PortalVariableMemory pmem;
+ VRelList p_vrl;
+ MemoryContext old;
+ PortalVariableMemory pmem;
- pmem = PortalGetVariableMemory(vc_portal);
- old = MemoryContextSwitchTo((MemoryContext)pmem);
+ pmem = PortalGetVariableMemory(vc_portal);
+ old = MemoryContextSwitchTo((MemoryContext) pmem);
- while (vrl != (VRelList) NULL) {
+ while (vrl != (VRelList) NULL)
+ {
- /* free rel list entry */
- p_vrl = vrl;
- vrl = vrl->vrl_next;
- pfree(p_vrl);
- }
+ /* free rel list entry */
+ p_vrl = vrl;
+ vrl = vrl->vrl_next;
+ pfree(p_vrl);
+ }
- MemoryContextSwitchTo(old);
+ MemoryContextSwitchTo(old);
}
/*
- * vc_getarchrel() -- open the archive relation for a heap relation
+ * vc_getarchrel() -- open the archive relation for a heap relation
*
- * The archive relation is named 'a,XXXXX' for the heap relation
- * whose relid is XXXXX.
+ * The archive relation is named 'a,XXXXX' for the heap relation
+ * whose relid is XXXXX.
*/
#define ARCHIVE_PREFIX "a,"
-static Relation
+static Relation
vc_getarchrel(Relation heaprel)
{
- Relation archrel;
- char *archrelname;
+ Relation archrel;
+ char *archrelname;
- archrelname = palloc(sizeof(ARCHIVE_PREFIX) + NAMEDATALEN); /* bogus */
- sprintf(archrelname, "%s%d", ARCHIVE_PREFIX, heaprel->rd_id);
+ archrelname = palloc(sizeof(ARCHIVE_PREFIX) + NAMEDATALEN); /* bogus */
+ sprintf(archrelname, "%s%d", ARCHIVE_PREFIX, heaprel->rd_id);
- archrel = heap_openr(archrelname);
+ archrel = heap_openr(archrelname);
- pfree(archrelname);
- return (archrel);
+ pfree(archrelname);
+ return (archrel);
}
/*
- * vc_archive() -- write a tuple to an archive relation
+ * vc_archive() -- write a tuple to an archive relation
*
- * In the future, this will invoke the archived accessd method. For
- * now, archive relations are on mag disk.
+ * In the future, this will invoke the archived accessd method. For
+ * now, archive relations are on mag disk.
*/
static void
vc_archive(Relation archrel, HeapTuple htup)
{
- doinsert(archrel, htup);
+ doinsert(archrel, htup);
}
-static bool
+static bool
vc_isarchrel(char *rname)
{
- if (strncmp(ARCHIVE_PREFIX, rname,strlen(ARCHIVE_PREFIX)) == 0)
- return (true);
+ if (strncmp(ARCHIVE_PREFIX, rname, strlen(ARCHIVE_PREFIX)) == 0)
+ return (true);
- return (false);
+ return (false);
}
-static char *
-vc_find_eq (char *bot, int nelem, int size, char *elm, int (*compar)(char *, char *))
+static char *
+vc_find_eq(char *bot, int nelem, int size, char *elm, int (*compar) (char *, char *))
{
- int res;
- int last = nelem - 1;
- int celm = nelem / 2;
- bool last_move, first_move;
-
- last_move = first_move = true;
- for ( ; ; )
- {
- if ( first_move == true )
+ int res;
+ int last = nelem - 1;
+ int celm = nelem / 2;
+ bool last_move,
+ first_move;
+
+ last_move = first_move = true;
+ for (;;)
{
- res = compar (bot, elm);
- if ( res > 0 )
- return (NULL);
- if ( res == 0 )
- return (bot);
- first_move = false;
- }
- if ( last_move == true )
- {
- res = compar (elm, bot + last*size);
- if ( res > 0 )
- return (NULL);
- if ( res == 0 )
- return (bot + last*size);
- last_move = false;
- }
- res = compar (elm, bot + celm*size);
- if ( res == 0 )
- return (bot + celm*size);
- if ( res < 0 )
- {
- if ( celm == 0 )
- return (NULL);
- last = celm - 1;
- celm = celm / 2;
- last_move = true;
- continue;
+ if (first_move == true)
+ {
+ res = compar(bot, elm);
+ if (res > 0)
+ return (NULL);
+ if (res == 0)
+ return (bot);
+ first_move = false;
+ }
+ if (last_move == true)
+ {
+ res = compar(elm, bot + last * size);
+ if (res > 0)
+ return (NULL);
+ if (res == 0)
+ return (bot + last * size);
+ last_move = false;
+ }
+ res = compar(elm, bot + celm * size);
+ if (res == 0)
+ return (bot + celm * size);
+ if (res < 0)
+ {
+ if (celm == 0)
+ return (NULL);
+ last = celm - 1;
+ celm = celm / 2;
+ last_move = true;
+ continue;
+ }
+
+ if (celm == last)
+ return (NULL);
+
+ last = last - celm - 1;
+ bot = bot + (celm + 1) * size;
+ celm = (last + 1) / 2;
+ first_move = true;
}
-
- if ( celm == last )
- return (NULL);
-
- last = last - celm - 1;
- bot = bot + (celm+1)*size;
- celm = (last + 1) / 2;
- first_move = true;
- }
-
-} /* vc_find_eq */
-
-static int
-vc_cmp_blk (char *left, char *right)
+
+} /* vc_find_eq */
+
+static int
+vc_cmp_blk(char *left, char *right)
{
- BlockNumber lblk, rblk;
+ BlockNumber lblk,
+ rblk;
- lblk = (*((VPageDescr*)left))->vpd_blkno;
- rblk = (*((VPageDescr*)right))->vpd_blkno;
+ lblk = (*((VPageDescr *) left))->vpd_blkno;
+ rblk = (*((VPageDescr *) right))->vpd_blkno;
- if ( lblk < rblk )
- return (-1);
- if ( lblk == rblk )
- return (0);
- return (1);
+ if (lblk < rblk)
+ return (-1);
+ if (lblk == rblk)
+ return (0);
+ return (1);
-} /* vc_cmp_blk */
+} /* vc_cmp_blk */
-static int
-vc_cmp_offno (char *left, char *right)
+static int
+vc_cmp_offno(char *left, char *right)
{
- if ( *(OffsetNumber*)left < *(OffsetNumber*)right )
- return (-1);
- if ( *(OffsetNumber*)left == *(OffsetNumber*)right )
- return (0);
- return (1);
+ if (*(OffsetNumber *) left < *(OffsetNumber *) right)
+ return (-1);
+ if (*(OffsetNumber *) left == *(OffsetNumber *) right)
+ return (0);
+ return (1);
-} /* vc_cmp_offno */
+} /* vc_cmp_offno */
static void
-vc_getindices (Oid relid, int *nindices, Relation **Irel)
+vc_getindices(Oid relid, int *nindices, Relation ** Irel)
{
- Relation pgindex;
- Relation irel;
- TupleDesc pgidesc;
- HeapTuple pgitup;
- HeapScanDesc pgiscan;
- Datum d;
- int i, k;
- bool n;
- ScanKeyData pgikey;
- Oid *ioid;
-
- *nindices = i = 0;
-
- ioid = (Oid *) palloc(10*sizeof(Oid));
-
- /* prepare a heap scan on the pg_index relation */
- pgindex = heap_openr(IndexRelationName);
- pgidesc = RelationGetTupleDescriptor(pgindex);
-
- ScanKeyEntryInitialize(&pgikey, 0x0, Anum_pg_index_indrelid,
- ObjectIdEqualRegProcedure,
- ObjectIdGetDatum(relid));
-
- pgiscan = heap_beginscan(pgindex, false, NowTimeQual, 1, &pgikey);
-
- while (HeapTupleIsValid(pgitup = heap_getnext(pgiscan, 0, NULL))) {
- d = (Datum) heap_getattr(pgitup, InvalidBuffer, Anum_pg_index_indexrelid,
- pgidesc, &n);
- i++;
- if ( i % 10 == 0 )
- ioid = (Oid *) repalloc(ioid, (i+10)*sizeof(Oid));
- ioid[i-1] = DatumGetObjectId(d);
- }
-
- heap_endscan(pgiscan);
- heap_close(pgindex);
-
- if ( i == 0 ) { /* No one index found */
- pfree(ioid);
- return;
- }
-
- if ( Irel != (Relation **) NULL )
- *Irel = (Relation *) palloc(i * sizeof(Relation));
-
- for (k = 0; i > 0; )
- {
- irel = index_open(ioid[--i]);
- if ( irel != (Relation) NULL )
+ Relation pgindex;
+ Relation irel;
+ TupleDesc pgidesc;
+ HeapTuple pgitup;
+ HeapScanDesc pgiscan;
+ Datum d;
+ int i,
+ k;
+ bool n;
+ ScanKeyData pgikey;
+ Oid *ioid;
+
+ *nindices = i = 0;
+
+ ioid = (Oid *) palloc(10 * sizeof(Oid));
+
+ /* prepare a heap scan on the pg_index relation */
+ pgindex = heap_openr(IndexRelationName);
+ pgidesc = RelationGetTupleDescriptor(pgindex);
+
+ ScanKeyEntryInitialize(&pgikey, 0x0, Anum_pg_index_indrelid,
+ ObjectIdEqualRegProcedure,
+ ObjectIdGetDatum(relid));
+
+ pgiscan = heap_beginscan(pgindex, false, NowTimeQual, 1, &pgikey);
+
+ while (HeapTupleIsValid(pgitup = heap_getnext(pgiscan, 0, NULL)))
{
- if ( Irel != (Relation **) NULL )
- (*Irel)[k] = irel;
- else
- index_close (irel);
- k++;
+ d = (Datum) heap_getattr(pgitup, InvalidBuffer, Anum_pg_index_indexrelid,
+ pgidesc, &n);
+ i++;
+ if (i % 10 == 0)
+ ioid = (Oid *) repalloc(ioid, (i + 10) * sizeof(Oid));
+ ioid[i - 1] = DatumGetObjectId(d);
}
- else
- elog (NOTICE, "CAN't OPEN INDEX %u - SKIP IT", ioid[i]);
- }
- *nindices = k;
- pfree(ioid);
- if ( Irel != (Relation **) NULL && *nindices == 0 )
- {
- pfree (*Irel);
- *Irel = (Relation *) NULL;
- }
+ heap_endscan(pgiscan);
+ heap_close(pgindex);
+
+ if (i == 0)
+ { /* No one index found */
+ pfree(ioid);
+ return;
+ }
+
+ if (Irel != (Relation **) NULL)
+ *Irel = (Relation *) palloc(i * sizeof(Relation));
+
+ for (k = 0; i > 0;)
+ {
+ irel = index_open(ioid[--i]);
+ if (irel != (Relation) NULL)
+ {
+ if (Irel != (Relation **) NULL)
+ (*Irel)[k] = irel;
+ else
+ index_close(irel);
+ k++;
+ }
+ else
+ elog(NOTICE, "CAN't OPEN INDEX %u - SKIP IT", ioid[i]);
+ }
+ *nindices = k;
+ pfree(ioid);
-} /* vc_getindices */
+ if (Irel != (Relation **) NULL && *nindices == 0)
+ {
+ pfree(*Irel);
+ *Irel = (Relation *) NULL;
+ }
+
+} /* vc_getindices */
static void
-vc_clsindices (int nindices, Relation *Irel)
+vc_clsindices(int nindices, Relation * Irel)
{
- if ( Irel == (Relation*) NULL )
- return;
+ if (Irel == (Relation *) NULL)
+ return;
- while (nindices--) {
- index_close (Irel[nindices]);
- }
- pfree (Irel);
+ while (nindices--)
+ {
+ index_close(Irel[nindices]);
+ }
+ pfree(Irel);
-} /* vc_clsindices */
+} /* vc_clsindices */
static void
-vc_mkindesc (Relation onerel, int nindices, Relation *Irel, IndDesc **Idesc)
+vc_mkindesc(Relation onerel, int nindices, Relation * Irel, IndDesc ** Idesc)
{
- IndDesc *idcur;
- HeapTuple pgIndexTup;
- AttrNumber *attnumP;
- int natts;
- int i;
-
- *Idesc = (IndDesc *) palloc (nindices * sizeof (IndDesc));
-
- for (i = 0, idcur = *Idesc; i < nindices; i++, idcur++) {
- pgIndexTup =
- SearchSysCacheTuple(INDEXRELID,
- ObjectIdGetDatum(Irel[i]->rd_id),
- 0,0,0);
- Assert(pgIndexTup);
- idcur->tform = (IndexTupleForm)GETSTRUCT(pgIndexTup);
- for (attnumP = &(idcur->tform->indkey[0]), natts = 0;
- *attnumP != InvalidAttrNumber && natts != INDEX_MAX_KEYS;
- attnumP++, natts++);
- if (idcur->tform->indproc != InvalidOid) {
- idcur->finfoP = &(idcur->finfo);
- FIgetnArgs(idcur->finfoP) = natts;
- natts = 1;
- FIgetProcOid(idcur->finfoP) = idcur->tform->indproc;
- *(FIgetname(idcur->finfoP)) = '\0';
- } else
- idcur->finfoP = (FuncIndexInfo *) NULL;
-
- idcur->natts = natts;
- }
-
-} /* vc_mkindesc */
-
-
-static bool
-vc_enough_space (VPageDescr vpd, Size len)
+ IndDesc *idcur;
+ HeapTuple pgIndexTup;
+ AttrNumber *attnumP;
+ int natts;
+ int i;
+
+ *Idesc = (IndDesc *) palloc(nindices * sizeof(IndDesc));
+
+ for (i = 0, idcur = *Idesc; i < nindices; i++, idcur++)
+ {
+ pgIndexTup =
+ SearchSysCacheTuple(INDEXRELID,
+ ObjectIdGetDatum(Irel[i]->rd_id),
+ 0, 0, 0);
+ Assert(pgIndexTup);
+ idcur->tform = (IndexTupleForm) GETSTRUCT(pgIndexTup);
+ for (attnumP = &(idcur->tform->indkey[0]), natts = 0;
+ *attnumP != InvalidAttrNumber && natts != INDEX_MAX_KEYS;
+ attnumP++, natts++);
+ if (idcur->tform->indproc != InvalidOid)
+ {
+ idcur->finfoP = &(idcur->finfo);
+ FIgetnArgs(idcur->finfoP) = natts;
+ natts = 1;
+ FIgetProcOid(idcur->finfoP) = idcur->tform->indproc;
+ *(FIgetname(idcur->finfoP)) = '\0';
+ }
+ else
+ idcur->finfoP = (FuncIndexInfo *) NULL;
+
+ idcur->natts = natts;
+ }
+
+} /* vc_mkindesc */
+
+
+static bool
+vc_enough_space(VPageDescr vpd, Size len)
{
- len = DOUBLEALIGN(len);
-
- if ( len > vpd->vpd_free )
- return (false);
-
- if ( vpd->vpd_nusd < vpd->vpd_noff ) /* there are free itemid(s) */
- return (true); /* and len <= free_space */
-
- /* ok. noff_usd >= noff_free and so we'll have to allocate new itemid */
- if ( len <= vpd->vpd_free - sizeof (ItemIdData) )
- return (true);
-
- return (false);
-
-} /* vc_enough_space */
+ len = DOUBLEALIGN(len);
+
+ if (len > vpd->vpd_free)
+ return (false);
+
+ if (vpd->vpd_nusd < vpd->vpd_noff) /* there are free itemid(s) */
+ return (true); /* and len <= free_space */
+
+ /* ok. noff_usd >= noff_free and so we'll have to allocate new itemid */
+ if (len <= vpd->vpd_free - sizeof(ItemIdData))
+ return (true);
+
+ return (false);
+
+} /* vc_enough_space */
diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c
index 3cd011ace25..99439de9ce3 100644
--- a/src/backend/commands/view.c
+++ b/src/backend/commands/view.c
@@ -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;
-
- /*
- * 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 = makeNode(TypeName);
-
- typename->name = pstrdup(restypename);
- def->colname = pstrdup(resname);
-
- def->typename = typename;
-
- def->is_not_null = false;
- def->defval = (char*) NULL;
-
- attrList = lappend(attrList, def);
+ 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;
+
+ /*
+ * 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 = makeNode(TypeName);
+
+ typename->name = pstrdup(restypename);
+ def->colname = pstrdup(resname);
+
+ 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");
- }
-
- /*
- * 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);
-}
+ 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);
+}
/*------------------------------------------------------------------
* 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);
-
- 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;
+ 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);
+
+ 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;
+ RuleStmt *retrieve_rule = NULL;
+
#ifdef NOTYET
- RuleStmt *replace_rule = NULL;
- RuleStmt *append_rule = NULL;
- RuleStmt *delete_rule = NULL;
+ RuleStmt *replace_rule = NULL;
+ RuleStmt *append_rule = NULL;
+ RuleStmt *delete_rule = NULL;
+
#endif
-
- retrieve_rule =
- FormViewRetrieveRule(viewName, viewParse);
-
+
+ retrieve_rule =
+ FormViewRetrieveRule(viewName, viewParse);
+
#ifdef NOTYET
-
- replace_rule =
- FormViewReplaceRule(viewName, viewParse);
- append_rule =
- FormViewAppendRule(viewName, viewParse);
- delete_rule =
- FormViewDeleteRule(viewName, viewParse);
-
+
+ replace_rule =
+ FormViewReplaceRule(viewName, viewParse);
+ append_rule =
+ FormViewAppendRule(viewName, viewParse);
+ delete_rule =
+ FormViewDeleteRule(viewName, viewParse);
+
#endif
-
- DefineQueryRewrite(retrieve_rule);
+
+ DefineQueryRewrite(retrieve_rule);
#ifdef NOTYET
- DefineQueryRewrite(replace_rule);
- DefineQueryRewrite(append_rule);
- DefineQueryRewrite(delete_rule);
+ 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;
-
- /*
- * 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;
+ 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;
+
+ /*
+ * 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;
-
- 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);
+ 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);
}
/*------------------------------------------------------------------
@@ -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);
-
- /*
- * we don't really need that, but just in case...
- */
- CommandCounterIncrement();
-
- /*
- * now remove the relation.
- */
- heap_destroy(viewName);
- pfree(rname);
+ char *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);
}