sets.c 4.96 KB
Newer Older
1 2 3
/*-------------------------------------------------------------------------
 *
 * sets.c--
4 5 6
 *	  Functions for sets, which are defined by queries.
 *	  Example:	 a set is defined as being the result of the query
 *			retrieve (X.all)
7 8 9 10 11
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
12
 *	  $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.15 1998/07/27 19:38:21 vadim Exp $
13 14 15
 *
 *-------------------------------------------------------------------------
 */
16
#include <stdio.h>				/* for sprintf() */
17 18
#include <string.h>

19
#include "postgres.h"
Bruce Momjian's avatar
Bruce Momjian committed
20

21 22 23
#include "access/heapam.h"
#include "access/relscan.h"
#include "access/xact.h"
24 25 26
#include "catalog/pg_proc.h"	/* for Form_pg_proc */
#include "catalog/catname.h"	/* for ProcedureRelationName */
#include "catalog/indexing.h"	/* for Num_pg_proc_indices */
Bruce Momjian's avatar
Bruce Momjian committed
27
#include "fmgr.h"
28
#include "storage/lmgr.h"
Bruce Momjian's avatar
Bruce Momjian committed
29
#include "tcop/dest.h"
30
#include "utils/sets.h"			/* for GENERICSETNAME	   */
Bruce Momjian's avatar
Bruce Momjian committed
31
#include "utils/syscache.h"		/* for PROOID */
32
#include "utils/tqual.h"
33

34
extern CommandDest whereToSendOutput;	/* defined in tcop/postgres.c */
35 36 37


/*
38
 *	  SetDefine		   - converts query string defining set to an oid
39
 *
40 41 42
 *	  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.
43 44 45 46
 */
Oid
SetDefine(char *querystr, char *typename)
{
47 48 49
	Oid			setoid;
	char	   *procname = GENERICSETNAME;
	char	   *fileName = "-";
50
	char		realprocname[NAMEDATALEN];
51 52 53 54 55 56 57 58 59 60
	HeapTuple	tup,
				newtup = NULL;
	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;
61 62 63
	ItemPointerData ipdata;

	static ScanKeyData oidKey[1] = {
Bruce Momjian's avatar
Bruce Momjian committed
64
	{0, ObjectIdAttributeNumber, F_OIDEQ}};
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93


	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))
94
		elog(ERROR, "setin: unable to define set %s", querystr);
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119

	/*
	 * 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);
Bruce Momjian's avatar
Bruce Momjian committed
120
		fmgr_info(F_OIDEQ,
121 122
				  &oidKey[0].sk_func);
		oidKey[0].sk_nargs = oidKey[0].sk_func.fn_nargs;
123 124 125
		oidKey[0].sk_argument = ObjectIdGetDatum(setoid);
		pg_proc_scan = heap_beginscan(procrel,
									  0,
126
									  SnapshotSelf,
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
									  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);
			heap_replace(procrel, &ipdata, newtup);
			setheapoverride(false);

			setoid = newtup->t_oid;
		}
		else
149
			elog(ERROR, "setin: could not find new set oid tuple");
150 151 152 153
		heap_endscan(pg_proc_scan);

		if (RelationGetRelationTupleForm(procrel)->relhasindex)
		{
154
			Relation	idescs[Num_pg_proc_indices];
155 156 157 158 159 160 161 162 163

			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;
164 165
}

166
/* This function is a placeholder.	The parser uses the OID of this
167
 * function to fill in the :funcid field  of a set.  This routine is
168
 * never executed.	At runtime, the OID of the actual set is substituted
169 170 171 172 173
 * into the :funcid.
 */
int
seteval(Oid funcoid)
{
174
	return 17;
175
}