Skip to content

Commit 6eb8d25

Browse files
committed
Allow CREATE FUNCTION's WITH clause to be used for all language types,
not just C, so that ISCACHABLE attribute can be specified for user-defined functions. Get rid of ParamString node type, which wasn't actually being generated by gram.y anymore, even though define.c thought that was what it was getting. Clean up minor bug in dfmgr.c (premature heap_close).
1 parent e23a2b1 commit 6eb8d25

File tree

7 files changed

+117
-137
lines changed

7 files changed

+117
-137
lines changed

src/backend/commands/define.c

Lines changed: 89 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.35 1999/09/28 04:34:40 momjian Exp $
12+
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.36 1999/10/02 21:33:24 tgl Exp $
1313
*
1414
* DESCRIPTION
1515
* The "DefineFoo" routines take the parse tree and pick out the
@@ -53,6 +53,7 @@
5353
#include "utils/syscache.h"
5454

5555
static char *defGetString(DefElem *def);
56+
static double defGetNumeric(DefElem *def);
5657
static int defGetTypeLength(DefElem *def);
5758

5859
#define DEFAULT_TYPDELIM ','
@@ -103,17 +104,26 @@ compute_return_type(const Node *returnType,
103104
}
104105

105106

106-
107107
static void
108-
compute_full_attributes(const List *parameters, int32 *byte_pct_p,
108+
compute_full_attributes(List *parameters, int32 *byte_pct_p,
109109
int32 *perbyte_cpu_p, int32 *percall_cpu_p,
110110
int32 *outin_ratio_p, bool *canCache_p)
111111
{
112112
/*--------------------------------------------------------------------------
113113
Interpret the parameters *parameters and return their contents as
114114
*byte_pct_p, etc.
115115
116-
These are the full parameters of a C or internal function.
116+
These parameters supply optional information about a function.
117+
All have defaults if not specified.
118+
119+
Note: as of version 6.6, canCache is used (if set, the optimizer's
120+
constant-folder is allowed to pre-evaluate the function if all its
121+
inputs are constant). The other four are not used. They used to be
122+
used in the "expensive functions" optimizer, but that's been dead code
123+
for a long time.
124+
125+
Since canCache is useful for any function, we now allow attributes to be
126+
supplied for all functions regardless of language.
117127
---------------------------------------------------------------------------*/
118128
List *pl;
119129

@@ -122,58 +132,33 @@ compute_full_attributes(const List *parameters, int32 *byte_pct_p,
122132
*perbyte_cpu_p = PERBYTE_CPU;
123133
*percall_cpu_p = PERCALL_CPU;
124134
*outin_ratio_p = OUTIN_RATIO;
135+
*canCache_p = false;
125136

126-
foreach(pl, (List *) parameters)
137+
foreach(pl, parameters)
127138
{
128-
ParamString *param = (ParamString *) lfirst(pl);
139+
DefElem *param = (DefElem *) lfirst(pl);
129140

130-
if (strcasecmp(param->name, "iscachable") == 0)
141+
if (strcasecmp(param->defname, "iscachable") == 0)
131142
*canCache_p = true;
132-
else if (strcasecmp(param->name, "trusted") == 0)
143+
else if (strcasecmp(param->defname, "trusted") == 0)
133144
{
134-
135145
/*
136146
* we don't have untrusted functions any more. The 4.2
137147
* implementation is lousy anyway so I took it out. -ay 10/94
138148
*/
139149
elog(ERROR, "untrusted function has been decommissioned.");
140150
}
141-
else if (strcasecmp(param->name, "byte_pct") == 0)
142-
{
143-
144-
/*
145-
* * handle expensive function parameters
146-
*/
147-
*byte_pct_p = atoi(param->val);
148-
}
149-
else if (strcasecmp(param->name, "perbyte_cpu") == 0)
150-
{
151-
if (sscanf(param->val, "%d", perbyte_cpu_p) == 0)
152-
{
153-
int count;
154-
char *ptr;
155-
156-
for (count = 0, ptr = param->val; *ptr != '\0'; ptr++)
157-
if (*ptr == '!')
158-
count++;
159-
*perbyte_cpu_p = (int) pow(10.0, (double) count);
160-
}
161-
}
162-
else if (strcasecmp(param->name, "percall_cpu") == 0)
163-
{
164-
if (sscanf(param->val, "%d", percall_cpu_p) == 0)
165-
{
166-
int count;
167-
char *ptr;
168-
169-
for (count = 0, ptr = param->val; *ptr != '\0'; ptr++)
170-
if (*ptr == '!')
171-
count++;
172-
*percall_cpu_p = (int) pow(10.0, (double) count);
173-
}
174-
}
175-
else if (strcasecmp(param->name, "outin_ratio") == 0)
176-
*outin_ratio_p = atoi(param->val);
151+
else if (strcasecmp(param->defname, "byte_pct") == 0)
152+
*byte_pct_p = (int) defGetNumeric(param);
153+
else if (strcasecmp(param->defname, "perbyte_cpu") == 0)
154+
*perbyte_cpu_p = (int) defGetNumeric(param);
155+
else if (strcasecmp(param->defname, "percall_cpu") == 0)
156+
*percall_cpu_p = (int) defGetNumeric(param);
157+
else if (strcasecmp(param->defname, "outin_ratio") == 0)
158+
*outin_ratio_p = (int) defGetNumeric(param);
159+
else
160+
elog(NOTICE, "Unrecognized function attribute '%s' ignored",
161+
param->defname);
177162
}
178163
}
179164

@@ -215,8 +200,8 @@ interpret_AS_clause(const char *languageName, const List *as,
215200
*probin_str_p = "-";
216201

217202
if (lnext(as) != NULL)
218-
elog(ERROR, "CREATE FUNCTION: parse error in 'AS %s, %s'.",
219-
strVal(lfirst(as)), strVal(lsecond(as)));
203+
elog(ERROR, "CREATE FUNCTION: only one AS item needed for %s language",
204+
languageName);
220205
}
221206
}
222207

@@ -246,39 +231,37 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
246231
* or "SQL"
247232
*/
248233

234+
bool returnsSet;
235+
/* The function returns a set of values, as opposed to a singleton. */
236+
237+
bool lanisPL = false;
238+
249239
/*
250-
* The following are attributes of the function, as expressed in the
251-
* CREATE FUNCTION statement, where applicable.
240+
* The following are optional user-supplied attributes of the function.
252241
*/
253242
int32 byte_pct,
254243
perbyte_cpu,
255244
percall_cpu,
256245
outin_ratio;
257246
bool canCache;
258-
bool returnsSet;
259-
260-
bool lanisPL = false;
261-
262-
/* The function returns a set of values, as opposed to a singleton. */
263247

264248

265249
case_translate_language_name(stmt->language, languageName);
266250

267-
compute_return_type(stmt->returnType, &prorettype, &returnsSet);
268-
269251
if (strcmp(languageName, "C") == 0 ||
270252
strcmp(languageName, "internal") == 0)
271253
{
272-
compute_full_attributes(stmt->withClause,
273-
&byte_pct, &perbyte_cpu, &percall_cpu,
274-
&outin_ratio, &canCache);
254+
if (!superuser())
255+
elog(ERROR,
256+
"Only users with Postgres superuser privilege are "
257+
"permitted to create a function "
258+
"in the '%s' language. Others may use the 'sql' language "
259+
"or the created procedural languages.",
260+
languageName);
275261
}
276262
else if (strcmp(languageName, "sql") == 0)
277263
{
278-
/* query optimizer groks sql, these are meaningless */
279-
perbyte_cpu = percall_cpu = 0;
280-
byte_pct = outin_ratio = 100;
281-
canCache = false;
264+
/* No security check needed for SQL functions */
282265
}
283266
else
284267
{
@@ -321,47 +304,34 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest)
321304
}
322305

