2002-04-25 04:56:56 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* regproc.c
|
2002-04-25 04:56:56 +02:00
|
|
|
* Functions for the built-in types regproc, regclass, regtype, etc.
|
|
|
|
*
|
|
|
|
* These types are all binary-compatible with type Oid, and rely on Oid
|
|
|
|
* for comparison and so forth. Their only interesting behavior is in
|
|
|
|
* special I/O conversion routines.
|
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2012-01-02 00:01:58 +01:00
|
|
|
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/utils/adt/regproc.c
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
#include <ctype.h>
|
|
|
|
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "access/genam.h"
|
|
|
|
#include "access/heapam.h"
|
1998-10-02 07:10:11 +02:00
|
|
|
#include "catalog/indexing.h"
|
2002-04-25 04:56:56 +02:00
|
|
|
#include "catalog/namespace.h"
|
2008-06-19 02:46:06 +02:00
|
|
|
#include "catalog/pg_class.h"
|
2002-04-25 04:56:56 +02:00
|
|
|
#include "catalog/pg_operator.h"
|
1998-08-19 04:04:17 +02:00
|
|
|
#include "catalog/pg_proc.h"
|
2007-08-21 03:11:32 +02:00
|
|
|
#include "catalog/pg_ts_config.h"
|
|
|
|
#include "catalog/pg_ts_dict.h"
|
2002-04-25 04:56:56 +02:00
|
|
|
#include "catalog/pg_type.h"
|
2012-08-29 01:02:00 +02:00
|
|
|
#include "lib/stringinfo.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "miscadmin.h"
|
2002-04-25 04:56:56 +02:00
|
|
|
#include "parser/parse_type.h"
|
1999-07-16 05:14:30 +02:00
|
|
|
#include "utils/builtins.h"
|
2000-05-28 19:56:29 +02:00
|
|
|
#include "utils/fmgroids.h"
|
2002-04-25 04:56:56 +02:00
|
|
|
#include "utils/lsyscache.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "utils/syscache.h"
|
2008-03-26 22:10:39 +01:00
|
|
|
#include "utils/tqual.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2007-06-26 18:48:09 +02:00
|
|
|
static void parseNameAndArgTypes(const char *string, bool allowNone,
|
2002-09-04 22:31:48 +02:00
|
|
|
List **names, int *nargs, Oid *argtypes);
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* USER I/O ROUTINES *
|
1996-07-09 08:22:35 +02:00
|
|
|
*****************************************************************************/
|
1998-09-01 06:40:42 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/*
|
2002-04-25 04:56:56 +02:00
|
|
|
* regprocin - converts "proname" to proc OID
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
* We also accept a numeric OID, for symmetry with the output routine.
|
2001-08-21 18:36:06 +02:00
|
|
|
*
|
2002-04-25 04:56:56 +02:00
|
|
|
* '-' signifies unknown (OID 0). In all other cases, the input must
|
|
|
|
* match an existing pg_proc entry.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
regprocin(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-06-05 09:29:25 +02:00
|
|
|
char *pro_name_or_oid = PG_GETARG_CSTRING(0);
|
1999-05-25 18:15:34 +02:00
|
|
|
RegProcedure result = InvalidOid;
|
2002-04-25 04:56:56 +02:00
|
|
|
List *names;
|
|
|
|
FuncCandidateList clist;
|
1998-08-19 04:04:17 +02:00
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
/* '-' ? */
|
|
|
|
if (strcmp(pro_name_or_oid, "-") == 0)
|
2000-06-05 09:29:25 +02:00
|
|
|
PG_RETURN_OID(InvalidOid);
|
1998-08-19 04:04:17 +02:00
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
/* Numeric OID? */
|
2001-08-21 18:36:06 +02:00
|
|
|
if (pro_name_or_oid[0] >= '0' &&
|
2002-04-05 02:31:36 +02:00
|
|
|
pro_name_or_oid[0] <= '9' &&
|
|
|
|
strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
result = DatumGetObjectId(DirectFunctionCall1(oidin,
|
2005-10-15 04:49:52 +02:00
|
|
|
CStringGetDatum(pro_name_or_oid)));
|
2002-04-25 04:56:56 +02:00
|
|
|
PG_RETURN_OID(result);
|
2001-08-21 18:36:06 +02:00
|
|
|
}
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
/* Else it's a name, possibly schema-qualified */
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* In bootstrap mode we assume the given name is not schema-qualified, and
|
|
|
|
* just search pg_proc for a unique match. This is needed for
|
|
|
|
* initializing other system catalogs (pg_namespace may not exist yet, and
|
|
|
|
* certainly there are no schemas other than pg_catalog).
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
|
|
|
if (IsBootstrapProcessingMode())
|
2001-08-21 18:36:06 +02:00
|
|
|
{
|
2002-04-25 04:56:56 +02:00
|
|
|
int matches = 0;
|
2001-08-21 18:36:06 +02:00
|
|
|
Relation hdesc;
|
2002-04-05 02:31:36 +02:00
|
|
|
ScanKeyData skey[1];
|
2002-09-04 22:31:48 +02:00
|
|
|
SysScanDesc sysscan;
|
2002-04-05 02:31:36 +02:00
|
|
|
HeapTuple tuple;
|
2001-08-21 18:36:06 +02:00
|
|
|
|
2003-11-12 22:15:59 +01:00
|
|
|
ScanKeyInit(&skey[0],
|
|
|
|
Anum_pg_proc_proname,
|
|
|
|
BTEqualStrategyNumber, F_NAMEEQ,
|
|
|
|
CStringGetDatum(pro_name_or_oid));
|
1999-05-25 18:15:34 +02:00
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
hdesc = heap_open(ProcedureRelationId, AccessShareLock);
|
|
|
|
sysscan = systable_beginscan(hdesc, ProcedureNameArgsNspIndexId, true,
|
2002-04-25 04:56:56 +02:00
|
|
|
SnapshotNow, 1, skey);
|
2001-08-21 18:36:06 +02:00
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
while (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
|
1998-08-19 04:04:17 +02:00
|
|
|
{
|
2002-07-20 07:16:59 +02:00
|
|
|
result = (RegProcedure) HeapTupleGetOid(tuple);
|
2001-08-21 18:36:06 +02:00
|
|
|
if (++matches > 1)
|
|
|
|
break;
|
1998-08-19 04:04:17 +02:00
|
|
|
}
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
systable_endscan(sysscan);
|
2002-04-05 02:31:36 +02:00
|
|
|
heap_close(hdesc, AccessShareLock);
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
if (matches == 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("function \"%s\" does not exist", pro_name_or_oid)));
|
2003-07-27 06:53:12 +02:00
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
else if (matches > 1)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("more than one function named \"%s\"",
|
2003-08-04 02:43:34 +02:00
|
|
|
pro_name_or_oid)));
|
2003-07-27 06:53:12 +02:00
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
PG_RETURN_OID(result);
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
1998-08-19 04:04:17 +02:00
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Normal case: parse the name into components and see if it matches any
|
|
|
|
* pg_proc entries in the current search path.
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
2007-06-26 18:48:09 +02:00
|
|
|
names = stringToQualifiedNameList(pro_name_or_oid);
|
2009-10-08 04:39:25 +02:00
|
|
|
clist = FuncnameGetCandidates(names, -1, NIL, false, false);
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
if (clist == NULL)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("function \"%s\" does not exist", pro_name_or_oid)));
|
2002-04-25 04:56:56 +02:00
|
|
|
else if (clist->next != NULL)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("more than one function named \"%s\"",
|
2003-08-04 02:43:34 +02:00
|
|
|
pro_name_or_oid)));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
result = clist->oid;
|
2001-08-21 18:36:06 +02:00
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
PG_RETURN_OID(result);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2002-04-25 04:56:56 +02:00
|
|
|
* regprocout - converts proc OID to "pro_name"
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2000-06-05 09:29:25 +02:00
|
|
|
Datum
|
|
|
|
regprocout(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-06-05 09:29:25 +02:00
|
|
|
RegProcedure proid = PG_GETARG_OID(0);
|
1997-09-08 04:41:22 +02:00
|
|
|
char *result;
|
2002-04-25 04:56:56 +02:00
|
|
|
HeapTuple proctup;
|
|
|
|
|
|
|
|
if (proid == InvalidOid)
|
|
|
|
{
|
|
|
|
result = pstrdup("-");
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(proid));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
if (HeapTupleIsValid(proctup))
|
|
|
|
{
|
|
|
|
Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
|
|
|
|
char *proname = NameStr(procform->proname);
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* In bootstrap mode, skip the fancy namespace stuff and just return
|
|
|
|
* the proc name. (This path is only needed for debugging output
|
|
|
|
* anyway.)
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
|
|
|
if (IsBootstrapProcessingMode())
|
|
|
|
result = pstrdup(proname);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char *nspname;
|
|
|
|
FuncCandidateList clist;
|
|
|
|
|
|
|
|
/*
|
2002-09-04 22:31:48 +02:00
|
|
|
* Would this proc be found (uniquely!) by regprocin? If not,
|
|
|
|
* qualify it.
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
2008-07-16 03:30:23 +02:00
|
|
|
clist = FuncnameGetCandidates(list_make1(makeString(proname)),
|
2009-10-08 04:39:25 +02:00
|
|
|
-1, NIL, false, false);
|
2002-04-25 04:56:56 +02:00
|
|
|
if (clist != NULL && clist->next == NULL &&
|
|
|
|
clist->oid == proid)
|
|
|
|
nspname = NULL;
|
|
|
|
else
|
|
|
|
nspname = get_namespace_name(procform->pronamespace);
|
|
|
|
|
|
|
|
result = quote_qualified_identifier(nspname, proname);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReleaseSysCache(proctup);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If OID doesn't match any pg_proc entry, return it numerically */
|
|
|
|
result = (char *) palloc(NAMEDATALEN);
|
|
|
|
snprintf(result, NAMEDATALEN, "%u", proid);
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
/*
|
|
|
|
* regprocrecv - converts external binary format to regproc
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regprocrecv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Exactly the same as oidrecv, so share code */
|
|
|
|
return oidrecv(fcinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regprocsend - converts regproc to binary format
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regprocsend(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Exactly the same as oidsend, so share code */
|
|
|
|
return oidsend(fcinfo);
|
|
|
|
}
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* regprocedurein - converts "proname(args)" to proc OID
|
|
|
|
*
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
* We also accept a numeric OID, for symmetry with the output routine.
|
2002-04-25 04:56:56 +02:00
|
|
|
*
|
|
|
|
* '-' signifies unknown (OID 0). In all other cases, the input must
|
|
|
|
* match an existing pg_proc entry.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regprocedurein(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *pro_name_or_oid = PG_GETARG_CSTRING(0);
|
|
|
|
RegProcedure result = InvalidOid;
|
|
|
|
List *names;
|
|
|
|
int nargs;
|
|
|
|
Oid argtypes[FUNC_MAX_ARGS];
|
|
|
|
FuncCandidateList clist;
|
|
|
|
|
|
|
|
/* '-' ? */
|
|
|
|
if (strcmp(pro_name_or_oid, "-") == 0)
|
|
|
|
PG_RETURN_OID(InvalidOid);
|
|
|
|
|
|
|
|
/* Numeric OID? */
|
|
|
|
if (pro_name_or_oid[0] >= '0' &&
|
|
|
|
pro_name_or_oid[0] <= '9' &&
|
|
|
|
strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
|
|
|
|
{
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
result = DatumGetObjectId(DirectFunctionCall1(oidin,
|
2005-10-15 04:49:52 +02:00
|
|
|
CStringGetDatum(pro_name_or_oid)));
|
2002-04-25 04:56:56 +02:00
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Else it's a name and arguments. Parse the name and arguments, look up
|
|
|
|
* potential matches in the current namespace search list, and scan to see
|
|
|
|
* which one exactly matches the given argument types. (There will not be
|
|
|
|
* more than one match.)
|
2002-04-25 04:56:56 +02:00
|
|
|
*
|
|
|
|
* XXX at present, this code will not work in bootstrap mode, hence this
|
|
|
|
* datatype cannot be used for any system column that needs to receive
|
|
|
|
* data during bootstrap.
|
|
|
|
*/
|
2007-06-26 18:48:09 +02:00
|
|
|
parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes);
|
2002-04-25 04:56:56 +02:00
|
|
|
|
2009-10-08 04:39:25 +02:00
|
|
|
clist = FuncnameGetCandidates(names, nargs, NIL, false, false);
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
for (; clist; clist = clist->next)
|
|
|
|
{
|
|
|
|
if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (clist == NULL)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("function \"%s\" does not exist", pro_name_or_oid)));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
result = clist->oid;
|
|
|
|
|
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2002-07-30 00:14:11 +02:00
|
|
|
* format_procedure - converts proc OID to "pro_name(args)"
|
|
|
|
*
|
|
|
|
* This exports the useful functionality of regprocedureout for use
|
|
|
|
* in other backend modules. The result is a palloc'd string.
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
2002-07-30 00:14:11 +02:00
|
|
|
char *
|
|
|
|
format_procedure(Oid procedure_oid)
|
2002-04-25 04:56:56 +02:00
|
|
|
{
|
|
|
|
char *result;
|
|
|
|
HeapTuple proctup;
|
1998-08-19 04:04:17 +02:00
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2001-08-21 18:36:06 +02:00
|
|
|
if (HeapTupleIsValid(proctup))
|
|
|
|
{
|
2002-04-25 04:56:56 +02:00
|
|
|
Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
|
|
|
|
char *proname = NameStr(procform->proname);
|
|
|
|
int nargs = procform->pronargs;
|
|
|
|
int i;
|
|
|
|
char *nspname;
|
|
|
|
StringInfoData buf;
|
|
|
|
|
|
|
|
/* XXX no support here for bootstrap mode */
|
|
|
|
|
2002-05-02 01:06:41 +02:00
|
|
|
initStringInfo(&buf);
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Would this proc be found (given the right args) by regprocedurein?
|
|
|
|
* If not, we need to qualify it.
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
2002-07-30 00:14:11 +02:00
|
|
|
if (FunctionIsVisible(procedure_oid))
|
2002-04-25 04:56:56 +02:00
|
|
|
nspname = NULL;
|
|
|
|
else
|
|
|
|
nspname = get_namespace_name(procform->pronamespace);
|
|
|
|
|
|
|
|
appendStringInfo(&buf, "%s(",
|
|
|
|
quote_qualified_identifier(nspname, proname));
|
|
|
|
for (i = 0; i < nargs; i++)
|
|
|
|
{
|
2005-03-29 02:17:27 +02:00
|
|
|
Oid thisargtype = procform->proargtypes.values[i];
|
2002-04-25 04:56:56 +02:00
|
|
|
|
2002-05-11 02:24:16 +02:00
|
|
|
if (i > 0)
|
|
|
|
appendStringInfoChar(&buf, ',');
|
2004-01-31 06:09:41 +01:00
|
|
|
appendStringInfoString(&buf, format_type_be(thisargtype));
|
2002-05-11 02:24:16 +02:00
|
|
|
}
|
|
|
|
appendStringInfoChar(&buf, ')');
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
result = buf.data;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2001-08-21 18:36:06 +02:00
|
|
|
ReleaseSysCache(proctup);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1998-08-19 04:04:17 +02:00
|
|
|
else
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2002-04-25 04:56:56 +02:00
|
|
|
/* If OID doesn't match any pg_proc entry, return it numerically */
|
|
|
|
result = (char *) palloc(NAMEDATALEN);
|
2002-07-30 00:14:11 +02:00
|
|
|
snprintf(result, NAMEDATALEN, "%u", procedure_oid);
|
2002-04-25 04:56:56 +02:00
|
|
|
}
|
|
|
|
|
2002-07-30 00:14:11 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regprocedureout - converts proc OID to "pro_name(args)"
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regprocedureout(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
RegProcedure proid = PG_GETARG_OID(0);
|
|
|
|
char *result;
|
|
|
|
|
|
|
|
if (proid == InvalidOid)
|
|
|
|
result = pstrdup("-");
|
|
|
|
else
|
|
|
|
result = format_procedure(proid);
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
/*
|
|
|
|
* regprocedurerecv - converts external binary format to regprocedure
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regprocedurerecv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Exactly the same as oidrecv, so share code */
|
|
|
|
return oidrecv(fcinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regproceduresend - converts regprocedure to binary format
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regproceduresend(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Exactly the same as oidsend, so share code */
|
|
|
|
return oidsend(fcinfo);
|
|
|
|
}
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* regoperin - converts "oprname" to operator OID
|
|
|
|
*
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
* We also accept a numeric OID, for symmetry with the output routine.
|
2002-04-25 04:56:56 +02:00
|
|
|
*
|
|
|
|
* '0' signifies unknown (OID 0). In all other cases, the input must
|
|
|
|
* match an existing pg_operator entry.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regoperin(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *opr_name_or_oid = PG_GETARG_CSTRING(0);
|
|
|
|
Oid result = InvalidOid;
|
|
|
|
List *names;
|
|
|
|
FuncCandidateList clist;
|
|
|
|
|
|
|
|
/* '0' ? */
|
|
|
|
if (strcmp(opr_name_or_oid, "0") == 0)
|
|
|
|
PG_RETURN_OID(InvalidOid);
|
|
|
|
|
|
|
|
/* Numeric OID? */
|
|
|
|
if (opr_name_or_oid[0] >= '0' &&
|
|
|
|
opr_name_or_oid[0] <= '9' &&
|
|
|
|
strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
|
|
|
|
{
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
result = DatumGetObjectId(DirectFunctionCall1(oidin,
|
2005-10-15 04:49:52 +02:00
|
|
|
CStringGetDatum(opr_name_or_oid)));
|
2002-04-25 04:56:56 +02:00
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Else it's a name, possibly schema-qualified */
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* In bootstrap mode we assume the given name is not schema-qualified, and
|
|
|
|
* just search pg_operator for a unique match. This is needed for
|
|
|
|
* initializing other system catalogs (pg_namespace may not exist yet, and
|
|
|
|
* certainly there are no schemas other than pg_catalog).
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
|
|
|
if (IsBootstrapProcessingMode())
|
|
|
|
{
|
|
|
|
int matches = 0;
|
|
|
|
Relation hdesc;
|
|
|
|
ScanKeyData skey[1];
|
2002-09-04 22:31:48 +02:00
|
|
|
SysScanDesc sysscan;
|
2002-04-25 04:56:56 +02:00
|
|
|
HeapTuple tuple;
|
|
|
|
|
2003-11-12 22:15:59 +01:00
|
|
|
ScanKeyInit(&skey[0],
|
|
|
|
Anum_pg_operator_oprname,
|
|
|
|
BTEqualStrategyNumber, F_NAMEEQ,
|
|
|
|
CStringGetDatum(opr_name_or_oid));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
hdesc = heap_open(OperatorRelationId, AccessShareLock);
|
|
|
|
sysscan = systable_beginscan(hdesc, OperatorNameNspIndexId, true,
|
2002-04-25 04:56:56 +02:00
|
|
|
SnapshotNow, 1, skey);
|
|
|
|
|
|
|
|
while (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
|
|
|
|
{
|
2002-07-20 07:16:59 +02:00
|
|
|
result = HeapTupleGetOid(tuple);
|
2002-04-25 04:56:56 +02:00
|
|
|
if (++matches > 1)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
systable_endscan(sysscan);
|
|
|
|
heap_close(hdesc, AccessShareLock);
|
|
|
|
|
|
|
|
if (matches == 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("operator does not exist: %s", opr_name_or_oid)));
|
2002-04-25 04:56:56 +02:00
|
|
|
else if (matches > 1)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
|
|
|
|
errmsg("more than one operator named %s",
|
2003-08-04 02:43:34 +02:00
|
|
|
opr_name_or_oid)));
|
2003-07-27 06:53:12 +02:00
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Normal case: parse the name into components and see if it matches any
|
|
|
|
* pg_operator entries in the current search path.
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
2007-06-26 18:48:09 +02:00
|
|
|
names = stringToQualifiedNameList(opr_name_or_oid);
|
2002-04-25 04:56:56 +02:00
|
|
|
clist = OpernameGetCandidates(names, '\0');
|
|
|
|
|
|
|
|
if (clist == NULL)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("operator does not exist: %s", opr_name_or_oid)));
|
2002-04-25 04:56:56 +02:00
|
|
|
else if (clist->next != NULL)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
|
|
|
|
errmsg("more than one operator named %s",
|
2003-08-04 02:43:34 +02:00
|
|
|
opr_name_or_oid)));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
result = clist->oid;
|
|
|
|
|
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regoperout - converts operator OID to "opr_name"
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regoperout(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid oprid = PG_GETARG_OID(0);
|
|
|
|
char *result;
|
|
|
|
HeapTuple opertup;
|
|
|
|
|
|
|
|
if (oprid == InvalidOid)
|
|
|
|
{
|
|
|
|
result = pstrdup("0");
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
if (HeapTupleIsValid(opertup))
|
|
|
|
{
|
|
|
|
Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
|
|
|
|
char *oprname = NameStr(operform->oprname);
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* In bootstrap mode, skip the fancy namespace stuff and just return
|
|
|
|
* the oper name. (This path is only needed for debugging output
|
|
|
|
* anyway.)
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
|
|
|
if (IsBootstrapProcessingMode())
|
|
|
|
result = pstrdup(oprname);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FuncCandidateList clist;
|
|
|
|
|
|
|
|
/*
|
2002-09-04 22:31:48 +02:00
|
|
|
* Would this oper be found (uniquely!) by regoperin? If not,
|
|
|
|
* qualify it.
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
2004-05-31 01:40:41 +02:00
|
|
|
clist = OpernameGetCandidates(list_make1(makeString(oprname)),
|
2002-04-25 04:56:56 +02:00
|
|
|
'\0');
|
|
|
|
if (clist != NULL && clist->next == NULL &&
|
|
|
|
clist->oid == oprid)
|
|
|
|
result = pstrdup(oprname);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const char *nspname;
|
|
|
|
|
|
|
|
nspname = get_namespace_name(operform->oprnamespace);
|
|
|
|
nspname = quote_identifier(nspname);
|
2002-09-04 22:31:48 +02:00
|
|
|
result = (char *) palloc(strlen(nspname) + strlen(oprname) + 2);
|
2002-04-25 04:56:56 +02:00
|
|
|
sprintf(result, "%s.%s", nspname, oprname);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ReleaseSysCache(opertup);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If OID doesn't match any pg_operator entry, return it numerically
|
2002-09-04 22:31:48 +02:00
|
|
|
*/
|
2002-04-25 04:56:56 +02:00
|
|
|
result = (char *) palloc(NAMEDATALEN);
|
|
|
|
snprintf(result, NAMEDATALEN, "%u", oprid);
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
/*
|
|
|
|
* regoperrecv - converts external binary format to regoper
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regoperrecv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Exactly the same as oidrecv, so share code */
|
|
|
|
return oidrecv(fcinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regopersend - converts regoper to binary format
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regopersend(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Exactly the same as oidsend, so share code */
|
|
|
|
return oidsend(fcinfo);
|
|
|
|
}
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* regoperatorin - converts "oprname(args)" to operator OID
|
|
|
|
*
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
* We also accept a numeric OID, for symmetry with the output routine.
|
2002-04-25 04:56:56 +02:00
|
|
|
*
|
|
|
|
* '0' signifies unknown (OID 0). In all other cases, the input must
|
|
|
|
* match an existing pg_operator entry.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regoperatorin(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *opr_name_or_oid = PG_GETARG_CSTRING(0);
|
2006-05-02 01:22:43 +02:00
|
|
|
Oid result;
|
2002-04-25 04:56:56 +02:00
|
|
|
List *names;
|
|
|
|
int nargs;
|
|
|
|
Oid argtypes[FUNC_MAX_ARGS];
|
|
|
|
|
|
|
|
/* '0' ? */
|
|
|
|
if (strcmp(opr_name_or_oid, "0") == 0)
|
|
|
|
PG_RETURN_OID(InvalidOid);
|
|
|
|
|
|
|
|
/* Numeric OID? */
|
|
|
|
if (opr_name_or_oid[0] >= '0' &&
|
|
|
|
opr_name_or_oid[0] <= '9' &&
|
|
|
|
strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
|
|
|
|
{
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
result = DatumGetObjectId(DirectFunctionCall1(oidin,
|
2005-10-15 04:49:52 +02:00
|
|
|
CStringGetDatum(opr_name_or_oid)));
|
2002-04-25 04:56:56 +02:00
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Else it's a name and arguments. Parse the name and arguments, look up
|
|
|
|
* potential matches in the current namespace search list, and scan to see
|
|
|
|
* which one exactly matches the given argument types. (There will not be
|
|
|
|
* more than one match.)
|
2002-04-25 04:56:56 +02:00
|
|
|
*
|
|
|
|
* XXX at present, this code will not work in bootstrap mode, hence this
|
|
|
|
* datatype cannot be used for any system column that needs to receive
|
|
|
|
* data during bootstrap.
|
|
|
|
*/
|
2007-06-26 18:48:09 +02:00
|
|
|
parseNameAndArgTypes(opr_name_or_oid, true, &names, &nargs, argtypes);
|
2002-04-25 04:56:56 +02:00
|
|
|
if (nargs == 1)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_PARAMETER),
|
|
|
|
errmsg("missing argument"),
|
|
|
|
errhint("Use NONE to denote the missing argument of a unary operator.")));
|
2002-04-25 04:56:56 +02:00
|
|
|
if (nargs != 2)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
|
|
|
|
errmsg("too many arguments"),
|
|
|
|
errhint("Provide two argument types for operator.")));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
2006-05-02 01:22:43 +02:00
|
|
|
result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
|
2002-04-25 04:56:56 +02:00
|
|
|
|
2006-05-02 01:22:43 +02:00
|
|
|
if (!OidIsValid(result))
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
2003-09-25 08:58:07 +02:00
|
|
|
errmsg("operator does not exist: %s", opr_name_or_oid)));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2002-07-30 00:14:11 +02:00
|
|
|
* format_operator - converts operator OID to "opr_name(args)"
|
|
|
|
*
|
|
|
|
* This exports the useful functionality of regoperatorout for use
|
|
|
|
* in other backend modules. The result is a palloc'd string.
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
2002-07-30 00:14:11 +02:00
|
|
|
char *
|
|
|
|
format_operator(Oid operator_oid)
|
2002-04-25 04:56:56 +02:00
|
|
|
{
|
|
|
|
char *result;
|
|
|
|
HeapTuple opertup;
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
if (HeapTupleIsValid(opertup))
|
|
|
|
{
|
|
|
|
Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
|
|
|
|
char *oprname = NameStr(operform->oprname);
|
|
|
|
char *nspname;
|
|
|
|
StringInfoData buf;
|
|
|
|
|
|
|
|
/* XXX no support here for bootstrap mode */
|
|
|
|
|
2002-05-02 01:06:41 +02:00
|
|
|
initStringInfo(&buf);
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Would this oper be found (given the right args) by regoperatorin?
|
|
|
|
* If not, we need to qualify it.
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
2002-07-30 00:14:11 +02:00
|
|
|
if (!OperatorIsVisible(operator_oid))
|
2002-04-25 04:56:56 +02:00
|
|
|
{
|
|
|
|
nspname = get_namespace_name(operform->oprnamespace);
|
|
|
|
appendStringInfo(&buf, "%s.",
|
|
|
|
quote_identifier(nspname));
|
|
|
|
}
|
|
|
|
|
|
|
|
appendStringInfo(&buf, "%s(", oprname);
|
|
|
|
|
|
|
|
if (operform->oprleft)
|
|
|
|
appendStringInfo(&buf, "%s,",
|
|
|
|
format_type_be(operform->oprleft));
|
|
|
|
else
|
|
|
|
appendStringInfo(&buf, "NONE,");
|
|
|
|
|
|
|
|
if (operform->oprright)
|
|
|
|
appendStringInfo(&buf, "%s)",
|
|
|
|
format_type_be(operform->oprright));
|
|
|
|
else
|
|
|
|
appendStringInfo(&buf, "NONE)");
|
|
|
|
|
|
|
|
result = buf.data;
|
|
|
|
|
|
|
|
ReleaseSysCache(opertup);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If OID doesn't match any pg_operator entry, return it numerically
|
2002-09-04 22:31:48 +02:00
|
|
|
*/
|
2002-04-25 04:56:56 +02:00
|
|
|
result = (char *) palloc(NAMEDATALEN);
|
2002-07-30 00:14:11 +02:00
|
|
|
snprintf(result, NAMEDATALEN, "%u", operator_oid);
|
1998-08-19 04:04:17 +02:00
|
|
|
}
|
|
|
|
|
2002-07-30 00:14:11 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regoperatorout - converts operator OID to "opr_name(args)"
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regoperatorout(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid oprid = PG_GETARG_OID(0);
|
|
|
|
char *result;
|
|
|
|
|
|
|
|
if (oprid == InvalidOid)
|
|
|
|
result = pstrdup("0");
|
|
|
|
else
|
|
|
|
result = format_operator(oprid);
|
|
|
|
|
2000-06-05 09:29:25 +02:00
|
|
|
PG_RETURN_CSTRING(result);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
/*
|
|
|
|
* regoperatorrecv - converts external binary format to regoperator
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regoperatorrecv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Exactly the same as oidrecv, so share code */
|
|
|
|
return oidrecv(fcinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regoperatorsend - converts regoperator to binary format
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regoperatorsend(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Exactly the same as oidsend, so share code */
|
|
|
|
return oidsend(fcinfo);
|
|
|
|
}
|
|
|
|
|
1997-11-15 17:32:25 +01:00
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
/*
|
|
|
|
* regclassin - converts "classname" to class OID
|
|
|
|
*
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
* We also accept a numeric OID, for symmetry with the output routine.
|
2002-04-25 04:56:56 +02:00
|
|
|
*
|
|
|
|
* '-' signifies unknown (OID 0). In all other cases, the input must
|
|
|
|
* match an existing pg_class entry.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regclassin(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *class_name_or_oid = PG_GETARG_CSTRING(0);
|
|
|
|
Oid result = InvalidOid;
|
|
|
|
List *names;
|
|
|
|
|
|
|
|
/* '-' ? */
|
|
|
|
if (strcmp(class_name_or_oid, "-") == 0)
|
|
|
|
PG_RETURN_OID(InvalidOid);
|
|
|
|
|
|
|
|
/* Numeric OID? */
|
|
|
|
if (class_name_or_oid[0] >= '0' &&
|
|
|
|
class_name_or_oid[0] <= '9' &&
|
2005-10-15 04:49:52 +02:00
|
|
|
strspn(class_name_or_oid, "0123456789") == strlen(class_name_or_oid))
|
2002-04-25 04:56:56 +02:00
|
|
|
{
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
result = DatumGetObjectId(DirectFunctionCall1(oidin,
|
2005-10-15 04:49:52 +02:00
|
|
|
CStringGetDatum(class_name_or_oid)));
|
2002-04-25 04:56:56 +02:00
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Else it's a name, possibly schema-qualified */
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* In bootstrap mode we assume the given name is not schema-qualified, and
|
|
|
|
* just search pg_class for a match. This is needed for initializing
|
|
|
|
* other system catalogs (pg_namespace may not exist yet, and certainly
|
|
|
|
* there are no schemas other than pg_catalog).
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
|
|
|
if (IsBootstrapProcessingMode())
|
|
|
|
{
|
|
|
|
Relation hdesc;
|
|
|
|
ScanKeyData skey[1];
|
2002-09-04 22:31:48 +02:00
|
|
|
SysScanDesc sysscan;
|
2002-04-25 04:56:56 +02:00
|
|
|
HeapTuple tuple;
|
|
|
|
|
2003-11-12 22:15:59 +01:00
|
|
|
ScanKeyInit(&skey[0],
|
|
|
|
Anum_pg_class_relname,
|
|
|
|
BTEqualStrategyNumber, F_NAMEEQ,
|
|
|
|
CStringGetDatum(class_name_or_oid));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
hdesc = heap_open(RelationRelationId, AccessShareLock);
|
|
|
|
sysscan = systable_beginscan(hdesc, ClassNameNspIndexId, true,
|
2002-04-25 04:56:56 +02:00
|
|
|
SnapshotNow, 1, skey);
|
|
|
|
|
|
|
|
if (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
|
2002-07-20 07:16:59 +02:00
|
|
|
result = HeapTupleGetOid(tuple);
|
2002-04-25 04:56:56 +02:00
|
|
|
else
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_TABLE),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("relation \"%s\" does not exist", class_name_or_oid)));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
/* We assume there can be only one match */
|
|
|
|
|
|
|
|
systable_endscan(sysscan);
|
|
|
|
heap_close(hdesc, AccessShareLock);
|
|
|
|
|
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Normal case: parse the name into components and see if it matches any
|
|
|
|
* pg_class entries in the current search path.
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
2007-06-26 18:48:09 +02:00
|
|
|
names = stringToQualifiedNameList(class_name_or_oid);
|
2002-04-25 04:56:56 +02:00
|
|
|
|
2011-07-09 04:19:30 +02:00
|
|
|
/* We might not even have permissions on this relation; don't lock it. */
|
Improve table locking behavior in the face of current DDL.
In the previous coding, callers were faced with an awkward choice:
look up the name, do permissions checks, and then lock the table; or
look up the name, lock the table, and then do permissions checks.
The first choice was wrong because the results of the name lookup
and permissions checks might be out-of-date by the time the table
lock was acquired, while the second allowed a user with no privileges
to interfere with access to a table by users who do have privileges
(e.g. if a malicious backend queues up for an AccessExclusiveLock on
a table on which AccessShareLock is already held, further attempts
to access the table will be blocked until the AccessExclusiveLock
is obtained and the malicious backend's transaction rolls back).
To fix, allow callers of RangeVarGetRelid() to pass a callback which
gets executed after performing the name lookup but before acquiring
the relation lock. If the name lookup is retried (because
invalidation messages are received), the callback will be re-executed
as well, so we get the best of both worlds. RangeVarGetRelid() is
renamed to RangeVarGetRelidExtended(); callers not wishing to supply
a callback can continue to invoke it as RangeVarGetRelid(), which is
now a macro. Since the only one caller that uses nowait = true now
passes a callback anyway, the RangeVarGetRelid() macro defaults nowait
as well. The callback can also be used for supplemental locking - for
example, REINDEX INDEX needs to acquire the table lock before the index
lock to reduce deadlock possibilities.
There's a lot more work to be done here to fix all the cases where this
can be a problem, but this commit provides the general infrastructure
and fixes the following specific cases: REINDEX INDEX, REINDEX TABLE,
LOCK TABLE, and and DROP TABLE/INDEX/SEQUENCE/VIEW/FOREIGN TABLE.
Per discussion with Noah Misch and Alvaro Herrera.
2011-11-30 16:12:27 +01:00
|
|
|
result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, false);
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regclassout - converts class OID to "class_name"
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regclassout(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid classid = PG_GETARG_OID(0);
|
|
|
|
char *result;
|
|
|
|
HeapTuple classtup;
|
|
|
|
|
|
|
|
if (classid == InvalidOid)
|
|
|
|
{
|
|
|
|
result = pstrdup("-");
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(classid));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
if (HeapTupleIsValid(classtup))
|
|
|
|
{
|
|
|
|
Form_pg_class classform = (Form_pg_class) GETSTRUCT(classtup);
|
|
|
|
char *classname = NameStr(classform->relname);
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* In bootstrap mode, skip the fancy namespace stuff and just return
|
|
|
|
* the class name. (This path is only needed for debugging output
|
|
|
|
* anyway.)
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
|
|
|
if (IsBootstrapProcessingMode())
|
|
|
|
result = pstrdup(classname);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char *nspname;
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Would this class be found by regclassin? If not, qualify it.
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
2002-05-02 01:06:41 +02:00
|
|
|
if (RelationIsVisible(classid))
|
2002-04-25 04:56:56 +02:00
|
|
|
nspname = NULL;
|
|
|
|
else
|
|
|
|
nspname = get_namespace_name(classform->relnamespace);
|
|
|
|
|
|
|
|
result = quote_qualified_identifier(nspname, classname);
|
|
|
|
}
|
|
|
|
|
|
|
|
ReleaseSysCache(classtup);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If OID doesn't match any pg_class entry, return it numerically */
|
|
|
|
result = (char *) palloc(NAMEDATALEN);
|
|
|
|
snprintf(result, NAMEDATALEN, "%u", classid);
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
/*
|
|
|
|
* regclassrecv - converts external binary format to regclass
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regclassrecv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Exactly the same as oidrecv, so share code */
|
|
|
|
return oidrecv(fcinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regclasssend - converts regclass to binary format
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regclasssend(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Exactly the same as oidsend, so share code */
|
|
|
|
return oidsend(fcinfo);
|
|
|
|
}
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* regtypein - converts "typename" to type OID
|
|
|
|
*
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
* We also accept a numeric OID, for symmetry with the output routine.
|
2002-04-25 04:56:56 +02:00
|
|
|
*
|
|
|
|
* '-' signifies unknown (OID 0). In all other cases, the input must
|
|
|
|
* match an existing pg_type entry.
|
|
|
|
*
|
|
|
|
* In bootstrap mode the name must just equal some existing name in pg_type.
|
|
|
|
* In normal mode the type name can be specified using the full type syntax
|
|
|
|
* recognized by the parser; for example, DOUBLE PRECISION and INTEGER[] will
|
|
|
|
* work and be translated to the correct type names. (We ignore any typmod
|
|
|
|
* info generated by the parser, however.)
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regtypein(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *typ_name_or_oid = PG_GETARG_CSTRING(0);
|
|
|
|
Oid result = InvalidOid;
|
|
|
|
int32 typmod;
|
|
|
|
|
|
|
|
/* '-' ? */
|
|
|
|
if (strcmp(typ_name_or_oid, "-") == 0)
|
|
|
|
PG_RETURN_OID(InvalidOid);
|
|
|
|
|
|
|
|
/* Numeric OID? */
|
|
|
|
if (typ_name_or_oid[0] >= '0' &&
|
|
|
|
typ_name_or_oid[0] <= '9' &&
|
|
|
|
strspn(typ_name_or_oid, "0123456789") == strlen(typ_name_or_oid))
|
|
|
|
{
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
2002-09-18 23:35:25 +02:00
|
|
|
result = DatumGetObjectId(DirectFunctionCall1(oidin,
|
2005-10-15 04:49:52 +02:00
|
|
|
CStringGetDatum(typ_name_or_oid)));
|
2002-04-25 04:56:56 +02:00
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Else it's a type name, possibly schema-qualified or decorated */
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* In bootstrap mode we assume the given name is not schema-qualified, and
|
|
|
|
* just search pg_type for a match. This is needed for initializing other
|
|
|
|
* system catalogs (pg_namespace may not exist yet, and certainly there
|
|
|
|
* are no schemas other than pg_catalog).
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
|
|
|
if (IsBootstrapProcessingMode())
|
|
|
|
{
|
|
|
|
Relation hdesc;
|
|
|
|
ScanKeyData skey[1];
|
2002-09-04 22:31:48 +02:00
|
|
|
SysScanDesc sysscan;
|
2002-04-25 04:56:56 +02:00
|
|
|
HeapTuple tuple;
|
|
|
|
|
2003-11-12 22:15:59 +01:00
|
|
|
ScanKeyInit(&skey[0],
|
|
|
|
Anum_pg_type_typname,
|
|
|
|
BTEqualStrategyNumber, F_NAMEEQ,
|
|
|
|
CStringGetDatum(typ_name_or_oid));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
2005-04-14 22:03:27 +02:00
|
|
|
hdesc = heap_open(TypeRelationId, AccessShareLock);
|
|
|
|
sysscan = systable_beginscan(hdesc, TypeNameNspIndexId, true,
|
2002-04-25 04:56:56 +02:00
|
|
|
SnapshotNow, 1, skey);
|
|
|
|
|
|
|
|
if (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
|
2002-07-20 07:16:59 +02:00
|
|
|
result = HeapTupleGetOid(tuple);
|
2002-04-25 04:56:56 +02:00
|
|
|
else
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("type \"%s\" does not exist", typ_name_or_oid)));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
/* We assume there can be only one match */
|
|
|
|
|
|
|
|
systable_endscan(sysscan);
|
|
|
|
heap_close(hdesc, AccessShareLock);
|
|
|
|
|
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Normal case: invoke the full parser to deal with special cases such as
|
|
|
|
* array syntax.
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
|
|
|
parseTypeString(typ_name_or_oid, &result, &typmod);
|
|
|
|
|
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regtypeout - converts type OID to "typ_name"
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regtypeout(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid typid = PG_GETARG_OID(0);
|
|
|
|
char *result;
|
|
|
|
HeapTuple typetup;
|
|
|
|
|
|
|
|
if (typid == InvalidOid)
|
|
|
|
{
|
|
|
|
result = pstrdup("-");
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
if (HeapTupleIsValid(typetup))
|
|
|
|
{
|
|
|
|
Form_pg_type typeform = (Form_pg_type) GETSTRUCT(typetup);
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* In bootstrap mode, skip the fancy namespace stuff and just return
|
|
|
|
* the type name. (This path is only needed for debugging output
|
|
|
|
* anyway.)
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
|
|
|
if (IsBootstrapProcessingMode())
|
|
|
|
{
|
2002-05-02 01:06:41 +02:00
|
|
|
char *typname = NameStr(typeform->typname);
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
result = pstrdup(typname);
|
|
|
|
}
|
|
|
|
else
|
2002-05-02 01:06:41 +02:00
|
|
|
result = format_type_be(typid);
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
ReleaseSysCache(typetup);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If OID doesn't match any pg_type entry, return it numerically */
|
|
|
|
result = (char *) palloc(NAMEDATALEN);
|
|
|
|
snprintf(result, NAMEDATALEN, "%u", typid);
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
|
|
|
|
2003-05-13 01:08:52 +02:00
|
|
|
/*
|
|
|
|
* regtyperecv - converts external binary format to regtype
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regtyperecv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Exactly the same as oidrecv, so share code */
|
|
|
|
return oidrecv(fcinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regtypesend - converts regtype to binary format
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regtypesend(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Exactly the same as oidsend, so share code */
|
|
|
|
return oidsend(fcinfo);
|
|
|
|
}
|
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2007-08-21 03:11:32 +02:00
|
|
|
/*
|
|
|
|
* regconfigin - converts "tsconfigname" to tsconfig OID
|
|
|
|
*
|
|
|
|
* We also accept a numeric OID, for symmetry with the output routine.
|
|
|
|
*
|
|
|
|
* '-' signifies unknown (OID 0). In all other cases, the input must
|
|
|
|
* match an existing pg_ts_config entry.
|
|
|
|
*
|
|
|
|
* This function is not needed in bootstrap mode, so we don't worry about
|
|
|
|
* making it work then.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regconfigin(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *cfg_name_or_oid = PG_GETARG_CSTRING(0);
|
|
|
|
Oid result;
|
|
|
|
List *names;
|
|
|
|
|
|
|
|
/* '-' ? */
|
|
|
|
if (strcmp(cfg_name_or_oid, "-") == 0)
|
|
|
|
PG_RETURN_OID(InvalidOid);
|
|
|
|
|
|
|
|
/* Numeric OID? */
|
|
|
|
if (cfg_name_or_oid[0] >= '0' &&
|
|
|
|
cfg_name_or_oid[0] <= '9' &&
|
|
|
|
strspn(cfg_name_or_oid, "0123456789") == strlen(cfg_name_or_oid))
|
|
|
|
{
|
|
|
|
result = DatumGetObjectId(DirectFunctionCall1(oidin,
|
|
|
|
CStringGetDatum(cfg_name_or_oid)));
|
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Normal case: parse the name into components and see if it matches any
|
|
|
|
* pg_ts_config entries in the current search path.
|
|
|
|
*/
|
|
|
|
names = stringToQualifiedNameList(cfg_name_or_oid);
|
|
|
|
|
2010-08-05 17:25:36 +02:00
|
|
|
result = get_ts_config_oid(names, false);
|
2007-08-21 03:11:32 +02:00
|
|
|
|
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regconfigout - converts tsconfig OID to "tsconfigname"
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regconfigout(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid cfgid = PG_GETARG_OID(0);
|
|
|
|
char *result;
|
|
|
|
HeapTuple cfgtup;
|
|
|
|
|
|
|
|
if (cfgid == InvalidOid)
|
|
|
|
{
|
|
|
|
result = pstrdup("-");
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
cfgtup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
|
2007-08-21 03:11:32 +02:00
|
|
|
|
|
|
|
if (HeapTupleIsValid(cfgtup))
|
|
|
|
{
|
|
|
|
Form_pg_ts_config cfgform = (Form_pg_ts_config) GETSTRUCT(cfgtup);
|
|
|
|
char *cfgname = NameStr(cfgform->cfgname);
|
|
|
|
char *nspname;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Would this config be found by regconfigin? If not, qualify it.
|
|
|
|
*/
|
|
|
|
if (TSConfigIsVisible(cfgid))
|
|
|
|
nspname = NULL;
|
|
|
|
else
|
|
|
|
nspname = get_namespace_name(cfgform->cfgnamespace);
|
|
|
|
|
|
|
|
result = quote_qualified_identifier(nspname, cfgname);
|
|
|
|
|
|
|
|
ReleaseSysCache(cfgtup);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If OID doesn't match any pg_ts_config row, return it numerically */
|
|
|
|
result = (char *) palloc(NAMEDATALEN);
|
|
|
|
snprintf(result, NAMEDATALEN, "%u", cfgid);
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regconfigrecv - converts external binary format to regconfig
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regconfigrecv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Exactly the same as oidrecv, so share code */
|
|
|
|
return oidrecv(fcinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regconfigsend - converts regconfig to binary format
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regconfigsend(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Exactly the same as oidsend, so share code */
|
|
|
|
return oidsend(fcinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regdictionaryin - converts "tsdictionaryname" to tsdictionary OID
|
|
|
|
*
|
|
|
|
* We also accept a numeric OID, for symmetry with the output routine.
|
|
|
|
*
|
|
|
|
* '-' signifies unknown (OID 0). In all other cases, the input must
|
|
|
|
* match an existing pg_ts_dict entry.
|
|
|
|
*
|
|
|
|
* This function is not needed in bootstrap mode, so we don't worry about
|
|
|
|
* making it work then.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regdictionaryin(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *dict_name_or_oid = PG_GETARG_CSTRING(0);
|
|
|
|
Oid result;
|
|
|
|
List *names;
|
|
|
|
|
|
|
|
/* '-' ? */
|
|
|
|
if (strcmp(dict_name_or_oid, "-") == 0)
|
|
|
|
PG_RETURN_OID(InvalidOid);
|
|
|
|
|
|
|
|
/* Numeric OID? */
|
|
|
|
if (dict_name_or_oid[0] >= '0' &&
|
|
|
|
dict_name_or_oid[0] <= '9' &&
|
|
|
|
strspn(dict_name_or_oid, "0123456789") == strlen(dict_name_or_oid))
|
|
|
|
{
|
|
|
|
result = DatumGetObjectId(DirectFunctionCall1(oidin,
|
2007-11-15 22:14:46 +01:00
|
|
|
CStringGetDatum(dict_name_or_oid)));
|
2007-08-21 03:11:32 +02:00
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Normal case: parse the name into components and see if it matches any
|
|
|
|
* pg_ts_dict entries in the current search path.
|
|
|
|
*/
|
|
|
|
names = stringToQualifiedNameList(dict_name_or_oid);
|
|
|
|
|
2010-08-05 17:25:36 +02:00
|
|
|
result = get_ts_dict_oid(names, false);
|
2007-08-21 03:11:32 +02:00
|
|
|
|
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regdictionaryout - converts tsdictionary OID to "tsdictionaryname"
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regdictionaryout(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
Oid dictid = PG_GETARG_OID(0);
|
|
|
|
char *result;
|
|
|
|
HeapTuple dicttup;
|
|
|
|
|
|
|
|
if (dictid == InvalidOid)
|
|
|
|
{
|
|
|
|
result = pstrdup("-");
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
|
|
|
|
2010-02-14 19:42:19 +01:00
|
|
|
dicttup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictid));
|
2007-08-21 03:11:32 +02:00
|
|
|
|
|
|
|
if (HeapTupleIsValid(dicttup))
|
|
|
|
{
|
|
|
|
Form_pg_ts_dict dictform = (Form_pg_ts_dict) GETSTRUCT(dicttup);
|
|
|
|
char *dictname = NameStr(dictform->dictname);
|
|
|
|
char *nspname;
|
|
|
|
|
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Would this dictionary be found by regdictionaryin? If not, qualify
|
|
|
|
* it.
|
2007-08-21 03:11:32 +02:00
|
|
|
*/
|
|
|
|
if (TSDictionaryIsVisible(dictid))
|
|
|
|
nspname = NULL;
|
|
|
|
else
|
|
|
|
nspname = get_namespace_name(dictform->dictnamespace);
|
|
|
|
|
|
|
|
result = quote_qualified_identifier(nspname, dictname);
|
|
|
|
|
|
|
|
ReleaseSysCache(dicttup);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If OID doesn't match any pg_ts_dict row, return it numerically */
|
|
|
|
result = (char *) palloc(NAMEDATALEN);
|
|
|
|
snprintf(result, NAMEDATALEN, "%u", dictid);
|
|
|
|
}
|
|
|
|
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regdictionaryrecv - converts external binary format to regdictionary
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regdictionaryrecv(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Exactly the same as oidrecv, so share code */
|
|
|
|
return oidrecv(fcinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* regdictionarysend - converts regdictionary to binary format
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
regdictionarysend(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
/* Exactly the same as oidsend, so share code */
|
|
|
|
return oidsend(fcinfo);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-10-03 01:50:16 +02:00
|
|
|
/*
|
|
|
|
* text_regclass: convert text to regclass
|
2007-06-05 23:31:09 +02:00
|
|
|
*
|
|
|
|
* This could be replaced by CoerceViaIO, except that we need to treat
|
|
|
|
* text-to-regclass as an implicit cast to support legacy forms of nextval()
|
|
|
|
* and related functions.
|
2005-10-03 01:50:16 +02:00
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
text_regclass(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
text *relname = PG_GETARG_TEXT_P(0);
|
|
|
|
Oid result;
|
|
|
|
RangeVar *rv;
|
|
|
|
|
|
|
|
rv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
|
2011-07-09 04:19:30 +02:00
|
|
|
|
|
|
|
/* We might not even have permissions on this relation; don't lock it. */
|
Improve table locking behavior in the face of current DDL.
In the previous coding, callers were faced with an awkward choice:
look up the name, do permissions checks, and then lock the table; or
look up the name, lock the table, and then do permissions checks.
The first choice was wrong because the results of the name lookup
and permissions checks might be out-of-date by the time the table
lock was acquired, while the second allowed a user with no privileges
to interfere with access to a table by users who do have privileges
(e.g. if a malicious backend queues up for an AccessExclusiveLock on
a table on which AccessShareLock is already held, further attempts
to access the table will be blocked until the AccessExclusiveLock
is obtained and the malicious backend's transaction rolls back).
To fix, allow callers of RangeVarGetRelid() to pass a callback which
gets executed after performing the name lookup but before acquiring
the relation lock. If the name lookup is retried (because
invalidation messages are received), the callback will be re-executed
as well, so we get the best of both worlds. RangeVarGetRelid() is
renamed to RangeVarGetRelidExtended(); callers not wishing to supply
a callback can continue to invoke it as RangeVarGetRelid(), which is
now a macro. Since the only one caller that uses nowait = true now
passes a callback anyway, the RangeVarGetRelid() macro defaults nowait
as well. The callback can also be used for supplemental locking - for
example, REINDEX INDEX needs to acquire the table lock before the index
lock to reduce deadlock possibilities.
There's a lot more work to be done here to fix all the cases where this
can be a problem, but this commit provides the general infrastructure
and fixes the following specific cases: REINDEX INDEX, REINDEX TABLE,
LOCK TABLE, and and DROP TABLE/INDEX/SEQUENCE/VIEW/FOREIGN TABLE.
Per discussion with Noah Misch and Alvaro Herrera.
2011-11-30 16:12:27 +01:00
|
|
|
result = RangeVarGetRelid(rv, NoLock, false);
|
2005-10-03 01:50:16 +02:00
|
|
|
|
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
/*
|
|
|
|
* Given a C string, parse it into a qualified-name list.
|
1997-04-27 21:20:16 +02:00
|
|
|
*/
|
2002-06-20 19:19:08 +02:00
|
|
|
List *
|
2007-06-26 18:48:09 +02:00
|
|
|
stringToQualifiedNameList(const char *string)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2002-04-25 04:56:56 +02:00
|
|
|
char *rawname;
|
|
|
|
List *result = NIL;
|
|
|
|
List *namelist;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *l;
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
/* We need a modifiable copy of the input string. */
|
|
|
|
rawname = pstrdup(string);
|
|
|
|
|
|
|
|
if (!SplitIdentifierString(rawname, '.', &namelist))
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_NAME),
|
|
|
|
errmsg("invalid name syntax")));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
if (namelist == NIL)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_NAME),
|
|
|
|
errmsg("invalid name syntax")));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
foreach(l, namelist)
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
char *curname = (char *) lfirst(l);
|
2000-06-05 09:29:25 +02:00
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
result = lappend(result, makeString(pstrdup(curname)));
|
|
|
|
}
|
|
|
|
|
|
|
|
pfree(rawname);
|
2004-05-31 01:40:41 +02:00
|
|
|
list_free(namelist);
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
return result;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2002-06-20 19:19:08 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* SUPPORT ROUTINES *
|
|
|
|
*****************************************************************************/
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
/*
|
|
|
|
* Given a C string, parse it into a qualified function or operator name
|
2002-09-04 22:31:48 +02:00
|
|
|
* followed by a parenthesized list of type names. Reduce the
|
2002-04-25 04:56:56 +02:00
|
|
|
* type names to an array of OIDs (returned into *nargs and *argtypes;
|
|
|
|
* the argtypes array should be of size FUNC_MAX_ARGS). The function or
|
|
|
|
* operator name is returned to *names as a List of Strings.
|
|
|
|
*
|
2002-08-22 02:01:51 +02:00
|
|
|
* If allowNone is TRUE, accept "NONE" and return it as InvalidOid (this is
|
|
|
|
* for unary operators).
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
|
|
|
static void
|
2007-06-26 18:48:09 +02:00
|
|
|
parseNameAndArgTypes(const char *string, bool allowNone, List **names,
|
|
|
|
int *nargs, Oid *argtypes)
|
2002-04-25 04:56:56 +02:00
|
|
|
{
|
|
|
|
char *rawname;
|
|
|
|
char *ptr;
|
|
|
|
char *ptr2;
|
|
|
|
char *typename;
|
|
|
|
bool in_quote;
|
|
|
|
bool had_comma;
|
|
|
|
int paren_count;
|
|
|
|
Oid typeid;
|
|
|
|
int32 typmod;
|
|
|
|
|
|
|
|
/* We need a modifiable copy of the input string. */
|
|
|
|
rawname = pstrdup(string);
|
|
|
|
|
|
|
|
/* Scan to find the expected left paren; mustn't be quoted */
|
|
|
|
in_quote = false;
|
|
|
|
for (ptr = rawname; *ptr; ptr++)
|
|
|
|
{
|
|
|
|
if (*ptr == '"')
|
|
|
|
in_quote = !in_quote;
|
|
|
|
else if (*ptr == '(' && !in_quote)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (*ptr == '\0')
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("expected a left parenthesis")));
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
/* Separate the name and parse it into a list */
|
|
|
|
*ptr++ = '\0';
|
2007-06-26 18:48:09 +02:00
|
|
|
*names = stringToQualifiedNameList(rawname);
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
/* Check for the trailing right parenthesis and remove it */
|
|
|
|
ptr2 = ptr + strlen(ptr);
|
|
|
|
while (--ptr2 > ptr)
|
|
|
|
{
|
|
|
|
if (!isspace((unsigned char) *ptr2))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (*ptr2 != ')')
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("expected a right parenthesis")));
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
*ptr2 = '\0';
|
|
|
|
|
|
|
|
/* Separate the remaining string into comma-separated type names */
|
|
|
|
*nargs = 0;
|
|
|
|
had_comma = false;
|
|
|
|
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
/* allow leading whitespace */
|
|
|
|
while (isspace((unsigned char) *ptr))
|
|
|
|
ptr++;
|
|
|
|
if (*ptr == '\0')
|
|
|
|
{
|
|
|
|
/* End of string. Okay unless we had a comma before. */
|
|
|
|
if (had_comma)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("expected a type name")));
|
2002-04-25 04:56:56 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
typename = ptr;
|
|
|
|
/* Find end of type name --- end of string or comma */
|
|
|
|
/* ... but not a quoted or parenthesized comma */
|
|
|
|
in_quote = false;
|
|
|
|
paren_count = 0;
|
|
|
|
for (; *ptr; ptr++)
|
|
|
|
{
|
|
|
|
if (*ptr == '"')
|
|
|
|
in_quote = !in_quote;
|
|
|
|
else if (*ptr == ',' && !in_quote && paren_count == 0)
|
|
|
|
break;
|
|
|
|
else if (!in_quote)
|
|
|
|
{
|
|
|
|
switch (*ptr)
|
|
|
|
{
|
|
|
|
case '(':
|
|
|
|
case '[':
|
|
|
|
paren_count++;
|
|
|
|
break;
|
|
|
|
case ')':
|
|
|
|
case ']':
|
|
|
|
paren_count--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (in_quote || paren_count != 0)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
|
|
|
errmsg("improper type name")));
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
ptr2 = ptr;
|
|
|
|
if (*ptr == ',')
|
|
|
|
{
|
|
|
|
had_comma = true;
|
|
|
|
*ptr++ = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
had_comma = false;
|
|
|
|
Assert(*ptr == '\0');
|
|
|
|
}
|
|
|
|
/* Lop off trailing whitespace */
|
|
|
|
while (--ptr2 >= typename)
|
|
|
|
{
|
|
|
|
if (!isspace((unsigned char) *ptr2))
|
|
|
|
break;
|
|
|
|
*ptr2 = '\0';
|
|
|
|
}
|
|
|
|
|
2004-05-07 02:24:59 +02:00
|
|
|
if (allowNone && pg_strcasecmp(typename, "none") == 0)
|
2002-04-25 04:56:56 +02:00
|
|
|
{
|
2002-08-22 02:01:51 +02:00
|
|
|
/* Special case for NONE */
|
2002-04-25 04:56:56 +02:00
|
|
|
typeid = InvalidOid;
|
|
|
|
typmod = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Use full parser to resolve the type name */
|
|
|
|
parseTypeString(typename, &typeid, &typmod);
|
|
|
|
}
|
|
|
|
if (*nargs >= FUNC_MAX_ARGS)
|
2003-07-27 06:53:12 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
|
2003-07-28 02:09:16 +02:00
|
|
|
errmsg("too many arguments")));
|
2003-07-27 06:53:12 +02:00
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
argtypes[*nargs] = typeid;
|
|
|
|
(*nargs)++;
|
|
|
|
}
|
|
|
|
|
|
|
|
pfree(rawname);
|
|
|
|
}
|