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