323306
lanisPL = true;
324-
325-
/*
326-
* These are meaningless
327-
*/
328-
perbyte_cpu = percall_cpu = 0;
329-
byte_pct = outin_ratio = 100;
330-
canCache = false;
331307
}
332308

333-
interpret_AS_clause(languageName, stmt->as, &prosrc_str, &probin_str);
309+
compute_return_type(stmt->returnType, &prorettype, &returnsSet);
334310

335-
if (strcmp(languageName, "sql") != 0 && lanisPL == false && !superuser())
336-
elog(ERROR,
337-
"Only users with Postgres superuser privilege are permitted "
338-
"to create a function "
339-
"in the '%s' language. Others may use the 'sql' language "
340-
"or the created procedural languages.",
341-
languageName);
342-
/* Above does not return. */
343-
else
344-
{
311+
compute_full_attributes(stmt->withClause,
312+
&byte_pct, &perbyte_cpu, &percall_cpu,
313+
&outin_ratio, &canCache);
345314

346-
/*
347-
* And now that we have all the parameters, and know we're
348-
* permitted to do so, go ahead and create the function.
349-
*/
350-
ProcedureCreate(stmt->funcname,
351-
returnsSet,
352-
prorettype,
353-
languageName,
354-
prosrc_str, /* converted to text later */
355-
probin_str, /* converted to text later */
356-
canCache,
357-
true, /* (obsolete "trusted") */
358-
byte_pct,
359-
perbyte_cpu,
360-
percall_cpu,
361-
outin_ratio,
362-
stmt->defArgs,
363-
dest);
364-
}
315+
interpret_AS_clause(languageName, stmt->as, &prosrc_str, &probin_str);
316+
317+
/*
318+
* And now that we have all the parameters, and know we're
319+
* permitted to do so, go ahead and create the function.
320+
*/
321+
ProcedureCreate(stmt->funcname,
322+
returnsSet,
323+
prorettype,
324+
languageName,
325+
prosrc_str, /* converted to text later */
326+
probin_str, /* converted to text later */
327+
canCache,
328+
true, /* (obsolete "trusted") */
329+
byte_pct,
330+
perbyte_cpu,
331+
percall_cpu,
332+
outin_ratio,
333+
stmt->defArgs,
334+
dest);
365335
}
366336

