diff options
Diffstat (limited to 'src/backend/commands/define.c')
-rw-r--r-- | src/backend/commands/define.c | 488 |
1 files changed, 312 insertions, 176 deletions
diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c index 92f8541fd6..9f47041e2e 100644 --- a/src/backend/commands/define.c +++ b/src/backend/commands/define.c @@ -41,6 +41,7 @@ #include "access/heapam.h" #include "catalog/catname.h" #include "catalog/heap.h" +#include "catalog/namespace.h" #include "catalog/pg_aggregate.h" #include "catalog/pg_language.h" #include "catalog/pg_operator.h" @@ -50,13 +51,19 @@ #include "fmgr.h" #include "miscadmin.h" #include "optimizer/cost.h" -#include "parser/parse_expr.h" +#include "parser/parse_func.h" +#include "parser/parse_type.h" #include "utils/acl.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" +#include "utils/lsyscache.h" #include "utils/syscache.h" + +static Oid findTypeIOFunction(const char *procname, bool isOutput); static char *defGetString(DefElem *def); static double defGetNumeric(DefElem *def); +static TypeName *defGetTypeName(DefElem *def); static int defGetTypeLength(DefElem *def); #define DEFAULT_TYPDELIM ',' @@ -77,16 +84,59 @@ case_translate_language_name(const char *input, char *output) } - -static void -compute_return_type(TypeName *returnType, - char **prorettype_p, bool *returnsSet_p) -{ /* * Examine the "returns" clause returnType of the CREATE FUNCTION statement * and return information about it as *prorettype_p and *returnsSet. + * + * This is more complex than the average typename lookup because we want to + * allow a shell type to be used, or even created if the specified return type + * doesn't exist yet. (Without this, there's no way to define the I/O procs + * for a new type.) But SQL function creation won't cope, so error out if + * the target language is SQL. */ - *prorettype_p = TypeNameToInternalName(returnType); +static void +compute_return_type(TypeName *returnType, Oid languageOid, + Oid *prorettype_p, bool *returnsSet_p) +{ + Oid rettype; + + rettype = LookupTypeName(returnType); + + if (OidIsValid(rettype)) + { + if (!get_typisdefined(rettype)) + { + if (languageOid == SQLlanguageId) + elog(ERROR, "SQL functions cannot return shell types"); + else + elog(WARNING, "Return type \"%s\" is only a shell", + TypeNameToString(returnType)); + } + } + else + { + char *typnam = TypeNameToString(returnType); + + if (strcmp(typnam, "opaque") == 0) + rettype = InvalidOid; + else + { + Oid namespaceId; + char *typname; + + if (languageOid == SQLlanguageId) + elog(ERROR, "Type \"%s\" does not exist", typnam); + elog(WARNING, "ProcedureCreate: type %s is not yet defined", + typnam); + namespaceId = QualifiedNameGetCreationNamespace(returnType->names, + &typname); + rettype = TypeShellMake(typname, namespaceId); + if (!OidIsValid(rettype)) + elog(ERROR, "could not create type %s", typnam); + } + } + + *prorettype_p = rettype; *returnsSet_p = returnType->setof; } @@ -211,34 +261,31 @@ interpret_AS_clause(Oid languageOid, const char *languageName, const List *as, void CreateFunction(ProcedureStmt *stmt) { - /* pathname of executable file that executes this function, if any */ char *probin_str; - /* SQL that executes this function, if any */ char *prosrc_str; - /* Type of return value (or member of set of values) from function */ - char *prorettype; - /* name of language of function, with case adjusted */ - char languageName[NAMEDATALEN]; - /* The function returns a set of values, as opposed to a singleton. */ + Oid prorettype; bool returnsSet; - /* - * The following are optional user-supplied attributes of the - * function. - */ + char languageName[NAMEDATALEN]; + Oid languageOid; + char *funcname; + Oid namespaceId; int32 byte_pct, perbyte_cpu, percall_cpu, outin_ratio; bool canCache, isStrict; - HeapTuple languageTuple; Form_pg_language languageStruct; - Oid languageOid; + + /* Convert list of names to a name and namespace */ + namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname, + &funcname); /* Convert language name to canonical case */ case_translate_language_name(stmt->language, languageName); + /* Look up the language and validate permissions */ languageTuple = SearchSysCache(LANGNAME, PointerGetDatum(languageName), 0, 0, 0); @@ -259,21 +306,22 @@ CreateFunction(ProcedureStmt *stmt) * Convert remaining parameters of CREATE to form wanted by * ProcedureCreate. */ - Assert(IsA(stmt->returnType, TypeName)); - compute_return_type((TypeName *) stmt->returnType, + compute_return_type(stmt->returnType, languageOid, &prorettype, &returnsSet); compute_full_attributes(stmt->withClause, &byte_pct, &perbyte_cpu, &percall_cpu, &outin_ratio, &canCache, &isStrict); - interpret_AS_clause(languageOid, languageName, stmt->as, &prosrc_str, &probin_str); + interpret_AS_clause(languageOid, languageName, stmt->as, + &prosrc_str, &probin_str); /* * And now that we have all the parameters, and know we're permitted * to do so, go ahead and create the function. */ - ProcedureCreate(stmt->funcname, + ProcedureCreate(funcname, + namespaceId, stmt->replace, returnsSet, prorettype, @@ -292,27 +340,28 @@ CreateFunction(ProcedureStmt *stmt) -/* -------------------------------- +/* * DefineOperator - * * this function extracts all the information from the * parameter list generated by the parser and then has * OperatorCreate() do all the actual work. * * 'parameters' is a list of DefElem - * -------------------------------- */ void -DefineOperator(char *oprName, - List *parameters) +DefineOperator(List *names, List *parameters) { + char *oprName; + Oid oprNamespace; uint16 precedence = 0; /* operator precedence */ bool canHash = false; /* operator hashes */ bool isLeftAssociative = true; /* operator is left * associative */ char *functionName = NULL; /* function for operator */ - char *typeName1 = NULL; /* first type name */ - char *typeName2 = NULL; /* second type name */ + TypeName *typeName1 = NULL; /* first type name */ + TypeName *typeName2 = NULL; /* second type name */ + Oid typeId1 = InvalidOid; /* types converted to OID */ + Oid typeId2 = InvalidOid; char *commutatorName = NULL; /* optional commutator operator * name */ char *negatorName = NULL; /* optional negator operator name */ @@ -323,6 +372,9 @@ DefineOperator(char *oprName, char *sortName2 = NULL; /* optional second sort operator */ List *pl; + /* Convert list of names to a name and namespace */ + oprNamespace = QualifiedNameGetCreationNamespace(names, &oprName); + /* * loop over the definition list and extract the information we need. */ @@ -332,16 +384,14 @@ DefineOperator(char *oprName, if (strcasecmp(defel->defname, "leftarg") == 0) { - typeName1 = defGetString(defel); - if (IsA(defel->arg, TypeName) && - ((TypeName *) defel->arg)->setof) + typeName1 = defGetTypeName(defel); + if (typeName1->setof) elog(ERROR, "setof type not implemented for leftarg"); } else if (strcasecmp(defel->defname, "rightarg") == 0) { - typeName2 = defGetString(defel); - if (IsA(defel->arg, TypeName) && - ((TypeName *) defel->arg)->setof) + typeName2 = defGetTypeName(defel); + if (typeName2->setof) elog(ERROR, "setof type not implemented for rightarg"); } else if (strcasecmp(defel->defname, "procedure") == 0) @@ -367,15 +417,7 @@ DefineOperator(char *oprName, else if (strcasecmp(defel->defname, "hashes") == 0) canHash = TRUE; else if (strcasecmp(defel->defname, "sort1") == 0) - { - /* ---------------- - * XXX ( ... [ , sort1 = oprname ] [ , sort2 = oprname ] ... ) - * XXX is undocumented in the reference manual source as of - * 89/8/22. - * ---------------- - */ sortName1 = defGetString(defel); - } else if (strcasecmp(defel->defname, "sort2") == 0) sortName2 = defGetString(defel); else @@ -391,12 +433,18 @@ DefineOperator(char *oprName, if (functionName == NULL) elog(ERROR, "Define: \"procedure\" unspecified"); + /* Transform type names to type OIDs */ + if (typeName1) + typeId1 = typenameTypeId(typeName1); + if (typeName2) + typeId2 = typenameTypeId(typeName2); + /* * now have OperatorCreate do all the work.. */ OperatorCreate(oprName, /* operator name */ - typeName1, /* first type name */ - typeName2, /* second type name */ + typeId1, /* left type id */ + typeId2, /* right type id */ functionName, /* function for operator */ precedence, /* operator precedence */ isLeftAssociative, /* operator is left associative */ @@ -412,20 +460,26 @@ DefineOperator(char *oprName, } -/* ------------------- +/* * DefineAggregate - * ------------------ */ void -DefineAggregate(char *aggName, List *parameters) +DefineAggregate(List *names, List *parameters) { + char *aggName; + Oid aggNamespace; char *transfuncName = NULL; char *finalfuncName = NULL; - char *baseType = NULL; - char *transType = NULL; + TypeName *baseType = NULL; + TypeName *transType = NULL; char *initval = NULL; + Oid baseTypeId; + Oid transTypeId; List *pl; + /* Convert list of names to a name and namespace */ + aggNamespace = QualifiedNameGetCreationNamespace(names, &aggName); + foreach(pl, parameters) { DefElem *defel = (DefElem *) lfirst(pl); @@ -441,11 +495,11 @@ DefineAggregate(char *aggName, List *parameters) else if (strcasecmp(defel->defname, "finalfunc") == 0) finalfuncName = defGetString(defel); else if (strcasecmp(defel->defname, "basetype") == 0) - baseType = defGetString(defel); + baseType = defGetTypeName(defel); else if (strcasecmp(defel->defname, "stype") == 0) - transType = defGetString(defel); + transType = defGetTypeName(defel); else if (strcasecmp(defel->defname, "stype1") == 0) - transType = defGetString(defel); + transType = defGetTypeName(defel); else if (strcasecmp(defel->defname, "initcond") == 0) initval = defGetString(defel); else if (strcasecmp(defel->defname, "initcond1") == 0) @@ -466,13 +520,39 @@ DefineAggregate(char *aggName, List *parameters) elog(ERROR, "Define: \"sfunc\" unspecified"); /* + * Handle the aggregate's base type (input data type). This can be + * specified as 'ANY' for a data-independent transition function, such + * as COUNT(*). + */ + baseTypeId = LookupTypeName(baseType); + if (OidIsValid(baseTypeId)) + { + /* no need to allow aggregates on as-yet-undefined types */ + if (!get_typisdefined(baseTypeId)) + elog(ERROR, "Type \"%s\" is only a shell", + TypeNameToString(baseType)); + } + else + { + char *typnam = TypeNameToString(baseType); + + if (strcasecmp(typnam, "ANY") != 0) + elog(ERROR, "Type \"%s\" does not exist", typnam); + baseTypeId = InvalidOid; + } + + /* handle transtype --- no special cases here */ + transTypeId = typenameTypeId(transType); + + /* * Most of the argument-checking is done inside of AggregateCreate */ AggregateCreate(aggName, /* aggregate name */ + aggNamespace, /* namespace */ transfuncName, /* step function name */ finalfuncName, /* final function name */ - baseType, /* type of data being aggregated */ - transType, /* transition data type */ + baseTypeId, /* type of data being aggregated */ + transTypeId, /* transition data type */ initval); /* initial condition */ } @@ -483,12 +563,14 @@ DefineAggregate(char *aggName, List *parameters) void DefineDomain(CreateDomainStmt *stmt) { + char *domainName; + Oid domainNamespace; int16 internalLength; int16 externalLength; - char *inputName; - char *outputName; - char *sendName; - char *receiveName; + Oid inputProcedure; + Oid outputProcedure; + Oid receiveProcedure; + Oid sendProcedure; bool byValue; char delimiter; char alignment; @@ -500,46 +582,27 @@ DefineDomain(CreateDomainStmt *stmt) char *defaultValueBin = NULL; bool typNotNull = false; Oid basetypelem; - char *elemName = NULL; - int32 typNDims = 0; /* No array dimensions by default */ + int32 typNDims = length(stmt->typename->arrayBounds); HeapTuple typeTup; - char *typeName = stmt->typename->name; List *schema = stmt->constraints; List *listptr; + /* Convert list of names to a name and namespace */ + domainNamespace = QualifiedNameGetCreationNamespace(stmt->domainname, + &domainName); + /* * Domainnames, unlike typenames don't need to account for the '_' * prefix. So they can be one character longer. */ - if (strlen(stmt->domainname) > (NAMEDATALEN - 1)) + if (strlen(domainName) > (NAMEDATALEN - 1)) elog(ERROR, "CREATE DOMAIN: domain names must be %d characters or less", NAMEDATALEN - 1); - /* Test for existing Domain (or type) of that name */ - typeTup = SearchSysCache(TYPENAME, - PointerGetDatum(stmt->domainname), - 0, 0, 0); - if (HeapTupleIsValid(typeTup)) - elog(ERROR, "CREATE DOMAIN: domain or type %s already exists", - stmt->domainname); - /* - * When the type is an array for some reason we don't actually receive - * the name here. We receive the base types name. Lets set Dims while - * were at it. + * Look up the base type. */ - if (stmt->typename->arrayBounds > 0) { - typeName = makeArrayTypeName(stmt->typename->name); - - typNDims = length(stmt->typename->arrayBounds); - } - - typeTup = SearchSysCache(TYPENAME, - PointerGetDatum(typeName), - 0, 0, 0); - if (!HeapTupleIsValid(typeTup)) - elog(ERROR, "CREATE DOMAIN: type %s does not exist", - stmt->typename->name); + typeTup = typenameType(stmt->typename); /* * What we really don't want is domains of domains. This could cause all sorts @@ -550,7 +613,7 @@ DefineDomain(CreateDomainStmt *stmt) typtype = ((Form_pg_type) GETSTRUCT(typeTup))->typtype; if (typtype != 'b') elog(ERROR, "DefineDomain: %s is not a basetype", - stmt->typename->name); + TypeNameToString(stmt->typename)); /* passed by value */ byValue = ((Form_pg_type) GETSTRUCT(typeTup))->typbyval; @@ -570,43 +633,20 @@ DefineDomain(CreateDomainStmt *stmt) /* Array element Delimiter */ delimiter = ((Form_pg_type) GETSTRUCT(typeTup))->typdelim; - /* - * XXX this is pretty bogus: should be passing function OIDs to - * TypeCreate, not names which aren't unique. - */ - - /* Input Function Name */ - datum = SysCacheGetAttr(TYPENAME, typeTup, Anum_pg_type_typinput, &isnull); - Assert(!isnull); - - inputName = DatumGetCString(DirectFunctionCall1(regprocout, datum)); - - /* Output Function Name */ - datum = SysCacheGetAttr(TYPENAME, typeTup, Anum_pg_type_typoutput, &isnull); - Assert(!isnull); - - outputName = DatumGetCString(DirectFunctionCall1(regprocout, datum)); - - /* ReceiveName */ - datum = SysCacheGetAttr(TYPENAME, typeTup, Anum_pg_type_typreceive, &isnull); - Assert(!isnull); - - receiveName = DatumGetCString(DirectFunctionCall1(regprocout, datum)); - - /* SendName */ - datum = SysCacheGetAttr(TYPENAME, typeTup, Anum_pg_type_typsend, &isnull); - Assert(!isnull); - - sendName = DatumGetCString(DirectFunctionCall1(regprocout, datum)); + /* I/O Functions */ + inputProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typinput; + outputProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typoutput; + receiveProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typreceive; + sendProcedure = ((Form_pg_type) GETSTRUCT(typeTup))->typsend; /* Inherited default value */ - datum = SysCacheGetAttr(TYPENAME, typeTup, + datum = SysCacheGetAttr(TYPEOID, typeTup, Anum_pg_type_typdefault, &isnull); if (!isnull) defaultValue = DatumGetCString(DirectFunctionCall1(textout, datum)); /* Inherited default binary value */ - datum = SysCacheGetAttr(TYPENAME, typeTup, + datum = SysCacheGetAttr(TYPEOID, typeTup, Anum_pg_type_typdefaultbin, &isnull); if (!isnull) defaultValueBin = DatumGetCString(DirectFunctionCall1(textout, datum)); @@ -617,16 +657,6 @@ DefineDomain(CreateDomainStmt *stmt) * This is what enables us to make a domain of an array */ basetypelem = ((Form_pg_type) GETSTRUCT(typeTup))->typelem; - if (basetypelem != InvalidOid) - { - HeapTuple tup; - - tup = SearchSysCache(TYPEOID, - ObjectIdGetDatum(basetypelem), - 0, 0, 0); - elemName = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(tup))->typname)); - ReleaseSysCache(tup); - } /* * Run through constraints manually to avoid the additional @@ -661,14 +691,14 @@ DefineDomain(CreateDomainStmt *stmt) expr = cookDefault(pstate, colDef->raw_expr, typeTup->t_data->t_oid, stmt->typename->typmod, - stmt->typename->name); + domainName); /* * Expression must be stored as a nodeToString result, * but we also require a valid textual representation * (mainly to make life easier for pg_dump). */ defaultValue = deparse_expression(expr, - deparse_context_for(stmt->domainname, + deparse_context_for(domainName, InvalidOid), false); defaultValueBin = nodeToString(expr); @@ -723,19 +753,20 @@ DefineDomain(CreateDomainStmt *stmt) /* * Have TypeCreate do all the real work. */ - TypeCreate(stmt->domainname, /* type name */ + TypeCreate(domainName, /* type name */ + domainNamespace, /* namespace */ InvalidOid, /* preassigned type oid (not done here) */ InvalidOid, /* relation oid (n/a here) */ internalLength, /* internal size */ externalLength, /* external size */ 'd', /* type-type (domain type) */ delimiter, /* array element delimiter */ - inputName, /* input procedure */ - outputName, /* output procedure */ - receiveName, /* receive procedure */ - sendName, /* send procedure */ - elemName, /* element type name */ - typeName, /* base type name */ + inputProcedure, /* input procedure */ + outputProcedure, /* output procedure */ + receiveProcedure, /* receive procedure */ + sendProcedure, /* send procedure */ + basetypelem, /* element type ID */ + typeTup->t_data->t_oid, /* base type ID */ defaultValue, /* default type value (text) */ defaultValueBin, /* default type value (binary) */ byValue, /* passed by value */ @@ -743,7 +774,7 @@ DefineDomain(CreateDomainStmt *stmt) storage, /* TOAST strategy */ stmt->typename->typmod, /* typeMod value */ typNDims, /* Array dimensions for base type */ - typNotNull); /* Type NOT NULL */ + typNotNull); /* Type NOT NULL */ /* * Now we can clean up. @@ -756,11 +787,13 @@ DefineDomain(CreateDomainStmt *stmt) * Registers a new type. */ void -DefineType(char *typeName, List *parameters) +DefineType(List *names, List *parameters) { + char *typeName; + Oid typeNamespace; int16 internalLength = -1; /* int2 */ int16 externalLength = -1; /* int2 */ - char *elemName = NULL; + Oid elemType = InvalidOid; char *inputName = NULL; char *outputName = NULL; char *sendName = NULL; @@ -768,10 +801,18 @@ DefineType(char *typeName, List *parameters) char *defaultValue = NULL; bool byValue = false; char delimiter = DEFAULT_TYPDELIM; - char *shadow_type; - List *pl; char alignment = 'i'; /* default alignment */ char storage = 'p'; /* default TOAST storage method */ + Oid inputOid; + Oid outputOid; + Oid sendOid; + Oid receiveOid; + char *shadow_type; + List *pl; + Oid typoid; + + /* Convert list of names to a name and namespace */ + typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName); /* * Type names must be one character shorter than other names, allowing @@ -796,16 +837,16 @@ DefineType(char *typeName, List *parameters) outputName = defGetString(defel); else if (strcasecmp(defel->defname, "send") == 0) sendName = defGetString(defel); + else if (strcasecmp(defel->defname, "receive") == 0) + receiveName = defGetString(defel); else if (strcasecmp(defel->defname, "delimiter") == 0) { char *p = defGetString(defel); delimiter = p[0]; } - else if (strcasecmp(defel->defname, "receive") == 0) - receiveName = defGetString(defel); else if (strcasecmp(defel->defname, "element") == 0) - elemName = defGetString(defel); + elemType = typenameTypeId(defGetTypeName(defel)); else if (strcasecmp(defel->defname, "default") == 0) defaultValue = defGetString(defel); else if (strcasecmp(defel->defname, "passedbyvalue") == 0) @@ -867,30 +908,44 @@ DefineType(char *typeName, List *parameters) if (outputName == NULL) elog(ERROR, "Define: \"output\" unspecified"); + /* Convert I/O proc names to OIDs */ + inputOid = findTypeIOFunction(inputName, false); + outputOid = findTypeIOFunction(outputName, true); + if (sendName) + sendOid = findTypeIOFunction(sendName, true); + else + sendOid = outputOid; + if (receiveName) + receiveOid = findTypeIOFunction(receiveName, false); + else + receiveOid = inputOid; + /* * now have TypeCreate do all the real work. */ - TypeCreate(typeName, /* type name */ - InvalidOid, /* preassigned type oid (not done here) */ - InvalidOid, /* relation oid (n/a here) */ - internalLength, /* internal size */ - externalLength, /* external size */ - 'b', /* type-type (base type) */ - delimiter, /* array element delimiter */ - inputName, /* input procedure */ - outputName, /* output procedure */ - receiveName, /* receive procedure */ - sendName, /* send procedure */ - elemName, /* element type name */ - NULL, /* base type name (only for domains) */ - defaultValue, /* default type value */ - NULL, /* no binary form available */ - byValue, /* passed by value */ - alignment, /* required alignment */ - storage, /* TOAST strategy */ - -1, /* typMod (Domains only) */ - 0, /* Array Dimensions of typbasetype */ - 'f'); /* Type NOT NULL */ + typoid = + TypeCreate(typeName, /* type name */ + typeNamespace, /* namespace */ + InvalidOid, /* preassigned type oid (not done here) */ + InvalidOid, /* relation oid (n/a here) */ + internalLength, /* internal size */ + externalLength, /* external size */ + 'b', /* type-type (base type) */ + delimiter, /* array element delimiter */ + inputOid, /* input procedure */ + outputOid, /* output procedure */ + receiveOid, /* receive procedure */ + sendOid, /* send procedure */ + elemType, /* element type ID */ + InvalidOid, /* base type ID (only for domains) */ + defaultValue, /* default type value */ + NULL, /* no binary form available */ + byValue, /* passed by value */ + alignment, /* required alignment */ + storage, /* TOAST strategy */ + -1, /* typMod (Domains only) */ + 0, /* Array Dimensions of typbasetype */ + false); /* Type NOT NULL */ /* * When we create a base type (as opposed to a complex type) we need @@ -902,18 +957,19 @@ DefineType(char *typeName, List *parameters) alignment = (alignment == 'd') ? 'd' : 'i'; TypeCreate(shadow_type, /* type name */ + typeNamespace, /* namespace */ InvalidOid, /* preassigned type oid (not done here) */ InvalidOid, /* relation oid (n/a here) */ -1, /* internal size */ -1, /* external size */ 'b', /* type-type (base type) */ DEFAULT_TYPDELIM, /* array element delimiter */ - "array_in", /* input procedure */ - "array_out", /* output procedure */ - "array_in", /* receive procedure */ - "array_out", /* send procedure */ - typeName, /* element type name */ - NULL, /* base type name */ + F_ARRAY_IN, /* input procedure */ + F_ARRAY_OUT, /* output procedure */ + F_ARRAY_IN, /* receive procedure */ + F_ARRAY_OUT, /* send procedure */ + typoid, /* element type ID */ + InvalidOid, /* base type ID */ NULL, /* never a default type value */ NULL, /* binary default isn't sent either */ false, /* never passed by value */ @@ -921,11 +977,65 @@ DefineType(char *typeName, List *parameters) 'x', /* ARRAY is always toastable */ -1, /* typMod (Domains only) */ 0, /* Array dimensions of typbasetype */ - 'f'); /* Type NOT NULL */ + false); /* Type NOT NULL */ pfree(shadow_type); } +static Oid +findTypeIOFunction(const char *procname, bool isOutput) +{ + Oid argList[FUNC_MAX_ARGS]; + int nargs; + Oid procOid; + + /* + * First look for a 1-argument func with all argtypes 0. This is + * valid for all kinds of procedure. + */ + MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid)); + + procOid = GetSysCacheOid(PROCNAME, + PointerGetDatum(procname), + Int32GetDatum(1), + PointerGetDatum(argList), + 0); + + if (!OidIsValid(procOid)) + { + /* + * Alternatively, input procedures may take 3 args (data + * value, element OID, atttypmod); the pg_proc argtype + * signature is 0,OIDOID,INT4OID. Output procedures may + * take 2 args (data value, element OID). + */ + if (isOutput) + { + /* output proc */ + nargs = 2; + argList[1] = OIDOID; + } + else + { + /* input proc */ + nargs = 3; + argList[1] = OIDOID; + argList[2] = INT4OID; + } + procOid = GetSysCacheOid(PROCNAME, + PointerGetDatum(procname), + Int32GetDatum(nargs), + PointerGetDatum(argList), + 0); + + if (!OidIsValid(procOid)) + func_error("TypeCreate", procname, 1, argList, NULL); + } + + return procOid; +} + + static char * defGetString(DefElem *def) { @@ -951,7 +1061,7 @@ defGetString(DefElem *def) case T_String: return strVal(def->arg); case T_TypeName: - return TypeNameToInternalName((TypeName *) def->arg); + return TypeNameToString((TypeName *) def->arg); default: elog(ERROR, "Define: cannot interpret argument of \"%s\"", def->defname); @@ -978,6 +1088,32 @@ defGetNumeric(DefElem *def) return 0; /* keep compiler quiet */ } +static TypeName * +defGetTypeName(DefElem *def) +{ + if (def->arg == NULL) + elog(ERROR, "Define: \"%s\" requires a parameter", + def->defname); + switch (nodeTag(def->arg)) + { + case T_TypeName: + return (TypeName *) def->arg; + case T_String: + { + /* Allow quoted typename for backwards compatibility */ + TypeName *n = makeNode(TypeName); + + n->names = makeList1(def->arg); + n->typmod = -1; + return n; + } + default: + elog(ERROR, "Define: argument of \"%s\" must be a type name", + def->defname); + } + return NULL; /* keep compiler quiet */ +} + static int defGetTypeLength(DefElem *def) { @@ -998,7 +1134,7 @@ defGetTypeLength(DefElem *def) break; case T_TypeName: /* cope if grammar chooses to believe "variable" is a typename */ - if (strcasecmp(TypeNameToInternalName((TypeName *) def->arg), + if (strcasecmp(TypeNameToString((TypeName *) def->arg), "variable") == 0) return -1; /* variable length */ break; |