pg_cast table, and standards-compliant CREATE/DROP CAST commands, plus

extension to create binary compatible casts.  Includes dependency tracking
as well.

pg_proc.proimplicit is now defunct, but will be removed in a separate
commit.

pg_dump provides a migration path from the previous scheme to declare
casts.  Dumping binary compatible casts is currently impossible, though.
This commit is contained in:
Peter Eisentraut 2002-07-18 23:11:32 +00:00
parent a345ac8842
commit 97377048b4
36 changed files with 1299 additions and 343 deletions

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.40 2002/07/18 16:47:22 tgl Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.41 2002/07/18 23:11:27 petere Exp $
PostgreSQL documentation
Complete list of usable sgml source files in this directory.
-->
@ -51,6 +51,7 @@ Complete list of usable sgml source files in this directory.
<!entity commit system "commit.sgml">
<!entity copyTable system "copy.sgml">
<!entity createAggregate system "create_aggregate.sgml">
<!entity createCast system "create_cast.sgml">
<!entity createConstraint system "create_constraint.sgml">
<!entity createDatabase system "create_database.sgml">
<!entity createDomain system "create_domain.sgml">
@ -71,6 +72,7 @@ Complete list of usable sgml source files in this directory.
<!entity declare system "declare.sgml">
<!entity delete system "delete.sgml">
<!entity dropAggregate system "drop_aggregate.sgml">
<!entity dropCast system "drop_cast.sgml">
<!entity dropDatabase system "drop_database.sgml">
<!entity dropDomain system "drop_domain.sgml">
<!entity dropFunction system "drop_function.sgml">

View File

