diff options
Diffstat (limited to 'src/backend/utils/adt/sets.c')
-rw-r--r-- | src/backend/utils/adt/sets.c | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/backend/utils/adt/sets.c b/src/backend/utils/adt/sets.c new file mode 100644 index 00000000000..9ad8d457820 --- /dev/null +++ b/src/backend/utils/adt/sets.c @@ -0,0 +1,164 @@ +/*------------------------------------------------------------------------- + * + * sets.c-- + * Functions for sets, which are defined by queries. + * Example: a set is defined as being the result of the query + * retrieve (X.all) + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ +#include <stdio.h> /* for sprintf() */ +#include "postgres.h" +#include "utils/elog.h" +#include "nodes/pg_list.h" /* for LispValue and List */ +#include "access/htup.h" /* for HeapTuple */ +#include "access/heapam.h" +#include "access/relscan.h" +#include "access/xact.h" +#include "catalog/pg_proc.h" /* for Form_pg_proc */ +#include "utils/syscache.h" /* for PROOID */ +#include "catalog/catname.h" /* for ProcedureRelationName */ +#include "catalog/indexing.h" /* for Num_pg_proc_indices */ +#include "storage/lmgr.h" +#include "utils/sets.h" /* for GENERICSETNAME */ +#include "tcop/dest.h" +#include "fmgr.h" + +extern CommandDest whereToSendOutput; /* defined in tcop/postgres.c */ + + +/* + * SetDefine - converts query string defining set to an oid + * + * The query string is used to store the set as a function in + * pg_proc. The name of the function is then changed to use the + * OID of its tuple in pg_proc. + */ +Oid +SetDefine(char *querystr, char *typename) +{ + Oid setoid; + char *procname = GENERICSETNAME; + char *fileName = "-"; + char realprocname[16]; + HeapTuple tup, newtup; + Form_pg_proc proc; + Relation procrel; + int i; + Datum replValue[Natts_pg_proc]; + char replNull[Natts_pg_proc]; + char repl[Natts_pg_proc]; + HeapScanDesc pg_proc_scan; + Buffer buffer; + ItemPointerData ipdata; + + static ScanKeyData oidKey[1] = { + { 0, ObjectIdAttributeNumber, ObjectIdEqualRegProcedure }}; + + + setoid = ProcedureCreate(procname, /* changed below, after oid known */ + true, /* returnsSet */ + typename, /* returnTypeName */ + "sql", /* languageName */ + querystr, /* sourceCode */ + fileName, /* fileName */ + false, /* canCache */ + true, /* trusted */ + 100, /* byte_pct */ + 0, /* perbyte_cpu */ + 0, /* percall_cpu */ + 100, /* outin_ratio */ + NIL, /* argList */ + whereToSendOutput); + /* Since we're still inside this command of the transaction, we can't + * see the results of the procedure definition unless we pretend + * we've started the next command. (Postgres's solution to the + * Halloween problem is to not allow you to see the results of your + * command until you start the next command.) + */ + CommandCounterIncrement(); + tup = SearchSysCacheTuple(PROOID, + ObjectIdGetDatum(setoid), + 0,0,0); + if (!HeapTupleIsValid(tup)) + elog(WARN, "setin: unable to define set %s", querystr); + + /* We can tell whether the set was already defined by checking + * the name. If it's GENERICSETNAME, the set is new. If it's + * "set<some oid>" it's already defined. + */ + proc = (Form_pg_proc)GETSTRUCT(tup); + if (!strcmp((char*)procname, (char*)&(proc->proname))) { + /* make the real proc name */ + sprintf(realprocname, "set%u", setoid); + + /* set up the attributes to be modified or kept the same */ + repl[0] = 'r'; + for (i = 1; i < Natts_pg_proc; i++) repl[i] = ' '; + replValue[0] = (Datum)realprocname; + for (i = 1; i < Natts_pg_proc; i++) replValue[i] = (Datum)0; + for (i = 0; i < Natts_pg_proc; i++) replNull[i] = ' '; + + /* change the pg_proc tuple */ + procrel = heap_openr(ProcedureRelationName); + RelationSetLockForWrite(procrel); + fmgr_info(ObjectIdEqualRegProcedure, + &oidKey[0].sk_func, + &oidKey[0].sk_nargs); + oidKey[0].sk_argument = ObjectIdGetDatum(setoid); + pg_proc_scan = heap_beginscan(procrel, + 0, + SelfTimeQual, + 1, + oidKey); + tup = heap_getnext(pg_proc_scan, 0, &buffer); + if (HeapTupleIsValid(tup)) { + newtup = heap_modifytuple(tup, + buffer, + procrel, + replValue, + replNull, + repl); + + /* XXX may not be necessary */ + ItemPointerCopy(&tup->t_ctid, &ipdata); + + setheapoverride(true); + (void) heap_replace(procrel, &ipdata, newtup); + setheapoverride(false); + + setoid = newtup->t_oid; + } else + elog(WARN, "setin: could not find new set oid tuple"); + heap_endscan(pg_proc_scan); + + if (RelationGetRelationTupleForm(procrel)->relhasindex) + { + Relation idescs[Num_pg_proc_indices]; + + CatalogOpenIndices(Num_pg_proc_indices, Name_pg_proc_indices, idescs); + CatalogIndexInsert(idescs, Num_pg_proc_indices, procrel, newtup); + CatalogCloseIndices(Num_pg_proc_indices, idescs); + } + RelationUnsetLockForWrite(procrel); + heap_close(procrel); + } + return setoid; +} + +/* This function is a placeholder. The parser uses the OID of this + * function to fill in the :funcid field of a set. This routine is + * never executed. At runtime, the OID of the actual set is substituted + * into the :funcid. + */ +int +seteval(Oid funcoid) +{ + return 17; +} |