Commit 902a6a0a authored by Tom Lane's avatar Tom Lane

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.
parent 3f6299df
<!--
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>
......
<!--
$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
......
<!--
$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;
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 (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS)
elog(ERROR, "functions cannot have more than %d arguments",
FUNC_MAX_ARGS);
if (t->setof)
elog(ERROR, "functions cannot accept set arguments");
typev[parameterCount++] = toid;
}
/* Make sure we have a zero-padded param type array */
MemSet(typev, 0, FUNC_MAX_ARGS * sizeof(Oid));
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),
......
This diff is collapsed.
......@@ -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));
......
This diff is collapsed.
......@@ -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 - - ));
......
This diff is collapsed.
......@@ -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
......
This diff is collapsed.
--
-- 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
......
This diff is collapsed.
......@@ -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;
......
--
-- 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
......
This diff is collapsed.
......@@ -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;
--
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment