Commit 33417507 authored by Bryan Henderson's avatar Bryan Henderson

Require superuser privilege to create C function.

parent b13f5c25
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* define.c-- * define.c--
* POSTGRES "define" utility code. *
* These routines execute some of the CREATE statements. In an earlier
* version of Postgres, these were "define" statements.
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.2 1996/10/23 07:40:01 scrappy Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.3 1996/10/31 09:07:41 bryanh Exp $
* *
* DESCRIPTION * DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the * The "DefineFoo" routines take the parse tree and pick out the
* appropriate arguments/flags, passing the results to the * appropriate arguments/flags, passing the results to the
* corresponding "FooDefine" routines (in src/catalog) that do * corresponding "FooDefine" routines (in src/catalog) that do
* the actual catalog-munging. * the actual catalog-munging. These routines also verify permission
* of the user to execute the command.
* *
* NOTES * NOTES
* These things must be defined and committed in the following order: * These things must be defined and committed in the following order:
* "define function": * "create function":
* input/output, recv/send procedures * input/output, recv/send procedures
* "define type": * "create type":
* type * type
* "define operator": * "create operator":
* operators * operators
* *
* Most of the parse-tree manipulation routines are defined in * Most of the parse-tree manipulation routines are defined in
* commands/manip.c. * commands/manip.c.
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -33,298 +36,358 @@ ...@@ -33,298 +36,358 @@
#include <ctype.h> #include <ctype.h>
#include <math.h> #include <math.h>
#include "postgres.h" #include <postgres.h>
#include "access/heapam.h" #include <access/heapam.h>
#include "access/htup.h" #include <access/htup.h>
#include "utils/tqual.h" #include <utils/tqual.h>
#include "catalog/catname.h" #include <catalog/catname.h>
#include "catalog/pg_aggregate.h" #include <catalog/pg_aggregate.h>
#include "catalog/pg_proc.h" #include <catalog/pg_operator.h>
#include "catalog/pg_type.h" #include <catalog/pg_proc.h>
#include "catalog/pg_operator.h" #include <catalog/pg_type.h>
#include "utils/syscache.h" #include <catalog/pg_user.h> /* superuser() uses this */
#include "nodes/pg_list.h" #include <utils/syscache.h>
#include "nodes/parsenodes.h" #include <nodes/pg_list.h>
#include "fmgr.h" /* for fmgr */ #include <nodes/parsenodes.h>
#include <fmgr.h> /* for fmgr */
#include "utils/builtins.h" /* prototype for textin() */
#include <utils/builtins.h> /* prototype for textin() */
#include "utils/elog.h"
#include "utils/palloc.h" #include <utils/elog.h>
#include "commands/defrem.h" #include <utils/palloc.h>
#include "optimizer/xfunc.h" #include <commands/defrem.h>
#include "tcop/dest.h" #include <optimizer/xfunc.h>
#include <tcop/dest.h>
static char *defGetString(DefElem *def); static char *defGetString(DefElem *def);
static int defGetTypeLength(DefElem *def); static int defGetTypeLength(DefElem *def);
#define DEFAULT_TYPDELIM ',' #define DEFAULT_TYPDELIM ','
bool
superuser(void) {
/*--------------------------------------------------------------------------
The Postgres user running this command has Postgres superuser
privileges.
--------------------------------------------------------------------------*/
HeapTuple utup;
char *userName;
userName = GetPgUserName();
utup = SearchSysCacheTuple(USENAME, PointerGetDatum(userName),
0,0,0);
Assert(utup != NULL);
return ((Form_pg_user)GETSTRUCT(utup))->usesuper;
}
/*
* DefineFunction --
* Registers a new function.
*
*/
void void
DefineFunction(ProcedureStmt *stmt, CommandDest dest) case_translate_language_name(const char *input, char *output) {
{ /*-------------------------------------------------------------------------
List *parameters = stmt->withClause; Translate the input language name to lower case, except if it's C,
char *proname = stmt->funcname; translate to upper case.
char* probin_str; --------------------------------------------------------------------------*/
char* prosrc_str; int i;
char *prorettype;
char *languageName; for (i = 0; i < NAMEDATALEN && input[i] != '\0'; ++i)
bool canCache = FALSE; output[i] = tolower(input[i]);
List *argList;
int32 byte_pct = 100, perbyte_cpu, percall_cpu, outin_ratio = 100; output[i] = '\0';
bool returnsSet;
int i; if (strcmp(output, "c") == 0) output[0] = 'C';
}
/* ----------------
* figure out the language and convert it to lowercase.
* ----------------
*/ void
languageName = stmt->language; compute_return_type(const Node *returnType,
for (i = 0; i < NAMEDATALEN && languageName[i]; ++i) { char **prorettype_p, bool *returnsSet_p) {
languageName[i] = tolower(languageName[i]); /*---------------------------------------------------------------------------
} Examine the "returns" clause returnType of the CREATE FUNCTION statement
and return information about it as **prorettype_p and **returnsSet.
/* ---------------- ----------------------------------------------------------------------------*/
* handle "returntype = X". The function could return a singleton if (nodeTag(returnType) == T_TypeName) {
* value or a set of values. Figure out which. /* a set of values */
* ---------------- TypeName *setType = (TypeName *)returnType;
*/ *prorettype_p = setType->name,
if (nodeTag(stmt->returnType)==T_TypeName) { *returnsSet_p = true;
TypeName *setType = (TypeName *)stmt->returnType;
/* a set of values */
prorettype = setType->name,
returnsSet = true;
}else { }else {
/* singleton */ /* singleton */
prorettype = strVal(stmt->returnType); *prorettype_p = strVal(returnType);
returnsSet = false; *returnsSet_p = false;
} }
}
/* Next attributes are only defined for C functions */
if ( strcmp(languageName, "c") == 0 || void
strcmp(languageName, "internal") == 0 ) { compute_full_attributes(const List *parameters, int32 *byte_pct_p,
List *pl; int32 *perbyte_cpu_p, int32 *percall_cpu_p,
int32 *outin_ratio_p, bool *canCache_p) {
/* the defaults */ /*--------------------------------------------------------------------------
byte_pct = BYTE_PCT; Interpret the parameters *parameters and return their contents as
perbyte_cpu = PERBYTE_CPU; *byte_pct_p, etc.
percall_cpu = PERCALL_CPU;
outin_ratio = OUTIN_RATIO; These are the full parameters of a C or internal function.
---------------------------------------------------------------------------*/
foreach(pl, parameters) { List *pl;
int count;
char *ptr; /* the defaults */
ParamString *param = (ParamString*)lfirst(pl); *byte_pct_p = BYTE_PCT;
*perbyte_cpu_p = PERBYTE_CPU;
if (!strcasecmp(param->name, "isacachable")) { *percall_cpu_p = PERCALL_CPU;
/* ---------------- *outin_ratio_p = OUTIN_RATIO;
* handle "[ iscachable ]": figure out if Postquel functions
* are cacheable automagically? foreach(pl, (List *)parameters) {
* ---------------- int count;
*/ char *ptr;
canCache = TRUE; ParamString *param = (ParamString*)lfirst(pl);
}else if (!strcasecmp(param->name, "trusted")) {
/* if (strcasecmp(param->name, "iscachable") == 0) {
* we don't have untrusted functions any more. The 4.2 *canCache_p = true;
* implementation is lousy anyway so I took it out. } else if (strcasecmp(param->name, "trusted") == 0) {
* -ay 10/94 /*
*/ * we don't have untrusted functions any more. The 4.2
elog(WARN, "untrusted function has been decommissioned."); * implementation is lousy anyway so I took it out.
}else if (!strcasecmp(param->name, "byte_pct")) { * -ay 10/94
/* */
** handle expensive function parameters elog(WARN, "untrusted function has been decommissioned.");
*/ } else if (strcasecmp(param->name, "byte_pct") == 0) {
byte_pct = atoi(param->val); /*
}else if (!strcasecmp(param->name, "perbyte_cpu")) { ** handle expensive function parameters
if (!sscanf(param->val, "%d", &perbyte_cpu)) { */
for (count = 0, ptr = param->val; *ptr != '\0'; ptr++) { *byte_pct_p = atoi(param->val);
if (*ptr == '!') { } else if (strcasecmp(param->name, "perbyte_cpu") == 0) {
count++; if (sscanf(param->val, "%d", perbyte_cpu_p) == 0) {
} for (count = 0, ptr = param->val; *ptr != '\0'; ptr++)
} if (*ptr == '!') count++;
perbyte_cpu = (int) pow(10.0, (double) count); }
} *perbyte_cpu_p = (int) pow(10.0, (double) count);
}else if (!strcasecmp(param->name, "percall_cpu")) { } else if (strcasecmp(param->name, "percall_cpu") == 0) {
if (!sscanf(param->val, "%d", &percall_cpu)) { if (sscanf(param->val, "%d", percall_cpu_p) == 0) {
for (count = 0, ptr = param->val; *ptr != '\0'; ptr++) { for (count = 0, ptr = param->val; *ptr != '\0'; ptr++)
if (*ptr == '!') { if (*ptr == '!') count++;
count++; *percall_cpu_p = (int) pow(10.0, (double) count);
} }
} } else if (strcasecmp(param->name, "outin_ratio") == 0) {
percall_cpu = (int) pow(10.0, (double) count); *outin_ratio_p = atoi(param->val);
} }
}else if (!strcasecmp(param->name, "outin_ratio")) {
outin_ratio = atoi(param->val);
}
}
} else if (!strcmp(languageName, "sql")) {
/* query optimizer groks sql, these are meaningless */
perbyte_cpu = percall_cpu = 0;
} else {
elog(WARN, "DefineFunction: language '%s' is not supported",
languageName);
} }
}
/* ----------------
* handle "[ arg is (...) ]"
* XXX fix optional arg handling below
* ---------------- void
*/ interpret_AS_clause(const char languageName[], const char as[],
argList = stmt->defArgs; char **prosrc_str_p, char **probin_str_p) {
if ( strcmp(languageName, "c") == 0 || if ( strcmp(languageName, "C") == 0 ||
strcmp(languageName, "internal") == 0 ) { strcmp(languageName, "internal") == 0 ) {
prosrc_str = "-"; *prosrc_str_p = "-";
probin_str = stmt->as; *probin_str_p = (char *)as;
} else { } else {
prosrc_str = stmt->as; *prosrc_str_p = (char *)as;
probin_str = "-"; *probin_str_p = "-";
} }
}
/* C is stored uppercase in pg_language */
if (!strcmp(languageName, "c")) {
languageName[0] = 'C';
/*
* CreateFunction --
* Execute a CREATE FUNCTION utility statement.
*
*/
void
CreateFunction(ProcedureStmt *stmt, CommandDest dest)
{
char *probin_str;
/* pathname of executable file that executes this function, if any */
char *prosrc_str;
/* SQL that executes this function, if any */
char *prorettype;
/* Type of return value (or member of set of values) from function */
char languageName[NAMEDATALEN+1];
/* name of language of function, with case adjusted:
"C", "internal", or "SQL"
*/
/* The following are attributes of the function, as expressed in the
CREATE FUNCTION statement, where applicable.
*/
int32 byte_pct, perbyte_cpu, percall_cpu, outin_ratio;
bool canCache;
bool returnsSet;
/* 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);
} 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;
} else {
elog(WARN,
"Unrecognized language specified in a CREATE FUNCTION: "
"'%s'. Recognized languages are sql, C, and internal.",
languageName);
} }
/* ---------------- interpret_AS_clause(languageName, stmt->as, &prosrc_str, &probin_str);
* now have ProcedureDefine do all the work..
* ---------------- if (strcmp(languageName, "sql") != 0 && !superuser())
*/ elog(WARN,
ProcedureCreate(proname, "Only users with Postgres superuser privilege are permitted "
returnsSet, "to create a function "
prorettype, "in the '%s' language. Others may use the 'sql' language.",
languageName, languageName);
prosrc_str, /* converted to text later */ /* Above does not return. */
probin_str, /* converted to text later */ else {
canCache, /* And now that we have all the parameters, and know we're permitted
TRUE, to do so, go ahead and create the function.
byte_pct, */
perbyte_cpu, ProcedureCreate(stmt->funcname,
percall_cpu, returnsSet,
outin_ratio, prorettype,
argList, languageName,
dest); 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);
}
} }
/* -------------------------------- /* --------------------------------
* DefineOperator-- * DefineOperator--
* *
* this function extracts all the information from the * this function extracts all the information from the
* parameter list generated by the parser and then has * parameter list generated by the parser and then has
* OperatorCreate() do all the actual work. * OperatorCreate() do all the actual work.
* *
* 'parameters' is a list of DefElem * 'parameters' is a list of DefElem
* -------------------------------- * --------------------------------
*/ */
void void
DefineOperator(char *oprName, DefineOperator(char *oprName,
List *parameters) List *parameters)
{ {
uint16 precedence=0; /* operator precedence */ uint16 precedence=0; /* operator precedence */
bool canHash=false; /* operator hashes */ bool canHash=false; /* operator hashes */
bool isLeftAssociative=true; /* operator is left associative */ bool isLeftAssociative=true; /* operator is left associative */
char *functionName=NULL; /* function for operator */ char *functionName=NULL; /* function for operator */
char *typeName1=NULL; /* first type name */ char *typeName1=NULL; /* first type name */
char *typeName2=NULL; /* second type name */ char *typeName2=NULL; /* second type name */
char *commutatorName=NULL; /* optional commutator operator name */ char *commutatorName=NULL; /* optional commutator operator name */
char *negatorName=NULL; /* optional negator operator name */ char *negatorName=NULL; /* optional negator operator name */
char *restrictionName=NULL; /* optional restrict. sel. procedure */ char *restrictionName=NULL; /* optional restrict. sel. procedure */
char *joinName=NULL; /* optional join sel. procedure name */ char *joinName=NULL; /* optional join sel. procedure name */
char *sortName1=NULL; /* optional first sort operator */ char *sortName1=NULL; /* optional first sort operator */
char *sortName2=NULL; /* optional second sort operator */ char *sortName2=NULL; /* optional second sort operator */
List *pl; List *pl;
/* /*
* loop over the definition list and extract the information we need. * loop over the definition list and extract the information we need.
*/ */
foreach (pl, parameters) { foreach (pl, parameters) {
DefElem *defel = (DefElem *)lfirst(pl); DefElem *defel = (DefElem *)lfirst(pl);
if (!strcasecmp(defel->defname, "leftarg")) { if (!strcasecmp(defel->defname, "leftarg")) {
/* see gram.y, must be setof */ /* see gram.y, must be setof */
if (nodeTag(defel->arg)==T_TypeName) if (nodeTag(defel->arg)==T_TypeName)
elog(WARN, "setof type not implemented for leftarg"); elog(WARN, "setof type not implemented for leftarg");
if (nodeTag(defel->arg)==T_String) { if (nodeTag(defel->arg)==T_String) {
typeName1 = defGetString(defel); typeName1 = defGetString(defel);
}else { }else {
elog(WARN, "type for leftarg is malformed."); elog(WARN, "type for leftarg is malformed.");
} }
} else if (!strcasecmp(defel->defname, "rightarg")) { } else if (!strcasecmp(defel->defname, "rightarg")) {
/* see gram.y, must be setof */ /* see gram.y, must be setof */
if (nodeTag(defel->arg)==T_TypeName) if (nodeTag(defel->arg)==T_TypeName)
elog(WARN, "setof type not implemented for rightarg"); elog(WARN, "setof type not implemented for rightarg");
if (nodeTag(defel->arg)==T_String) { if (nodeTag(defel->arg)==T_String) {
typeName2 = defGetString(defel); typeName2 = defGetString(defel);
}else { }else {
elog(WARN, "type for rightarg is malformed."); elog(WARN, "type for rightarg is malformed.");
} }
} else if (!strcasecmp(defel->defname, "procedure")) { } else if (!strcasecmp(defel->defname, "procedure")) {
functionName = defGetString(defel); functionName = defGetString(defel);
} else if (!strcasecmp(defel->defname, "precedence")) { } else if (!strcasecmp(defel->defname, "precedence")) {
/* NOT IMPLEMENTED (never worked in v4.2) */ /* NOT IMPLEMENTED (never worked in v4.2) */
elog(NOTICE, "CREATE OPERATOR: precedence not implemented"); elog(NOTICE, "CREATE OPERATOR: precedence not implemented");
} else if (!strcasecmp(defel->defname, "associativity")) { } else if (!strcasecmp(defel->defname, "associativity")) {
/* NOT IMPLEMENTED (never worked in v4.2) */ /* NOT IMPLEMENTED (never worked in v4.2) */
elog(NOTICE, "CREATE OPERATOR: associativity not implemented"); elog(NOTICE, "CREATE OPERATOR: associativity not implemented");
} else if (!strcasecmp(defel->defname, "commutator")) { } else if (!strcasecmp(defel->defname, "commutator")) {
commutatorName = defGetString(defel); commutatorName = defGetString(defel);
} else if (!strcasecmp(defel->defname, "negator")) { } else if (!strcasecmp(defel->defname, "negator")) {
negatorName = defGetString(defel); negatorName = defGetString(defel);
} else if (!strcasecmp(defel->defname, "restrict")) { } else if (!strcasecmp(defel->defname, "restrict")) {
restrictionName = defGetString(defel); restrictionName = defGetString(defel);
} else if (!strcasecmp(defel->defname, "join")) { } else if (!strcasecmp(defel->defname, "join")) {
joinName = defGetString(defel); joinName = defGetString(defel);
} else if (!strcasecmp(defel->defname, "hashes")) { } else if (!strcasecmp(defel->defname, "hashes")) {
canHash = TRUE; canHash = TRUE;
} else if (!strcasecmp(defel->defname, "sort1")) { } else if (!strcasecmp(defel->defname, "sort1")) {
/* ---------------- /* ----------------
* XXX ( ... [ , sort1 = oprname ] [ , sort2 = oprname ] ... ) * XXX ( ... [ , sort1 = oprname ] [ , sort2 = oprname ] ... )
* XXX is undocumented in the reference manual source as of * XXX is undocumented in the reference manual source as of
* 89/8/22. * 89/8/22.
* ---------------- * ----------------
*/ */
sortName1 = defGetString(defel); sortName1 = defGetString(defel);
} else if (!strcasecmp(defel->defname, "sort2")) { } else if (!strcasecmp(defel->defname, "sort2")) {
sortName2 = defGetString(defel); sortName2 = defGetString(defel);
} else { } else {
elog(NOTICE, "DefineOperator: attribute \"%s\" not recognized", elog(NOTICE, "DefineOperator: attribute \"%s\" not recognized",
defel->defname); defel->defname);
} }
} }
/* /*
* make sure we have our required definitions * make sure we have our required definitions
*/ */
if (functionName==NULL) { if (functionName==NULL) {
elog(WARN, "Define: \"procedure\" unspecified"); elog(WARN, "Define: \"procedure\" unspecified");
} }
/* ---------------- /* ----------------
* now have OperatorCreate do all the work.. * now have OperatorCreate do all the work..
* ---------------- * ----------------
*/ */
OperatorCreate(oprName, /* operator name */ OperatorCreate(oprName, /* operator name */
typeName1, /* first type name */ typeName1, /* first type name */
typeName2, /* second type name */ typeName2, /* second type name */
functionName, /* function for operator */ functionName, /* function for operator */
precedence, /* operator precedence */ precedence, /* operator precedence */
isLeftAssociative, /* operator is left associative */ isLeftAssociative, /* operator is left associative */
commutatorName, /* optional commutator operator name */ commutatorName, /* optional commutator operator name */
negatorName, /* optional negator operator name */ negatorName, /* optional negator operator name */
restrictionName, /* optional restrict. sel. procedure */ restrictionName, /* optional restrict. sel. procedure */
joinName, /* optional join sel. procedure name */ joinName, /* optional join sel. procedure name */
canHash, /* operator hashes */ canHash, /* operator hashes */
sortName1, /* optional first sort operator */ sortName1, /* optional first sort operator */
sortName2); /* optional second sort operator */ sortName2); /* optional second sort operator */
} }
...@@ -347,170 +410,170 @@ DefineAggregate(char *aggName, List *parameters) ...@@ -347,170 +410,170 @@ DefineAggregate(char *aggName, List *parameters)
List *pl; List *pl;
foreach (pl, parameters) { foreach (pl, parameters) {
DefElem *defel = (DefElem *)lfirst(pl); DefElem *defel = (DefElem *)lfirst(pl);
/* /*
* sfunc1 * sfunc1
*/ */
if (!strcasecmp(defel->defname, "sfunc1")) { if (!strcasecmp(defel->defname, "sfunc1")) {
stepfunc1Name = defGetString(defel); stepfunc1Name = defGetString(defel);
} else if (!strcasecmp(defel->defname, "basetype")) { } else if (!strcasecmp(defel->defname, "basetype")) {
baseType = defGetString(defel); baseType = defGetString(defel);
} else if (!strcasecmp(defel->defname, "stype1")) { } else if (!strcasecmp(defel->defname, "stype1")) {
stepfunc1Type = defGetString(defel); stepfunc1Type = defGetString(defel);
/* /*
* sfunc2 * sfunc2
*/ */
} else if (!strcasecmp(defel->defname, "sfunc2")) { } else if (!strcasecmp(defel->defname, "sfunc2")) {
stepfunc2Name = defGetString(defel); stepfunc2Name = defGetString(defel);
} else if (!strcasecmp(defel->defname, "stype2")) { } else if (!strcasecmp(defel->defname, "stype2")) {
stepfunc2Type = defGetString(defel); stepfunc2Type = defGetString(defel);
/* /*
* final * final
*/ */
} else if (!strcasecmp(defel->defname, "finalfunc")) { } else if (!strcasecmp(defel->defname, "finalfunc")) {
finalfuncName = defGetString(defel); finalfuncName = defGetString(defel);
/* /*
* initial conditions * initial conditions
*/ */
} else if (!strcasecmp(defel->defname, "initcond1")) { } else if (!strcasecmp(defel->defname, "initcond1")) {
init1 = defGetString(defel); init1 = defGetString(defel);
} else if (!strcasecmp(defel->defname, "initcond2")) { } else if (!strcasecmp(defel->defname, "initcond2")) {
init2 = defGetString(defel); init2 = defGetString(defel);
} else { } else {
elog(NOTICE, "DefineAggregate: attribute \"%s\" not recognized", elog(NOTICE, "DefineAggregate: attribute \"%s\" not recognized",
defel->defname); defel->defname);
} }
} }
/* /*
* make sure we have our required definitions * make sure we have our required definitions
*/ */
if (baseType==NULL) if (baseType==NULL)
elog(WARN, "Define: \"basetype\" unspecified"); elog(WARN, "Define: \"basetype\" unspecified");
if (stepfunc1Name!=NULL) { if (stepfunc1Name!=NULL) {
if (stepfunc1Type==NULL) if (stepfunc1Type==NULL)
elog(WARN, "Define: \"stype1\" unspecified"); elog(WARN, "Define: \"stype1\" unspecified");
} }
if (stepfunc2Name!=NULL) { if (stepfunc2Name!=NULL) {
if (stepfunc2Type==NULL) if (stepfunc2Type==NULL)
elog(WARN, "Define: \"stype2\" unspecified"); elog(WARN, "Define: \"stype2\" unspecified");
} }
/* /*
* Most of the argument-checking is done inside of AggregateCreate * Most of the argument-checking is done inside of AggregateCreate
*/ */
AggregateCreate(aggName, /* aggregate name */ AggregateCreate(aggName, /* aggregate name */
stepfunc1Name, /* first step function name */ stepfunc1Name, /* first step function name */
stepfunc2Name, /* second step function name */ stepfunc2Name, /* second step function name */
finalfuncName, /* final function name */ finalfuncName, /* final function name */
baseType, /* type of object being aggregated */ baseType, /* type of object being aggregated */
stepfunc1Type, /* return type of first function */ stepfunc1Type, /* return type of first function */
stepfunc2Type, /* return type of second function */ stepfunc2Type, /* return type of second function */
init1, /* first initial condition */ init1, /* first initial condition */
init2); /* second initial condition */ init2); /* second initial condition */
/* XXX free palloc'd memory */ /* XXX free palloc'd memory */
} }
/* /*
* DefineType -- * DefineType --
* Registers a new type. * Registers a new type.
* *
*/ */
void void
DefineType(char *typeName, List *parameters) DefineType(char *typeName, List *parameters)
{ {
int16 internalLength= 0; /* int2 */ int16 internalLength= 0; /* int2 */
int16 externalLength= 0; /* int2 */ int16 externalLength= 0; /* int2 */
char *elemName = NULL; char *elemName = NULL;
char *inputName = NULL; char *inputName = NULL;
char *outputName = NULL; char *outputName = NULL;
char *sendName = NULL; char *sendName = NULL;
char *receiveName = NULL; char *receiveName = NULL;
char *defaultValue = NULL; /* Datum */ char *defaultValue = NULL; /* Datum */
bool byValue = false; bool byValue = false;
char delimiter = DEFAULT_TYPDELIM; char delimiter = DEFAULT_TYPDELIM;
char *shadow_type; char *shadow_type;
List *pl; List *pl;
char alignment = 'i'; /* default alignment */ char alignment = 'i'; /* default alignment */
/* /*
* Type names can only be 15 characters long, so that the shadow type * Type names can only be 15 characters long, so that the shadow type
* can be created using the 16th character as necessary. * can be created using the 16th character as necessary.
*/ */
if (strlen(typeName) >= (NAMEDATALEN - 1)) { if (strlen(typeName) >= (NAMEDATALEN - 1)) {
elog(WARN, "DefineType: type names must be %d characters or less", elog(WARN, "DefineType: type names must be %d characters or less",
NAMEDATALEN - 1); NAMEDATALEN - 1);
} }
foreach(pl, parameters) { foreach(pl, parameters) {
DefElem *defel = (DefElem*)lfirst(pl); DefElem *defel = (DefElem*)lfirst(pl);
if (!strcasecmp(defel->defname, "internallength")) { if (!strcasecmp(defel->defname, "internallength")) {
internalLength = defGetTypeLength(defel); internalLength = defGetTypeLength(defel);
}else if (!strcasecmp(defel->defname, "externallength")) { }else if (!strcasecmp(defel->defname, "externallength")) {
externalLength = defGetTypeLength(defel); externalLength = defGetTypeLength(defel);
}else if (!strcasecmp(defel->defname, "input")) { }else if (!strcasecmp(defel->defname, "input")) {
inputName = defGetString(defel); inputName = defGetString(defel);
}else if (!strcasecmp(defel->defname, "output")) { }else if (!strcasecmp(defel->defname, "output")) {
outputName = defGetString(defel); outputName = defGetString(defel);
}else if (!strcasecmp(defel->defname, "send")) { }else if (!strcasecmp(defel->defname, "send")) {
sendName = defGetString(defel); sendName = defGetString(defel);
}else if (!strcasecmp(defel->defname, "delimiter")) { }else if (!strcasecmp(defel->defname, "delimiter")) {
char *p = defGetString(defel); char *p = defGetString(defel);
delimiter = p[0]; delimiter = p[0];
}else if (!strcasecmp(defel->defname, "receive")) { }else if (!strcasecmp(defel->defname, "receive")) {
receiveName = defGetString(defel); receiveName = defGetString(defel);
}else if (!strcasecmp(defel->defname, "element")) { }else if (!strcasecmp(defel->defname, "element")) {
elemName = defGetString(defel); elemName = defGetString(defel);
}else if (!strcasecmp(defel->defname, "default")) { }else if (!strcasecmp(defel->defname, "default")) {
defaultValue = defGetString(defel); defaultValue = defGetString(defel);
}else if (!strcasecmp(defel->defname, "passedbyvalue")) { }else if (!strcasecmp(defel->defname, "passedbyvalue")) {
byValue = true; byValue = true;
}else if (!strcasecmp(defel->defname, "alignment")) { }else if (!strcasecmp(defel->defname, "alignment")) {
char *a = defGetString(defel); char *a = defGetString(defel);
if (!strcasecmp(a, "double")) { if (!strcasecmp(a, "double")) {
alignment = 'd'; alignment = 'd';
} else if (!strcasecmp(a, "int")) { } else if (!strcasecmp(a, "int")) {
alignment = 'i'; alignment = 'i';
} else { } else {
elog(WARN, "DefineType: \"%s\" alignment not recognized", elog(WARN, "DefineType: \"%s\" alignment not recognized",
a); a);
} }
}else { }else {
elog(NOTICE, "DefineType: attribute \"%s\" not recognized", elog(NOTICE, "DefineType: attribute \"%s\" not recognized",
defel->defname); defel->defname);
} }
} }
/* /*
* make sure we have our required definitions * make sure we have our required definitions
*/ */
if (inputName==NULL) if (inputName==NULL)
elog(WARN, "Define: \"input\" unspecified"); elog(WARN, "Define: \"input\" unspecified");
if (outputName==NULL) if (outputName==NULL)
elog(WARN, "Define: \"output\" unspecified"); elog(WARN, "Define: \"output\" unspecified");
/* ---------------- /* ----------------
* now have TypeCreate do all the real work. * now have TypeCreate do all the real work.
* ---------------- * ----------------
*/ */
(void) TypeCreate(typeName, /* type name */ (void) TypeCreate(typeName, /* type name */
InvalidOid, /* relation oid (n/a here) */ InvalidOid, /* relation oid (n/a here) */
internalLength, /* internal size */ internalLength, /* internal size */
externalLength, /* external size */ externalLength, /* external size */
'b', /* type-type (base type) */ 'b', /* type-type (base type) */
delimiter, /* array element delimiter */ delimiter, /* array element delimiter */
inputName, /* input procedure */ inputName, /* input procedure */
outputName, /* output procedure */ outputName, /* output procedure */
sendName, /* send procedure */ sendName, /* send procedure */
receiveName, /* receive procedure */ receiveName, /* receive procedure */
elemName, /* element type name */ elemName, /* element type name */
defaultValue, /* default type value */ defaultValue, /* default type value */
byValue, /* passed by value */ byValue, /* passed by value */
alignment); alignment);
/* ---------------- /* ----------------
* When we create a true type (as opposed to a complex type) * When we create a true type (as opposed to a complex type)
...@@ -519,20 +582,20 @@ DefineType(char *typeName, List *parameters) ...@@ -519,20 +582,20 @@ DefineType(char *typeName, List *parameters)
*/ */
shadow_type = makeArrayTypeName(typeName); shadow_type = makeArrayTypeName(typeName);
(void) TypeCreate(shadow_type, /* type name */ (void) TypeCreate(shadow_type, /* type name */
InvalidOid, /* relation oid (n/a here) */ InvalidOid, /* relation oid (n/a here) */
-1, /* internal size */ -1, /* internal size */
-1, /* external size */ -1, /* external size */
'b', /* type-type (base type) */ 'b', /* type-type (base type) */
DEFAULT_TYPDELIM, /* array element delimiter */ DEFAULT_TYPDELIM, /* array element delimiter */
"array_in", /* input procedure */ "array_in", /* input procedure */
"array_out", /* output procedure */ "array_out", /* output procedure */
"array_out", /* send procedure */ "array_out", /* send procedure */
"array_in", /* receive procedure */ "array_in", /* receive procedure */
typeName, /* element type name */ typeName, /* element type name */
defaultValue, /* default type value */ defaultValue, /* default type value */
false, /* never passed by value */ false, /* never passed by value */
alignment); alignment);
pfree(shadow_type); pfree(shadow_type);
} }
...@@ -541,7 +604,7 @@ static char * ...@@ -541,7 +604,7 @@ static char *
defGetString(DefElem *def) defGetString(DefElem *def)
{ {
if (nodeTag(def->arg)!=T_String) if (nodeTag(def->arg)!=T_String)
elog(WARN, "Define: \"%s\" = what?", def->defname); elog(WARN, "Define: \"%s\" = what?", def->defname);
return (strVal(def->arg)); return (strVal(def->arg));
} }
...@@ -549,10 +612,10 @@ static int ...@@ -549,10 +612,10 @@ static int
defGetTypeLength(DefElem *def) defGetTypeLength(DefElem *def)
{ {
if (nodeTag(def->arg)==T_Integer) if (nodeTag(def->arg)==T_Integer)
return (intVal(def->arg)); return (intVal(def->arg));
else if (nodeTag(def->arg)==T_String && else if (nodeTag(def->arg)==T_String &&
!strcasecmp(strVal(def->arg),"variable")) !strcasecmp(strVal(def->arg),"variable"))
return -1; /* variable length */ return -1; /* variable length */
elog(WARN, "Define: \"%s\" = what?", def->defname); elog(WARN, "Define: \"%s\" = what?", def->defname);
return -1; return -1;
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.2 1996/08/24 20:49:03 scrappy Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.3 1996/10/31 09:08:10 bryanh Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -367,7 +367,7 @@ ProcessUtility(Node *parsetree, ...@@ -367,7 +367,7 @@ ProcessUtility(Node *parsetree,
} }
break; break;
case T_ViewStmt: /* VIEW */ case T_ViewStmt: /* CREATE VIEW */
{ {
ViewStmt *stmt = (ViewStmt *)parsetree; ViewStmt *stmt = (ViewStmt *)parsetree;
...@@ -377,13 +377,13 @@ ProcessUtility(Node *parsetree, ...@@ -377,13 +377,13 @@ ProcessUtility(Node *parsetree,
} }
break; break;
case T_ProcedureStmt: /* FUNCTION */ case T_ProcedureStmt: /* CREATE FUNCTION */
commandTag = "CREATE"; commandTag = "CREATE";
CHECK_IF_ABORTED(); CHECK_IF_ABORTED();
DefineFunction((ProcedureStmt *)parsetree, dest); /* everything */ CreateFunction((ProcedureStmt *)parsetree, dest); /* everything */
break; break;
case T_IndexStmt: case T_IndexStmt: /* CREATE INDEX */
{ {
IndexStmt *stmt = (IndexStmt *)parsetree; IndexStmt *stmt = (IndexStmt *)parsetree;
...@@ -400,7 +400,7 @@ ProcessUtility(Node *parsetree, ...@@ -400,7 +400,7 @@ ProcessUtility(Node *parsetree,
} }
break; break;
case T_RuleStmt: case T_RuleStmt: /* CREATE RULE */
{ {
RuleStmt *stmt = (RuleStmt *)parsetree; RuleStmt *stmt = (RuleStmt *)parsetree;
#ifndef NO_SECURITY #ifndef NO_SECURITY
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment