/*------------------------------------------------------------------------- * * version.c * This file contains all the rules that govern all version semantics. * * Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions 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 * * * $Id: version.c,v 1.24 2000/01/26 05:56:19 momjian Exp $ * * NOTES * At the point the version is defined, 2 physical relations are created * _added and _deleted. * * In addition, 4 rules are defined which govern the semantics of * versions w.r.t retrieves, appends, replaces and deletes. * *------------------------------------------------------------------------- */ #include "postgres.h" #define MAX_QUERY_LEN 1024 char rule_buf[MAX_QUERY_LEN]; /* * 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 * * 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. * * NOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO * OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO * OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO * OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO * OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO * OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO * OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO * OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO * OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO * OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO * OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO * OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO * OOOOOOOOOOOOOOOOOOO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * * DONT DO THAT!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! * * If you commit the current Xact all the palloced memory GOES AWAY * and could be re-palloced in the new Xact and the whole hell breaks * loose and poor people like me spend 2 hours of their live chassing * a strange memory bug instead of watching the "Get Smart" marathon * in NICK ! * DO NOT COMMIT THE XACT, just increase the Cid counter! * _sp. */ #ifdef NOT_USED static void eval_as_new_xact(char *query) { /* * WARNING! do not uncomment the following lines WARNING! * CommitTransactionCommand(); StartTransactionCommand(); */ CommandCounterIncrement(); pg_exec_query(query); } #endif /* * 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); } #endif /* * 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_exec_query(query_buf); /* * 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. */ #ifdef NOT_USED static void setAttrList(char *bname) { Relation rel; int i = 0; int maxattrs = 0; char *attrname; char temp_buf[512]; int notfirst = 0; rel = heap_openr(bname); if (rel == NULL) { elog(ERROR, "Unable to expand all -- amopenr failed "); return; } maxattrs = RelationGetNumberOfAttributes(rel); attr_list[0] = '\0'; for (i = maxattrs - 1; i > -1; --i) { attrname = NameStr(rel->rd_att->attrs[i]->attname); if (notfirst == 1) sprintf(temp_buf, ", %s = new.%s", attrname, attrname); else { sprintf(temp_buf, "%s = new.%s", attrname, attrname); notfirst = 1; } strcat(attr_list, temp_buf); } heap_close(rel); return; } #endif /* * This routine defines the rule governing the append semantics of * versions. All tuples appended to a version gets appended to the * _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); } #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 _added relation. * 2. Retrieve all tuples in the base relation which are not in * the _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\ 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); */ } #endif /* * 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 _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 _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 \ [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); 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 \ append %s_del(DOID = current.oid) from _%s in %s%s \ where current.oid = _%s.oid \n", vname, vname, vname, bname, bname, snapshot, bname); 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: * * 1. If the tuple is in _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 _del relation. * 2.2 A copy of the tuple is appended to the _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\ [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); eval_as_new_xact(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\ append %s_del(DOID = current.oid) from _%s in %s%s \ where current.oid = _%s.oid\n", vname, vname, vname, bname, bname, snapshot, bname); eval_as_new_xact(rule_buf); 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); eval_as_new_xact(rule_buf); #endif /* OLD_REWRITE */ /* printf("%s\n",rule_buf); */ } #endif