Commit b985d487 authored by Tom Lane's avatar Tom Lane

Further code review for range types patch.

Fix some bugs in coercion logic and pg_dump; more comment cleanup;
minor cosmetic improvements.
parent 40d35036
......@@ -4506,6 +4506,12 @@ SELECT * FROM pg_attribute
<entry>Indicates that a function accepts any input data type.</entry>
</row>
<row>
<entry><type>anyelement</></entry>
<entry>Indicates that a function accepts any data type
(see <xref linkend="extend-types-polymorphic">).</entry>
</row>
<row>
<entry><type>anyarray</></entry>
<entry>Indicates that a function accepts any array data type
......@@ -4513,8 +4519,8 @@ SELECT * FROM pg_attribute
</row>
<row>
<entry><type>anyelement</></entry>
<entry>Indicates that a function accepts any data type
<entry><type>anynonarray</></entry>
<entry>Indicates that a function accepts any non-array data type
(see <xref linkend="extend-types-polymorphic">).</entry>
</row>
......@@ -4532,12 +4538,6 @@ SELECT * FROM pg_attribute
<xref linkend="rangetypes">).</entry>
</row>
<row>
<entry><type>anynonarray</></entry>
<entry>Indicates that a function accepts any non-array data type
(see <xref linkend="extend-types-polymorphic">).</entry>
</row>
<row>
<entry><type>cstring</></entry>
<entry>Indicates that a function accepts or returns a null-terminated C string.</entry>
......@@ -4595,9 +4595,9 @@ SELECT * FROM pg_attribute
languages all forbid use of a pseudo-type as argument type, and allow
only <type>void</> and <type>record</> as a result type (plus
<type>trigger</> when the function is used as a trigger). Some also
support polymorphic functions using the types <type>anyarray</>,
<type>anyelement</>, <type>anyenum</>, <type>anyrange</>, and
<type>anynonarray</>.
support polymorphic functions using the types <type>anyelement</>,
<type>anyarray</>, <type>anynonarray</>, <type>anyenum</>, and
<type>anyrange</>.
</para>
<para>
......
......@@ -91,7 +91,7 @@ ProcedureCreate(const char *procedureName,
int parameterCount;
int allParamCount;
Oid *allParams;
char *modes = NULL;
char *paramModes = NULL;
bool genericInParam = false;
bool genericOutParam = false;
bool anyrangeInParam = false;
......@@ -130,6 +130,7 @@ ProcedureCreate(const char *procedureName,
FUNC_MAX_ARGS)));
/* note: the above is correct, we do NOT count output arguments */
/* Deconstruct array inputs */
if (allParameterTypes != PointerGetDatum(NULL))
{
/*
......@@ -169,28 +170,27 @@ ProcedureCreate(const char *procedureName,
ARR_HASNULL(modesArray) ||
ARR_ELEMTYPE(modesArray) != CHAROID)
elog(ERROR, "parameterModes is not a 1-D char array");
modes = (char *) ARR_DATA_PTR(modesArray);
paramModes = (char *) ARR_DATA_PTR(modesArray);
}
/*
* Do not allow polymorphic return type unless at least one input argument
* is polymorphic. Also, do not allow return type INTERNAL unless at
* least one input argument is INTERNAL.
* Detect whether we have polymorphic or INTERNAL arguments. The first
* loop checks input arguments, the second output arguments.
*/
for (i = 0; i < parameterCount; i++)
{
switch (parameterTypes->values[i])
{
case ANYRANGEOID:
anyrangeInParam = true;
/* FALL THROUGH */
case ANYARRAYOID:
case ANYELEMENTOID:
case ANYNONARRAYOID:
case ANYENUMOID:
genericInParam = true;
break;
case ANYRANGEOID:
genericInParam = true;
anyrangeInParam = true;
break;
case INTERNALOID:
internalInParam = true;
break;
......@@ -201,23 +201,23 @@ ProcedureCreate(const char *procedureName,
{
for (i = 0; i < allParamCount; i++)
{
if (modes == NULL ||
(modes[i] != PROARGMODE_OUT &&
modes[i] != PROARGMODE_INOUT &&
modes[i] != PROARGMODE_TABLE))
continue;
if (paramModes == NULL ||
paramModes[i] == PROARGMODE_IN ||
paramModes[i] == PROARGMODE_VARIADIC)
continue; /* ignore input-only params */
switch (allParams[i])
{
case ANYRANGEOID:
anyrangeOutParam = true;
/* FALL THROUGH */
case ANYARRAYOID:
case ANYELEMENTOID:
case ANYNONARRAYOID:
case ANYENUMOID:
genericOutParam = true;
break;
case ANYRANGEOID:
genericOutParam = true;
anyrangeOutParam = true;
break;
case INTERNALOID:
internalOutParam = true;
break;
......@@ -225,6 +225,13 @@ ProcedureCreate(const char *procedureName,
}
}
/*
* Do not allow polymorphic return type unless at least one input argument
* is polymorphic. ANYRANGE return type is even stricter: must have an
* ANYRANGE input (since we can't deduce the specific range type from
* ANYELEMENT). Also, do not allow return type INTERNAL unless at least
* one input argument is INTERNAL.
*/
if ((IsPolymorphicType(returnType) || genericOutParam)
&& !genericInParam)
ereport(ERROR,
......@@ -259,7 +266,7 @@ ProcedureCreate(const char *procedureName,
procedureName,
format_type_be(parameterTypes->values[0]))));
if (modes != NULL)
if (paramModes != NULL)
{
/*
* Only the last input parameter can be variadic; if it is, save its
......@@ -268,7 +275,7 @@ ProcedureCreate(const char *procedureName,
*/
for (i = 0; i < allParamCount; i++)
{
switch (modes[i])
switch (paramModes[i])
{
case PROARGMODE_IN:
case PROARGMODE_INOUT:
......@@ -298,7 +305,7 @@ ProcedureCreate(const char *procedureName,
}
break;
default:
elog(ERROR, "invalid parameter mode '%c'", modes[i]);
elog(ERROR, "invalid parameter mode '%c'", paramModes[i]);
break;
}
}
......
......@@ -654,9 +654,9 @@ RemoveTypeById(Oid typeOid)
EnumValuesDelete(typeOid);
/*
* If it is a range type, delete the pg_range entries too; we don't bother
* with making dependency entries for those, so it has to be done "by
* hand" here.
* If it is a range type, delete the pg_range entry too; we don't bother
* with making a dependency entry for that, so it has to be done "by hand"
* here.
*/
if (((Form_pg_type) GETSTRUCT(tup))->typtype == TYPTYPE_RANGE)
RangeDelete(typeOid);
......@@ -1475,8 +1475,9 @@ makeRangeConstructor(char *name, Oid namespace, Oid rangeOid, Oid subtype)
0.0); /* prorows */
/*
* Make the constructor internally-dependent on the range type so that
* the user doesn't have to treat them as separate objects.
* Make the constructors internally-dependent on the range type so
* that they go away silently when the type is dropped. Note that
* pg_dump depends on this choice to avoid dumping the constructors.
*/
myself.classId = ProcedureRelationId;
myself.objectId = procOid;
......
This diff is collapsed.
......@@ -851,11 +851,11 @@ standard_ProcessUtility(Node *parsetree,
}
break;
case T_CreateEnumStmt: /* CREATE TYPE (enum) */
case T_CreateEnumStmt: /* CREATE TYPE AS ENUM */
DefineEnum((CreateEnumStmt *) parsetree);
break;
case T_CreateRangeStmt:
case T_CreateRangeStmt: /* CREATE TYPE AS RANGE */
DefineRange((CreateRangeStmt *) parsetree);
break;
......
......@@ -2253,7 +2253,7 @@ type_is_enum(Oid typid)
/*
* type_is_range
* Returns true if the given type is an range type.
* Returns true if the given type is a range type.
*/
bool
type_is_range(Oid typid)
......@@ -2867,6 +2867,14 @@ get_namespace_name(Oid nspid)
return NULL;
}
/* ---------- PG_RANGE CACHE ---------- */
/*
* get_range_subtype
* Returns the subtype of a given range type
*
* Returns InvalidOid if the type is not a range type.
*/
Oid
get_range_subtype(Oid rangeOid)
{
......
......@@ -555,7 +555,7 @@ static const struct cachedesc cacheinfo[] = {
},
2048
},
{RangeRelationId, /* RANGETYPE */
{RangeRelationId, /* RANGETYPE */
RangeTypidIndexId,
1,
{
......@@ -564,7 +564,7 @@ static const struct cachedesc cacheinfo[] = {
0,
0
},
1024
64
},
{RelationRelationId, /* RELNAMENSP */
ClassNameNspIndexId,
......
......@@ -481,14 +481,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
!OidIsValid(anyrange_type))
return false;
/*
* We can't deduce a range type from the subtype, because there may be
* multiple range types for a single subtype.
*/
if (have_anyrange_result && !OidIsValid(anyrange_type))
return false;
/* If needed, deduce one polymorphic type from the other */
/* If needed, deduce one polymorphic type from others */
if (have_anyelement_result && !OidIsValid(anyelement_type))
{
if (OidIsValid(anyarray_type))
......@@ -497,14 +490,14 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
ANYARRAYOID);
if (OidIsValid(anyrange_type))
{
Oid subtype = resolve_generic_type(ANYELEMENTOID,
anyrange_type,
ANYRANGEOID);
if (OidIsValid(anyelement_type) &&
anyelement_type != subtype)
Oid subtype = resolve_generic_type(ANYELEMENTOID,
anyrange_type,
ANYRANGEOID);
/* check for inconsistent array and range results */
if (OidIsValid(anyelement_type) && anyelement_type != subtype)
return false;
else
anyelement_type = subtype;
anyelement_type = subtype;
}
}
......@@ -513,6 +506,13 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
anyelement_type,
ANYELEMENTOID);
/*
* We can't deduce a range type from other polymorphic inputs, because
* there may be multiple range types for the same subtype.
*/
if (have_anyrange_result && !OidIsValid(anyrange_type))
return false;
/* Enforce ANYNONARRAY if needed */
if (have_anynonarray && type_is_array(anyelement_type))
return false;
......@@ -523,9 +523,10 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
/*
* Identify the collation to use for polymorphic OUT parameters. (It'll
* necessarily be the same for both anyelement and anyarray.)
* necessarily be the same for both anyelement and anyarray.) Note that
* range types are not collatable, so any possible internal collation of
* a range type is not considered here.
*/
if (OidIsValid(anyelement_type))
anycollation = get_typcollation(anyelement_type);
else if (OidIsValid(anyarray_type))
......@@ -573,7 +574,7 @@ resolve_polymorphic_tupdesc(TupleDesc tupdesc, oidvector *declared_args,
anyrange_type,
-1,
0);
TupleDescInitEntryCollation(tupdesc, i + 1, anycollation);
/* no collation should be attached to a range type */
break;
default:
break;
......@@ -672,19 +673,12 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
!have_anyrange_result)
return true;
/*
* We can't deduce a range type from the subtype, because there may be
* multiple range types for a single subtype.
*/
if (have_anyrange_result && !OidIsValid(anyrange_type))
return false;
/* If no input polymorphics, parser messed up */
if (!OidIsValid(anyelement_type) && !OidIsValid(anyarray_type) &&
!OidIsValid(anyrange_type))
return false;
/* If needed, deduce one polymorphic type from the other */
/* If needed, deduce one polymorphic type from others */
if (have_anyelement_result && !OidIsValid(anyelement_type))
{
if (OidIsValid(anyarray_type))
......@@ -693,14 +687,14 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
ANYARRAYOID);
if (OidIsValid(anyrange_type))
{
Oid subtype = resolve_generic_type(ANYELEMENTOID,
anyrange_type,
ANYRANGEOID);
if (OidIsValid(anyelement_type) &&
anyelement_type != subtype)
Oid subtype = resolve_generic_type(ANYELEMENTOID,
anyrange_type,
ANYRANGEOID);
/* check for inconsistent array and range results */
if (OidIsValid(anyelement_type) && anyelement_type != subtype)
return false;
else
anyelement_type = subtype;
anyelement_type = subtype;
}
}
......@@ -709,6 +703,13 @@ resolve_polymorphic_argtypes(int numargs, Oid *argtypes, char *argmodes,
anyelement_type,
ANYELEMENTOID);
/*
* We can't deduce a range type from other polymorphic inputs, because
* there may be multiple range types for the same subtype.
*/
if (have_anyrange_result && !OidIsValid(anyrange_type))
return false;
/* XXX do we need to enforce ANYNONARRAY or ANYENUM here? I think not */
/* And finally replace the output column types as needed */
......
......@@ -52,7 +52,6 @@
#include "catalog/pg_largeobject.h"
#include "catalog/pg_largeobject_metadata.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_range.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "libpq/libpq-fs.h"
......@@ -3703,34 +3702,16 @@ getFuncs(int *numFuncs)
* pg_catalog. In normal dumps we can still ignore those --- but in
* binary-upgrade mode, we must dump the member objects of the extension,
* so be sure to fetch any such functions.
*
* Also, in 9.2 and up, exclude functions that are internally dependent on
* something else, since presumably those will be created as a result of
* creating the something else. This currently only acts to suppress
* constructor functions for range types. Note that this is OK only
* because the constructors don't have any dependencies the range type
* doesn't have; otherwise we might not get creation ordering correct.
*/
if (g_fout->remoteVersion >= 90200)
{
appendPQExpBuffer(query,
"SELECT tableoid, oid, proname, prolang, "
"pronargs, proargtypes, prorettype, proacl, "
"pronamespace, "
"(%s proowner) AS rolname "
"FROM pg_proc p "
"WHERE NOT proisagg AND "
" NOT EXISTS (SELECT 1 FROM pg_depend "
" WHERE classid = 'pg_proc'::regclass AND "
" objid = p.oid AND deptype = 'i') AND "
"(pronamespace != "
"(SELECT oid FROM pg_namespace "
"WHERE nspname = 'pg_catalog')",
username_subquery);
if (binary_upgrade && g_fout->remoteVersion >= 90100)
appendPQExpBuffer(query,
" OR EXISTS(SELECT 1 FROM pg_depend WHERE "
"classid = 'pg_proc'::regclass AND "
"objid = p.oid AND "
"refclassid = 'pg_extension'::regclass AND "
"deptype = 'e')");
appendPQExpBuffer(query, ")");
}
else if (g_fout->remoteVersion >= 70300)
if (g_fout->remoteVersion >= 70300)
{
appendPQExpBuffer(query,
"SELECT tableoid, oid, proname, prolang, "
......@@ -3743,9 +3724,14 @@ getFuncs(int *numFuncs)
"(SELECT oid FROM pg_namespace "
"WHERE nspname = 'pg_catalog')",
username_subquery);
if (g_fout->remoteVersion >= 90200)
appendPQExpBuffer(query,
"\n AND NOT EXISTS (SELECT 1 FROM pg_depend "
"WHERE classid = 'pg_proc'::regclass AND "
"objid = p.oid AND deptype = 'i')");
if (binary_upgrade && g_fout->remoteVersion >= 90100)
appendPQExpBuffer(query,
" OR EXISTS(SELECT 1 FROM pg_depend WHERE "
"\n OR EXISTS(SELECT 1 FROM pg_depend WHERE "
"classid = 'pg_proc'::regclass AND "
"objid = p.oid AND "
"refclassid = 'pg_extension'::regclass AND "
......@@ -7479,31 +7465,25 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
PQExpBuffer labelq = createPQExpBuffer();
PQExpBuffer query = createPQExpBuffer();
PGresult *res;
Oid collationOid;
char *procname;
Oid collationOid;
Oid opclassOid;
Oid analyzeOid;
Oid canonicalOid;
Oid subdiffOid;
/* Set proper schema search path */
selectSourceSchema("pg_catalog");
/*
* select appropriate schema to ensure names in CREATE are properly
* qualified
*/
selectSourceSchema(tyinfo->dobj.namespace->dobj.name);
appendPQExpBuffer(query,
"SELECT rngtypid, "
"format_type(rngsubtype, NULL) as rngsubtype, "
"rngsubtype::oid as rngsubtypeoid, "
"SELECT pg_catalog.format_type(rngsubtype, NULL) AS rngsubtype, "
"opc.opcname AS opcname, "
"(SELECT nspname FROM pg_catalog.pg_namespace nsp "
" WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
"opc.opcdefault, "
"CASE WHEN rngcollation = st.typcollation THEN 0 "
" ELSE rngcollation END AS collation, "
"CASE WHEN opcdefault THEN 0 ELSE rngsubopc END "
" AS rngsubopc, "
"(SELECT nspname FROM pg_namespace nsp "
" WHERE nsp.oid = opc.opcnamespace) AS opcnsp, "
"t.typanalyze, t.typanalyze::oid as typanalyzeoid, "
"rngcanonical, rngcanonical::oid as rngcanonicaloid, "
"rngsubdiff, rngsubdiff::oid as rngsubdiffoid "
"FROM pg_catalog.pg_type t, pg_type st, "
"rngcanonical, rngsubdiff, t.typanalyze "
"FROM pg_catalog.pg_type t, pg_catalog.pg_type st, "
" pg_catalog.pg_opclass opc, pg_catalog.pg_range r "
"WHERE t.oid = rngtypid AND st.oid = rngsubtype AND "
" opc.oid = rngsubopc AND rngtypid = '%u'",
......@@ -7511,6 +7491,12 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
if (PQntuples(res) != 1)
{
write_msg(NULL, "query returned %d pg_range entries for range type \"%s\"\n",
PQntuples(res), tyinfo->dobj.name);
exit_nicely();
}
/*
* DROP must be fully qualified in case same name appears in pg_catalog.
......@@ -7522,68 +7508,53 @@ dumpRangeType(Archive *fout, TypeInfo *tyinfo)
appendPQExpBuffer(delq, "%s;\n",
fmtId(tyinfo->dobj.name));
/* We might already have a shell type, but setting pg_type_oid is harmless */
if (binary_upgrade)
binary_upgrade_set_type_oids_by_type_oid(q, tyinfo->dobj.catId.oid);
appendPQExpBuffer(q, "CREATE TYPE %s AS RANGE (",
fmtId(tyinfo->dobj.name));
/* SUBTYPE */
appendPQExpBuffer(q, "\n SUBTYPE = %s",
appendPQExpBuffer(q, "\n subtype = %s",
PQgetvalue(res, 0, PQfnumber(res, "rngsubtype")));
/* COLLATION */
collationOid = atooid(PQgetvalue(res, 0,
PQfnumber(res, "collation")));
/* print subtype_opclass only if not default for subtype */
if (PQgetvalue(res, 0, PQfnumber(res, "opcdefault"))[0] != 't')
{
char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
/* always schema-qualify, don't try to be smart */
appendPQExpBuffer(q, ",\n subtype_opclass = %s.",
fmtId(nspname));
appendPQExpBuffer(q, "%s", fmtId(opcname));
}
collationOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "collation")));
if (OidIsValid(collationOid))
{
CollInfo *coll;
CollInfo *coll = findCollationByOid(collationOid);
coll = findCollationByOid(collationOid);
if (coll)
{
/* always schema-qualify, don't try to be smart */
appendPQExpBuffer(q, ",\n COLLATION = %s.",
appendPQExpBuffer(q, ",\n collation = %s.",
fmtId(coll->dobj.namespace->dobj.name));
appendPQExpBuffer(q, "%s",
fmtId(coll->dobj.name));
}
}
/* SUBTYPE_OPCLASS */
opclassOid = atooid(PQgetvalue(res, 0,
PQfnumber(res, "rngsubopc")));
if (OidIsValid(opclassOid))
{
char *opcname = PQgetvalue(res, 0, PQfnumber(res, "opcname"));
char *nspname = PQgetvalue(res, 0, PQfnumber(res, "opcnsp"));
procname = PQgetvalue(res, 0, PQfnumber(res, "rngcanonical"));
if (strcmp(procname, "-") != 0)
appendPQExpBuffer(q, ",\n canonical = %s", procname);
/* always schema-qualify, don't try to be smart */
appendPQExpBuffer(q, ",\n SUBTYPE_OPCLASS = %s.",
fmtId(nspname));
appendPQExpBuffer(q, "%s", fmtId(opcname));
}
procname = PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff"));
if (strcmp(procname, "-") != 0)
appendPQExpBuffer(q, ",\n subtype_diff = %s", procname);
/* ANALYZE */
analyzeOid = atooid(PQgetvalue(res, 0,
PQfnumber(res, "typanalyzeoid")));
if (OidIsValid(analyzeOid))
appendPQExpBuffer(q, ",\n ANALYZE = %s",
PQgetvalue(res, 0, PQfnumber(res, "typanalyze")));
/* CANONICAL */
canonicalOid = atooid(PQgetvalue(res, 0,
PQfnumber(res, "rngcanonicaloid")));
if (OidIsValid(canonicalOid))
appendPQExpBuffer(q, ",\n CANONICAL = %s",
PQgetvalue(res, 0, PQfnumber(res, "rngcanonical")));
/* SUBTYPE_DIFF */
subdiffOid = atooid(PQgetvalue(res, 0, PQfnumber(res, "rngsubdiffoid")));
if (OidIsValid(subdiffOid))
appendPQExpBuffer(q, ",\n SUBTYPE_DIFF = %s",
PQgetvalue(res, 0, PQfnumber(res, "rngsubdiff")));
procname = PQgetvalue(res, 0, PQfnumber(res, "typanalyze"));
if (strcmp(procname, "-") != 0)
appendPQExpBuffer(q, ",\n analyze = %s", procname);
appendPQExpBuffer(q, "\n);\n");
......
......@@ -2241,28 +2241,28 @@ typedef struct CreateEnumStmt
} CreateEnumStmt;
/* ----------------------
* Alter Type Statement, enum types
* Create Type Statement, range types
* ----------------------
*/
typedef struct AlterEnumStmt
typedef struct CreateRangeStmt
{
NodeTag type;
List *typeName; /* qualified name (list of Value strings) */
char *newVal; /* new enum value's name */
char *newValNeighbor; /* neighboring enum value, if specified */
bool newValIsAfter; /* place new enum value after neighbor? */
} AlterEnumStmt;
List *params; /* range parameters (list of DefElem) */
} CreateRangeStmt;
/* ----------------------
* Create Type Statement, range types
* Alter Type Statement, enum types
* ----------------------
*/
typedef struct CreateRangeStmt
typedef struct AlterEnumStmt
{
NodeTag type;
List *typeName; /* qualified name (list of Value strings) */
List *params; /* range parameters (list of DefElem) */
} CreateRangeStmt;
char *newVal; /* new enum value's name */
char *newValNeighbor; /* neighboring enum value, if specified */
bool newValIsAfter; /* place new enum value after neighbor? */
} AlterEnumStmt;
/* ----------------------
* Create View Statement
......
......@@ -502,6 +502,8 @@ extern Datum anynonarray_in(PG_FUNCTION_ARGS);
extern Datum anynonarray_out(PG_FUNCTION_ARGS);
extern Datum anyenum_in(PG_FUNCTION_ARGS);
extern Datum anyenum_out(PG_FUNCTION_ARGS);
extern Datum anyrange_in(PG_FUNCTION_ARGS);
extern Datum anyrange_out(PG_FUNCTION_ARGS);
extern Datum void_in(PG_FUNCTION_ARGS);
extern Datum void_out(PG_FUNCTION_ARGS);
extern Datum void_recv(PG_FUNCTION_ARGS);
......
......@@ -73,9 +73,7 @@ typedef struct
* prototypes for functions defined in rangetypes.c
*/
/* IO */
extern Datum anyrange_in(PG_FUNCTION_ARGS);
extern Datum anyrange_out(PG_FUNCTION_ARGS);
/* I/O */
extern Datum range_in(PG_FUNCTION_ARGS);
extern Datum range_out(PG_FUNCTION_ARGS);
extern Datum range_recv(PG_FUNCTION_ARGS);
......
......@@ -2378,7 +2378,7 @@ compute_function_hashkey(FunctionCallInfo fcinfo,
/*
* This is the same as the standard resolve_polymorphic_argtypes() function,
* but with a special case for validation: assume that polymorphic arguments
* are integer, integer-range or integer-array. Also, we go ahead and report
* are integer, integer-array or integer-range. Also, we go ahead and report
* the error if we can't resolve the types.
*/
static void
......@@ -2412,12 +2412,12 @@ plpgsql_resolve_polymorphic_argtypes(int numargs,
case ANYENUMOID: /* XXX dubious */
argtypes[i] = INT4OID;
break;
case ANYRANGEOID:
argtypes[i] = INT4RANGEOID;
break;
case ANYARRAYOID:
argtypes[i] = INT4ARRAYOID;
break;
case ANYRANGEOID:
argtypes[i] = INT4RANGEOID;
break;
default:
break;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment