mirror of
https://github.com/postgres/postgres.git
synced 2025-08-24 09:27:52 +03:00
Add a bunch of pseudo-types to replace the behavior formerly associated
with OPAQUE, as per recent pghackers discussion. I still want to do some more work on the 'cstring' pseudo-type, but I'm going to commit the bulk of the changes now before the tree starts shifting under me ...
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.3 2002/07/12 18:43:15 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.4 2002/08/22 00:01:41 tgl Exp $
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The "DefineFoo" routines take the parse tree and pick out the
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_aggregate.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "commands/defrem.h"
|
||||
#include "miscadmin.h"
|
||||
#include "parser/parse_func.h"
|
||||
@@ -104,29 +105,23 @@ DefineAggregate(List *names, 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(*).
|
||||
* look up the aggregate's base type (input datatype) and transtype.
|
||||
*
|
||||
* We have historically allowed the command to look like basetype = 'ANY'
|
||||
* so we must do a case-insensitive comparison for the name ANY. Ugh.
|
||||
*
|
||||
* basetype can be a pseudo-type, but transtype can't, since we need
|
||||
* to be able to store values of the transtype.
|
||||
*/
|
||||
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));
|
||||
}
|
||||
if (strcasecmp(TypeNameToString(baseType), "ANY") == 0)
|
||||
baseTypeId = ANYOID;
|
||||
else
|
||||
{
|
||||
char *typnam = TypeNameToString(baseType);
|
||||
baseTypeId = typenameTypeId(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);
|
||||
if (get_typtype(transTypeId) == 'p')
|
||||
elog(ERROR, "Aggregate transition datatype cannot be %s",
|
||||
format_type_be(transTypeId));
|
||||
|
||||
/*
|
||||
* Most of the argument-checking is done inside of AggregateCreate
|
||||
@@ -159,14 +154,13 @@ RemoveAggregate(RemoveAggrStmt *stmt)
|
||||
* if a basetype is passed in, then attempt to find an aggregate for
|
||||
* that specific type.
|
||||
*
|
||||
* else if the basetype is blank, then attempt to find an aggregate with
|
||||
* a basetype of zero. This is valid. It means that the aggregate is
|
||||
* to apply to all basetypes (eg, COUNT).
|
||||
* else attempt to find an aggregate with a basetype of ANYOID.
|
||||
* This means that the aggregate is to apply to all basetypes (eg, COUNT).
|
||||
*/
|
||||
if (aggType)
|
||||
basetypeID = typenameTypeId(aggType);
|
||||
else
|
||||
basetypeID = InvalidOid;
|
||||
basetypeID = ANYOID;
|
||||
|
||||
procOid = find_aggregate_func("RemoveAggregate", aggName, basetypeID);
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
* Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.56 2002/08/09 16:45:14 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.57 2002/08/22 00:01:41 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_rewrite.h"
|
||||
#include "catalog/pg_trigger.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "commands/comment.h"
|
||||
#include "commands/dbcommands.h"
|
||||
#include "miscadmin.h"
|
||||
@@ -628,7 +629,7 @@ CommentAggregate(List *aggregate, List *arguments, char *comment)
|
||||
if (aggtype)
|
||||
baseoid = typenameTypeId(aggtype);
|
||||
else
|
||||
baseoid = InvalidOid;
|
||||
baseoid = ANYOID;
|
||||
|
||||
/* Now, attempt to find the actual tuple in pg_proc */
|
||||
|
||||
@@ -661,7 +662,7 @@ CommentProc(List *function, List *arguments, char *comment)
|
||||
/* Look up the procedure */
|
||||
|
||||
oid = LookupFuncNameTypeNames(function, arguments,
|
||||
true, "CommentProc");
|
||||
"CommentProc");
|
||||
|
||||
/* Now, validate the user's ability to comment on this function */
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* conversionmacmds.c
|
||||
* conversioncmds.c
|
||||
* conversion creation command support code
|
||||
*
|
||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/conversioncmds.c,v 1.2 2002/07/25 10:07:11 ishii Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/conversioncmds.c,v 1.3 2002/08/22 00:01:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -45,7 +45,7 @@ CreateConversionCommand(CreateConversionStmt *stmt)
|
||||
const char *to_encoding_name = stmt->to_encoding_name;
|
||||
List *func_name = stmt->func_name;
|
||||
|
||||
static Oid funcargs[] = {INT4OID, INT4OID, 0, 0, INT4OID};
|
||||
static Oid funcargs[] = {INT4OID, INT4OID, CSTRINGOID, CSTRINGOID, INT4OID};
|
||||
|
||||
/* Convert list of names to a name and namespace */
|
||||
namespaceId = QualifiedNameGetCreationNamespace(stmt->conversion_name, &conversion_name);
|
||||
|
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.165 2002/08/19 15:08:46 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.166 2002/08/22 00:01:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/relcache.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
#ifdef MULTIBYTE
|
||||
|
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.17 2002/08/11 17:44:12 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.18 2002/08/22 00:01:42 tgl Exp $
|
||||
*
|
||||
* DESCRIPTION
|
||||
* These routines take the parse tree and pick out the
|
||||
@@ -61,7 +61,9 @@
|
||||
* 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.
|
||||
* the target language is SQL. (We do this here, not in the SQL-function
|
||||
* validator, so as not to produce a WARNING and then an ERROR for the same
|
||||
* condition.)
|
||||
*/
|
||||
static void
|
||||
compute_return_type(TypeName *returnType, Oid languageOid,
|
||||
@@ -76,7 +78,8 @@ compute_return_type(TypeName *returnType, Oid languageOid,
|
||||
if (!get_typisdefined(rettype))
|
||||
{
|
||||
if (languageOid == SQLlanguageId)
|
||||
elog(ERROR, "SQL functions cannot return shell types");
|
||||
elog(ERROR, "SQL function cannot return shell type \"%s\"",
|
||||
TypeNameToString(returnType));
|
||||
else
|
||||
elog(WARNING, "Return type \"%s\" is only a shell",
|
||||
TypeNameToString(returnType));
|
||||
@@ -85,29 +88,32 @@ compute_return_type(TypeName *returnType, Oid languageOid,
|
||||
else
|
||||
{
|
||||
char *typnam = TypeNameToString(returnType);
|
||||
Oid namespaceId;
|
||||
AclResult aclresult;
|
||||
char *typname;
|
||||
|
||||
if (strcmp(typnam, "opaque") == 0)
|
||||
rettype = InvalidOid;
|
||||
else
|
||||
{
|
||||
Oid namespaceId;
|
||||
AclResult aclresult;
|
||||
char *typname;
|
||||
/*
|
||||
* Only C-coded functions can be I/O functions. We enforce this
|
||||
* restriction here mainly to prevent littering the catalogs with
|
||||
* shell types due to simple typos in user-defined function
|
||||
* definitions.
|
||||
*/
|
||||
if (languageOid != INTERNALlanguageId &&
|
||||
languageOid != ClanguageId)
|
||||
elog(ERROR, "Type \"%s\" does not exist", typnam);
|
||||
|
||||
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);
|
||||
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
|
||||
ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, get_namespace_name(namespaceId));
|
||||
rettype = TypeShellMake(typname, namespaceId);
|
||||
if (!OidIsValid(rettype))
|
||||
elog(ERROR, "could not create type %s", typnam);
|
||||
}
|
||||
/* Otherwise, go ahead and make a shell type */
|
||||
elog(WARNING, "ProcedureCreate: type %s is not yet defined",
|
||||
typnam);
|
||||
namespaceId = QualifiedNameGetCreationNamespace(returnType->names,
|
||||
&typname);
|
||||
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
|
||||
ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, get_namespace_name(namespaceId));
|
||||
rettype = TypeShellMake(typname, namespaceId);
|
||||
if (!OidIsValid(rettype))
|
||||
elog(ERROR, "could not create type %s", typnam);
|
||||
}
|
||||
|
||||
*prorettype_p = rettype;
|
||||
@@ -138,25 +144,24 @@ compute_parameter_types(List *argTypes, Oid languageOid,
|
||||
if (OidIsValid(toid))
|
||||
{
|
||||
if (!get_typisdefined(toid))
|
||||
elog(WARNING, "Argument type \"%s\" is only a shell",
|
||||
TypeNameToString(t));
|
||||
{
|
||||
/* As above, hard error if language is SQL */
|
||||
if (languageOid == SQLlanguageId)
|
||||
elog(ERROR, "SQL function cannot accept shell type \"%s\"",
|
||||
TypeNameToString(t));
|
||||
else
|
||||
elog(WARNING, "Argument type \"%s\" is only a shell",
|
||||
TypeNameToString(t));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
char *typnam = TypeNameToString(t);
|
||||
|
||||
if (strcmp(typnam, "opaque") == 0)
|
||||
{
|
||||
if (languageOid == SQLlanguageId)
|
||||
elog(ERROR, "SQL functions cannot have arguments of type \"opaque\"");
|
||||
toid = InvalidOid;
|
||||
}
|
||||
else
|
||||
elog(ERROR, "Type \"%s\" does not exist", typnam);
|
||||
elog(ERROR, "Type \"%s\" does not exist",
|
||||
TypeNameToString(t));
|
||||
}
|
||||
|
||||
if (t->setof)
|
||||
elog(ERROR, "functions cannot accept set arguments");
|
||||
elog(ERROR, "Functions cannot accept set arguments");
|
||||
|
||||
parameterTypes[parameterCount++] = toid;
|
||||
}
|
||||
@@ -492,7 +497,7 @@ RemoveFunction(RemoveFuncStmt *stmt)
|
||||
* Find the function, do permissions and validity checks
|
||||
*/
|
||||
funcOid = LookupFuncNameTypeNames(functionName, argTypes,
|
||||
true, "RemoveFunction");
|
||||
"RemoveFunction");
|
||||
|
||||
tup = SearchSysCache(PROCOID,
|
||||
ObjectIdGetDatum(funcOid),
|
||||
@@ -621,6 +626,23 @@ CreateCast(CreateCastStmt *stmt)
|
||||
if (sourcetypeid == targettypeid)
|
||||
elog(ERROR, "source data type and target data type are the same");
|
||||
|
||||
/* No shells, no pseudo-types allowed */
|
||||
if (!get_typisdefined(sourcetypeid))
|
||||
elog(ERROR, "source data type %s is only a shell",
|
||||
TypeNameToString(stmt->sourcetype));
|
||||
|
||||
if (!get_typisdefined(targettypeid))
|
||||
elog(ERROR, "target data type %s is only a shell",
|
||||
TypeNameToString(stmt->targettype));
|
||||
|
||||
if (get_typtype(sourcetypeid) == 'p')
|
||||
elog(ERROR, "source data type %s is a pseudo-type",
|
||||
TypeNameToString(stmt->sourcetype));
|
||||
|
||||
if (get_typtype(targettypeid) == 'p')
|
||||
elog(ERROR, "target data type %s is a pseudo-type",
|
||||
TypeNameToString(stmt->targettype));
|
||||
|
||||
if (!pg_type_ownercheck(sourcetypeid, GetUserId())
|
||||
&& !pg_type_ownercheck(targettypeid, GetUserId()))
|
||||
elog(ERROR, "must be owner of type %s or type %s",
|
||||
@@ -642,7 +664,6 @@ CreateCast(CreateCastStmt *stmt)
|
||||
{
|
||||
funcid = LookupFuncNameTypeNames(stmt->func->funcname,
|
||||
stmt->func->funcargs,
|
||||
false,
|
||||
"CreateCast");
|
||||
|
||||
tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(funcid), 0, 0, 0);
|
||||
|
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/opclasscmds.c,v 1.3 2002/08/05 03:29:16 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/opclasscmds.c,v 1.4 2002/08/22 00:01:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -177,7 +177,7 @@ DefineOpClass(CreateOpClassStmt *stmt)
|
||||
elog(ERROR, "DefineOpClass: procedure number %d appears more than once",
|
||||
item->number);
|
||||
funcOid = LookupFuncNameTypeNames(item->name, item->args,
|
||||
true, "DefineOpClass");
|
||||
"DefineOpClass");
|
||||
/* Caller must have execute permission on functions */
|
||||
aclresult = pg_proc_aclcheck(funcOid, GetUserId(),
|
||||
ACL_EXECUTE);
|
||||
|
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.40 2002/08/13 17:22:08 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.41 2002/08/22 00:01:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -71,17 +71,18 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
|
||||
elog(ERROR, "Language %s already exists", languageName);
|
||||
|
||||
/*
|
||||
* Lookup the PL handler function and check that it is of return type
|
||||
* Opaque
|
||||
* Lookup the PL handler function and check that it is of the expected
|
||||
* return type
|
||||
*/
|
||||
MemSet(typev, 0, sizeof(typev));
|
||||
procOid = LookupFuncName(stmt->plhandler, 0, typev);
|
||||
if (!OidIsValid(procOid))
|
||||
elog(ERROR, "function %s() doesn't exist",
|
||||
NameListToString(stmt->plhandler));
|
||||
if (get_func_rettype(procOid) != InvalidOid)
|
||||
elog(ERROR, "function %s() does not return type \"opaque\"",
|
||||
NameListToString(stmt->plhandler));
|
||||
if (get_func_rettype(procOid) != LANGUAGE_HANDLEROID)
|
||||
elog(ERROR, "function %s() does not return type %s",
|
||||
NameListToString(stmt->plhandler),
|
||||
format_type_be(LANGUAGE_HANDLEROID));
|
||||
|
||||
/* validate the validator function */
|
||||
if (stmt->plvalidator)
|
||||
@@ -91,6 +92,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
|
||||
if (!OidIsValid(valProcOid))
|
||||
elog(ERROR, "function %s(oid) doesn't exist",
|
||||
NameListToString(stmt->plvalidator));
|
||||
/* return value is ignored, so we don't check the type */
|
||||
}
|
||||
else
|
||||
valProcOid = InvalidOid;
|
||||
|
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.127 2002/08/18 11:20:05 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/trigger.c,v 1.128 2002/08/22 00:01:42 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "catalog/pg_language.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_trigger.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "commands/trigger.h"
|
||||
#include "executor/executor.h"
|
||||
#include "miscadmin.h"
|
||||
@@ -222,9 +223,15 @@ CreateTrigger(CreateTrigStmt *stmt, bool forConstraint)
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "CreateTrigger: function %s() does not exist",
|
||||
NameListToString(stmt->funcname));
|
||||
if (((Form_pg_proc) GETSTRUCT(tuple))->prorettype != 0)
|
||||
elog(ERROR, "CreateTrigger: function %s() must return OPAQUE",
|
||||
NameListToString(stmt->funcname));
|
||||
if (((Form_pg_proc) GETSTRUCT(tuple))->prorettype != TRIGGEROID)
|
||||
{
|
||||
/* OPAQUE is deprecated, but allowed for backwards compatibility */
|
||||
if (((Form_pg_proc) GETSTRUCT(tuple))->prorettype == OPAQUEOID)
|
||||
elog(NOTICE, "CreateTrigger: OPAQUE is deprecated, use type TRIGGER instead to define trigger functions");
|
||||
else
|
||||
elog(ERROR, "CreateTrigger: function %s() must return TRIGGER",
|
||||
NameListToString(stmt->funcname));
|
||||
}
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
/*
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.9 2002/08/15 16:36:02 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/typecmds.c,v 1.10 2002/08/22 00:01:42 tgl Exp $
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The "DefineFoo" routines take the parse tree and pick out the
|
||||
@@ -49,7 +49,7 @@
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
static Oid findTypeIOFunction(List *procname, bool isOutput);
|
||||
static Oid findTypeIOFunction(List *procname, Oid typeOid, bool isOutput);
|
||||
|
||||
/*
|
||||
* DefineType
|
||||
@@ -75,6 +75,7 @@ DefineType(List *names, List *parameters)
|
||||
char *shadow_type;
|
||||
List *pl;
|
||||
Oid typoid;
|
||||
Oid resulttype;
|
||||
|
||||
/* Convert list of names to a name and namespace */
|
||||
typeNamespace = QualifiedNameGetCreationNamespace(names, &typeName);
|
||||
@@ -116,7 +117,13 @@ DefineType(List *names, List *parameters)
|
||||
delimiter = p[0];
|
||||
}
|
||||
else if (strcasecmp(defel->defname, "element") == 0)
|
||||
{
|
||||
elemType = typenameTypeId(defGetTypeName(defel));
|
||||
/* disallow arrays of pseudotypes */
|
||||
if (get_typtype(elemType) == 'p')
|
||||
elog(ERROR, "Array element type cannot be %s",
|
||||
format_type_be(elemType));
|
||||
}
|
||||
else if (strcasecmp(defel->defname, "default") == 0)
|
||||
defaultValue = defGetString(defel);
|
||||
else if (strcasecmp(defel->defname, "passedbyvalue") == 0)
|
||||
@@ -179,9 +186,36 @@ DefineType(List *names, List *parameters)
|
||||
if (outputName == NIL)
|
||||
elog(ERROR, "Define: \"output\" unspecified");
|
||||
|
||||
/* Convert I/O proc names to OIDs */
|
||||
inputOid = findTypeIOFunction(inputName, false);
|
||||
outputOid = findTypeIOFunction(outputName, true);
|
||||
/*
|
||||
* Look to see if type already exists (presumably as a shell; if not,
|
||||
* TypeCreate will complain). If it does then the declarations of the
|
||||
* I/O functions might use it.
|
||||
*/
|
||||
typoid = GetSysCacheOid(TYPENAMENSP,
|
||||
CStringGetDatum(typeName),
|
||||
ObjectIdGetDatum(typeNamespace),
|
||||
0, 0);
|
||||
|
||||
/*
|
||||
* Convert I/O proc names to OIDs
|
||||
*/
|
||||
inputOid = findTypeIOFunction(inputName, typoid, false);
|
||||
outputOid = findTypeIOFunction(outputName, typoid, true);
|
||||
|
||||
/*
|
||||
* Verify that I/O procs return the expected thing. OPAQUE is an allowed
|
||||
* (but deprecated) alternative to the fully type-safe choices.
|
||||
*/
|
||||
resulttype = get_func_rettype(inputOid);
|
||||
if (!((OidIsValid(typoid) && resulttype == typoid) ||
|
||||
resulttype == OPAQUEOID))
|
||||
elog(ERROR, "Type input function %s must return %s or OPAQUE",
|
||||
NameListToString(inputName), typeName);
|
||||
resulttype = get_func_rettype(outputOid);
|
||||
if (!(resulttype == CSTRINGOID ||
|
||||
resulttype == OPAQUEOID))
|
||||
elog(ERROR, "Type output function %s must return CSTRING or OPAQUE",
|
||||
NameListToString(outputName));
|
||||
|
||||
/*
|
||||
* now have TypeCreate do all the real work.
|
||||
@@ -377,10 +411,9 @@ DefineDomain(CreateDomainStmt *stmt)
|
||||
basetypeoid = HeapTupleGetOid(typeTup);
|
||||
|
||||
/*
|
||||
* What we really don't want is domains of domains. This could cause all sorts
|
||||
* of neat issues if we allow that.
|
||||
*
|
||||
* With testing, we may determine complex types should be allowed
|
||||
* Base type must be a plain base type. Domains over pseudo types would
|
||||
* create a security hole. Domains of domains might be made to work in
|
||||
* the future, but not today. Ditto for domains over complex types.
|
||||
*/
|
||||
typtype = baseType->typtype;
|
||||
if (typtype != 'b')
|
||||
@@ -621,52 +654,109 @@ RemoveDomain(List *names, DropBehavior behavior)
|
||||
|
||||
/*
|
||||
* Find a suitable I/O function for a type.
|
||||
*
|
||||
* typeOid is the type's OID, if it already exists as a shell type,
|
||||
* otherwise InvalidOid.
|
||||
*/
|
||||
static Oid
|
||||
findTypeIOFunction(List *procname, bool isOutput)
|
||||
findTypeIOFunction(List *procname, Oid typeOid, 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 = LookupFuncName(procname, 1, argList);
|
||||
|
||||
if (!OidIsValid(procOid))
|
||||
if (isOutput)
|
||||
{
|
||||
/*
|
||||
* 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).
|
||||
* Output functions can take a single argument of the type,
|
||||
* or two arguments (data value, element OID). The signature
|
||||
* may use OPAQUE in place of the actual type name; this is the
|
||||
* only possibility if the type doesn't yet exist as a shell.
|
||||
*/
|
||||
if (isOutput)
|
||||
if (OidIsValid(typeOid))
|
||||
{
|
||||
/* output proc */
|
||||
nargs = 2;
|
||||
argList[1] = OIDOID;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* input proc */
|
||||
nargs = 3;
|
||||
argList[1] = OIDOID;
|
||||
argList[2] = INT4OID;
|
||||
}
|
||||
procOid = LookupFuncName(procname, nargs, argList);
|
||||
MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||
|
||||
if (!OidIsValid(procOid))
|
||||
func_error("TypeCreate", procname, 1, argList, NULL);
|
||||
argList[0] = typeOid;
|
||||
|
||||
procOid = LookupFuncName(procname, 1, argList);
|
||||
if (OidIsValid(procOid))
|
||||
return procOid;
|
||||
|
||||
argList[1] = OIDOID;
|
||||
|
||||
procOid = LookupFuncName(procname, 2, argList);
|
||||
if (OidIsValid(procOid))
|
||||
return procOid;
|
||||
|
||||
}
|
||||
|
||||
MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||
|
||||
argList[0] = OPAQUEOID;
|
||||
|
||||
procOid = LookupFuncName(procname, 1, argList);
|
||||
if (OidIsValid(procOid))
|
||||
return procOid;
|
||||
|
||||
argList[1] = OIDOID;
|
||||
|
||||
procOid = LookupFuncName(procname, 2, argList);
|
||||
if (OidIsValid(procOid))
|
||||
return procOid;
|
||||
|
||||
/* Prefer type name over OPAQUE in the failure message. */
|
||||
if (OidIsValid(typeOid))
|
||||
argList[0] = typeOid;
|
||||
|
||||
func_error("TypeCreate", procname, 1, argList, NULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Input functions can take a single argument of type CSTRING,
|
||||
* or three arguments (string, element OID, typmod). The signature
|
||||
* may use OPAQUE in place of CSTRING.
|
||||
*/
|
||||
MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||
|
||||
argList[0] = CSTRINGOID;
|
||||
|
||||
procOid = LookupFuncName(procname, 1, argList);
|
||||
if (OidIsValid(procOid))
|
||||
return procOid;
|
||||
|
||||
argList[1] = OIDOID;
|
||||
argList[2] = INT4OID;
|
||||
|
||||
procOid = LookupFuncName(procname, 3, argList);
|
||||
if (OidIsValid(procOid))
|
||||
return procOid;
|
||||
|
||||
MemSet(argList, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||
|
||||
argList[0] = OPAQUEOID;
|
||||
|
||||
procOid = LookupFuncName(procname, 1, argList);
|
||||
if (OidIsValid(procOid))
|
||||
return procOid;
|
||||
|
||||
argList[1] = OIDOID;
|
||||
argList[2] = INT4OID;
|
||||
|
||||
procOid = LookupFuncName(procname, 3, argList);
|
||||
if (OidIsValid(procOid))
|
||||
return procOid;
|
||||
|
||||
/* Use CSTRING (preferred) in the error message */
|
||||
argList[0] = CSTRINGOID;
|
||||
|
||||
func_error("TypeCreate", procname, 1, argList, NULL);
|
||||
}
|
||||
|
||||
return procOid;
|
||||
return InvalidOid; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------
|
||||
* DefineCompositeType
|
||||
*
|
||||
|
Reference in New Issue
Block a user