Restructure representation of aggregate functions so that they have pg_proc
entries, per pghackers discussion. This fixes aggregates to live in namespaces, and also simplifies/speeds up lookup in parse_func.c. Also, add a 'proimplicit' flag to pg_proc that controls whether a type coercion function may be invoked implicitly, or only explicitly. The current settings of these flags are more permissive than I would like, but we will need to debate and refine the behavior; for now, I avoided breaking regression tests as much as I could.
This commit is contained in:
parent
3f6299df6c
commit
902a6a0a4b
|
@ -1,6 +1,6 @@
|
|||
<!--
|
||||
Documentation of the system catalogs, directed toward PostgreSQL developers
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.40 2002/04/05 00:31:22 tgl Exp $
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.41 2002/04/11 19:59:54 tgl Exp $
|
||||
-->
|
||||
|
||||
<chapter id="catalogs">
|
||||
|
@ -183,7 +183,11 @@
|
|||
that matches a query condition) and returns a single value computed
|
||||
from all these values. Typical aggregate functions are
|
||||
<function>sum</function>, <function>count</function>, and
|
||||
<function>max</function>.
|
||||
<function>max</function>. Each entry in
|
||||
<structname>pg_aggregate</structname> is an extension of an entry
|
||||
in <structname>pg_proc</structname>. The <structname>pg_proc</structname>
|
||||
entry carries the aggregate's name, input and output datatypes, and
|
||||
other information that is similar to ordinary functions.
|
||||
</para>
|
||||
|
||||
<table>
|
||||
|
@ -200,47 +204,29 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry>aggname</entry>
|
||||
<entry><type>name</type></entry>
|
||||
<entry></entry>
|
||||
<entry>Name of the aggregate function</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>aggowner</entry>
|
||||
<entry><type>int4</type></entry>
|
||||
<entry>pg_shadow.usesysid</entry>
|
||||
<entry>Owner (creator) of the aggregate function</entry>
|
||||
<entry>aggfnoid</entry>
|
||||
<entry><type>regproc</type></entry>
|
||||
<entry>pg_proc.oid</entry>
|
||||
<entry>pg_proc OID of the aggregate function</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>aggtransfn</entry>
|
||||
<entry><type>regproc</type> (function)</entry>
|
||||
<entry><type>regproc</type></entry>
|
||||
<entry>pg_proc.oid</entry>
|
||||
<entry>Transition function</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>aggfinalfn</entry>
|
||||
<entry><type>regproc</type> (function)</entry>
|
||||
<entry><type>regproc</type></entry>
|
||||
<entry>pg_proc.oid</entry>
|
||||
<entry>Final function</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>aggbasetype</entry>
|
||||
<entry><type>oid</type></entry>
|
||||
<entry>pg_type.oid</entry>
|
||||
<entry>The input data type for this aggregate function</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>aggtranstype</entry>
|
||||
<entry><type>oid</type></entry>
|
||||
<entry>pg_type.oid</entry>
|
||||
<entry>The type of the aggregate function's internal transition (state) data</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>aggfinaltype</entry>
|
||||
<entry><type>oid</type></entry>
|
||||
<entry>pg_type.oid</entry>
|
||||
<entry>The type of the result</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>agginitval</entry>
|
||||
<entry><type>text</type></entry>
|
||||
|
@ -263,12 +249,6 @@
|
|||
functions and the meaning of the transition functions, etc.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
An aggregate function is identified through name
|
||||
<emphasis>and</emphasis> argument type. Hence aggname and aggbasetype
|
||||
are the composite primary key.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
|
@ -1632,6 +1612,12 @@
|
|||
about the meaning of some fields.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The table contains data for aggregate functions as well as plain functions.
|
||||
If <structfield>proisagg</structfield> is true, there should be a matching
|
||||
row in <structname>pg_aggregate</structname>.
|
||||
</para>
|
||||
|
||||
<table>
|
||||
<title>pg_proc Columns</title>
|
||||
|
||||
|
@ -1677,10 +1663,10 @@
|
|||
</row>
|
||||
|
||||
<row>
|
||||
<entry>proisinh</entry>
|
||||
<entry>proisagg</entry>
|
||||
<entry><type>bool</type></entry>
|
||||
<entry></entry>
|
||||
<entry>unused</entry>
|
||||
<entry>Function is an aggregate function</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
|
@ -1690,6 +1676,13 @@
|
|||
<entry>not functional</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>proimplicit</entry>
|
||||
<entry><type>bool</type></entry>
|
||||
<entry></entry>
|
||||
<entry>Function may be invoked as an implicit type coercion</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>proisstrict</entry>
|
||||
<entry><type>bool</type></entry>
|
||||
|
@ -1702,6 +1695,14 @@
|
|||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>proretset</entry>
|
||||
<entry><type>bool</type></entry>
|
||||
<entry></entry>
|
||||
<entry>Function returns a set (ie, multiple values of the specified
|
||||
data type)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>provolatile</entry>
|
||||
<entry><type>char</type></entry>
|
||||
|
@ -1728,14 +1729,6 @@
|
|||
<entry>Number of arguments</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>proretset</entry>
|
||||
<entry><type>bool</type></entry>
|
||||
<entry></entry>
|
||||
<entry>Function returns a set (ie, multiple values of the specified
|
||||
data type)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>prorettype</entry>
|
||||
<entry><type>oid</type></entry>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!--
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_aggregate.sgml,v 1.16 2001/12/08 03:24:34 thomas Exp $
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_aggregate.sgml,v 1.17 2002/04/11 19:59:55 tgl Exp $
|
||||
PostgreSQL documentation
|
||||
-->
|
||||
|
||||
|
@ -168,8 +168,9 @@ CREATE
|
|||
<para>
|
||||
An aggregate function is identified by its name and input data type.
|
||||
Two aggregates can have the same name if they operate on different
|
||||
input types. To avoid confusion, do not make an ordinary function
|
||||
of the same name and input data type as an aggregate.
|
||||
input types. The
|
||||
name and input data type of an aggregate must also be distinct from
|
||||
the name and input data type of every ordinary function.
|
||||
</para>
|
||||
<para>
|
||||
An aggregate function is made from one or two ordinary
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!--
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.35 2002/04/05 00:31:24 tgl Exp $
|
||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.36 2002/04/11 19:59:55 tgl Exp $
|
||||
-->
|
||||
|
||||
<refentry id="SQL-CREATEFUNCTION">
|
||||
|
@ -214,6 +214,18 @@ CREATE [ OR REPLACE ] FUNCTION <replaceable class="parameter">name</replaceable>
|
|||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>implicitCoercion</term>
|
||||
<listitem>
|
||||
<para>
|
||||
<option>implicitCoercion</option> indicates that the function
|
||||
may be used for implicit type conversions.
|
||||
See <xref linkend="coercion-functions"
|
||||
endterm="coercion-functions-title"> for more detail.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
Attribute names are not case-sensitive.
|
||||
|
@ -311,6 +323,54 @@ CREATE [ OR REPLACE ] FUNCTION <replaceable class="parameter">name</replaceable>
|
|||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="COERCION-FUNCTIONS">
|
||||
<refsect1info>
|
||||
<date>2002-04-11</date>
|
||||
</refsect1info>
|
||||
<title id="coercion-functions-title">
|
||||
Type Coercion Functions
|
||||
</title>
|
||||
<para>
|
||||
A function that has one parameter and is named the same as its output
|
||||
datatype is considered to be a <firstterm>type coercion function</>:
|
||||
it can be invoked to convert a value of its input datatype into a value
|
||||
of its output datatype. For example,
|
||||
<programlisting>
|
||||
SELECT CAST(42 AS text);
|
||||
</programlisting>
|
||||
converts the integer constant 42 to text by invoking a function
|
||||
<literal>text(int4)</>, if such a function exists and returns type
|
||||
text. (If no suitable conversion function can be found, the cast fails.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If a potential coercion function is marked <literal>implicitCoercion</>,
|
||||
then it can be invoked in any context where the conversion it defines
|
||||
is required. Coercion functions not so marked can be invoked only by
|
||||
explicit <literal>CAST</>,
|
||||
<replaceable>x</><literal>::</><replaceable>typename</>,
|
||||
or <replaceable>typename</>(<replaceable>x</>) constructs.
|
||||
For example, supposing that foo.f1 is a column of type text, then
|
||||
<programlisting>
|
||||
INSERT INTO foo(f1) VALUES(42);
|
||||
</programlisting>
|
||||
will be allowed if <literal>text(int4)</> is marked
|
||||
<literal>implicitCoercion</>, otherwise not.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
It is wise to be conservative about marking coercion functions as
|
||||
implicit coercions. An overabundance of implicit coercion paths
|
||||
can cause <productname>PostgreSQL</productname> to choose surprising
|
||||
interpretations of commands,
|
||||
or to be unable to resolve commands at all because there are multiple
|
||||
possible interpretations. A good rule of thumb is to make coercions
|
||||
implicitly invokable only for information-preserving transformations
|
||||
between types in the same general type category. For example, int2
|
||||
to int4 coercion can reasonably be implicit, but be wary of marking
|
||||
int4 to text or float8 to int4 as implicit coercions.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="sql-createfunction-examples">
|
||||
<title>Examples</title>
|
||||
|
@ -356,8 +416,8 @@ CREATE TABLE product (
|
|||
</para>
|
||||
|
||||
<para>
|
||||
This example creates a function that does type conversion between the
|
||||
user-defined type complex, and the internal type point. The
|
||||
This example creates a function that does type conversion from the
|
||||
user-defined type complex to the built-in type point. The
|
||||
function is implemented by a dynamically loaded object that was
|
||||
compiled from C source (we illustrate the now-deprecated alternative
|
||||
of specifying the absolute file name to the shared object file).
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.63 2002/04/11 05:32:02 petere Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.64 2002/04/11 19:59:56 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* See acl.h.
|
||||
|
@ -733,7 +733,7 @@ pg_class_aclcheck(Oid table_oid, Oid userid, AclMode mode)
|
|||
Acl *acl;
|
||||
|
||||
/*
|
||||
* Validate userid, find out if he is superuser
|
||||
* Validate userid, find out if he is superuser, also get usecatupd
|
||||
*/
|
||||
tuple = SearchSysCache(SHADOWSYSID,
|
||||
ObjectIdGetDatum(userid),
|
||||
|
@ -1035,29 +1035,3 @@ pg_proc_ownercheck(Oid proc_oid, Oid userid)
|
|||
|
||||
return userid == owner_id;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ownership check for an aggregate function (specified by OID).
|
||||
*/
|
||||
bool
|
||||
pg_aggr_ownercheck(Oid aggr_oid, Oid userid)
|
||||
{
|
||||
HeapTuple tuple;
|
||||
AclId owner_id;
|
||||
|
||||
/* Superusers bypass all permission checking. */
|
||||
if (superuser_arg(userid))
|
||||
return true;
|
||||
|
||||
tuple = SearchSysCache(AGGOID,
|
||||
ObjectIdGetDatum(aggr_oid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "pg_aggr_ownercheck: aggregate %u not found", aggr_oid);
|
||||
|
||||
owner_id = ((Form_pg_aggregate) GETSTRUCT(tuple))->aggowner;
|
||||
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
return userid == owner_id;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.194 2002/03/31 06:26:29 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.195 2002/04/11 19:59:56 tgl Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
|
@ -1791,7 +1791,7 @@ cookDefault(ParseState *pstate,
|
|||
if (type_id != atttypid)
|
||||
{
|
||||
if (CoerceTargetExpr(pstate, expr, type_id,
|
||||
atttypid, atttypmod) == NULL)
|
||||
atttypid, atttypmod, false) == NULL)
|
||||
elog(ERROR, "Column \"%s\" is of type %s"
|
||||
" but default expression is of type %s"
|
||||
"\n\tYou will need to rewrite or cast the expression",
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.87 2002/04/05 00:31:24 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.88 2002/04/11 19:59:57 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -32,7 +32,7 @@
|
|||
*/
|
||||
|
||||
char *Name_pg_aggregate_indices[Num_pg_aggregate_indices] =
|
||||
{AggregateNameTypeIndex, AggregateOidIndex};
|
||||
{AggregateFnoidIndex};
|
||||
char *Name_pg_am_indices[Num_pg_am_indices] =
|
||||
{AmNameIndex, AmOidIndex};
|
||||
char *Name_pg_amop_indices[Num_pg_amop_indices] =
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.43 2002/04/09 20:35:47 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.44 2002/04/11 19:59:57 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -19,15 +19,16 @@
|
|||
#include "catalog/indexing.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_aggregate.h"
|
||||
#include "catalog/pg_language.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "miscadmin.h"
|
||||
#include "optimizer/cost.h"
|
||||
#include "parser/parse_coerce.h"
|
||||
#include "parser/parse_func.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
/*
|
||||
* AggregateCreate
|
||||
*/
|
||||
|
@ -50,7 +51,7 @@ AggregateCreate(const char *aggName,
|
|||
Oid finaltype;
|
||||
Oid fnArgs[FUNC_MAX_ARGS];
|
||||
int nargs;
|
||||
NameData aname;
|
||||
Oid procOid;
|
||||
TupleDesc tupDesc;
|
||||
int i;
|
||||
|
||||
|
@ -61,15 +62,6 @@ AggregateCreate(const char *aggName,
|
|||
if (!aggtransfnName)
|
||||
elog(ERROR, "aggregate must have a transition function");
|
||||
|
||||
/* make sure there is no existing agg of same name and base type */
|
||||
if (SearchSysCacheExists(AGGNAME,
|
||||
PointerGetDatum(aggName),
|
||||
ObjectIdGetDatum(aggBaseType),
|
||||
0, 0))
|
||||
elog(ERROR,
|
||||
"aggregate function \"%s\" with base type %s already exists",
|
||||
aggName, typeidTypeName(aggBaseType));
|
||||
|
||||
/* handle transfn */
|
||||
MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||
fnArgs[0] = aggTransType;
|
||||
|
@ -109,8 +101,8 @@ AggregateCreate(const char *aggName,
|
|||
/* handle finalfn, if supplied */
|
||||
if (aggfinalfnName)
|
||||
{
|
||||
MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||
fnArgs[0] = aggTransType;
|
||||
fnArgs[1] = 0;
|
||||
finalfn = LookupFuncName(aggfinalfnName, 1, fnArgs);
|
||||
if (!OidIsValid(finalfn))
|
||||
func_error("AggregateCreate", aggfinalfnName, 1, fnArgs, NULL);
|
||||
|
@ -132,21 +124,47 @@ AggregateCreate(const char *aggName,
|
|||
}
|
||||
Assert(OidIsValid(finaltype));
|
||||
|
||||
/*
|
||||
* Everything looks okay. Try to create the pg_proc entry for the
|
||||
* aggregate. (This could fail if there's already a conflicting entry.)
|
||||
*/
|
||||
MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||
fnArgs[0] = aggBaseType;
|
||||
|
||||
procOid = ProcedureCreate(aggName,
|
||||
aggNamespace,
|
||||
false, /* no replacement */
|
||||
false, /* doesn't return a set */
|
||||
finaltype, /* returnType */
|
||||
INTERNALlanguageId, /* languageObjectId */
|
||||
"aggregate_dummy", /* placeholder proc */
|
||||
"-", /* probin */
|
||||
true, /* isAgg */
|
||||
true, /* (obsolete "trusted") */
|
||||
false, /* isImplicit */
|
||||
false, /* isStrict (not needed for agg) */
|
||||
PROVOLATILE_IMMUTABLE, /* volatility (not needed for agg) */
|
||||
BYTE_PCT, /* default cost values */
|
||||
PERBYTE_CPU,
|
||||
PERCALL_CPU,
|
||||
OUTIN_RATIO,
|
||||
1, /* parameterCount */
|
||||
fnArgs); /* parameterTypes */
|
||||
|
||||
/*
|
||||
* Okay to create the pg_aggregate entry.
|
||||
*/
|
||||
|
||||
/* initialize nulls and values */
|
||||
for (i = 0; i < Natts_pg_aggregate; i++)
|
||||
{
|
||||
nulls[i] = ' ';
|
||||
values[i] = (Datum) NULL;
|
||||
}
|
||||
namestrcpy(&aname, aggName);
|
||||
values[Anum_pg_aggregate_aggname - 1] = NameGetDatum(&aname);
|
||||
values[Anum_pg_aggregate_aggowner - 1] = Int32GetDatum(GetUserId());
|
||||
values[Anum_pg_aggregate_aggfnoid - 1] = ObjectIdGetDatum(procOid);
|
||||
values[Anum_pg_aggregate_aggtransfn - 1] = ObjectIdGetDatum(transfn);
|
||||
values[Anum_pg_aggregate_aggfinalfn - 1] = ObjectIdGetDatum(finalfn);
|
||||
values[Anum_pg_aggregate_aggbasetype - 1] = ObjectIdGetDatum(aggBaseType);
|
||||
values[Anum_pg_aggregate_aggtranstype - 1] = ObjectIdGetDatum(aggTransType);
|
||||
values[Anum_pg_aggregate_aggfinaltype - 1] = ObjectIdGetDatum(finaltype);
|
||||
|
||||
if (agginitval)
|
||||
values[Anum_pg_aggregate_agginitval - 1] =
|
||||
DirectFunctionCall1(textin, CStringGetDatum(agginitval));
|
||||
|
@ -155,12 +173,9 @@ AggregateCreate(const char *aggName,
|
|||
|
||||
aggdesc = heap_openr(AggregateRelationName, RowExclusiveLock);
|
||||
tupDesc = aggdesc->rd_att;
|
||||
if (!HeapTupleIsValid(tup = heap_formtuple(tupDesc,
|
||||
values,
|
||||
nulls)))
|
||||
elog(ERROR, "AggregateCreate: heap_formtuple failed");
|
||||
if (!OidIsValid(heap_insert(aggdesc, tup)))
|
||||
elog(ERROR, "AggregateCreate: heap_insert failed");
|
||||
|
||||
tup = heap_formtuple(tupDesc, values, nulls);
|
||||
heap_insert(aggdesc, tup);
|
||||
|
||||
if (RelationGetForm(aggdesc)->relhasindex)
|
||||
{
|
||||
|
@ -173,62 +188,3 @@ AggregateCreate(const char *aggName,
|
|||
|
||||
heap_close(aggdesc, RowExclusiveLock);
|
||||
}
|
||||
|
||||
Datum
|
||||
AggNameGetInitVal(char *aggName, Oid basetype, bool *isNull)
|
||||
{
|
||||
HeapTuple tup;
|
||||
Oid transtype,
|
||||
typinput,
|
||||
typelem;
|
||||
Datum textInitVal;
|
||||
char *strInitVal;
|
||||
Datum initVal;
|
||||
|
||||
Assert(PointerIsValid(aggName));
|
||||
Assert(PointerIsValid(isNull));
|
||||
|
||||
tup = SearchSysCache(AGGNAME,
|
||||
PointerGetDatum(aggName),
|
||||
ObjectIdGetDatum(basetype),
|
||||
0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "AggNameGetInitVal: cache lookup failed for aggregate '%s'",
|
||||
aggName);
|
||||
transtype = ((Form_pg_aggregate) GETSTRUCT(tup))->aggtranstype;
|
||||
|
||||
/*
|
||||
* initval is potentially null, so don't try to access it as a struct
|
||||
* field. Must do it the hard way with SysCacheGetAttr.
|
||||
*/
|
||||
textInitVal = SysCacheGetAttr(AGGNAME, tup,
|
||||
Anum_pg_aggregate_agginitval,
|
||||
isNull);
|
||||
if (*isNull)
|
||||
{
|
||||
ReleaseSysCache(tup);
|
||||
return (Datum) 0;
|
||||
}
|
||||
|
||||
strInitVal = DatumGetCString(DirectFunctionCall1(textout, textInitVal));
|
||||
|
||||
ReleaseSysCache(tup);
|
||||
|
||||
tup = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(transtype),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "AggNameGetInitVal: cache lookup failed on aggregate transition function return type %u", transtype);
|
||||
|
||||
typinput = ((Form_pg_type) GETSTRUCT(tup))->typinput;
|
||||
typelem = ((Form_pg_type) GETSTRUCT(tup))->typelem;
|
||||
ReleaseSysCache(tup);
|
||||
|
||||
initVal = OidFunctionCall3(typinput,
|
||||
CStringGetDatum(strInitVal),
|
||||
ObjectIdGetDatum(typelem),
|
||||
Int32GetDatum(-1));
|
||||
|
||||
pfree(strInitVal);
|
||||
return initVal;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.69 2002/04/09 20:35:47 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.70 2002/04/11 19:59:57 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -19,7 +19,6 @@
|
|||
#include "catalog/indexing.h"
|
||||
#include "catalog/pg_language.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "executor/executor.h"
|
||||
#include "miscadmin.h"
|
||||
#include "parser/parse_coerce.h"
|
||||
|
@ -48,24 +47,25 @@ ProcedureCreate(const char *procedureName,
|
|||
Oid languageObjectId,
|
||||
const char *prosrc,
|
||||
const char *probin,
|
||||
bool isAgg,
|
||||
bool trusted,
|
||||
bool isImplicit,
|
||||
bool isStrict,
|
||||
char volatility,
|
||||
int32 byte_pct,
|
||||
int32 perbyte_cpu,
|
||||
int32 percall_cpu,
|
||||
int32 outin_ratio,
|
||||
List *argList)
|
||||
int parameterCount,
|
||||
const Oid *parameterTypes)
|
||||
{
|
||||
int i;
|
||||
Relation rel;
|
||||
HeapTuple tup;
|
||||
HeapTuple oldtup;
|
||||
uint16 parameterCount;
|
||||
char nulls[Natts_pg_proc];
|
||||
Datum values[Natts_pg_proc];
|
||||
char replaces[Natts_pg_proc];
|
||||
List *x;
|
||||
List *querytree_list;
|
||||
Oid typev[FUNC_MAX_ARGS];
|
||||
Oid relid;
|
||||
|
@ -79,43 +79,14 @@ ProcedureCreate(const char *procedureName,
|
|||
Assert(PointerIsValid(prosrc));
|
||||
Assert(PointerIsValid(probin));
|
||||
|
||||
parameterCount = 0;
|
||||
if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS)
|
||||
elog(ERROR, "functions cannot have more than %d arguments",
|
||||
FUNC_MAX_ARGS);
|
||||
|
||||
/* Make sure we have a zero-padded param type array */
|
||||
MemSet(typev, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||
foreach(x, argList)
|
||||
{
|
||||
TypeName *t = (TypeName *) lfirst(x);
|
||||
Oid toid;
|
||||
|
||||
if (parameterCount >= FUNC_MAX_ARGS)
|
||||
elog(ERROR, "functions cannot have more than %d arguments",
|
||||
FUNC_MAX_ARGS);
|
||||
|
||||
toid = LookupTypeName(t);
|
||||
if (OidIsValid(toid))
|
||||
{
|
||||
if (!get_typisdefined(toid))
|
||||
elog(WARNING, "Argument type \"%s\" is only a shell",
|
||||
TypeNameToString(t));
|
||||
}
|
||||
else
|
||||
{
|
||||
char *typnam = TypeNameToString(t);
|
||||
|
||||
if (strcmp(typnam, "opaque") == 0)
|
||||
{
|
||||
if (languageObjectId == SQLlanguageId)
|
||||
elog(ERROR, "SQL functions cannot have arguments of type \"opaque\"");
|
||||
toid = InvalidOid;
|
||||
}
|
||||
else
|
||||
elog(ERROR, "Type \"%s\" does not exist", typnam);
|
||||
}
|
||||
|
||||
if (t->setof)
|
||||
elog(ERROR, "functions cannot accept set arguments");
|
||||
|
||||
typev[parameterCount++] = toid;
|
||||
}
|
||||
if (parameterCount > 0)
|
||||
memcpy(typev, parameterTypes, parameterCount * sizeof(Oid));
|
||||
|
||||
if (languageObjectId == SQLlanguageId)
|
||||
{
|
||||
|
@ -248,12 +219,13 @@ ProcedureCreate(const char *procedureName,
|
|||
values[i++] = ObjectIdGetDatum(procNamespace); /* pronamespace */
|
||||
values[i++] = Int32GetDatum(GetUserId()); /* proowner */
|
||||
values[i++] = ObjectIdGetDatum(languageObjectId); /* prolang */
|
||||
values[i++] = BoolGetDatum(false); /* proisinh (unused) */
|
||||
values[i++] = BoolGetDatum(isAgg); /* proisagg */
|
||||
values[i++] = BoolGetDatum(trusted); /* proistrusted */
|
||||
values[i++] = BoolGetDatum(isImplicit); /* proimplicit */
|
||||
values[i++] = BoolGetDatum(isStrict); /* proisstrict */
|
||||
values[i++] = BoolGetDatum(returnsSet); /* proretset */
|
||||
values[i++] = CharGetDatum(volatility); /* provolatile */
|
||||
values[i++] = UInt16GetDatum(parameterCount); /* pronargs */
|
||||
values[i++] = BoolGetDatum(returnsSet); /* proretset */
|
||||
values[i++] = ObjectIdGetDatum(returnType); /* prorettype */
|
||||
values[i++] = PointerGetDatum(typev); /* proargtypes */
|
||||
values[i++] = Int32GetDatum(byte_pct); /* probyte_pct */
|
||||
|
@ -298,6 +270,17 @@ ProcedureCreate(const char *procedureName,
|
|||
elog(ERROR, "ProcedureCreate: cannot change return type of existing function."
|
||||
"\n\tUse DROP FUNCTION first.");
|
||||
|
||||
/* Can't change aggregate status, either */
|
||||
if (oldproc->proisagg != isAgg)
|
||||
{
|
||||
if (oldproc->proisagg)
|
||||
elog(ERROR, "function %s is an aggregate",
|
||||
procedureName);
|
||||
else
|
||||
elog(ERROR, "function %s is not an aggregate",
|
||||
procedureName);
|
||||
}
|
||||
|
||||
/* do not change existing permissions, either */
|
||||
replaces[Anum_pg_proc_proacl-1] = ' ';
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Copyright (c) 1999-2001, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.39 2002/04/09 20:35:47 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.40 2002/04/11 19:59:57 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -25,15 +25,11 @@
|
|||
#include "catalog/pg_operator.h"
|
||||
#include "catalog/pg_rewrite.h"
|
||||
#include "catalog/pg_trigger.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "commands/comment.h"
|
||||
#include "miscadmin.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "parser/parse_agg.h"
|
||||
#include "parser/parse_func.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "parser/parse.h"
|
||||
#include "rewrite/rewriteRemove.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/fmgroids.h"
|
||||
|
@ -573,7 +569,6 @@ CommentAggregate(List *aggregate, List *arguments, char *comment)
|
|||
TypeName *aggtype = (TypeName *) lfirst(arguments);
|
||||
Oid baseoid,
|
||||
oid;
|
||||
Oid classoid;
|
||||
|
||||
/* First, attempt to determine the base aggregate oid */
|
||||
if (aggtype)
|
||||
|
@ -581,18 +576,13 @@ CommentAggregate(List *aggregate, List *arguments, char *comment)
|
|||
else
|
||||
baseoid = InvalidOid;
|
||||
|
||||
/* Now, attempt to find the actual tuple in pg_aggregate */
|
||||
/* Now, attempt to find the actual tuple in pg_proc */
|
||||
|
||||
oid = GetSysCacheOid(AGGNAME,
|
||||
PointerGetDatum(strVal(lfirst(aggregate))), /* XXX */
|
||||
ObjectIdGetDatum(baseoid),
|
||||
0, 0);
|
||||
if (!OidIsValid(oid))
|
||||
agg_error("CommentAggregate", aggregate, baseoid);
|
||||
oid = find_aggregate_func("CommentAggregate", aggregate, baseoid);
|
||||
|
||||
/* Next, validate the user's attempt to comment */
|
||||
|
||||
if (!pg_aggr_ownercheck(oid, GetUserId()))
|
||||
if (!pg_proc_ownercheck(oid, GetUserId()))
|
||||
{
|
||||
if (baseoid == InvalidOid)
|
||||
elog(ERROR, "you are not permitted to comment on aggregate %s for all types",
|
||||
|
@ -602,14 +592,9 @@ CommentAggregate(List *aggregate, List *arguments, char *comment)
|
|||
NameListToString(aggregate), format_type_be(baseoid));
|
||||
}
|
||||
|
||||
/* pg_aggregate doesn't have a hard-coded OID, so must look it up */
|
||||
|
||||
classoid = get_relname_relid(AggregateRelationName, PG_CATALOG_NAMESPACE);
|
||||
Assert(OidIsValid(classoid));
|
||||
|
||||
/* Call CreateComments() to create/drop the comments */
|
||||
|
||||
CreateComments(oid, classoid, 0, comment);
|
||||
CreateComments(oid, RelOid_pg_proc, 0, comment);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.74 2002/04/09 20:35:47 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.75 2002/04/11 19:59:57 tgl Exp $
|
||||
*
|
||||
* DESCRIPTION
|
||||
* The "DefineFoo" routines take the parse tree and pick out the
|
||||
|
@ -141,13 +141,56 @@ compute_return_type(TypeName *returnType, Oid languageOid,
|
|||
*returnsSet_p = returnType->setof;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
compute_full_attributes(List *parameters,
|
||||
int32 *byte_pct_p, int32 *perbyte_cpu_p,
|
||||
int32 *percall_cpu_p, int32 *outin_ratio_p,
|
||||
bool *isStrict_p, char *volatility_p)
|
||||
/*
|
||||
* Interpret the argument-types list of the CREATE FUNCTION statement.
|
||||
*/
|
||||
static int
|
||||
compute_parameter_types(List *argTypes, Oid languageOid,
|
||||
Oid *parameterTypes)
|
||||
{
|
||||
int parameterCount = 0;
|
||||
List *x;
|
||||
|
||||
MemSet(parameterTypes, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||
foreach(x, argTypes)
|
||||
{
|
||||
TypeName *t = (TypeName *) lfirst(x);
|
||||
Oid toid;
|
||||
|
||||
if (parameterCount >= FUNC_MAX_ARGS)
|
||||
elog(ERROR, "functions cannot have more than %d arguments",
|
||||
FUNC_MAX_ARGS);
|
||||
|
||||
toid = LookupTypeName(t);
|
||||
if (OidIsValid(toid))
|
||||
{
|
||||
if (!get_typisdefined(toid))
|
||||
elog(WARNING, "Argument type \"%s\" is only a shell",
|
||||
TypeNameToString(t));
|
||||
}
|
||||
else
|
||||
{
|
||||
char *typnam = TypeNameToString(t);
|
||||
|
||||
if (strcmp(typnam, "opaque") == 0)
|
||||
{
|
||||
if (languageOid == SQLlanguageId)
|
||||
elog(ERROR, "SQL functions cannot have arguments of type \"opaque\"");
|
||||
toid = InvalidOid;
|
||||
}
|
||||
else
|
||||
elog(ERROR, "Type \"%s\" does not exist", typnam);
|
||||
}
|
||||
|
||||
if (t->setof)
|
||||
elog(ERROR, "functions cannot accept set arguments");
|
||||
|
||||
parameterTypes[parameterCount++] = toid;
|
||||
}
|
||||
|
||||
return parameterCount;
|
||||
}
|
||||
|
||||
/*-------------
|
||||
* Interpret the parameters *parameters and return their contents as
|
||||
* *byte_pct_p, etc.
|
||||
|
@ -155,7 +198,10 @@ compute_full_attributes(List *parameters,
|
|||
* These parameters supply optional information about a function.
|
||||
* All have defaults if not specified.
|
||||
*
|
||||
* Note: currently, only two of these parameters actually do anything:
|
||||
* Note: currently, only three of these parameters actually do anything:
|
||||
*
|
||||
* * isImplicit means the function may be used as an implicit type
|
||||
* coercion.
|
||||
*
|
||||
* * isStrict means the function should not be called when any NULL
|
||||
* inputs are present; instead a NULL result value should be assumed.
|
||||
|
@ -168,6 +214,13 @@ compute_full_attributes(List *parameters,
|
|||
* for a long time.
|
||||
*------------
|
||||
*/
|
||||
static void
|
||||
compute_full_attributes(List *parameters,
|
||||
int32 *byte_pct_p, int32 *perbyte_cpu_p,
|
||||
int32 *percall_cpu_p, int32 *outin_ratio_p,
|
||||
bool *isImplicit_p, bool *isStrict_p,
|
||||
char *volatility_p)
|
||||
{
|
||||
List *pl;
|
||||
|
||||
/* the defaults */
|
||||
|
@ -175,6 +228,7 @@ compute_full_attributes(List *parameters,
|
|||
*perbyte_cpu_p = PERBYTE_CPU;
|
||||
*percall_cpu_p = PERCALL_CPU;
|
||||
*outin_ratio_p = OUTIN_RATIO;
|
||||
*isImplicit_p = false;
|
||||
*isStrict_p = false;
|
||||
*volatility_p = PROVOLATILE_VOLATILE;
|
||||
|
||||
|
@ -182,7 +236,9 @@ compute_full_attributes(List *parameters,
|
|||
{
|
||||
DefElem *param = (DefElem *) lfirst(pl);
|
||||
|
||||
if (strcasecmp(param->defname, "isstrict") == 0)
|
||||
if (strcasecmp(param->defname, "implicitcoercion") == 0)
|
||||
*isImplicit_p = true;
|
||||
else if (strcasecmp(param->defname, "isstrict") == 0)
|
||||
*isStrict_p = true;
|
||||
else if (strcasecmp(param->defname, "isimmutable") == 0)
|
||||
*volatility_p = PROVOLATILE_IMMUTABLE;
|
||||
|
@ -276,11 +332,14 @@ CreateFunction(ProcedureStmt *stmt)
|
|||
Oid languageOid;
|
||||
char *funcname;
|
||||
Oid namespaceId;
|
||||
int parameterCount;
|
||||
Oid parameterTypes[FUNC_MAX_ARGS];
|
||||
int32 byte_pct,
|
||||
perbyte_cpu,
|
||||
percall_cpu,
|
||||
outin_ratio;
|
||||
bool isStrict;
|
||||
bool isImplicit,
|
||||
isStrict;
|
||||
char volatility;
|
||||
HeapTuple languageTuple;
|
||||
Form_pg_language languageStruct;
|
||||
|
@ -316,9 +375,13 @@ CreateFunction(ProcedureStmt *stmt)
|
|||
compute_return_type(stmt->returnType, languageOid,
|
||||
&prorettype, &returnsSet);
|
||||
|
||||
parameterCount = compute_parameter_types(stmt->argTypes, languageOid,
|
||||
parameterTypes);
|
||||
|
||||
compute_full_attributes(stmt->withClause,
|
||||
&byte_pct, &perbyte_cpu, &percall_cpu,
|
||||
&outin_ratio, &isStrict, &volatility);
|
||||
&outin_ratio, &isImplicit, &isStrict,
|
||||
&volatility);
|
||||
|
||||
interpret_AS_clause(languageOid, languageName, stmt->as,
|
||||
&prosrc_str, &probin_str);
|
||||
|
@ -335,18 +398,20 @@ CreateFunction(ProcedureStmt *stmt)
|
|||
languageOid,
|
||||
prosrc_str, /* converted to text later */
|
||||
probin_str, /* converted to text later */
|
||||
false, /* not an aggregate */
|
||||
true, /* (obsolete "trusted") */
|
||||
isImplicit,
|
||||
isStrict,
|
||||
volatility,
|
||||
byte_pct,
|
||||
perbyte_cpu,
|
||||
percall_cpu,
|
||||
outin_ratio,
|
||||
stmt->argTypes);
|
||||
parameterCount,
|
||||
parameterTypes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* DefineOperator
|
||||
* this function extracts all the information from the
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.68 2002/04/09 20:35:47 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.69 2002/04/11 19:59:58 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -303,7 +303,9 @@ FuncIndexArgs(IndexInfo *indexInfo,
|
|||
&true_typeids);
|
||||
if (fdresult != FUNCDETAIL_NORMAL)
|
||||
{
|
||||
if (fdresult == FUNCDETAIL_COERCION)
|
||||
if (fdresult == FUNCDETAIL_AGGREGATE)
|
||||
elog(ERROR, "DefineIndex: functional index may not use an aggregate function");
|
||||
else if (fdresult == FUNCDETAIL_COERCION)
|
||||
elog(ERROR, "DefineIndex: functional index must use a real function, not a type coercion"
|
||||
"\n\tTry specifying the index opclass you want to use, instead");
|
||||
else
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.73 2002/04/09 20:35:48 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/remove.c,v 1.74 2002/04/11 19:59:58 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -24,7 +24,6 @@
|
|||
#include "commands/defrem.h"
|
||||
#include "miscadmin.h"
|
||||
#include "parser/parse.h"
|
||||
#include "parser/parse_agg.h"
|
||||
#include "parser/parse_func.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "utils/acl.h"
|
||||
|
@ -381,6 +380,11 @@ RemoveFunction(List *functionName, /* function name to be removed */
|
|||
elog(ERROR, "RemoveFunction: function '%s': permission denied",
|
||||
NameListToString(functionName));
|
||||
|
||||
if (((Form_pg_proc) GETSTRUCT(tup))->proisagg)
|
||||
elog(ERROR, "RemoveFunction: function '%s' is an aggregate"
|
||||
"\n\tUse DROP AGGREGATE to remove it",
|
||||
NameListToString(functionName));
|
||||
|
||||
if (((Form_pg_proc) GETSTRUCT(tup))->prolang == INTERNALlanguageId)
|
||||
{
|
||||
/* "Helpful" WARNING when removing a builtin function ... */
|
||||
|
@ -404,6 +408,7 @@ RemoveAggregate(List *aggName, TypeName *aggType)
|
|||
Relation relation;
|
||||
HeapTuple tup;
|
||||
Oid basetypeID;
|
||||
Oid procOid;
|
||||
|
||||
/*
|
||||
* if a basetype is passed in, then attempt to find an aggregate for
|
||||
|
@ -413,23 +418,16 @@ RemoveAggregate(List *aggName, TypeName *aggType)
|
|||
* a basetype of zero. This is valid. It means that the aggregate is
|
||||
* to apply to all basetypes (eg, COUNT).
|
||||
*/
|
||||
|
||||
if (aggType)
|
||||
basetypeID = typenameTypeId(aggType);
|
||||
else
|
||||
basetypeID = InvalidOid;
|
||||
|
||||
relation = heap_openr(AggregateRelationName, RowExclusiveLock);
|
||||
procOid = find_aggregate_func("RemoveAggregate", aggName, basetypeID);
|
||||
|
||||
tup = SearchSysCache(AGGNAME,
|
||||
PointerGetDatum(strVal(llast(aggName))),
|
||||
ObjectIdGetDatum(basetypeID),
|
||||
0, 0);
|
||||
/* Permission check */
|
||||
|
||||
if (!HeapTupleIsValid(tup))
|
||||
agg_error("RemoveAggregate", aggName, basetypeID);
|
||||
|
||||
if (!pg_aggr_ownercheck(tup->t_data->t_oid, GetUserId()))
|
||||
if (!pg_proc_ownercheck(procOid, GetUserId()))
|
||||
{
|
||||
if (basetypeID == InvalidOid)
|
||||
elog(ERROR, "RemoveAggregate: aggregate %s for all types: permission denied",
|
||||
|
@ -439,8 +437,36 @@ RemoveAggregate(List *aggName, TypeName *aggType)
|
|||
NameListToString(aggName), format_type_be(basetypeID));
|
||||
}
|
||||
|
||||
/* Remove any comments related to this aggregate */
|
||||
DeleteComments(tup->t_data->t_oid, RelationGetRelid(relation));
|
||||
/* Remove the pg_proc tuple */
|
||||
|
||||
relation = heap_openr(ProcedureRelationName, RowExclusiveLock);
|
||||
|
||||
tup = SearchSysCache(PROCOID,
|
||||
ObjectIdGetDatum(procOid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "RemoveAggregate: couldn't find pg_proc tuple for %s",
|
||||
NameListToString(aggName));
|
||||
|
||||
/* Delete any comments associated with this function */
|
||||
DeleteComments(procOid, RelationGetRelid(relation));
|
||||
|
||||
simple_heap_delete(relation, &tup->t_self);
|
||||
|
||||
ReleaseSysCache(tup);
|
||||
|
||||
heap_close(relation, RowExclusiveLock);
|
||||
|
||||
/* Remove the pg_aggregate tuple */
|
||||
|
||||
relation = heap_openr(AggregateRelationName, RowExclusiveLock);
|
||||
|
||||
tup = SearchSysCache(AGGFNOID,
|
||||
ObjectIdGetDatum(procOid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup)) /* should not happen */
|
||||
elog(ERROR, "RemoveAggregate: couldn't find pg_aggregate tuple for %s",
|
||||
NameListToString(aggName));
|
||||
|
||||
simple_heap_delete(relation, &tup->t_self);
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.80 2002/03/20 19:43:54 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.81 2002/04/11 19:59:58 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -63,11 +63,13 @@
|
|||
#include "parser/parse_expr.h"
|
||||
#include "parser/parse_oper.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "utils/tuplesort.h"
|
||||
#include "utils/datum.h"
|
||||
|
||||
|
||||
/*
|
||||
* AggStatePerAggData - per-aggregate working state for the Agg scan
|
||||
*/
|
||||
|
@ -160,6 +162,7 @@ static void process_sorted_aggregate(AggState *aggstate,
|
|||
AggStatePerAgg peraggstate);
|
||||
static void finalize_aggregate(AggStatePerAgg peraggstate,
|
||||
Datum *resultVal, bool *resultIsNull);
|
||||
static Datum GetAggInitVal(Datum textInitVal, Oid transtype);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -244,7 +247,7 @@ advance_transition_function(AggStatePerAgg peraggstate,
|
|||
* transValue has not been initialized. This is the first
|
||||
* non-NULL input value. We use it as the initial value for
|
||||
* transValue. (We already checked that the agg's input type
|
||||
* is binary- compatible with its transtype, so straight copy
|
||||
* is binary-compatible with its transtype, so straight copy
|
||||
* here is OK.)
|
||||
*
|
||||
* We had better copy the datum if it is pass-by-ref, since the
|
||||
|
@ -838,11 +841,11 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
|||
{
|
||||
Aggref *aggref = (Aggref *) lfirst(alist);
|
||||
AggStatePerAgg peraggstate = &peragg[++aggno];
|
||||
char *aggname = aggref->aggname;
|
||||
HeapTuple aggTuple;
|
||||
Form_pg_aggregate aggform;
|
||||
Oid transfn_oid,
|
||||
finalfn_oid;
|
||||
Datum textInitVal;
|
||||
|
||||
/* Mark Aggref node with its associated index in the result array */
|
||||
aggref->aggno = aggno;
|
||||
|
@ -850,28 +853,34 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
|||
/* Fill in the peraggstate data */
|
||||
peraggstate->aggref = aggref;
|
||||
|
||||
aggTuple = SearchSysCache(AGGNAME,
|
||||
PointerGetDatum(aggname),
|
||||
ObjectIdGetDatum(aggref->basetype),
|
||||
0, 0);
|
||||
aggTuple = SearchSysCache(AGGFNOID,
|
||||
ObjectIdGetDatum(aggref->aggfnoid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(aggTuple))
|
||||
elog(ERROR, "ExecAgg: cache lookup failed for aggregate %s(%s)",
|
||||
aggname,
|
||||
aggref->basetype ?
|
||||
typeidTypeName(aggref->basetype) : (char *) "");
|
||||
elog(ERROR, "ExecAgg: cache lookup failed for aggregate %u",
|
||||
aggref->aggfnoid);
|
||||
aggform = (Form_pg_aggregate) GETSTRUCT(aggTuple);
|
||||
|
||||
get_typlenbyval(aggform->aggfinaltype,
|
||||
get_typlenbyval(aggref->aggtype,
|
||||
&peraggstate->resulttypeLen,
|
||||
&peraggstate->resulttypeByVal);
|
||||
get_typlenbyval(aggform->aggtranstype,
|
||||
&peraggstate->transtypeLen,
|
||||
&peraggstate->transtypeByVal);
|
||||
|
||||
peraggstate->initValue =
|
||||
AggNameGetInitVal(aggname,
|
||||
aggform->aggbasetype,
|
||||
&peraggstate->initValueIsNull);
|
||||
/*
|
||||
* initval is potentially null, so don't try to access it as a struct
|
||||
* field. Must do it the hard way with SysCacheGetAttr.
|
||||
*/
|
||||
textInitVal = SysCacheGetAttr(AGGFNOID, aggTuple,
|
||||
Anum_pg_aggregate_agginitval,
|
||||
&peraggstate->initValueIsNull);
|
||||
|
||||
if (peraggstate->initValueIsNull)
|
||||
peraggstate->initValue = (Datum) 0;
|
||||
else
|
||||
peraggstate->initValue = GetAggInitVal(textInitVal,
|
||||
aggform->aggtranstype);
|
||||
|
||||
peraggstate->transfn_oid = transfn_oid = aggform->aggtransfn;
|
||||
peraggstate->finalfn_oid = finalfn_oid = aggform->aggfinalfn;
|
||||
|
@ -891,21 +900,21 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
|||
{
|
||||
/*
|
||||
* Note: use the type from the input expression here, not
|
||||
* aggform->aggbasetype, because the latter might be 0.
|
||||
* from pg_proc.proargtypes, because the latter might be 0.
|
||||
* (Consider COUNT(*).)
|
||||
*/
|
||||
Oid inputType = exprType(aggref->target);
|
||||
|
||||
if (!IsBinaryCompatible(inputType, aggform->aggtranstype))
|
||||
elog(ERROR, "Aggregate %s needs to have compatible input type and transition type",
|
||||
aggname);
|
||||
elog(ERROR, "Aggregate %u needs to have compatible input type and transition type",
|
||||
aggref->aggfnoid);
|
||||
}
|
||||
|
||||
if (aggref->aggdistinct)
|
||||
{
|
||||
/*
|
||||
* Note: use the type from the input expression here, not
|
||||
* aggform->aggbasetype, because the latter might be 0.
|
||||
* from pg_proc.proargtypes, because the latter might be 0.
|
||||
* (Consider COUNT(*).)
|
||||
*/
|
||||
Oid inputType = exprType(aggref->target);
|
||||
|
@ -932,6 +941,36 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static Datum
|
||||
GetAggInitVal(Datum textInitVal, Oid transtype)
|
||||
{
|
||||
char *strInitVal;
|
||||
HeapTuple tup;
|
||||
Oid typinput,
|
||||
typelem;
|
||||
Datum initVal;
|
||||
|
||||
strInitVal = DatumGetCString(DirectFunctionCall1(textout, textInitVal));
|
||||
|
||||
tup = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(transtype),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "GetAggInitVal: cache lookup failed on aggregate transition function return type %u", transtype);
|
||||
|
||||
typinput = ((Form_pg_type) GETSTRUCT(tup))->typinput;
|
||||
typelem = ((Form_pg_type) GETSTRUCT(tup))->typelem;
|
||||
ReleaseSysCache(tup);
|
||||
|
||||
initVal = OidFunctionCall3(typinput,
|
||||
CStringGetDatum(strInitVal),
|
||||
ObjectIdGetDatum(typelem),
|
||||
Int32GetDatum(-1));
|
||||
|
||||
pfree(strInitVal);
|
||||
return initVal;
|
||||
}
|
||||
|
||||
int
|
||||
ExecCountSlotsAgg(Agg *node)
|
||||
{
|
||||
|
@ -985,3 +1024,21 @@ ExecReScanAgg(Agg *node, ExprContext *exprCtxt, Plan *parent)
|
|||
if (((Plan *) node)->lefttree->chgParam == NULL)
|
||||
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
||||
}
|
||||
|
||||
/*
|
||||
* aggregate_dummy - dummy execution routine for aggregate functions
|
||||
*
|
||||
* This function is listed as the implementation (prosrc field) of pg_proc
|
||||
* entries for aggregate functions. Its only purpose is to throw an error
|
||||
* if someone mistakenly executes such a function in the normal way.
|
||||
*
|
||||
* Perhaps someday we could assign real meaning to the prosrc field of
|
||||
* an aggregate?
|
||||
*/
|
||||
Datum
|
||||
aggregate_dummy(PG_FUNCTION_ARGS)
|
||||
{
|
||||
elog(ERROR, "Aggregate function %u called as normal function",
|
||||
fcinfo->flinfo->fn_oid);
|
||||
return (Datum) 0; /* keep compiler quiet */
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.176 2002/04/09 20:35:49 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.177 2002/04/11 19:59:59 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -852,11 +852,7 @@ _copyAggref(Aggref *from)
|
|||
{
|
||||
Aggref *newnode = makeNode(Aggref);
|
||||
|
||||
/*
|
||||
* copy remainder of node
|
||||
*/
|
||||
newnode->aggname = pstrdup(from->aggname);
|
||||
newnode->basetype = from->basetype;
|
||||
newnode->aggfnoid = from->aggfnoid;
|
||||
newnode->aggtype = from->aggtype;
|
||||
Node_Copy(from, newnode, target);
|
||||
newnode->aggstar = from->aggstar;
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.124 2002/04/09 20:35:50 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.125 2002/04/11 19:59:59 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -220,9 +220,7 @@ _equalFunc(Func *a, Func *b)
|
|||
static bool
|
||||
_equalAggref(Aggref *a, Aggref *b)
|
||||
{
|
||||
if (strcmp(a->aggname, b->aggname) != 0)
|
||||
return false;
|
||||
if (a->basetype != b->basetype)
|
||||
if (a->aggfnoid != b->aggfnoid)
|
||||
return false;
|
||||
if (a->aggtype != b->aggtype)
|
||||
return false;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.153 2002/04/09 20:35:50 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.154 2002/04/11 19:59:59 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Every (plan) node in POSTGRES has an associated "out" routine which
|
||||
|
@ -785,10 +785,8 @@ _outConst(StringInfo str, Const *node)
|
|||
static void
|
||||
_outAggref(StringInfo str, Aggref *node)
|
||||
{
|
||||
appendStringInfo(str, " AGGREG :aggname ");
|
||||
_outToken(str, node->aggname);
|
||||
appendStringInfo(str, " :basetype %u :aggtype %u :target ",
|
||||
node->basetype, node->aggtype);
|
||||
appendStringInfo(str, " AGGREG :aggfnoid %u :aggtype %u :target ",
|
||||
node->aggfnoid, node->aggtype);
|
||||
_outNode(str, node->target);
|
||||
|
||||
appendStringInfo(str, " :aggstar %s :aggdistinct %s ",
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.118 2002/03/22 02:56:32 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.119 2002/04/11 20:00:00 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Most of the read functions for plan nodes are tested. (In fact, they
|
||||
|
@ -1159,13 +1159,9 @@ _readAggref(void)
|
|||
|
||||
local_node = makeNode(Aggref);
|
||||
|
||||
token = pg_strtok(&length); /* eat :aggname */
|
||||
token = pg_strtok(&length); /* get aggname */
|
||||
local_node->aggname = debackslash(token, length);
|
||||
|
||||
token = pg_strtok(&length); /* eat :basetype */
|
||||
token = pg_strtok(&length); /* get basetype */
|
||||
local_node->basetype = atooid(token);
|
||||
token = pg_strtok(&length); /* eat :aggfnoid */
|
||||
token = pg_strtok(&length); /* get aggfnoid */
|
||||
local_node->aggfnoid = atooid(token);
|
||||
|
||||
token = pg_strtok(&length); /* eat :aggtype */
|
||||
token = pg_strtok(&length); /* get aggtype */
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.34 2002/03/12 00:51:51 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/var.c,v 1.35 2002/04/11 20:00:00 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -485,7 +485,7 @@ flatten_join_alias_var(Var *var, Query *root, int expandRTI)
|
|||
if (subtype != vartype)
|
||||
{
|
||||
l_var = coerce_type(NULL, l_var, subtype,
|
||||
vartype, vartypmod);
|
||||
vartype, vartypmod, false);
|
||||
l_var = coerce_type_typmod(NULL, l_var,
|
||||
vartype, vartypmod);
|
||||
}
|
||||
|
@ -504,7 +504,7 @@ flatten_join_alias_var(Var *var, Query *root, int expandRTI)
|
|||
if (subtype != vartype)
|
||||
{
|
||||
r_var = coerce_type(NULL, r_var, subtype,
|
||||
vartype, vartypmod);
|
||||
vartype, vartypmod, false);
|
||||
r_var = coerce_type_typmod(NULL, r_var,
|
||||
vartype, vartypmod);
|
||||
}
|
||||
|
|
|
@ -8,24 +8,17 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.48 2002/04/09 20:35:52 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.49 2002/04/11 20:00:00 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#include "postgres.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_aggregate.h"
|
||||
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/tlist.h"
|
||||
#include "parser/parse_agg.h"
|
||||
#include "parser/parse_coerce.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "parser/parsetree.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -185,70 +178,3 @@ parseCheckAggregates(ParseState *pstate, Query *qry, Node *qual)
|
|||
/* Release the list storage (but not the pointed-to expressions!) */
|
||||
freeList(groupClauses);
|
||||
}
|
||||
|
||||
|
||||
Aggref *
|
||||
ParseAgg(ParseState *pstate, List *aggname, Oid basetype,
|
||||
List *args, bool agg_star, bool agg_distinct)
|
||||
{
|
||||
HeapTuple aggtuple;
|
||||
Form_pg_aggregate aggform;
|
||||
Aggref *aggref;
|
||||
|
||||
aggtuple = SearchSysCache(AGGNAME,
|
||||
PointerGetDatum(strVal(llast(aggname))),
|
||||
ObjectIdGetDatum(basetype),
|
||||
0, 0);
|
||||
/* shouldn't happen --- caller should have checked already */
|
||||
if (!HeapTupleIsValid(aggtuple))
|
||||
agg_error("ParseAgg", aggname, basetype);
|
||||
aggform = (Form_pg_aggregate) GETSTRUCT(aggtuple);
|
||||
|
||||
/*
|
||||
* There used to be a really ugly hack for count(*) here.
|
||||
*
|
||||
* It's gone. Now, the grammar transforms count(*) into count(1), which
|
||||
* does the right thing. (It didn't use to do the right thing,
|
||||
* because the optimizer had the wrong ideas about semantics of
|
||||
* queries without explicit variables. Fixed as of Oct 1999 --- tgl.)
|
||||
*/
|
||||
|
||||
/*
|
||||
* We assume caller has already checked that given args are compatible
|
||||
* with the agg's basetype.
|
||||
*/
|
||||
|
||||
aggref = makeNode(Aggref);
|
||||
aggref->aggname = pstrdup(strVal(llast(aggname)));
|
||||
aggref->basetype = aggform->aggbasetype;
|
||||
aggref->aggtype = aggform->aggfinaltype;
|
||||
aggref->target = lfirst(args);
|
||||
aggref->aggstar = agg_star;
|
||||
aggref->aggdistinct = agg_distinct;
|
||||
|
||||
ReleaseSysCache(aggtuple);
|
||||
|
||||
pstate->p_hasAggs = true;
|
||||
|
||||
return aggref;
|
||||
}
|
||||
|
||||
/*
|
||||
* Error message when aggregate lookup fails that gives details of the
|
||||
* basetype
|
||||
*/
|
||||
void
|
||||
agg_error(const char *caller, List *aggname, Oid basetypeID)
|
||||
{
|
||||
/*
|
||||
* basetypeID that is Invalid (zero) means aggregate over all types.
|
||||
* (count)
|
||||
*/
|
||||
|
||||
if (basetypeID == InvalidOid)
|
||||
elog(ERROR, "%s: aggregate '%s' for all types does not exist",
|
||||
caller, NameListToString(aggname));
|
||||
else
|
||||
elog(ERROR, "%s: aggregate '%s' for type %s does not exist",
|
||||
caller, NameListToString(aggname), format_type_be(basetypeID));
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.69 2002/04/09 20:35:52 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.70 2002/04/11 20:00:00 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -32,7 +32,7 @@ Oid PromoteTypeToNext(Oid inType);
|
|||
static Oid PreferredType(CATEGORY category, Oid type);
|
||||
static Node *build_func_call(Oid funcid, Oid rettype, List *args);
|
||||
static Oid find_coercion_function(Oid targetTypeId, Oid inputTypeId,
|
||||
Oid secondArgType);
|
||||
Oid secondArgType, bool isExplicit);
|
||||
|
||||
|
||||
/* coerce_type()
|
||||
|
@ -40,7 +40,7 @@ static Oid find_coercion_function(Oid targetTypeId, Oid inputTypeId,
|
|||
*/
|
||||
Node *
|
||||
coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
||||
Oid targetTypeId, int32 atttypmod)
|
||||
Oid targetTypeId, int32 atttypmod, bool isExplicit)
|
||||
{
|
||||
Node *result;
|
||||
|
||||
|
@ -131,7 +131,8 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
|||
|
||||
funcId = find_coercion_function(baseTypeId,
|
||||
getBaseType(inputTypeId),
|
||||
InvalidOid);
|
||||
InvalidOid,
|
||||
isExplicit);
|
||||
if (!OidIsValid(funcId))
|
||||
elog(ERROR, "coerce_type: no conversion function from %s to %s",
|
||||
format_type_be(inputTypeId), format_type_be(targetTypeId));
|
||||
|
@ -171,13 +172,18 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
|||
*
|
||||
* There are a few types which are known apriori to be convertible.
|
||||
* We will check for those cases first, and then look for possible
|
||||
* conversion functions.
|
||||
* conversion functions.
|
||||
*
|
||||
* We must be told whether this is an implicit or explicit coercion
|
||||
* (explicit being a CAST construct, explicit function call, etc).
|
||||
* We will accept a wider set of coercion cases for an explicit coercion.
|
||||
*
|
||||
* Notes:
|
||||
* This uses the same mechanism as the CAST() SQL construct in gram.y.
|
||||
*/
|
||||
bool
|
||||
can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
|
||||
can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
|
||||
bool isExplicit)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -230,7 +236,7 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
|
|||
return false;
|
||||
|
||||
/*
|
||||
* Else, try for explicit conversion using functions: look for a
|
||||
* Else, try for run-time conversion using functions: look for a
|
||||
* single-argument function named with the target type name and
|
||||
* accepting the source type.
|
||||
*
|
||||
|
@ -238,7 +244,8 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
|
|||
*/
|
||||
funcId = find_coercion_function(getBaseType(targetTypeId),
|
||||
getBaseType(inputTypeId),
|
||||
InvalidOid);
|
||||
InvalidOid,
|
||||
isExplicit);
|
||||
if (!OidIsValid(funcId))
|
||||
return false;
|
||||
}
|
||||
|
@ -279,7 +286,8 @@ coerce_type_typmod(ParseState *pstate, Node *node,
|
|||
/* If given type is a domain, use base type instead */
|
||||
baseTypeId = getBaseType(targetTypeId);
|
||||
|
||||
funcId = find_coercion_function(baseTypeId, baseTypeId, INT4OID);
|
||||
/* Note this is always implicit coercion */
|
||||
funcId = find_coercion_function(baseTypeId, baseTypeId, INT4OID, false);
|
||||
|
||||
if (OidIsValid(funcId))
|
||||
{
|
||||
|
@ -321,9 +329,10 @@ coerce_to_boolean(ParseState *pstate, Node **pnode)
|
|||
if (inputTypeId == BOOLOID)
|
||||
return true; /* no work */
|
||||
targetTypeId = BOOLOID;
|
||||
if (!can_coerce_type(1, &inputTypeId, &targetTypeId))
|
||||
if (!can_coerce_type(1, &inputTypeId, &targetTypeId, false))
|
||||
return false; /* fail, but let caller choose error msg */
|
||||
*pnode = coerce_type(pstate, *pnode, inputTypeId, targetTypeId, -1);
|
||||
*pnode = coerce_type(pstate, *pnode, inputTypeId, targetTypeId, -1,
|
||||
false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -378,7 +387,7 @@ select_common_type(List *typeids, const char *context)
|
|||
}
|
||||
else if (IsPreferredType(pcategory, ntype)
|
||||
&& !IsPreferredType(pcategory, ptype)
|
||||
&& can_coerce_type(1, &ptype, &ntype))
|
||||
&& can_coerce_type(1, &ptype, &ntype, false))
|
||||
{
|
||||
/*
|
||||
* new one is preferred and can convert? then take it...
|
||||
|
@ -424,8 +433,9 @@ coerce_to_common_type(ParseState *pstate, Node *node,
|
|||
|
||||
if (inputTypeId == targetTypeId)
|
||||
return node; /* no work */
|
||||
if (can_coerce_type(1, &inputTypeId, &targetTypeId))
|
||||
node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1);
|
||||
if (can_coerce_type(1, &inputTypeId, &targetTypeId, false))
|
||||
node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1,
|
||||
false);
|
||||
else
|
||||
{
|
||||
elog(ERROR, "%s unable to convert to type \"%s\"",
|
||||
|
@ -659,6 +669,9 @@ PreferredType(CATEGORY category, Oid type)
|
|||
* A coercion function must be named after (the internal name of) its
|
||||
* result type, and must accept exactly the specified input type. We
|
||||
* also require it to be defined in the same namespace as its result type.
|
||||
* Furthermore, unless we are doing explicit coercion the function must
|
||||
* be marked as usable for implicit coercion --- this allows coercion
|
||||
* functions to be provided that aren't implicitly invokable.
|
||||
*
|
||||
* This routine is also used to look for length-coercion functions, which
|
||||
* are similar but accept a second argument. secondArgType is the type
|
||||
|
@ -668,16 +681,16 @@ PreferredType(CATEGORY category, Oid type)
|
|||
* If a function is found, return its pg_proc OID; else return InvalidOid.
|
||||
*/
|
||||
static Oid
|
||||
find_coercion_function(Oid targetTypeId, Oid inputTypeId, Oid secondArgType)
|
||||
find_coercion_function(Oid targetTypeId, Oid inputTypeId, Oid secondArgType,
|
||||
bool isExplicit)
|
||||
{
|
||||
Oid funcid = InvalidOid;
|
||||
Type targetType;
|
||||
char *typname;
|
||||
Oid typnamespace;
|
||||
Oid oid_array[FUNC_MAX_ARGS];
|
||||
int nargs;
|
||||
HeapTuple ftup;
|
||||
Form_pg_proc pform;
|
||||
Oid funcid;
|
||||
|
||||
targetType = typeidType(targetTypeId);
|
||||
typname = NameStr(((Form_pg_type) GETSTRUCT(targetType))->typname);
|
||||
|
@ -698,21 +711,24 @@ find_coercion_function(Oid targetTypeId, Oid inputTypeId, Oid secondArgType)
|
|||
Int16GetDatum(nargs),
|
||||
PointerGetDatum(oid_array),
|
||||
ObjectIdGetDatum(typnamespace));
|
||||
if (!HeapTupleIsValid(ftup))
|
||||
{
|
||||
ReleaseSysCache(targetType);
|
||||
return InvalidOid;
|
||||
}
|
||||
/* Make sure the function's result type is as expected, too */
|
||||
pform = (Form_pg_proc) GETSTRUCT(ftup);
|
||||
if (pform->prorettype != targetTypeId)
|
||||
if (HeapTupleIsValid(ftup))
|
||||
{
|
||||
Form_pg_proc pform = (Form_pg_proc) GETSTRUCT(ftup);
|
||||
|
||||
/* Make sure the function's result type is as expected */
|
||||
if (pform->prorettype == targetTypeId && !pform->proretset &&
|
||||
!pform->proisagg)
|
||||
{
|
||||
/* If needed, make sure it can be invoked implicitly */
|
||||
if (isExplicit || pform->proimplicit)
|
||||
{
|
||||
/* Okay to use it */
|
||||
funcid = ftup->t_data->t_oid;
|
||||
}
|
||||
}
|
||||
ReleaseSysCache(ftup);
|
||||
ReleaseSysCache(targetType);
|
||||
return InvalidOid;
|
||||
}
|
||||
funcid = ftup->t_data->t_oid;
|
||||
ReleaseSysCache(ftup);
|
||||
|
||||
ReleaseSysCache(targetType);
|
||||
return funcid;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.113 2002/04/09 20:35:52 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.114 2002/04/11 20:00:00 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -1174,7 +1174,8 @@ parser_typecast_expression(ParseState *pstate,
|
|||
if (inputType != targetType)
|
||||
{
|
||||
expr = CoerceTargetExpr(pstate, expr, inputType,
|
||||
targetType, typename->typmod);
|
||||
targetType, typename->typmod,
|
||||
true); /* explicit coercion */
|
||||
if (expr == NULL)
|
||||
elog(ERROR, "Cannot cast type '%s' to '%s'",
|
||||
format_type_be(inputType),
|
||||
|
|
|
@ -8,23 +8,18 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.125 2002/04/09 20:35:53 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.126 2002/04/11 20:00:01 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/genam.h"
|
||||
#include "access/heapam.h"
|
||||
#include "catalog/catname.h"
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_aggregate.h"
|
||||
#include "catalog/pg_inherits.h"
|
||||
#include "catalog/pg_namespace.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "parser/parse_agg.h"
|
||||
#include "parser/parse_coerce.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "parser/parse_func.h"
|
||||
|
@ -35,6 +30,7 @@
|
|||
#include "utils/lsyscache.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
static Node *ParseComplexProjection(ParseState *pstate,
|
||||
char *funcname,
|
||||
Node *first_arg);
|
||||
|
@ -54,9 +50,6 @@ static int match_argtypes(int nargs,
|
|||
static FieldSelect *setup_field_select(Node *input, char *attname, Oid relid);
|
||||
static FuncCandidateList func_select_candidate(int nargs, Oid *input_typeids,
|
||||
FuncCandidateList candidates);
|
||||
static int agg_get_candidates(List *aggname, Oid typeId,
|
||||
FuncCandidateList *candidates);
|
||||
static Oid agg_select_candidate(Oid typeid, FuncCandidateList candidates);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -89,14 +82,10 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
|||
char *refname;
|
||||
int nargs = length(fargs);
|
||||
int argn;
|
||||
Func *funcnode;
|
||||
Oid oid_array[FUNC_MAX_ARGS];
|
||||
Oid *true_oid_array;
|
||||
Node *retval;
|
||||
bool retset;
|
||||
bool must_be_agg = agg_star || agg_distinct;
|
||||
bool could_be_agg;
|
||||
Expr *expr;
|
||||
FuncDetailCode fdresult;
|
||||
|
||||
/*
|
||||
|
@ -123,7 +112,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
|||
* then the "function call" could be a projection. We also check
|
||||
* that there wasn't any aggregate decoration.
|
||||
*/
|
||||
if (nargs == 1 && !must_be_agg && length(funcname) == 1)
|
||||
if (nargs == 1 && !agg_star && !agg_distinct && length(funcname) == 1)
|
||||
{
|
||||
char *cname = strVal(lfirst(funcname));
|
||||
|
||||
|
@ -151,84 +140,6 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* See if it's an aggregate.
|
||||
*/
|
||||
if (must_be_agg)
|
||||
{
|
||||
/* We don't presently cope with, eg, foo(DISTINCT x,y) */
|
||||
if (nargs != 1)
|
||||
elog(ERROR, "Aggregate functions may only have one parameter");
|
||||
/* Agg's argument can't be a relation name, either */
|
||||
if (IsA(first_arg, RangeVar))
|
||||
elog(ERROR, "Aggregate functions cannot be applied to relation names");
|
||||
could_be_agg = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Try to parse as an aggregate if above-mentioned checks are OK */
|
||||
could_be_agg = (nargs == 1) && !(IsA(first_arg, RangeVar));
|
||||
}
|
||||
|
||||
if (could_be_agg)
|
||||
{
|
||||
Oid basetype = exprType(lfirst(fargs));
|
||||
int ncandidates;
|
||||
FuncCandidateList candidates;
|
||||
|
||||
/* try for exact match first... */
|
||||
if (SearchSysCacheExists(AGGNAME,
|
||||
PointerGetDatum(strVal(llast(funcname))),
|
||||
ObjectIdGetDatum(basetype),
|
||||
0, 0))
|
||||
return (Node *) ParseAgg(pstate, funcname, basetype,
|
||||
fargs, agg_star, agg_distinct);
|
||||
|
||||
/* check for aggregate-that-accepts-any-type (eg, COUNT) */
|
||||
if (SearchSysCacheExists(AGGNAME,
|
||||
PointerGetDatum(strVal(llast(funcname))),
|
||||
ObjectIdGetDatum(0),
|
||||
0, 0))
|
||||
return (Node *) ParseAgg(pstate, funcname, 0,
|
||||
fargs, agg_star, agg_distinct);
|
||||
|
||||
/*
|
||||
* No exact match yet, so see if there is another entry in the
|
||||
* aggregate table that is compatible. - thomas 1998-12-05
|
||||
*/
|
||||
ncandidates = agg_get_candidates(funcname, basetype, &candidates);
|
||||
if (ncandidates > 0)
|
||||
{
|
||||
Oid type;
|
||||
|
||||
type = agg_select_candidate(basetype, candidates);
|
||||
if (OidIsValid(type))
|
||||
{
|
||||
lfirst(fargs) = coerce_type(pstate, lfirst(fargs),
|
||||
basetype, type, -1);
|
||||
basetype = type;
|
||||
return (Node *) ParseAgg(pstate, funcname, basetype,
|
||||
fargs, agg_star, agg_distinct);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Multiple possible matches --- give up */
|
||||
elog(ERROR, "Unable to select an aggregate function %s(%s)",
|
||||
NameListToString(funcname), format_type_be(basetype));
|
||||
}
|
||||
}
|
||||
|
||||
if (must_be_agg)
|
||||
{
|
||||
/*
|
||||
* No matching agg, but we had '*' or DISTINCT, so a plain
|
||||
* function could not have been meant.
|
||||
*/
|
||||
elog(ERROR, "There is no aggregate function %s(%s)",
|
||||
NameListToString(funcname), format_type_be(basetype));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Okay, it's not a column projection, so it must really be a function.
|
||||
* Extract arg type info and transform RangeVar arguments into varnodes
|
||||
|
@ -321,9 +232,22 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
|||
* these cases, so why duplicate code...
|
||||
*/
|
||||
return coerce_type(pstate, lfirst(fargs),
|
||||
oid_array[0], rettype, -1);
|
||||
oid_array[0], rettype, -1, true);
|
||||
}
|
||||
if (fdresult != FUNCDETAIL_NORMAL)
|
||||
else if (fdresult == FUNCDETAIL_NORMAL)
|
||||
{
|
||||
/*
|
||||
* Normal function found; was there anything indicating it must be
|
||||
* an aggregate?
|
||||
*/
|
||||
if (agg_star)
|
||||
elog(ERROR, "%s(*) specified, but %s is not an aggregate function",
|
||||
NameListToString(funcname), NameListToString(funcname));
|
||||
if (agg_distinct)
|
||||
elog(ERROR, "DISTINCT specified, but %s is not an aggregate function",
|
||||
NameListToString(funcname));
|
||||
}
|
||||
else if (fdresult != FUNCDETAIL_AGGREGATE)
|
||||
{
|
||||
/*
|
||||
* Oops. Time to die.
|
||||
|
@ -341,167 +265,64 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
|||
"\n\tYou may need to add explicit typecasts");
|
||||
}
|
||||
|
||||
/* got it */
|
||||
funcnode = makeNode(Func);
|
||||
funcnode->funcid = funcid;
|
||||
funcnode->functype = rettype;
|
||||
funcnode->func_fcache = NULL;
|
||||
|
||||
/* perform the necessary typecasting of arguments */
|
||||
make_arguments(pstate, nargs, fargs, oid_array, true_oid_array);
|
||||
|
||||
expr = makeNode(Expr);
|
||||
expr->typeOid = rettype;
|
||||
expr->opType = FUNC_EXPR;
|
||||
expr->oper = (Node *) funcnode;
|
||||
expr->args = fargs;
|
||||
retval = (Node *) expr;
|
||||
|
||||
/*
|
||||
* if the function returns a set of values, then we need to iterate
|
||||
* over all the returned values in the executor, so we stick an iter
|
||||
* node here. if it returns a singleton, then we don't need the iter
|
||||
* node.
|
||||
*/
|
||||
if (retset)
|
||||
/* build the appropriate output structure */
|
||||
if (fdresult == FUNCDETAIL_NORMAL)
|
||||
{
|
||||
Iter *iter = makeNode(Iter);
|
||||
Expr *expr = makeNode(Expr);
|
||||
Func *funcnode = makeNode(Func);
|
||||
|
||||
iter->itertype = rettype;
|
||||
iter->iterexpr = retval;
|
||||
retval = (Node *) iter;
|
||||
funcnode->funcid = funcid;
|
||||
funcnode->functype = rettype;
|
||||
funcnode->func_fcache = NULL;
|
||||
|
||||
expr->typeOid = rettype;
|
||||
expr->opType = FUNC_EXPR;
|
||||
expr->oper = (Node *) funcnode;
|
||||
expr->args = fargs;
|
||||
|
||||
retval = (Node *) expr;
|
||||
|
||||
/*
|
||||
* if the function returns a set of values, then we need to iterate
|
||||
* over all the returned values in the executor, so we stick an iter
|
||||
* node here. if it returns a singleton, then we don't need the iter
|
||||
* node.
|
||||
*/
|
||||
if (retset)
|
||||
{
|
||||
Iter *iter = makeNode(Iter);
|
||||
|
||||
iter->itertype = rettype;
|
||||
iter->iterexpr = retval;
|
||||
retval = (Node *) iter;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* aggregate function */
|
||||
Aggref *aggref = makeNode(Aggref);
|
||||
|
||||
aggref->aggfnoid = funcid;
|
||||
aggref->aggtype = rettype;
|
||||
aggref->target = lfirst(fargs);
|
||||
aggref->aggstar = agg_star;
|
||||
aggref->aggdistinct = agg_distinct;
|
||||
|
||||
retval = (Node *) aggref;
|
||||
|
||||
if (retset)
|
||||
elog(ERROR, "Aggregates may not return sets");
|
||||
|
||||
pstate->p_hasAggs = true;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
agg_get_candidates(List *aggname,
|
||||
Oid typeId,
|
||||
FuncCandidateList *candidates)
|
||||
{
|
||||
Relation pg_aggregate_desc;
|
||||
SysScanDesc pg_aggregate_scan;
|
||||
HeapTuple tup;
|
||||
int ncandidates = 0;
|
||||
ScanKeyData aggKey[1];
|
||||
|
||||
*candidates = NULL;
|
||||
|
||||
ScanKeyEntryInitialize(&aggKey[0], 0,
|
||||
Anum_pg_aggregate_aggname,
|
||||
F_NAMEEQ,
|
||||
NameGetDatum(strVal(llast(aggname))));
|
||||
|
||||
pg_aggregate_desc = heap_openr(AggregateRelationName, AccessShareLock);
|
||||
pg_aggregate_scan = systable_beginscan(pg_aggregate_desc,
|
||||
AggregateNameTypeIndex, true,
|
||||
SnapshotNow,
|
||||
1, aggKey);
|
||||
|
||||
while (HeapTupleIsValid(tup = systable_getnext(pg_aggregate_scan)))
|
||||
{
|
||||
Form_pg_aggregate agg = (Form_pg_aggregate) GETSTRUCT(tup);
|
||||
FuncCandidateList current_candidate;
|
||||
|
||||
current_candidate = (FuncCandidateList)
|
||||
palloc(sizeof(struct _FuncCandidateList));
|
||||
current_candidate->args[0] = agg->aggbasetype;
|
||||
current_candidate->next = *candidates;
|
||||
*candidates = current_candidate;
|
||||
ncandidates++;
|
||||
}
|
||||
|
||||
systable_endscan(pg_aggregate_scan);
|
||||
heap_close(pg_aggregate_desc, AccessShareLock);
|
||||
|
||||
return ncandidates;
|
||||
} /* agg_get_candidates() */
|
||||
|
||||
/* agg_select_candidate()
|
||||
*
|
||||
* Try to choose only one candidate aggregate function from a list of
|
||||
* possible matches. Return value is Oid of input type of aggregate
|
||||
* if successful, else InvalidOid.
|
||||
*/
|
||||
static Oid
|
||||
agg_select_candidate(Oid typeid, FuncCandidateList candidates)
|
||||
{
|
||||
FuncCandidateList current_candidate;
|
||||
FuncCandidateList last_candidate;
|
||||
Oid current_typeid;
|
||||
int ncandidates;
|
||||
CATEGORY category,
|
||||
current_category;
|
||||
|
||||
/*
|
||||
* First look for exact matches or binary compatible matches. (Of
|
||||
* course exact matches shouldn't even get here, but anyway.)
|
||||
*/
|
||||
ncandidates = 0;
|
||||
last_candidate = NULL;
|
||||
for (current_candidate = candidates;
|
||||
current_candidate != NULL;
|
||||
current_candidate = current_candidate->next)
|
||||
{
|
||||
current_typeid = current_candidate->args[0];
|
||||
|
||||
if (IsBinaryCompatible(current_typeid, typeid))
|
||||
{
|
||||
last_candidate = current_candidate;
|
||||
ncandidates++;
|
||||
}
|
||||
}
|
||||
if (ncandidates == 1)
|
||||
return last_candidate->args[0];
|
||||
|
||||
/*
|
||||
* If no luck that way, look for candidates which allow coercion and
|
||||
* have a preferred type. Keep all candidates if none match.
|
||||
*/
|
||||
category = TypeCategory(typeid);
|
||||
ncandidates = 0;
|
||||
last_candidate = NULL;
|
||||
for (current_candidate = candidates;
|
||||
current_candidate != NULL;
|
||||
current_candidate = current_candidate->next)
|
||||
{
|
||||
current_typeid = current_candidate->args[0];
|
||||
current_category = TypeCategory(current_typeid);
|
||||
|
||||
if (current_category == category
|
||||
&& IsPreferredType(current_category, current_typeid)
|
||||
&& can_coerce_type(1, &typeid, ¤t_typeid))
|
||||
{
|
||||
/* only one so far? then keep it... */
|
||||
if (last_candidate == NULL)
|
||||
{
|
||||
candidates = current_candidate;
|
||||
last_candidate = current_candidate;
|
||||
ncandidates = 1;
|
||||
}
|
||||
/* otherwise, keep this one too... */
|
||||
else
|
||||
{
|
||||
last_candidate->next = current_candidate;
|
||||
last_candidate = current_candidate;
|
||||
ncandidates++;
|
||||
}
|
||||
}
|
||||
/* otherwise, don't bother keeping this one around... */
|
||||
}
|
||||
|
||||
if (last_candidate) /* terminate rebuilt list */
|
||||
last_candidate->next = NULL;
|
||||
|
||||
if (ncandidates == 1)
|
||||
return candidates->args[0];
|
||||
|
||||
return InvalidOid;
|
||||
} /* agg_select_candidate() */
|
||||
|
||||
|
||||
/* match_argtypes()
|
||||
*
|
||||
* Given a list of possible typeid arrays to a function and an array of
|
||||
|
@ -529,7 +350,8 @@ match_argtypes(int nargs,
|
|||
current_candidate = next_candidate)
|
||||
{
|
||||
next_candidate = current_candidate->next;
|
||||
if (can_coerce_type(nargs, input_typeids, current_candidate->args))
|
||||
if (can_coerce_type(nargs, input_typeids, current_candidate->args,
|
||||
false))
|
||||
{
|
||||
current_candidate->next = *candidates;
|
||||
*candidates = current_candidate;
|
||||
|
@ -1014,6 +836,7 @@ func_get_detail(List *funcname,
|
|||
{
|
||||
HeapTuple ftup;
|
||||
Form_pg_proc pform;
|
||||
FuncDetailCode result;
|
||||
|
||||
*funcid = best_candidate->oid;
|
||||
*true_typeids = best_candidate->args;
|
||||
|
@ -1026,8 +849,9 @@ func_get_detail(List *funcname,
|
|||
pform = (Form_pg_proc) GETSTRUCT(ftup);
|
||||
*rettype = pform->prorettype;
|
||||
*retset = pform->proretset;
|
||||
result = pform->proisagg ? FUNCDETAIL_AGGREGATE : FUNCDETAIL_NORMAL;
|
||||
ReleaseSysCache(ftup);
|
||||
return FUNCDETAIL_NORMAL;
|
||||
return result;
|
||||
}
|
||||
|
||||
return FUNCDETAIL_NOTFOUND;
|
||||
|
@ -1294,7 +1118,8 @@ make_arguments(ParseState *pstate,
|
|||
lfirst(current_fargs) = coerce_type(pstate,
|
||||
lfirst(current_fargs),
|
||||
input_typeids[i],
|
||||
function_typeids[i], -1);
|
||||
function_typeids[i], -1,
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1450,6 +1275,58 @@ func_error(const char *caller, List *funcname,
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* find_aggregate_func
|
||||
* Convenience routine to check that a function exists and is an
|
||||
* aggregate.
|
||||
*
|
||||
* Note: basetype is InvalidOid if we are looking for an aggregate on
|
||||
* all types.
|
||||
*/
|
||||
Oid
|
||||
find_aggregate_func(const char *caller, List *aggname, Oid basetype)
|
||||
{
|
||||
Oid oid;
|
||||
HeapTuple ftup;
|
||||
Form_pg_proc pform;
|
||||
|
||||
oid = LookupFuncName(aggname, 1, &basetype);
|
||||
|
||||
if (!OidIsValid(oid))
|
||||
{
|
||||
if (basetype == InvalidOid)
|
||||
elog(ERROR, "%s: aggregate '%s' for all types does not exist",
|
||||
caller, NameListToString(aggname));
|
||||
else
|
||||
elog(ERROR, "%s: aggregate '%s' for type %s does not exist",
|
||||
caller, NameListToString(aggname),
|
||||
format_type_be(basetype));
|
||||
}
|
||||
|
||||
/* Make sure it's an aggregate */
|
||||
ftup = SearchSysCache(PROCOID,
|
||||
ObjectIdGetDatum(oid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(ftup)) /* should not happen */
|
||||
elog(ERROR, "function %u not found", oid);
|
||||
pform = (Form_pg_proc) GETSTRUCT(ftup);
|
||||
|
||||
if (!pform->proisagg)
|
||||
{
|
||||
if (basetype == InvalidOid)
|
||||
elog(ERROR, "%s: function %s(*) is not an aggregate",
|
||||
caller, NameListToString(aggname));
|
||||
else
|
||||
elog(ERROR, "%s: function %s(%s) is not an aggregate",
|
||||
caller, NameListToString(aggname),
|
||||
format_type_be(basetype));
|
||||
}
|
||||
|
||||
ReleaseSysCache(ftup);
|
||||
|
||||
return oid;
|
||||
}
|
||||
|
||||
/*
|
||||
* LookupFuncName
|
||||
* Given a possibly-qualified function name and a set of argument types,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.60 2002/03/21 16:01:07 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.61 2002/04/11 20:00:01 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -73,7 +73,8 @@ make_operand(char *opname,
|
|||
{
|
||||
/* must coerce? */
|
||||
if (target_typeId != orig_typeId)
|
||||
result = coerce_type(NULL, tree, orig_typeId, target_typeId, -1);
|
||||
result = coerce_type(NULL, tree, orig_typeId, target_typeId, -1,
|
||||
false);
|
||||
else
|
||||
result = tree;
|
||||
}
|
||||
|
@ -288,7 +289,7 @@ transformArraySubscripts(ParseState *pstate,
|
|||
subexpr = transformExpr(pstate, ai->lidx);
|
||||
/* If it's not int4 already, try to coerce */
|
||||
subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr),
|
||||
INT4OID, -1);
|
||||
INT4OID, -1, false);
|
||||
if (subexpr == NULL)
|
||||
elog(ERROR, "array index expressions must be integers");
|
||||
}
|
||||
|
@ -308,7 +309,7 @@ transformArraySubscripts(ParseState *pstate,
|
|||
subexpr = transformExpr(pstate, ai->uidx);
|
||||
/* If it's not int4 already, try to coerce */
|
||||
subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr),
|
||||
INT4OID, -1);
|
||||
INT4OID, -1, false);
|
||||
if (subexpr == NULL)
|
||||
elog(ERROR, "array index expressions must be integers");
|
||||
upperIndexpr = lappend(upperIndexpr, subexpr);
|
||||
|
@ -329,7 +330,7 @@ transformArraySubscripts(ParseState *pstate,
|
|||
/* XXX fixme: need to get the array's atttypmod? */
|
||||
assignFrom = CoerceTargetExpr(pstate, assignFrom,
|
||||
typesource, typeneeded,
|
||||
-1);
|
||||
-1, false);
|
||||
if (assignFrom == NULL)
|
||||
elog(ERROR, "Array assignment requires type '%s'"
|
||||
" but expression is of type '%s'"
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.53 2002/03/20 19:44:31 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.54 2002/04/11 20:00:02 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -265,7 +265,8 @@ oper_select_candidate(int nargs,
|
|||
current_candidate != NULL;
|
||||
current_candidate = current_candidate->next)
|
||||
{
|
||||
if (can_coerce_type(nargs, input_typeids, current_candidate->args))
|
||||
if (can_coerce_type(nargs, input_typeids, current_candidate->args,
|
||||
false))
|
||||
{
|
||||
if (last_candidate == NULL)
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.83 2002/04/09 20:35:53 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.84 2002/04/11 20:00:02 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -290,7 +290,8 @@ updateTargetListEntry(ParseState *pstate,
|
|||
if (type_id != attrtype)
|
||||
{
|
||||
tle->expr = CoerceTargetExpr(pstate, tle->expr, type_id,
|
||||
attrtype, attrtypmod);
|
||||
attrtype, attrtypmod,
|
||||
false);
|
||||
if (tle->expr == NULL)
|
||||
elog(ERROR, "column \"%s\" is of type '%s'"
|
||||
" but expression is of type '%s'"
|
||||
|
@ -327,10 +328,12 @@ CoerceTargetExpr(ParseState *pstate,
|
|||
Node *expr,
|
||||
Oid type_id,
|
||||
Oid attrtype,
|
||||
int32 attrtypmod)
|
||||
int32 attrtypmod,
|
||||
bool isExplicit)
|
||||
{
|
||||
if (can_coerce_type(1, &type_id, &attrtype))
|
||||
expr = coerce_type(pstate, expr, type_id, attrtype, attrtypmod);
|
||||
if (can_coerce_type(1, &type_id, &attrtype, isExplicit))
|
||||
expr = coerce_type(pstate, expr, type_id, attrtype, attrtypmod,
|
||||
isExplicit);
|
||||
|
||||
#ifndef DISABLE_STRING_HACKS
|
||||
|
||||
|
@ -345,8 +348,9 @@ CoerceTargetExpr(ParseState *pstate,
|
|||
if (type_id == TEXTOID)
|
||||
{
|
||||
}
|
||||
else if (can_coerce_type(1, &type_id, &text_id))
|
||||
expr = coerce_type(pstate, expr, type_id, text_id, attrtypmod);
|
||||
else if (can_coerce_type(1, &type_id, &text_id, isExplicit))
|
||||
expr = coerce_type(pstate, expr, type_id, text_id, attrtypmod,
|
||||
isExplicit);
|
||||
else
|
||||
expr = NULL;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.101 2002/04/05 05:47:05 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.102 2002/04/11 20:00:02 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -476,7 +476,7 @@ build_column_default(Relation rel, int attrno)
|
|||
if (exprtype != atttype)
|
||||
{
|
||||
expr = CoerceTargetExpr(NULL, expr, exprtype,
|
||||
atttype, atttypmod);
|
||||
atttype, atttypmod, false);
|
||||
|
||||
/*
|
||||
* This really shouldn't fail; should have checked the
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/utils/Attic/Gen_fmgrtab.sh,v 1.22 2002/04/05 00:31:28 tgl Exp $
|
||||
# $Header: /cvsroot/pgsql/src/backend/utils/Attic/Gen_fmgrtab.sh,v 1.23 2002/04/11 20:00:04 tgl Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
|
@ -88,6 +88,8 @@ trap 'echo "Caught signal." ; cleanup ; exit 1' 1 2 15
|
|||
# deal with preprocessor statements first (before we sort the
|
||||
# function table by oid).
|
||||
#
|
||||
# Note assumption here that prolang == $5 and INTERNALlanguageId == 12.
|
||||
#
|
||||
$AWK '
|
||||
BEGIN { raw = 0; }
|
||||
/^DATA/ { print; next; }
|
||||
|
@ -161,6 +163,8 @@ cat > "$$-$OIDSFILE" <<FuNkYfMgRsTuFf
|
|||
*/
|
||||
FuNkYfMgRsTuFf
|
||||
|
||||
# Note assumption here that prosrc == $(NF-2).
|
||||
|
||||
tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' < $RAWFILE | \
|
||||
$AWK '
|
||||
BEGIN { OFS = ""; }
|
||||
|
@ -209,6 +213,8 @@ cat > "$$-$TABLEFILE" <<FuNkYfMgRtAbStUfF
|
|||
|
||||
FuNkYfMgRtAbStUfF
|
||||
|
||||
# Note assumption here that prosrc == $(NF-2).
|
||||
|
||||
$AWK '{ print "extern Datum", $(NF-2), "(PG_FUNCTION_ARGS);"; }' $RAWFILE >> "$$-$TABLEFILE"
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
|
@ -226,13 +232,16 @@ FuNkYfMgRtAbStUfF
|
|||
# Note: using awk arrays to translate from pg_proc values to fmgrtab values
|
||||
# may seem tedious, but avoid the temptation to write a quick x?y:z
|
||||
# conditional expression instead. Not all awks have conditional expressions.
|
||||
#
|
||||
# Note assumptions here that prosrc == $(NF-2), pronargs == $12,
|
||||
# proisstrict == $9, proretset == $10
|
||||
|
||||
$AWK 'BEGIN {
|
||||
Bool["t"] = "true"
|
||||
Bool["f"] = "false"
|
||||
}
|
||||
{ printf (" { %d, \"%s\", %d, %s, %s, %s },\n"), \
|
||||
$1, $(NF-2), $10, Bool[$8], Bool[$11], $(NF-2)
|
||||
$1, $(NF-2), $12, Bool[$9], Bool[$10], $(NF-2)
|
||||
}' $RAWFILE >> "$$-$TABLEFILE"
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* back to source text
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.95 2002/03/22 02:56:35 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.96 2002/04/11 20:00:04 tgl Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
|
@ -130,6 +130,7 @@ static void get_names_for_var(Var *var, deparse_context *context,
|
|||
char **refname, char **attname);
|
||||
static void get_rule_expr(Node *node, deparse_context *context);
|
||||
static void get_func_expr(Expr *expr, deparse_context *context);
|
||||
static void get_agg_expr(Aggref *aggref, deparse_context *context);
|
||||
static Node *strip_type_coercion(Node *expr, Oid resultType);
|
||||
static void get_tle_expr(TargetEntry *tle, deparse_context *context);
|
||||
static void get_const_expr(Const *constval, deparse_context *context);
|
||||
|
@ -1694,18 +1695,7 @@ get_rule_expr(Node *node, deparse_context *context)
|
|||
break;
|
||||
|
||||
case T_Aggref:
|
||||
{
|
||||
Aggref *aggref = (Aggref *) node;
|
||||
|
||||
appendStringInfo(buf, "%s(%s",
|
||||
quote_identifier(aggref->aggname),
|
||||
aggref->aggdistinct ? "DISTINCT " : "");
|
||||
if (aggref->aggstar)
|
||||
appendStringInfo(buf, "*");
|
||||
else
|
||||
get_rule_expr(aggref->target, context);
|
||||
appendStringInfoChar(buf, ')');
|
||||
}
|
||||
get_agg_expr((Aggref *) node, context);
|
||||
break;
|
||||
|
||||
case T_Iter:
|
||||
|
@ -2000,6 +1990,45 @@ get_func_expr(Expr *expr, deparse_context *context)
|
|||
ReleaseSysCache(proctup);
|
||||
}
|
||||
|
||||
/* ----------
|
||||
* get_agg_expr - Parse back an Aggref node
|
||||
* ----------
|
||||
*/
|
||||
static void
|
||||
get_agg_expr(Aggref *aggref, deparse_context *context)
|
||||
{
|
||||
StringInfo buf = context->buf;
|
||||
HeapTuple proctup;
|
||||
Form_pg_proc procStruct;
|
||||
char *proname;
|
||||
|
||||
/*
|
||||
* Get the aggregate's pg_proc tuple
|
||||
*/
|
||||
proctup = SearchSysCache(PROCOID,
|
||||
ObjectIdGetDatum(aggref->aggfnoid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(proctup))
|
||||
elog(ERROR, "cache lookup for proc %u failed", aggref->aggfnoid);
|
||||
|
||||
procStruct = (Form_pg_proc) GETSTRUCT(proctup);
|
||||
proname = NameStr(procStruct->proname);
|
||||
|
||||
/*
|
||||
* Display it
|
||||
*/
|
||||
appendStringInfo(buf, "%s(%s",
|
||||
quote_identifier(proname),
|
||||
aggref->aggdistinct ? "DISTINCT " : "");
|
||||
if (aggref->aggstar)
|
||||
appendStringInfo(buf, "*");
|
||||
else
|
||||
get_rule_expr(aggref->target, context);
|
||||
appendStringInfoChar(buf, ')');
|
||||
|
||||
ReleaseSysCache(proctup);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* strip_type_coercion
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.42 2002/04/05 00:31:29 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.43 2002/04/11 20:00:05 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -58,16 +58,19 @@ SetDefine(char *querystr, Oid elemType)
|
|||
true, /* returnsSet */
|
||||
elemType, /* returnType */
|
||||
SQLlanguageId, /* language */
|
||||
querystr, /* sourceCode */
|
||||
fileName, /* fileName */
|
||||
querystr, /* prosrc */
|
||||
fileName, /* probin */
|
||||
false, /* not aggregate */
|
||||
true, /* trusted */
|
||||
false, /* not implicit coercion */
|
||||
false, /* isStrict (irrelevant, no args) */
|
||||
PROVOLATILE_VOLATILE, /* assume unsafe */
|
||||
100, /* byte_pct */
|
||||
0, /* perbyte_cpu */
|
||||
0, /* percall_cpu */
|
||||
100, /* outin_ratio */
|
||||
NIL); /* argList */
|
||||
0, /* parameterCount */
|
||||
NULL); /* parameterTypes */
|
||||
|
||||
/*
|
||||
* Since we're still inside this command of the transaction, we can't
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.88 2002/03/09 17:35:36 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.89 2002/04/11 20:00:05 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -307,19 +307,6 @@ _bpchar(PG_FUNCTION_ARGS)
|
|||
}
|
||||
|
||||
|
||||
/* bpchar_char()
|
||||
* Convert bpchar(1) to char.
|
||||
*
|
||||
* If input is multiple chars, only the first is returned.
|
||||
*/
|
||||
Datum
|
||||
bpchar_char(PG_FUNCTION_ARGS)
|
||||
{
|
||||
BpChar *s = PG_GETARG_BPCHAR_P(0);
|
||||
|
||||
PG_RETURN_CHAR(*VARDATA(s));
|
||||
}
|
||||
|
||||
/* char_bpchar()
|
||||
* Convert char to bpchar(1).
|
||||
*/
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.75 2002/04/09 20:35:54 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.76 2002/04/11 20:00:06 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* These routines allow the parser/planner/executor to perform
|
||||
|
@ -93,22 +93,12 @@ struct cachedesc
|
|||
};
|
||||
|
||||
static const struct cachedesc cacheinfo[] = {
|
||||
{AggregateRelationName, /* AGGNAME */
|
||||
AggregateNameTypeIndex,
|
||||
0,
|
||||
2,
|
||||
{
|
||||
Anum_pg_aggregate_aggname,
|
||||
Anum_pg_aggregate_aggbasetype,
|
||||
0,
|
||||
0
|
||||
}},
|
||||
{AggregateRelationName, /* AGGOID */
|
||||
AggregateOidIndex,
|
||||
{AggregateRelationName, /* AGGFNOID */
|
||||
AggregateFnoidIndex,
|
||||
0,
|
||||
1,
|
||||
{
|
||||
ObjectIdAttributeNumber,
|
||||
Anum_pg_aggregate_aggfnoid,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.246 2002/04/05 11:51:12 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.247 2002/04/11 20:00:06 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -1873,7 +1873,7 @@ getAggregates(int *numAggs)
|
|||
"(select usename from pg_user where aggowner = usesysid) as usename "
|
||||
"from pg_aggregate");
|
||||
}
|
||||
else
|
||||
else if (g_fout->remoteVersion < 70300)
|
||||
{
|
||||
appendPQExpBuffer(query, "SELECT pg_aggregate.oid, aggname, aggtransfn, "
|
||||
"aggfinalfn, aggtranstype, aggbasetype, "
|
||||
|
@ -1882,6 +1882,16 @@ getAggregates(int *numAggs)
|
|||
"(select usename from pg_user where aggowner = usesysid) as usename "
|
||||
"from pg_aggregate");
|
||||
}
|
||||
else
|
||||
{
|
||||
appendPQExpBuffer(query, "SELECT p.oid, proname as aggname, aggtransfn, "
|
||||
"aggfinalfn, aggtranstype, proargtypes[0] as aggbasetype, "
|
||||
"agginitval, "
|
||||
"'t'::boolean as convertok, "
|
||||
"(select usename from pg_user where proowner = usesysid) as usename "
|
||||
"from pg_aggregate a, pg_proc p "
|
||||
"where a.aggfnoid = p.oid");
|
||||
}
|
||||
|
||||
res = PQexec(g_conn, query->data);
|
||||
if (!res ||
|
||||
|
@ -1960,6 +1970,7 @@ getFuncs(int *numFuncs)
|
|||
int i_prosrc;
|
||||
int i_probin;
|
||||
int i_provolatile;
|
||||
int i_isimplicit;
|
||||
int i_isstrict;
|
||||
int i_usename;
|
||||
|
||||
|
@ -1972,7 +1983,8 @@ getFuncs(int *numFuncs)
|
|||
"proretset, proargtypes, prosrc, probin, "
|
||||
"(select usename from pg_user where proowner = usesysid) as usename, "
|
||||
"case when proiscachable then 'i' else 'v' end as provolatile, "
|
||||
"'f'::boolean as proisstrict "
|
||||
"'f'::boolean as proimplicit, "
|
||||
"'f'::boolean as proisstrict "
|
||||
"from pg_proc "
|
||||
"where pg_proc.oid > '%u'::oid",
|
||||
g_last_builtin_oid);
|
||||
|
@ -1984,6 +1996,7 @@ getFuncs(int *numFuncs)
|
|||
"proretset, proargtypes, prosrc, probin, "
|
||||
"(select usename from pg_user where proowner = usesysid) as usename, "
|
||||
"case when proiscachable then 'i' else 'v' end as provolatile, "
|
||||
"'f'::boolean as proimplicit, "
|
||||
"proisstrict "
|
||||
"from pg_proc "
|
||||
"where pg_proc.oid > '%u'::oid",
|
||||
|
@ -1995,9 +2008,9 @@ getFuncs(int *numFuncs)
|
|||
"SELECT pg_proc.oid, proname, prolang, pronargs, prorettype, "
|
||||
"proretset, proargtypes, prosrc, probin, "
|
||||
"(select usename from pg_user where proowner = usesysid) as usename, "
|
||||
"provolatile, proisstrict "
|
||||
"provolatile, proimplicit, proisstrict "
|
||||
"from pg_proc "
|
||||
"where pg_proc.oid > '%u'::oid",
|
||||
"where pg_proc.oid > '%u'::oid and not proisagg",
|
||||
g_last_builtin_oid);
|
||||
}
|
||||
|
||||
|
@ -2028,6 +2041,7 @@ getFuncs(int *numFuncs)
|
|||
i_prosrc = PQfnumber(res, "prosrc");
|
||||
i_probin = PQfnumber(res, "probin");
|
||||
i_provolatile = PQfnumber(res, "provolatile");
|
||||
i_isimplicit = PQfnumber(res, "proimplicit");
|
||||
i_isstrict = PQfnumber(res, "proisstrict");
|
||||
i_usename = PQfnumber(res, "usename");
|
||||
|
||||
|
@ -2045,6 +2059,7 @@ getFuncs(int *numFuncs)
|
|||
finfo[i].lang = atooid(PQgetvalue(res, i, i_prolang));
|
||||
finfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
|
||||
finfo[i].provolatile = (PQgetvalue(res, i, i_provolatile))[0];
|
||||
finfo[i].isimplicit = (strcmp(PQgetvalue(res, i, i_isimplicit), "t") == 0);
|
||||
finfo[i].isstrict = (strcmp(PQgetvalue(res, i, i_isstrict), "t") == 0);
|
||||
|
||||
if (strlen(finfo[i].usename) == 0)
|
||||
|
@ -3670,6 +3685,7 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
|
|||
formatStringLiteral(q, func_lang, CONV_ALL);
|
||||
|
||||
if (finfo[i].provolatile != PROVOLATILE_VOLATILE ||
|
||||
finfo[i].isimplicit ||
|
||||
finfo[i].isstrict) /* OR in new attrs here */
|
||||
{
|
||||
appendPQExpBuffer(q, " WITH (");
|
||||
|
@ -3692,11 +3708,18 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo, int i,
|
|||
exit_nicely();
|
||||
}
|
||||
|
||||
if (finfo[i].isimplicit)
|
||||
{
|
||||
appendPQExpBuffer(q, "%s implicitCoercion", listSep);
|
||||
listSep = listSepComma;
|
||||
}
|
||||
|
||||
if (finfo[i].isstrict)
|
||||
{
|
||||
appendPQExpBuffer(q, "%s isStrict", listSep);
|
||||
listSep = listSepComma;
|
||||
}
|
||||
|
||||
appendPQExpBuffer(q, " )");
|
||||
}
|
||||
|
||||
|
@ -4012,7 +4035,12 @@ dumpAggs(Archive *fout, AggInfo *agginfo, int numAggs,
|
|||
|
||||
resetPQExpBuffer(q);
|
||||
appendPQExpBuffer(q, "AGGREGATE %s", aggSig->data);
|
||||
dumpComment(fout, q->data, agginfo[i].oid, "pg_aggregate", 0, NULL);
|
||||
if (g_fout->remoteVersion < 70300)
|
||||
dumpComment(fout, q->data, agginfo[i].oid, "pg_aggregate",
|
||||
0, NULL);
|
||||
else
|
||||
dumpComment(fout, q->data, agginfo[i].oid, "pg_proc",
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
destroyPQExpBuffer(q);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pg_dump.h,v 1.80 2002/04/05 11:51:13 momjian Exp $
|
||||
* $Id: pg_dump.h,v 1.81 2002/04/11 20:00:08 tgl Exp $
|
||||
*
|
||||
* Modifications - 6/12/96 - dave@bensoft.com - version 1.13.dhb.2
|
||||
*
|
||||
|
@ -73,6 +73,7 @@ typedef struct _funcInfo
|
|||
char *probin;
|
||||
char *usename;
|
||||
char provolatile; /* Attr */
|
||||
bool isimplicit; /* Attr */
|
||||
bool isstrict; /* Attr */
|
||||
int dumped; /* 1 if already dumped */
|
||||
} FuncInfo;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright 2000 by PostgreSQL Global Development Group
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.48 2002/04/05 11:52:38 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.49 2002/04/11 20:00:08 tgl Exp $
|
||||
*/
|
||||
#include "postgres_fe.h"
|
||||
#include "describe.h"
|
||||
|
@ -43,22 +43,23 @@ describeAggregates(const char *name)
|
|||
|
||||
/*
|
||||
* There are two kinds of aggregates: ones that work on particular
|
||||
* types ones that work on all
|
||||
* types and ones that work on all (denoted by input type = 0)
|
||||
*/
|
||||
snprintf(buf, sizeof(buf),
|
||||
"SELECT a.aggname AS \"%s\",\n"
|
||||
" CASE a.aggbasetype\n"
|
||||
"SELECT p.proname AS \"%s\",\n"
|
||||
" CASE p.proargtypes[0]\n"
|
||||
" WHEN 0 THEN CAST('%s' AS text)\n"
|
||||
" ELSE format_type(a.aggbasetype, NULL)\n"
|
||||
" ELSE format_type(p.proargtypes[0], NULL)\n"
|
||||
" END AS \"%s\",\n"
|
||||
" obj_description(a.oid, 'pg_aggregate') as \"%s\"\n"
|
||||
"FROM pg_aggregate a\n",
|
||||
" obj_description(p.oid, 'pg_proc') as \"%s\"\n"
|
||||
"FROM pg_proc p\n"
|
||||
"WHERE p.proisagg\n",
|
||||
_("Name"), _("(all types)"),
|
||||
_("Data type"), _("Description"));
|
||||
|
||||
if (name)
|
||||
{
|
||||
strcat(buf, "WHERE a.aggname ~ '^");
|
||||
strcat(buf, " AND p.proname ~ '^");
|
||||
strncat(buf, name, REGEXP_CUTOFF);
|
||||
strcat(buf, "'\n");
|
||||
}
|
||||
|
@ -112,12 +113,12 @@ describeFunctions(const char *name, bool verbose)
|
|||
if (!verbose)
|
||||
strcat(buf,
|
||||
"\nFROM pg_proc p\n"
|
||||
"WHERE p.prorettype <> 0 AND (pronargs = 0 OR oidvectortypes(p.proargtypes) <> '')\n");
|
||||
"WHERE p.prorettype <> 0 AND (pronargs = 0 OR oidvectortypes(p.proargtypes) <> '') AND NOT p.proisagg\n");
|
||||
else
|
||||
strcat(buf,
|
||||
"\nFROM pg_proc p, pg_language l, pg_user u\n"
|
||||
"WHERE p.prolang = l.oid AND p.proowner = u.usesysid\n"
|
||||
" AND p.prorettype <> 0 AND (pronargs = 0 OR oidvectortypes(p.proargtypes) <> '')\n");
|
||||
" AND p.prorettype <> 0 AND (pronargs = 0 OR oidvectortypes(p.proargtypes) <> '') AND NOT p.proisagg\n");
|
||||
|
||||
if (name)
|
||||
{
|
||||
|
@ -347,16 +348,17 @@ objectDescription(const char *object)
|
|||
"FROM (\n"
|
||||
|
||||
/* Aggregate descriptions */
|
||||
" SELECT a.oid as oid, a.tableoid as tableoid,\n"
|
||||
" CAST(a.aggname AS text) as name, CAST('%s' AS text) as object\n"
|
||||
" FROM pg_aggregate a\n"
|
||||
" SELECT p.oid as oid, p.tableoid as tableoid,\n"
|
||||
" CAST(p.proname AS text) as name, CAST('%s' AS text) as object\n"
|
||||
" FROM pg_proc p\n"
|
||||
" WHERE p.proisagg\n"
|
||||
|
||||
/* Function descriptions (except in/outs for datatypes) */
|
||||
"UNION ALL\n"
|
||||
" SELECT p.oid as oid, p.tableoid as tableoid,\n"
|
||||
" CAST(p.proname AS text) as name, CAST('%s' AS text) as object\n"
|
||||
" FROM pg_proc p\n"
|
||||
" WHERE p.pronargs = 0 or oidvectortypes(p.proargtypes) <> ''\n"
|
||||
" WHERE (p.pronargs = 0 or oidvectortypes(p.proargtypes) <> '') AND NOT p.proisagg\n"
|
||||
|
||||
/* Operator descriptions (must get comment via associated function) */
|
||||
"UNION ALL\n"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright 2000 by PostgreSQL Global Development Group
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.47 2002/04/01 03:34:27 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/bin/psql/tab-complete.c,v 1.48 2002/04/11 20:00:09 tgl Exp $
|
||||
*/
|
||||
|
||||
/*----------------------------------------------------------------------
|
||||
|
@ -132,7 +132,7 @@ typedef struct
|
|||
} pgsql_thing_t;
|
||||
|
||||
pgsql_thing_t words_after_create[] = {
|
||||
{"AGGREGATE", "SELECT distinct aggname FROM pg_aggregate WHERE substr(aggname,1,%d)='%s'"},
|
||||
{"AGGREGATE", "SELECT distinct proname FROM pg_proc WHERE proisagg AND substr(proname,1,%d)='%s'"},
|
||||
{"DATABASE", "SELECT datname FROM pg_database WHERE substr(datname,1,%d)='%s'"},
|
||||
{"FUNCTION", "SELECT distinct proname FROM pg_proc WHERE substr(proname,1,%d)='%s'"},
|
||||
{"GROUP", "SELECT groname FROM pg_group WHERE substr(groname,1,%d)='%s'"},
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: catversion.h,v 1.113 2002/04/05 00:31:32 tgl Exp $
|
||||
* $Id: catversion.h,v 1.114 2002/04/11 20:00:10 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -53,6 +53,6 @@
|
|||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 200204031
|
||||
#define CATALOG_VERSION_NO 200204101
|
||||
|
||||
#endif
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: indexing.h,v 1.61 2002/04/05 00:31:32 tgl Exp $
|
||||
* $Id: indexing.h,v 1.62 2002/04/11 20:00:10 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -20,7 +20,7 @@
|
|||
/*
|
||||
* Number of indices that exist for each system catalog
|
||||
*/
|
||||
#define Num_pg_aggregate_indices 2
|
||||
#define Num_pg_aggregate_indices 1
|
||||
#define Num_pg_am_indices 2
|
||||
#define Num_pg_amop_indices 2
|
||||
#define Num_pg_amproc_indices 1
|
||||
|
@ -51,8 +51,7 @@
|
|||
#define AccessMethodOperatorIndex "pg_amop_opc_opr_index"
|
||||
#define AccessMethodStrategyIndex "pg_amop_opc_strategy_index"
|
||||
#define AccessMethodProcedureIndex "pg_amproc_opc_procnum_index"
|
||||
#define AggregateNameTypeIndex "pg_aggregate_name_type_index"
|
||||
#define AggregateOidIndex "pg_aggregate_oid_index"
|
||||
#define AggregateFnoidIndex "pg_aggregate_fnoid_index"
|
||||
#define AmNameIndex "pg_am_name_index"
|
||||
#define AmOidIndex "pg_am_oid_index"
|
||||
#define AttrDefaultIndex "pg_attrdef_adrelid_adnum_index"
|
||||
|
@ -145,8 +144,7 @@ extern void CatalogIndexInsert(Relation *idescs, int nIndices,
|
|||
* that is just like in a normal 'create index' SQL command.
|
||||
*/
|
||||
|
||||
DECLARE_UNIQUE_INDEX(pg_aggregate_name_type_index on pg_aggregate using btree(aggname name_ops, aggbasetype oid_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_aggregate_oid_index on pg_aggregate using btree(oid oid_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_aggregate_fnoid_index on pg_aggregate using btree(aggfnoid oid_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_am_name_index on pg_am using btree(amname name_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_am_oid_index on pg_am using btree(oid oid_ops));
|
||||
DECLARE_UNIQUE_INDEX(pg_amop_opc_opr_index on pg_amop using btree(amopclaid oid_ops, amopopr oid_ops));
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pg_aggregate.h,v 1.37 2002/04/09 20:35:54 tgl Exp $
|
||||
* $Id: pg_aggregate.h,v 1.38 2002/04/11 20:00:11 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* the genbki.sh script reads this file and generates .bki
|
||||
|
@ -31,25 +31,19 @@
|
|||
*
|
||||
* cpp turns this into typedef struct FormData_pg_aggregate
|
||||
*
|
||||
* aggname name of the aggregate
|
||||
* aggowner owner (creator) of the aggregate
|
||||
* aggfnoid pg_proc OID of the aggregate itself
|
||||
* aggtransfn transition function
|
||||
* aggfinalfn final function
|
||||
* aggbasetype type of data on which aggregate operates
|
||||
* aggtranstype type of aggregate's transition (state) data
|
||||
* aggfinaltype type of aggregate's final result
|
||||
* agginitval initial value for transition state
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
CATALOG(pg_aggregate)
|
||||
CATALOG(pg_aggregate) BKI_WITHOUT_OIDS
|
||||
{
|
||||
NameData aggname;
|
||||
int4 aggowner;
|
||||
regproc aggfnoid;
|
||||
regproc aggtransfn;
|
||||
regproc aggfinalfn;
|
||||
Oid aggbasetype;
|
||||
Oid aggtranstype;
|
||||
Oid aggfinaltype;
|
||||
text agginitval; /* VARIABLE LENGTH FIELD */
|
||||
} FormData_pg_aggregate;
|
||||
|
||||
|
@ -65,15 +59,12 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
|
|||
* ----------------
|
||||
*/
|
||||
|
||||
#define Natts_pg_aggregate 8
|
||||
#define Anum_pg_aggregate_aggname 1
|
||||
#define Anum_pg_aggregate_aggowner 2
|
||||
#define Anum_pg_aggregate_aggtransfn 3
|
||||
#define Anum_pg_aggregate_aggfinalfn 4
|
||||
#define Anum_pg_aggregate_aggbasetype 5
|
||||
#define Anum_pg_aggregate_aggtranstype 6
|
||||
#define Anum_pg_aggregate_aggfinaltype 7
|
||||
#define Anum_pg_aggregate_agginitval 8
|
||||
#define Natts_pg_aggregate 5
|
||||
#define Anum_pg_aggregate_aggfnoid 1
|
||||
#define Anum_pg_aggregate_aggtransfn 2
|
||||
#define Anum_pg_aggregate_aggfinalfn 3
|
||||
#define Anum_pg_aggregate_aggtranstype 4
|
||||
#define Anum_pg_aggregate_agginitval 5
|
||||
|
||||
|
||||
/* ----------------
|
||||
|
@ -81,76 +72,82 @@ typedef FormData_pg_aggregate *Form_pg_aggregate;
|
|||
* ---------------
|
||||
*/
|
||||
|
||||
DATA(insert OID = 0 ( avg PGUID int8_accum numeric_avg 20 1231 1700 "{0,0,0}" ));
|
||||
DATA(insert OID = 0 ( avg PGUID int4_avg_accum int8_avg 23 1016 1700 "{0,0}" ));
|
||||
DATA(insert OID = 0 ( avg PGUID int2_avg_accum int8_avg 21 1016 1700 "{0,0}" ));
|
||||
DATA(insert OID = 0 ( avg PGUID numeric_accum numeric_avg 1700 1231 1700 "{0,0,0}" ));
|
||||
DATA(insert OID = 0 ( avg PGUID float4_accum float8_avg 700 1022 701 "{0,0,0}" ));
|
||||
DATA(insert OID = 0 ( avg PGUID float8_accum float8_avg 701 1022 701 "{0,0,0}" ));
|
||||
DATA(insert OID = 0 ( avg PGUID interval_accum interval_avg 1186 1187 1186 "{0 second,0 second}" ));
|
||||
/* avg */
|
||||
DATA(insert ( 2100 int8_accum numeric_avg 1231 "{0,0,0}" ));
|
||||
DATA(insert ( 2101 int4_avg_accum int8_avg 1016 "{0,0}" ));
|
||||
DATA(insert ( 2102 int2_avg_accum int8_avg 1016 "{0,0}" ));
|
||||
DATA(insert ( 2103 numeric_accum numeric_avg 1231 "{0,0,0}" ));
|
||||
DATA(insert ( 2104 float4_accum float8_avg 1022 "{0,0,0}" ));
|
||||
DATA(insert ( 2105 float8_accum float8_avg 1022 "{0,0,0}" ));
|
||||
DATA(insert ( 2106 interval_accum interval_avg 1187 "{0 second,0 second}" ));
|
||||
|
||||
DATA(insert OID = 0 ( sum PGUID int8_sum - 20 1700 1700 _null_ ));
|
||||
DATA(insert OID = 0 ( sum PGUID int4_sum - 23 20 20 _null_ ));
|
||||
DATA(insert OID = 0 ( sum PGUID int2_sum - 21 20 20 _null_ ));
|
||||
DATA(insert OID = 0 ( sum PGUID float4pl - 700 700 700 _null_ ));
|
||||
DATA(insert OID = 0 ( sum PGUID float8pl - 701 701 701 _null_ ));
|
||||
DATA(insert OID = 0 ( sum PGUID cash_pl - 790 790 790 _null_ ));
|
||||
DATA(insert OID = 0 ( sum PGUID interval_pl - 1186 1186 1186 _null_ ));
|
||||
DATA(insert OID = 0 ( sum PGUID numeric_add - 1700 1700 1700 _null_ ));
|
||||
/* sum */
|
||||
DATA(insert ( 2107 int8_sum - 1700 _null_ ));
|
||||
DATA(insert ( 2108 int4_sum - 20 _null_ ));
|
||||
DATA(insert ( 2109 int2_sum - 20 _null_ ));
|
||||
DATA(insert ( 2110 float4pl - 700 _null_ ));
|
||||
DATA(insert ( 2111 float8pl - 701 _null_ ));
|
||||
DATA(insert ( 2112 cash_pl - 790 _null_ ));
|
||||
DATA(insert ( 2113 interval_pl - 1186 _null_ ));
|
||||
DATA(insert ( 2114 numeric_add - 1700 _null_ ));
|
||||
|
||||
DATA(insert OID = 0 ( max PGUID int8larger - 20 20 20 _null_ ));
|
||||
DATA(insert OID = 0 ( max PGUID int4larger - 23 23 23 _null_ ));
|
||||
DATA(insert OID = 0 ( max PGUID int2larger - 21 21 21 _null_ ));
|
||||
DATA(insert OID = 0 ( max PGUID oidlarger - 26 26 26 _null_ ));
|
||||
DATA(insert OID = 0 ( max PGUID float4larger - 700 700 700 _null_ ));
|
||||
DATA(insert OID = 0 ( max PGUID float8larger - 701 701 701 _null_ ));
|
||||
DATA(insert OID = 0 ( max PGUID int4larger - 702 702 702 _null_ ));
|
||||
DATA(insert OID = 0 ( max PGUID date_larger - 1082 1082 1082 _null_ ));
|
||||
DATA(insert OID = 0 ( max PGUID time_larger - 1083 1083 1083 _null_ ));
|
||||
DATA(insert OID = 0 ( max PGUID timetz_larger - 1266 1266 1266 _null_ ));
|
||||
DATA(insert OID = 0 ( max PGUID cashlarger - 790 790 790 _null_ ));
|
||||
DATA(insert OID = 0 ( max PGUID timestamp_larger - 1114 1114 1114 _null_ ));
|
||||
DATA(insert OID = 0 ( max PGUID timestamptz_larger - 1184 1184 1184 _null_ ));
|
||||
DATA(insert OID = 0 ( max PGUID interval_larger - 1186 1186 1186 _null_ ));
|
||||
DATA(insert OID = 0 ( max PGUID text_larger - 25 25 25 _null_ ));
|
||||
DATA(insert OID = 0 ( max PGUID numeric_larger - 1700 1700 1700 _null_ ));
|
||||
/* max */
|
||||
DATA(insert ( 2115 int8larger - 20 _null_ ));
|
||||
DATA(insert ( 2116 int4larger - 23 _null_ ));
|
||||
DATA(insert ( 2117 int2larger - 21 _null_ ));
|
||||
DATA(insert ( 2118 oidlarger - 26 _null_ ));
|
||||
DATA(insert ( 2119 float4larger - 700 _null_ ));
|
||||
DATA(insert ( 2120 float8larger - 701 _null_ ));
|
||||
DATA(insert ( 2121 int4larger - 702 _null_ ));
|
||||
DATA(insert ( 2122 date_larger - 1082 _null_ ));
|
||||
DATA(insert ( 2123 time_larger - 1083 _null_ ));
|
||||
DATA(insert ( 2124 timetz_larger - 1266 _null_ ));
|
||||
DATA(insert ( 2125 cashlarger - 790 _null_ ));
|
||||
DATA(insert ( 2126 timestamp_larger - 1114 _null_ ));
|
||||
DATA(insert ( 2127 timestamptz_larger - 1184 _null_ ));
|
||||
DATA(insert ( 2128 interval_larger - 1186 _null_ ));
|
||||
DATA(insert ( 2129 text_larger - 25 _null_ ));
|
||||
DATA(insert ( 2130 numeric_larger - 1700 _null_ ));
|
||||
|
||||
DATA(insert OID = 0 ( min PGUID int8smaller - 20 20 20 _null_ ));
|
||||
DATA(insert OID = 0 ( min PGUID int4smaller - 23 23 23 _null_ ));
|
||||
DATA(insert OID = 0 ( min PGUID int2smaller - 21 21 21 _null_ ));
|
||||
DATA(insert OID = 0 ( min PGUID oidsmaller - 26 26 26 _null_ ));
|
||||
DATA(insert OID = 0 ( min PGUID float4smaller - 700 700 700 _null_ ));
|
||||
DATA(insert OID = 0 ( min PGUID float8smaller - 701 701 701 _null_ ));
|
||||
DATA(insert OID = 0 ( min PGUID int4smaller - 702 702 702 _null_ ));
|
||||
DATA(insert OID = 0 ( min PGUID date_smaller - 1082 1082 1082 _null_ ));
|
||||
DATA(insert OID = 0 ( min PGUID time_smaller - 1083 1083 1083 _null_ ));
|
||||
DATA(insert OID = 0 ( min PGUID timetz_smaller - 1266 1266 1266 _null_ ));
|
||||
DATA(insert OID = 0 ( min PGUID cashsmaller - 790 790 790 _null_ ));
|
||||
DATA(insert OID = 0 ( min PGUID timestamp_smaller - 1114 1114 1114 _null_ ));
|
||||
DATA(insert OID = 0 ( min PGUID timestamptz_smaller - 1184 1184 1184 _null_ ));
|
||||
DATA(insert OID = 0 ( min PGUID interval_smaller - 1186 1186 1186 _null_ ));
|
||||
DATA(insert OID = 0 ( min PGUID text_smaller - 25 25 25 _null_ ));
|
||||
DATA(insert OID = 0 ( min PGUID numeric_smaller - 1700 1700 1700 _null_ ));
|
||||
/* min */
|
||||
DATA(insert ( 2131 int8smaller - 20 _null_ ));
|
||||
DATA(insert ( 2132 int4smaller - 23 _null_ ));
|
||||
DATA(insert ( 2133 int2smaller - 21 _null_ ));
|
||||
DATA(insert ( 2134 oidsmaller - 26 _null_ ));
|
||||
DATA(insert ( 2135 float4smaller - 700 _null_ ));
|
||||
DATA(insert ( 2136 float8smaller - 701 _null_ ));
|
||||
DATA(insert ( 2137 int4smaller - 702 _null_ ));
|
||||
DATA(insert ( 2138 date_smaller - 1082 _null_ ));
|
||||
DATA(insert ( 2139 time_smaller - 1083 _null_ ));
|
||||
DATA(insert ( 2140 timetz_smaller - 1266 _null_ ));
|
||||
DATA(insert ( 2141 cashsmaller - 790 _null_ ));
|
||||
DATA(insert ( 2142 timestamp_smaller - 1114 _null_ ));
|
||||
DATA(insert ( 2143 timestamptz_smaller - 1184 _null_ ));
|
||||
DATA(insert ( 2144 interval_smaller - 1186 _null_ ));
|
||||
DATA(insert ( 2145 text_smaller - 25 _null_ ));
|
||||
DATA(insert ( 2146 numeric_smaller - 1700 _null_ ));
|
||||
|
||||
/*
|
||||
* Using int8inc for count() is cheating a little, since it really only
|
||||
* takes 1 parameter not 2, but nodeAgg.c won't complain ...
|
||||
*/
|
||||
DATA(insert OID = 0 ( count PGUID int8inc - 0 20 20 0 ));
|
||||
DATA(insert ( 2147 int8inc - 20 0 ));
|
||||
|
||||
DATA(insert OID = 0 ( variance PGUID int8_accum numeric_variance 20 1231 1700 "{0,0,0}" ));
|
||||
DATA(insert OID = 0 ( variance PGUID int4_accum numeric_variance 23 1231 1700 "{0,0,0}" ));
|
||||
DATA(insert OID = 0 ( variance PGUID int2_accum numeric_variance 21 1231 1700 "{0,0,0}" ));
|
||||
DATA(insert OID = 0 ( variance PGUID float4_accum float8_variance 700 1022 701 "{0,0,0}" ));
|
||||
DATA(insert OID = 0 ( variance PGUID float8_accum float8_variance 701 1022 701 "{0,0,0}" ));
|
||||
DATA(insert OID = 0 ( variance PGUID numeric_accum numeric_variance 1700 1231 1700 "{0,0,0}" ));
|
||||
/* variance */
|
||||
DATA(insert ( 2148 int8_accum numeric_variance 1231 "{0,0,0}" ));
|
||||
DATA(insert ( 2149 int4_accum numeric_variance 1231 "{0,0,0}" ));
|
||||
DATA(insert ( 2150 int2_accum numeric_variance 1231 "{0,0,0}" ));
|
||||
DATA(insert ( 2151 float4_accum float8_variance 1022 "{0,0,0}" ));
|
||||
DATA(insert ( 2152 float8_accum float8_variance 1022 "{0,0,0}" ));
|
||||
DATA(insert ( 2153 numeric_accum numeric_variance 1231 "{0,0,0}" ));
|
||||
|
||||
DATA(insert OID = 0 ( stddev PGUID int8_accum numeric_stddev 20 1231 1700 "{0,0,0}" ));
|
||||
DATA(insert OID = 0 ( stddev PGUID int4_accum numeric_stddev 23 1231 1700 "{0,0,0}" ));
|
||||
DATA(insert OID = 0 ( stddev PGUID int2_accum numeric_stddev 21 1231 1700 "{0,0,0}" ));
|
||||
DATA(insert OID = 0 ( stddev PGUID float4_accum float8_stddev 700 1022 701 "{0,0,0}" ));
|
||||
DATA(insert OID = 0 ( stddev PGUID float8_accum float8_stddev 701 1022 701 "{0,0,0}" ));
|
||||
DATA(insert OID = 0 ( stddev PGUID numeric_accum numeric_stddev 1700 1231 1700 "{0,0,0}" ));
|
||||
/* stddev */
|
||||
DATA(insert ( 2154 int8_accum numeric_stddev 1231 "{0,0,0}" ));
|
||||
DATA(insert ( 2155 int4_accum numeric_stddev 1231 "{0,0,0}" ));
|
||||
DATA(insert ( 2156 int2_accum numeric_stddev 1231 "{0,0,0}" ));
|
||||
DATA(insert ( 2157 float4_accum float8_stddev 1022 "{0,0,0}" ));
|
||||
DATA(insert ( 2158 float8_accum float8_stddev 1022 "{0,0,0}" ));
|
||||
DATA(insert ( 2159 numeric_accum numeric_stddev 1231 "{0,0,0}" ));
|
||||
|
||||
/*
|
||||
* prototypes for functions in pg_aggregate.c
|
||||
|
@ -163,7 +160,4 @@ extern void AggregateCreate(const char *aggName,
|
|||
Oid aggTransType,
|
||||
const char *agginitval);
|
||||
|
||||
extern Datum AggNameGetInitVal(char *aggName, Oid basetype,
|
||||
bool *isNull);
|
||||
|
||||
#endif /* PG_AGGREGATE_H */
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pg_attribute.h,v 1.89 2002/04/05 00:31:33 tgl Exp $
|
||||
* $Id: pg_attribute.h,v 1.90 2002/04/11 20:00:11 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* the genbki.sh script reads this file and generates .bki
|
||||
|
@ -298,41 +298,43 @@ DATA(insert ( 1262 tableoid 26 0 4 -7 0 -1 -1 t p f i f f));
|
|||
{ 1255, {"pronamespace"}, 26, 0, 4, 2, 0, -1, -1, true, 'p', false, 'i', false, false }, \
|
||||
{ 1255, {"proowner"}, 23, 0, 4, 3, 0, -1, -1, true, 'p', false, 'i', false, false }, \
|
||||
{ 1255, {"prolang"}, 26, 0, 4, 4, 0, -1, -1, true, 'p', false, 'i', false, false }, \
|
||||
{ 1255, {"proisinh"}, 16, 0, 1, 5, 0, -1, -1, true, 'p', false, 'c', false, false }, \
|
||||
{ 1255, {"proisagg"}, 16, 0, 1, 5, 0, -1, -1, true, 'p', false, 'c', false, false }, \
|
||||
{ 1255, {"proistrusted"}, 16, 0, 1, 6, 0, -1, -1, true, 'p', false, 'c', false, false }, \
|
||||
{ 1255, {"proisstrict"}, 16, 0, 1, 7, 0, -1, -1, true, 'p', false, 'c', false, false }, \
|
||||
{ 1255, {"provolatile"}, 18, 0, 1, 8, 0, -1, -1, true, 'p', false, 'c', false, false }, \
|
||||
{ 1255, {"pronargs"}, 21, 0, 2, 9, 0, -1, -1, true, 'p', false, 's', false, false }, \
|
||||
{ 1255, {"proretset"}, 16, 0, 1, 10, 0, -1, -1, true, 'p', false, 'c', false, false }, \
|
||||
{ 1255, {"prorettype"}, 26, 0, 4, 11, 0, -1, -1, true, 'p', false, 'i', false, false }, \
|
||||
{ 1255, {"proargtypes"}, 30, 0, INDEX_MAX_KEYS*4, 12, 0, -1, -1, false, 'p', false, 'i', false, false }, \
|
||||
{ 1255, {"probyte_pct"}, 23, 0, 4, 13, 0, -1, -1, true, 'p', false, 'i', false, false }, \
|
||||
{ 1255, {"properbyte_cpu"}, 23, 0, 4, 14, 0, -1, -1, true, 'p', false, 'i', false, false }, \
|
||||
{ 1255, {"propercall_cpu"}, 23, 0, 4, 15, 0, -1, -1, true, 'p', false, 'i', false, false }, \
|
||||
{ 1255, {"prooutin_ratio"}, 23, 0, 4, 16, 0, -1, -1, true, 'p', false, 'i', false, false }, \
|
||||
{ 1255, {"prosrc"}, 25, 0, -1, 17, 0, -1, -1, false, 'x', false, 'i', false, false }, \
|
||||
{ 1255, {"probin"}, 17, 0, -1, 18, 0, -1, -1, false, 'x', false, 'i', false, false }, \
|
||||
{ 1255, {"proacl"}, 1034, 0, -1, 19, 0, -1, -1, false, 'x', false, 'i', false, false }
|
||||
{ 1255, {"proimplicit"}, 16, 0, 1, 7, 0, -1, -1, true, 'p', false, 'c', false, false }, \
|
||||
{ 1255, {"proisstrict"}, 16, 0, 1, 8, 0, -1, -1, true, 'p', false, 'c', false, false }, \
|
||||
{ 1255, {"proretset"}, 16, 0, 1, 9, 0, -1, -1, true, 'p', false, 'c', false, false }, \
|
||||
{ 1255, {"provolatile"}, 18, 0, 1, 10, 0, -1, -1, true, 'p', false, 'c', false, false }, \
|
||||
{ 1255, {"pronargs"}, 21, 0, 2, 11, 0, -1, -1, true, 'p', false, 's', false, false }, \
|
||||
{ 1255, {"prorettype"}, 26, 0, 4, 12, 0, -1, -1, true, 'p', false, 'i', false, false }, \
|
||||
{ 1255, {"proargtypes"}, 30, 0, INDEX_MAX_KEYS*4, 13, 0, -1, -1, false, 'p', false, 'i', false, false }, \
|
||||
{ 1255, {"probyte_pct"}, 23, 0, 4, 14, 0, -1, -1, true, 'p', false, 'i', false, false }, \
|
||||
{ 1255, {"properbyte_cpu"}, 23, 0, 4, 15, 0, -1, -1, true, 'p', false, 'i', false, false }, \
|
||||
{ 1255, {"propercall_cpu"}, 23, 0, 4, 16, 0, -1, -1, true, 'p', false, 'i', false, false }, \
|
||||
{ 1255, {"prooutin_ratio"}, 23, 0, 4, 17, 0, -1, -1, true, 'p', false, 'i', false, false }, \
|
||||
{ 1255, {"prosrc"}, 25, 0, -1, 18, 0, -1, -1, false, 'x', false, 'i', false, false }, \
|
||||
{ 1255, {"probin"}, 17, 0, -1, 19, 0, -1, -1, false, 'x', false, 'i', false, false }, \
|
||||
{ 1255, {"proacl"}, 1034, 0, -1, 20, 0, -1, -1, false, 'x', false, 'i', false, false }
|
||||
|
||||
DATA(insert ( 1255 proname 19 DEFAULT_ATTSTATTARGET NAMEDATALEN 1 0 -1 -1 f p f i f f));
|
||||
DATA(insert ( 1255 pronamespace 26 0 4 2 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1255 proowner 23 0 4 3 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1255 prolang 26 0 4 4 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1255 proisinh 16 0 1 5 0 -1 -1 t p f c f f));
|
||||
DATA(insert ( 1255 proisagg 16 0 1 5 0 -1 -1 t p f c f f));
|
||||
DATA(insert ( 1255 proistrusted 16 0 1 6 0 -1 -1 t p f c f f));
|
||||
DATA(insert ( 1255 proisstrict 16 0 1 7 0 -1 -1 t p f c f f));
|
||||
DATA(insert ( 1255 provolatile 18 0 1 8 0 -1 -1 t p f c f f));
|
||||
DATA(insert ( 1255 pronargs 21 0 2 9 0 -1 -1 t p f s f f));
|
||||
DATA(insert ( 1255 proretset 16 0 1 10 0 -1 -1 t p f c f f));
|
||||
DATA(insert ( 1255 prorettype 26 0 4 11 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1255 proargtypes 30 0 INDEX_MAX_KEYS*4 12 0 -1 -1 f p f i f f));
|
||||
DATA(insert ( 1255 probyte_pct 23 0 4 13 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1255 properbyte_cpu 23 0 4 14 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1255 propercall_cpu 23 0 4 15 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1255 prooutin_ratio 23 0 4 16 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1255 prosrc 25 0 -1 17 0 -1 -1 f x f i f f));
|
||||
DATA(insert ( 1255 probin 17 0 -1 18 0 -1 -1 f x f i f f));
|
||||
DATA(insert ( 1255 proacl 1034 0 -1 19 0 -1 -1 f x f i f f));
|
||||
DATA(insert ( 1255 proimplicit 16 0 1 7 0 -1 -1 t p f c f f));
|
||||
DATA(insert ( 1255 proisstrict 16 0 1 8 0 -1 -1 t p f c f f));
|
||||
DATA(insert ( 1255 proretset 16 0 1 9 0 -1 -1 t p f c f f));
|
||||
DATA(insert ( 1255 provolatile 18 0 1 10 0 -1 -1 t p f c f f));
|
||||
DATA(insert ( 1255 pronargs 21 0 2 11 0 -1 -1 t p f s f f));
|
||||
DATA(insert ( 1255 prorettype 26 0 4 12 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1255 proargtypes 30 0 INDEX_MAX_KEYS*4 13 0 -1 -1 f p f i f f));
|
||||
DATA(insert ( 1255 probyte_pct 23 0 4 14 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1255 properbyte_cpu 23 0 4 15 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1255 propercall_cpu 23 0 4 16 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1255 prooutin_ratio 23 0 4 17 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1255 prosrc 25 0 -1 18 0 -1 -1 f x f i f f));
|
||||
DATA(insert ( 1255 probin 17 0 -1 19 0 -1 -1 f x f i f f));
|
||||
DATA(insert ( 1255 proacl 1034 0 -1 20 0 -1 -1 f x f i f f));
|
||||
DATA(insert ( 1255 ctid 27 0 6 -1 0 -1 -1 f p f i f f));
|
||||
DATA(insert ( 1255 oid 26 0 4 -2 0 -1 -1 t p f i f f));
|
||||
DATA(insert ( 1255 xmin 28 0 4 -3 0 -1 -1 t p f i f f));
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pg_class.h,v 1.65 2002/04/05 00:31:33 tgl Exp $
|
||||
* $Id: pg_class.h,v 1.66 2002/04/11 20:00:11 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* the genbki.sh script reads this file and generates .bki
|
||||
|
@ -138,7 +138,7 @@ DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 f f r 23 0 0 0
|
|||
DESCR("");
|
||||
DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 f f r 15 0 0 0 0 0 f f f f _null_ ));
|
||||
DESCR("");
|
||||
DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 f f r 19 0 0 0 0 0 t f f f _null_ ));
|
||||
DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 f f r 20 0 0 0 0 0 t f f f _null_ ));
|
||||
DESCR("");
|
||||
DATA(insert OID = 1259 ( pg_class PGNSP 83 PGUID 0 1259 0 0 0 0 f f r 24 0 0 0 0 0 t f f f _null_ ));
|
||||
DESCR("");
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pg_operator.h,v 1.100 2002/03/29 19:06:19 tgl Exp $
|
||||
* $Id: pg_operator.h,v 1.101 2002/04/11 20:00:11 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* the genbki.sh script reads this file and generates .bki
|
||||
|
@ -289,10 +289,10 @@ DATA(insert OID = 612 ( ">=" PGUID 0 b t f 26 26 16 611 609 0 0 oidge s
|
|||
#define MAX_OIDCMP 612 /* used by cache code */
|
||||
|
||||
DATA(insert OID = 644 ( "<>" PGUID 0 b t f 30 30 16 644 649 0 0 oidvectorne neqsel neqjoinsel ));
|
||||
DATA(insert OID = 645 ( "<" PGUID 0 b t f 30 30 16 646 648 0 0 oidvectorlt - - ));
|
||||
DATA(insert OID = 646 ( ">" PGUID 0 b t f 30 30 16 645 647 0 0 oidvectorgt - - ));
|
||||
DATA(insert OID = 647 ( "<=" PGUID 0 b t f 30 30 16 648 646 0 0 oidvectorle - - ));
|
||||
DATA(insert OID = 648 ( ">=" PGUID 0 b t f 30 30 16 647 645 0 0 oidvectorge - - ));
|
||||
DATA(insert OID = 645 ( "<" PGUID 0 b t f 30 30 16 646 648 0 0 oidvectorlt scalarltsel scalarltjoinsel ));
|
||||
DATA(insert OID = 646 ( ">" PGUID 0 b t f 30 30 16 645 647 0 0 oidvectorgt scalargtsel scalargtjoinsel ));
|
||||
DATA(insert OID = 647 ( "<=" PGUID 0 b t f 30 30 16 648 646 0 0 oidvectorle scalarltsel scalarltjoinsel ));
|
||||
DATA(insert OID = 648 ( ">=" PGUID 0 b t f 30 30 16 647 645 0 0 oidvectorge scalargtsel scalargtjoinsel ));
|
||||
DATA(insert OID = 649 ( "=" PGUID 0 b t t 30 30 16 649 644 645 645 oidvectoreq eqsel eqjoinsel ));
|
||||
|
||||
DATA(insert OID = 613 ( "<->" PGUID 0 b t f 600 628 701 0 0 0 0 dist_pl - - ));
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -7,13 +7,14 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodeAgg.h,v 1.15 2001/11/05 17:46:33 momjian Exp $
|
||||
* $Id: nodeAgg.h,v 1.16 2002/04/11 20:00:14 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef NODEAGG_H
|
||||
#define NODEAGG_H
|
||||
|
||||
#include "fmgr.h"
|
||||
#include "nodes/plannodes.h"
|
||||
|
||||
extern TupleTableSlot *ExecAgg(Agg *node);
|
||||
|
@ -22,4 +23,6 @@ extern int ExecCountSlotsAgg(Agg *node);
|
|||
extern void ExecEndAgg(Agg *node);
|
||||
extern void ExecReScanAgg(Agg *node, ExprContext *exprCtxt, Plan *parent);
|
||||
|
||||
extern Datum aggregate_dummy(PG_FUNCTION_ARGS);
|
||||
|
||||
#endif /* NODEAGG_H */
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: primnodes.h,v 1.60 2002/03/26 19:16:53 tgl Exp $
|
||||
* $Id: primnodes.h,v 1.61 2002/04/11 20:00:15 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -322,13 +322,9 @@ typedef struct Iter
|
|||
typedef struct Aggref
|
||||
{
|
||||
NodeTag type;
|
||||
char *aggname; /* name of the aggregate */
|
||||
Oid basetype; /* base type Oid of the aggregate (ie,
|
||||
* input type) */
|
||||
Oid aggtype; /* type Oid of final result of the
|
||||
* aggregate */
|
||||
Node *target; /* attribute or expression we are
|
||||
* aggregating on */
|
||||
Oid aggfnoid; /* pg_proc Oid of the aggregate */
|
||||
Oid aggtype; /* type Oid of result of the aggregate */
|
||||
Node *target; /* expression we are aggregating on */
|
||||
bool aggstar; /* TRUE if argument was really '*' */
|
||||
bool aggdistinct; /* TRUE if it's agg(DISTINCT ...) */
|
||||
int aggno; /* workspace for executor (see nodeAgg.c) */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: parse_agg.h,v 1.22 2002/04/09 20:35:55 tgl Exp $
|
||||
* $Id: parse_agg.h,v 1.23 2002/04/11 20:00:15 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -16,10 +16,6 @@
|
|||
|
||||
#include "parser/parse_node.h"
|
||||
|
||||
extern void AddAggToParseState(ParseState *pstate, Aggref *aggref);
|
||||
extern void parseCheckAggregates(ParseState *pstate, Query *qry, Node *qual);
|
||||
extern Aggref *ParseAgg(ParseState *pstate, List *aggname, Oid basetype,
|
||||
List *args, bool agg_star, bool agg_distinct);
|
||||
extern void agg_error(const char *caller, List *aggname, Oid basetypeID);
|
||||
|
||||
#endif /* PARSE_AGG_H */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: parse_coerce.h,v 1.41 2002/03/20 19:45:07 tgl Exp $
|
||||
* $Id: parse_coerce.h,v 1.42 2002/04/11 20:00:15 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -38,9 +38,10 @@ extern bool IsBinaryCompatible(Oid type1, Oid type2);
|
|||
extern bool IsPreferredType(CATEGORY category, Oid type);
|
||||
extern CATEGORY TypeCategory(Oid type);
|
||||
|
||||
extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids);
|
||||
extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
|
||||
bool isExplicit);
|
||||
extern Node *coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
||||
Oid targetTypeId, int32 atttypmod);
|
||||
Oid targetTypeId, int32 atttypmod, bool isExplicit);
|
||||
extern Node *coerce_type_typmod(ParseState *pstate, Node *node,
|
||||
Oid targetTypeId, int32 atttypmod);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: parse_func.h,v 1.38 2002/04/09 20:35:55 tgl Exp $
|
||||
* $Id: parse_func.h,v 1.39 2002/04/11 20:00:15 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -42,7 +42,8 @@ typedef struct _CandidateList
|
|||
typedef enum
|
||||
{
|
||||
FUNCDETAIL_NOTFOUND, /* no suitable interpretation */
|
||||
FUNCDETAIL_NORMAL, /* found a matching function */
|
||||
FUNCDETAIL_NORMAL, /* found a matching regular function */
|
||||
FUNCDETAIL_AGGREGATE, /* found a matching aggregate function */
|
||||
FUNCDETAIL_COERCION /* it's a type coercion request */
|
||||
} FuncDetailCode;
|
||||
|
||||
|
@ -62,6 +63,9 @@ extern void func_error(const char *caller, List *funcname,
|
|||
int nargs, const Oid *argtypes,
|
||||
const char *msg);
|
||||
|
||||
extern Oid find_aggregate_func(const char *caller, List *aggname,
|
||||
Oid basetype);
|
||||
|
||||
extern Oid LookupFuncName(List *funcname, int nargs, const Oid *argtypes);
|
||||
extern Oid LookupFuncNameTypeNames(List *funcname, List *argtypes,
|
||||
bool opaqueOK, const char *caller);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: parse_target.h,v 1.23 2001/11/05 17:46:35 momjian Exp $
|
||||
* $Id: parse_target.h,v 1.24 2002/04/11 20:00:16 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -24,7 +24,8 @@ extern void updateTargetListEntry(ParseState *pstate, TargetEntry *tle,
|
|||
char *colname, int attrno,
|
||||
List *indirection);
|
||||
extern Node *CoerceTargetExpr(ParseState *pstate, Node *expr,
|
||||
Oid type_id, Oid attrtype, int32 attrtypmod);
|
||||
Oid type_id, Oid attrtype, int32 attrtypmod,
|
||||
bool isExplicit);
|
||||
extern List *checkInsertTargets(ParseState *pstate, List *cols,
|
||||
List **attrnos);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: acl.h,v 1.41 2002/03/21 23:27:25 tgl Exp $
|
||||
* $Id: acl.h,v 1.42 2002/04/11 20:00:17 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* For backward-compatibility purposes we have to allow there
|
||||
|
@ -209,6 +209,5 @@ extern bool pg_class_ownercheck(Oid class_oid, Oid userid);
|
|||
extern bool pg_type_ownercheck(Oid type_oid, Oid userid);
|
||||
extern bool pg_oper_ownercheck(Oid oper_oid, Oid userid);
|
||||
extern bool pg_proc_ownercheck(Oid proc_oid, Oid userid);
|
||||
extern bool pg_aggr_ownercheck(Oid aggr_oid, Oid userid);
|
||||
|
||||
#endif /* ACL_H */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: builtins.h,v 1.175 2002/04/01 03:34:27 tgl Exp $
|
||||
* $Id: builtins.h,v 1.176 2002/04/11 20:00:17 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -363,7 +363,6 @@ extern Datum bpcharout(PG_FUNCTION_ARGS);
|
|||
extern Datum bpchar(PG_FUNCTION_ARGS);
|
||||
extern Datum _bpchar(PG_FUNCTION_ARGS);
|
||||
extern Datum char_bpchar(PG_FUNCTION_ARGS);
|
||||
extern Datum bpchar_char(PG_FUNCTION_ARGS);
|
||||
extern Datum name_bpchar(PG_FUNCTION_ARGS);
|
||||
extern Datum bpchar_name(PG_FUNCTION_ARGS);
|
||||
extern Datum bpchareq(PG_FUNCTION_ARGS);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: syscache.h,v 1.43 2002/04/09 20:35:55 tgl Exp $
|
||||
* $Id: syscache.h,v 1.44 2002/04/11 20:00:17 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -28,37 +28,36 @@
|
|||
* Keep them in alphabetical order.
|
||||
*/
|
||||
|
||||
#define AGGNAME 0
|
||||
#define AGGOID 1
|
||||
#define AMNAME 2
|
||||
#define AMOID 3
|
||||
#define AMOPOPID 4
|
||||
#define AMOPSTRATEGY 5
|
||||
#define AMPROCNUM 6
|
||||
#define ATTNAME 7
|
||||
#define ATTNUM 8
|
||||
#define CLAAMNAME 9
|
||||
#define CLAOID 10
|
||||
#define GRONAME 11
|
||||
#define GROSYSID 12
|
||||
#define INDEXRELID 13
|
||||
#define INHRELID 14
|
||||
#define LANGNAME 15
|
||||
#define LANGOID 16
|
||||
#define NAMESPACENAME 17
|
||||
#define NAMESPACEOID 18
|
||||
#define OPERNAME 19
|
||||
#define OPEROID 20
|
||||
#define PROCNAMENSP 21
|
||||
#define PROCOID 22
|
||||
#define RELNAMENSP 23
|
||||
#define RELOID 24
|
||||
#define RULENAME 25
|
||||
#define SHADOWNAME 26
|
||||
#define SHADOWSYSID 27
|
||||
#define STATRELATT 28
|
||||
#define TYPENAMENSP 29
|
||||
#define TYPEOID 30
|
||||
#define AGGFNOID 0
|
||||
#define AMNAME 1
|
||||
#define AMOID 2
|
||||
#define AMOPOPID 3
|
||||
#define AMOPSTRATEGY 4
|
||||
#define AMPROCNUM 5
|
||||
#define ATTNAME 6
|
||||
#define ATTNUM 7
|
||||
#define CLAAMNAME 8
|
||||
#define CLAOID 9
|
||||
#define GRONAME 10
|
||||
#define GROSYSID 11
|
||||
#define INDEXRELID 12
|
||||
#define INHRELID 13
|
||||
#define LANGNAME 14
|
||||
#define LANGOID 15
|
||||
#define NAMESPACENAME 16
|
||||
#define NAMESPACEOID 17
|
||||
#define OPERNAME 18
|
||||
#define OPEROID 19
|
||||
#define PROCNAMENSP 20
|
||||
#define PROCOID 21
|
||||
#define RELNAMENSP 22
|
||||
#define RELOID 23
|
||||
#define RULENAME 24
|
||||
#define SHADOWNAME 25
|
||||
#define SHADOWSYSID 26
|
||||
#define STATRELATT 27
|
||||
#define TYPENAMENSP 28
|
||||
#define TYPEOID 29
|
||||
|
||||
|
||||
extern void InitCatalogCache(void);
|
||||
|
|
|
@ -101,10 +101,11 @@ def list_lang_func(pgcnx, l):
|
|||
|
||||
# lists all the aggregate functions and the type to which they can be applied
|
||||
def list_agg_func(pgcnx):
|
||||
result = pgcnx.query("""SELECT a.aggname, t.typname
|
||||
FROM pg_aggregate a, pg_type t
|
||||
WHERE a.aggbasetype = t.oid
|
||||
ORDER BY aggname, typname""")
|
||||
result = pgcnx.query("""SELECT p.proname, t.typname
|
||||
FROM pg_aggregate a, pg_proc p, pg_type t
|
||||
WHERE a.aggfnoid = p.oid
|
||||
and p.proargtypes[0] = t.oid
|
||||
ORDER BY proname, typname""")
|
||||
return result
|
||||
|
||||
# lists all the operator classes that can be used with each access method as
|
||||
|
|
|
@ -292,8 +292,8 @@ ALTER TABLE foo_seq RENAME TO foo_seq_new;
|
|||
SELECT * FROM foo_seq_new;
|
||||
sequence_name | last_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called
|
||||
---------------+------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
|
||||
foo_seq | 1 | 1 | 9223372036854775807 | 1 | 1 | 1 | f | f
|
||||
(1 row)
|
||||
foo_seq | 1 | 1 | 9223372036854775807 | 1 | 1 | 1 | f | f
|
||||
(1 row)
|
||||
|
||||
DROP SEQUENCE foo_seq_new;
|
||||
-- FOREIGN KEY CONSTRAINT adding TEST
|
||||
|
@ -345,17 +345,17 @@ DROP TABLE tmp2;
|
|||
-- is run in parallel with foreign_key.sql.
|
||||
CREATE TEMP TABLE PKTABLE (ptest1 int PRIMARY KEY);
|
||||
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
|
||||
CREATE TEMP TABLE FKTABLE (ftest1 text);
|
||||
-- This next should fail, because text=int does not exist
|
||||
CREATE TEMP TABLE FKTABLE (ftest1 inet);
|
||||
-- This next should fail, because inet=int does not exist
|
||||
ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable;
|
||||
NOTICE: ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'text' and 'integer'
|
||||
ERROR: Unable to identify an operator '=' for types 'inet' and 'integer'
|
||||
You will have to retype this query using an explicit cast
|
||||
-- This should also fail for the same reason, but here we
|
||||
-- give the column name
|
||||
ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1);
|
||||
NOTICE: ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'text' and 'integer'
|
||||
ERROR: Unable to identify an operator '=' for types 'inet' and 'integer'
|
||||
You will have to retype this query using an explicit cast
|
||||
-- This should succeed, even though they are different types
|
||||
-- because varchar=int does exist
|
||||
|
@ -370,7 +370,7 @@ DROP TABLE pktable;
|
|||
NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "fktable"
|
||||
NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "fktable"
|
||||
DROP TABLE fktable;
|
||||
CREATE TEMP TABLE PKTABLE (ptest1 int, ptest2 text,
|
||||
CREATE TEMP TABLE PKTABLE (ptest1 int, ptest2 inet,
|
||||
PRIMARY KEY(ptest1, ptest2));
|
||||
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
|
||||
-- This should fail, because we just chose really odd types
|
||||
|
@ -389,17 +389,17 @@ ERROR: Unable to identify an operator '=' for types 'cidr' and 'integer'
|
|||
You will have to retype this query using an explicit cast
|
||||
-- This fails because we mixed up the column ordering
|
||||
DROP TABLE FKTABLE;
|
||||
CREATE TEMP TABLE FKTABLE (ftest1 int, ftest2 text);
|
||||
CREATE TEMP TABLE FKTABLE (ftest1 int, ftest2 inet);
|
||||
ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2)
|
||||
references pktable(ptest2, ptest1);
|
||||
NOTICE: ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'integer' and 'text'
|
||||
ERROR: Unable to identify an operator '=' for types 'integer' and 'inet'
|
||||
You will have to retype this query using an explicit cast
|
||||
-- As does this...
|
||||
ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest2, ftest1)
|
||||
references pktable(ptest1, ptest2);
|
||||
NOTICE: ALTER TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'text' and 'integer'
|
||||
ERROR: Unable to identify an operator '=' for types 'inet' and 'integer'
|
||||
You will have to retype this query using an explicit cast
|
||||
-- temp tables should go away by themselves, need not drop them.
|
||||
-- test check constraint adding
|
||||
|
|
|
@ -718,16 +718,16 @@ DROP TABLE PKTABLE;
|
|||
-- Basic one column, two table setup
|
||||
CREATE TABLE PKTABLE (ptest1 int PRIMARY KEY);
|
||||
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
|
||||
-- This next should fail, because text=int does not exist
|
||||
CREATE TABLE FKTABLE (ftest1 text REFERENCES pktable);
|
||||
-- This next should fail, because inet=int does not exist
|
||||
CREATE TABLE FKTABLE (ftest1 inet REFERENCES pktable);
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'text' and 'integer'
|
||||
ERROR: Unable to identify an operator '=' for types 'inet' and 'integer'
|
||||
You will have to retype this query using an explicit cast
|
||||
-- This should also fail for the same reason, but here we
|
||||
-- give the column name
|
||||
CREATE TABLE FKTABLE (ftest1 text REFERENCES pktable(ptest1));
|
||||
CREATE TABLE FKTABLE (ftest1 inet REFERENCES pktable(ptest1));
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'text' and 'integer'
|
||||
ERROR: Unable to identify an operator '=' for types 'inet' and 'integer'
|
||||
You will have to retype this query using an explicit cast
|
||||
-- This should succeed, even though they are different types
|
||||
-- because varchar=int does exist
|
||||
|
@ -744,7 +744,7 @@ NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "p
|
|||
NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "pktable"
|
||||
DROP TABLE PKTABLE;
|
||||
-- Two columns, two tables
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 text, PRIMARY KEY(ptest1, ptest2));
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 inet, PRIMARY KEY(ptest1, ptest2));
|
||||
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
|
||||
-- This should fail, because we just chose really odd types
|
||||
CREATE TABLE FKTABLE (ftest1 cidr, ftest2 datetime, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable);
|
||||
|
@ -757,28 +757,28 @@ NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
|||
ERROR: Unable to identify an operator '=' for types 'cidr' and 'integer'
|
||||
You will have to retype this query using an explicit cast
|
||||
-- This fails because we mixed up the column ordering
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable);
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 inet, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable);
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'text' and 'integer'
|
||||
ERROR: Unable to identify an operator '=' for types 'inet' and 'integer'
|
||||
You will have to retype this query using an explicit cast
|
||||
-- As does this...
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable(ptest1, ptest2));
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 inet, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable(ptest1, ptest2));
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'text' and 'integer'
|
||||
ERROR: Unable to identify an operator '=' for types 'inet' and 'integer'
|
||||
You will have to retype this query using an explicit cast
|
||||
-- And again..
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest2, ptest1));
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 inet, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest2, ptest1));
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'integer' and 'text'
|
||||
ERROR: Unable to identify an operator '=' for types 'integer' and 'inet'
|
||||
You will have to retype this query using an explicit cast
|
||||
-- This works...
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable(ptest2, ptest1));
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 inet, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable(ptest2, ptest1));
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
DROP TABLE FKTABLE;
|
||||
NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "pktable"
|
||||
NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "pktable"
|
||||
-- As does this
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest1, ptest2));
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 inet, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest1, ptest2));
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
DROP TABLE FKTABLE;
|
||||
NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "pktable"
|
||||
|
@ -786,37 +786,37 @@ NOTICE: DROP TABLE implicitly drops referential integrity trigger from table "p
|
|||
DROP TABLE PKTABLE;
|
||||
-- Two columns, same table
|
||||
-- Make sure this still works...
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 inet, ptest3 int, ptest4 inet, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
|
||||
ptest4) REFERENCES pktable(ptest1, ptest2));
|
||||
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
DROP TABLE PKTABLE;
|
||||
-- And this,
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 inet, ptest3 int, ptest4 inet, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
|
||||
ptest4) REFERENCES pktable);
|
||||
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
DROP TABLE PKTABLE;
|
||||
-- This shouldn't (mixed up columns)
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 inet, ptest3 int, ptest4 inet, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
|
||||
ptest4) REFERENCES pktable(ptest2, ptest1));
|
||||
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'integer' and 'text'
|
||||
ERROR: Unable to identify an operator '=' for types 'integer' and 'inet'
|
||||
You will have to retype this query using an explicit cast
|
||||
-- Nor should this... (same reason, we have 4,3 referencing 1,2 which mismatches types
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest4,
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 inet, ptest3 int, ptest4 inet, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest4,
|
||||
ptest3) REFERENCES pktable(ptest1, ptest2));
|
||||
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'text' and 'integer'
|
||||
ERROR: Unable to identify an operator '=' for types 'inet' and 'integer'
|
||||
You will have to retype this query using an explicit cast
|
||||
-- Not this one either... Same as the last one except we didn't defined the columns being referenced.
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest4,
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 inet, ptest3 int, ptest4 inet, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest4,
|
||||
ptest3) REFERENCES pktable);
|
||||
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'text' and 'integer'
|
||||
ERROR: Unable to identify an operator '=' for types 'inet' and 'integer'
|
||||
You will have to retype this query using an explicit cast
|
||||
--
|
||||
-- Now some cases with inheritance
|
||||
|
@ -907,7 +907,7 @@ drop table pktable;
|
|||
drop table pktable_base;
|
||||
-- 2 columns (2 tables), mismatched types
|
||||
create table pktable_base(base1 int not null);
|
||||
create table pktable(ptest1 text, primary key(base1, ptest1)) inherits (pktable_base);
|
||||
create table pktable(ptest1 inet, primary key(base1, ptest1)) inherits (pktable_base);
|
||||
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
|
||||
-- just generally bad types (with and without column references on the referenced table)
|
||||
create table fktable(ftest1 cidr, ftest2 int[], foreign key (ftest1, ftest2) references pktable);
|
||||
|
@ -919,45 +919,45 @@ NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
|||
ERROR: Unable to identify an operator '=' for types 'cidr' and 'integer'
|
||||
You will have to retype this query using an explicit cast
|
||||
-- let's mix up which columns reference which
|
||||
create table fktable(ftest1 int, ftest2 text, foreign key(ftest2, ftest1) references pktable);
|
||||
create table fktable(ftest1 int, ftest2 inet, foreign key(ftest2, ftest1) references pktable);
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'text' and 'integer'
|
||||
ERROR: Unable to identify an operator '=' for types 'inet' and 'integer'
|
||||
You will have to retype this query using an explicit cast
|
||||
create table fktable(ftest1 int, ftest2 text, foreign key(ftest2, ftest1) references pktable(base1, ptest1));
|
||||
create table fktable(ftest1 int, ftest2 inet, foreign key(ftest2, ftest1) references pktable(base1, ptest1));
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'text' and 'integer'
|
||||
ERROR: Unable to identify an operator '=' for types 'inet' and 'integer'
|
||||
You will have to retype this query using an explicit cast
|
||||
create table fktable(ftest1 int, ftest2 text, foreign key(ftest1, ftest2) references pktable(ptest1, base1));
|
||||
create table fktable(ftest1 int, ftest2 inet, foreign key(ftest1, ftest2) references pktable(ptest1, base1));
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'integer' and 'text'
|
||||
ERROR: Unable to identify an operator '=' for types 'integer' and 'inet'
|
||||
You will have to retype this query using an explicit cast
|
||||
drop table pktable;
|
||||
drop table pktable_base;
|
||||
-- 2 columns (1 table), mismatched types
|
||||
create table pktable_base(base1 int not null, base2 int);
|
||||
create table pktable(ptest1 text, ptest2 text[], primary key(base1, ptest1), foreign key(base2, ptest2) references
|
||||
create table pktable(ptest1 inet, ptest2 inet[], primary key(base1, ptest1), foreign key(base2, ptest2) references
|
||||
pktable(base1, ptest1)) inherits (pktable_base);
|
||||
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'text[]' and 'text'
|
||||
ERROR: Unable to identify an operator '=' for types 'inet[]' and 'inet'
|
||||
You will have to retype this query using an explicit cast
|
||||
create table pktable(ptest1 text, ptest2 text, primary key(base1, ptest1), foreign key(base2, ptest2) references
|
||||
create table pktable(ptest1 inet, ptest2 inet, primary key(base1, ptest1), foreign key(base2, ptest2) references
|
||||
pktable(ptest1, base1)) inherits (pktable_base);
|
||||
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'integer' and 'text'
|
||||
ERROR: Unable to identify an operator '=' for types 'integer' and 'inet'
|
||||
You will have to retype this query using an explicit cast
|
||||
create table pktable(ptest1 text, ptest2 text, primary key(base1, ptest1), foreign key(ptest2, base2) references
|
||||
create table pktable(ptest1 inet, ptest2 inet, primary key(base1, ptest1), foreign key(ptest2, base2) references
|
||||
pktable(base1, ptest1)) inherits (pktable_base);
|
||||
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'text' and 'integer'
|
||||
ERROR: Unable to identify an operator '=' for types 'inet' and 'integer'
|
||||
You will have to retype this query using an explicit cast
|
||||
create table pktable(ptest1 text, ptest2 text, primary key(base1, ptest1), foreign key(ptest2, base2) references
|
||||
create table pktable(ptest1 inet, ptest2 inet, primary key(base1, ptest1), foreign key(ptest2, base2) references
|
||||
pktable(base1, ptest1)) inherits (pktable_base);
|
||||
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index 'pktable_pkey' for table 'pktable'
|
||||
NOTICE: CREATE TABLE will create implicit trigger(s) for FOREIGN KEY check(s)
|
||||
ERROR: Unable to identify an operator '=' for types 'text' and 'integer'
|
||||
ERROR: Unable to identify an operator '=' for types 'inet' and 'integer'
|
||||
You will have to retype this query using an explicit cast
|
||||
drop table pktable;
|
||||
ERROR: table "pktable" does not exist
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
--
|
||||
-- This is created by pgsql/contrib/findoidjoins/make_oidjoin_check
|
||||
--
|
||||
SELECT ctid, pg_aggregate.aggfnoid
|
||||
FROM pg_aggregate
|
||||
WHERE pg_aggregate.aggfnoid != 0 AND
|
||||
NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggfnoid);
|
||||
ctid | aggfnoid
|
||||
------+----------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, pg_aggregate.aggtransfn
|
||||
FROM pg_aggregate
|
||||
WHERE pg_aggregate.aggtransfn != 0 AND
|
||||
|
@ -17,14 +25,6 @@ WHERE pg_aggregate.aggfinalfn != 0 AND
|
|||
------+------------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, pg_aggregate.aggbasetype
|
||||
FROM pg_aggregate
|
||||
WHERE pg_aggregate.aggbasetype != 0 AND
|
||||
NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggbasetype);
|
||||
ctid | aggbasetype
|
||||
------+-------------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, pg_aggregate.aggtranstype
|
||||
FROM pg_aggregate
|
||||
WHERE pg_aggregate.aggtranstype != 0 AND
|
||||
|
@ -33,14 +33,6 @@ WHERE pg_aggregate.aggtranstype != 0 AND
|
|||
------+--------------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, pg_aggregate.aggfinaltype
|
||||
FROM pg_aggregate
|
||||
WHERE pg_aggregate.aggfinaltype != 0 AND
|
||||
NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggfinaltype);
|
||||
ctid | aggfinaltype
|
||||
------+--------------
|
||||
(0 rows)
|
||||
|
||||
SELECT ctid, pg_am.amgettuple
|
||||
FROM pg_am
|
||||
WHERE pg_am.amgettuple != 0 AND
|
||||
|
|
|
@ -48,7 +48,7 @@ WHERE p1.oid != p2.oid AND
|
|||
-----+---------+-----+---------
|
||||
(0 rows)
|
||||
|
||||
-- Considering only built-in procs (prolang = 11/12), look for multiple uses
|
||||
-- Considering only built-in procs (prolang = 12), look for multiple uses
|
||||
-- of the same internal function (ie, matching prosrc fields). It's OK to
|
||||
-- have several entries with different pronames for the same internal function,
|
||||
-- but conflicts in the number of arguments and other critical items should
|
||||
|
@ -57,14 +57,14 @@ SELECT p1.oid, p1.proname, p2.oid, p2.proname
|
|||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
(p1.prolang != p2.prolang OR
|
||||
p1.proisinh != p2.proisinh OR
|
||||
p1.proisagg != p2.proisagg OR
|
||||
p1.proistrusted != p2.proistrusted OR
|
||||
p1.proisstrict != p2.proisstrict OR
|
||||
p1.proretset != p2.proretset OR
|
||||
p1.provolatile != p2.provolatile OR
|
||||
p1.pronargs != p2.pronargs OR
|
||||
p1.proretset != p2.proretset);
|
||||
p1.pronargs != p2.pronargs);
|
||||
oid | proname | oid | proname
|
||||
-----+---------+-----+---------
|
||||
(0 rows)
|
||||
|
@ -75,12 +75,14 @@ WHERE p1.oid != p2.oid AND
|
|||
-- That's not wrong, necessarily, but we make lists of all the types being
|
||||
-- so treated. Note that the expected output of this part of the test will
|
||||
-- need to be modified whenever new pairs of types are made binary-equivalent!
|
||||
-- Note: ignore aggregate functions here, since they all point to the same
|
||||
-- dummy built-in function.
|
||||
SELECT DISTINCT p1.prorettype, p2.prorettype
|
||||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.prorettype < p2.prorettype);
|
||||
prorettype | prorettype
|
||||
------------+------------
|
||||
|
@ -92,8 +94,8 @@ SELECT DISTINCT p1.proargtypes[0], p2.proargtypes[0]
|
|||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.proargtypes[0] < p2.proargtypes[0]);
|
||||
proargtypes | proargtypes
|
||||
-------------+-------------
|
||||
|
@ -106,8 +108,8 @@ SELECT DISTINCT p1.proargtypes[1], p2.proargtypes[1]
|
|||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.proargtypes[1] < p2.proargtypes[1]);
|
||||
proargtypes | proargtypes
|
||||
-------------+-------------
|
||||
|
@ -119,8 +121,8 @@ SELECT DISTINCT p1.proargtypes[2], p2.proargtypes[2]
|
|||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.proargtypes[2] < p2.proargtypes[2]);
|
||||
proargtypes | proargtypes
|
||||
-------------+-------------
|
||||
|
@ -131,8 +133,8 @@ SELECT DISTINCT p1.proargtypes[3], p2.proargtypes[3]
|
|||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.proargtypes[3] < p2.proargtypes[3]);
|
||||
proargtypes | proargtypes
|
||||
-------------+-------------
|
||||
|
@ -143,8 +145,8 @@ SELECT DISTINCT p1.proargtypes[4], p2.proargtypes[4]
|
|||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.proargtypes[4] < p2.proargtypes[4]);
|
||||
proargtypes | proargtypes
|
||||
-------------+-------------
|
||||
|
@ -154,8 +156,8 @@ SELECT DISTINCT p1.proargtypes[5], p2.proargtypes[5]
|
|||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.proargtypes[5] < p2.proargtypes[5]);
|
||||
proargtypes | proargtypes
|
||||
-------------+-------------
|
||||
|
@ -165,8 +167,8 @@ SELECT DISTINCT p1.proargtypes[6], p2.proargtypes[6]
|
|||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.proargtypes[6] < p2.proargtypes[6]);
|
||||
proargtypes | proargtypes
|
||||
-------------+-------------
|
||||
|
@ -176,13 +178,29 @@ SELECT DISTINCT p1.proargtypes[7], p2.proargtypes[7]
|
|||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.proargtypes[7] < p2.proargtypes[7]);
|
||||
proargtypes | proargtypes
|
||||
-------------+-------------
|
||||
(0 rows)
|
||||
|
||||
-- If a proc is marked as an implicit cast, then it should be something that
|
||||
-- the system might actually use as a cast function: name same as the name
|
||||
-- of its output type, and either one arg that's a different type, or two
|
||||
-- args where the first is the same as the output type and the second is int4.
|
||||
SELECT p1.oid, p1.proname
|
||||
FROM pg_proc as p1
|
||||
WHERE p1.proimplicit AND
|
||||
(NOT EXISTS (SELECT 1 FROM pg_type t WHERE t.oid = p1.prorettype AND
|
||||
t.typname = p1.proname) OR
|
||||
NOT ((p1.pronargs = 1 AND p1.proargtypes[0] != prorettype) OR
|
||||
(p1.pronargs = 2 AND p1.proargtypes[0] = prorettype AND
|
||||
p1.proargtypes[1] = 23)));
|
||||
oid | proname
|
||||
-----+---------
|
||||
(0 rows)
|
||||
|
||||
-- **************** pg_operator ****************
|
||||
-- Look for illegal values in pg_operator fields.
|
||||
SELECT p1.oid, p1.oprname
|
||||
|
@ -238,6 +256,7 @@ WHERE p1.oprcom = p2.oid AND
|
|||
-- single-operand operators.
|
||||
-- We expect that B will always say that B.oprnegate = A as well; that's not
|
||||
-- inherently essential, but it would be inefficient not to mark it so.
|
||||
-- Also, A and B had better not be the same operator.
|
||||
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
|
||||
FROM pg_operator AS p1, pg_operator AS p2
|
||||
WHERE p1.oprnegate = p2.oid AND
|
||||
|
@ -246,7 +265,8 @@ WHERE p1.oprnegate = p2.oid AND
|
|||
p1.oprright != p2.oprright OR
|
||||
p1.oprresult != 16 OR
|
||||
p2.oprresult != 16 OR
|
||||
p1.oid != p2.oprnegate);
|
||||
p1.oid != p2.oprnegate OR
|
||||
p1.oid = p2.oid);
|
||||
oid | oprcode | oid | oprcode
|
||||
-----+---------+-----+---------
|
||||
(0 rows)
|
||||
|
@ -455,19 +475,38 @@ WHERE p1.oprjoin = p2.oid AND
|
|||
|
||||
-- **************** pg_aggregate ****************
|
||||
-- Look for illegal values in pg_aggregate fields.
|
||||
SELECT p1.oid, p1.aggname
|
||||
SELECT ctid, aggfnoid::oid
|
||||
FROM pg_aggregate as p1
|
||||
WHERE aggtransfn = 0 OR aggtranstype = 0 OR aggfinaltype = 0;
|
||||
oid | aggname
|
||||
WHERE aggfnoid = 0 OR aggtransfn = 0 OR aggtranstype = 0;
|
||||
ctid | aggfnoid
|
||||
------+----------
|
||||
(0 rows)
|
||||
|
||||
-- Make sure the matching pg_proc entry is sensible, too.
|
||||
SELECT a.aggfnoid::oid, p.proname
|
||||
FROM pg_aggregate as a, pg_proc as p
|
||||
WHERE a.aggfnoid = p.oid AND
|
||||
(NOT p.proisagg OR p.pronargs != 1 OR p.proretset);
|
||||
aggfnoid | proname
|
||||
----------+---------
|
||||
(0 rows)
|
||||
|
||||
-- Make sure there are no proisagg pg_proc entries without matches.
|
||||
SELECT oid, proname
|
||||
FROM pg_proc as p
|
||||
WHERE p.proisagg AND
|
||||
NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid);
|
||||
oid | proname
|
||||
-----+---------
|
||||
(0 rows)
|
||||
|
||||
-- If there is no finalfn then the output type must be the transtype.
|
||||
SELECT p1.oid, p1.aggname
|
||||
FROM pg_aggregate as p1
|
||||
WHERE p1.aggfinalfn = 0 AND p1.aggfinaltype != p1.aggtranstype;
|
||||
oid | aggname
|
||||
-----+---------
|
||||
SELECT a.aggfnoid::oid, p.proname
|
||||
FROM pg_aggregate as a, pg_proc as p
|
||||
WHERE a.aggfnoid = p.oid AND
|
||||
a.aggfinalfn = 0 AND p.prorettype != a.aggtranstype;
|
||||
aggfnoid | proname
|
||||
----------+---------
|
||||
(0 rows)
|
||||
|
||||
-- Cross-check transfn against its entry in pg_proc.
|
||||
|
@ -476,41 +515,44 @@ WHERE p1.aggfinalfn = 0 AND p1.aggfinaltype != p1.aggtranstype;
|
|||
-- implemented using int4larger/int4smaller. Until we have
|
||||
-- some cleaner way of dealing with binary-equivalent types, just leave
|
||||
-- those two tuples in the expected output.
|
||||
SELECT p1.oid, p1.aggname, p2.oid, p2.proname
|
||||
FROM pg_aggregate AS p1, pg_proc AS p2
|
||||
WHERE p1.aggtransfn = p2.oid AND
|
||||
SELECT a.aggfnoid::oid, p.proname, p2.oid, p2.proname
|
||||
FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS p2
|
||||
WHERE a.aggfnoid = p.oid AND
|
||||
a.aggtransfn = p2.oid AND
|
||||
(p2.proretset OR
|
||||
p1.aggtranstype != p2.prorettype OR
|
||||
p1.aggtranstype != p2.proargtypes[0] OR
|
||||
NOT ((p2.pronargs = 2 AND p1.aggbasetype = p2.proargtypes[1]) OR
|
||||
(p2.pronargs = 1 AND p1.aggbasetype = 0)));
|
||||
oid | aggname | oid | proname
|
||||
-------+---------+-----+-------------
|
||||
10021 | max | 768 | int4larger
|
||||
10037 | min | 769 | int4smaller
|
||||
a.aggtranstype != p2.prorettype OR
|
||||
a.aggtranstype != p2.proargtypes[0] OR
|
||||
NOT ((p2.pronargs = 2 AND p.proargtypes[0] = p2.proargtypes[1]) OR
|
||||
(p2.pronargs = 1 AND p.proargtypes[0] = 0)));
|
||||
aggfnoid | proname | oid | proname
|
||||
----------+---------+-----+-------------
|
||||
2121 | max | 768 | int4larger
|
||||
2137 | min | 769 | int4smaller
|
||||
(2 rows)
|
||||
|
||||
-- Cross-check finalfn (if present) against its entry in pg_proc.
|
||||
-- FIXME: what about binary-compatible types?
|
||||
SELECT p1.oid, p1.aggname, p2.oid, p2.proname
|
||||
FROM pg_aggregate AS p1, pg_proc AS p2
|
||||
WHERE p1.aggfinalfn = p2.oid AND
|
||||
(p2.proretset OR p1.aggfinaltype != p2.prorettype OR
|
||||
SELECT a.aggfnoid::oid, p.proname, p2.oid, p2.proname
|
||||
FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS p2
|
||||
WHERE a.aggfnoid = p.oid AND
|
||||
a.aggfinalfn = p2.oid AND
|
||||
(p2.proretset OR p.prorettype != p2.prorettype OR
|
||||
p2.pronargs != 1 OR
|
||||
p1.aggtranstype != p2.proargtypes[0]);
|
||||
oid | aggname | oid | proname
|
||||
-----+---------+-----+---------
|
||||
a.aggtranstype != p2.proargtypes[0]);
|
||||
aggfnoid | proname | oid | proname
|
||||
----------+---------+-----+---------
|
||||
(0 rows)
|
||||
|
||||
-- If transfn is strict then either initval should be non-NULL, or
|
||||
-- basetype should equal transtype so that the first non-null input
|
||||
-- input type should equal transtype so that the first non-null input
|
||||
-- can be assigned as the state value.
|
||||
SELECT p1.oid, p1.aggname, p2.oid, p2.proname
|
||||
FROM pg_aggregate AS p1, pg_proc AS p2
|
||||
WHERE p1.aggtransfn = p2.oid AND p2.proisstrict AND
|
||||
p1.agginitval IS NULL AND p1.aggbasetype != p1.aggtranstype;
|
||||
oid | aggname | oid | proname
|
||||
-----+---------+-----+---------
|
||||
SELECT a.aggfnoid::oid, p.proname, p2.oid, p2.proname
|
||||
FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS p2
|
||||
WHERE a.aggfnoid = p.oid AND
|
||||
a.aggtransfn = p2.oid AND p2.proisstrict AND
|
||||
a.agginitval IS NULL AND p.proargtypes[0] != a.aggtranstype;
|
||||
aggfnoid | proname | oid | proname
|
||||
----------+---------+-----+---------
|
||||
(0 rows)
|
||||
|
||||
-- **************** pg_opclass ****************
|
||||
|
@ -574,6 +616,17 @@ WHERE p1.amopopr = p2.oid AND
|
|||
-----------+---------+-----+---------
|
||||
(0 rows)
|
||||
|
||||
-- Check that all operators linked to by opclass entries have selectivity
|
||||
-- estimators. This is not absolutely required, but it seems a reasonable
|
||||
-- thing to insist on for all standard datatypes.
|
||||
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname
|
||||
FROM pg_amop AS p1, pg_operator AS p2
|
||||
WHERE p1.amopopr = p2.oid AND
|
||||
(p2.oprrest = 0 OR p2.oprjoin = 0);
|
||||
amopclaid | amopopr | oid | oprname
|
||||
-----------+---------+-----+---------
|
||||
(0 rows)
|
||||
|
||||
-- Check that operator input types match the opclass
|
||||
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname, p3.opcname
|
||||
FROM pg_amop AS p1, pg_operator AS p2, pg_opclass AS p3
|
||||
|
|
|
@ -1024,7 +1024,7 @@ SELECT * FROM shoe_ready WHERE total_avail >= 2;
|
|||
NEW.sl_name,
|
||||
NEW.sl_avail,
|
||||
'Al Bundy',
|
||||
'epoch'::text
|
||||
'epoch'
|
||||
);
|
||||
UPDATE shoelace_data SET sl_avail = 6 WHERE sl_name = 'sl7';
|
||||
SELECT * FROM shoelace_log;
|
||||
|
@ -1308,8 +1308,8 @@ SELECT viewname, definition FROM pg_views ORDER BY viewname;
|
|||
|
||||
SELECT tablename, rulename, definition FROM pg_rules
|
||||
ORDER BY tablename, rulename;
|
||||
tablename | rulename | definition
|
||||
---------------+-----------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
tablename | rulename | definition
|
||||
---------------+-----------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
rtest_emp | rtest_emp_del | CREATE RULE rtest_emp_del AS ON DELETE TO rtest_emp DO INSERT INTO rtest_emplog (ename, who, "action", newsal, oldsal) VALUES (old.ename, "current_user"(), 'fired '::bpchar, '$0.00'::money, old.salary);
|
||||
rtest_emp | rtest_emp_ins | CREATE RULE rtest_emp_ins AS ON INSERT TO rtest_emp DO INSERT INTO rtest_emplog (ename, who, "action", newsal, oldsal) VALUES (new.ename, "current_user"(), 'hired '::bpchar, new.salary, '$0.00'::money);
|
||||
rtest_emp | rtest_emp_upd | CREATE RULE rtest_emp_upd AS ON UPDATE TO rtest_emp WHERE (new.salary <> old.salary) DO INSERT INTO rtest_emplog (ename, who, "action", newsal, oldsal) VALUES (new.ename, "current_user"(), 'honored '::bpchar, new.salary, old.salary);
|
||||
|
@ -1335,7 +1335,7 @@ SELECT tablename, rulename, definition FROM pg_rules
|
|||
shoelace | shoelace_del | CREATE RULE shoelace_del AS ON DELETE TO shoelace DO INSTEAD DELETE FROM shoelace_data WHERE (shoelace_data.sl_name = old.sl_name);
|
||||
shoelace | shoelace_ins | CREATE RULE shoelace_ins AS ON INSERT TO shoelace DO INSTEAD INSERT INTO shoelace_data (sl_name, sl_avail, sl_color, sl_len, sl_unit) VALUES (new.sl_name, new.sl_avail, new.sl_color, new.sl_len, new.sl_unit);
|
||||
shoelace | shoelace_upd | CREATE RULE shoelace_upd AS ON UPDATE TO shoelace DO INSTEAD UPDATE shoelace_data SET sl_name = new.sl_name, sl_avail = new.sl_avail, sl_color = new.sl_color, sl_len = new.sl_len, sl_unit = new.sl_unit WHERE (shoelace_data.sl_name = old.sl_name);
|
||||
shoelace_data | log_shoelace | CREATE RULE log_shoelace AS ON UPDATE TO shoelace_data WHERE (new.sl_avail <> old.sl_avail) DO INSERT INTO shoelace_log (sl_name, sl_avail, log_who, log_when) VALUES (new.sl_name, new.sl_avail, 'Al Bundy'::name, "timestamp"('epoch'::text));
|
||||
shoelace_data | log_shoelace | CREATE RULE log_shoelace AS ON UPDATE TO shoelace_data WHERE (new.sl_avail <> old.sl_avail) DO INSERT INTO shoelace_log (sl_name, sl_avail, log_who, log_when) VALUES (new.sl_name, new.sl_avail, 'Al Bundy'::name, 'Thu Jan 01 00:00:00 1970'::"timestamp");
|
||||
shoelace_ok | shoelace_ok_ins | CREATE RULE shoelace_ok_ins AS ON INSERT TO shoelace_ok DO INSTEAD UPDATE shoelace SET sl_avail = (shoelace.sl_avail + new.ok_quant) WHERE (shoelace.sl_name = new.ok_name);
|
||||
(27 rows)
|
||||
|
||||
|
|
|
@ -234,8 +234,8 @@ DROP TABLE tmp2;
|
|||
-- is run in parallel with foreign_key.sql.
|
||||
|
||||
CREATE TEMP TABLE PKTABLE (ptest1 int PRIMARY KEY);
|
||||
CREATE TEMP TABLE FKTABLE (ftest1 text);
|
||||
-- This next should fail, because text=int does not exist
|
||||
CREATE TEMP TABLE FKTABLE (ftest1 inet);
|
||||
-- This next should fail, because inet=int does not exist
|
||||
ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable;
|
||||
-- This should also fail for the same reason, but here we
|
||||
-- give the column name
|
||||
|
@ -250,7 +250,7 @@ ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1) references pktable(ptest1);
|
|||
DROP TABLE pktable;
|
||||
DROP TABLE fktable;
|
||||
|
||||
CREATE TEMP TABLE PKTABLE (ptest1 int, ptest2 text,
|
||||
CREATE TEMP TABLE PKTABLE (ptest1 int, ptest2 inet,
|
||||
PRIMARY KEY(ptest1, ptest2));
|
||||
-- This should fail, because we just chose really odd types
|
||||
CREATE TEMP TABLE FKTABLE (ftest1 cidr, ftest2 datetime);
|
||||
|
@ -262,7 +262,7 @@ ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2)
|
|||
references pktable(ptest1, ptest2);
|
||||
-- This fails because we mixed up the column ordering
|
||||
DROP TABLE FKTABLE;
|
||||
CREATE TEMP TABLE FKTABLE (ftest1 int, ftest2 text);
|
||||
CREATE TEMP TABLE FKTABLE (ftest1 int, ftest2 inet);
|
||||
ALTER TABLE FKTABLE ADD FOREIGN KEY(ftest1, ftest2)
|
||||
references pktable(ptest2, ptest1);
|
||||
-- As does this...
|
||||
|
|
|
@ -431,11 +431,11 @@ DROP TABLE PKTABLE;
|
|||
--
|
||||
-- Basic one column, two table setup
|
||||
CREATE TABLE PKTABLE (ptest1 int PRIMARY KEY);
|
||||
-- This next should fail, because text=int does not exist
|
||||
CREATE TABLE FKTABLE (ftest1 text REFERENCES pktable);
|
||||
-- This next should fail, because inet=int does not exist
|
||||
CREATE TABLE FKTABLE (ftest1 inet REFERENCES pktable);
|
||||
-- This should also fail for the same reason, but here we
|
||||
-- give the column name
|
||||
CREATE TABLE FKTABLE (ftest1 text REFERENCES pktable(ptest1));
|
||||
CREATE TABLE FKTABLE (ftest1 inet REFERENCES pktable(ptest1));
|
||||
-- This should succeed, even though they are different types
|
||||
-- because varchar=int does exist
|
||||
CREATE TABLE FKTABLE (ftest1 varchar REFERENCES pktable);
|
||||
|
@ -446,42 +446,42 @@ DROP TABLE FKTABLE;
|
|||
DROP TABLE PKTABLE;
|
||||
|
||||
-- Two columns, two tables
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 text, PRIMARY KEY(ptest1, ptest2));
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 inet, PRIMARY KEY(ptest1, ptest2));
|
||||
-- This should fail, because we just chose really odd types
|
||||
CREATE TABLE FKTABLE (ftest1 cidr, ftest2 datetime, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable);
|
||||
-- Again, so should this...
|
||||
CREATE TABLE FKTABLE (ftest1 cidr, ftest2 datetime, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest1, ptest2));
|
||||
-- This fails because we mixed up the column ordering
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable);
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 inet, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable);
|
||||
-- As does this...
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable(ptest1, ptest2));
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 inet, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable(ptest1, ptest2));
|
||||
-- And again..
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest2, ptest1));
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 inet, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest2, ptest1));
|
||||
-- This works...
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable(ptest2, ptest1));
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 inet, FOREIGN KEY(ftest2, ftest1) REFERENCES pktable(ptest2, ptest1));
|
||||
DROP TABLE FKTABLE;
|
||||
-- As does this
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 text, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest1, ptest2));
|
||||
CREATE TABLE FKTABLE (ftest1 int, ftest2 inet, FOREIGN KEY(ftest1, ftest2) REFERENCES pktable(ptest1, ptest2));
|
||||
DROP TABLE FKTABLE;
|
||||
DROP TABLE PKTABLE;
|
||||
|
||||
-- Two columns, same table
|
||||
-- Make sure this still works...
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 inet, ptest3 int, ptest4 inet, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
|
||||
ptest4) REFERENCES pktable(ptest1, ptest2));
|
||||
DROP TABLE PKTABLE;
|
||||
-- And this,
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 inet, ptest3 int, ptest4 inet, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
|
||||
ptest4) REFERENCES pktable);
|
||||
DROP TABLE PKTABLE;
|
||||
-- This shouldn't (mixed up columns)
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 inet, ptest3 int, ptest4 inet, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest3,
|
||||
ptest4) REFERENCES pktable(ptest2, ptest1));
|
||||
-- Nor should this... (same reason, we have 4,3 referencing 1,2 which mismatches types
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest4,
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 inet, ptest3 int, ptest4 inet, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest4,
|
||||
ptest3) REFERENCES pktable(ptest1, ptest2));
|
||||
-- Not this one either... Same as the last one except we didn't defined the columns being referenced.
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 text, ptest3 int, ptest4 text, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest4,
|
||||
CREATE TABLE PKTABLE (ptest1 int, ptest2 inet, ptest3 int, ptest4 inet, PRIMARY KEY(ptest1, ptest2), FOREIGN KEY(ptest4,
|
||||
ptest3) REFERENCES pktable);
|
||||
|
||||
--
|
||||
|
@ -557,26 +557,26 @@ drop table pktable_base;
|
|||
|
||||
-- 2 columns (2 tables), mismatched types
|
||||
create table pktable_base(base1 int not null);
|
||||
create table pktable(ptest1 text, primary key(base1, ptest1)) inherits (pktable_base);
|
||||
create table pktable(ptest1 inet, primary key(base1, ptest1)) inherits (pktable_base);
|
||||
-- just generally bad types (with and without column references on the referenced table)
|
||||
create table fktable(ftest1 cidr, ftest2 int[], foreign key (ftest1, ftest2) references pktable);
|
||||
create table fktable(ftest1 cidr, ftest2 int[], foreign key (ftest1, ftest2) references pktable(base1, ptest1));
|
||||
-- let's mix up which columns reference which
|
||||
create table fktable(ftest1 int, ftest2 text, foreign key(ftest2, ftest1) references pktable);
|
||||
create table fktable(ftest1 int, ftest2 text, foreign key(ftest2, ftest1) references pktable(base1, ptest1));
|
||||
create table fktable(ftest1 int, ftest2 text, foreign key(ftest1, ftest2) references pktable(ptest1, base1));
|
||||
create table fktable(ftest1 int, ftest2 inet, foreign key(ftest2, ftest1) references pktable);
|
||||
create table fktable(ftest1 int, ftest2 inet, foreign key(ftest2, ftest1) references pktable(base1, ptest1));
|
||||
create table fktable(ftest1 int, ftest2 inet, foreign key(ftest1, ftest2) references pktable(ptest1, base1));
|
||||
drop table pktable;
|
||||
drop table pktable_base;
|
||||
|
||||
-- 2 columns (1 table), mismatched types
|
||||
create table pktable_base(base1 int not null, base2 int);
|
||||
create table pktable(ptest1 text, ptest2 text[], primary key(base1, ptest1), foreign key(base2, ptest2) references
|
||||
create table pktable(ptest1 inet, ptest2 inet[], primary key(base1, ptest1), foreign key(base2, ptest2) references
|
||||
pktable(base1, ptest1)) inherits (pktable_base);
|
||||
create table pktable(ptest1 text, ptest2 text, primary key(base1, ptest1), foreign key(base2, ptest2) references
|
||||
create table pktable(ptest1 inet, ptest2 inet, primary key(base1, ptest1), foreign key(base2, ptest2) references
|
||||
pktable(ptest1, base1)) inherits (pktable_base);
|
||||
create table pktable(ptest1 text, ptest2 text, primary key(base1, ptest1), foreign key(ptest2, base2) references
|
||||
create table pktable(ptest1 inet, ptest2 inet, primary key(base1, ptest1), foreign key(ptest2, base2) references
|
||||
pktable(base1, ptest1)) inherits (pktable_base);
|
||||
create table pktable(ptest1 text, ptest2 text, primary key(base1, ptest1), foreign key(ptest2, base2) references
|
||||
create table pktable(ptest1 inet, ptest2 inet, primary key(base1, ptest1), foreign key(ptest2, base2) references
|
||||
pktable(base1, ptest1)) inherits (pktable_base);
|
||||
drop table pktable;
|
||||
drop table pktable_base;
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
--
|
||||
-- This is created by pgsql/contrib/findoidjoins/make_oidjoin_check
|
||||
--
|
||||
SELECT ctid, pg_aggregate.aggfnoid
|
||||
FROM pg_aggregate
|
||||
WHERE pg_aggregate.aggfnoid != 0 AND
|
||||
NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggfnoid);
|
||||
SELECT ctid, pg_aggregate.aggtransfn
|
||||
FROM pg_aggregate
|
||||
WHERE pg_aggregate.aggtransfn != 0 AND
|
||||
|
@ -9,18 +13,10 @@ SELECT ctid, pg_aggregate.aggfinalfn
|
|||
FROM pg_aggregate
|
||||
WHERE pg_aggregate.aggfinalfn != 0 AND
|
||||
NOT EXISTS(SELECT * FROM pg_proc AS t1 WHERE t1.oid = pg_aggregate.aggfinalfn);
|
||||
SELECT ctid, pg_aggregate.aggbasetype
|
||||
FROM pg_aggregate
|
||||
WHERE pg_aggregate.aggbasetype != 0 AND
|
||||
NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggbasetype);
|
||||
SELECT ctid, pg_aggregate.aggtranstype
|
||||
FROM pg_aggregate
|
||||
WHERE pg_aggregate.aggtranstype != 0 AND
|
||||
NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggtranstype);
|
||||
SELECT ctid, pg_aggregate.aggfinaltype
|
||||
FROM pg_aggregate
|
||||
WHERE pg_aggregate.aggfinaltype != 0 AND
|
||||
NOT EXISTS(SELECT * FROM pg_type AS t1 WHERE t1.oid = pg_aggregate.aggfinaltype);
|
||||
SELECT ctid, pg_am.amgettuple
|
||||
FROM pg_am
|
||||
WHERE pg_am.amgettuple != 0 AND
|
||||
|
|
|
@ -46,7 +46,7 @@ WHERE p1.oid != p2.oid AND
|
|||
p1.pronargs = p2.pronargs AND
|
||||
p1.proargtypes = p2.proargtypes;
|
||||
|
||||
-- Considering only built-in procs (prolang = 11/12), look for multiple uses
|
||||
-- Considering only built-in procs (prolang = 12), look for multiple uses
|
||||
-- of the same internal function (ie, matching prosrc fields). It's OK to
|
||||
-- have several entries with different pronames for the same internal function,
|
||||
-- but conflicts in the number of arguments and other critical items should
|
||||
|
@ -56,14 +56,14 @@ SELECT p1.oid, p1.proname, p2.oid, p2.proname
|
|||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
(p1.prolang != p2.prolang OR
|
||||
p1.proisinh != p2.proisinh OR
|
||||
p1.proisagg != p2.proisagg OR
|
||||
p1.proistrusted != p2.proistrusted OR
|
||||
p1.proisstrict != p2.proisstrict OR
|
||||
p1.proretset != p2.proretset OR
|
||||
p1.provolatile != p2.provolatile OR
|
||||
p1.pronargs != p2.pronargs OR
|
||||
p1.proretset != p2.proretset);
|
||||
p1.pronargs != p2.pronargs);
|
||||
|
||||
-- Look for uses of different type OIDs in the argument/result type fields
|
||||
-- for different aliases of the same built-in function.
|
||||
|
@ -71,79 +71,95 @@ WHERE p1.oid != p2.oid AND
|
|||
-- That's not wrong, necessarily, but we make lists of all the types being
|
||||
-- so treated. Note that the expected output of this part of the test will
|
||||
-- need to be modified whenever new pairs of types are made binary-equivalent!
|
||||
-- Note: ignore aggregate functions here, since they all point to the same
|
||||
-- dummy built-in function.
|
||||
|
||||
SELECT DISTINCT p1.prorettype, p2.prorettype
|
||||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.prorettype < p2.prorettype);
|
||||
|
||||
SELECT DISTINCT p1.proargtypes[0], p2.proargtypes[0]
|
||||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.proargtypes[0] < p2.proargtypes[0]);
|
||||
|
||||
SELECT DISTINCT p1.proargtypes[1], p2.proargtypes[1]
|
||||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.proargtypes[1] < p2.proargtypes[1]);
|
||||
|
||||
SELECT DISTINCT p1.proargtypes[2], p2.proargtypes[2]
|
||||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.proargtypes[2] < p2.proargtypes[2]);
|
||||
|
||||
SELECT DISTINCT p1.proargtypes[3], p2.proargtypes[3]
|
||||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.proargtypes[3] < p2.proargtypes[3]);
|
||||
|
||||
SELECT DISTINCT p1.proargtypes[4], p2.proargtypes[4]
|
||||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.proargtypes[4] < p2.proargtypes[4]);
|
||||
|
||||
SELECT DISTINCT p1.proargtypes[5], p2.proargtypes[5]
|
||||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.proargtypes[5] < p2.proargtypes[5]);
|
||||
|
||||
SELECT DISTINCT p1.proargtypes[6], p2.proargtypes[6]
|
||||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.proargtypes[6] < p2.proargtypes[6]);
|
||||
|
||||
SELECT DISTINCT p1.proargtypes[7], p2.proargtypes[7]
|
||||
FROM pg_proc AS p1, pg_proc AS p2
|
||||
WHERE p1.oid != p2.oid AND
|
||||
p1.prosrc = p2.prosrc AND
|
||||
(p1.prolang = 11 OR p1.prolang = 12) AND
|
||||
(p2.prolang = 11 OR p2.prolang = 12) AND
|
||||
p1.prolang = 12 AND p2.prolang = 12 AND
|
||||
NOT p1.proisagg AND NOT p2.proisagg AND
|
||||
(p1.proargtypes[7] < p2.proargtypes[7]);
|
||||
|
||||
-- If a proc is marked as an implicit cast, then it should be something that
|
||||
-- the system might actually use as a cast function: name same as the name
|
||||
-- of its output type, and either one arg that's a different type, or two
|
||||
-- args where the first is the same as the output type and the second is int4.
|
||||
|
||||
SELECT p1.oid, p1.proname
|
||||
FROM pg_proc as p1
|
||||
WHERE p1.proimplicit AND
|
||||
(NOT EXISTS (SELECT 1 FROM pg_type t WHERE t.oid = p1.prorettype AND
|
||||
t.typname = p1.proname) OR
|
||||
NOT ((p1.pronargs = 1 AND p1.proargtypes[0] != prorettype) OR
|
||||
(p1.pronargs = 2 AND p1.proargtypes[0] = prorettype AND
|
||||
p1.proargtypes[1] = 23)));
|
||||
|
||||
-- **************** pg_operator ****************
|
||||
|
||||
-- Look for illegal values in pg_operator fields.
|
||||
|
@ -192,6 +208,7 @@ WHERE p1.oprcom = p2.oid AND
|
|||
-- single-operand operators.
|
||||
-- We expect that B will always say that B.oprnegate = A as well; that's not
|
||||
-- inherently essential, but it would be inefficient not to mark it so.
|
||||
-- Also, A and B had better not be the same operator.
|
||||
|
||||
SELECT p1.oid, p1.oprcode, p2.oid, p2.oprcode
|
||||
FROM pg_operator AS p1, pg_operator AS p2
|
||||
|
@ -201,7 +218,8 @@ WHERE p1.oprnegate = p2.oid AND
|
|||
p1.oprright != p2.oprright OR
|
||||
p1.oprresult != 16 OR
|
||||
p2.oprresult != 16 OR
|
||||
p1.oid != p2.oprnegate);
|
||||
p1.oid != p2.oprnegate OR
|
||||
p1.oid = p2.oid);
|
||||
|
||||
-- Look for mergejoin operators that don't match their links.
|
||||
-- A mergejoin link leads from an '=' operator to the
|
||||
|
@ -378,15 +396,30 @@ WHERE p1.oprjoin = p2.oid AND
|
|||
|
||||
-- Look for illegal values in pg_aggregate fields.
|
||||
|
||||
SELECT p1.oid, p1.aggname
|
||||
SELECT ctid, aggfnoid::oid
|
||||
FROM pg_aggregate as p1
|
||||
WHERE aggtransfn = 0 OR aggtranstype = 0 OR aggfinaltype = 0;
|
||||
WHERE aggfnoid = 0 OR aggtransfn = 0 OR aggtranstype = 0;
|
||||
|
||||
-- Make sure the matching pg_proc entry is sensible, too.
|
||||
|
||||
SELECT a.aggfnoid::oid, p.proname
|
||||
FROM pg_aggregate as a, pg_proc as p
|
||||
WHERE a.aggfnoid = p.oid AND
|
||||
(NOT p.proisagg OR p.pronargs != 1 OR p.proretset);
|
||||
|
||||
-- Make sure there are no proisagg pg_proc entries without matches.
|
||||
|
||||
SELECT oid, proname
|
||||
FROM pg_proc as p
|
||||
WHERE p.proisagg AND
|
||||
NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid);
|
||||
|
||||
-- If there is no finalfn then the output type must be the transtype.
|
||||
|
||||
SELECT p1.oid, p1.aggname
|
||||
FROM pg_aggregate as p1
|
||||
WHERE p1.aggfinalfn = 0 AND p1.aggfinaltype != p1.aggtranstype;
|
||||
SELECT a.aggfnoid::oid, p.proname
|
||||
FROM pg_aggregate as a, pg_proc as p
|
||||
WHERE a.aggfnoid = p.oid AND
|
||||
a.aggfinalfn = 0 AND p.prorettype != a.aggtranstype;
|
||||
|
||||
-- Cross-check transfn against its entry in pg_proc.
|
||||
-- FIXME: what about binary-compatible types?
|
||||
|
@ -394,33 +427,36 @@ WHERE p1.aggfinalfn = 0 AND p1.aggfinaltype != p1.aggtranstype;
|
|||
-- implemented using int4larger/int4smaller. Until we have
|
||||
-- some cleaner way of dealing with binary-equivalent types, just leave
|
||||
-- those two tuples in the expected output.
|
||||
SELECT p1.oid, p1.aggname, p2.oid, p2.proname
|
||||
FROM pg_aggregate AS p1, pg_proc AS p2
|
||||
WHERE p1.aggtransfn = p2.oid AND
|
||||
SELECT a.aggfnoid::oid, p.proname, p2.oid, p2.proname
|
||||
FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS p2
|
||||
WHERE a.aggfnoid = p.oid AND
|
||||
a.aggtransfn = p2.oid AND
|
||||
(p2.proretset OR
|
||||
p1.aggtranstype != p2.prorettype OR
|
||||
p1.aggtranstype != p2.proargtypes[0] OR
|
||||
NOT ((p2.pronargs = 2 AND p1.aggbasetype = p2.proargtypes[1]) OR
|
||||
(p2.pronargs = 1 AND p1.aggbasetype = 0)));
|
||||
a.aggtranstype != p2.prorettype OR
|
||||
a.aggtranstype != p2.proargtypes[0] OR
|
||||
NOT ((p2.pronargs = 2 AND p.proargtypes[0] = p2.proargtypes[1]) OR
|
||||
(p2.pronargs = 1 AND p.proargtypes[0] = 0)));
|
||||
|
||||
-- Cross-check finalfn (if present) against its entry in pg_proc.
|
||||
-- FIXME: what about binary-compatible types?
|
||||
|
||||
SELECT p1.oid, p1.aggname, p2.oid, p2.proname
|
||||
FROM pg_aggregate AS p1, pg_proc AS p2
|
||||
WHERE p1.aggfinalfn = p2.oid AND
|
||||
(p2.proretset OR p1.aggfinaltype != p2.prorettype OR
|
||||
SELECT a.aggfnoid::oid, p.proname, p2.oid, p2.proname
|
||||
FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS p2
|
||||
WHERE a.aggfnoid = p.oid AND
|
||||
a.aggfinalfn = p2.oid AND
|
||||
(p2.proretset OR p.prorettype != p2.prorettype OR
|
||||
p2.pronargs != 1 OR
|
||||
p1.aggtranstype != p2.proargtypes[0]);
|
||||
a.aggtranstype != p2.proargtypes[0]);
|
||||
|
||||
-- If transfn is strict then either initval should be non-NULL, or
|
||||
-- basetype should equal transtype so that the first non-null input
|
||||
-- input type should equal transtype so that the first non-null input
|
||||
-- can be assigned as the state value.
|
||||
|
||||
SELECT p1.oid, p1.aggname, p2.oid, p2.proname
|
||||
FROM pg_aggregate AS p1, pg_proc AS p2
|
||||
WHERE p1.aggtransfn = p2.oid AND p2.proisstrict AND
|
||||
p1.agginitval IS NULL AND p1.aggbasetype != p1.aggtranstype;
|
||||
SELECT a.aggfnoid::oid, p.proname, p2.oid, p2.proname
|
||||
FROM pg_aggregate AS a, pg_proc AS p, pg_proc AS p2
|
||||
WHERE a.aggfnoid = p.oid AND
|
||||
a.aggtransfn = p2.oid AND p2.proisstrict AND
|
||||
a.agginitval IS NULL AND p.proargtypes[0] != a.aggtranstype;
|
||||
|
||||
-- **************** pg_opclass ****************
|
||||
|
||||
|
@ -473,6 +509,15 @@ FROM pg_amop AS p1, pg_operator AS p2
|
|||
WHERE p1.amopopr = p2.oid AND
|
||||
(p2.oprkind != 'b' OR p2.oprresult != 16 OR p2.oprleft != p2.oprright);
|
||||
|
||||
-- Check that all operators linked to by opclass entries have selectivity
|
||||
-- estimators. This is not absolutely required, but it seems a reasonable
|
||||
-- thing to insist on for all standard datatypes.
|
||||
|
||||
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname
|
||||
FROM pg_amop AS p1, pg_operator AS p2
|
||||
WHERE p1.amopopr = p2.oid AND
|
||||
(p2.oprrest = 0 OR p2.oprjoin = 0);
|
||||
|
||||
-- Check that operator input types match the opclass
|
||||
|
||||
SELECT p1.amopclaid, p1.amopopr, p2.oid, p2.oprname, p3.opcname
|
||||
|
|
|
@ -604,7 +604,7 @@ SELECT * FROM shoe_ready WHERE total_avail >= 2;
|
|||
NEW.sl_name,
|
||||
NEW.sl_avail,
|
||||
'Al Bundy',
|
||||
'epoch'::text
|
||||
'epoch'
|
||||
);
|
||||
|
||||
UPDATE shoelace_data SET sl_avail = 6 WHERE sl_name = 'sl7';
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
-- Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
-- Portions Copyright (c) 1994, Regents of the University of California
|
||||
--
|
||||
-- $Id: syscat.source,v 1.5 2001/08/21 16:36:06 tgl Exp $
|
||||
-- $Id: syscat.source,v 1.6 2002/04/11 20:00:18 tgl Exp $
|
||||
--
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
|
@ -129,10 +129,11 @@ SELECT p.proname, p.pronargs, t.typname
|
|||
--
|
||||
-- lists all aggregate functions and the types to which they can be applied
|
||||
--
|
||||
SELECT a.aggname, t.typname
|
||||
FROM pg_aggregate a, pg_type t
|
||||
WHERE a.aggbasetype = t.oid
|
||||
ORDER BY aggname, typname;
|
||||
SELECT p.proname, t.typname
|
||||
FROM pg_aggregate a, pg_proc p, pg_type t
|
||||
WHERE a.aggfnoid = p.oid
|
||||
and p.proargtypes[0] = t.oid
|
||||
ORDER BY proname, typname;
|
||||
|
||||
|
||||
--
|
||||
|
|
Loading…
Reference in New Issue