head 1.52; access; symbols Version_2_1:1.21 Version_2:1.16 C_Demo_1:1.5; locks; strict; comment @ * @; 1.52 date 92.08.19.19.37.41; author mer; state Exp; branches; next 1.51; 1.51 date 92.08.10.21.32.08; author mer; state Exp; branches; next 1.50; 1.50 date 92.07.21.08.03.19; author dpassage; state Exp; branches; next 1.49; 1.49 date 92.07.10.18.55.58; author mao; state Exp; branches; next 1.48; 1.48 date 92.07.06.18.34.26; author mao; state Exp; branches; next 1.47; 1.47 date 92.07.06.18.21.18; author mao; state Exp; branches; next 1.46; 1.46 date 92.07.06.15.47.43; author mao; state Exp; branches; next 1.45; 1.45 date 92.07.06.06.14.02; author mer; state Exp; branches; next 1.44; 1.44 date 92.07.06.05.01.34; author mao; state Exp; branches; next 1.43; 1.43 date 92.07.01.18.36.37; author joey; state Exp; branches; next 1.42; 1.42 date 92.06.28.03.46.38; author mao; state Exp; branches; next 1.41; 1.41 date 92.06.26.02.54.28; author joey; state Exp; branches; next 1.40; 1.40 date 92.06.11.23.37.07; author joey; state Exp; branches; next 1.39; 1.39 date 92.03.17.23.19.35; author joey; state Exp; branches; next 1.38; 1.38 date 92.01.13.02.20.36; author mao; state Exp; branches; next 1.37; 1.37 date 91.11.21.00.55.46; author mer; state Exp; branches; next 1.36; 1.36 date 91.11.20.13.13.18; author mer; state Exp; branches; next 1.35; 1.35 date 91.11.20.00.29.37; author mao; state Exp; branches; next 1.34; 1.34 date 91.11.19.18.18.35; author glass; state Exp; branches; next 1.33; 1.33 date 91.10.25.02.17.54; author joey; state Exp; branches; next 1.32; 1.32 date 91.09.08.16.22.03; author glass; state Exp; branches; next 1.31; 1.31 date 91.08.18.02.02.22; author caetta; state Exp; branches; next 1.30; 1.30 date 91.08.16.00.12.58; author kemnitz; state Exp; branches; next 1.29; 1.29 date 91.08.15.23.28.29; author kemnitz; state Exp; branches; next 1.28; 1.28 date 91.08.15.05.51.02; author glass; state Exp; branches; next 1.27; 1.27 date 91.05.07.23.46.50; author kemnitz; state Exp; branches; next 1.26; 1.26 date 91.04.19.05.34.11; author kemnitz; state Exp; branches; next 1.25; 1.25 date 91.03.29.05.31.52; author kemnitz; state Exp; branches; next 1.24; 1.24 date 91.03.26.13.07.14; author kemnitz; state Exp; branches; next 1.23; 1.23 date 91.03.20.01.57.55; author kemnitz; state Exp; branches; next 1.22; 1.22 date 91.03.20.01.52.05; author sp; state Exp; branches; next 1.21; 1.21 date 90.11.01.15.58.33; author goh; state Exp; branches; next 1.20; 1.20 date 90.10.25.21.03.14; author goh; state Exp; branches; next 1.19; 1.19 date 90.08.18.00.39.20; author cimarron; state Exp; branches; next 1.18; 1.18 date 90.08.13.20.46.57; author cimarron; state Exp; branches; next 1.17; 1.17 date 90.08.08.08.10.39; author cimarron; state Exp; branches; next 1.16; 1.16 date 90.07.13.19.58.29; author kemnitz; state Version_2; branches; next 1.15; 1.15 date 90.07.12.11.57.59; author goh; state Exp; branches; next 1.14; 1.14 date 90.07.09.12.56.24; author ong; state Exp; branches; next 1.13; 1.13 date 90.06.19.09.13.04; author cimarron; state Exp; branches; next 1.12; 1.12 date 90.06.13.15.29.30; author cimarron; state Exp; branches; next 1.11; 1.11 date 90.06.09.18.33.23; author kemnitz; state Exp; branches; next 1.10; 1.10 date 90.06.07.18.19.42; author cimarron; state Exp; branches; next 1.9; 1.9 date 89.11.02.18.06.26; author hirohama; state Exp; branches; next 1.8; 1.8 date 89.10.11.13.07.21; author hirohama; state Exp; branches; next 1.7; 1.7 date 89.09.06.14.10.18; author hirohama; state Exp; branches; next 1.5; 1.5 date 89.09.05.16.47.34; author mao; state C_Demo_1; branches; next 1.4; 1.4 date 89.08.22.20.36.38; author hirohama; state Exp; branches; next 1.3; 1.3 date 89.08.09.18.10.02; author cimarron; state Exp; branches; next 1.2; 1.2 date 89.02.02.16.55.17; author aoki; state Stab; branches; next 1.1; 1.1 date 89.01.17.05.52.54; author cimarron; state Exp; branches; next ; desc @@ 1.52 log @set up operator name correctly (it is a char16 not a char *) @ text @/* ---------------------------------------------------------------- * 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 /* XXX style */ #include #include #include "tmp/postgres.h" RcsId("$Header: /users/mer/pg/src/commands/RCS/define.c,v 1.51 1992/08/10 21:32:08 mer Exp mer $"); #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 */ } @ 1.51 log @init trusted to true (PQ funcs are trusted) @ text @d19 1 a19 1 RcsId("$Header: /users/mer/pg/src/commands/RCS/define.c,v 1.50 1992/07/21 08:03:19 dpassage Exp mer $"); d285 1 d297 2 d442 1 a442 1 OperatorDefine(name, /* operator name */ @ 1.50 log @handle "trusted" attribute when defining c functions @ text @d19 1 a19 1 RcsId("$Header: /private/dpassage/postgres/src/commands/RCS/define.c,v 1.49 1992/07/10 18:55:58 mao Exp dpassage $"); d81 1 a81 1 bool trusted; @ 1.49 log @elide dead code. that's why we use rcs, folks. @ text @d19 1 a19 1 RcsId("$Header: /private/mao/postgres/src/commands/RCS/define.c,v 1.48 1992/07/06 18:34:26 mao Exp mao $"); d81 2 d132 11 d252 1 @ 1.48 log @fix up constants used for cost estimation; joey said i guessed wrong. @ text @d19 1 a19 1 RcsId("$Header: /private/mao/postgres/src/commands/RCS/define.c,v 1.47 1992/07/06 18:21:18 mao Exp mao $"); a243 73 /* * Utility to handle definition of postquel procedures. * NO LONGER USED. -- JMH, 6/25/92 */ void DefinePFunction(pname,parameters, query_tree) char *pname; List parameters; List query_tree; { static char query_buf[1024]; static char tbuf[32]; extern void eval_as_new_xact(); List entry; List p = LispNil; List argList; char *relname; List reln; String returnTypeName; /* * First we have to add a column to the relation. */ /* XXX Fix this after catalogs fix to get relation type. */ entry = DefineListRemoveRequiredAssignment(¶meters, "returntype"); returnTypeName = DefineEntryGetString(entry); argList = LispRemoveMatchingSymbol(¶meters, ARG); argList = CDR(argList); AssertArg(length(argList) > 0); if (length(argList) >1) elog(WARN, "POSTQUEL functions with base type arguments aren't implemented yet"); reln = CAR(argList); if (!lispStringp(reln)) elog(WARN, "DefineFunction: arg type = ?"); relname = CString(reln); sprintf(query_buf, "addattr (%s = SET ) to %s", pname, relname); pg_eval(query_buf, (char *) NULL, (ObjectId *) NULL, 0); /* * Now we have to define the appropriate rule for the Postquel * function(procedure). */ CommandCounterIncrement(); strcpy(tbuf, pname); strcat(tbuf, "_rule"); p = nappend1(p, lispString(tbuf)); /* rulename */ p = nappend1(p, lispAtom("retrieve")); /* event_type */ p = nappend1(p, lispCons(lispString(relname), lispCons(lispString(pname), LispNil))); /* event_obj */ p = nappend1(p, LispNil); /* event_qual */ p = nappend1(p, lispInteger(true)); /* is instead */ p = nappend1(p, lispCons(query_tree,LispNil)); /* action list*/ DefineQueryRewrite(p); #ifdef notdef sprintf(query_buf, "define rewrite rule %s_rule is on retrieve to %s.%s do instead %s", pname, relname, pname, qstring); /* printf("Rule defined is: %s\n", query_buf); */ StartTransaction();*/ eval_as_new_xact(query_buf); #endif } @ 1.47 log @initialize cost estimate fields to -1 for postquel functions @ text @d19 1 a19 1 RcsId("$Header: /private/mao/postgres/src/commands/RCS/define.c,v 1.46 1992/07/06 15:47:43 mao Exp $"); d176 2 a177 1 byte_pct = perbyte_cpu = percall_cpu = outin_ratio = -1; @ 1.46 log @botched list management in the case that the returntype was not a setof xyzzy. @ text @d19 1 a19 1 RcsId("$Header: /private/mao/postgres/src/commands/RCS/define.c,v 1.45 1992/07/06 06:14:02 mer Exp $"); d172 1 d174 3 @ 1.45 log @initialize canCache for non 'c' functions @ text @d19 1 a19 1 RcsId("$Header: /users/mer/pg/src/commands/RCS/define.c,v 1.44 1992/07/06 05:01:34 mao Exp mer $"); d111 1 a111 1 if (IsA(CDR(entry),LispList)) { d115 1 a115 1 returnTypeName = DefineEntryGetString(entry); @ 1.44 log @support for 'returntype = setof typename' in function definition @ text @d19 1 a19 1 RcsId("$Header: /private/mao/postgres/src/commands/RCS/define.c,v 1.43 1992/07/01 18:36:37 joey Exp $"); d169 4 @ 1.43 log @disallow expensive function parameters for postquel functions @ text @d19 1 a19 1 RcsId("$Header: /private/joey/pg/src/commands/RCS/define.c,v 1.42 1992/06/28 03:46:38 mao Exp joey $"); d86 1 a87 1 d106 2 a107 1 * handle "returntype = X" d111 8 a118 2 returnTypeName = DefineEntryGetString(entry); d224 1 @ 1.42 log @rearrange parse, plan to support postquel function invocations @ text @d19 1 a19 1 RcsId("$Header: /home/postgres/mao/postgres/src/commands/RCS/define.c,v 1.41 1992/06/26 02:54:28 joey Exp mao $"); d112 1 a112 5 /* ---------------- * handle "[ iscachable ]": figure out if Postquel functions are * cacheable automagically? * ---------------- */ d115 6 a122 2 } d124 10 a133 13 /* ** 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)) d135 7 a141 3 for (count = 0, ptr = perbyte_str; *ptr != '\0'; ptr++) if (*ptr == '!') count++; perbyte_cpu = (int) pow(10.0, (double)count); a142 1 } d144 3 a146 6 entry = DefineListRemoveOptionalAssignment(¶meters, "percall_cpu"); if (null(entry)) percall_cpu = PERCALL_CPU; else { percall_str = DefineEntryGetString(entry); if (!sscanf(percall_str, "%d", &percall_cpu)) d148 7 a154 3 for (count = 0, ptr = percall_str; *ptr != '\0'; ptr++) if (*ptr == '!') count++; percall_cpu = (int) pow(10.0, (double)count); a155 1 } d158 3 a160 3 entry = DefineListRemoveOptionalAssignment(¶meters, "outin_ratio"); if (null(entry)) outin_ratio = OUTIN_RATIO; else outin_ratio = DefineEntryGetInteger(entry); d162 1 @ 1.41 log @define function now works similarly for postquel and c functions @ text @d19 1 a19 1 RcsId("$Header: /private/joey/pg/src/commands/RCS/define.c,v 1.40 1992/06/11 23:37:07 joey Exp joey $"); d37 2 d69 1 a69 1 DefineFunction(nameargsexe) d71 1 d100 1 a100 1 *c = (isupper(*c) ? tolower(*c) : *c); d223 2 a224 1 argList); d268 3 a270 2 /* printf( "Query is : %s\n", query_buf); */ pg_eval(query_buf); a298 39 /* NO LONGER USED. -- JMH, 6/25/92 */ void DefineRealPFunction(args) List args; { static Name lang = (Name) "postquel"; Name funcname = (Name) CString(nth(0, args)); List args_list = nth(1, args); Name return_type_name = (Name) CString(CAR(nth(2, args))); List parsetree = nth(3, args); List qd; List plan; List newargs = LispNil; List i; AssertArg(NameIsValid(funcname)); AssertArg(listp(args_list)); AssertArg(NameIsValid(return_type_name)); AssertArg(listp(parsetree)); foreach (i, args_list) { /* flatten def_list */ List t = CAR(CAR(i)); if (!lispStringp(t)) /* parser also does this....-- glass */ elog(WARN, "DefinePFunction: arg type = ?"); newargs = nappend1(newargs, t); } /* simple type checking should be done here at least for retrieves*/ init_planner(); plan = (List) planner(parsetree); qd = lispCons(parsetree, lispCons(plan, LispNil)); ProcedureDefine(funcname, return_type_name, lang, PlanToString(qd), /* query descriptor */ "-", true,newargs); } @ 1.40 log @Fix expensive function syntax to remove arch_pct and disk_pct, and handle the exclamation point syntax @ text @d19 1 a19 1 RcsId("$Header: /private/joey/stablepg/src/commands/RCS/define.c,v 1.40 1992/06/11 02:50:50 joey Exp $"); d73 1 a73 1 String languageName; d75 8 d84 1 d92 1 a92 5 /* ** Figure out language and call routine for that language. */ d95 1 a95 1 /* Uppercase-ise the language */ d97 1 a97 12 *c = (islower(*c) ? toupper(*c) : *c); if (!strcmp(languageName, "POSTQUEL")) { DefinePFunction((char *)name, parameters, CADR((nameargsexe))); } else if (!strcmp(languageName, "C")) { DefineCFunction(name, parameters, CString(CADR(nameargsexe)), languageName); } d99 2 a100 23 else elog(WARN, "DefineFunction: Specified language not supported"); } /* -------------------------------- ** DefineFunction ** -------------------------------- */ void DefineCFunction(name, parameters, fileName, languageName) Name name; LispValue parameters; String fileName; String languageName; { String returnTypeName; bool canCache; LispValue argList; LispValue entry; int32 byte_pct, perbyte_cpu, percall_cpu, outin_ratio; String perbyte_str, percall_str; int count; char *ptr; d103 1 a103 1 * handle "[ iscachable ]" d106 3 a108 3 entry = DefineListRemoveOptionalIndicator(¶meters, "iscachable"); canCache = (bool)!null(entry); d110 2 a111 1 * handle "returntype = X" d114 7 a120 3 entry = DefineListRemoveRequiredAssignment(¶meters, "returntype"); returnTypeName = DefineEntryGetString(entry); d122 1 a122 1 ** Handle new parameters for expensive functions. To be done by Joey. d131 9 a139 9 { 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); } } d144 9 a152 9 { 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); } } d159 1 d189 19 d215 1 a215 1 "-", d225 1 d295 1 @ 1.39 log @Modified DefineCFunction and ProcedureDefine to handle expensive function syntax @ text @d15 1 d19 1 a19 1 RcsId("$Header: /usr/private/joey/pg/src/commands/RCS/define.c,v 1.38 1992/01/13 02:20:36 mao Exp joey $"); d124 4 a127 1 int32 arch_pct, disk_pct, byte_pct, perbyte_cpu, percall_cpu, outin_ratio; a145 8 entry = DefineListRemoveOptionalAssignment(¶meters, "arch_pct"); if (null(entry)) arch_pct = ARCH_PCT; else arch_pct = DefineEntryGetInteger(entry); entry = DefineListRemoveOptionalAssignment(¶meters, "disk_pct"); if (null(entry)) disk_pct = DISK_PCT; else disk_pct = DefineEntryGetInteger(entry); d152 10 a161 1 else perbyte_cpu = DefineEntryGetInteger(entry); d165 11 a175 1 else percall_cpu = DefineEntryGetInteger(entry); d220 1 a220 1 arch_pct, disk_pct, byte_pct, perbyte_cpu, percall_cpu, @ 1.38 log @flatten include file graph @ text @d18 1 a18 1 RcsId("$Header: /n/hermes/usr5/postgres/mao/postgres/src/commands/RCS/define.c,v 1.37 1991/11/21 00:55:46 mer Exp mao $"); d34 1 d123 1 d142 24 a165 1 d205 2 @ 1.37 log @Make aggregate definition more general @ text @d18 1 a18 1 RcsId("$Header: /users/mer/postgres/src/commands/RCS/define.c,v 1.36 1991/11/20 13:13:18 mer Exp mer $"); d30 1 @ 1.36 log @ can't use toupper indiscriminately @ text @d18 1 a18 1 RcsId("$Header: RCS/define.c,v 1.35 91/11/20 00:29:37 mao Exp Locker: mer $"); d93 1 a93 1 DefinePFunction(name, parameters, CADR((nameargsexe))); d495 3 a498 5 Name stepfunc1Name; Name stepfunc2Name; Name finalfuncName; int32 InitPrimValue; int32 InitSecValue; d517 3 a519 1 /* handle InitStepCond = number */ d521 2 a522 1 InitPrimValue = DefineEntryGetInteger(entry); d524 3 a526 1 /* handle InitSecCond = number */ d528 2 a529 1 InitSecValue = DefineEntryGetInteger(entry); d537 2 a538 2 InitPrimValue, /* first initial condition */ InitSecValue); /* second initial condition */ @ 1.35 log @ifdef must have a macro name @ text @d18 1 a18 1 RcsId("$Header: RCS/define.c,v 1.34 91/11/19 18:18:35 glass Exp Locker: mao $"); d89 1 a89 1 *c = toupper(*c); @ 1.34 log @postquel function fix @ text @d18 1 a18 1 RcsId("$Header: RCS/define.c,v 1.33 91/10/25 02:17:54 joey Exp Locker: glass $"); d242 1 a242 1 #ifdef @ 1.33 log @modified function definition stuff @ text @d18 1 a18 1 RcsId("$Header: /users/joey/pg/src/commands/RCS/define.c,v 1.32 1991/09/08 16:22:03 glass Exp joey $"); d93 1 a93 3 /* to be done by Adam */ elog(WARN, "DefineFunction: can't handle POSTQUEL yet"); /* DefinePFunction(name, relationname, CDR(CDR(nameargsexe))); */ d187 4 a190 4 DefinePFunction(pname,relname,qstring) Name pname; Name relname; char *qstring; d193 1 d195 6 a200 1 d207 14 a223 1 d228 12 d241 2 d246 1 a246 1 /* CommitTransaction(); d249 1 @ 1.32 log @initial postquel function checkin @ text @d14 1 d18 1 a18 1 RcsId("$Header: RCS/define.c,v 1.31 91/08/18 02:02:22 caetta Exp Locker: glass $"); d64 2 a65 3 DefineFunction(name, parameters) Name name; LispValue parameters; d67 3 a69 1 String returnTypeName; d71 2 a72 5 String fileName; bool canCache; LispValue argList; LispValue entry; d79 1 a79 1 AssertArg(listp(parameters)); d81 43 a123 9 languageName = FetchDefault("language", "C"); /* ---------------- * handle "file = X" * ---------------- */ entry = DefineListRemoveRequiredAssignment(¶meters, "file"); fileName = filename_in(DefineEntryGetString(entry)); d130 1 a130 1 d137 5 a141 1 d148 1 a148 1 d151 1 a151 1 d157 1 a157 1 d164 1 a164 1 d170 1 a170 1 @ 1.31 log @definition of aggregates... @ text @d17 1 a17 1 RcsId("$Header: RCS/define.c,v 1.30 91/08/16 00:12:58 kemnitz Exp Locker: caetta $"); d141 1 d183 38 @ 1.30 log @hopefully fixed delimiter stuff @ text @d17 1 a17 1 RcsId("$Header: RCS/define.c,v 1.29 91/08/15 23:28:29 kemnitz Exp Locker: kemnitz $"); d40 1 d376 51 @ 1.29 log @added "delimiter". @ text @d17 1 a17 1 RcsId("$Header: RCS/define.c,v 1.28 91/08/15 05:51:02 glass Exp $"); d472 2 a473 1 delimiter = CAtom(CADR(entry)); @ 1.28 log @definepfunc() no longer does so in two transactions... @ text @d17 1 a17 1 RcsId("$Header: RCS/define.c,v 1.27 91/05/07 23:46:50 kemnitz Exp Locker: glass $"); d469 1 a469 1 entry = DefineListRemoveOptionalAssignment(¶meters, "send"); @ 1.27 log @define c function uses filenames. @ text @d17 1 a17 1 RcsId("$Header: RCS/define.c,v 1.26 91/04/19 05:34:11 kemnitz Exp Locker: kemnitz $"); d176 3 a178 3 CommitTransaction(); StartTransaction(); pg_eval (query_buf); @ 1.26 log @uses new scankey stuff @ text @d17 1 a17 1 RcsId("$Header: RCS/define.c,v 1.25 91/03/29 05:31:52 kemnitz Exp Locker: kemnitz $"); d88 1 a88 1 fileName = DefineEntryGetString(entry); @ 1.25 log @added define for defining shadow type. @ text @d17 1 a17 1 RcsId("$Header: RCS/define.c,v 1.24 91/03/26 13:07:14 kemnitz Exp Locker: kemnitz $"); d545 1 a545 1 (void) TypeDefine(name, /* type name */ @ 1.24 log @added delimiter for type. @ text @d17 1 a17 1 RcsId("$Header: RCS/define.c,v 1.23 91/03/20 01:57:55 kemnitz Exp Locker: kemnitz $"); d396 2 a397 1 char delimiter; d408 10 d537 21 @ 1.23 log @RELATION -> SET @ text @d17 1 a17 1 RcsId("$Header: RCS/define.c,v 1.22 91/03/20 01:52:05 sp Exp Locker: kemnitz $"); d396 1 d415 1 a415 1 d451 13 d518 1 @ 1.22 log @HACK HACK HACK!!!!!! we must use start/commit Xact, because if we just increment the cid the system cache is not really updated (or it seems so!) But doing that frees all palloced space!!!!! arghhhhhh! @ text @d17 1 a17 1 RcsId("$Header: RCS/define.c,v 1.21 90/11/01 15:58:33 goh Exp Locker: kemnitz $"); d164 1 a164 1 sprintf(query_buf, "addattr (%s = RELATION ) to %s", pname, relname); @ 1.21 log @changed define postquel function to use type "RELATION" for pseudo attribute that is added @ text @d17 1 a17 1 RcsId("$Header: RCS/define.c,v 1.20 90/10/25 21:03:14 goh Exp $"); d176 3 a178 1 eval_as_new_xact (query_buf); @ 1.20 log @changed "define postquel function" to call define rewrite rule instead of define rule @ text @d17 1 a17 1 RcsId("$Header: RCS/define.c,v 1.19 90/08/18 00:39:20 cimarron Exp Locker: goh $"); d164 1 a164 1 sprintf(query_buf, "addattr (%s = int4) to %s", pname, relname); @ 1.19 log @eliminated less significant .h files @ text @d17 1 a17 1 RcsId("$Header: RCS/define.c,v 1.18 90/08/13 20:46:57 cimarron Exp Locker: cimarron $"); d156 1 d173 1 a173 1 sprintf(query_buf, "define rule %s_rule is on retrieve to %s.%s do instead %s", pname, relname, pname, qstring); d176 1 a176 1 pg_eval(query_buf); @ 1.18 log @added pathnames to include statements @ text @d15 1 a15 1 #include "tmp/c.h" d17 1 a17 1 RcsId("$Header: RCS/define.c,v 1.17 90/08/08 08:10:39 cimarron Exp Locker: cimarron $"); a27 1 #include "tmp/name.h" @ 1.17 log @reorganized some header files @ text @d15 1 a15 1 #include "c.h" d17 1 a17 1 RcsId("$Header: RCS/define.c,v 1.16 90/07/13 19:58:29 kemnitz Version_2 Locker: cimarron $"); d19 6 a24 6 #include "catname.h" #include "fmgr.h" /* for fmgr */ #include "ftup.h" #include "heapam.h" #include "htup.h" #include "log.h" d26 5 a30 5 #include "name.h" #include "parse.h" /* for ARG */ #include "pg_lisp.h" #include "syscache.h" #include "tqual.h" d32 1 a32 1 #include "defrem.h" @ 1.16 log @Added element to Define Type @ text @d13 2 d17 1 a17 1 RcsId("$Header: RCS/define.c,v 1.15 90/07/12 11:57:59 goh Exp Locker: kemnitz $"); a18 4 #include /* XXX style */ #include "cat.h" #include "anum.h" a28 1 #include "rproc.h" @ 1.15 log @removes the old "language = C" parameter because only C functions are defined by define c function @ text @d15 1 a15 1 RcsId("$Header: RCS/define.c,v 1.14 90/07/09 12:56:24 ong Exp $"); d390 1 d461 12 d509 1 @ 1.14 log @added routine to handle postquel procedures. @ text @d15 1 a15 1 RcsId("$Header: RCS/define.c,v 1.13 90/06/19 09:13:04 cimarron Exp Locker: ong $"); d85 1 a85 10 /* ---------------- * handle "[ language = X ]" * ---------------- */ entry = DefineListRemoveOptionalAssignment(¶meters, "language"); if (null(entry)) { languageName = FetchDefault("language", "C"); } else { languageName = DefineEntryGetString(entry); } @ 1.13 log @reorginized code and added support for relation types @ text @d15 1 a15 1 RcsId("$Header: RCS/define.c,v 1.12 90/06/13 15:29:30 cimarron Exp Locker: cimarron $"); d157 34 @ 1.12 log @removed dependency on default.h @ text @d1 1 a1 1 /* d10 1 d15 1 a15 1 RcsId("$Header: RCS/define.c,v 1.11 90/06/09 18:33:23 kemnitz Exp Locker: cimarron $"); d18 1 a18 1 #include "cat.h" /* XXX obsolete file, needed for (struct proc), etc. */ d37 7 a43 8 ObjectId TypeGet(); static ObjectId OperatorGet(); static ObjectId TypeShellMake(); static ObjectId OperatorShellMake(); static int OperatorDef(); extern TypeDefine(); extern ProcedureDefine(); extern OperatorDefine(); d45 4 a48 2 /*#define USEPARGS /* XXX */ d56 3 a58 102 /* * TypeGet * * Finds the ObjectId of a type, even if uncommitted; "defined" * is only set if the type has actually been defined, i.e., if * the type tuple is not a shell. * * Also called from util/remove.c */ ObjectId TypeGet(typeName, defined) Name typeName; /* name of type to be fetched */ bool *defined; /* has the type been defined? */ { Relation relation; HeapScanDesc scan; HeapTuple tup; static ScanKeyEntryData typeKey[1] = { { 0, TypeNameAttributeNumber, NameEqualRegProcedure } }; Assert(NameIsValid(typeName)); Assert(PointerIsValid(defined)); typeKey[0].argument = NameGetDatum(typeName); relation = RelationNameOpenHeapRelation(TypeRelationName); scan = RelationBeginHeapScan(relation, 0, SelfTimeQual, 1, (ScanKey) typeKey); tup = HeapScanGetNextTuple(scan, 0, (Buffer *) 0); if (!HeapTupleIsValid(tup)) { HeapScanEnd(scan); RelationCloseHeapRelation(relation); *defined = false; return(InvalidObjectId); } HeapScanEnd(scan); RelationCloseHeapRelation(relation); *defined = (bool) ((TypeTupleForm) GETSTRUCT(tup))->typisdefined; return(tup->t_oid); } /* * OperatorGet */ static ObjectId OperatorGet(operatorName, leftTypeName, rightTypeName) Name operatorName; /* name of operator */ Name leftTypeName; /* lefthand type */ Name rightTypeName; /* righthand type */ { Relation relation; HeapScanDesc scan; HeapTuple tup; ObjectId leftObjectId = InvalidObjectId; ObjectId rightObjectId = InvalidObjectId; ObjectId operatorObjectId; bool leftDefined = false, rightDefined = false; static ScanKeyEntryData operatorKey[3] = { { 0, OperatorNameAttributeNumber, NameEqualRegProcedure }, { 0, OperatorLeftAttributeNumber, ObjectIdEqualRegProcedure }, { 0, OperatorRightAttributeNumber, ObjectIdEqualRegProcedure }, }; Assert(NameIsValid(operatorName)); Assert(NameIsValid(leftTypeName) || NameIsValid(rightTypeName)); /* Types must be defined before operators */ if (NameIsValid(leftTypeName)) { leftObjectId = TypeGet(leftTypeName, &leftDefined); if (!ObjectIdIsValid(leftObjectId) || !leftDefined) elog(WARN, "OperatorGet: left type %s nonexistent", leftTypeName); } if (NameIsValid(rightTypeName)) { rightObjectId = TypeGet(rightTypeName, &rightDefined); if (!ObjectIdIsValid(rightObjectId) || !rightDefined) elog(WARN, "OperatorGet: right type %s nonexistent", rightTypeName); } if (!((ObjectIdIsValid(leftObjectId) && leftDefined) || (ObjectIdIsValid(rightObjectId) && rightDefined))) elog(WARN, "OperatorGet: no argument types??"); operatorKey[0].argument = NameGetDatum(operatorName); operatorKey[1].argument = ObjectIdGetDatum(leftObjectId); operatorKey[2].argument = ObjectIdGetDatum(rightObjectId); relation = RelationNameOpenHeapRelation(OperatorRelationName); scan = RelationBeginHeapScan(relation, 0, SelfTimeQual, 3, (ScanKey) operatorKey); tup = HeapScanGetNextTuple(scan, 0, (Buffer *) 0); operatorObjectId = HeapTupleIsValid(tup) ? tup->t_oid : InvalidObjectId; HeapScanEnd(scan); RelationCloseHeapRelation(relation); return(operatorObjectId); } /* * TypeShellMake a59 9 static ObjectId TypeShellMake(typeName) Name typeName; { register i; Relation rdesc; HeapTuple tup; char *values[TypeRelationNumberOfAttributes]; char nulls[TypeRelationNumberOfAttributes]; d61 3 a63 40 Assert(PointerIsValid(typeName)); for (i = 0; i < TypeRelationNumberOfAttributes; ++i) { nulls[i] = ' '; values[i] = (char *) NULL; } i = 0; values[i++] = (char *) typeName; values[i++] = (char *) InvalidObjectId; values[i++] = (char *) (int16) 0; values[i++] = (char *) (int16) 0; values[i++] = (char *) (Boolean) 0; values[i++] = (char *) (Boolean) 0; values[i++] = (char *) (Boolean) 0; values[i++] = (char *) InvalidObjectId; values[i++] = (char *) InvalidObjectId; values[i++] = (char *) InvalidObjectId; values[i++] = (char *) InvalidObjectId; values[i++] = (char *) InvalidObjectId; values[i++] = (char *) InvalidObjectId; /* * ... and fill typdefault with a bogus value */ values[i++] = fmgr(TextInRegProcedure, (char *) typeName); rdesc = RelationNameOpenHeapRelation(TypeRelationName); tup = FormHeapTuple(TypeRelationNumberOfAttributes, &rdesc->rd_att, values, nulls); RelationInsertHeapTuple(rdesc, (HeapTuple) tup, (double *) NULL); RelationCloseHeapRelation(rdesc); return(tup->t_oid); } /* * OperatorShellMake * * Specify operator name and left and right type names, fill * an operator struct with this info and NULL's, call RelationInsertHeapTuple * and return the ObjectId to the calling process d65 4 a68 3 static ObjectId OperatorShellMake(operatorName, leftTypeName, rightTypeName) Name operatorName, leftTypeName, rightTypeName; d70 57 a126 29 register i; Relation rdesc; HeapTuple tup; char nulls[OperatorRelationNumberOfAttributes]; char *values[OperatorRelationNumberOfAttributes]; ObjectId leftObjectId = InvalidObjectId; ObjectId rightObjectId = InvalidObjectId; bool leftDefined = false, rightDefined = false; Assert(PointerIsValid(operatorName)); Assert(NameIsValid(leftTypeName) || NameIsValid(rightTypeName)); if (NameIsValid(leftTypeName)) leftObjectId = TypeGet(leftTypeName, &leftDefined); if (NameIsValid(rightTypeName)) rightObjectId = TypeGet(rightTypeName, &rightDefined); if (!((ObjectIdIsValid(leftObjectId) && leftDefined) || (ObjectIdIsValid(rightObjectId) && rightDefined))) elog(WARN, "OperatorShellMake: no valid argument types??"); for (i = 0; i < OperatorRelationNumberOfAttributes; ++i) { nulls[i] = ' '; values[i] = NULL; } i = 0; values[i++] = (char *) operatorName; values[i++] = (char *) InvalidObjectId; values[i++] = (char *) (uint16) 0; d128 1 a128 1 * ... and fill oprkind with a bogus value ... d130 2 a131 13 values[i++] = (char *)'b'; values[i++] = (char *) (Boolean) 0; values[i++] = (char *) (Boolean) 0; values[i++] = (char *) leftObjectId; values[i++] = (char *) rightObjectId; values[i++] = (char *) InvalidObjectId; values[i++] = (char *) InvalidObjectId; values[i++] = (char *) InvalidObjectId; values[i++] = (char *) InvalidObjectId; values[i++] = (char *) InvalidObjectId; values[i++] = (char *) InvalidObjectId; values[i++] = (char *) InvalidObjectId; values[i++] = (char *) InvalidObjectId; d133 6 a138 7 rdesc = RelationNameOpenHeapRelation(OperatorRelationName); tup = FormHeapTuple(OperatorRelationNumberOfAttributes, &rdesc->rd_att, values, nulls); RelationInsertHeapTuple(rdesc, (HeapTuple) tup, (double *) NULL); RelationCloseHeapRelation(rdesc); return(OperatorGet(operatorName, leftTypeName, rightTypeName)); } d140 5 d146 10 a155 100 /* * TypeDefine */ TypeDefine(typeName, internalSize, externalSize, inputProcedure, outputProcedure, sendProcedure, receiveProcedure, defaultTypeValue, passedByValue) Name typeName; int16 internalSize; int16 externalSize; Name inputProcedure; Name outputProcedure; Name sendProcedure; Name receiveProcedure; char *defaultTypeValue; /* internal rep */ Boolean passedByValue; { register i, j; Relation rdesc; HeapScanDesc sdesc; static ScanKeyEntryData typeKey[1] = { { 0, TypeNameAttributeNumber, NameEqualRegProcedure } }; HeapTuple tup; char nulls[TypeRelationNumberOfAttributes]; char replaces[TypeRelationNumberOfAttributes]; char *values[TypeRelationNumberOfAttributes]; ObjectId typeObjectId; Buffer buffer; char procname[sizeof(NameData)+1]; Name procs[4]; bool defined; ItemPointerData itemPointerData; Assert(NameIsValid(typeName)); Assert(NameIsValid(inputProcedure) && NameIsValid(outputProcedure)); typeObjectId = TypeGet(typeName, &defined); if (ObjectIdIsValid(typeObjectId) && defined) { elog(WARN, "TypeDefine: type %s already defined", typeName); } if (externalSize == 0) { externalSize = -1; /* variable length */ } for (i = 0; i < TypeRelationNumberOfAttributes; ++i) { nulls[i] = ' '; replaces[i] = 'r'; values[i] = (char *) NULL; } i = 0; values[i++] = (char *) typeName; values[i++] = (char *) getuid(); values[i++] = (char *) internalSize; values[i++] = (char *) externalSize; values[i++] = (char *) passedByValue; values[i++] = (char *) (Boolean) 0; values[i++] = (char *) (Boolean) 1; values[i++] = (char *) InvalidObjectId; values[i++] = (char *) InvalidObjectId; procname[sizeof(NameData)] = '\0'; /* XXX feh */ procs[0] = inputProcedure; procs[1] = outputProcedure; procs[2] = NameIsValid(receiveProcedure) ? receiveProcedure : inputProcedure; procs[3] = NameIsValid(sendProcedure) ? sendProcedure : outputProcedure; for (j = 0; j < 4; ++j) { (void) strncpy(procname, (char *) procs[j], sizeof(NameData)); tup = SearchSysCacheTuple(PRONAME, procname, (char *) NULL, (char *) NULL, (char *) NULL); if (!HeapTupleIsValid(tup)) elog(WARN, "TypeDefine: procedure %s nonexistent", procname); values[i++] = (char *) tup->t_oid; } values[i] = fmgr(TextInRegProcedure, PointerIsValid(defaultTypeValue) ? defaultTypeValue : "-"); /* XXX default typdefault */ rdesc = RelationNameOpenHeapRelation(TypeRelationName); typeKey[0].argument = NameGetDatum(typeName); sdesc = RelationBeginHeapScan(rdesc, 0, SelfTimeQual, 1, (ScanKey) typeKey); tup = HeapScanGetNextTuple(sdesc, 0, &buffer); if (HeapTupleIsValid(tup)) { tup = ModifyHeapTuple(tup, buffer, rdesc, values, nulls, replaces); /* XXX may not be necessary */ ItemPointerCopy(&tup->t_ctid, &itemPointerData); setheapoverride(true); RelationReplaceHeapTuple(rdesc, &itemPointerData, tup); setheapoverride(false); } else { tup = FormHeapTuple(TypeRelationNumberOfAttributes, &rdesc->rd_att, values, nulls); RelationInsertHeapTuple(rdesc, tup, (double *) NULL); } HeapScanEnd(sdesc); RelationCloseHeapRelation(rdesc); d158 2 a159 3 /* * OperatorDef d161 4 a164 73 * This routine gets complicated because it allows the user to * specify operators that do not exist. For example, if operator * "op" is being defined, the negator operator "negop" and the * commutator "commop" can also be defined without specifying * any information other than their names. Since in order to * add "op" to the PG_OPERATOR catalog, all the ObjectId's for these * operators must be placed in the fields of "op", a forward * declaration is done on the commutator and negator operators. * This is called creating a shell, and its main effect is to * create a tuple in the PG_OPERARTOR catalog with minimal * information about the operator (just its name and types). * Forward declaration is used only for this purpose, it is * not available to the user as it is for type definition. * * Algorithm: * * check if operator already defined * if so issue error if not definedOk, this is a duplicate * but if definedOk, save the ObjectId -- filling in a shell * get the attribute types from relation descriptor for pg_operator * assign values to the fields of the operator: * operatorName * owner id (simply the user id of the caller) * precedence * operator "kind" either "b" for binary or "l" for left unary * isLeftAssociative boolean * canHash boolean * leftType ObjectId -- type must already be defined * rightTypeObjectId -- this is optional, enter ObjectId=0 if none specified * resultType -- defer this, since it must be determined from * the pg_procedure catalog * commutatorObjectId -- if this is NULL, enter ObjectId=0 * else if this already exists, enter it's ObjectId * else if this does not yet exist, and is not * the same as the main operatorName, then create * a shell and enter the new ObjectId * else if this does not exist but IS the same * name as the main operator, set the ObjectId=0. * Later OperatorDefine will make another call * to OperatorDef which will cause this field * to be filled in (because even though the names * will be switched, they are the same name and * at this point this ObjectId will then be defined) * negatorObjectId -- same as for commutatorObjectId * leftSortObjectId -- same as for commutatorObjectId * rightSortObjectId -- same as for commutatorObjectId * operatorProcedure -- must access the pg_procedure catalog to get the * ObjectId of the procedure that actually does the operator * actions this is required. Do an amgetattr to find out the * return type of the procedure * restrictionProcedure -- must access the pg_procedure catalog to get * the ObjectId but this is optional * joinProcedure -- same as restrictionProcedure * now either insert or replace the operator into the pg_operator catalog * if the operator shell is being filled in * access the catalog in order to get a valid buffer * create a tuple using ModifyHeapTuple * get the t_ctid from the modified tuple and call RelationReplaceHeapTuple * else if a new operator is being created * create a tuple using FormHeapTuple * call RelationInsertHeapTuple * ***************************** NOTE NOTE NOTE *************************** * * Currently the system doesn't do anything with negators, commutators, etc. * Eventually it will be necessary to add a field to the operator catalog * indicating whether the operator is a negator and/or a commutator of a * real operator. Furthermore, depending on how the commutation is implemented, * it may be necessary to switch the order of the type fields given to * the commutator. Must be careful when doing this, because don't want * to also switch the order of the negator. Should be considered whether * it makes sense to have the same negator for both the operator and * its commutator. d166 28 d195 50 a244 84 static int /* return status */ OperatorDef(operatorName, definedOK, leftTypeName, rightTypeName, procedureName, precedence, isLeftAssociative, commutatorName, negatorName, restrictionName, joinName, canHash, leftSortName, rightSortName) /* "X" indicates an optional argument (i.e. one that can be NULL) */ Name operatorName; /* operator name */ int definedOK; /* operator can already have a ObjectId? */ Name leftTypeName; /* X left type name */ Name rightTypeName; /* X right type name */ Name procedureName; /* procedure ObjectId for operator code */ uint16 precedence; /* operator precedence */ Boolean isLeftAssociative; /* operator is left associative? */ Name commutatorName; /* X commutator operator name */ Name negatorName; /* X negator operator name */ Name restrictionName; /* X restriction sel. procedure name */ Name joinName; /* X join sel. procedure name */ Boolean canHash; /* possible hash operator? */ Name leftSortName; /* X left sort operator */ Name rightSortName; /* X right sort operator */ { register i, j; Relation rdesc; static ScanKeyEntryData operatorKey[3] = { { 0, OperatorNameAttributeNumber, NameEqualRegProcedure }, { 0, OperatorLeftAttributeNumber, ObjectIdEqualRegProcedure }, { 0, OperatorRightAttributeNumber, ObjectIdEqualRegProcedure }, }; HeapScanDesc sdesc; HeapTuple tup; Buffer buffer; ItemPointerData itemPointerData; char nulls[OperatorRelationNumberOfAttributes]; char replaces[OperatorRelationNumberOfAttributes]; char *values[OperatorRelationNumberOfAttributes]; ObjectId oid, operatorObjectId; ObjectId leftTypeId = InvalidObjectId; ObjectId rightTypeId = InvalidObjectId; bool leftDefined = false, rightDefined = false; Name name[4]; Assert(NameIsValid(operatorName)); Assert(PointerIsValid(leftTypeName) || PointerIsValid(rightTypeName)); Assert(NameIsValid(procedureName)); operatorObjectId = OperatorGet(operatorName, leftTypeName, rightTypeName); if (ObjectIdIsValid(operatorObjectId) && !definedOK) elog(WARN, "OperatorDef: operator %s already defined", operatorName); if (NameIsValid(leftTypeName)) leftTypeId = TypeGet(leftTypeName, &leftDefined); if (NameIsValid(rightTypeName)) rightTypeId = TypeGet(rightTypeName, &rightDefined); if (!((ObjectIdIsValid(leftTypeId && leftDefined)) || (ObjectIdIsValid(rightTypeId && rightDefined)))) elog(WARN, "OperatorGet: no argument types??"); for (i = 0; i < OperatorRelationNumberOfAttributes; ++i) { values[i] = (char *) NULL; replaces[i] = 'r'; nulls[i] = ' '; } /* * Look up registered procedures -- find the return type * of procedureName to place in "result" field. * Do this before shells are created so we don't * have to worry about deleting them later. */ tup = SearchSysCacheTuple(PRONAME, (char *) procedureName, (char *) NULL, (char *) NULL, (char *) NULL); if (!PointerIsValid(tup)) elog(WARN, "OperatorDef: operator procedure %s nonexistent", procedureName); values[OperatorProcedureAttributeNumber-1] = (char *) tup->t_oid; values[OperatorResultAttributeNumber-1] = (char *) ((struct proc *) GETSTRUCT(tup))->prorettype; d246 7 a252 99 if (NameIsValid(restrictionName)) { /* optional */ tup = SearchSysCacheTuple(PRONAME, (char *) restrictionName, (char *) NULL, (char *) NULL, (char *) NULL); if (!HeapTupleIsValid(tup)) elog(WARN, "OperatorDef: restriction proc %s nonexistent", restrictionName); values[OperatorRestrictAttributeNumber-1] = (char *) tup->t_oid; } else values[OperatorRestrictAttributeNumber-1] = (char *) InvalidObjectId; if (NameIsValid(joinName)) { /* optional */ tup = SearchSysCacheTuple(PRONAME, (char *) joinName, (char *) NULL, (char *) NULL, (char *) NULL); if (!HeapTupleIsValid(tup)) elog(WARN, "OperatorDef: join proc %s nonexistent", joinName); values[OperatorJoinAttributeNumber-1] = (char *) tup->t_oid; } else values[OperatorJoinAttributeNumber-1] = (char *) InvalidObjectId; i = 0; values[i++] = (char *) operatorName; values[i++] = (char *) (ObjectId) getuid(); values[i++] = (char *) precedence; values[i++] = (char *) (NameIsValid(leftTypeName) ? (NameIsValid(rightTypeName) ? 'b' : 'l') : 'r'); values[i++] = (char *) isLeftAssociative; values[i++] = (char *) canHash; values[i++] = (char *) leftTypeId; values[i++] = (char *) rightTypeId; ++i; /* Skip "prorettype", this was done above */ /* * Set up the other operators. If they do not currently exist, * set up shells in order to get ObjectId's and call OperatorDef * again later to fill in the shells. */ name[0] = commutatorName; name[1] = negatorName; name[2] = leftSortName; name[3] = rightSortName; for (j = 0; j < 4; ++j) { if (NameIsValid(name[j])) { oid = OperatorGet(name[j], leftTypeName, rightTypeName); if (ObjectIdIsValid(oid)) /* already in catalogs */ values[i++] = (char *) oid; else if (!NameIsEqual(operatorName, name[j])) { /* not in catalogs, different from operator */ /* NOTE -- eventually should switch order */ /* for commutator's types */ oid = OperatorShellMake(name[j], leftTypeName, rightTypeName); if (!ObjectIdIsValid(oid)) elog(WARN, "OperatorDef: can't create %s", name[j]); values[i++] = (char *) oid; } else /* not in catalogs, same as operator ??? */ values[i++] = (char *) InvalidObjectId; } else /* new operator is optional */ values[i++] = (char *) InvalidObjectId; } /* last three fields were filled in first */ /* * If we are adding to an operator shell, get its t_ctid and a * buffer. */ rdesc = RelationNameOpenHeapRelation(OperatorRelationName); if (operatorObjectId) { operatorKey[0].argument = NameGetDatum(operatorName); operatorKey[1].argument = ObjectIdGetDatum(leftTypeId); operatorKey[2].argument = ObjectIdGetDatum(rightTypeId); sdesc = RelationBeginHeapScan(rdesc, 0, SelfTimeQual, 3, (ScanKey) operatorKey); tup = HeapScanGetNextTuple(sdesc, 0, &buffer); if (HeapTupleIsValid(tup)) { tup = ModifyHeapTuple(tup, buffer, rdesc, values, nulls, replaces); ItemPointerCopy(&tup->t_ctid, &itemPointerData); setheapoverride(true); RelationReplaceHeapTuple(rdesc, &itemPointerData, tup); setheapoverride(false); } else elog(WARN, "OperatorDef: no operator %d", oid); HeapScanEnd(sdesc); d254 1 a254 3 tup = FormHeapTuple(OperatorRelationNumberOfAttributes, &rdesc->rd_att, values, nulls); RelationInsertHeapTuple(rdesc, tup, (double *) NULL); d256 71 a326 2 RelationCloseHeapRelation(rdesc); } d328 5 d334 17 a350 117 /* * OperatorDefine * * Algorithm: * * Since the commutator, negator, leftsortoperator, and rightsortoperator * can be defined implicitly through OperatorDefine, must check before * the main operator is added to see if they already exist. If they * do not already exist, OperatorDef makes a "shell" for each undefined * one, and then OperatorDefine must call OperatorDef again to fill in * each shell. All this is necessary in order to get the right ObjectId's * filled into the right fields. * * The "definedOk" flag indicates that OperatorDef can be called on * the operator even though it already has an entry in the PG_OPERATOR * relation. This allows shells to be filled in. The user cannot * forward declare operators, this is strictly an internal capability. * * When the shells are filled in by subsequent calls to OperatorDef, * all the fields are the same as the definition of the original operator * except that the target operator name and the original operatorName * are switched. In the case of commutator and negator, special flags * are set to indicate their status, telling the executor(?) that * the operands are to be switched, or the outcome of the procedure * negated. * * ************************* NOTE NOTE NOTE ****************************** * * If the execution of this utility is interrupted, the pg_operator * catalog may be left in an inconsistent state. Similarly, if * something is removed from the pg_operator, pg_type, or pg_procedure * catalog while this is executing, the results may be inconsistent. * */ OperatorDefine(operatorName, leftTypeName, rightTypeName, procedureName, precedence, isLeftAssociative, commutatorName, negatorName, restrictionName, joinName, canHash, leftSortName, rightSortName) /* "X" indicates an optional argument (i.e. one that can be NULL) */ Name operatorName; /* operator name */ Name leftTypeName; /* X left type name */ Name rightTypeName; /* X right type name */ Name procedureName; /* procedure for operator */ uint16 precedence; /* operator precedence */ Boolean isLeftAssociative; /* operator is left associative */ Name commutatorName; /* X commutator operator name */ Name negatorName; /* X negator operator name */ Name restrictionName; /* X restriction sel. procedure */ Name joinName; /* X join sel. procedure name */ Boolean canHash; /* operator hashes */ Name leftSortName; /* X left sort operator */ Name rightSortName; /* X right sort operator */ { ObjectId commObjectId, negObjectId; ObjectId leftSortObjectId, rightSortObjectId; /* ObjectId newOpObjectId;*/ int definedOK; Assert(NameIsValid(operatorName)); Assert(PointerIsValid(leftTypeName) || PointerIsValid(rightTypeName)); Assert(NameIsValid(procedureName)); if (NameIsValid(commutatorName)) commObjectId = OperatorGet(commutatorName, /* commute type order*/ rightTypeName, leftTypeName); if (NameIsValid(negatorName)) negObjectId = OperatorGet(negatorName, leftTypeName, rightTypeName); if (NameIsValid(leftSortName)) leftSortObjectId = OperatorGet(leftSortName, leftTypeName, rightTypeName); if (NameIsValid(rightSortName)) rightSortObjectId = OperatorGet(rightSortName, rightTypeName, leftTypeName); /* This operator should not be defined yet. */ definedOK = 0; OperatorDef(operatorName, definedOK, leftTypeName, rightTypeName, procedureName, precedence, isLeftAssociative, commutatorName, negatorName, restrictionName, joinName, canHash, leftSortName, rightSortName); /* newOpObjectId = OperatorGet(operatorName, leftTypeName, rightTypeName);*/ /* These operators should be defined or have shells defined. */ definedOK = 1; if (!ObjectIdIsValid(commObjectId) && NameIsValid(commutatorName)) OperatorDef(commutatorName, definedOK, leftTypeName, rightTypeName, /* should eventually */ /* commute order */ procedureName, precedence, isLeftAssociative, operatorName, /* commutator */ negatorName, restrictionName, joinName, canHash, rightSortName, leftSortName); if (!ObjectIdIsValid(negObjectId) && NameIsValid(negatorName)) OperatorDef(negatorName, definedOK, leftTypeName, rightTypeName, procedureName, precedence, isLeftAssociative, commutatorName, operatorName, /* negator */ restrictionName, joinName, canHash, leftSortName, rightSortName); if (!ObjectIdIsValid(leftSortObjectId) && NameIsValid(leftSortName)) OperatorDef(leftSortName, definedOK, leftTypeName, rightTypeName, procedureName, precedence, isLeftAssociative, commutatorName, negatorName, restrictionName, joinName, canHash, operatorName, /* left sort */ rightSortName); if (!ObjectIdIsValid(rightSortObjectId) && NameIsValid(rightSortName)) OperatorDef(rightSortName, definedOK, leftTypeName, rightTypeName, procedureName, precedence, isLeftAssociative, commutatorName, negatorName, restrictionName, joinName, canHash, leftSortName, operatorName); /* right sort */ d353 3 a355 3 /* * ProcedureDefine a356 108 /*ARGSUSED*/ ProcedureDefine(procedureName, returnTypeName, languageName, fileName, canCache, argList) Name procedureName; Name returnTypeName; Name languageName; char *fileName; /* XXX path to binary */ Boolean canCache; List argList; { register i; Relation rdesc; HeapTuple tup; char nulls[ProcedureRelationNumberOfAttributes]; char *values[ProcedureRelationNumberOfAttributes]; ObjectId languageObjectId, typeObjectId; #ifdef USEPARGS ObjectId procedureObjectId; #endif bool defined; uint16 parameterCount; Assert(NameIsValid(procedureName)); Assert(NameIsValid(returnTypeName)); Assert(NameIsValid(languageName)); Assert(PointerIsValid(fileName)); parameterCount = length(argList); tup = SearchSysCacheTuple(PRONAME, (char *) procedureName, (char *) NULL, (char *) NULL, (char *) NULL); if (HeapTupleIsValid(tup)) elog(WARN, "ProcedureDefine: procedure %s already exists", procedureName); tup = SearchSysCacheTuple(LANNAME, (char *) languageName, (char *) NULL, (char *) NULL, (char *) NULL); if (!HeapTupleIsValid(tup)) elog(WARN, "ProcedureDefine: no such language %s", languageName); languageObjectId = tup->t_oid; typeObjectId = TypeGet(returnTypeName, &defined); if (!ObjectIdIsValid(typeObjectId)) { elog(NOTICE, "ProcedureDefine: return type %s not yet defined", returnTypeName); typeObjectId = TypeShellMake(returnTypeName); if (!ObjectIdIsValid(typeObjectId)) elog(WARN, "ProcedureDefine: could not create type %s", returnTypeName); } for (i = 0; i < ProcedureRelationNumberOfAttributes; ++i) { nulls[i] = ' '; values[i] = (char *) NULL; } i = 0; values[i++] = (char *) procedureName; values[i++] = (char *) (ObjectId) getuid(); values[i++] = (char *) languageObjectId; /* XXX isinherited is always false for now */ values[i++] = (char *) (Boolean) 0; /* XXX istrusted is always false for now */ values[i++] = (char *) (Boolean) 0; values[i++] = (char *) canCache; values[i++] = (char *) parameterCount; values[i++] = (char *) typeObjectId; { /* XXX Fix this when prosrc is used */ values[i++] = fmgr(TextInRegProcedure, "-"); /* prosrc */ values[i++] = fmgr(TextInRegProcedure, fileName); /* probin */ } rdesc = RelationNameOpenHeapRelation(ProcedureRelationName); tup = FormHeapTuple(ProcedureRelationNumberOfAttributes, &rdesc->rd_att, values, nulls); RelationInsertHeapTuple(rdesc, (HeapTuple) tup, (double *) NULL); #ifdef USEPARGS procedureObjectId = tup->t_oid; #endif RelationCloseHeapRelation(rdesc); /* XXX Test to see if tuple inserted ?? */ /* XXX don't fill in PARG for now (not used for anything) */ #ifdef USEPARGS rdesc = RelationNameOpenHeapRelation(ProcedureArgumentRelationName); for (i = 0; i < parameterCount; ++i) { HeapTuple typeTuple; typeTuple = SearchSysCacheTuple(TYPNAME, CString(CAR(argList))); if (!HeapTupleIsValid(typeTuple)) { elog(WARN, "DEFINE FUNCTION: arg type \"%s\" unknown", CString(CAR(argList))); } j = 0; values[j++] = (char *) procedureObjectId; values[j++] = (char *)(1 + i); /* XXX ignore array bound for now */ values[j++] = (char *) '\0'; values[j++] = (char *)typeTuple->t_oid; tup = FormHeapTuple(ProcedureArgumentRelationNumberOfAttributes, &rdesc->rd_att, values, nulls); RelationInsertHeapTuple(rdesc, (HeapTuple) tup, (double *) NULL); } RelationCloseHeapRelation(rdesc); #endif /* USEPARGS */ } a357 74 DefineFunction(name, parameters) Name name; LispValue parameters; { String returnTypeName; String languageName; String fileName; bool canCache; LispValue argList; LispValue entry; /* * Note: * XXX Checking of "name" validity (16 characters?) is needed. */ AssertArg(NameIsValid(name)); AssertArg(listp(parameters)); /* * handle "[ language = X ]" */ entry = DefineListRemoveOptionalAssignment(¶meters, "language"); if (null(entry)) { languageName = FetchDefault("language", "C"); } else { languageName = DefineEntryGetString(entry); } /* * handle "file = X" */ entry = DefineListRemoveRequiredAssignment(¶meters, "file"); fileName = DefineEntryGetString(entry); /* * handle "[ iscachable ]" */ entry = DefineListRemoveOptionalIndicator(¶meters, "iscachable"); canCache = (bool)!null(entry); /* * handle "returntype = X" */ entry = DefineListRemoveRequiredAssignment(¶meters, "returntype"); returnTypeName = DefineEntryGetString(entry); /* * 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 = ?"); } } } DefineListAssertEmpty(parameters); ProcedureDefine(name, returnTypeName, languageName, fileName, canCache, argList); } void d359 2 a360 2 Name name; LispValue parameters; d362 95 a456 9 LispValue entry; int16 internalLength; /* int2 */ int16 externalLength; /* int2 */ Name inputName; Name outputName; Name sendName; Name receiveName; char* defaultValue; /* Datum */ bool byValue; /* Boolean */ d458 15 a472 230 /* * Note: * XXX Checking of "name" validity (16 characters?) is needed. */ AssertArg(NameIsValid(name)); AssertArg(listp(parameters)); /* * 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 "[ receive = procedure ]" */ entry = DefineListRemoveOptionalAssignment(¶meters, "receive"); receiveName = NULL; if (!null(entry)) { receiveName = 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); DefineListAssertEmpty(parameters); TypeDefine(name, internalLength, externalLength, inputName, outputName, sendName, receiveName, defaultValue, byValue); } 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 */ /* * Note: * XXX Checking of "name" validity (16 characters?) is needed. */ AssertArg(NameIsValid(name)); AssertArg(listp(parameters)); /* * XXX ( ... arg1 = typname [ , arg2 = typname ] ... ) * XXX is undocumented in the reference manual source as of 89/8/22. */ /* * handle "arg1 = typname" */ 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); /* * XXX ( ... [ , sort1 = oprname ] [ , sort2 = oprname ] ... ) * XXX is undocumented in the reference manual source as of 89/8/22. */ /* * handle "[ sort1 = oprname ]" */ 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); } DefineListAssertEmpty(parameters); OperatorDefine(name, typeName1, typeName2, functionName, precedence, isLeftAssociative, commutatorName, negatorName, restrictionName, joinName, canHash, sortName1, sortName2); @ 1.11 log @Got rid of datum indirections - replaced with accessor macros. @ text @d14 1 a14 1 RcsId("$Header: RCS/define.c,v 1.9 89/11/02 18:06:26 hirohama Exp $"); a20 1 #include "default.h" /* for FetchDefault */ d46 7 @ 1.10 log @made changes to simplify header include files @ text @d17 1 a17 1 #include "cat.h" d72 1 a72 1 typeKey[0].argument.name.value = typeName; d132 3 a134 3 operatorKey[0].argument.name.value = operatorName; operatorKey[1].argument.objectId.value = leftObjectId; operatorKey[2].argument.objectId.value = rightObjectId; d342 1 a342 1 typeKey[0].argument.name.value = typeName; d609 3 a611 3 operatorKey[0].argument.name.value = operatorName; operatorKey[1].argument.objectId.value = leftTypeId; operatorKey[2].argument.objectId.value = rightTypeId; @ 1.9 log @fixed "associativity" @ text @d14 1 a14 1 RcsId("$Header: RCS/define.c,v 1.8 89/10/11 13:07:21 hirohama Exp Locker: hirohama $"); d17 1 a17 1 #include "catalog.h" /* XXX obsolete file, needed for (struct proc), etc. */ @ 1.8 log @bug fix DEFINE FUNCTION will now define functions with arguments which can be dynamically loaded and called with proper arguments @ text @d14 1 a14 1 RcsId("$Header: RCS/define.c,v 1.7 89/09/06 14:10:18 hirohama Exp Locker: hirohama $"); d1098 1 a1098 1 entry = DefineListRemoveOptionalAssignment(¶meters, "precedence"); @ 1.7 log @bug fix for DEFINE FUNCTION @ text @d14 1 a14 1 RcsId("$Header: RCS/define.c,v 1.6 89/09/05 23:25:01 hirohama Exp Locker: hirohama $"); d760 1 a760 1 canCache, parameterCount, parameters) d766 1 a766 2 uint16 parameterCount; struct attribute *parameters[]; /* XXX for use with PARGS */ d778 1 d784 2 d843 8 d853 1 a853 1 values[j++] = (char *) parameters[i]->attnum; d856 1 a856 1 values[j++] = (char *) parameters[i]->atttypid; a874 2 Count argCount; TupleDesc arg; d918 4 a921 4 if (null(argList)) { argCount = 0; arg = NULL; } else { d926 1 a926 5 argCount = length(argList); arg = NULL; if (argCount != 0) { int index; LispValue rest; d928 3 a930 5 arg = CreateTemplateTupleDesc(argCount); for (rest = argList; !null(rest); rest = CDR(rest)) { if (!lispStringp(CAR(rest))) { elog(WARN, "DefineFunction: returntype = ?"); } a932 5 /* * XXX for now, arg is not passed on. */ argCount = 0; arg = NULL; a933 1 d937 1 a937 1 canCache, argCount, arg); @ 1.5 log @Working version of C-only demo @ text @d14 1 a14 1 RcsId("$Header: RCS/define.c,v 1.4 89/08/22 20:36:38 hirohama Exp $"); d914 4 d926 1 a926 1 if (!lispStringp(CAR(CAR(rest)))) { @ 1.4 log @lispified version @ text @d14 1 a14 1 RcsId("$Header: RCS/define.c,v 1.3 89/08/09 18:10:02 cimarron Exp Locker: hirohama $"); @ 1.3 log @"retrieve(x=1)" @ text @d3 1 a3 1 * define {procedure, operator, type} system commands d12 7 a18 2 #include #include "access.h" d21 2 a22 1 #include "fmgr.h" d25 1 d27 5 d35 1 a35 1 RcsId("$Header: /usr6/postgres/cimarron/postgres3/src/commands/RCS/define.c,v 1.2 89/02/02 16:55:17 aoki Stab $"); d66 1 a66 1 { 0, TypeNameAttributeNumber, F_CHAR16EQ } d107 3 a109 3 { 0, OperatorNameAttributeNumber, F_CHAR16EQ }, { 0, OperatorLeftAttributeNumber, F_OIDEQ }, { 0, OperatorRightAttributeNumber, F_OIDEQ } d181 4 a184 1 values[i++] = fmgr(F_TEXTIN, (char *) typeName); d235 4 a238 1 values[i++] = fmgr(F_CHARIN, "b"); d281 1 a281 1 { 0, TypeNameAttributeNumber, F_CHAR16EQ } d298 1 a298 1 if (ObjectIdIsValid(typeObjectId) && defined) d300 2 a301 6 if (internalSize < 0) elog(WARN, "TypeDefine: invalid internal length: %d", internalSize); if (internalSize == 0) internalSize = -1; /* variable length */ if (externalSize == 0) d303 1 d336 1 a336 1 values[i] = fmgr(F_TEXTIN, d470 3 a472 3 { 0, OperatorNameAttributeNumber, F_CHAR16EQ }, { 0, OperatorLeftAttributeNumber, F_OIDEQ }, { 0, OperatorRightAttributeNumber, F_OIDEQ } d559 2 a560 3 values[i++] = fmgr(F_CHARIN, NameIsValid(leftTypeName) ? (NameIsValid(rightTypeName) ? "b" : "l") : "r"); d798 1 a798 1 elog(DEBUG, "ProcedureDefine: return type %s not defined", d823 2 a824 2 values[i++] = fmgr(F_TEXTIN, "-"); /* prosrc */ values[i++] = fmgr(F_TEXTIN, fileName); /* probin */ d854 331 @ 1.2 log @MERGE WITH OLD TREE @ text @d23 1 a23 1 RcsId("$Header: define.c,v 1.9 89/01/24 20:26:36 aoki Locked $"); d51 1 a51 1 HeapScan scan; d88 1 a88 1 HeapScan scan; d261 1 a261 1 HeapScan sdesc; d459 1 a459 1 HeapScan sdesc; @ 1.1 log @Initial revision @ text @a0 1 a1 26 * * POSTGRES Data Base Management System * * Copyright (c) 1988 Regents of the University of California * * Permission to use, copy, modify, and distribute this software and its * documentation for educational, research, and non-profit purposes and * without fee is hereby granted, provided that the above copyright * notice appear in all copies and that both that copyright notice and * this permission notice appear in supporting documentation, and that * the name of the University of California not be used in advertising * or publicity pertaining to distribution of the software without * specific, written prior permission. Permission to incorporate this * software into commercial products can be obtained from the Campus * Software Office, 295 Evans Hall, University of California, Berkeley, * Ca., 94720 provided only that the the requestor give the University * of California a free licence to any derived software for educational * and research purposes. The University of California makes no * representations about the suitability of this software for any * purpose. It is provided "as is" without express or implied warranty. * */ /* d23 1 a23 1 RcsId("$Header: define.c,v 1.1 88/11/11 16:42:12 postgres Exp $"); d73 1 a73 1 *defined = (bool) ((struct type *) GETSTRUCT(tup))->typisdefined; @