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
|
|
|
*
|
2014-01-07 22:05:30 +01:00
|
|
|
* Portions Copyright (c) 1996-2014, 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"
|
2012-08-30 22:15:44 +02:00
|
|
|
#include "access/htup_details.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
|
|
|
|
2013-03-20 22:19:19 +01:00
|
|
|
static char *format_operator_internal(Oid operator_oid, bool force_qualify);
|
|
|
|
static char *format_procedure_internal(Oid procedure_oid, bool force_qualify);
|
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,
|
Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.
SnapshotNow scans have the undesirable property that, in the face of
concurrent updates, the scan can fail to see either the old or the new
versions of the row. In many cases, we work around this by requiring
DDL operations to hold AccessExclusiveLock on the object being
modified; in some cases, the existing locking is inadequate and random
failures occur as a result. This commit doesn't change anything
related to locking, but will hopefully pave the way to allowing lock
strength reductions in the future.
The major issue has held us back from making this change in the past
is that taking an MVCC snapshot is significantly more expensive than
using a static special snapshot such as SnapshotNow. However, testing
of various worst-case scenarios reveals that this problem is not
severe except under fairly extreme workloads. To mitigate those
problems, we avoid retaking the MVCC snapshot for each new scan;
instead, we take a new snapshot only when invalidation messages have
been processed. The catcache machinery already requires that
invalidation messages be sent before releasing the related heavyweight
lock; else other backends might rely on locally-cached data rather
than scanning the catalog at all. Thus, making snapshot reuse
dependent on the same guarantees shouldn't break anything that wasn't
already subtly broken.
Patch by me. Review by Michael Paquier and Andres Freund.
2013-07-02 15:47:01 +02:00
|
|
|
NULL, 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);
|
2014-01-23 18:40:29 +01:00
|
|
|
clist = FuncnameGetCandidates(names, -1, NIL, false, 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
|
|
|
}
|
|
|
|
|
2014-04-08 16:27:56 +02:00
|
|
|
/*
|
|
|
|
* to_regproc - converts "proname" to proc OID
|
|
|
|
*
|
|
|
|
* If the name is not found, we return NULL.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
to_regproc(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *pro_name = PG_GETARG_CSTRING(0);
|
|
|
|
List *names;
|
|
|
|
FuncCandidateList clist;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse the name into components and see if it matches any pg_proc entries
|
|
|
|
* in the current search path.
|
|
|
|
*/
|
|
|
|
names = stringToQualifiedNameList(pro_name);
|
|
|
|
clist = FuncnameGetCandidates(names, -1, NIL, false, false, true);
|
|
|
|
|
|
|
|
if (clist == NULL || clist->next != NULL)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
PG_RETURN_OID(clist->oid);
|
|
|
|
}
|
|
|
|
|
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)),
|
2014-01-23 18:40:29 +01:00
|
|
|
-1, NIL, false, 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
|
|
|
|
2014-01-23 18:40:29 +01:00
|
|
|
clist = FuncnameGetCandidates(names, nargs, NIL, false, 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)
|
2013-03-20 22:19:19 +01:00
|
|
|
{
|
|
|
|
return format_procedure_internal(procedure_oid, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
format_procedure_qualified(Oid procedure_oid)
|
|
|
|
{
|
|
|
|
return format_procedure_internal(procedure_oid, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Routine to produce regprocedure names; see format_procedure above.
|
|
|
|
*
|
|
|
|
* force_qualify says whether to schema-qualify; if true, the name is always
|
2013-05-29 22:58:43 +02:00
|
|
|
* qualified regardless of search_path visibility. Otherwise the name is only
|
2013-03-20 22:19:19 +01:00
|
|
|
* qualified if the function is not in path.
|
|
|
|
*/
|
|
|
|
static char *
|
|
|
|
format_procedure_internal(Oid procedure_oid, bool force_qualify)
|
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?
|
Add sql_drop event for event triggers
This event takes place just before ddl_command_end, and is fired if and
only if at least one object has been dropped by the command. (For
instance, DROP TABLE IF EXISTS of a table that does not in fact exist
will not lead to such a trigger firing). Commands that drop multiple
objects (such as DROP SCHEMA or DROP OWNED BY) will cause a single event
to fire. Some firings might be surprising, such as
ALTER TABLE DROP COLUMN.
The trigger is fired after the drop has taken place, because that has
been deemed the safest design, to avoid exposing possibly-inconsistent
internal state (system catalogs as well as current transaction) to the
user function code. This means that careful tracking of object
identification is required during the object removal phase.
Like other currently existing events, there is support for tag
filtering.
To support the new event, add a new pg_event_trigger_dropped_objects()
set-returning function, which returns a set of rows comprising the
objects affected by the command. This is to be used within the user
function code, and is mostly modelled after the recently introduced
pg_identify_object() function.
Catalog version bumped due to the new function.
Dimitri Fontaine and Álvaro Herrera
Review by Robert Haas, Tom Lane
2013-03-27 20:02:10 +01:00
|
|
|
* If not, or if caller requests it, we need to qualify it.
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
2013-03-20 22:19:19 +01:00
|
|
|
if (!force_qualify && 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, ',');
|
2013-03-20 22:19:19 +01:00
|
|
|
appendStringInfoString(&buf,
|
|
|
|
force_qualify ?
|
|
|
|
format_type_be_qualified(thisargtype) :
|
|
|
|
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,
|
Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.
SnapshotNow scans have the undesirable property that, in the face of
concurrent updates, the scan can fail to see either the old or the new
versions of the row. In many cases, we work around this by requiring
DDL operations to hold AccessExclusiveLock on the object being
modified; in some cases, the existing locking is inadequate and random
failures occur as a result. This commit doesn't change anything
related to locking, but will hopefully pave the way to allowing lock
strength reductions in the future.
The major issue has held us back from making this change in the past
is that taking an MVCC snapshot is significantly more expensive than
using a static special snapshot such as SnapshotNow. However, testing
of various worst-case scenarios reveals that this problem is not
severe except under fairly extreme workloads. To mitigate those
problems, we avoid retaking the MVCC snapshot for each new scan;
instead, we take a new snapshot only when invalidation messages have
been processed. The catcache machinery already requires that
invalidation messages be sent before releasing the related heavyweight
lock; else other backends might rely on locally-cached data rather
than scanning the catalog at all. Thus, making snapshot reuse
dependent on the same guarantees shouldn't break anything that wasn't
already subtly broken.
Patch by me. Review by Michael Paquier and Andres Freund.
2013-07-02 15:47:01 +02:00
|
|
|
NULL, 1, skey);
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
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);
|
2014-04-08 16:27:56 +02:00
|
|
|
clist = OpernameGetCandidates(names, '\0', 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),
|
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);
|
|
|
|
}
|
|
|
|
|
2014-04-08 16:27:56 +02:00
|
|
|
/*
|
|
|
|
* to_regoper - converts "oprname" to operator OID
|
|
|
|
*
|
|
|
|
* If the name is not found, we return NULL.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
to_regoper(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *opr_name = PG_GETARG_CSTRING(0);
|
|
|
|
List *names;
|
|
|
|
FuncCandidateList clist;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse the name into components and see if it matches any pg_operator
|
|
|
|
* entries in the current search path.
|
|
|
|
*/
|
|
|
|
names = stringToQualifiedNameList(opr_name);
|
|
|
|
clist = OpernameGetCandidates(names, '\0', true);
|
|
|
|
|
|
|
|
if (clist == NULL || clist->next != NULL)
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
|
|
|
PG_RETURN_OID(clist->oid);
|
|
|
|
}
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
/*
|
|
|
|
* 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)),
|
2014-04-08 16:27:56 +02:00
|
|
|
'\0', false);
|
2002-04-25 04:56:56 +02:00
|
|
|
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
|
|
|
*/
|
2013-03-20 22:19:19 +01:00
|
|
|
static char *
|
|
|
|
format_operator_internal(Oid operator_oid, bool force_qualify)
|
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?
|
2013-05-29 22:58:43 +02:00
|
|
|
* If not, or if caller explicitely requests it, we need to qualify
|
|
|
|
* it.
|
2002-04-25 04:56:56 +02:00
|
|
|
*/
|
2013-03-20 22:19:19 +01:00
|
|
|
if (force_qualify || !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,",
|
2013-03-20 22:19:19 +01:00
|
|
|
force_qualify ?
|
|
|
|
format_type_be_qualified(operform->oprleft) :
|
2002-04-25 04:56:56 +02:00
|
|
|
format_type_be(operform->oprleft));
|
|
|
|
else
|
2013-10-31 15:55:59 +01:00
|
|
|
appendStringInfoString(&buf, "NONE,");
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
if (operform->oprright)
|
|
|
|
appendStringInfo(&buf, "%s)",
|
2013-03-20 22:19:19 +01:00
|
|
|
force_qualify ?
|
|
|
|
format_type_be_qualified(operform->oprright) :
|
2002-04-25 04:56:56 +02:00
|
|
|
format_type_be(operform->oprright));
|
|
|
|
else
|
2013-10-31 15:55:59 +01:00
|
|
|
appendStringInfoString(&buf, "NONE)");
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-03-20 22:19:19 +01:00
|
|
|
char *
|
|
|
|
format_operator(Oid operator_oid)
|
|
|
|
{
|
|
|
|
return format_operator_internal(operator_oid, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
char *
|
|
|
|
format_operator_qualified(Oid operator_oid)
|
|
|
|
{
|
|
|
|
return format_operator_internal(operator_oid, true);
|
|
|
|
}
|
|
|
|
|
2002-07-30 00:14:11 +02:00
|
|
|
/*
|
|
|
|
* 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,
|
Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.
SnapshotNow scans have the undesirable property that, in the face of
concurrent updates, the scan can fail to see either the old or the new
versions of the row. In many cases, we work around this by requiring
DDL operations to hold AccessExclusiveLock on the object being
modified; in some cases, the existing locking is inadequate and random
failures occur as a result. This commit doesn't change anything
related to locking, but will hopefully pave the way to allowing lock
strength reductions in the future.
The major issue has held us back from making this change in the past
is that taking an MVCC snapshot is significantly more expensive than
using a static special snapshot such as SnapshotNow. However, testing
of various worst-case scenarios reveals that this problem is not
severe except under fairly extreme workloads. To mitigate those
problems, we avoid retaking the MVCC snapshot for each new scan;
instead, we take a new snapshot only when invalidation messages have
been processed. The catcache machinery already requires that
invalidation messages be sent before releasing the related heavyweight
lock; else other backends might rely on locally-cached data rather
than scanning the catalog at all. Thus, making snapshot reuse
dependent on the same guarantees shouldn't break anything that wasn't
already subtly broken.
Patch by me. Review by Michael Paquier and Andres Freund.
2013-07-02 15:47:01 +02:00
|
|
|
NULL, 1, skey);
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2014-04-08 16:27:56 +02:00
|
|
|
/*
|
|
|
|
* to_regclass - converts "classname" to class OID
|
|
|
|
*
|
|
|
|
* If the name is not found, we return NULL.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
to_regclass(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *class_name = PG_GETARG_CSTRING(0);
|
|
|
|
Oid result;
|
|
|
|
List *names;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parse the name into components and see if it matches any pg_class entries
|
|
|
|
* in the current search path.
|
|
|
|
*/
|
|
|
|
names = stringToQualifiedNameList(class_name);
|
|
|
|
|
|
|
|
/* We might not even have permissions on this relation; don't lock it. */
|
|
|
|
result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true);
|
|
|
|
|
|
|
|
if (OidIsValid(result))
|
|
|
|
PG_RETURN_OID(result);
|
|
|
|
else
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
/*
|
|
|
|
* 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,
|
Use an MVCC snapshot, rather than SnapshotNow, for catalog scans.
SnapshotNow scans have the undesirable property that, in the face of
concurrent updates, the scan can fail to see either the old or the new
versions of the row. In many cases, we work around this by requiring
DDL operations to hold AccessExclusiveLock on the object being
modified; in some cases, the existing locking is inadequate and random
failures occur as a result. This commit doesn't change anything
related to locking, but will hopefully pave the way to allowing lock
strength reductions in the future.
The major issue has held us back from making this change in the past
is that taking an MVCC snapshot is significantly more expensive than
using a static special snapshot such as SnapshotNow. However, testing
of various worst-case scenarios reveals that this problem is not
severe except under fairly extreme workloads. To mitigate those
problems, we avoid retaking the MVCC snapshot for each new scan;
instead, we take a new snapshot only when invalidation messages have
been processed. The catcache machinery already requires that
invalidation messages be sent before releasing the related heavyweight
lock; else other backends might rely on locally-cached data rather
than scanning the catalog at all. Thus, making snapshot reuse
dependent on the same guarantees shouldn't break anything that wasn't
already subtly broken.
Patch by me. Review by Michael Paquier and Andres Freund.
2013-07-02 15:47:01 +02:00
|
|
|
NULL, 1, skey);
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
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
|
|
|
*/
|
2014-04-08 16:27:56 +02:00
|
|
|
parseTypeString(typ_name_or_oid, &result, &typmod, false);
|
2002-04-25 04:56:56 +02:00
|
|
|
|
|
|
|
PG_RETURN_OID(result);
|
|
|
|
}
|
|
|
|
|
2014-04-08 16:27:56 +02:00
|
|
|
/*
|
|
|
|
* to_regtype - converts "typename" to type OID
|
|
|
|
*
|
|
|
|
* If the name is not found, we return NULL.
|
|
|
|
*/
|
|
|
|
Datum
|
|
|
|
to_regtype(PG_FUNCTION_ARGS)
|
|
|
|
{
|
|
|
|
char *typ_name = PG_GETARG_CSTRING(0);
|
|
|
|
Oid result;
|
|
|
|
int32 typmod;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Invoke the full parser to deal with special cases such as array syntax.
|
|
|
|
*/
|
|
|
|
parseTypeString(typ_name, &result, &typmod, true);
|
|
|
|
|
|
|
|
if (OidIsValid(result))
|
|
|
|
PG_RETURN_OID(result);
|
|
|
|
else
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
}
|
|
|
|
|
2002-04-25 04:56:56 +02:00
|
|
|
/*
|
|
|
|
* 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 */
|
2014-04-08 16:27:56 +02:00
|
|
|
parseTypeString(typename, &typeid, &typmod, false);
|
2002-04-25 04:56:56 +02:00
|
|
|
}
|
|
|
|
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);
|
|
|
|
}
|