summaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/sets.c
blob: 1d150805ce941d6534eabee0dfce4c410004a49c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
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
94
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/*-------------------------------------------------------------------------
 *
 * 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.16 1998/08/19 02:03:06 momjian Exp $
 *
 *-------------------------------------------------------------------------
 */
#include <stdio.h>				/* for sprintf() */
#include <string.h>

#include "postgres.h"

#include "access/heapam.h"
#include "access/relscan.h"
#include "access/xact.h"
#include "catalog/pg_proc.h"	/* for Form_pg_proc */
#include "catalog/catname.h"	/* for ProcedureRelationName */
#include "catalog/indexing.h"	/* for Num_pg_proc_indices */
#include "fmgr.h"
#include "storage/lmgr.h"
#include "tcop/dest.h"
#include "utils/sets.h"			/* for GENERICSETNAME	   */
#include "utils/syscache.h"		/* for PROOID */
#include "utils/tqual.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[NAMEDATALEN];
	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];

	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(ERROR, "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);

		tup = SearchSysCacheTuple(PROOID,
									ObjectIdGetDatum(setoid),
									0, 0, 0);
		if (HeapTupleIsValid(tup))
		{
			newtup = heap_modifytuple(tup,
									  procrel,
									  replValue,
									  replNull,
									  repl);

			setheapoverride(true);
			heap_replace(procrel, &tup->t_ctid, newtup);
			setheapoverride(false);

			setoid = newtup->t_oid;
		}
		else
			elog(ERROR, "setin: could not find new set oid tuple");

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