367337

@@ -734,6 +704,25 @@ defGetString(DefElem *def)
734704
return strVal(def->arg);
735705
}
736706

707+
static double
708+
defGetNumeric(DefElem *def)
709+
{
710+
if (def->arg == NULL)
711+
elog(ERROR, "Define: \"%s\" requires a numeric value",
712+
def->defname);
713+
switch (nodeTag(def->arg))
714+
{
715+
case T_Integer:
716+
return (double) intVal(def->arg);
717+
case T_Float:
718+
return floatVal(def->arg);
719+
default:
720+
elog(ERROR, "Define: \"%s\" requires a numeric value",
721+
def->defname);
722+
}
723+
return 0; /* keep compiler quiet */
724+
}
725+
737726
static int
738727
defGetTypeLength(DefElem *def)
739728
{

src/backend/commands/indexcmds.c

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.11 1999/09/18 19:06:40 tgl Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.12 1999/10/02 21:33:24 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -50,7 +50,7 @@ static char *GetDefaultOpClass(Oid atttypid);
5050
*
5151
* 'attributeList' is a list of IndexElem specifying either a functional
5252
* index or a list of attributes to index on.
53-
* 'parameterList' is a list of ParamString specified in the with clause.
53+
* 'parameterList' is a list of DefElem specified in the with clause.
5454
* 'predicate' is the qual specified in the where clause.
5555
* 'rangetable' is for the predicate
5656
*
@@ -116,22 +116,20 @@ DefineIndex(char *heapRelationName,
116116
}
117117
accessMethodId = tuple->t_data->t_oid;
118118

119-
120119
/*
121-
* Handle parameters [param list is now different (NOT USED, really) -
122-
* ay 10/94]
123-
*
124120
* WITH clause reinstated to handle lossy indices. -- JMH, 7/22/96
125121
*/
126122
foreach(pl, parameterList)
127123
{
128-
ParamString *param = (ParamString *) lfirst(pl);
124+
DefElem *param = (DefElem *) lfirst(pl);
129125

130-
if (!strcasecmp(param->name, "islossy"))
126+
if (!strcasecmp(param->defname, "islossy"))
131127
lossy = TRUE;
128+
else
129+
elog(NOTICE, "Unrecognized index attribute '%s' ignored",
130+
param->defname);
132131
}
133132

134-
135133
/*
136134
* Convert the partial-index predicate from parsetree form to plan
137135
* form, so it can be readily evaluated during index creation. Note:

src/backend/parser/gram.y

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
*
1212
* IDENTIFICATION
13-
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.104 1999/09/29 16:06:06 wieck Exp $
13+
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.105 1999/10/02 21:33:21 tgl Exp $
1414
*
1515
* HISTORY
1616
* AUTHOR DATE MAJOR EVENT
@@ -103,7 +103,6 @@ Oid param_type(int t); /* used in parse_expr.c */
103103

104104
TypeName *typnam;
105105
DefElem *defelt;
106-
ParamString *param;
107106
SortGroupBy *sortgroupby;
108107
JoinExpr *joinexpr;
109108
IndexElem *ielem;

src/backend/utils/fmgr/dfmgr.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*
88
*
99
* IDENTIFICATION
10-
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.34 1999/09/28 11:27:13 vadim Exp $
10+
* $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.35 1999/10/02 21:33:25 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -42,15 +42,16 @@ fmgr_dynamic(Oid procedureId, int *pronargs)
4242
HeapTuple procedureTuple;
4343
Form_pg_proc procedureStruct;
4444
char *proname,
45-
*probinstring,
46-
*prosrcstring,
47-
*linksymbol;
45+
*linksymbol,
46+
*probinstring;
47+
char *prosrcstring = NULL;
4848
Datum probinattr;
4949
Datum prosrcattr;
5050
func_ptr user_fn;
5151
Relation rel;
5252
bool isnull;
5353

54+
/* Implement simple one-element cache for function lookups */
5455
if (procedureId == procedureId_save)
5556
{
5657
*pronargs = pronargs_save;
@@ -91,8 +92,6 @@ fmgr_dynamic(Oid procedureId, int *pronargs)
9192
}
9293
probinstring = textout((struct varlena *) probinattr);
9394

94-
heap_close(rel, AccessShareLock);
95-
9695
prosrcattr = heap_getattr(procedureTuple,
9796
Anum_pg_proc_prosrc,
9897
RelationGetDescr(rel), &isnull);
@@ -118,9 +117,12 @@ fmgr_dynamic(Oid procedureId, int *pronargs)
118117
linksymbol = prosrcstring;
119118
}
120119

120+
heap_close(rel, AccessShareLock);
121+
121122
user_fn = handle_load(probinstring, linksymbol);
122123

123124
pfree(probinstring);
125+
if (prosrcstring) pfree(prosrcstring);
124126

125127
procedureId_save = procedureId;
126128
user_fn_save = user_fn;

0 commit comments

Comments
 (0)