diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c index 509d5026d301a55e73b1872074f95ae779b243f4..2aa197654c7f07e6793b085c3ab2c6f054477786 100644 --- a/src/backend/commands/define.c +++ b/src/backend/commands/define.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.35 1999/09/28 04:34:40 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.36 1999/10/02 21:33:24 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -53,6 +53,7 @@ #include "utils/syscache.h" static char *defGetString(DefElem *def); +static double defGetNumeric(DefElem *def); static int defGetTypeLength(DefElem *def); #define DEFAULT_TYPDELIM ',' @@ -103,9 +104,8 @@ compute_return_type(const Node *returnType, } - static void -compute_full_attributes(const List *parameters, int32 *byte_pct_p, +compute_full_attributes(List *parameters, int32 *byte_pct_p, int32 *perbyte_cpu_p, int32 *percall_cpu_p, int32 *outin_ratio_p, bool *canCache_p) { @@ -113,7 +113,17 @@ compute_full_attributes(const List *parameters, int32 *byte_pct_p, Interpret the parameters *parameters and return their contents as *byte_pct_p, etc. - These are the full parameters of a C or internal function. + These parameters supply optional information about a function. + All have defaults if not specified. + + Note: as of version 6.6, canCache is used (if set, the optimizer's + constant-folder is allowed to pre-evaluate the function if all its + inputs are constant). The other four are not used. They used to be + used in the "expensive functions" optimizer, but that's been dead code + for a long time. + + Since canCache is useful for any function, we now allow attributes to be + supplied for all functions regardless of language. ---------------------------------------------------------------------------*/ List *pl; @@ -122,58 +132,33 @@ compute_full_attributes(const List *parameters, int32 *byte_pct_p, *perbyte_cpu_p = PERBYTE_CPU; *percall_cpu_p = PERCALL_CPU; *outin_ratio_p = OUTIN_RATIO; + *canCache_p = false; - foreach(pl, (List *) parameters) + foreach(pl, parameters) { - ParamString *param = (ParamString *) lfirst(pl); + DefElem *param = (DefElem *) lfirst(pl); - if (strcasecmp(param->name, "iscachable") == 0) + if (strcasecmp(param->defname, "iscachable") == 0) *canCache_p = true; - else if (strcasecmp(param->name, "trusted") == 0) + else if (strcasecmp(param->defname, "trusted") == 0) { - /* * we don't have untrusted functions any more. The 4.2 * implementation is lousy anyway so I took it out. -ay 10/94 */ elog(ERROR, "untrusted function has been decommissioned."); } - else if (strcasecmp(param->name, "byte_pct") == 0) - { - - /* - * * handle expensive function parameters - */ - *byte_pct_p = atoi(param->val); - } - else if (strcasecmp(param->name, "perbyte_cpu") == 0) - { - if (sscanf(param->val, "%d", perbyte_cpu_p) == 0) - { - int count; - char *ptr; - - for (count = 0, ptr = param->val; *ptr != '\0'; ptr++) - if (*ptr == '!') - count++; - *perbyte_cpu_p = (int) pow(10.0, (double) count); - } - } - else if (strcasecmp(param->name, "percall_cpu") == 0) - { - if (sscanf(param->val, "%d", percall_cpu_p) == 0) - { - int count; - char *ptr; - - for (count = 0, ptr = param->val; *ptr != '\0'; ptr++) - if (*ptr == '!') - count++; - *percall_cpu_p = (int) pow(10.0, (double) count); - } - } - else if (strcasecmp(param->name, "outin_ratio") == 0) - *outin_ratio_p = atoi(param->val); + else if (strcasecmp(param->defname, "byte_pct") == 0) + *byte_pct_p = (int) defGetNumeric(param); + else if (strcasecmp(param->defname, "perbyte_cpu") == 0) + *perbyte_cpu_p = (int) defGetNumeric(param); + else if (strcasecmp(param->defname, "percall_cpu") == 0) + *percall_cpu_p = (int) defGetNumeric(param); + else if (strcasecmp(param->defname, "outin_ratio") == 0) + *outin_ratio_p = (int) defGetNumeric(param); + else + elog(NOTICE, "Unrecognized function attribute '%s' ignored", + param->defname); } } @@ -215,8 +200,8 @@ interpret_AS_clause(const char *languageName, const List *as, *probin_str_p = "-"; if (lnext(as) != NULL) - elog(ERROR, "CREATE FUNCTION: parse error in 'AS %s, %s'.", - strVal(lfirst(as)), strVal(lsecond(as))); + elog(ERROR, "CREATE FUNCTION: only one AS item needed for %s language", + languageName); } } @@ -246,39 +231,37 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) * or "SQL" */ + bool returnsSet; + /* The function returns a set of values, as opposed to a singleton. */ + + bool lanisPL = false; + /* - * The following are attributes of the function, as expressed in the - * CREATE FUNCTION statement, where applicable. + * The following are optional user-supplied attributes of the function. */ int32 byte_pct, perbyte_cpu, percall_cpu, outin_ratio; bool canCache; - bool returnsSet; - - bool lanisPL = false; - - /* The function returns a set of values, as opposed to a singleton. */ case_translate_language_name(stmt->language, languageName); - compute_return_type(stmt->returnType, &prorettype, &returnsSet); - if (strcmp(languageName, "C") == 0 || strcmp(languageName, "internal") == 0) { - compute_full_attributes(stmt->withClause, - &byte_pct, &perbyte_cpu, &percall_cpu, - &outin_ratio, &canCache); + if (!superuser()) + elog(ERROR, + "Only users with Postgres superuser privilege are " + "permitted to create a function " + "in the '%s' language. Others may use the 'sql' language " + "or the created procedural languages.", + languageName); } else if (strcmp(languageName, "sql") == 0) { - /* query optimizer groks sql, these are meaningless */ - perbyte_cpu = percall_cpu = 0; - byte_pct = outin_ratio = 100; - canCache = false; + /* No security check needed for SQL functions */ } else { @@ -321,47 +304,34 @@ CreateFunction(ProcedureStmt *stmt, CommandDest dest) } lanisPL = true; - - /* - * These are meaningless - */ - perbyte_cpu = percall_cpu = 0; - byte_pct = outin_ratio = 100; - canCache = false; } - interpret_AS_clause(languageName, stmt->as, &prosrc_str, &probin_str); + compute_return_type(stmt->returnType, &prorettype, &returnsSet); - if (strcmp(languageName, "sql") != 0 && lanisPL == false && !superuser()) - elog(ERROR, - "Only users with Postgres superuser privilege are permitted " - "to create a function " - "in the '%s' language. Others may use the 'sql' language " - "or the created procedural languages.", - languageName); - /* Above does not return. */ - else - { + compute_full_attributes(stmt->withClause, + &byte_pct, &perbyte_cpu, &percall_cpu, + &outin_ratio, &canCache); - /* - * And now that we have all the parameters, and know we're - * permitted to do so, go ahead and create the function. - */ - ProcedureCreate(stmt->funcname, - returnsSet, - prorettype, - languageName, - prosrc_str, /* converted to text later */ - probin_str, /* converted to text later */ - canCache, - true, /* (obsolete "trusted") */ - byte_pct, - perbyte_cpu, - percall_cpu, - outin_ratio, - stmt->defArgs, - dest); - } + interpret_AS_clause(languageName, stmt->as, &prosrc_str, &probin_str); + + /* + * And now that we have all the parameters, and know we're + * permitted to do so, go ahead and create the function. + */ + ProcedureCreate(stmt->funcname, + returnsSet, + prorettype, + languageName, + prosrc_str, /* converted to text later */ + probin_str, /* converted to text later */ + canCache, + true, /* (obsolete "trusted") */ + byte_pct, + perbyte_cpu, + percall_cpu, + outin_ratio, + stmt->defArgs, + dest); } @@ -734,6 +704,25 @@ defGetString(DefElem *def) return strVal(def->arg); } +static double +defGetNumeric(DefElem *def) +{ + if (def->arg == NULL) + elog(ERROR, "Define: \"%s\" requires a numeric value", + def->defname); + switch (nodeTag(def->arg)) + { + case T_Integer: + return (double) intVal(def->arg); + case T_Float: + return floatVal(def->arg); + default: + elog(ERROR, "Define: \"%s\" requires a numeric value", + def->defname); + } + return 0; /* keep compiler quiet */ +} + static int defGetTypeLength(DefElem *def) { diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 113854311d6aaf22b855fd59077154e7f3241812..5f82c2b532152a03dea0746fa3f4c89ab5509a17 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.11 1999/09/18 19:06:40 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.12 1999/10/02 21:33:24 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -50,7 +50,7 @@ static char *GetDefaultOpClass(Oid atttypid); * * 'attributeList' is a list of IndexElem specifying either a functional * index or a list of attributes to index on. - * 'parameterList' is a list of ParamString specified in the with clause. + * 'parameterList' is a list of DefElem specified in the with clause. * 'predicate' is the qual specified in the where clause. * 'rangetable' is for the predicate * @@ -116,22 +116,20 @@ DefineIndex(char *heapRelationName, } accessMethodId = tuple->t_data->t_oid; - /* - * Handle parameters [param list is now different (NOT USED, really) - - * ay 10/94] - * * WITH clause reinstated to handle lossy indices. -- JMH, 7/22/96 */ foreach(pl, parameterList) { - ParamString *param = (ParamString *) lfirst(pl); + DefElem *param = (DefElem *) lfirst(pl); - if (!strcasecmp(param->name, "islossy")) + if (!strcasecmp(param->defname, "islossy")) lossy = TRUE; + else + elog(NOTICE, "Unrecognized index attribute '%s' ignored", + param->defname); } - /* * Convert the partial-index predicate from parsetree form to plan * form, so it can be readily evaluated during index creation. Note: diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index b6583197be3962902544901404896717d76d0f5f..96f480ea0ca27f5467401df138f5aab53715692b 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.104 1999/09/29 16:06:06 wieck Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.105 1999/10/02 21:33:21 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -103,7 +103,6 @@ Oid param_type(int t); /* used in parse_expr.c */ TypeName *typnam; DefElem *defelt; - ParamString *param; SortGroupBy *sortgroupby; JoinExpr *joinexpr; IndexElem *ielem; diff --git a/src/backend/utils/fmgr/dfmgr.c b/src/backend/utils/fmgr/dfmgr.c index a69d20a047694c84e7393fd62a91ddc6f477ddf1..15b22bdfa41a6268d27d1567fcdf646f40f7d11e 100644 --- a/src/backend/utils/fmgr/dfmgr.c +++ b/src/backend/utils/fmgr/dfmgr.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.34 1999/09/28 11:27:13 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.35 1999/10/02 21:33:25 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -42,15 +42,16 @@ fmgr_dynamic(Oid procedureId, int *pronargs) HeapTuple procedureTuple; Form_pg_proc procedureStruct; char *proname, - *probinstring, - *prosrcstring, - *linksymbol; + *linksymbol, + *probinstring; + char *prosrcstring = NULL; Datum probinattr; Datum prosrcattr; func_ptr user_fn; Relation rel; bool isnull; + /* Implement simple one-element cache for function lookups */ if (procedureId == procedureId_save) { *pronargs = pronargs_save; @@ -91,8 +92,6 @@ fmgr_dynamic(Oid procedureId, int *pronargs) } probinstring = textout((struct varlena *) probinattr); - heap_close(rel, AccessShareLock); - prosrcattr = heap_getattr(procedureTuple, Anum_pg_proc_prosrc, RelationGetDescr(rel), &isnull); @@ -118,9 +117,12 @@ fmgr_dynamic(Oid procedureId, int *pronargs) linksymbol = prosrcstring; } + heap_close(rel, AccessShareLock); + user_fn = handle_load(probinstring, linksymbol); pfree(probinstring); + if (prosrcstring) pfree(prosrcstring); procedureId_save = procedureId; user_fn_save = user_fn; diff --git a/src/bin/psql/psqlHelp.h b/src/bin/psql/psqlHelp.h index 63268c2cbd9ee7ffaa02f927175c80df2e2fc4cf..3b39f7b2d8eadc23ef140bbabe907a3645ec7115 100644 --- a/src/bin/psql/psqlHelp.h +++ b/src/bin/psql/psqlHelp.h @@ -5,7 +5,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: psqlHelp.h,v 1.76 1999/09/28 04:34:48 momjian Exp $ + * $Id: psqlHelp.h,v 1.77 1999/10/02 21:33:29 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -88,14 +88,16 @@ static struct _helpStruct QL_HELP[] = { "create a user-defined function", "\ \tCREATE FUNCTION function_name ([type1, ...typeN]) RETURNS return_type\n\ -\tAS 'sql-queries'|'builtin_function_name'|'object_filename'\n\ -\tLANGUAGE 'sql'|'internal'|'c';\n\ +\t[WITH ( attributes )]\n\ +\tAS 'sql_queries'|'builtin_function_name'|'procedural_commands'\n\ +\tLANGUAGE 'sql'|'internal'|'procedural_language_name';\n\ \n\ OR\n\ \n\ \tCREATE FUNCTION function_name ([type1, ...typeN]) RETURNS return_type\n\ -\tAS 'object_filename', 'link_symbol'\n\ -\tLANGUAGE 'c';"}, +\t[WITH ( attributes )]\n\ +\tAS 'object_filename' [, 'link_symbol']\n\ +\tLANGUAGE 'C';"}, {"create index", "construct an index", "\ diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 68d824732447feb70abdf2ab05a5a22551bedd2b..08705ea9f6ebfcc5cce71595f0e00687ea3755ee 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: nodes.h,v 1.53 1999/09/29 16:06:23 wieck Exp $ + * $Id: nodes.h,v 1.54 1999/10/02 21:33:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -194,7 +194,7 @@ typedef enum NodeTag T_FuncCall, T_A_Indices, T_ResTarget, - T_ParamString, + T_ParamString, /* not used anymore */ T_RelExpr, T_SortGroupBy, T_RangeVar, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index a736c1af67e79a4274eb178d851fc617d1d18fd2..463ea1518e0d92407a4e300d0949da0df94bee7f 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: parsenodes.h,v 1.81 1999/09/29 16:06:23 wieck Exp $ + * $Id: parsenodes.h,v 1.82 1999/10/02 21:33:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -346,7 +346,7 @@ typedef struct IndexStmt char *relname; /* name of relation to index on */ char *accessMethod; /* name of acess methood (eg. btree) */ List *indexParams; /* a list of IndexElem */ - List *withClause; /* a list of ParamString */ + List *withClause; /* a list of DefElem */ Node *whereClause; /* qualifications */ List *rangetable; /* range table, filled in by * transformStmt() */ @@ -367,7 +367,7 @@ typedef struct ProcedureStmt * (as Value *) */ Node *returnType; /* the return type (as a string or a * TypeName (ie.setof) */ - List *withClause; /* a list of ParamString */ + List *withClause; /* a list of DefElem */ List *as; /* the SQL statement or filename */ char *language; /* C or SQL */ } ProcedureStmt; @@ -862,16 +862,6 @@ typedef struct ResTarget * assign */ } ResTarget; -/* - * ParamString - used in WITH clauses - */ -typedef struct ParamString -{ - NodeTag type; - char *name; - char *val; -} ParamString; - /* * RelExpr - relation expressions */