home *** CD-ROM | disk | FTP | other *** search
- /* ----------------------------------------------------------------
- * define.c --
- * POSTGRES define (function | type | operator) utility code.
- *
- * NOTES:
- * These things must be defined and committed in the following order:
- * input/output, recv/send procedures
- * type
- * operators
- * ----------------------------------------------------------------
- */
-
- #include <strings.h> /* XXX style */
- #include <ctype.h>
- #include <math.h>
-
- #include "tmp/postgres.h"
-
- RcsId("$Header: /private/postgres/src/commands/RCS/define.c,v 1.52 1992/08/19 19:37:41 mer Exp $");
-
- #include "access/ftup.h"
- #include "access/heapam.h"
- #include "access/htup.h"
- #include "access/tqual.h"
- #include "catalog/catname.h"
- #include "catalog/syscache.h"
- #include "manip.h"
- #include "nodes/pg_lisp.h"
- #include "parser/parse.h" /* for ARG */
- #include "utils/fmgr.h" /* for fmgr */
- #include "utils/builtins.h" /* prototype for textin() */
- #include "utils/log.h"
-
- #include "commands/defrem.h"
- #include "planner/xfunc.h"
-
- #include "tcop/dest.h"
-
- /* ----------------
- * external functions
- * ----------------
- */
- extern ObjectId TypeDefine();
- extern void ProcedureDefine();
- extern void OperatorDefine();
- extern void AggregateDefine();
-
- /* ----------------
- * this is used by the DefineXXX functions below.
- * ----------------
- */
- extern
- String /* XXX Datum */
- FetchDefault ARGS((
- String string,
- String standard
- ));
-
- /* ----------------------------------------------------------------
- * Define Function / Operator / Type
- * ----------------------------------------------------------------
- */
-
- /* --------------------------------
- * DefineFunction
- * --------------------------------
- */
- void
- DefineFunction(nameargsexe, dest)
- LispValue nameargsexe;
- CommandDest dest;
- {
- Name name = (Name) CString(CAR(CAR(nameargsexe)));
- LispValue parameters = CDR(CAR(nameargsexe));
- LispValue entry;
- String languageName, fileName, sourceCode;
- char *c;
- String returnTypeName;
- char blankstring[2];
- bool canCache;
- bool trusted = true;
- String trusted_str;
- LispValue argList;
- int32 byte_pct, perbyte_cpu, percall_cpu, outin_ratio;
- String perbyte_str, percall_str;
- int count;
- char *ptr;
- bool returnsSet;
-
- /* ----------------
- * Note:
- * XXX Checking of "name" validity (16 characters?) is needed.
- * ----------------
- */
- AssertArg(NameIsValid(name));
-
- /* figure out the language */
- entry = DefineListRemoveRequiredAssignment(¶meters, "language");
- languageName = DefineEntryGetString(entry);
- /* lowercase-ise the language */
- for (c = languageName; *c != '\0'; c++)
- *c = tolower(*c);
-
- if (!strcmp(languageName, "postquel") && !strcmp(languageName, "c"))
- elog(WARN, "DefineFunction: Specified language not supported");
-
- /* ----------------
- * handle "returntype = X". The function could return a singleton
- * value or a set of values. Figure out which.
- * ----------------
- */
- entry = DefineListRemoveRequiredAssignment(¶meters, "returntype");
- if (IsA(CADR(entry),LispList)) {
- returnTypeName = LISPVALUE_STRING(CDR(CADR(entry)));
- returnsSet = true;
- } else {
- returnTypeName = CString(CADR(entry));
- returnsSet = false;
- }
-
- /* Next attributes only definable for C functions */
- if (!strcmp(languageName, "c"))
- {
- /* ----------------
- * handle "[ iscachable ]": figure out if Postquel functions are
- * cacheable automagically?
- * ----------------
- */
-
- entry = DefineListRemoveOptionalIndicator(¶meters, "iscachable");
- canCache = (bool)!null(entry);
-
- /*
- * handle trusted/untrusted. defaults to trusted for now; when
- * i finish real support it'll default untrusted. -dpassage
- */
-
- entry = DefineListRemoveOptionalAssignment(¶meters, "trusted");
- if (null(entry))
- trusted = true;
- else
- trusted = ((DefineEntryGetString(entry)[0]) == 't');
-
- /*
- ** handle expensive function parameters
- */
- entry = DefineListRemoveOptionalAssignment(¶meters, "byte_pct");
- if (null(entry)) byte_pct = BYTE_PCT;
- else byte_pct = DefineEntryGetInteger(entry);
-
- entry = DefineListRemoveOptionalAssignment(¶meters, "perbyte_cpu");
- if (null(entry)) perbyte_cpu = PERBYTE_CPU;
- else
- {
- perbyte_str = DefineEntryGetString(entry);
- if (!sscanf(perbyte_str, "%d", &perbyte_cpu))
- {
- for (count = 0, ptr = perbyte_str; *ptr != '\0'; ptr++)
- if (*ptr == '!') count++;
- perbyte_cpu = (int) pow(10.0, (double)count);
- }
- }
-
- entry = DefineListRemoveOptionalAssignment(¶meters, "percall_cpu");
- if (null(entry)) percall_cpu = PERCALL_CPU;
- else
- {
- percall_str = DefineEntryGetString(entry);
- if (!sscanf(percall_str, "%d", &percall_cpu))
- {
- for (count = 0, ptr = percall_str; *ptr != '\0'; ptr++)
- if (*ptr == '!') count++;
- percall_cpu = (int) pow(10.0, (double)count);
- }
- }
-
-
- entry = DefineListRemoveOptionalAssignment(¶meters, "outin_ratio");
- if (null(entry)) outin_ratio = OUTIN_RATIO;
- else outin_ratio = DefineEntryGetInteger(entry);
-
- }
- else
- {
- /* postquel function */
- canCache = false;
-
- /* query optimizer groks postquel, these are meaningless */
- perbyte_cpu = percall_cpu = 0;
- byte_pct = outin_ratio = 100;
- }
-
- /* ----------------
- * handle "[ arg is (...) ]"
- * XXX fix optional arg handling below
- * ----------------
- */
- argList = LispRemoveMatchingSymbol(¶meters, ARG);
-
- if (!null(argList)) {
- LispValue rest;
-
- /*
- * first discard symbol 'arg from list
- */
- argList = CDR(argList);
- AssertArg(length(argList) > 0);
-
- foreach (rest, argList) {
- if (!lispStringp(CAR(rest))) {
- elog(WARN, "DefineFunction: arg type = ?");
- }
- }
- }
-
- /* ----------------
- * there should be nothing more
- * ----------------
- */
- DefineListAssertEmpty(parameters);
-
-
- /* set up the sourcecode and filename strings */
- blankstring[0] = '-';
- blankstring[1] = '\0';
- if (!strcmp(languageName, "c"))
- {
- sourceCode = blankstring;
- fileName = CString(CADR(nameargsexe));
- }
- else
- {
- sourceCode = CString(CADR(nameargsexe));
- fileName = blankstring;
- }
-
- /* C is stored uppercase in pg_language */
- if (!strcmp(languageName, "c"))
- *languageName = 'C';
-
- /* ----------------
- * now have ProcedureDefine do all the work..
- * ----------------
- */
- ProcedureDefine(name,
- returnsSet,
- returnTypeName,
- languageName,
- sourceCode,
- fileName,
- canCache,
- trusted,
- byte_pct, perbyte_cpu, percall_cpu,
- outin_ratio,
- argList,
- dest);
- }
-
- /* --------------------------------
- * DefineOperator
- *
- * this function extracts all the information from the
- * parameter list generated by the parser and then has
- * OperatorDefine() do all the actual work.
- * --------------------------------
- */
- void
- DefineOperator(name, parameters)
- Name name;
- LispValue parameters;
- {
- LispValue entry;
- Name functionName; /* function for operator */
- Name typeName1; /* first type name */
- Name typeName2; /* optional second type name */
- uint16 precedence; /* operator precedence */
- bool canHash; /* operator hashes */
- bool isLeftAssociative; /* operator is left associative */
- Name commutatorName; /* optional commutator operator name */
- Name negatorName; /* optional negator operator name */
- Name restrictionName; /* optional restrict. sel. procedure */
- Name joinName; /* optional join sel. procedure name */
- Name sortName1; /* optional first sort operator */
- Name sortName2; /* optional second sort operator */
- NameData oprName; /* operator name */
-
- /* ----------------
- * sanity checks
- *
- * XXX Checking of operator "name" validity
- * (16 characters?) is needed.
- * ----------------
- */
- AssertArg(NameIsValid(name));
- AssertArg(listp(parameters));
-
- bzero(&oprName, sizeof(NameData));
- strncpy(&(oprName.data[0]), name, 16);
- /* ----------------
- * handle "arg1 = typname"
- *
- * XXX ( ... arg1 = typname [ , arg2 = typname ] ... )
- * XXX is undocumented in the reference manual source as of 89/8/22.
- * ----------------
- */
- entry = DefineListRemoveRequiredAssignment(¶meters, "arg1");
- typeName1 = DefineEntryGetName(entry);
-
- /* ----------------
- * handle "[ arg2 = typname ]"
- * ----------------
- */
- entry = DefineListRemoveOptionalAssignment(¶meters, "arg2");
- typeName2 = NULL;
- if (!null(entry)) {
- typeName2 = DefineEntryGetName(entry);
- }
-
- /* ----------------
- * handle "procedure = proname"
- * ----------------
- */
- entry = DefineListRemoveRequiredAssignment(¶meters, "procedure");
- functionName = DefineEntryGetName(entry);
-
- /* ----------------
- * handle "[ precedence = number ]"
- * ----------------
- */
- entry = DefineListRemoveOptionalAssignment(¶meters, "precedence");
- if (null(entry)) {
- precedence = 0; /* FetchDefault? */
- } else {
- precedence = DefineEntryGetInteger(entry);
- }
-
- /* ----------------
- * handle "[ associativity = (left|right|none|any) ]"
- *
- * XXX Associativity code below must be fixed when the catalogs and
- * XXX the planner/executor support proper associativity semantics.
- * ----------------
- */
- entry = DefineListRemoveOptionalAssignment(¶meters, "associativity");
- if (null(entry)) {
- isLeftAssociative = true; /* XXX FetchDefault */
- } else {
- String string;
-
- string = DefineEntryGetString(entry);
- if (StringEquals(string, "right")) {
- isLeftAssociative = false;
- } else if (!StringEquals(string, "left") &&
- !StringEquals(string, "none") &&
- !StringEquals(string, "any")) {
- elog(WARN, "Define: precedence = what?");
- } else {
- isLeftAssociative = true;
- }
- }
-
- /* ----------------
- * handle "[ commutator = oprname ]"
- * ----------------
- */
- entry = DefineListRemoveOptionalAssignment(¶meters, "commutator");
- commutatorName = NULL;
- if (!null(entry)) {
- commutatorName = DefineEntryGetName(entry);
- }
-
- /* ----------------
- * handle "[ negator = oprname ]"
- * ----------------
- */
- entry = DefineListRemoveOptionalAssignment(¶meters, "negator");
- negatorName = NULL;
- if (!null(entry)) {
- negatorName = DefineEntryGetName(entry);
- }
-
- /* ----------------
- * handle "[ restrict = proname ]"
- * ----------------
- */
- entry = DefineListRemoveOptionalAssignment(¶meters, "restrict");
- restrictionName = NULL;
- if (!null(entry)) {
- restrictionName = DefineEntryGetName(entry);
- }
-
- /* ----------------
- * handle "[ join = proname ]"
- * ----------------
- */
- entry = DefineListRemoveOptionalAssignment(¶meters, "join");
- joinName = NULL;
- if (!null(entry)) {
- joinName = DefineEntryGetName(entry);
- }
-
- /* ----------------
- * handle "[ hashes ]"
- * ----------------
- */
- entry = DefineListRemoveOptionalIndicator(¶meters, "hashes");
- canHash = (bool)!null(entry);
-
- /* ----------------
- * handle "[ sort1 = oprname ]"
- *
- * XXX ( ... [ , sort1 = oprname ] [ , sort2 = oprname ] ... )
- * XXX is undocumented in the reference manual source as of 89/8/22.
- * ----------------
- */
- entry = DefineListRemoveOptionalAssignment(¶meters, "sort1");
- sortName1 = NULL;
- if (!null(entry)) {
- sortName1 = DefineEntryGetName(entry);
- }
-
- /* ----------------
- * handle "[ sort2 = oprname ]"
- * ----------------
- */
- entry = DefineListRemoveOptionalAssignment(¶meters, "sort2");
- sortName2 = NULL;
- if (!null(entry)) {
- sortName2 = DefineEntryGetName(entry);
- }
-
- /* ----------------
- * there should be nothing more..
- * ----------------
- */
- DefineListAssertEmpty(parameters);
-
- /* ----------------
- * now have OperatorDefine do all the work..
- * ----------------
- */
- OperatorDefine(&oprName, /* operator name */
- typeName1, /* first type name */
- typeName2, /* optional 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 */
- }
-
- /* -------------------
- * DefineAggregate
- * ------------------
- */
- void
- DefineAggregate(name, parameters)
- Name name;
- LispValue parameters;
- {
- Name stepfunc1Name, stepfunc2Name, finalfuncName;
- String primStr, secStr;
- struct varlena *primVal, *secVal;
- LispValue entry;
-
- /* sanity checks...name validity */
-
- AssertArg(NameIsValid(name));
- AssertArg(listp(parameters));
-
- /* handle "stepfunc = proname" */
- entry = DefineListRemoveRequiredAssignment(¶meters, "sfunc1");
- stepfunc1Name = DefineEntryGetName(entry);
-
- /* handle "countfunc = proname " */
- entry = DefineListRemoveRequiredAssignment(¶meters, "sfunc2");
- stepfunc2Name = DefineEntryGetName(entry);
-
- /* handle "finalfunc = proname */
- entry = DefineListRemoveRequiredAssignment(¶meters, "finalfunc");
- finalfuncName = DefineEntryGetName(entry);
-
- /* -----------------
- * handle first initial condition
- */
- entry = DefineListRemoveRequiredAssignment(¶meters, "initcond1");
- primStr = DefineEntryGetString(entry);
- primVal = textin(primStr);
-
- /* -------------------
- * handle second initial condition
- */
- entry = DefineListRemoveRequiredAssignment(¶meters, "initcond2");
- secStr = DefineEntryGetString(entry);
- secVal = textin(secStr);
-
- DefineListAssertEmpty(parameters);
-
- AggregateDefine(name, /* aggregate name */
- stepfunc1Name, /* first step function name */
- stepfunc2Name, /* second step function name */
- finalfuncName, /* final function name */
- primVal, /* first initial condition */
- secVal); /* second initial condition */
- }
-
- /* --------------------------------
- * DefineType
- * --------------------------------
- */
- void
- DefineType(name, parameters)
- Name name;
- LispValue parameters;
- {
- LispValue entry;
- int16 internalLength; /* int2 */
- int16 externalLength; /* int2 */
- Name elemName;
- Name inputName;
- Name outputName;
- Name sendName;
- Name receiveName;
- char* defaultValue; /* Datum */
- bool byValue; /* Boolean */
- char delimiter;
- char shadow_type[16];
-
- /* ----------------
- * sanity checks
- *
- * XXX Checking of operator "name" validity
- * (16 characters?) is needed.
- * ----------------
- */
- AssertArg(NameIsValid(name));
- AssertArg(listp(parameters));
-
- /*
- * Type names can only be 15 characters long, so that the shadow type
- * can be created using the 16th character as necessary.
- */
-
- if (strlen(name) > 15)
- {
- elog(WARN, "DefineType: Names can only be 15 characters long or less");
- }
-
- /* ----------------
- * handle "internallength = (number | variable)"
- * ----------------
- */
- entry = DefineListRemoveRequiredAssignment(¶meters,
- "internallength");
- internalLength = DefineEntryGetLength(entry);
-
- /* ----------------
- * handle "[ externallength = (number | variable) ]"
- * ----------------
- */
- entry = DefineListRemoveOptionalAssignment(¶meters,
- "externallength");
- externalLength = 0; /* FetchDefault? */
- if (!null(entry)) {
- externalLength = DefineEntryGetLength(entry);
- }
-
- /* ----------------
- * handle "input = procedure"
- * ----------------
- */
- entry = DefineListRemoveRequiredAssignment(¶meters, "input");
- inputName = DefineEntryGetName(entry);
-
- /* ----------------
- * handle "output = procedure"
- * ----------------
- */
- entry = DefineListRemoveRequiredAssignment(¶meters, "output");
- outputName = DefineEntryGetName(entry);
-
- /* ----------------
- * handle "[ send = procedure ]"
- * ----------------
- */
- entry = DefineListRemoveOptionalAssignment(¶meters, "send");
- sendName = NULL;
- if (!null(entry)) {
- sendName = DefineEntryGetName(entry);
- }
-
-
- /*
- * ----------------
- * handle "[ delimiter = delim]"
- * ----------------
- */
-
- entry = DefineListRemoveOptionalAssignment(¶meters, "delimiter");
- delimiter = ',';
- if (!null(entry)) {
- char *p = (char *) DefineEntryGetName(entry);
- delimiter = p[0];
- }
-
- /* ----------------
- * handle "[ receive = procedure ]"
- * ----------------
- */
- entry = DefineListRemoveOptionalAssignment(¶meters, "receive");
- receiveName = NULL;
- if (!null(entry)) {
- receiveName = DefineEntryGetName(entry);
- }
-
- /*
- * ----------------
- * handle "[ element = type]"
- * ----------------
- */
-
- entry = DefineListRemoveOptionalAssignment(¶meters, "element");
- elemName = NULL;
- if (!null(entry)) {
- elemName = DefineEntryGetName(entry);
- }
-
- /* ----------------
- * handle "[ default = `...' ]"
- * ----------------
- */
- entry = DefineListRemoveOptionalAssignment(¶meters, "default");
- defaultValue = NULL;
- if (!null(entry)) {
- defaultValue = DefineEntryGetString(entry);
- }
-
- /* ----------------
- * handle "[ passedbyvalue ]"
- * ----------------
- */
- entry = DefineListRemoveOptionalIndicator(¶meters, "passedbyvalue");
- byValue = (bool)!null(entry);
-
- /* ----------------
- * there should be nothing more..
- * ----------------
- */
- DefineListAssertEmpty(parameters);
-
- /* ----------------
- * now have TypeDefine do all the real work.
- * ----------------
- */
- (void) TypeDefine(name, /* type name */
- InvalidObjectId, /* 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, /* recieve procedure */
- elemName, /* element type name */
- defaultValue, /* default type value */
- byValue); /* passed by value */
- /*
- * ----------------
- * When we create a true type (as opposed to a complex type)
- * we need to have an shadow array entry for it in pg type as well.
- * ----------------
- */
- sprintf(shadow_type, "_%s", name);
-
- (void) TypeDefine(shadow_type, /* type name */
- InvalidObjectId, /* relation oid (n/a here) */
- -1, /* internal size */
- -1, /* external size */
- 'b', /* type-type (base type) */
- ',', /* array element delimiter */
- "array_in", /* input procedure */
- "array_out", /* output procedure */
- "array_out", /* send procedure */
- "array_in", /* recieve procedure */
- name, /* element type name */
- defaultValue, /* default type value */
- false); /* never passed by value */
- }
-