@ -0,0 +1,232 @@
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/create_cast.sgml,v 1.1 2002/07/18 23:11:27 petere Exp $ -->
<refentry id="SQL-CREATECAST">
<refmeta>
<refentrytitle id="SQL-CREATECAST-TITLE">CREATE CAST</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>CREATE CAST</refname>
<refpurpose>define a user-defined cast</refpurpose>
</refnamediv>
<refsynopsisdiv>
<synopsis>
CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
WITH FUNCTION <replaceable>funcname</replaceable> (<replaceable>argtype</replaceable>)
[AS ASSIGNMENT]
CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
WITHOUT FUNCTION
[AS ASSIGNMENT]
</synopsis>
</refsynopsisdiv>
<refsect1 id="sql-createcast-description">
<title>Description</title>
<para>
<command>CREATE CAST</command> defines a new cast. A cast
specifies which function can be invoked when a conversion between
two data types is requested. For example,
<programlisting>
SELECT CAST(42 AS text);
</programlisting>
converts the integer constant 42 to type <type>text</type> by
invoking a previously specified function, in this case
<literal>text(int4)</>. (If no suitable cast has been defined, the
conversion fails.)
</para>
<para>
Two types may be <firstterm>binary compatible</firstterm>, which
means that they can be converted into one another <quote>for
free</quote> without invoking any function. This requires that
corresponding values use the same internal representation. For
instance, the types <type>text</type> and <type>varchar</type> are
binary compatible.
</para>
<para>
A cast can marked <literal>AS ASSIGNMENT</>, which means that it
can be invoked implicitly in any context where the conversion it
defines is required. Cast 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 <literal>foo.f1</literal> is a column of
type <type>text</type>, then
<programlisting>
INSERT INTO foo(f1) VALUES(42);
</programlisting>
will be allowed if the cast from type <type>integer</type> to type
<type>text</type> is marked <literal>AS ASSIGNMENT</>, otherwise
not. (We generally use the term <firstterm>implicit
cast</firstterm> to describe this kind of cast.)
</para>
<para>
It is wise to be conservative about marking casts as implicit. An
overabundance of implicit casting 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 cast implicitly invokable only for
information-preserving transformations between types in the same
general type category. For example, <type>int2</type> to
<type>int4</type> casts can reasonably be implicit, but be wary of
marking <type>int4</type> to <type>text</type> or
<type>float8</type> to <type>int4</type> as implicit casts.
</para>
<para>
To be able to create a cast, you must own the underlying function.
To be able to create a binary compatible cast, you must own both
the source and the target data type.
</para>
<variablelist>
<title>Parameters</title>
<varlistentry>
<term><replaceable>sourcetype</replaceable></term>
<listitem>
<para>
The name of the source data type of the cast.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable>targettype</replaceable></term>
<listitem>
<para>
The name of the target data type of the cast.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable>funcname</replaceable>(<replaceable>argtype</replaceable>)</term>
<listitem>
<para>
The function used to perform the cast. The function name may
be schema-qualified. If it is not, the function will be looked
up in the path. The argument type must be identical to the
source type, the result data type must match the target type of
the cast. Cast functions must be marked immutable.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>WITHOUT FUNCTION</literal></term>
<listitem>
<para>
Indicates that the source type and the target type are binary
compatible, so no function is required to perform the cast.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>AS ASSIGNMENT</literal></term>
<listitem>
<para>
Indicates that the cast may be invoked implicitly.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id="sql-createcast-notes">
<title>Notes</title>
<para>
Use <command>DROP CAST</command> to remove user-defined casts.
</para>
<para>
The privileges required to create a cast may be changed in a future
release.
</para>
<para>
Remember that if you want to be able to convert types both ways you
need to declare casts both ways explicitly.
</para>
<para>
Prior to PostgreSQL 7.3, every function that had the same name as a
data type, returned that data type, and took one argument of a
different type was automatically a cast function. This system has
been abandoned in face of the introduction of schemas and to be
able to store binary compatible casts. The built-in cast functions
still follow this naming scheme, but they have to be declared as
casts explicitly now.
</para>
</refsect1>
<refsect1 id="sql-createcast-examples">
<title>Examples</title>
<para>
To create a cast from type <type>text</type> to type
<type>int</type> using the function <literal>int4(text)</literal>:
<programlisting>
CREATE CAST (text AS int4) WITH FUNCTION int4(text);
</programlisting>
(This cast is already predefined in the system.)
</para>
</refsect1>
<refsect1 id="sql-createcast-compat">
<title>Compatibility</title>
<para>
The <command>CREATE CAST</command> command conforms to SQL99,
except that SQL99 does not make provisions for binary compatible
types.
</para>
</refsect1>
<refsect1 id="sql-createcast-seealso">
<title>See Also</title>
<para>
<xref linkend="sql-createfunction" endterm="sql-createfunction-title">,
<xref linkend="sql-createtype" endterm="sql-createtype-title">,
<xref linkend="sql-dropcast" endterm="sql-dropcast-title">,
<citetitle>PostgreSQL Programmer's Guide</citetitle>
</para>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode:sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:("/usr/lib/sgml/catalog")
sgml-local-ecat-files:nil
End:
-->

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.39 2002/05/18 13:47:59 petere Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.40 2002/07/18 23:11:27 petere Exp $
-->
<refentry id="SQL-CREATEFUNCTION">
@ -20,7 +20,6 @@ CREATE [ OR REPLACE ] FUNCTION <replaceable class="parameter">name</replaceable>
{ LANGUAGE <replaceable class="parameter">langname</replaceable>
| IMMUTABLE | STABLE | VOLATILE
| CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
| IMPLICIT CAST
| [EXTERNAL] SECURITY INVOKER | [EXTERNAL] SECURITY DEFINER
| AS '<replaceable class="parameter">definition</replaceable>'
| AS '<replaceable class="parameter">obj_file</replaceable>', '<replaceable class="parameter">link_symbol</replaceable>'
@ -188,18 +187,6 @@ CREATE [ OR REPLACE ] FUNCTION <replaceable class="parameter">name</replaceable>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>IMPLICIT CAST</literal</term>
<listitem>
<para>
Indicates that the function may be used for implicit type
conversions. See <xref linkend="sql-createfunction-cast-functions"
endterm="sql-createfunction-cast-functions-title"> for more detail.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><optional>EXTERNAL</optional> SECURITY INVOKER</term>
<term><optional>EXTERNAL</optional> SECURITY DEFINER</term>
@ -285,14 +272,6 @@ CREATE [ OR REPLACE ] FUNCTION <replaceable class="parameter">name</replaceable>
</listitem>
</varlistentry>
<varlistentry>
<term>implicitCoercion</term>
<listitem>
<para>
Same as <literal>IMPLICIT CAST</literal>
</para>
</listitem>
</varlistentry>
</variablelist>
Attribute names are not case-sensitive.
@ -394,55 +373,6 @@ CREATE [ OR REPLACE ] FUNCTION <replaceable class="parameter">name</replaceable>
</para>
</refsect1>
<refsect1 id="sql-createfunction-cast-functions">
<title id="sql-createfunction-cast-functions-title">
Type Cast Functions
</title>
<para>
A function that has one argument and is named the same as its return
data type (including the schema name) is considered to be a <firstterm>type
casting function</>: it can be invoked to convert a value of its input
data type 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 cast function is marked <literal>IMPLICIT CAST</>,
then it can be invoked implicitly in any context where the
conversion it defines is required. Cast 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 <literal>foo.f1</literal> is a column of
type <type>text</type>, then
<programlisting>
INSERT INTO foo(f1) VALUES(42);
</programlisting>
will be allowed if <literal>text(int4)</> is marked
<literal>IMPLICIT CAST</>, otherwise not.
</para>
<para>
It is wise to be conservative about marking cast functions as
implicit casts. An overabundance of implicit casting 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 cast implicitly invokable only for
information-preserving transformations between types in the same
general type category. For example, <type>int2</type> to
<type>int4</type> casts can reasonably be implicit, but be wary of
marking <type>int4</type> to <type>text</type> or
<type>float8</type> to <type>int4</type> as implicit casts.
</para>
</refsect1>
<refsect1 id="sql-createfunction-examples">
<title>Examples</title>

View File

@ -0,0 +1,133 @@
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_cast.sgml,v 1.1 2002/07/18 23:11:27 petere Exp $ -->
<refentry id="SQL-DROPCAST">
<refmeta>
<refentrytitle id="SQL-DROPCAST-TITLE">DROP CAST</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>DROP CAST</refname>
<refpurpose>remove a user-defined cast</refpurpose>
</refnamediv>
<refsynopsisdiv>
<synopsis>
DROP CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
[ CASCADE | RESTRICT ]
</synopsis>
</refsynopsisdiv>
<refsect1 id="sql-dropcast-description">
<title>Description</title>
<para>
<command>DROP CAST</command> removes a previously defined cast.
</para>
<para>
To be able to drop a cast, you must own the underlying function.
To be able to drop a binary compatible cast, you must own both the
source and the target data type. These are the same privileges
that are required to create a cast.
</para>
<variablelist>
<title>Parameters</title>
<varlistentry>
<term><replaceable>sourcetype</replaceable></term>
<listitem>
<para>
The name of the source data type of the cast.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable>targettype</replaceable></term>
<listitem>
<para>
The name of the target data type of the cast.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>CASCADE</literal></term>
<term><literal>RESTRICT</literal></term>
<listitem>
<para>
These key words do not have any effect, since there are no
dependencies on casts.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1 id="sql-dropcast-notes">
<title>Notes</title>
<para>
Use <command>CREATE CAST</command> to create user-defined casts.
</para>
<para>
The privileges required to drop a cast may be changed in a future
release.
</para>
</refsect1>
<refsect1 id="sql-dropcast-examples">
<title>Examples</title>
<para>
To drop the cast from type <type>text</type> to type <type>int</type>:
<programlisting>
DROP CAST (text AS int4);
</programlisting>
</para>
</refsect1>
<refsect1 id="sql-dropcast-compat">
<title>Compatibility</title>
<para>
The <command>DROP CAST</command> command conforms to SQL99.
</para>
</refsect1>
<refsect1 id="sql-dropcast-seealso">
<title>See Also</title>
<para>
<xref linkend="sql-createcast" endterm="sql-createcast-title">
</para>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode:sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:("/usr/lib/sgml/catalog")
sgml-local-ecat-files:nil
End:
-->

View File

@ -1,5 +1,5 @@
<!-- reference.sgml
$Header: /cvsroot/pgsql/doc/src/sgml/reference.sgml,v 1.29 2002/07/18 16:47:22 tgl Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/reference.sgml,v 1.30 2002/07/18 23:11:27 petere Exp $
PostgreSQL Reference Manual
-->
@ -60,6 +60,7 @@ PostgreSQL Reference Manual
&commit;
&copyTable;
&createAggregate;
&createCast;
&createConstraint;
&createDatabase;
&createDomain;
@ -80,6 +81,7 @@ PostgreSQL Reference Manual
&declare;
&delete;
&dropAggregate;
&dropCast;
&dropDatabase;
&dropDomain;
&dropFunction;

View File

@ -1,5 +1,5 @@
<!--
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.141 2002/07/16 22:12:18 tgl Exp $
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.142 2002/07/18 23:11:27 petere Exp $
-->
<appendix id="release">
@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
worries about funny characters.
-->
<literallayout><![CDATA[
CREATE CAST/DROP CAST
Sequences created by SERIAL column definitions now auto-drop with the column
Most forms of DROP now support RESTRICT and CASCADE options
Recursive SQL functions can be defined

View File

@ -2,7 +2,7 @@
#
# Makefile for backend/catalog
#
# $Header: /cvsroot/pgsql/src/backend/catalog/Makefile,v 1.41 2002/07/12 18:43:13 tgl Exp $
# $Header: /cvsroot/pgsql/src/backend/catalog/Makefile,v 1.42 2002/07/18 23:11:27 petere Exp $
#
#-------------------------------------------------------------------------
@ -30,7 +30,7 @@ POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h \
pg_operator.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h \
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
pg_namespace.h pg_conversion.h pg_database.h pg_shadow.h pg_group.h \
pg_depend.h indexing.h \
)

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.4 2002/07/18 16:47:22 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.5 2002/07/18 23:11:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -47,6 +47,7 @@
/* This enum covers all system catalogs whose OIDs can appear in classid. */
typedef enum ObjectClasses
{
OCLASS_CAST, /* pg_cast */
OCLASS_CLASS, /* pg_class */
OCLASS_PROC, /* pg_proc */
OCLASS_TYPE, /* pg_type */
@ -604,6 +605,10 @@ doDeletion(const ObjectAddress *object)
RemoveSchemaById(object->objectId);
break;
case OCLASS_CAST:
DropCastById(object->objectId);
break;
default:
elog(ERROR, "doDeletion: Unsupported object class %u",
object->classId);
@ -979,6 +984,7 @@ term_object_addresses(ObjectAddresses *addrs)
static void
init_object_classes(void)
{
object_classes[OCLASS_CAST] = get_system_catalog_relid(CastRelationName);
object_classes[OCLASS_CLASS] = RelOid_pg_class;
object_classes[OCLASS_PROC] = RelOid_pg_proc;
object_classes[OCLASS_TYPE] = RelOid_pg_type;
@ -1023,6 +1029,11 @@ getObjectClass(const ObjectAddress *object)
if (!object_classes_initialized)
init_object_classes();
if (object->classId == object_classes[OCLASS_CAST])
{
Assert(object->objectSubId == 0);
return OCLASS_CAST;
}
if (object->classId == object_classes[OCLASS_CONSTRAINT])
{
Assert(object->objectSubId == 0);
@ -1078,6 +1089,10 @@ getObjectDescription(const ObjectAddress *object)
switch (getObjectClass(object))
{
case OCLASS_CAST:
appendStringInfo(&buffer, "cast");
break;
case OCLASS_CLASS:
getRelationDescription(&buffer, object->objectId);
if (object->objectSubId != 0)

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.97 2002/07/15 16:33:31 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/indexing.c,v 1.98 2002/07/18 23:11:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -43,6 +43,8 @@ char *Name_pg_attr_indices[Num_pg_attr_indices] =
{AttributeRelidNameIndex, AttributeRelidNumIndex};
char *Name_pg_attrdef_indices[Num_pg_attrdef_indices] =
{AttrDefaultIndex, AttrDefaultOidIndex};
char *Name_pg_cast_indices[Num_pg_cast_indices] =
{CastSourceTargetIndex};
char *Name_pg_class_indices[Num_pg_class_indices] =
{ClassNameNspIndex, ClassOidIndex};
char *Name_pg_constraint_indices[Num_pg_constraint_indices] =

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.50 2002/07/16 22:12:18 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.51 2002/07/18 23:11:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -144,7 +144,6 @@ AggregateCreate(const char *aggName,
"-", /* probin */
true, /* isAgg */
false, /* security invoker (currently not definable for agg) */
false, /* isImplicit */
false, /* isStrict (not needed for agg) */
PROVOLATILE_IMMUTABLE, /* volatility (not needed for agg) */
BYTE_PCT, /* default cost values */

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.78 2002/07/18 16:47:23 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.79 2002/07/18 23:11:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -55,7 +55,6 @@ ProcedureCreate(const char *procedureName,
const char *probin,
bool isAgg,
bool security_definer,
bool isImplicit,
bool isStrict,
char volatility,
int32 byte_pct,
@ -163,7 +162,7 @@ ProcedureCreate(const char *procedureName,
values[i++] = ObjectIdGetDatum(languageObjectId); /* prolang */
values[i++] = BoolGetDatum(isAgg); /* proisagg */
values[i++] = BoolGetDatum(security_definer); /* prosecdef */
values[i++] = BoolGetDatum(isImplicit); /* proimplicit */
values[i++] = BoolGetDatum(false); /* proimplicit */
values[i++] = BoolGetDatum(isStrict); /* proisstrict */
values[i++] = BoolGetDatum(returnsSet); /* proretset */
values[i++] = CharGetDatum(volatility); /* provolatile */

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.8 2002/07/12 18:43:16 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.9 2002/07/18 23:11:27 petere Exp $
*
* DESCRIPTION
* These routines take the parse tree and pick out the
@ -34,7 +34,9 @@
#include "access/heapam.h"
#include "catalog/catname.h"
#include "catalog/dependency.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_language.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
@ -44,6 +46,7 @@
#include "parser/parse_func.h"
#include "parser/parse_type.h"
#include "utils/acl.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
@ -171,8 +174,7 @@ compute_attributes_sql_style(const List *options,
char **language,
char *volatility_p,
bool *strict_p,
bool *security_definer,
bool *implicit_cast)
bool *security_definer)
{
const List *option;
DefElem *as_item = NULL;
@ -180,7 +182,6 @@ compute_attributes_sql_style(const List *options,
DefElem *volatility_item = NULL;
DefElem *strict_item = NULL;
DefElem *security_item = NULL;
DefElem *implicit_item = NULL;
foreach(option, options)
{
@ -216,12 +217,6 @@ compute_attributes_sql_style(const List *options,
elog(ERROR, "conflicting or redundant options");
security_item = defel;
}
else if (strcmp(defel->defname, "implicit")==0)
{
if (implicit_item)
elog(ERROR, "conflicting or redundant options");
implicit_item = defel;
}
else
elog(ERROR, "invalid CREATE FUNCTION option");
}
@ -252,8 +247,6 @@ compute_attributes_sql_style(const List *options,
*strict_p = intVal(strict_item->arg);
if (security_item)
*security_definer = intVal(security_item->arg);
if (implicit_item)
*implicit_cast = intVal(implicit_item->arg);
}
@ -264,10 +257,7 @@ compute_attributes_sql_style(const List *options,
* These parameters supply optional information about a function.
* All have defaults if not specified.
*
* Note: currently, only three of these parameters actually do anything:
*
* * isImplicit means the function may be used as an implicit type
* coercion.
* Note: currently, only two of these parameters actually do anything:
*
* * isStrict means the function should not be called when any NULL
* inputs are present; instead a NULL result value should be assumed.
@ -284,7 +274,7 @@ static void
compute_attributes_with_style(List *parameters,
int32 *byte_pct_p, int32 *perbyte_cpu_p,
int32 *percall_cpu_p, int32 *outin_ratio_p,
bool *isImplicit_p, bool *isStrict_p,
bool *isStrict_p,
char *volatility_p)
{
List *pl;
@ -293,9 +283,7 @@ compute_attributes_with_style(List *parameters,
{
DefElem *param = (DefElem *) lfirst(pl);
if (strcasecmp(param->defname, "implicitcoercion") == 0)
*isImplicit_p = true;
else if (strcasecmp(param->defname, "isstrict") == 0)
if (strcasecmp(param->defname, "isstrict") == 0)
*isStrict_p = true;
else if (strcasecmp(param->defname, "isimmutable") == 0)
*volatility_p = PROVOLATILE_IMMUTABLE;
@ -398,8 +386,7 @@ CreateFunction(CreateFunctionStmt *stmt)
perbyte_cpu,
percall_cpu,
outin_ratio;
bool isImplicit,
isStrict,
bool isStrict,
security;
char volatility;
HeapTuple languageTuple;
@ -420,14 +407,13 @@ CreateFunction(CreateFunctionStmt *stmt)
perbyte_cpu = PERBYTE_CPU;
percall_cpu = PERCALL_CPU;
outin_ratio = OUTIN_RATIO;
isImplicit = false;
isStrict = false;
security = false;
volatility = PROVOLATILE_VOLATILE;
/* override attributes from explicit list */
compute_attributes_sql_style(stmt->options,
&as_clause, &language, &volatility, &isStrict, &security, &isImplicit);
&as_clause, &language, &volatility, &isStrict, &security);
/* Convert language name to canonical case */
case_translate_language_name(language, languageName);
@ -474,8 +460,7 @@ CreateFunction(CreateFunctionStmt *stmt)
compute_attributes_with_style(stmt->withClause,
&byte_pct, &perbyte_cpu, &percall_cpu,
&outin_ratio, &isImplicit, &isStrict,
&volatility);
&outin_ratio, &isStrict, &volatility);
interpret_AS_clause(languageOid, languageName, as_clause,
&prosrc_str, &probin_str);
@ -517,7 +502,6 @@ CreateFunction(CreateFunctionStmt *stmt)
probin_str, /* converted to text later */
false, /* not an aggregate */
security,
isImplicit,
isStrict,
volatility,
byte_pct,
@ -639,3 +623,217 @@ RemoveFunctionById(Oid funcOid)
heap_close(relation, RowExclusiveLock);
}
}
/*
* CREATE CAST
*/
void
CreateCast(CreateCastStmt *stmt)
{
Oid sourcetypeid;
Oid targettypeid;
Oid funcid;
HeapTuple tuple;
Relation relation;
Form_pg_proc procstruct;
Datum values[Natts_pg_proc];
char nulls[Natts_pg_proc];
int i;
ObjectAddress myself,
referenced;
sourcetypeid = LookupTypeName(stmt->sourcetype);
if (!OidIsValid(sourcetypeid))
elog(ERROR, "source data type %s does not exist",
TypeNameToString(stmt->sourcetype));
targettypeid = LookupTypeName(stmt->targettype);
if (!OidIsValid(targettypeid))
elog(ERROR, "target data type %s does not exist",
TypeNameToString(stmt->targettype));
if (sourcetypeid == targettypeid)
elog(ERROR, "source data type and target data type are the same");
relation = heap_openr(CastRelationName, RowExclusiveLock);
tuple = SearchSysCache(CASTSOURCETARGET,
ObjectIdGetDatum(sourcetypeid),
ObjectIdGetDatum(targettypeid),
0, 0);
if (HeapTupleIsValid(tuple))
elog(ERROR, "cast from data type %s to data type %s already exists",
TypeNameToString(stmt->sourcetype),
TypeNameToString(stmt->targettype));
if (stmt->func != NULL)
{
funcid = LookupFuncNameTypeNames(stmt->func->funcname, stmt->func->funcargs, false, "CreateCast");
if(!pg_proc_ownercheck(funcid, GetUserId()))
elog(ERROR, "permission denied");
tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(funcid), 0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup of function %u failed", funcid);
procstruct = (Form_pg_proc) GETSTRUCT(tuple);
if (procstruct->pronargs != 1)
elog(ERROR, "cast function must take 1 argument");
if (procstruct->proargtypes[0] != sourcetypeid)
elog(ERROR, "argument of cast function must match source data type");
if (procstruct->prorettype != targettypeid)
elog(ERROR, "return data type of cast function must match target data type");
if (procstruct->provolatile != PROVOLATILE_IMMUTABLE)
elog(ERROR, "cast function must be immutable");
if (procstruct->proisagg)
elog(ERROR, "cast function must not be an aggregate function");
if (procstruct->proretset)
elog(ERROR, "cast function must be not return a set");
ReleaseSysCache(tuple);
}
else
{
/* indicates binary compatibility */
if (!pg_type_ownercheck(sourcetypeid, GetUserId())
|| !pg_type_ownercheck(targettypeid, GetUserId()))
elog(ERROR, "permission denied");
funcid = 0;
}
/* ready to go */
values[Anum_pg_cast_castsource-1] = ObjectIdGetDatum(sourcetypeid);
values[Anum_pg_cast_casttarget-1] = ObjectIdGetDatum(targettypeid);
values[Anum_pg_cast_castfunc-1] = ObjectIdGetDatum(funcid);
values[Anum_pg_cast_castimplicit-1] = BoolGetDatum(stmt->implicit);
for (i = 0; i < Natts_pg_cast; ++i)
nulls[i] = ' ';
tuple = heap_formtuple(RelationGetDescr(relation), values, nulls);
simple_heap_insert(relation, tuple);
if (RelationGetForm(relation)->relhasindex)
{
Relation idescs[Num_pg_cast_indices];
CatalogOpenIndices(Num_pg_cast_indices, Name_pg_cast_indices, idescs);
CatalogIndexInsert(idescs, Num_pg_cast_indices, relation, tuple);
CatalogCloseIndices(Num_pg_cast_indices, idescs);
}
myself.classId = get_system_catalog_relid(CastRelationName);
myself.objectId = tuple->t_data->t_oid;
myself.objectSubId = 0;
/* dependency on source type */
referenced.classId = RelOid_pg_type;
referenced.objectId = sourcetypeid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on target type */
referenced.classId = RelOid_pg_type;
referenced.objectId = targettypeid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on function */
if (OidIsValid(funcid))
{
referenced.classId = RelOid_pg_proc;
referenced.objectId = funcid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
heap_freetuple(tuple);
heap_close(relation, RowExclusiveLock);
}
/*
* DROP CAST
*/
void
DropCast(DropCastStmt *stmt)
{
Oid sourcetypeid;
Oid targettypeid;
HeapTuple tuple;
Form_pg_cast caststruct;
ObjectAddress object;
sourcetypeid = LookupTypeName(stmt->sourcetype);
if (!OidIsValid(sourcetypeid))
elog(ERROR, "source data type %s does not exist",
TypeNameToString(stmt->sourcetype));
targettypeid = LookupTypeName(stmt->targettype);
if (!OidIsValid(targettypeid))
elog(ERROR, "target data type %s does not exist",
TypeNameToString(stmt->targettype));
tuple = SearchSysCache(CASTSOURCETARGET,
ObjectIdGetDatum(sourcetypeid),
ObjectIdGetDatum(targettypeid),
0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cast from type %s to type %s does not exist",
TypeNameToString(stmt->sourcetype),
TypeNameToString(stmt->targettype));
/* Permission check */
caststruct = (Form_pg_cast) GETSTRUCT(tuple);
if (caststruct->castfunc != InvalidOid)
{
if(!pg_proc_ownercheck(caststruct->castfunc, GetUserId()))
elog(ERROR, "permission denied");
}
else
{
if (!pg_type_ownercheck(sourcetypeid, GetUserId())
|| !pg_type_ownercheck(targettypeid, GetUserId()))
elog(ERROR, "permission denied");
}
ReleaseSysCache(tuple);
/*
* Do the deletion
*/
object.classId = get_system_catalog_relid(CastRelationName);
object.objectId = tuple->t_data->t_oid;
object.objectSubId = 0;
performDeletion(&object, stmt->behavior);
}
void
DropCastById(Oid castOid)
{
Relation relation;
ScanKeyData scankey;
HeapScanDesc scan;
HeapTuple tuple;
relation = heap_openr(CastRelationName, RowExclusiveLock);
ScanKeyEntryInitialize(&scankey, 0x0,
ObjectIdAttributeNumber, F_OIDEQ,
ObjectIdGetDatum(castOid));
scan = heap_beginscan(relation, SnapshotNow, 1, &scankey);
tuple = heap_getnext(scan, ForwardScanDirection);
if (HeapTupleIsValid(tuple))
simple_heap_delete(relation, &tuple->t_self);
else
elog(ERROR, "could not find tuple for cast %u", castOid);
heap_endscan(scan);
heap_close(relation, RowExclusiveLock);
}

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.346 2002/07/18 17:14:19 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.347 2002/07/18 23:11:27 petere Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -135,13 +135,13 @@ static void doNegateFloat(Value *v);
AlterDatabaseSetStmt, AlterGroupStmt,
AlterTableStmt, AlterUserStmt, AlterUserSetStmt,
AnalyzeStmt, ClosePortalStmt, ClusterStmt, CommentStmt,
ConstraintsSetStmt, CopyStmt, CreateAsStmt,
ConstraintsSetStmt, CopyStmt, CreateAsStmt, CreateCastStmt,
CreateDomainStmt, CreateGroupStmt, CreatePLangStmt,
CreateSchemaStmt, CreateSeqStmt, CreateStmt,
CreateAssertStmt, CreateTrigStmt, CreateUserStmt,
CreatedbStmt, CursorStmt, DefineStmt, DeleteStmt,
DropGroupStmt, DropPLangStmt, DropStmt,
DropAssertStmt, DropTrigStmt, DropRuleStmt,
DropAssertStmt, DropTrigStmt, DropRuleStmt, DropCastStmt,
DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt,
LockStmt, NotifyStmt, OptimizableStmt,
@ -165,7 +165,7 @@ static void doNegateFloat(Value *v);
%type <defelt> createdb_opt_item, copy_opt_item
%type <ival> opt_lock, lock_type
%type <boolean> opt_force, opt_or_replace
%type <boolean> opt_force, opt_or_replace, opt_assignment
%type <list> user_list
@ -346,7 +346,7 @@ static void doNegateFloat(Value *v);
HANDLER, HAVING, HOUR_P,
ILIKE, IMMEDIATE, IMMUTABLE, IMPLICIT, IN_P, INCREMENT,
ILIKE, IMMEDIATE, IMMUTABLE, IN_P, INCREMENT,
INDEX, INHERITS, INITIALLY, INNER_P, INOUT, INPUT,
INSENSITIVE, INSERT, INSTEAD, INT, INTEGER, INTERSECT,
INTERVAL, INTO, INVOKER, IS, ISNULL, ISOLATION,
@ -475,6 +475,7 @@ stmt :
| CopyStmt
| CreateStmt
| CreateAsStmt
| CreateCastStmt
| CreateDomainStmt
| CreateFunctionStmt
| CreateSchemaStmt
@ -489,6 +490,7 @@ stmt :
| DropStmt
| TruncateStmt
| CommentStmt
| DropCastStmt
| DropGroupStmt
| DropPLangStmt
| DropAssertStmt
@ -2886,15 +2888,6 @@ RecipeStmt: EXECUTE RECIPE recipe_name
* as <filename or code in language as appropriate>
* language <lang> [with parameters]
*
* CAST() form allowing all options from the CREATE FUNCTION form:
* create [or replace] cast (<type> as <type>)
* as <filename or code in language as appropriate>
* language <lang> [with parameters]
*
* SQL99 CAST() form (requires a function to be previously defined):
* create [or replace] cast (<type> as <type>)
* with function fname (<type>) [as assignment]
*
*****************************************************************************/
CreateFunctionStmt:
@ -2910,63 +2903,6 @@ CreateFunctionStmt:
n->withClause = $9;
$$ = (Node *)n;
}
/* CREATE CAST SQL99 standard form */
| CREATE opt_or_replace CAST '(' func_type AS func_type ')'
WITH FUNCTION func_name func_args opt_assignment opt_definition
{
CreateFunctionStmt *n;
char buf[256];
n = makeNode(CreateFunctionStmt);
n->replace = $2;
n->funcname = $7->names;
n->argTypes = makeList1($5);
n->returnType = $7;
/* expand this into a string of SQL language */
strcpy(buf, "select ");
strcat(buf, ((Value *)lfirst($11))->val.str);
strcat(buf, "($1)");
n->options = lappend($14, makeDefElem("as", (Node *)makeList1(makeString(pstrdup(buf)))));
/* make sure that this will allow implicit casting */
n->options = lappend(n->options,
makeDefElem("implicit", (Node *)makeInteger(TRUE)));
/* and mention that this is SQL language */
n->options = lappend(n->options,
makeDefElem("language", (Node *)makeString(pstrdup("sql"))));
$$ = (Node *)n;
}
/* CREATE CAST SQL99 minimally variant form */
| CREATE opt_or_replace CAST '(' func_type AS func_type ')'
WITH FUNCTION func_name func_args AS Sconst opt_definition
{
CreateFunctionStmt *n;
n = makeNode(CreateFunctionStmt);
n->replace = $2;
n->funcname = $7->names;
n->argTypes = makeList1($5);
n->returnType = $7;
n->options = lappend($15, makeDefElem("as", (Node *)lcons(makeList1(makeString($14)), $11)));
/* make sure that this will allow implicit casting */
n->options = lappend(n->options,
makeDefElem("implicit", (Node *)makeInteger(TRUE)));
n->options = lappend(n->options,
makeDefElem("language", (Node *)makeString(pstrdup("c"))));
$$ = (Node *)n;
}
/* CREATE CAST with mostly CREATE FUNCTION clauses */
| CREATE opt_or_replace CAST '(' func_type AS func_type ')'
createfunc_opt_list opt_definition
{
CreateFunctionStmt *n;
n = makeNode(CreateFunctionStmt);
n->replace = $2;
n->funcname = $7->names;
n->argTypes = makeList1($5);
n->returnType = $7;
/* make sure that this will allow implicit casting */
n->options = lappend($9, makeDefElem("implicit", (Node *)makeInteger(TRUE)));
n->withClause = $10;
$$ = (Node *)n;
}
;
opt_or_replace:
@ -3090,10 +3026,6 @@ createfunc_opt_item:
{
$$ = makeDefElem("security", (Node *)makeInteger(FALSE));
}
| IMPLICIT CAST
{
$$ = makeDefElem("implicit", (Node *)makeInteger(TRUE));
}
;
func_as: Sconst { $$ = makeList1(makeString($1)); }
@ -3108,10 +3040,6 @@ opt_definition:
| /*EMPTY*/ { $$ = NIL; }
;
opt_assignment: AS ASSIGNMENT {}
| /*EMPTY*/ {}
;
/*****************************************************************************
*
@ -3132,14 +3060,6 @@ RemoveFuncStmt:
n->behavior = $5;
$$ = (Node *)n;
}
| DROP CAST '(' func_type AS func_type ')' opt_drop_behavior
{
RemoveFuncStmt *n = makeNode(RemoveFuncStmt);
n->funcname = $6->names;
n->args = makeList1($4);
n->behavior = $8;
$$ = (Node *)n;
}
;
RemoveAggrStmt:
@ -3190,6 +3110,49 @@ any_operator:
;
/*****************************************************************************
*
* CREATE CAST / DROP CAST
*
*****************************************************************************/
CreateCastStmt: CREATE CAST '(' ConstTypename AS ConstTypename ')'
WITH FUNCTION function_with_argtypes opt_assignment
{
CreateCastStmt *n = makeNode(CreateCastStmt);
n->sourcetype = $4;
n->targettype = $6;
n->func = (FuncWithArgs *) $10;
n->implicit = $11;
$$ = (Node *)n;
}
| CREATE CAST '(' ConstTypename AS ConstTypename ')'
WITHOUT FUNCTION opt_assignment
{
CreateCastStmt *n = makeNode(CreateCastStmt);
n->sourcetype = $4;
n->targettype = $6;
n->func = NULL;
n->implicit = $10;
$$ = (Node *)n;
}
opt_assignment: AS ASSIGNMENT { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
DropCastStmt: DROP CAST '(' ConstTypename AS ConstTypename ')' opt_drop_behavior
{
DropCastStmt *n = makeNode(DropCastStmt);
n->sourcetype = $4;
n->targettype = $6;
n->behavior = $8;
$$ = (Node *)n;
}
/*****************************************************************************
*
* QUERY:
@ -6701,7 +6664,6 @@ unreserved_keyword:
| HOUR_P
| IMMEDIATE
| IMMUTABLE
| IMPLICIT
| INCREMENT
| INDEX
| INHERITS

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.121 2002/07/18 17:14:19 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.122 2002/07/18 23:11:28 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -142,7 +142,6 @@ static const ScanKeyword ScanKeywords[] = {
{"ilike", ILIKE},
{"immediate", IMMEDIATE},
{"immutable", IMMUTABLE},
{"implicit", IMPLICIT},
{"in", IN_P},
{"increment", INCREMENT},
{"index", INDEX},

View File

@ -8,12 +8,13 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.77 2002/07/09 13:52:14 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.78 2002/07/18 23:11:28 petere Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_proc.h"
#include "nodes/makefuncs.h"
#include "optimizer/clauses.h"
@ -31,8 +32,9 @@ 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, bool isExplicit);
static Oid find_coercion_function(Oid targetTypeId, Oid sourceTypeId,
bool isExplicit);
static Oid find_typmod_coercion_function(Oid typeId);
static Node *TypeConstraints(Node *arg, Oid typeId);
/* coerce_type()
@ -142,7 +144,6 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
funcId = find_coercion_function(baseTypeId,
getBaseType(inputTypeId),
InvalidOid,
isExplicit);
if (!OidIsValid(funcId))
elog(ERROR, "coerce_type: no conversion function from '%s' to '%s'",
@ -258,7 +259,6 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
*/
funcId = find_coercion_function(getBaseType(targetTypeId),
getBaseType(inputTypeId),
InvalidOid,
isExplicit);
if (!OidIsValid(funcId))
return false;
@ -312,8 +312,7 @@ coerce_type_typmod(ParseState *pstate, Node *node,
if (atttypmod < 0 || atttypmod == exprTypmod(node))
return node;
/* Note this is always implicit coercion */
funcId = find_coercion_function(baseTypeId, baseTypeId, INT4OID, false);
funcId = find_typmod_coercion_function(baseTypeId);
if (OidIsValid(funcId))
{
Const *cons;
@ -621,21 +620,25 @@ TypeCategory(Oid inType)
static bool
DirectlyBinaryCompatible(Oid type1, Oid type2)
{
HeapTuple tuple;
bool result;
if (type1 == type2)
return true;
if (TypeIsTextGroup(type1) && TypeIsTextGroup(type2))
return true;
if (TypeIsInt4GroupA(type1) && TypeIsInt4GroupA(type2))
return true;
if (TypeIsInt4GroupB(type1) && TypeIsInt4GroupB(type2))
return true;
if (TypeIsInt4GroupC(type1) && TypeIsInt4GroupC(type2))
return true;
if (TypeIsInetGroup(type1) && TypeIsInetGroup(type2))
return true;
if (TypeIsBitGroup(type1) && TypeIsBitGroup(type2))
return true;
return false;
tuple = SearchSysCache(CASTSOURCETARGET, type1, type2, 0, 0);
if (HeapTupleIsValid(tuple))
{
Form_pg_cast caststruct;
caststruct = (Form_pg_cast) GETSTRUCT(tuple);
result = caststruct->castfunc == InvalidOid && caststruct->castimplicit;
ReleaseSysCache(tuple);
}
else
result = false;
return result;
}
@ -750,34 +753,51 @@ 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,
bool isExplicit)
find_coercion_function(Oid targetTypeId, Oid sourceTypeId, bool isExplicit)
{
Oid funcid = InvalidOid;
HeapTuple tuple;
tuple = SearchSysCache(CASTSOURCETARGET,
ObjectIdGetDatum(sourceTypeId),
ObjectIdGetDatum(targetTypeId),
0, 0);
if (HeapTupleIsValid(tuple))
{
Form_pg_cast cform = (Form_pg_cast) GETSTRUCT(tuple);
if (isExplicit || cform->castimplicit)
funcid = cform->castfunc;
ReleaseSysCache(tuple);
}
return funcid;
}
static Oid
find_typmod_coercion_function(Oid typeId)
{
Oid funcid = InvalidOid;
Type targetType;
char *typname;
Oid typnamespace;
Oid oid_array[FUNC_MAX_ARGS];
int nargs;
HeapTuple ftup;
targetType = typeidType(targetTypeId);
targetType = typeidType(typeId);
typname = NameStr(((Form_pg_type) GETSTRUCT(targetType))->typname);
typnamespace = ((Form_pg_type) GETSTRUCT(targetType))->typnamespace;
MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid));
oid_array[0] = inputTypeId;
if (OidIsValid(secondArgType))
{
oid_array[1] = secondArgType;
nargs = 2;
}
else
nargs = 1;
oid_array[0] = typeId;
oid_array[1] = INT4OID;
ftup = SearchSysCache(PROCNAMENSP,
CStringGetDatum(typname),
Int16GetDatum(nargs),
Int16GetDatum(2),
PointerGetDatum(oid_array),
ObjectIdGetDatum(typnamespace));
if (HeapTupleIsValid(ftup))
@ -785,15 +805,11 @@ find_coercion_function(Oid targetTypeId, Oid inputTypeId, Oid secondArgType,
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 &&
if (pform->prorettype == typeId && !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;
}
/* Okay to use it */
funcid = ftup->t_data->t_oid;
}
ReleaseSysCache(ftup);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.271 2002/07/18 16:47:25 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.272 2002/07/18 23:11:28 petere Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@ -1693,7 +1693,7 @@ PostgresMain(int argc, char *argv[], const char *username)
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.271 $ $Date: 2002/07/18 16:47:25 $\n");
puts("$Revision: 1.272 $ $Date: 2002/07/18 23:11:28 $\n");
}
/*
@ -2444,6 +2444,14 @@ CreateCommandTag(Node *parsetree)
tag = "CREATE CONVERSION";
break;
case T_CreateCastStmt:
tag = "CREATE CAST";
break;
case T_DropCastStmt:
tag = "DROP CAST";
break;
default:
elog(LOG, "CreateCommandTag: unknown parse node type %d",
nodeTag(parsetree));

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.163 2002/07/18 16:47:25 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.164 2002/07/18 23:11:28 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -829,6 +829,14 @@ ProcessUtility(Node *parsetree,
}
break;
case T_CreateCastStmt:
CreateCast((CreateCastStmt *) parsetree);
break;
case T_DropCastStmt:
DropCast((DropCastStmt *) parsetree);
break;
default:
elog(ERROR, "ProcessUtility: command #%d unsupported",
nodeTag(parsetree));

View File

@ -3,7 +3,7 @@
* back to source text
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.111 2002/07/18 17:14:20 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.112 2002/07/18 23:11:28 petere Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@ -43,6 +43,7 @@
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/namespace.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_index.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_operator.h"
@ -2048,9 +2049,9 @@ get_agg_expr(Aggref *aggref, deparse_context *context)
* Strip any type coercions at the top of the given expression tree,
* as long as they are coercions to the given datatype.
*
* A RelabelType node is always a type coercion. A function call is also
* considered a type coercion if it has one argument and the function name
* is the same as the (internal) name of its result type.
* A RelabelType node is always a type coercion. A function call is
* also considered a type coercion if it has one argument and there is
* a cast declared that uses it.
*
* XXX It'd be better if the parsetree retained some explicit indication
* of the coercion, so we didn't need these heuristics.
@ -2069,9 +2070,9 @@ strip_type_coercion(Node *expr, Oid resultType)
{
Func *func;
HeapTuple procTuple;
HeapTuple typeTuple;
HeapTuple castTuple;
Form_pg_proc procStruct;
Form_pg_type typeStruct;
Form_pg_cast castStruct;
func = (Func *) (((Expr *) expr)->oper);
Assert(IsA(func, Func));
@ -2085,33 +2086,33 @@ strip_type_coercion(Node *expr, Oid resultType)
elog(ERROR, "cache lookup for proc %u failed", func->funcid);
procStruct = (Form_pg_proc) GETSTRUCT(procTuple);
/* Double-check func has one arg and correct result type */
/* Also, it must be an implicit coercion function */
if (procStruct->pronargs != 1 ||
procStruct->prorettype != resultType ||
!procStruct->proimplicit)
procStruct->prorettype != resultType)
{
ReleaseSysCache(procTuple);
return expr;
}
/* See if function has same name/namespace as its result type */
typeTuple = SearchSysCache(TYPEOID,
ObjectIdGetDatum(procStruct->prorettype),
0, 0, 0);
if (!HeapTupleIsValid(typeTuple))
elog(ERROR, "cache lookup for type %u failed",
procStruct->prorettype);
typeStruct = (Form_pg_type) GETSTRUCT(typeTuple);
if (strcmp(NameStr(procStruct->proname),
NameStr(typeStruct->typname)) != 0 ||
procStruct->pronamespace != typeStruct->typnamespace)
/* See if function has is actually declared as a cast */
castTuple = SearchSysCache(CASTSOURCETARGET,
ObjectIdGetDatum(procStruct->proargtypes[0]),
ObjectIdGetDatum(procStruct->prorettype),
0, 0);
if (!HeapTupleIsValid(castTuple))
{
ReleaseSysCache(procTuple);
ReleaseSysCache(typeTuple);
return expr;
}
/* It must also be an implicit cast. */
castStruct = (Form_pg_cast) GETSTRUCT(castTuple);
if (!castStruct->castimplicit)
{
ReleaseSysCache(procTuple);
ReleaseSysCache(castTuple);
return expr;
}
/* Okay, it is indeed a type-coercion function */
ReleaseSysCache(procTuple);
ReleaseSysCache(typeTuple);
ReleaseSysCache(castTuple);
return strip_type_coercion(lfirst(((Expr *) expr)->args), resultType);
}

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.46 2002/06/20 20:29:38 momjian Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.47 2002/07/18 23:11:29 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -63,7 +63,6 @@ SetDefine(char *querystr, Oid elemType)
fileName, /* probin */
false, /* not aggregate */
false, /* security invoker */
false, /* not implicit coercion */
false, /* isStrict (irrelevant, no args) */
PROVOLATILE_VOLATILE, /* assume unsafe */
100, /* byte_pct */

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.81 2002/07/11 07:39:27 ishii Exp $
* $Header: /cvsroot/pgsql/src/backend/utils/cache/syscache.c,v 1.82 2002/07/18 23:11:29 petere Exp $
*
* NOTES
* These routines allow the parser/planner/executor to perform
@ -28,6 +28,7 @@
#include "catalog/pg_aggregate.h"
#include "catalog/pg_amop.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_group.h"
#include "catalog/pg_index.h"
@ -174,6 +175,17 @@ static const struct cachedesc cacheinfo[] = {
0,
0
}},
{
CastRelationName, /* CASTSOURCETARGET */
CastSourceTargetIndex,
0,
2,
{
Anum_pg_cast_castsource,
Anum_pg_cast_casttarget,
0,
0
}},
{OperatorClassRelationName, /* CLAAMNAMENSP */
OpclassAmNameNspIndex,
0,

View File

@ -27,7 +27,7 @@
# Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.160 2002/07/18 16:47:25 tgl Exp $
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.161 2002/07/18 23:11:29 petere Exp $
#
#-------------------------------------------------------------------------
@ -708,6 +708,7 @@ $ECHO_N "initializing pg_depend... "$ECHO_C
-- First delete any already-made entries; PINs override all else, and must
-- be the only entries for their objects.
DELETE FROM pg_depend;
INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_cast;
INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_class;
INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_proc;
INSERT INTO pg_depend SELECT 0,0,0, tableoid,oid,0, 'p' FROM pg_type;

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.65 2002/06/20 20:29:41 momjian Exp $
* $Header: /cvsroot/pgsql/src/bin/pg_dump/common.c,v 1.66 2002/07/18 23:11:29 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -170,6 +170,13 @@ dumpSchema(Archive *fout,
dumpOprs(fout, oprinfo, numOperators);
}
if (!dataOnly)
{
if (g_verbose)
write_msg(NULL, "dumping out user-defined casts\n");
dumpCasts(fout, finfo, numFuncs, tinfo, numTypes);
}
*numTablesPtr = numTables;
return tblinfo;
}
@ -386,6 +393,23 @@ findFuncByOid(FuncInfo *finfo, int numFuncs, const char *oid)
return -1;
}
/*
* Finds the index (in tinfo) of the type with the given OID. Returns
* -1 if not found.
*/
int
findTypeByOid(TypeInfo *tinfo, int numTypes, const char *oid)
{
int i;
for (i = 0; i < numTypes; i++)
{
if (strcmp(tinfo[i].oid, oid) == 0)
return i;
}
return -1;
}
/*
* findOprByOid
* given the oid of an operator, return the name of the operator

View File

@ -22,7 +22,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.273 2002/07/18 04:50:51 momjian Exp $
* $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.274 2002/07/18 23:11:29 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -3398,7 +3398,6 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo)
char *prosrc;
char *probin;
char *provolatile;
char *proimplicit;
char *proisstrict;
char *prosecdef;
char *lanname;
@ -3417,7 +3416,7 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo)
{
appendPQExpBuffer(query,
"SELECT proretset, prosrc, probin, "
"provolatile, proimplicit, proisstrict, prosecdef, "
"provolatile, proisstrict, prosecdef, "
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
"FROM pg_catalog.pg_proc "
"WHERE oid = '%s'::pg_catalog.oid",
@ -3428,7 +3427,6 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo)
appendPQExpBuffer(query,
"SELECT proretset, prosrc, probin, "
"case when proiscachable then 'i' else 'v' end as provolatile, "
"'f'::boolean as proimplicit, "
"proisstrict, "
"'f'::boolean as prosecdef, "
"(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
@ -3441,7 +3439,6 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo)
appendPQExpBuffer(query,
"SELECT proretset, prosrc, probin, "
"case when proiscachable then 'i' else 'v' end as provolatile, "
"'f'::boolean as proimplicit, "
"'f'::boolean as proisstrict, "
"'f'::boolean as prosecdef, "
"(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
@ -3472,7 +3469,6 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo)
prosrc = PQgetvalue(res, 0, PQfnumber(res, "prosrc"));
probin = PQgetvalue(res, 0, PQfnumber(res, "probin"));
provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
proimplicit = PQgetvalue(res, 0, PQfnumber(res, "proimplicit"));
proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
@ -3533,9 +3529,6 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo)
}
}
if (proimplicit[0] == 't')
appendPQExpBuffer(q, " IMPLICIT CAST");
if (proisstrict[0] == 't')
appendPQExpBuffer(q, " STRICT");
@ -3569,6 +3562,108 @@ done:
free(funcsig_tag);
}
/*
* Dump all casts
*/
void
dumpCasts(Archive *fout,
FuncInfo *finfo, int numFuncs,
TypeInfo *tinfo, int numTypes)
{
PGresult *res;
PQExpBuffer query = createPQExpBuffer();
PQExpBuffer defqry = createPQExpBuffer();
PQExpBuffer delqry = createPQExpBuffer();
int ntups;
int i;
/* Make sure we are in proper schema */
selectSourceSchema("pg_catalog");
if (fout->remoteVersion >= 70300)
appendPQExpBuffer(query, "SELECT oid, castsource, casttarget, castfunc, castimplicit FROM pg_cast ORDER BY 1,2,3;");
else
appendPQExpBuffer(query, "SELECT p.oid, t1.oid, t2.oid, p.oid, true FROM pg_type t1, pg_type t2, pg_proc p WHERE p.pronargs = 1 AND p.proargtypes[0] = t1.oid AND p.prorettype = t2.oid AND p.proname = t2.typname ORDER BY 1,2,3;");
res = PQexec(g_conn, query->data);
if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
{
write_msg(NULL, "query to obtain list of casts failed: %s",
PQerrorMessage(g_conn));
exit_nicely();
}
ntups = PQntuples(res);
for (i = 0; i < ntups; i++)
{
char * castoid = PQgetvalue(res, i, 0);
char * castsource = PQgetvalue(res, i, 1);
char * casttarget = PQgetvalue(res, i, 2);
char * castfunc = PQgetvalue(res, i, 3);
char * castimplicit = PQgetvalue(res, i, 4);
int fidx = -1;
const char *((*deps)[]);
if (strcmp(castfunc, "0") != 0)
fidx = findFuncByOid(finfo, numFuncs, castfunc);
/*
* We treat the cast as being in the namespace of the
* underlying function. This doesn't handle binary compatible
* casts. Where should those go?
*/
if (fidx < 0 || !finfo[fidx].pronamespace->dump)
continue;
/* Make a dependency to ensure function is dumped first */
if (fidx >= 0)
{
deps = malloc(sizeof(char *) * 2);
(*deps)[0] = strdup(castfunc);
(*deps)[1] = NULL; /* End of List */
}
else
deps = NULL;
resetPQExpBuffer(defqry);
resetPQExpBuffer(delqry);
appendPQExpBuffer(delqry, "DROP CAST (%s AS %s);\n",
getFormattedTypeName(castsource, zeroAsNone),
getFormattedTypeName(casttarget, zeroAsNone));
appendPQExpBuffer(defqry, "CREATE CAST (%s AS %s) ",
getFormattedTypeName(castsource, zeroAsNone),
getFormattedTypeName(casttarget, zeroAsNone));
if (strcmp(castfunc, "0")==0)
appendPQExpBuffer(defqry, "WITHOUT FUNCTION");
else
appendPQExpBuffer(defqry, "WITH FUNCTION %s",
format_function_signature(&finfo[fidx], true));
if (strcmp(castimplicit, "t")==0)
appendPQExpBuffer(defqry, " AS ASSIGNMENT");
appendPQExpBuffer(defqry, ";\n");
ArchiveEntry(fout, castoid,
format_function_signature(&finfo[fidx], false),
finfo[fidx].pronamespace->nspname, "",
"CAST", deps,
defqry->data, delqry->data,
NULL, NULL, NULL);
}
PQclear(res);
destroyPQExpBuffer(query);
destroyPQExpBuffer(defqry);
destroyPQExpBuffer(delqry);
}
/*
* dumpOprs
* writes out to fout the queries to recreate all the user-defined operators

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_dump.h,v 1.90 2002/07/06 20:12:30 momjian Exp $
* $Id: pg_dump.h,v 1.91 2002/07/18 23:11:29 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -177,6 +177,7 @@ typedef enum _OidOptions
extern int findTableByOid(TableInfo *tbinfo, int numTables, const char *oid);
extern char *findOprByOid(OprInfo *oprinfo, int numOprs, const char *oid);
extern int findFuncByOid(FuncInfo *finfo, int numFuncs, const char *oid);
extern int findTypeByOid(TypeInfo *tinfo, int numTypes, const char *oid);
extern void check_conn_and_db(void);
extern void exit_nicely(void);
@ -202,6 +203,8 @@ extern void dumpTypes(Archive *fout, FuncInfo *finfo, int numFuncs,
TypeInfo *tinfo, int numTypes);
extern void dumpProcLangs(Archive *fout, FuncInfo finfo[], int numFuncs);
extern void dumpFuncs(Archive *fout, FuncInfo finfo[], int numFuncs);
extern void dumpCasts(Archive *fout, FuncInfo *finfo, int numFuncs,
TypeInfo *tinfo, int numTypes);
extern void dumpAggs(Archive *fout, AggInfo agginfo[], int numAggregates);
extern void dumpOprs(Archive *fout, OprInfo *oprinfo, int numOperators);
extern void dumpTables(Archive *fout, TableInfo tblinfo[], int numTables,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: catname.h,v 1.28 2002/07/12 18:43:19 tgl Exp $
* $Id: catname.h,v 1.29 2002/07/18 23:11:30 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -20,6 +20,7 @@
#define AccessMethodOperatorRelationName "pg_amop"
#define AccessMethodProcedureRelationName "pg_amproc"
#define AttributeRelationName "pg_attribute"
#define CastRelationName "pg_cast"
#define ConstraintRelationName "pg_constraint"
#define ConversionRelationName "pg_conversion"
#define DatabaseRelationName "pg_database"

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: catversion.h,v 1.140 2002/07/15 16:33:31 tgl Exp $
* $Id: catversion.h,v 1.141 2002/07/18 23:11:30 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200207141
#define CATALOG_VERSION_NO 200207191
#endif

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: indexing.h,v 1.70 2002/07/15 16:33:31 tgl Exp $
* $Id: indexing.h,v 1.71 2002/07/18 23:11:30 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -26,6 +26,7 @@
#define Num_pg_amproc_indices 1
#define Num_pg_attr_indices 2
#define Num_pg_attrdef_indices 2
#define Num_pg_cast_indices 1
#define Num_pg_class_indices 2
#define Num_pg_constraint_indices 3
#define Num_pg_conversion_indices 3
@ -60,6 +61,7 @@
#define AttrDefaultOidIndex "pg_attrdef_oid_index"
#define AttributeRelidNameIndex "pg_attribute_relid_attnam_index"
#define AttributeRelidNumIndex "pg_attribute_relid_attnum_index"
#define CastSourceTargetIndex "pg_cast_source_target_index"
#define ClassNameNspIndex "pg_class_relname_nsp_index"
#define ClassOidIndex "pg_class_oid_index"
#define ConstraintNameNspIndex "pg_constraint_conname_nsp_index"
@ -108,6 +110,7 @@ extern char *Name_pg_amop_indices[];
extern char *Name_pg_amproc_indices[];
extern char *Name_pg_attr_indices[];
extern char *Name_pg_attrdef_indices[];
extern char *Name_pg_cast_indices[];
extern char *Name_pg_class_indices[];
extern char *Name_pg_constraint_indices[];
extern char *Name_pg_conversion_indices[];
@ -166,6 +169,7 @@ DECLARE_UNIQUE_INDEX(pg_attrdef_adrelid_adnum_index on pg_attrdef using btree(ad
DECLARE_UNIQUE_INDEX(pg_attrdef_oid_index on pg_attrdef using btree(oid oid_ops));
DECLARE_UNIQUE_INDEX(pg_attribute_relid_attnam_index on pg_attribute using btree(attrelid oid_ops, attname name_ops));
DECLARE_UNIQUE_INDEX(pg_attribute_relid_attnum_index on pg_attribute using btree(attrelid oid_ops, attnum int2_ops));
DECLARE_UNIQUE_INDEX(pg_cast_source_target_index on pg_cast using btree(castsource oid_ops, casttarget oid_ops));
DECLARE_UNIQUE_INDEX(pg_class_oid_index on pg_class using btree(oid oid_ops));
DECLARE_UNIQUE_INDEX(pg_class_relname_nsp_index on pg_class using btree(relname name_ops, relnamespace oid_ops));
/* This following index is not used for a cache and is not unique */

View File

@ -0,0 +1,225 @@
/*-------------------------------------------------------------------------
*
* $Header: /cvsroot/pgsql/src/include/catalog/pg_cast.h,v 1.1 2002/07/18 23:11:30 petere Exp $
*
* Copyright (c) 2002, PostgreSQL Global Development Group
*
*-------------------------------------------------------------------------
*/
#ifndef PG_CAST_H
#define PG_CAST_H
CATALOG(pg_cast)
{
Oid castsource;
Oid casttarget;
Oid castfunc; /* 0 = binary compatible */
bool castimplicit;
} FormData_pg_cast;
typedef FormData_pg_cast *Form_pg_cast;
#define Natts_pg_cast 4
#define Anum_pg_cast_castsource 1
#define Anum_pg_cast_casttarget 2
#define Anum_pg_cast_castfunc 3
#define Anum_pg_cast_castimplicit 4
/* ----------------
* initial contents of pg_cast
* ----------------
*/
/*
* binary compatible casts
*/
DATA(insert ( 25 1042 0 t ));
DATA(insert ( 25 1043 0 t ));
DATA(insert ( 1042 25 0 t ));
DATA(insert ( 1042 1043 0 t ));
DATA(insert ( 1043 25 0 t ));
DATA(insert ( 1043 1042 0 t ));
DATA(insert ( 23 24 0 t ));
DATA(insert ( 23 26 0 t ));
DATA(insert ( 23 2202 0 t ));
DATA(insert ( 23 2203 0 t ));
DATA(insert ( 23 2204 0 t ));
DATA(insert ( 23 2205 0 t ));
DATA(insert ( 23 2206 0 t ));
DATA(insert ( 24 23 0 t ));
DATA(insert ( 24 26 0 t ));
DATA(insert ( 24 2202 0 t ));
DATA(insert ( 24 2203 0 t ));
DATA(insert ( 24 2204 0 t ));
DATA(insert ( 24 2205 0 t ));
DATA(insert ( 24 2206 0 t ));
DATA(insert ( 26 23 0 t ));
DATA(insert ( 26 24 0 t ));
DATA(insert ( 26 2202 0 t ));
DATA(insert ( 26 2203 0 t ));
DATA(insert ( 26 2204 0 t ));
DATA(insert ( 26 2205 0 t ));
DATA(insert ( 26 2206 0 t ));
DATA(insert ( 2202 23 0 t ));
DATA(insert ( 2202 24 0 t ));
DATA(insert ( 2202 26 0 t ));
DATA(insert ( 2202 2203 0 t ));
DATA(insert ( 2202 2204 0 t ));
DATA(insert ( 2202 2205 0 t ));
DATA(insert ( 2202 2206 0 t ));
DATA(insert ( 2203 23 0 t ));
DATA(insert ( 2203 24 0 t ));
DATA(insert ( 2203 26 0 t ));
DATA(insert ( 2203 2202 0 t ));
DATA(insert ( 2203 2204 0 t ));
DATA(insert ( 2203 2205 0 t ));
DATA(insert ( 2203 2206 0 t ));
DATA(insert ( 2204 23 0 t ));
DATA(insert ( 2204 24 0 t ));
DATA(insert ( 2204 26 0 t ));
DATA(insert ( 2204 2202 0 t ));
DATA(insert ( 2204 2203 0 t ));
DATA(insert ( 2204 2205 0 t ));
DATA(insert ( 2204 2206 0 t ));
DATA(insert ( 2205 23 0 t ));
DATA(insert ( 2205 24 0 t ));
DATA(insert ( 2205 26 0 t ));
DATA(insert ( 2205 2202 0 t ));
DATA(insert ( 2205 2203 0 t ));
DATA(insert ( 2205 2204 0 t ));
DATA(insert ( 2205 2206 0 t ));
DATA(insert ( 2206 23 0 t ));
DATA(insert ( 2206 24 0 t ));
DATA(insert ( 2206 26 0 t ));
DATA(insert ( 2206 2202 0 t ));
DATA(insert ( 2206 2203 0 t ));
DATA(insert ( 2206 2204 0 t ));
DATA(insert ( 2206 2205 0 t ));
DATA(insert ( 23 702 0 t ));
DATA(insert ( 702 23 0 t ));
DATA(insert ( 23 703 0 t ));
DATA(insert ( 703 23 0 t ));
DATA(insert ( 650 869 0 t ));
DATA(insert ( 869 650 0 t ));
DATA(insert ( 1560 1562 0 t ));
DATA(insert ( 1562 1560 0 t ));
/*
* regular casts through a function
*
* This list can be obtained from the following query as long as the
* naming convention of the cast functions remains the same:
*
* select p.proargtypes[0] as source, p.prorettype as target, p.oid as func, p.proimplicit as implicit from pg_proc p, pg_type t where p.pronargs=1 and p.proname = t.typname and p.prorettype = t.oid order by 1, 2;
*/
DATA(insert ( 18 25 946 t ));
DATA(insert ( 18 1042 860 t ));
DATA(insert ( 19 25 406 t ));
DATA(insert ( 19 1042 408 t ));
DATA(insert ( 19 1043 1401 t ));
DATA(insert ( 20 21 714 t ));
DATA(insert ( 20 23 480 t ));
DATA(insert ( 20 25 1288 t ));
DATA(insert ( 20 701 482 t ));
DATA(insert ( 20 1043 1623 f ));
DATA(insert ( 20 1700 1781 t ));
DATA(insert ( 21 20 754 t ));
DATA(insert ( 21 23 313 t ));
DATA(insert ( 21 25 113 t ));
DATA(insert ( 21 700 236 t ));
DATA(insert ( 21 701 235 t ));
DATA(insert ( 21 1700 1782 t ));
DATA(insert ( 23 20 481 t ));
DATA(insert ( 23 21 314 t ));
DATA(insert ( 23 25 112 t ));
DATA(insert ( 23 700 318 t ));
DATA(insert ( 23 701 316 t ));
/*xDATA(insert ( 23 703 1200 f ));*/
DATA(insert ( 23 1043 1619 f ));
DATA(insert ( 23 1700 1740 t ));
DATA(insert ( 25 18 944 t ));
DATA(insert ( 25 19 407 t ));
DATA(insert ( 25 20 1289 f ));
DATA(insert ( 25 21 818 f ));
DATA(insert ( 25 23 819 f ));
DATA(insert ( 25 26 817 f ));
DATA(insert ( 25 650 1714 f ));
DATA(insert ( 25 700 839 f ));
DATA(insert ( 25 701 838 f ));
DATA(insert ( 25 829 767 f ));
DATA(insert ( 25 869 1713 f ));
DATA(insert ( 25 1082 748 f ));
DATA(insert ( 25 1083 837 f ));
DATA(insert ( 25 1114 2022 f ));
DATA(insert ( 25 1184 1191 f ));
DATA(insert ( 25 1186 1263 f ));
DATA(insert ( 25 1266 938 f ));
DATA(insert ( 26 25 114 f ));
DATA(insert ( 601 600 1532 f ));
DATA(insert ( 602 600 1533 f ));
DATA(insert ( 602 604 1449 f ));
DATA(insert ( 603 600 1534 f ));
DATA(insert ( 603 601 1541 f ));
DATA(insert ( 603 604 1448 f ));
DATA(insert ( 603 718 1479 f ));
DATA(insert ( 604 600 1540 f ));
DATA(insert ( 604 602 1447 f ));
DATA(insert ( 604 603 1446 f ));
DATA(insert ( 604 718 1474 f ));
DATA(insert ( 700 21 238 f ));
DATA(insert ( 700 23 319 f ));
DATA(insert ( 700 25 841 t ));
DATA(insert ( 700 701 311 t ));
DATA(insert ( 700 1700 1742 t ));
DATA(insert ( 701 20 483 f ));
DATA(insert ( 701 21 237 f ));
DATA(insert ( 701 23 317 f ));
DATA(insert ( 701 25 840 t ));
DATA(insert ( 701 700 312 t ));
DATA(insert ( 701 1700 1743 t ));
DATA(insert ( 702 1082 1179 f ));
DATA(insert ( 702 1083 1364 f ));
DATA(insert ( 702 1114 2023 t ));
DATA(insert ( 702 1184 1173 t ));
DATA(insert ( 703 1186 1177 t ));
DATA(insert ( 718 600 1416 f ));
DATA(insert ( 718 603 1480 f ));
DATA(insert ( 718 604 1544 f ));
DATA(insert ( 829 25 752 f ));
DATA(insert ( 869 25 730 f ));
DATA(insert ( 1042 19 409 t ));
DATA(insert ( 1043 19 1400 t ));
DATA(insert ( 1082 25 749 t ));
DATA(insert ( 1082 1114 2024 t ));
DATA(insert ( 1082 1184 1174 t ));
DATA(insert ( 1083 25 948 t ));
DATA(insert ( 1083 1186 1370 t ));
DATA(insert ( 1083 1266 2047 t ));
DATA(insert ( 1114 25 2034 t ));
DATA(insert ( 1114 702 2030 f ));
DATA(insert ( 1114 1082 2029 f ));
DATA(insert ( 1114 1083 1316 f ));
DATA(insert ( 1114 1184 2028 t ));
DATA(insert ( 1184 25 1192 t ));
DATA(insert ( 1184 702 1180 f ));
DATA(insert ( 1184 1082 1178 f ));
DATA(insert ( 1184 1083 2019 f ));
DATA(insert ( 1184 1114 2027 t ));
DATA(insert ( 1184 1266 1388 f ));
DATA(insert ( 1186 25 1193 t ));
DATA(insert ( 1186 703 1194 f ));
DATA(insert ( 1186 1083 1419 f ));
DATA(insert ( 1266 25 939 t ));
DATA(insert ( 1266 1083 2046 t ));
DATA(insert ( 1700 20 1779 f ));
DATA(insert ( 1700 21 1783 f ));
DATA(insert ( 1700 23 1744 f ));
DATA(insert ( 1700 700 1745 f ));
DATA(insert ( 1700 701 1746 f ));
#endif /* PG_CAST_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: pg_proc.h,v 1.243 2002/06/20 20:29:44 momjian Exp $
* $Id: pg_proc.h,v 1.244 2002/07/18 23:11:30 petere Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
@ -45,7 +45,7 @@ CATALOG(pg_proc) BOOTSTRAP
Oid prolang; /* OID of pg_language entry */
bool proisagg; /* is it an aggregate? */
bool prosecdef; /* security definer */
bool proimplicit; /* can be invoked as implicit coercion? */
bool proimplicit; /* unused */
bool proisstrict; /* strict with respect to NULLs? */
bool proretset; /* returns a set? */
char provolatile; /* see PROVOLATILE_ categories below */
@ -3007,7 +3007,6 @@ extern Oid ProcedureCreate(const char *procedureName,
const char *probin,
bool isAgg,
bool security_definer,
bool isImplicit,
bool isStrict,
char volatility,
int32 byte_pct,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: defrem.h,v 1.41 2002/07/12 18:43:19 tgl Exp $
* $Id: defrem.h,v 1.42 2002/07/18 23:11:32 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -42,6 +42,9 @@ extern void ReindexDatabase(const char *databaseName, bool force, bool all);
extern void CreateFunction(CreateFunctionStmt *stmt);
extern void RemoveFunction(RemoveFuncStmt *stmt);
extern void RemoveFunctionById(Oid funcOid);
extern void CreateCast(CreateCastStmt *stmt);
extern void DropCast(DropCastStmt *stmt);
extern void DropCastById(Oid castOid);
extern void DefineOperator(List *names, List *parameters);
extern void RemoveOperator(RemoveOperStmt *stmt);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: nodes.h,v 1.112 2002/07/18 17:14:20 momjian Exp $
* $Id: nodes.h,v 1.113 2002/07/18 23:11:32 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -199,6 +199,8 @@ typedef enum NodeTag
T_AlterDatabaseSetStmt,
T_AlterUserSetStmt,
T_CreateConversionStmt,
T_CreateCastStmt,
T_DropCastStmt,
T_A_Expr = 700,
T_ColumnRef,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parsenodes.h,v 1.192 2002/07/18 17:14:20 momjian Exp $
* $Id: parsenodes.h,v 1.193 2002/07/18 23:11:32 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -1555,4 +1555,30 @@ typedef struct CreateConversionStmt
bool def; /* is this a default conversion? */
} CreateConversionStmt;
/* ----------------------
* CREATE CAST Statement
* ----------------------
*/
typedef struct CreateCastStmt
{
NodeTag type;
TypeName *sourcetype;
TypeName *targettype;
FuncWithArgs *func;
bool implicit;
} CreateCastStmt;
/* ----------------------
* DROP CAST Statement
* ----------------------
*/
typedef struct DropCastStmt
{
NodeTag type;
TypeName *sourcetype;
TypeName *targettype;
DropBehavior behavior;
} DropCastStmt;
#endif /* PARSENODES_H */

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: syscache.h,v 1.49 2002/07/11 07:39:28 ishii Exp $
* $Id: syscache.h,v 1.50 2002/07/18 23:11:32 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -36,29 +36,30 @@
#define AMPROCNUM 5
#define ATTNAME 6
#define ATTNUM 7
#define CLAAMNAMENSP 8
#define CLAOID 9
#define CONNAMESP 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 OPERNAMENSP 19
#define OPEROID 20
#define PROCNAMENSP 21
#define PROCOID 22
#define RELNAMENSP 23
#define RELOID 24
#define RULERELNAME 25
#define SHADOWNAME 26
#define SHADOWSYSID 27
#define STATRELATT 28
#define TYPENAMENSP 29
#define TYPEOID 30
#define CASTSOURCETARGET 8
#define CLAAMNAMENSP 9
#define CLAOID 10
#define CONNAMESP 11
#define GRONAME 12
#define GROSYSID 13
#define INDEXRELID 14
#define INHRELID 15
#define LANGNAME 16
#define LANGOID 17
#define NAMESPACENAME 18
#define NAMESPACEOID 19
#define OPERNAMENSP 20
#define OPEROID 21
#define PROCNAMENSP 22
#define PROCOID 23
#define RELNAMENSP 24
#define RELOID 25
#define RULERELNAME 26
#define SHADOWNAME 27
#define SHADOWSYSID 28
#define STATRELATT 29
#define TYPENAMENSP 30
#define TYPEOID 31
extern void InitCatalogCache(void);
extern void InitCatalogCachePhase2(void);

View File

@ -1,7 +1,7 @@
--
-- OPR_SANITY
-- Sanity checks for common errors in making operator/procedure system tables:
-- pg_operator, pg_proc, pg_aggregate, pg_am, pg_amop, pg_amproc, pg_opclass.
-- pg_operator, pg_proc, pg_cast, pg_aggregate, pg_am, pg_amop, pg_amproc, pg_opclass.
--
-- None of the SELECTs here should ever find any matching entries,
-- so the expected output is easy to maintain ;-).
@ -180,20 +180,49 @@ WHERE p1.oid != p2.oid AND
-------------+-------------
(0 rows)
-- If a proc is marked as an implicit cast, then it should be something that
-- the system might actually use as a cast function: name same as the name
-- of its output type, and either one arg that's a different type, or two
-- args where the first is the same as the output type and the second is int4.
SELECT p1.oid, p1.proname
FROM pg_proc as p1
WHERE p1.proimplicit AND
(NOT EXISTS (SELECT 1 FROM pg_type t WHERE t.oid = p1.prorettype AND
t.typname = p1.proname) OR
NOT ((p1.pronargs = 1 AND p1.proargtypes[0] != prorettype) OR
(p1.pronargs = 2 AND p1.proargtypes[0] = prorettype AND
p1.proargtypes[1] = 'int4'::regtype)));
oid | proname
-----+---------
-- **************** pg_cast ****************
-- Look for casts from and to the same type. This is not harmful, but
-- useless.
SELECT *
FROM pg_cast c
WHERE c.castsource = c.casttarget;
castsource | casttarget | castfunc | castimplicit
------------+------------+----------+--------------
(0 rows)
-- Look for cast functions with incorrect number or type of argument
-- or return value.
SELECT c.*
FROM pg_cast c, pg_proc p
WHERE c.castfunc = p.oid AND
(p.pronargs <> 1 OR
p.proargtypes[0] <> c.castsource OR
p.prorettype <> c.casttarget);
castsource | casttarget | castfunc | castimplicit
------------+------------+----------+--------------
(0 rows)
-- Look for binary compatible casts that are not implicit. This is
-- legal, but probably not intended.
SELECT *
FROM pg_cast c
WHERE c.castfunc = 0 AND NOT c.castimplicit;
castsource | casttarget | castfunc | castimplicit
------------+------------+----------+--------------
(0 rows)
-- Look for binary compatible casts that do not have the reverse
-- direction registered as well, or where the reverse direction is not
-- also binary compatible. This is legal, but probably not intended.
SELECT *
FROM pg_cast c
WHERE c.castfunc = 0 AND
NOT EXISTS (SELECT * FROM pg_cast k
WHERE k.castfunc = 0 AND
k.castsource = c.casttarget AND
k.casttarget = c.castsource);
castsource | casttarget | castfunc | castimplicit
------------+------------+----------+--------------
(0 rows)
-- **************** pg_operator ****************

View File

@ -37,6 +37,7 @@ SELECT relname, relhasindex
pg_amproc | t
pg_attrdef | t
pg_attribute | t
pg_cast | t
pg_class | t
pg_constraint | t
pg_conversion | t
@ -62,5 +63,5 @@ SELECT relname, relhasindex
shighway | t
tenk1 | t
tenk2 | t
(52 rows)
(53 rows)

View File

@ -1,7 +1,7 @@
--
-- OPR_SANITY
-- Sanity checks for common errors in making operator/procedure system tables:
-- pg_operator, pg_proc, pg_aggregate, pg_am, pg_amop, pg_amproc, pg_opclass.
-- pg_operator, pg_proc, pg_cast, pg_aggregate, pg_am, pg_amop, pg_amproc, pg_opclass.
--
-- None of the SELECTs here should ever find any matching entries,
-- so the expected output is easy to maintain ;-).
@ -141,19 +141,43 @@ WHERE p1.oid != p2.oid AND
NOT p1.proisagg AND NOT p2.proisagg AND
(p1.proargtypes[7] < p2.proargtypes[7]);
-- If a proc is marked as an implicit cast, then it should be something that
-- the system might actually use as a cast function: name same as the name
-- of its output type, and either one arg that's a different type, or two
-- args where the first is the same as the output type and the second is int4.
-- **************** pg_cast ****************
SELECT p1.oid, p1.proname
FROM pg_proc as p1
WHERE p1.proimplicit AND
(NOT EXISTS (SELECT 1 FROM pg_type t WHERE t.oid = p1.prorettype AND
t.typname = p1.proname) OR
NOT ((p1.pronargs = 1 AND p1.proargtypes[0] != prorettype) OR
(p1.pronargs = 2 AND p1.proargtypes[0] = prorettype AND
p1.proargtypes[1] = 'int4'::regtype)));
-- Look for casts from and to the same type. This is not harmful, but
-- useless.
SELECT *
FROM pg_cast c
WHERE c.castsource = c.casttarget;
-- Look for cast functions with incorrect number or type of argument
-- or return value.
SELECT c.*
FROM pg_cast c, pg_proc p
WHERE c.castfunc = p.oid AND
(p.pronargs <> 1 OR
p.proargtypes[0] <> c.castsource OR
p.prorettype <> c.casttarget);
-- Look for binary compatible casts that are not implicit. This is
-- legal, but probably not intended.
SELECT *
FROM pg_cast c
WHERE c.castfunc = 0 AND NOT c.castimplicit;
-- Look for binary compatible casts that do not have the reverse
-- direction registered as well, or where the reverse direction is not
-- also binary compatible. This is legal, but probably not intended.
SELECT *
FROM pg_cast c
WHERE c.castfunc = 0 AND
NOT EXISTS (SELECT * FROM pg_cast k
WHERE k.castfunc = 0 AND
k.castsource = c.casttarget AND
k.casttarget = c.castsource);
-- **************** pg_operator ****************