<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
- $Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.59 2002/09/03 01:04:40 tgl Exp $
+ $Header: /cvsroot/pgsql/doc/src/sgml/catalogs.sgml,v 2.60 2002/09/18 21:35:20 tgl Exp $
-->
<chapter id="catalogs">
<title>pg_cast</title>
<para>
- <structname>pg_cast</structname> stores data type conversion paths
- defined with <command>CREATE CAST</command> plus the built-in
- conversions.
+ <structname>pg_cast</structname> stores data type conversion paths,
+ both built-in paths and those defined with <command>CREATE CAST</command>.
</para>
<table>
<entry><type>oid</type></entry>
<entry>pg_proc.oid</entry>
<entry>
- The OID of the function to use to perform this cast. A 0 is
- stored if the data types are binary compatible (that is, no
- function is needed to perform the cast).
+ The OID of the function to use to perform this cast. Zero is
+ stored if the data types are binary coercible (that is, no
+ run-time operation is needed to perform the cast).
</entry>
</row>
<row>
- <entry>castimplicit</entry>
- <entry><type>bool</type></entry>
+ <entry>castcontext</entry>
+ <entry><type>char</type></entry>
<entry></entry>
- <entry>Indication whether this cast can be invoked implicitly</entry>
+ <entry>
+ Indicates what contexts the cast may be invoked in.
+ <literal>e</> means only as an explicit cast (using
+ <literal>CAST</>, <literal>::</>, or function-call syntax).
+ <literal>a</> means implicitly in assignment
+ to a target column, as well as explicitly.
+ <literal>i</> means implicitly in expressions, as well as the
+ other cases.
+ </entry>
</row>
</tbody>
</tgroup>
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.102 2002/08/23 02:54:18 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/datatype.sgml,v 1.103 2002/09/18 21:35:20 tgl Exp $
-->
<chapter id="datatype">
<note>
<para>
- Prior to <productname>PostgreSQL</> 7.2, strings that were too long were silently
- truncated, no error was raised.
+ If one explicitly casts a value to
+ <type>character(<replaceable>n</>)</type> or <type>character
+ varying(<replaceable>n</>)</type>, then an overlength value will
+ be truncated to <replaceable>n</> characters without raising an
+ error. (This too is required by the SQL standard.)
+ </para>
+ </note>
+
+ <note>
+ <para>
+ Prior to <productname>PostgreSQL</> 7.2, strings that were too long were
+ always truncated without raising an error, in either explicit or
+ implicit casting contexts.
</para>
</note>
INSERT INTO test2 VALUES ('good ');
INSERT INTO test2 VALUES ('too long');
<computeroutput>ERROR: value too long for type character varying(5)</computeroutput>
+INSERT INTO test2 VALUES ('too long'::varchar(5)); -- explicit truncation
SELECT b, char_length(b) FROM test2;
<computeroutput>
b | char_length
-------+-------------
ok | 2
good | 5
+ too l | 5
</computeroutput>
</programlisting>
<calloutlist>
</para>
<table tocentry="1">
- <title>Specialty Character Type</title>
+ <title>Specialty Character Types</title>
<tgroup cols="3">
<thead>
<row>
<para>
Bit strings are strings of 1's and 0's. They can be used to store
or visualize bit masks. There are two SQL bit types:
- <type>BIT(<replaceable>x</replaceable>)</type> and <type>BIT
- VARYING(<replaceable>x</replaceable>)</type>; where
- <replaceable>x</replaceable> is a positive integer.
+ <type>BIT(<replaceable>n</replaceable>)</type> and <type>BIT
+ VARYING(<replaceable>n</replaceable>)</type>, where
+ <replaceable>n</replaceable> is a positive integer.
</para>
<para>
<type>BIT</type> type data must match the length
- <replaceable>x</replaceable> exactly; it is an error to attempt to
- store shorter or longer bit strings. <type>BIT VARYING</type> is
+ <replaceable>n</replaceable> exactly; it is an error to attempt to
+ store shorter or longer bit strings. <type>BIT VARYING</type> data is
of variable length up to the maximum length
- <replaceable>x</replaceable>; longer strings will be rejected.
- <type>BIT</type> without length is equivalent to
- <literal>BIT(1)</literal>, <type>BIT VARYING</type> without length
+ <replaceable>n</replaceable>; longer strings will be rejected.
+ Writing <type>BIT</type> without a length is equivalent to
+ <literal>BIT(1)</literal>, while <type>BIT VARYING</type> without a length
specification means unlimited length.
</para>
<note>
<para>
- Prior to <productname>PostgreSQL</> 7.2, <type>BIT</type> type data was
- zero-padded on the right. This was changed to comply with the
- SQL standard. To implement zero-padded bit strings, a
- combination of the concatenation operator and the
- <function>substring</function> function can be used.
+ If one explicitly casts a bit-string value to
+ <type>BIT(<replaceable>n</>)</type>, it will be truncated or
+ zero-padded on the right to be exactly <replaceable>n</> bits,
+ without raising an error. Similarly,
+ if one explicitly casts a bit-string value to
+ <type>BIT VARYING(<replaceable>n</>)</type>, it will be truncated
+ on the right if it is more than <replaceable>n</> bits.
+ </para>
+ </note>
+
+ <note>
+ <para>
+ Prior to <productname>PostgreSQL</> 7.2, <type>BIT</type> data was
+ always silently truncated or zero-padded on the right, with or without an
+ explicit cast. This was changed to comply with the SQL standard.
</para>
</note>
INSERT INTO test VALUES (B'101', B'00');
INSERT INTO test VALUES (B'10', B'101');
<computeroutput>
-ERROR: bit string length does not match type bit(3)
+ERROR: Bit string length 2 does not match type BIT(3)
+</computeroutput>
+INSERT INTO test VALUES (B'10'::bit(3), B'101');
+SELECT * FROM test;
+<computeroutput>
+ a | b
+-----+-----
+ 101 | 00
+ 100 | 101
</computeroutput>
-SELECT SUBSTRING(b FROM 1 FOR 2) FROM test;
</programlisting>
</example>
-<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/create_cast.sgml,v 1.4 2002/09/15 13:04:16 petere Exp $ -->
+<!-- $Header: /cvsroot/pgsql/doc/src/sgml/ref/create_cast.sgml,v 1.5 2002/09/18 21:35:20 tgl Exp $ -->
<refentry id="SQL-CREATECAST">
<refmeta>
<synopsis>
CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
WITH FUNCTION <replaceable>funcname</replaceable> (<replaceable>argtype</replaceable>)
- [AS ASSIGNMENT]
+ [ AS ASSIGNMENT | AS IMPLICIT ]
CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
WITHOUT FUNCTION
- [AS ASSIGNMENT]
+ [ AS ASSIGNMENT | AS IMPLICIT ]
</synopsis>
</refsynopsisdiv>
</para>
<para>
- A cast can be 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</>,
+ By default, a cast can be invoked only by an explicit cast request,
+ that is an explicit <literal>CAST(<replaceable>x</> AS
+ <replaceable>typename</>)</literal>,
<replaceable>x</><literal>::</><replaceable>typename</>, or
- <replaceable>typename</>(<replaceable>x</>) constructs. For
- example, supposing that <literal>foo.f1</literal> is a column of
+ <replaceable>typename</>(<replaceable>x</>) construct.
+ </para>
+
+ <para>
+ If the cast is marked <literal>AS ASSIGNMENT</> then it can be invoked
+ implicitly when assigning to a column of the target data type.
+ 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
+ not.
+ (We generally use the term <firstterm>assignment
+ cast</firstterm> to describe this kind of cast.)
+ </para>
+
+ <para>
+ If the cast is marked <literal>AS IMPLICIT</> then it can be invoked
+ implicitly in any context, whether assignment or internally in an
+ expression. For example, since <literal>||</> takes <type>text</>
+ arguments,
+<programlisting>
+SELECT 'The time is ' || now();
+</programlisting>
+ will be allowed only if the cast from type <type>timestamp</> to
+ <type>text</type> is marked <literal>AS IMPLICIT</>. Otherwise it
+ will be necessary to write one of
+<programlisting>
+SELECT 'The time is ' || CAST(now() AS text);
+SELECT 'The time is ' || now()::text;
+</programlisting>
+ (We generally use the term <firstterm>implicit
cast</firstterm> to describe this kind of cast.)
</para>
all because there are multiple possible interpretations. A good
rule of thumb is to make a 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.
+ general type category. For example, the cast from <type>int2</type> to
+ <type>int4</type> can reasonably be implicit, but the cast from
+ <type>float8</type> to <type>int4</type> should probably be
+ assignment-only. Cross-type-category casts, such as <type>text</>
+ to <type>int4</>, are best made explicit-only.
</para>
<para>
<listitem>
<para>
- Indicates that the cast may be invoked implicitly.
+ Indicates that the cast may be invoked implicitly in assignment
+ contexts.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>AS IMPLICIT</literal></term>
+
+ <listitem>
+ <para>
+ Indicates that the cast may be invoked implicitly in any context.
</para>
</listitem>
</varlistentry>
data type, returned that data type, and took one argument of a
different type was automatically a cast function. This convention has
been abandoned in face of the introduction of schemas and to be
- able to represent binary compatible casts in the catalogs. The built-in
+ able to represent binary compatible casts in the catalogs. (The built-in
cast functions
- still follow this naming scheme, but they have to be declared as
- casts explicitly now.
+ still follow this naming scheme, but they have to be shown as
+ casts in <literal>pg_cast</> now.)
</para>
</refsect1>
<para>
The <command>CREATE CAST</command> command conforms to SQL99,
except that SQL99 does not make provisions for binary compatible
- types.
+ types. <literal>AS IMPLICIT</> is a <productname>PostgreSQL</productname>
+ extension, too.
</para>
</refsect1>
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.158 2002/09/04 07:16:32 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.159 2002/09/18 21:35:20 tgl Exp $
-->
<appendix id="release">
worries about funny characters.
-->
<literallayout><![CDATA[
+Mixed numeric-and-float expressions are evaluated as float, per SQL spec
+Explicit casts to char, varchar, bit, varbit will truncate or pad without error
CREATE OR REPLACE VIEW, CREATE OR REPLACE RULE are available
No-autocommit mode is available (set autocommit to off)
Substantial improvements in functionality for functions returning sets
<step performance="required">
<para>
-If one or more non-unknown inputs are of a preferred type in that category,
-resolve as that type.
-</para></step>
-
-<step performance="required">
-<para>
-Otherwise, resolve as the type of the first non-unknown input.
+Choose the first non-unknown input type which is a preferred type in
+that category or allows all the non-unknown inputs to be implicitly
+coerced to it.
</para></step>
<step performance="required">
<para>
<screen>
-tgl=> SELECT 1.2 AS "Double" UNION SELECT 1;
- Double
---------
- 1
- 1.2
+tgl=> SELECT 1.2 AS "Numeric" UNION SELECT 1;
+ Numeric
+---------
+ 1
+ 1.2
(2 rows)
</screen>
-The literal <literal>1.2</> is of type <type>double precision</>,
-the preferred type in the numeric category, so that type is used.
+The literal <literal>1.2</> is of type <type>numeric</>,
+and the integer value <literal>1</> can be cast implicitly to
+<type>numeric</>, so that type is used.
</para>
</example>
<title>Type Conversion in a Transposed Union</title>
<para>
-Here the output type of the union is forced to match the type of
-the first clause in the union:
-
<screen>
-tgl=> SELECT 1 AS "All integers"
+tgl=> SELECT 1 AS "Real"
tgl-> UNION SELECT CAST('2.2' AS REAL);
- All integers
---------------
- 1
- 2
+ Real
+------
+ 1
+ 2.2
(2 rows)
</screen>
-</para>
-<para>
-Since <type>REAL</type> is not a preferred type, the parser sees no reason
-to select it over <type>INTEGER</type> (which is what the 1 is), and instead
-falls back on the use-the-first-alternative rule.
-This example demonstrates that the preferred-type mechanism doesn't encode
-as much information as we'd like. Future versions of
-<productname>PostgreSQL</productname> may support a more general notion of
-type preferences.
+Here, since type <type>real</> cannot be implicitly cast to <type>integer</>,
+but <type>integer</> can be implicitly cast to <type>real</>, the union
+result type is resolved as <type>real</>.
</para>
</example>
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.226 2002/09/14 22:14:49 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.227 2002/09/18 21:35:20 tgl Exp $
*
*
* INTERFACE ROUTINES
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "parser/parse_relation.h"
-#include "parser/parse_target.h"
#include "rewrite/rewriteRemove.h"
#include "storage/smgr.h"
#include "utils/builtins.h"
{
Oid type_id = exprType(expr);
- if (type_id != atttypid)
- {
- if (CoerceTargetExpr(pstate, expr, type_id,
- 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",
- attname,
- format_type_be(atttypid),
- format_type_be(type_id));
- }
+ if (coerce_to_target_type(expr, type_id,
+ atttypid, atttypmod,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST) == 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",
+ attname,
+ format_type_be(atttypid),
+ format_type_be(type_id));
}
/*
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.55 2002/09/04 20:31:14 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.56 2002/09/18 21:35:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
if (proc->proisstrict && agginitval == NULL)
{
- if (!IsBinaryCompatible(aggBaseType, aggTransType))
+ if (!IsBinaryCoercible(aggBaseType, aggTransType))
elog(ERROR, "must not omit initval when transfn is strict and transtype is not compatible with input type");
}
ReleaseSysCache(tup);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.93 2002/09/04 20:31:14 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.94 2002/09/18 21:35:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
format_type_be(rettype));
restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
- if (!IsBinaryCompatible(restype, rettype))
+ if (!IsBinaryCoercible(restype, rettype))
elog(ERROR, "return type mismatch in function: declared to return %s, returns %s",
format_type_be(rettype), format_type_be(restype));
}
if (tlistlen == 1)
{
restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
- if (IsBinaryCompatible(restype, rettype))
+ if (IsBinaryCoercible(restype, rettype))
return;
}
tletype = exprType(tle->expr);
atttype = attr->atttypid;
- if (!IsBinaryCompatible(tletype, atttype))
+ if (!IsBinaryCoercible(tletype, atttype))
elog(ERROR, "function declared to return %s returns %s instead of %s at column %d",
format_type_be(rettype),
format_type_be(tletype),
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.20 2002/09/15 13:04:16 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.21 2002/09/18 21:35:20 tgl Exp $
*
* DESCRIPTION
* These routines take the parse tree and pick out the
Oid sourcetypeid;
Oid targettypeid;
Oid funcid;
- HeapTuple tuple;
+ char castcontext;
Relation relation;
- Form_pg_proc procstruct;
-
- Datum values[Natts_pg_proc];
- char nulls[Natts_pg_proc];
- int i;
-
+ HeapTuple tuple;
+ Datum values[Natts_pg_cast];
+ char nulls[Natts_pg_cast];
ObjectAddress myself,
referenced;
TypeNameToString(stmt->sourcetype),
TypeNameToString(stmt->targettype));
- 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)
{
+ Form_pg_proc procstruct;
+
funcid = LookupFuncNameTypeNames(stmt->func->funcname,
stmt->func->funcargs,
"CreateCast");
- tuple = SearchSysCache(PROCOID, ObjectIdGetDatum(funcid), 0, 0, 0);
+ tuple = SearchSysCache(PROCOID,
+ ObjectIdGetDatum(funcid),
+ 0, 0, 0);
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup of function %u failed", funcid);
}
else
{
- /* indicates binary compatibility */
+ /* indicates binary coercibility */
funcid = InvalidOid;
}
+ /* convert CoercionContext enum to char value for castcontext */
+ switch (stmt->context)
+ {
+ case COERCION_IMPLICIT:
+ castcontext = COERCION_CODE_IMPLICIT;
+ break;
+ case COERCION_ASSIGNMENT:
+ castcontext = COERCION_CODE_ASSIGNMENT;
+ break;
+ case COERCION_EXPLICIT:
+ castcontext = COERCION_CODE_EXPLICIT;
+ break;
+ default:
+ elog(ERROR, "CreateCast: bogus CoercionContext %c", stmt->context);
+ castcontext = 0; /* keep compiler quiet */
+ break;
+ }
+
+ relation = heap_openr(CastRelationName, RowExclusiveLock);
+
+ /*
+ * Check for duplicate. This is just to give a friendly error message,
+ * the unique index would catch it anyway (so no need to sweat about
+ * race conditions).
+ */
+ 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));
+
/* 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);
+ values[Anum_pg_cast_castcontext - 1] = CharGetDatum(castcontext);
- for (i = 0; i < Natts_pg_cast; ++i)
- nulls[i] = ' ';
+ MemSet(nulls, ' ', Natts_pg_cast);
tuple = heap_formtuple(RelationGetDescr(relation), values, nulls);
CatalogUpdateIndexes(relation, tuple);
+ /* make dependency entries */
myself.classId = RelationGetRelid(relation);
myself.objectId = HeapTupleGetOid(tuple);
myself.objectSubId = 0;
}
heap_freetuple(tuple);
+
heap_close(relation, RowExclusiveLock);
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.87 2002/09/04 20:31:15 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/indexcmds.c,v 1.88 2002/09/18 21:35:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
for (i = 0; i < nargs; i++)
{
- if (!IsBinaryCompatible(argTypes[i], true_typeids[i]))
- func_error("DefineIndex", funcIndex->funcname, nargs, argTypes,
+ if (!IsBinaryCoercible(argTypes[i], true_typeids[i]))
+ func_error("DefineIndex", funcIndex->funcname, nargs, true_typeids,
"Index function must be binary-compatible with table datatype");
}
opClassId = HeapTupleGetOid(tuple);
opInputType = ((Form_pg_opclass) GETSTRUCT(tuple))->opcintype;
- if (!IsBinaryCompatible(attrType, opInputType))
+ if (!IsBinaryCoercible(attrType, opInputType))
elog(ERROR, "operator class \"%s\" does not accept data type %s",
NameListToString(attribute->opclass), format_type_be(attrType));
nexact++;
exactOid = opclass->oid;
}
- else if (IsBinaryCompatible(opclass->opcintype, attrType))
+ else if (IsBinaryCoercible(attrType, opclass->opcintype))
{
ncompatible++;
compatibleOid = opclass->oid;
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.86 2002/09/04 20:31:18 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.87 2002/09/18 21:35:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
Oid inputType = exprType(aggref->target);
- if (!IsBinaryCompatible(inputType, aggform->aggtranstype))
+ if (!IsBinaryCoercible(inputType, aggform->aggtranstype))
elog(ERROR, "Aggregate %u needs to have compatible input type and transition type",
aggref->aggfnoid);
}
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.211 2002/09/04 20:31:19 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.212 2002/09/18 21:35:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
newnode->funcid = from->funcid;
newnode->funcresulttype = from->funcresulttype;
newnode->funcretset = from->funcretset;
+ newnode->funcformat = from->funcformat;
/* Do not copy the run-time state, if any */
newnode->func_fcache = NULL;
Node_Copy(from, newnode, arg);
newnode->resulttype = from->resulttype;
newnode->resulttypmod = from->resulttypmod;
+ newnode->relabelformat = from->relabelformat;
return newnode;
}
Node_Copy(from, newnode, sourcetype);
Node_Copy(from, newnode, targettype);
Node_Copy(from, newnode, func);
- newnode->implicit = from->implicit;
+ newnode->context = from->context;
return newnode;
}
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.158 2002/09/02 02:13:01 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.159 2002/09/18 21:35:20 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return false;
if (a->funcretset != b->funcretset)
return false;
+ /*
+ * Special-case COERCE_DONTCARE, so that pathkeys can build coercion
+ * nodes that are equal() to both explicit and implicit coercions.
+ */
+ if (a->funcformat != b->funcformat &&
+ a->funcformat != COERCE_DONTCARE &&
+ b->funcformat != COERCE_DONTCARE)
+ return false;
+
/* Note we do not look at func_fcache; see notes for _equalOper */
return true;
return false;
if (a->resulttypmod != b->resulttypmod)
return false;
+ /*
+ * Special-case COERCE_DONTCARE, so that pathkeys can build coercion
+ * nodes that are equal() to both explicit and implicit coercions.
+ */
+ if (a->relabelformat != b->relabelformat &&
+ a->relabelformat != COERCE_DONTCARE &&
+ b->relabelformat != COERCE_DONTCARE)
+ return false;
return true;
}
return false;
if (!equal(a->func, b->func))
return false;
- if (a->implicit != b->implicit)
+ if (a->context != b->context)
return false;
return true;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.34 2002/09/04 20:31:19 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.35 2002/09/18 21:35:21 tgl Exp $
*/
#include "postgres.h"
* creates a RelabelType node
*/
RelabelType *
-makeRelabelType(Node *arg, Oid rtype, int32 rtypmod)
+makeRelabelType(Node *arg, Oid rtype, int32 rtypmod, CoercionForm rformat)
{
RelabelType *r = makeNode(RelabelType);
r->arg = arg;
r->resulttype = rtype;
r->resulttypmod = rtypmod;
+ r->relabelformat = rformat;
return r;
}
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.173 2002/09/04 20:31:19 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.174 2002/09/18 21:35:21 tgl Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
_outFunc(StringInfo str, Func *node)
{
appendStringInfo(str,
- " FUNC :funcid %u :funcresulttype %u :funcretset %s ",
+ " FUNC :funcid %u :funcresulttype %u :funcretset %s :funcformat %d ",
node->funcid,
node->funcresulttype,
- booltostr(node->funcretset));
+ booltostr(node->funcretset),
+ (int) node->funcformat);
}
/*
{
appendStringInfo(str, " RELABELTYPE :arg ");
_outNode(str, node->arg);
-
- appendStringInfo(str, " :resulttype %u :resulttypmod %d ",
- node->resulttype, node->resulttypmod);
+ appendStringInfo(str,
+ " :resulttype %u :resulttypmod %d :relabelformat %d ",
+ node->resulttype,
+ node->resulttypmod,
+ (int) node->relabelformat);
}
/*
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.132 2002/09/04 20:31:20 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.133 2002/09/18 21:35:21 tgl Exp $
*
* NOTES
* Most of the read functions for plan nodes are tested. (In fact, they
token = pg_strtok(&length); /* now read it */
local_node->funcretset = strtobool(token);
+ token = pg_strtok(&length); /* get :funcformat */
+ token = pg_strtok(&length); /* now read it */
+ local_node->funcformat = (CoercionForm) atoi(token);
+
local_node->func_fcache = NULL;
return local_node;
token = pg_strtok(&length); /* get resulttypmod */
local_node->resulttypmod = atoi(token);
+ token = pg_strtok(&length); /* eat :relabelformat */
+ token = pg_strtok(&length); /* get relabelformat */
+ local_node->relabelformat = (CoercionForm) atoi(token);
+
return local_node;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.122 2002/09/04 20:31:20 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.123 2002/09/18 21:35:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* is whether the operator has a commutator operator that matches
* the index's opclass.
*
- * We try both the straightforward match and matches that rely on
- * recognizing binary-compatible datatypes. For example, if we have
- * an expression like "oid = 123", the operator will be oideqint4,
- * which we need to replace with oideq in order to recognize it as
- * matching an oid_ops index on the oid field. A variant case is where
- * the expression is like "oid::int4 = 123", where the given operator
- * will be int4eq and again we need to intuit that we want to use oideq.
- *
* Returns the OID of the matching operator, or InvalidOid if no match.
- * Note that the returned OID will be different from the one in the given
- * expression if we used a binary-compatible substitution. Also note that
- * if indexkey_on_left is FALSE (meaning we need to commute), the returned
- * OID is *not* commuted; it can be plugged directly into the given clause.
+ * (Formerly, this routine might return a binary-compatible operator
+ * rather than the original one, but that kluge is history.)
*/
Oid
indexable_operator(Expr *clause, Oid opclass, bool indexkey_on_left)
{
Oid expr_op = ((Oper *) clause->oper)->opno;
- Oid commuted_op,
- new_op;
- Operator oldoptup;
- Form_pg_operator oldopform;
- char *opname;
- Oid ltype,
- rtype,
- indexkeytype;
+ Oid commuted_op;
/* Get the commuted operator if necessary */
if (indexkey_on_left)
if (commuted_op == InvalidOid)
return InvalidOid;
- /* Done if the (commuted) operator is a member of the index's opclass */
+ /* OK if the (commuted) operator is a member of the index's opclass */
if (op_in_opclass(commuted_op, opclass))
return expr_op;
- /*
- * Maybe the index uses a binary-compatible operator set.
- *
- * Get the nominal input types of the given operator and the actual type
- * (before binary-compatible relabeling) of the index key.
- */
- oldoptup = SearchSysCache(OPEROID,
- ObjectIdGetDatum(expr_op),
- 0, 0, 0);
- if (!HeapTupleIsValid(oldoptup))
- return InvalidOid; /* probably can't happen */
- oldopform = (Form_pg_operator) GETSTRUCT(oldoptup);
- opname = pstrdup(NameStr(oldopform->oprname));
- ltype = oldopform->oprleft;
- rtype = oldopform->oprright;
- ReleaseSysCache(oldoptup);
-
- if (indexkey_on_left)
- {
- Node *leftop = (Node *) get_leftop(clause);
-
- if (leftop && IsA(leftop, RelabelType))
- leftop = ((RelabelType *) leftop)->arg;
- indexkeytype = exprType(leftop);
- }
- else
- {
- Node *rightop = (Node *) get_rightop(clause);
-
- if (rightop && IsA(rightop, RelabelType))
- rightop = ((RelabelType *) rightop)->arg;
- indexkeytype = exprType(rightop);
- }
-
- /*
- * Make sure we have different but binary-compatible types.
- */
- if (ltype == indexkeytype && rtype == indexkeytype)
- return InvalidOid; /* no chance for a different operator */
- if (!IsBinaryCompatible(ltype, indexkeytype))
- return InvalidOid;
- if (!IsBinaryCompatible(rtype, indexkeytype))
- return InvalidOid;
-
- /*
- * OK, look for operator of the same name with the indexkey's data
- * type. (In theory this might find a non-semantically-comparable
- * operator, but in practice that seems pretty unlikely for
- * binary-compatible types.)
- */
- new_op = compatible_oper_opid(makeList1(makeString(opname)),
- indexkeytype, indexkeytype, true);
-
- if (OidIsValid(new_op))
- {
- if (new_op != expr_op)
- {
- /*
- * OK, we found a binary-compatible operator of the same name;
- * now does it match the index?
- */
- if (indexkey_on_left)
- commuted_op = new_op;
- else
- commuted_op = get_commutator(new_op);
- if (commuted_op == InvalidOid)
- return InvalidOid;
-
- if (op_in_opclass(commuted_op, opclass))
- return new_op;
- }
- }
-
return InvalidOid;
}
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.40 2002/09/04 20:31:20 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.41 2002/09/18 21:35:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
funcnode->funcid = index->indproc;
funcnode->funcresulttype = get_func_rettype(index->indproc);
funcnode->funcretset = false; /* can never be a set */
+ funcnode->funcformat = COERCE_DONTCARE; /* to match any user expr */
funcnode->func_fcache = NULL;
while (*indexkeys != 0)
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.118 2002/09/04 20:31:21 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.119 2002/09/18 21:35:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
Expr *clause = (Expr *) lfirst(i);
Expr *newclause;
List *leftvarnos;
- Oid opclass,
- newopno;
+ Oid opclass;
if (!is_opclause((Node *) clause) || length(clause->args) != 2)
elog(ERROR, "fix_indxqual_sublist: indexqual clause is not binary opclause");
index,
&opclass);
- /*
- * Substitute the appropriate operator if the expression operator
- * is merely binary-compatible with the index. This shouldn't
- * fail, since indxpath.c found it before...
- */
- newopno = indexable_operator(newclause, opclass, true);
- if (newopno == InvalidOid)
- elog(ERROR, "fix_indxqual_sublist: failed to find substitute op");
- ((Oper *) newclause->oper)->opno = newopno;
-
fixed_qual = lappend(fixed_qual, newclause);
/*
* Finally, check to see if index is lossy for this operator. If
* so, add (a copy of) original form of clause to recheck list.
*/
- if (op_requires_recheck(newopno, opclass))
+ if (op_requires_recheck(((Oper *) newclause->oper)->opno, opclass))
recheck_qual = lappend(recheck_qual,
copyObject((Node *) clause));
}
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.56 2002/09/04 20:31:22 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.57 2002/09/18 21:35:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
false, /* not a set */
false);
if (!att_tup->attisdropped)
- new_expr = coerce_type_constraints(NULL, new_expr,
- atttype, false);
+ new_expr = coerce_type_constraints(new_expr,
+ atttype,
+ COERCE_IMPLICIT_CAST);
break;
case CMD_UPDATE:
/* Insert NULLs for dropped columns */
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.79 2002/09/11 14:48:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.80 2002/09/18 21:35:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
}
else
{
- expr = coerce_to_common_type(NULL,
- expr,
+ expr = coerce_to_common_type(expr,
colType,
"UNION/INTERSECT/EXCEPT");
colTypmod = -1;
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.248 2002/09/04 20:31:22 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.249 2002/09/18 21:35:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
given_type_id = exprType(expr);
expected_type_id = (Oid) lfirsti(paramtypes);
- if (given_type_id != expected_type_id)
- {
- expr = CoerceTargetExpr(pstate,
- expr,
- given_type_id,
- expected_type_id,
- -1,
- false);
-
- if (!expr)
- elog(ERROR, "Parameter $%d of type %s cannot be coerced into the expected type %s"
- "\n\tYou will need to rewrite or cast the expression",
- i,
- format_type_be(given_type_id),
- format_type_be(expected_type_id));
- }
+ expr = coerce_to_target_type(expr, given_type_id,
+ expected_type_id, -1,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST);
+
+ if (expr == NULL)
+ elog(ERROR, "Parameter $%d of type %s cannot be coerced into the expected type %s"
+ "\n\tYou will need to rewrite or cast the expression",
+ i,
+ format_type_be(given_type_id),
+ format_type_be(expected_type_id));
fix_opids(expr);
+
lfirst(l) = expr;
paramtypes = lnext(paramtypes);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.366 2002/09/05 22:52:48 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.367 2002/09/18 21:35:21 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
%type <list> createdb_opt_list, copy_opt_list
%type <defelt> createdb_opt_item, copy_opt_item
-%type <ival> opt_lock, lock_type
-%type <boolean> opt_force, opt_or_replace, opt_assignment
+%type <ival> opt_lock, lock_type, cast_context
+%type <boolean> opt_force, opt_or_replace
%type <list> user_list
HANDLER, HAVING, HOUR_P,
- ILIKE, IMMEDIATE, IMMUTABLE, IN_P, INCREMENT,
+ ILIKE, IMMEDIATE, IMMUTABLE, IMPLICIT_P, IN_P, INCREMENT,
INDEX, INHERITS, INITIALLY, INNER_P, INOUT, INPUT,
INSENSITIVE, INSERT, INSTEAD, INT, INTEGER, INTERSECT,
INTERVAL, INTO, INVOKER, IS, ISNULL, ISOLATION,
*****************************************************************************/
CreateCastStmt: CREATE CAST '(' ConstTypename AS ConstTypename ')'
- WITH FUNCTION function_with_argtypes opt_assignment
+ WITH FUNCTION function_with_argtypes cast_context
{
CreateCastStmt *n = makeNode(CreateCastStmt);
n->sourcetype = $4;
n->targettype = $6;
n->func = (FuncWithArgs *) $10;
- n->implicit = $11;
+ n->context = (CoercionContext) $11;
$$ = (Node *)n;
}
| CREATE CAST '(' ConstTypename AS ConstTypename ')'
- WITHOUT FUNCTION opt_assignment
+ WITHOUT FUNCTION cast_context
{
CreateCastStmt *n = makeNode(CreateCastStmt);
n->sourcetype = $4;
n->targettype = $6;
n->func = NULL;
- n->implicit = $10;
+ n->context = (CoercionContext) $10;
$$ = (Node *)n;
}
;
-opt_assignment: AS ASSIGNMENT { $$ = TRUE; }
- | /*EMPTY*/ { $$ = FALSE; }
+cast_context: AS IMPLICIT_P { $$ = COERCION_IMPLICIT; }
+ | AS ASSIGNMENT { $$ = COERCION_ASSIGNMENT; }
+ | /*EMPTY*/ { $$ = COERCION_EXPLICIT; }
;
| HOUR_P
| IMMEDIATE
| IMMUTABLE
+ | IMPLICIT_P
| INCREMENT
| INDEX
| INHERITS
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.126 2002/08/27 04:55:09 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.127 2002/09/18 21:35:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
{"ilike", ILIKE},
{"immediate", IMMEDIATE},
{"immutable", IMMUTABLE},
+ {"implicit", IMPLICIT_P},
{"in", IN_P},
{"increment", INCREMENT},
{"index", INDEX},
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.97 2002/09/04 20:31:23 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.98 2002/09/18 21:35:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* typmod is not same as input.
*/
if (l_colvar->vartype != outcoltype)
- l_node = coerce_type(NULL, (Node *) l_colvar, l_colvar->vartype,
- outcoltype, outcoltypmod, false);
+ l_node = coerce_type((Node *) l_colvar, l_colvar->vartype,
+ outcoltype,
+ COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
else if (l_colvar->vartypmod != outcoltypmod)
l_node = (Node *) makeRelabelType((Node *) l_colvar,
- outcoltype, outcoltypmod);
+ outcoltype, outcoltypmod,
+ COERCE_IMPLICIT_CAST);
else
l_node = (Node *) l_colvar;
if (r_colvar->vartype != outcoltype)
- r_node = coerce_type(NULL, (Node *) r_colvar, r_colvar->vartype,
- outcoltype, outcoltypmod, false);
+ r_node = coerce_type((Node *) r_colvar, r_colvar->vartype,
+ outcoltype,
+ COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
else if (r_colvar->vartypmod != outcoltypmod)
r_node = (Node *) makeRelabelType((Node *) r_colvar,
- outcoltype, outcoltypmod);
+ outcoltype, outcoltypmod,
+ COERCE_IMPLICIT_CAST);
else
r_node = (Node *) r_colvar;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.83 2002/09/04 20:31:23 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.84 2002/09/18 21:35:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "parser/parse_func.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
+#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
+static Node *coerce_type_typmod(Node *node,
+ Oid targetTypeId, int32 targetTypMod,
+ CoercionForm cformat);
static Oid PreferredType(CATEGORY category, Oid type);
static bool find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
- bool isExplicit,
- Oid *funcid);
-static Oid find_typmod_coercion_function(Oid typeId);
-static Node *build_func_call(Oid funcid, Oid rettype, List *args);
+ CoercionContext ccontext,
+ Oid *funcid);
+static Node *build_func_call(Oid funcid, Oid rettype, List *args,
+ CoercionForm fformat);
+
+
+/*
+ * coerce_to_target_type()
+ * Convert an expression to a target type and typmod.
+ *
+ * This is the general-purpose entry point for arbitrary type coercion
+ * operations. Direct use of the component operations can_coerce_type,
+ * coerce_type, and coerce_type_typmod should be restricted to special
+ * cases (eg, when the conversion is expected to succeed).
+ *
+ * Returns the possibly-transformed expression tree, or NULL if the type
+ * conversion is not possible. (We do this, rather than elog'ing directly,
+ * so that callers can generate custom error messages indicating context.)
+ *
+ * expr - input expression tree (already transformed by transformExpr)
+ * exprtype - result type of expr
+ * targettype - desired result type
+ * targettypmod - desired result typmod
+ * ccontext, cformat - context indicators to control coercions
+ */
+Node *
+coerce_to_target_type(Node *expr, Oid exprtype,
+ Oid targettype, int32 targettypmod,
+ CoercionContext ccontext,
+ CoercionForm cformat)
+{
+ if (can_coerce_type(1, &exprtype, &targettype, ccontext))
+ expr = coerce_type(expr, exprtype, targettype,
+ ccontext, cformat);
+ /*
+ * String hacks to get transparent conversions for char and varchar:
+ * if a coercion to text is available, use it for forced coercions to
+ * char(n) or varchar(n).
+ *
+ * This is pretty grotty, but seems easier to maintain than providing
+ * entries in pg_cast that parallel all the ones for text.
+ */
+ else if (ccontext >= COERCION_ASSIGNMENT &&
+ (targettype == BPCHAROID || targettype == VARCHAROID))
+ {
+ Oid text_id = TEXTOID;
+
+ if (can_coerce_type(1, &exprtype, &text_id, ccontext))
+ {
+ expr = coerce_type(expr, exprtype, text_id,
+ ccontext, cformat);
+ /* Need a RelabelType if no typmod coercion is performed */
+ if (targettypmod < 0)
+ expr = (Node *) makeRelabelType(expr, targettype, -1,
+ cformat);
+ }
+ else
+ expr = NULL;
+ }
+ else
+ expr = NULL;
+
+ /*
+ * If the target is a fixed-length type, it may need a length coercion
+ * as well as a type coercion.
+ */
+ if (expr != NULL)
+ expr = coerce_type_typmod(expr, targettype, targettypmod, cformat);
+
+ return expr;
+}
/*
* coerce_type()
- * Convert a function argument to a different type.
+ * Convert an expression to a different type.
*
* The caller should already have determined that the coercion is possible;
* see can_coerce_type.
+ *
+ * No coercion to a typmod (length) is performed here. The caller must
+ * call coerce_type_typmod as well, if a typmod constraint is wanted.
+ * (But if the target type is a domain, it may internally contain a
+ * typmod constraint, which will be applied inside coerce_type_constraints.)
*/
Node *
-coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
- Oid targetTypeId, int32 atttypmod, bool isExplicit)
+coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
+ CoercionContext ccontext, CoercionForm cformat)
{
Node *result;
Oid funcId;
* example, int4's typinput function will reject "1.2", whereas
* float-to-int type conversion will round to integer.
*
- * XXX if the typinput function is not cachable, we really ought to
+ * XXX if the typinput function is not immutable, we really ought to
* postpone evaluation of the function call until runtime. But
* there is no way to represent a typinput function call as an
* expression tree, because C-string values are not Datums. (XXX
con->constvalue));
/*
- * If target is a domain, use the typmod it applies to the
- * base type. Note that we call stringTypeDatum using the
- * domain's pg_type row, though. This works because the
- * domain row has the same typinput and typelem as the base
- * type --- ugly...
+ * We pass typmod -1 to the input routine, primarily because
+ * existing input routines follow implicit-coercion semantics
+ * for length checks, which is not always what we want here.
+ * Any length constraint will be applied later by our caller.
+ *
+ * Note that we call stringTypeDatum using the domain's pg_type
+ * row, if it's a domain. This works because the domain row has
+ * the same typinput and typelem as the base type --- ugly...
*/
- if (targetTyptype == 'd')
- atttypmod = getBaseTypeMod(targetTypeId, atttypmod);
-
- newcon->constvalue = stringTypeDatum(targetType, val, atttypmod);
+ newcon->constvalue = stringTypeDatum(targetType, val, -1);
pfree(val);
}
result = (Node *) newcon;
- /*
- * If target is a domain, apply constraints (except for typmod,
- * which we assume the input routine took care of).
- */
+ /* If target is a domain, apply constraints. */
if (targetTyptype == 'd')
- result = coerce_type_constraints(pstate, result, targetTypeId,
- false);
+ {
+ result = coerce_type_constraints(result, targetTypeId,
+ cformat);
+ /* We might now need a RelabelType. */
+ if (exprType(result) != targetTypeId)
+ result = (Node *) makeRelabelType(result, targetTypeId, -1,
+ cformat);
+ }
ReleaseSysCache(targetType);
}
targetTypeId == ANYARRAYOID)
{
/* assume can_coerce_type verified that implicit coercion is okay */
+ /* NB: we do NOT want a RelabelType here */
result = node;
}
- else if (find_coercion_pathway(targetTypeId, inputTypeId, isExplicit,
+ else if (find_coercion_pathway(targetTypeId, inputTypeId, ccontext,
&funcId))
{
if (OidIsValid(funcId))
*/
Oid baseTypeId = getBaseType(targetTypeId);
- result = build_func_call(funcId, baseTypeId, makeList1(node));
+ result = build_func_call(funcId, baseTypeId, makeList1(node),
+ cformat);
/*
* If domain, test against domain constraints and relabel with
*/
if (targetTypeId != baseTypeId)
{
- result = coerce_type_constraints(pstate, result,
- targetTypeId, true);
- result = (Node *) makeRelabelType(result, targetTypeId, -1);
+ result = coerce_type_constraints(result, targetTypeId,
+ cformat);
+ result = (Node *) makeRelabelType(result, targetTypeId, -1,
+ cformat);
}
/*
* Also, domains may have value restrictions beyond the base type
* that must be accounted for.
*/
- result = coerce_type_constraints(pstate, node,
- targetTypeId, true);
+ result = coerce_type_constraints(node, targetTypeId,
+ cformat);
/*
* XXX could we label result with exprTypmod(node) instead of
* typmod, which is likely but not certain (wrong if target is
* a domain, in any case).
*/
- result = (Node *) makeRelabelType(result, targetTypeId, -1);
+ result = (Node *) makeRelabelType(result, targetTypeId, -1,
+ cformat);
}
}
else if (typeInheritsFrom(inputTypeId, targetTypeId))
* except relabel the type. This is binary compatibility for
* complex types.
*/
- result = (Node *) makeRelabelType(node, targetTypeId, -1);
+ result = (Node *) makeRelabelType(node, targetTypeId, -1,
+ cformat);
}
else
{
/*
* can_coerce_type()
- * Can input_typeids be coerced to func_typeids?
+ * Can input_typeids be coerced to target_typeids?
*
- * 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.
+ * We must be told the context (CAST construct, assignment, implicit coercion)
+ * as this determines the set of available casts.
*/
bool
-can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids,
- bool isExplicit)
+can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
+ CoercionContext ccontext)
{
int i;
for (i = 0; i < nargs; i++)
{
Oid inputTypeId = input_typeids[i];
- Oid targetTypeId = func_typeids[i];
+ Oid targetTypeId = target_typeids[i];
Oid funcId;
/* no problem if same type */
/*
* Otherwise reject; this assumes there are no explicit
- * coercions to ANYARRAY. If we don't reject then
+ * coercion paths to ANYARRAY. If we don't reject then
* parse_coerce would have to repeat the above test.
*/
return false;
* If pg_cast shows that we can coerce, accept. This test now
* covers both binary-compatible and coercion-function cases.
*/
- if (find_coercion_pathway(targetTypeId, inputTypeId, isExplicit,
+ if (find_coercion_pathway(targetTypeId, inputTypeId, ccontext,
&funcId))
continue;
* Create an expression tree to enforce the constraints (if any)
* that should be applied by the type. Currently this is only
* interesting for domain types.
+ *
+ * NOTE: result tree is not guaranteed to show the correct exprType() for
+ * the domain; it may show the base type. Caller must relabel if needed.
*/
Node *
-coerce_type_constraints(ParseState *pstate, Node *arg,
- Oid typeId, bool applyTypmod)
+coerce_type_constraints(Node *arg, Oid typeId, CoercionForm cformat)
{
char *notNull = NULL;
int32 typmod = -1;
/*
* If domain applies a typmod to its base type, do length coercion.
*/
- if (applyTypmod && typmod >= 0)
- arg = coerce_type_typmod(pstate, arg, typeId, typmod);
+ if (typmod >= 0)
+ arg = coerce_type_typmod(arg, typeId, typmod, cformat);
/*
* Only need to add one NOT NULL check regardless of how many domains
}
-/* coerce_type_typmod()
- * Force a value to a particular typmod, if meaningful and possible.
+/*
+ * coerce_type_typmod()
+ * Force a value to a particular typmod, if meaningful and possible.
*
* This is applied to values that are going to be stored in a relation
* (where we have an atttypmod for the column) as well as values being
* coercion for a domain is considered to be part of the type coercion
* needed to produce the domain value in the first place. So, no getBaseType.
*/
-Node *
-coerce_type_typmod(ParseState *pstate, Node *node,
- Oid targetTypeId, int32 atttypmod)
+static Node *
+coerce_type_typmod(Node *node, Oid targetTypeId, int32 targetTypMod,
+ CoercionForm cformat)
{
Oid funcId;
+ int nargs;
/*
* A negative typmod is assumed to mean that no coercion is wanted.
*/
- if (atttypmod < 0 || atttypmod == exprTypmod(node))
+ if (targetTypMod < 0 || targetTypMod == exprTypmod(node))
return node;
- funcId = find_typmod_coercion_function(targetTypeId);
+ funcId = find_typmod_coercion_function(targetTypeId, &nargs);
if (OidIsValid(funcId))
{
+ List *args;
Const *cons;
+ Node *fcall;
+ /* Pass given value, plus target typmod as an int4 constant */
cons = makeConst(INT4OID,
sizeof(int32),
- Int32GetDatum(atttypmod),
+ Int32GetDatum(targetTypMod),
false,
true,
false,
false);
- node = build_func_call(funcId, targetTypeId, makeList2(node, cons));
+ args = makeList2(node, cons);
+
+ if (nargs == 3)
+ {
+ /* Pass it a boolean isExplicit parameter, too */
+ cons = makeConst(BOOLOID,
+ sizeof(bool),
+ BoolGetDatum(cformat != COERCE_IMPLICIT_CAST),
+ false,
+ true,
+ false,
+ false);
+
+ args = lappend(args, cons);
+ }
+
+ fcall = build_func_call(funcId, targetTypeId, args, cformat);
+
+ /*
+ * If the input is a constant, apply the length coercion
+ * function now instead of delaying to runtime.
+ *
+ * See the comments for the similar case in coerce_type.
+ */
+ if (node && IsA(node, Const) &&
+ !((Const *) node)->constisnull)
+ node = eval_const_expressions(fcall);
+ else
+ node = fcall;
}
return node;
coerce_to_boolean(Node *node, const char *constructName)
{
Oid inputTypeId = exprType(node);
- Oid targetTypeId;
if (inputTypeId != BOOLOID)
{
- targetTypeId = BOOLOID;
- if (!can_coerce_type(1, &inputTypeId, &targetTypeId, false))
+ node = coerce_to_target_type(node, inputTypeId,
+ BOOLOID, -1,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST);
+ if (node == NULL)
{
/* translator: first %s is name of a SQL construct, eg WHERE */
elog(ERROR, "Argument of %s must be type boolean, not type %s",
constructName, format_type_be(inputTypeId));
}
- node = coerce_type(NULL, node, inputTypeId, targetTypeId, -1,
- false);
}
if (expression_returns_set(node))
* in the list will be preferred if there is doubt.
* 'context' is a phrase to use in the error message if we fail to select
* a usable type.
- *
- * XXX this code is WRONG, since (for example) given the input (int4,int8)
- * it will select int4, whereas according to SQL92 clause 9.3 the correct
- * answer is clearly int8. To fix this we need a notion of a promotion
- * hierarchy within type categories --- something more complete than
- * just a single preferred type.
*/
Oid
select_common_type(List *typeids, const char *context)
elog(ERROR, "%s types '%s' and '%s' not matched",
context, format_type_be(ptype), format_type_be(ntype));
}
- else if (IsPreferredType(pcategory, ntype)
- && !IsPreferredType(pcategory, ptype)
- && can_coerce_type(1, &ptype, &ntype, false))
+ else if (!IsPreferredType(pcategory, ptype) &&
+ can_coerce_type(1, &ptype, &ntype, COERCION_IMPLICIT) &&
+ !can_coerce_type(1, &ntype, &ptype, COERCION_IMPLICIT))
{
/*
- * new one is preferred and can convert? then take it...
+ * take new type if can coerce to it implicitly but not the
+ * other way; but if we have a preferred type, stay on it.
*/
ptype = ntype;
pcategory = TypeCategory(ptype);
* This is used following select_common_type() to coerce the individual
* expressions to the desired type. 'context' is a phrase to use in the
* error message if we fail to coerce.
- *
- * NOTE: pstate may be NULL.
*/
Node *
-coerce_to_common_type(ParseState *pstate, Node *node,
- Oid targetTypeId,
- const char *context)
+coerce_to_common_type(Node *node, Oid targetTypeId, const char *context)
{
Oid inputTypeId = exprType(node);
if (inputTypeId == targetTypeId)
return node; /* no work */
- if (can_coerce_type(1, &inputTypeId, &targetTypeId, false))
- node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1,
- false);
+ if (can_coerce_type(1, &inputTypeId, &targetTypeId, COERCION_IMPLICIT))
+ node = coerce_type(node, inputTypeId, targetTypeId,
+ COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
else
- {
elog(ERROR, "%s unable to convert to type %s",
context, format_type_be(targetTypeId));
- }
return node;
}
type == REGCLASSOID ||
type == REGTYPEOID)
result = OIDOID;
- else if (type == NUMERICOID)
- result = NUMERICOID;
else
result = FLOAT8OID;
break;
} /* PreferredType() */
-/* IsBinaryCompatible()
- * Check if two types are binary-compatible.
+/* IsBinaryCoercible()
+ * Check if srctype is binary-coercible to targettype.
*
* This notion allows us to cheat and directly exchange values without
* going through the trouble of calling a conversion function.
*
- * As of 7.3, binary compatibility isn't hardwired into the code anymore.
- * We consider two types binary-compatible if there is an implicit,
- * no-function-needed pg_cast entry. NOTE that we assume that such
- * entries are symmetric, ie, it doesn't matter which type we consider
- * source and which target. (cf. checks in opr_sanity regression test)
+ * As of 7.3, binary coercibility isn't hardwired into the code anymore.
+ * We consider two types binary-coercible if there is an implicitly
+ * invokable, no-function-needed pg_cast entry.
+ *
+ * This function replaces IsBinaryCompatible(), which was an inherently
+ * symmetric test. Since the pg_cast entries aren't necessarily symmetric,
+ * the order of the operands is now significant.
*/
bool
-IsBinaryCompatible(Oid type1, Oid type2)
+IsBinaryCoercible(Oid srctype, Oid targettype)
{
HeapTuple tuple;
Form_pg_cast castForm;
bool result;
/* Fast path if same type */
- if (type1 == type2)
+ if (srctype == targettype)
return true;
/* Perhaps the types are domains; if so, look at their base types */
- if (OidIsValid(type1))
- type1 = getBaseType(type1);
- if (OidIsValid(type2))
- type2 = getBaseType(type2);
+ if (OidIsValid(srctype))
+ srctype = getBaseType(srctype);
+ if (OidIsValid(targettype))
+ targettype = getBaseType(targettype);
/* Somewhat-fast path if same base type */
- if (type1 == type2)
+ if (srctype == targettype)
return true;
/* Else look in pg_cast */
tuple = SearchSysCache(CASTSOURCETARGET,
- ObjectIdGetDatum(type1),
- ObjectIdGetDatum(type2),
+ ObjectIdGetDatum(srctype),
+ ObjectIdGetDatum(targettype),
0, 0);
if (!HeapTupleIsValid(tuple))
return false; /* no cast */
castForm = (Form_pg_cast) GETSTRUCT(tuple);
- result = (castForm->castfunc == InvalidOid) && castForm->castimplicit;
+ result = (castForm->castfunc == InvalidOid &&
+ castForm->castcontext == COERCION_CODE_IMPLICIT);
ReleaseSysCache(tuple);
* find_coercion_pathway
* Look for a coercion pathway between two types.
*
- * If we find a matching entry in pg_cast, return TRUE, and set *funcid
+ * ccontext determines the set of available casts.
+ *
+ * If we find a suitable entry in pg_cast, return TRUE, and set *funcid
* to the castfunc value (which may be InvalidOid for a binary-compatible
* coercion).
*/
static bool
-find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, bool isExplicit,
+find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
+ CoercionContext ccontext,
Oid *funcid)
{
bool result = false;
if (HeapTupleIsValid(tuple))
{
Form_pg_cast castForm = (Form_pg_cast) GETSTRUCT(tuple);
+ CoercionContext castcontext;
+
+ /* convert char value for castcontext to CoercionContext enum */
+ switch (castForm->castcontext)
+ {
+ case COERCION_CODE_IMPLICIT:
+ castcontext = COERCION_IMPLICIT;
+ break;
+ case COERCION_CODE_ASSIGNMENT:
+ castcontext = COERCION_ASSIGNMENT;
+ break;
+ case COERCION_CODE_EXPLICIT:
+ castcontext = COERCION_EXPLICIT;
+ break;
+ default:
+ elog(ERROR, "find_coercion_pathway: bogus castcontext %c",
+ castForm->castcontext);
+ castcontext = 0; /* keep compiler quiet */
+ break;
+ }
- if (isExplicit || castForm->castimplicit)
+ /* Rely on ordering of enum for correct behavior here */
+ if (ccontext >= castcontext)
{
*funcid = castForm->castfunc;
result = true;
* the type requires coercion to its own length and that the said
* function should be invoked to do that.
*
+ * Alternatively, the length-coercing function may have the signature
+ * (targettype, int4, bool). On success, *nargs is set to report which
+ * signature we found.
+ *
* "bpchar" (ie, char(N)) and "numeric" are examples of such types.
*
+ * If the given type is a varlena array type, we do not look for a coercion
+ * function associated directly with the array type, but instead look for
+ * one associated with the element type. If one exists, we report
+ * array_length_coerce() as the coercion function to use.
+ *
* This mechanism may seem pretty grotty and in need of replacement by
* something in pg_cast, but since typmod is only interesting for datatypes
* that have special handling in the grammar, there's not really much
* percentage in making it any easier to apply such coercions ...
*/
-static Oid
-find_typmod_coercion_function(Oid typeId)
+Oid
+find_typmod_coercion_function(Oid typeId, int *nargs)
{
Oid funcid = InvalidOid;
+ bool isArray = false;
Type targetType;
+ Form_pg_type typeForm;
char *typname;
Oid typnamespace;
Oid oid_array[FUNC_MAX_ARGS];
HeapTuple ftup;
targetType = typeidType(typeId);
- typname = NameStr(((Form_pg_type) GETSTRUCT(targetType))->typname);
- typnamespace = ((Form_pg_type) GETSTRUCT(targetType))->typnamespace;
+ typeForm = (Form_pg_type) GETSTRUCT(targetType);
+ /* Check for a varlena array type (and not a domain) */
+ if (typeForm->typelem != InvalidOid &&
+ typeForm->typlen == -1 &&
+ typeForm->typtype != 'd')
+ {
+ /* Yes, switch our attention to the element type */
+ typeId = typeForm->typelem;
+ ReleaseSysCache(targetType);
+ targetType = typeidType(typeId);
+ typeForm = (Form_pg_type) GETSTRUCT(targetType);
+ isArray = true;
+ }
+
+ /* Function name is same as type internal name, and in same namespace */
+ typname = NameStr(typeForm->typname);
+ typnamespace = typeForm->typnamespace;
+
+ /* First look for parameters (type, int4) */
MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid));
oid_array[0] = typeId;
oid_array[1] = INT4OID;
+ *nargs = 2;
ftup = SearchSysCache(PROCNAMENSP,
CStringGetDatum(typname),
ReleaseSysCache(ftup);
}
+ if (!OidIsValid(funcid))
+ {
+ /* Didn't find a function, so now try (type, int4, bool) */
+ oid_array[2] = BOOLOID;
+ *nargs = 3;
+
+ ftup = SearchSysCache(PROCNAMENSP,
+ CStringGetDatum(typname),
+ Int16GetDatum(3),
+ PointerGetDatum(oid_array),
+ ObjectIdGetDatum(typnamespace));
+ 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 == typeId && !pform->proretset &&
+ !pform->proisagg)
+ {
+ /* Okay to use it */
+ funcid = HeapTupleGetOid(ftup);
+ }
+ ReleaseSysCache(ftup);
+ }
+ }
+
ReleaseSysCache(targetType);
+ /*
+ * Now, if we did find a coercion function for an array element type,
+ * report array_length_coerce() as the function to use. We know it
+ * takes three arguments always.
+ */
+ if (isArray && OidIsValid(funcid))
+ {
+ funcid = F_ARRAY_LENGTH_COERCE;
+ *nargs = 3;
+ }
+
return funcid;
}
* The argument expressions must have been transformed already.
*/
static Node *
-build_func_call(Oid funcid, Oid rettype, List *args)
+build_func_call(Oid funcid, Oid rettype, List *args, CoercionForm fformat)
{
Func *funcnode;
Expr *expr;
funcnode->funcid = funcid;
funcnode->funcresulttype = rettype;
funcnode->funcretset = false; /* only possible case here */
+ funcnode->funcformat = fformat;
funcnode->func_fcache = NULL;
expr = makeNode(Expr);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.128 2002/09/04 20:31:23 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.129 2002/09/18 21:35:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "parser/parse_func.h"
#include "parser/parse_oper.h"
#include "parser/parse_relation.h"
-#include "parser/parse_target.h"
#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
bool Transform_null_equals = false;
-static Node *parser_typecast_constant(Value *expr, TypeName *typename);
-static Node *parser_typecast_expression(ParseState *pstate,
- Node *expr, TypeName *typename);
+static Node *typecast_expression(Node *expr, TypeName *typename);
static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref);
static Node *transformIndirection(ParseState *pstate, Node *basenode,
List *indirection);
A_Const *con = (A_Const *) expr;
Value *val = &con->val;
+ result = (Node *) make_const(val);
if (con->typename != NULL)
- result = parser_typecast_constant(val, con->typename);
- else
- result = (Node *) make_const(val);
+ result = typecast_expression(result, con->typename);
break;
}
case T_ExprFieldSelect:
TypeCast *tc = (TypeCast *) expr;
Node *arg = transformExpr(pstate, tc->arg);
- result = parser_typecast_expression(pstate, arg, tc->typename);
+ result = typecast_expression(arg, tc->typename);
break;
}
case T_A_Expr:
newc->casetype = ptype;
/* Convert default result clause, if necessary */
- newc->defresult = coerce_to_common_type(pstate,
- newc->defresult,
+ newc->defresult = coerce_to_common_type(newc->defresult,
ptype,
"CASE/ELSE");
{
CaseWhen *w = (CaseWhen *) lfirst(args);
- w->result = coerce_to_common_type(pstate,
- w->result,
+ w->result = coerce_to_common_type(w->result,
ptype,
"CASE/WHEN");
}
if (indirection == NIL)
return basenode;
return (Node *) transformArraySubscripts(pstate,
- basenode, exprType(basenode),
- indirection, false, NULL);
+ basenode,
+ exprType(basenode),
+ exprTypmod(basenode),
+ indirection,
+ false,
+ NULL);
}
static Node *
*
* If coercedTypmod is not NULL, the typmod is stored there if the expression
* is a length-coercion function, else -1 is stored there.
- *
- * We assume that a two-argument function named for a datatype, whose
- * output and first argument types are that datatype, and whose second
- * input is an int32 constant, represents a forced length coercion.
- *
- * XXX It'd be better if the parsetree retained some explicit indication
- * of the coercion, so we didn't need these heuristics.
*/
bool
exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
{
Func *func;
+ int nargs;
Const *second_arg;
- HeapTuple procTuple;
- HeapTuple typeTuple;
- Form_pg_proc procStruct;
- Form_pg_type typeStruct;
if (coercedTypmod != NULL)
*coercedTypmod = -1; /* default result on failure */
Assert(IsA(func, Func));
/*
- * If it's not a two-argument function with the second argument being
- * an int4 constant, it can't have been created from a length
- * coercion.
+ * If it didn't come from a coercion context, reject.
*/
- if (length(((Expr *) expr)->args) != 2)
- return false;
- second_arg = (Const *) lsecond(((Expr *) expr)->args);
- if (!IsA(second_arg, Const) ||
- second_arg->consttype != INT4OID ||
- second_arg->constisnull)
+ if (func->funcformat != COERCE_EXPLICIT_CAST &&
+ func->funcformat != COERCE_IMPLICIT_CAST)
return false;
/*
- * Lookup the function in pg_proc
- */
- procTuple = SearchSysCache(PROCOID,
- ObjectIdGetDatum(func->funcid),
- 0, 0, 0);
- if (!HeapTupleIsValid(procTuple))
- elog(ERROR, "cache lookup for proc %u failed", func->funcid);
- procStruct = (Form_pg_proc) GETSTRUCT(procTuple);
-
- /*
- * It must be a function with two arguments where the first is of the
- * same type as the return value and the second is an int4. Also, just
- * to be sure, check return type agrees with expr node.
+ * If it's not a two-argument or three-argument function with the second
+ * argument being an int4 constant, it can't have been created from a
+ * length coercion (it must be a type coercion, instead).
*/
- if (procStruct->pronargs != 2 ||
- procStruct->prorettype != procStruct->proargtypes[0] ||
- procStruct->proargtypes[1] != INT4OID ||
- procStruct->prorettype != ((Expr *) expr)->typeOid)
- {
- ReleaseSysCache(procTuple);
+ nargs = length(((Expr *) expr)->args);
+ if (nargs < 2 || nargs > 3)
return false;
- }
- /*
- * Furthermore, the name and namespace of the function must be the
- * same as its result type's name/namespace (cf.
- * find_coercion_function).
- */
- 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)
- {
- ReleaseSysCache(procTuple);
- ReleaseSysCache(typeTuple);
+ second_arg = (Const *) lsecond(((Expr *) expr)->args);
+ if (!IsA(second_arg, Const) ||
+ second_arg->consttype != INT4OID ||
+ second_arg->constisnull)
return false;
- }
/*
* OK, it is indeed a length-coercion function.
if (coercedTypmod != NULL)
*coercedTypmod = DatumGetInt32(second_arg->constvalue);
- ReleaseSysCache(procTuple);
- ReleaseSysCache(typeTuple);
return true;
}
/*
- * Produce an appropriate Const node from a constant value produced
- * by the parser and an explicit type name to cast to.
- */
-static Node *
-parser_typecast_constant(Value *expr, TypeName *typename)
-{
- Type tp;
- Datum datum;
- Const *con;
- char *const_string = NULL;
- bool string_palloced = false;
- bool isNull = false;
-
- tp = typenameType(typename);
-
- switch (nodeTag(expr))
- {
- case T_Integer:
- const_string = DatumGetCString(DirectFunctionCall1(int4out,
- Int32GetDatum(expr->val.ival)));
- string_palloced = true;
- break;
- case T_Float:
- case T_String:
- case T_BitString:
- const_string = expr->val.str;
- break;
- case T_Null:
- isNull = true;
- break;
- default:
- elog(ERROR, "Cannot cast this expression to type '%s'",
- typeTypeName(tp));
- }
-
- if (isNull)
- datum = (Datum) NULL;
- else
- datum = stringTypeDatum(tp, const_string, typename->typmod);
-
- con = makeConst(typeTypeId(tp),
- typeLen(tp),
- datum,
- isNull,
- typeByVal(tp),
- false, /* not a set */
- true /* is cast */ );
-
- if (string_palloced)
- pfree(const_string);
-
- ReleaseSysCache(tp);
-
- return (Node *) con;
-}
-
-/*
- * Handle an explicit CAST applied to a non-constant expression.
- * (Actually, this works for constants too, but gram.y won't generate
- * a TypeCast node if the argument is just a constant.)
+ * Handle an explicit CAST construct.
*
* The given expr has already been transformed, but we need to lookup
* the type name and then apply any necessary coercion function(s).
*/
static Node *
-parser_typecast_expression(ParseState *pstate,
- Node *expr, TypeName *typename)
+typecast_expression(Node *expr, TypeName *typename)
{
Oid inputType = exprType(expr);
Oid targetType;
if (inputType == InvalidOid)
return expr; /* do nothing if NULL input */
- if (inputType != targetType)
- {
- expr = CoerceTargetExpr(pstate, expr, inputType,
- targetType, typename->typmod,
- true); /* explicit coercion */
- if (expr == NULL)
- elog(ERROR, "Cannot cast type '%s' to '%s'",
- format_type_be(inputType),
- format_type_be(targetType));
- }
-
- /*
- * If the target is a fixed-length type, it may need a length coercion
- * as well as a type coercion.
- */
- expr = coerce_type_typmod(pstate, expr,
- targetType, typename->typmod);
+ expr = coerce_to_target_type(expr, inputType,
+ targetType, typename->typmod,
+ COERCION_EXPLICIT,
+ COERCE_EXPLICIT_CAST);
+ if (expr == NULL)
+ elog(ERROR, "Cannot cast type %s to %s",
+ format_type_be(inputType),
+ format_type_be(targetType));
return expr;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.136 2002/09/04 20:31:23 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.137 2002/09/18 21:35:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/syscache.h"
-static Node *ParseComplexProjection(ParseState *pstate,
- char *funcname,
- Node *first_arg);
+static Node *ParseComplexProjection(char *funcname, Node *first_arg);
static Oid **argtype_inherit(int nargs, Oid *argtypes);
static int find_inheritors(Oid relid, Oid **supervec);
static Oid **gen_cross_product(InhPaths *arginh, int nargs);
-static void make_arguments(ParseState *pstate,
- int nargs,
+static void make_arguments(int nargs,
List *fargs,
Oid *input_typeids,
Oid *function_typeids);
* ParseComplexProjection can't handle the projection, we have
* to keep going.
*/
- retval = ParseComplexProjection(pstate, cname, first_arg);
+ retval = ParseComplexProjection(cname, first_arg);
if (retval)
return retval;
}
* We can do it as a trivial coercion. coerce_type can handle
* these cases, so why duplicate code...
*/
- return coerce_type(pstate, lfirst(fargs),
- oid_array[0], rettype, -1, true);
+ return coerce_type(lfirst(fargs), oid_array[0], rettype,
+ COERCION_EXPLICIT, COERCE_EXPLICIT_CALL);
}
else if (fdresult == FUNCDETAIL_NORMAL)
{
}
/* perform the necessary typecasting of arguments */
- make_arguments(pstate, nargs, fargs, oid_array, true_oid_array);
+ make_arguments(nargs, fargs, oid_array, true_oid_array);
/* build the appropriate output structure */
if (fdresult == FUNCDETAIL_NORMAL)
funcnode->funcid = funcid;
funcnode->funcresulttype = rettype;
funcnode->funcretset = retset;
+ funcnode->funcformat = COERCE_EXPLICIT_CALL;
funcnode->func_fcache = NULL;
expr->typeOid = rettype;
{
next_candidate = current_candidate->next;
if (can_coerce_type(nargs, input_typeids, current_candidate->args,
- false))
+ COERCION_IMPLICIT))
{
current_candidate->next = *candidates;
*candidates = current_candidate;
{
if (input_typeids[i] != UNKNOWNOID)
{
- if (IsBinaryCompatible(current_typeids[i], input_typeids[i]))
+ if (IsBinaryCoercible(input_typeids[i], current_typeids[i]))
nmatch++;
}
}
Node *arg1 = lfirst(fargs);
if ((sourceType == UNKNOWNOID && IsA(arg1, Const)) ||
- IsBinaryCompatible(sourceType, targetType))
+ IsBinaryCoercible(sourceType, targetType))
{
/* Yup, it's a type coercion */
*funcid = InvalidOid;
* actual arguments and argument types, do the necessary typecasting.
*/
static void
-make_arguments(ParseState *pstate,
- int nargs,
+make_arguments(int nargs,
List *fargs,
Oid *input_typeids,
Oid *function_typeids)
/* types don't match? then force coercion using a function call... */
if (input_typeids[i] != function_typeids[i])
{
- lfirst(current_fargs) = coerce_type(pstate,
- lfirst(current_fargs),
+ lfirst(current_fargs) = coerce_type(lfirst(current_fargs),
input_typeids[i],
- function_typeids[i], -1,
- false);
+ function_typeids[i],
+ COERCION_IMPLICIT,
+ COERCE_IMPLICIT_CAST);
}
}
}
* NB: argument is expected to be transformed already, ie, not a RangeVar.
*/
static Node *
-ParseComplexProjection(ParseState *pstate,
- char *funcname,
- Node *first_arg)
+ParseComplexProjection(char *funcname, Node *first_arg)
{
Oid argtype = exprType(first_arg);
Oid argrelid;
/*-------------------------------------------------------------------------
*
* parse_node.c
- * various routines that make nodes for query plans
+ * various routines that make nodes for querytrees
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.68 2002/09/04 20:31:24 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.69 2002/09/18 21:35:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-#include <ctype.h>
-#include <errno.h>
-#include <float.h>
-
#include "access/heapam.h"
#include "catalog/pg_operator.h"
#include "catalog/pg_type.h"
-#include "fmgr.h"
#include "nodes/makefuncs.h"
#include "parser/parsetree.h"
#include "parser/parse_coerce.h"
#include "parser/parse_node.h"
#include "parser/parse_oper.h"
#include "parser/parse_relation.h"
-#include "parser/parse_target.h"
-#include "parser/parse_type.h"
#include "utils/builtins.h"
-#include "utils/varbit.h"
+#include "utils/int8.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
-
-static bool fitsInFloat(Value *value);
+#include "utils/varbit.h"
/* make_parsestate()
{
/* must coerce? */
if (target_typeId != orig_typeId)
- result = coerce_type(NULL, tree, orig_typeId, target_typeId, -1,
- false);
+ result = coerce_type(tree, orig_typeId, target_typeId,
+ COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
else
result = tree;
}
* arrayBase Already-transformed expression for the array as a whole
* (may be NULL if we are handling an INSERT)
* arrayType OID of array's datatype
+ * arrayTypMod typmod to be applied to array elements
* indirection Untransformed list of subscripts (must not be NIL)
* forceSlice If true, treat subscript as array slice in all cases
* assignFrom NULL for array fetch, else transformed expression for source.
transformArraySubscripts(ParseState *pstate,
Node *arrayBase,
Oid arrayType,
+ int32 arrayTypMod,
List *indirection,
bool forceSlice,
Node *assignFrom)
{
subexpr = transformExpr(pstate, ai->lidx);
/* If it's not int4 already, try to coerce */
- subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr),
- INT4OID, -1, false);
+ subexpr = coerce_to_target_type(subexpr, exprType(subexpr),
+ INT4OID, -1,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST);
if (subexpr == NULL)
elog(ERROR, "array index expressions must be integers");
}
}
subexpr = transformExpr(pstate, ai->uidx);
/* If it's not int4 already, try to coerce */
- subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr),
- INT4OID, -1, false);
+ subexpr = coerce_to_target_type(subexpr, exprType(subexpr),
+ INT4OID, -1,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST);
if (subexpr == NULL)
elog(ERROR, "array index expressions must be integers");
upperIndexpr = lappend(upperIndexpr, subexpr);
if (typesource != InvalidOid)
{
- if (typesource != typeneeded)
- {
- /* XXX fixme: need to get the array's atttypmod? */
- assignFrom = CoerceTargetExpr(pstate, assignFrom,
- typesource, typeneeded,
- -1, false);
- if (assignFrom == NULL)
- elog(ERROR, "Array assignment requires type '%s'"
- " but expression is of type '%s'"
- "\n\tYou will need to rewrite or cast the expression",
- format_type_be(typeneeded),
- format_type_be(typesource));
- }
+ assignFrom = coerce_to_target_type(assignFrom, typesource,
+ typeneeded, arrayTypMod,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST);
+ if (assignFrom == NULL)
+ elog(ERROR, "Array assignment requires type %s"
+ " but expression is of type %s"
+ "\n\tYou will need to rewrite or cast the expression",
+ format_type_be(typeneeded),
+ format_type_be(typesource));
}
}
*/
aref = makeNode(ArrayRef);
aref->refrestype = resultType; /* XXX should save element type
- * too */
+ * OID too */
aref->refattrlength = type_struct_array->typlen;
aref->refelemlength = type_struct_element->typlen;
aref->refelembyval = type_struct_element->typbyval;
* resolution that we're not sure that it should be considered text.
* Explicit "NULL" constants are also typed as UNKNOWN.
*
- * For integers and floats we produce int4, float8, or numeric depending
- * on the value of the number. XXX In some cases it would be nice to take
- * context into account when determining the type to convert to, but in
- * other cases we can't delay the type choice. One possibility is to invent
- * a dummy type "UNKNOWNNUMERIC" that's treated similarly to UNKNOWN;
- * that would allow us to do the right thing in examples like a simple
- * INSERT INTO table (numericcolumn) VALUES (1.234), since we wouldn't
- * have to resolve the unknown type until we knew the destination column
- * type. On the other hand UNKNOWN has considerable problems of its own.
- * We would not like "SELECT 1.2 + 3.4" to claim it can't choose a type.
+ * For integers and floats we produce int4, int8, or numeric depending
+ * on the value of the number. XXX This should include int2 as well,
+ * but additional cleanup is needed before we can do that; else cases
+ * like "WHERE int4var = 42" will fail to be indexable.
*/
Const *
make_const(Value *value)
{
Datum val;
+ int64 val64;
Oid typeid;
int typelen;
bool typebyval;
break;
case T_Float:
- if (fitsInFloat(value))
+ /* could be an oversize integer as well as a float ... */
+ if (scanint8(strVal(value), true, &val64))
{
- val = Float8GetDatum(floatVal(value));
+ val = Int64GetDatum(val64);
- typeid = FLOAT8OID;
- typelen = sizeof(float8);
+ typeid = INT8OID;
+ typelen = sizeof(int64);
typebyval = false; /* XXX might change someday */
}
else
return con;
}
-
-/*
- * Decide whether a T_Float value fits in float8, or must be treated as
- * type "numeric". We check the number of digits and check for overflow/
- * underflow. (With standard compilation options, Postgres' NUMERIC type
- * can handle decimal exponents up to 1000, considerably more than most
- * implementations of float8, so this is a sensible test.)
- */
-static bool
-fitsInFloat(Value *value)
-{
- const char *ptr;
- int ndigits;
- char *endptr;
-
- /*
- * Count digits, ignoring leading zeroes (but not trailing zeroes).
- * DBL_DIG is the maximum safe number of digits for "double".
- */
- ptr = strVal(value);
- while (*ptr == '+' || *ptr == '-' || *ptr == '0' || *ptr == '.')
- ptr++;
- ndigits = 0;
- for (; *ptr; ptr++)
- {
- if (isdigit((unsigned char) *ptr))
- ndigits++;
- else if (*ptr == 'e' || *ptr == 'E')
- break; /* don't count digits in exponent */
- }
- if (ndigits > DBL_DIG)
- return false;
-
- /*
- * Use strtod() to check for overflow/underflow.
- */
- errno = 0;
- (void) strtod(strVal(value), &endptr);
- if (*endptr != '\0' || errno != 0)
- return false;
-
- return true;
-}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.59 2002/09/04 20:31:24 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.60 2002/09/18 21:35:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
current_candidate = current_candidate->next)
{
if (can_coerce_type(nargs, input_typeids, current_candidate->args,
- false))
+ COERCION_IMPLICIT))
{
if (last_candidate == NULL)
{
{
if (input_typeids[i] != UNKNOWNOID)
{
- if (IsBinaryCompatible(current_typeids[i], input_typeids[i]))
+ if (IsBinaryCoercible(input_typeids[i], current_typeids[i]))
nmatch++;
}
}
/* but is it good enough? */
opform = (Form_pg_operator) GETSTRUCT(optup);
- if (IsBinaryCompatible(opform->oprleft, arg1) &&
- IsBinaryCompatible(opform->oprright, arg2))
+ if (IsBinaryCoercible(arg1, opform->oprleft) &&
+ IsBinaryCoercible(arg2, opform->oprright))
return optup;
/* nope... */
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.89 2002/09/04 20:31:24 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.90 2002/09/18 21:35:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
aref = transformArraySubscripts(pstate,
arrayBase,
attrtype,
+ attrtypmod,
indirection,
pstate->p_is_insert,
tle->expr);
/*
* For normal non-subscripted target column, do type checking and
* coercion. But accept InvalidOid, which indicates the source is
- * a NULL constant.
+ * a NULL constant. (XXX is that still true?)
*/
if (type_id != InvalidOid)
{
- if (type_id != attrtype)
- {
- tle->expr = CoerceTargetExpr(pstate, tle->expr, type_id,
- attrtype, attrtypmod,
- false);
- if (tle->expr == NULL)
- elog(ERROR, "column \"%s\" is of type '%s'"
- " but expression is of type '%s'"
- "\n\tYou will need to rewrite or cast the expression",
- colname,
- format_type_be(attrtype),
- format_type_be(type_id));
- }
-
- /*
- * If the target is a fixed-length type, it may need a length
- * coercion as well as a type coercion.
- */
- tle->expr = coerce_type_typmod(pstate, tle->expr,
- attrtype, attrtypmod);
+ tle->expr = coerce_to_target_type(tle->expr, type_id,
+ attrtype, attrtypmod,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST);
+ if (tle->expr == NULL)
+ elog(ERROR, "column \"%s\" is of type %s"
+ " but expression is of type %s"
+ "\n\tYou will need to rewrite or cast the expression",
+ colname,
+ format_type_be(attrtype),
+ format_type_be(type_id));
}
}
}
-Node *
-CoerceTargetExpr(ParseState *pstate,
- Node *expr,
- Oid type_id,
- Oid attrtype,
- int32 attrtypmod,
- bool isExplicit)
-{
- if (can_coerce_type(1, &type_id, &attrtype, isExplicit))
- expr = coerce_type(pstate, expr, type_id, attrtype, attrtypmod,
- isExplicit);
-
-#ifndef DISABLE_STRING_HACKS
-
- /*
- * string hacks to get transparent conversions w/o explicit
- * conversions
- */
- else if ((attrtype == BPCHAROID) || (attrtype == VARCHAROID))
- {
- Oid text_id = TEXTOID;
-
- if (type_id == TEXTOID)
- {
- }
- 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;
- }
-#endif
-
- else
- expr = NULL;
-
- return expr;
-}
-
-
/*
* checkInsertTargets -
* generate a list of INSERT column targets if not supplied, or
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.109 2002/09/11 14:48:54 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.110 2002/09/18 21:35:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "parser/parse_oper.h"
-#include "parser/parse_target.h"
#include "parser/parse_type.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteHandler.h"
*/
exprtype = exprType(expr);
- if (exprtype != atttype)
- {
- expr = CoerceTargetExpr(NULL, expr, exprtype,
- atttype, atttypmod, false);
-
- /*
- * This really shouldn't fail; should have checked the default's
- * type when it was created ...
- */
- if (expr == 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",
- NameStr(att_tup->attname),
- format_type_be(atttype),
- format_type_be(exprtype));
- }
-
+ expr = coerce_to_target_type(expr, exprtype,
+ atttype, atttypmod,
+ COERCION_ASSIGNMENT,
+ COERCE_IMPLICIT_CAST);
/*
- * If the column is a fixed-length type, it may need a length coercion
- * as well as a type coercion.
+ * This really shouldn't fail; should have checked the default's
+ * type when it was created ...
*/
- expr = coerce_type_typmod(NULL, expr, atttype, atttypmod);
+ if (expr == 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",
+ NameStr(att_tup->attname),
+ format_type_be(atttype),
+ format_type_be(exprtype));
return expr;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.80 2002/09/04 20:31:27 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.81 2002/09/18 21:35:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "access/tupmacs.h"
#include "catalog/catalog.h"
#include "catalog/pg_type.h"
+#include "parser/parse_coerce.h"
#include "utils/array.h"
#include "utils/memutils.h"
#include "utils/syscache.h"
PG_RETURN_CSTRING(retval);
}
+/*-------------------------------------------------------------------------
+ * array_length_coerce :
+ * Apply the element type's length-coercion routine to each element
+ * of the given array.
+ *-------------------------------------------------------------------------
+ */
+Datum
+array_length_coerce(PG_FUNCTION_ARGS)
+{
+ ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
+ int32 len = PG_GETARG_INT32(1);
+ bool isExplicit = PG_GETARG_BOOL(2);
+ FmgrInfo *fmgr_info = fcinfo->flinfo;
+ FmgrInfo *element_finfo;
+ FunctionCallInfoData locfcinfo;
+
+ /* If no typmod is provided, shortcircuit the whole thing */
+ if (len < 0)
+ PG_RETURN_ARRAYTYPE_P(v);
+
+ /*
+ * We arrange to look up the element type's coercion function only
+ * once per series of calls.
+ */
+ if (fmgr_info->fn_extra == NULL)
+ {
+ Oid funcId;
+ int nargs;
+
+ fmgr_info->fn_extra = MemoryContextAlloc(fmgr_info->fn_mcxt,
+ sizeof(FmgrInfo));
+ element_finfo = (FmgrInfo *) fmgr_info->fn_extra;
+
+ funcId = find_typmod_coercion_function(ARR_ELEMTYPE(v), &nargs);
+
+ if (OidIsValid(funcId))
+ fmgr_info_cxt(funcId, element_finfo, fmgr_info->fn_mcxt);
+ else
+ element_finfo->fn_oid = InvalidOid;
+ }
+ else
+ element_finfo = (FmgrInfo *) fmgr_info->fn_extra;
+
+ /*
+ * If we didn't find a coercion function, return the array unmodified
+ * (this should not happen in the normal course of things, but might
+ * happen if this function is called manually).
+ */
+ if (element_finfo->fn_oid == InvalidOid)
+ PG_RETURN_ARRAYTYPE_P(v);
+
+ /*
+ * Use array_map to apply the function to each array element.
+ *
+ * Note: we pass isExplicit whether or not the function wants it ...
+ */
+ MemSet(&locfcinfo, 0, sizeof(locfcinfo));
+ locfcinfo.flinfo = element_finfo;
+ locfcinfo.nargs = 3;
+ locfcinfo.arg[0] = PointerGetDatum(v);
+ locfcinfo.arg[1] = Int32GetDatum(len);
+ locfcinfo.arg[2] = BoolGetDatum(isExplicit);
+
+ return array_map(&locfcinfo, ARR_ELEMTYPE(v), ARR_ELEMTYPE(v));
+}
+
/*-----------------------------------------------------------------------------
* array_dims :
* returns the dimensions of the array pointed to by "v", as a "text"
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/int8.c,v 1.41 2002/09/04 20:31:28 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/int8.c,v 1.42 2002/09/18 21:35:22 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* Formatting and conversion routines.
*---------------------------------------------------------*/
-/* int8in()
+/*
+ * scanint8 --- try to parse a string into an int8.
+ *
+ * If errorOK is false, elog a useful error message if the string is bad.
+ * If errorOK is true, just return "false" for bad input.
*/
-Datum
-int8in(PG_FUNCTION_ARGS)
+bool
+scanint8(const char *str, bool errorOK, int64 *result)
{
- char *str = PG_GETARG_CSTRING(0);
- int64 result;
- char *ptr = str;
+ const char *ptr = str;
int64 tmp = 0;
int sign = 1;
* Do our own scan, rather than relying on sscanf which might be
* broken for long long.
*/
- while (*ptr && isspace((unsigned char) *ptr)) /* skip leading spaces */
+
+ /* skip leading spaces */
+ while (*ptr && isspace((unsigned char) *ptr))
ptr++;
+
/* handle sign */
if (*ptr == '-')
{
#ifndef INT64_IS_BUSTED
if (strcmp(ptr, "9223372036854775808") == 0)
{
- result = -INT64CONST(0x7fffffffffffffff) - 1;
- PG_RETURN_INT64(result);
+ *result = -INT64CONST(0x7fffffffffffffff) - 1;
+ return true;
}
#endif
}
else if (*ptr == '+')
ptr++;
- if (!isdigit((unsigned char) *ptr)) /* require at least one digit */
- elog(ERROR, "Bad int8 external representation \"%s\"", str);
- while (*ptr && isdigit((unsigned char) *ptr)) /* process digits */
+
+ /* require at least one digit */
+ if (!isdigit((unsigned char) *ptr))
+ {
+ if (errorOK)
+ return false;
+ else
+ elog(ERROR, "Bad int8 external representation \"%s\"", str);
+ }
+
+ /* process digits */
+ while (*ptr && isdigit((unsigned char) *ptr))
{
int64 newtmp = tmp * 10 + (*ptr++ - '0');
if ((newtmp / 10) != tmp) /* overflow? */
- elog(ERROR, "int8 value out of range: \"%s\"", str);
+ {
+ if (errorOK)
+ return false;
+ else
+ elog(ERROR, "int8 value out of range: \"%s\"", str);
+ }
tmp = newtmp;
}
- if (*ptr) /* trailing junk? */
- elog(ERROR, "Bad int8 external representation \"%s\"", str);
- result = (sign < 0) ? -tmp : tmp;
+ /* trailing junk? */
+ if (*ptr)
+ {
+ if (errorOK)
+ return false;
+ else
+ elog(ERROR, "Bad int8 external representation \"%s\"", str);
+ }
+ *result = (sign < 0) ? -tmp : tmp;
+
+ return true;
+}
+
+/* int8in()
+ */
+Datum
+int8in(PG_FUNCTION_ARGS)
+{
+ char *str = PG_GETARG_CSTRING(0);
+ int64 result;
+
+ (void) scanint8(str, false, &result);
PG_RETURN_INT64(result);
}
}
/* dtoi8()
- * Convert double float to 8-byte integer.
+ * Convert float8 to 8-byte integer.
*/
Datum
dtoi8(PG_FUNCTION_ARGS)
PG_RETURN_INT64(result);
}
-/* text_int8()
+Datum
+i8tof(PG_FUNCTION_ARGS)
+{
+ int64 val = PG_GETARG_INT64(0);
+ float4 result;
+
+ result = val;
+
+ PG_RETURN_FLOAT4(result);
+}
+
+/* ftoi8()
+ * Convert float4 to 8-byte integer.
*/
+Datum
+ftoi8(PG_FUNCTION_ARGS)
+{
+ float4 val = PG_GETARG_FLOAT4(0);
+ int64 result;
+ float8 dval;
+
+ /* Round val to nearest integer (but it's still in float form) */
+ dval = rint(val);
+
+ /*
+ * Does it fit in an int64? Avoid assuming that we have handy
+ * constants defined for the range boundaries, instead test for
+ * overflow by reverse-conversion.
+ */
+ result = (int64) dval;
+
+ if ((float8) result != dval)
+ elog(ERROR, "Floating point conversion to int8 is out of range");
+
+ PG_RETURN_INT64(result);
+}
+
+Datum
+i8tooid(PG_FUNCTION_ARGS)
+{
+ int64 val = PG_GETARG_INT64(0);
+ Oid result;
+
+ result = (Oid) val;
+
+ /* Test for overflow by reverse-conversion. */
+ if ((int64) result != val)
+ elog(ERROR, "int8 conversion to OID is out of range");
+
+ PG_RETURN_OID(result);
+}
+
+Datum
+oidtoi8(PG_FUNCTION_ARGS)
+{
+ Oid val = PG_GETARG_OID(0);
+
+ PG_RETURN_INT64((int64) val);
+}
+
Datum
text_int8(PG_FUNCTION_ARGS)
{
return result;
}
-
-/* int8_text()
- */
Datum
int8_text(PG_FUNCTION_ARGS)
{
*
* 1998 Jan Wieck
*
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.53 2002/09/04 20:31:28 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/numeric.c,v 1.54 2002/09/18 21:35:22 tgl Exp $
*
* ----------
*/
}
+Datum
+text_numeric(PG_FUNCTION_ARGS)
+{
+ text *str = PG_GETARG_TEXT_P(0);
+ int len;
+ char *s;
+ Datum result;
+
+ len = (VARSIZE(str) - VARHDRSZ);
+ s = palloc(len + 1);
+ memcpy(s, VARDATA(str), len);
+ *(s + len) = '\0';
+
+ result = DirectFunctionCall3(numeric_in, CStringGetDatum(s),
+ ObjectIdGetDatum(0), Int32GetDatum(-1));
+
+ pfree(s);
+
+ return result;
+}
+
+Datum
+numeric_text(PG_FUNCTION_ARGS)
+{
+ /* val is numeric, but easier to leave it as Datum */
+ Datum val = PG_GETARG_DATUM(0);
+ char *s;
+ int len;
+ text *result;
+
+ s = DatumGetCString(DirectFunctionCall1(numeric_out, val));
+ len = strlen(s);
+
+ result = (text *) palloc(VARHDRSZ + len);
+
+ VARATT_SIZEP(result) = len + VARHDRSZ;
+ memcpy(VARDATA(result), s, len);
+
+ pfree(s);
+
+ PG_RETURN_TEXT_P(result);
+}
+
+
/* ----------------------------------------------------------------------
*
* Aggregate functions
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.75 2002/09/04 20:31:28 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.76 2002/09/18 21:35:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* regprocin - converts "proname" to proc OID
*
- * We also accept a numeric OID, mostly for historical reasons.
+ * We also accept a numeric OID, for symmetry with the output routine.
*
* '-' signifies unknown (OID 0). In all other cases, the input must
* match an existing pg_proc entry.
pro_name_or_oid[0] <= '9' &&
strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
{
- Oid searchOid;
-
- searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+ result = DatumGetObjectId(DirectFunctionCall1(oidin,
CStringGetDatum(pro_name_or_oid)));
- result = (RegProcedure) GetSysCacheOid(PROCOID,
- ObjectIdGetDatum(searchOid),
- 0, 0, 0);
- if (!RegProcedureIsValid(result))
- elog(ERROR, "No procedure with oid %s", pro_name_or_oid);
PG_RETURN_OID(result);
}
/*
* regprocedurein - converts "proname(args)" to proc OID
*
- * We also accept a numeric OID, mostly for historical reasons.
+ * We also accept a numeric OID, for symmetry with the output routine.
*
* '-' signifies unknown (OID 0). In all other cases, the input must
* match an existing pg_proc entry.
pro_name_or_oid[0] <= '9' &&
strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
{
- Oid searchOid;
-
- searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+ result = DatumGetObjectId(DirectFunctionCall1(oidin,
CStringGetDatum(pro_name_or_oid)));
- result = (RegProcedure) GetSysCacheOid(PROCOID,
- ObjectIdGetDatum(searchOid),
- 0, 0, 0);
- if (!RegProcedureIsValid(result))
- elog(ERROR, "No procedure with oid %s", pro_name_or_oid);
PG_RETURN_OID(result);
}
/*
* regoperin - converts "oprname" to operator OID
*
- * We also accept a numeric OID, mostly for historical reasons.
+ * We also accept a numeric OID, for symmetry with the output routine.
*
* '0' signifies unknown (OID 0). In all other cases, the input must
* match an existing pg_operator entry.
opr_name_or_oid[0] <= '9' &&
strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
{
- Oid searchOid;
-
- searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+ result = DatumGetObjectId(DirectFunctionCall1(oidin,
CStringGetDatum(opr_name_or_oid)));
- result = GetSysCacheOid(OPEROID,
- ObjectIdGetDatum(searchOid),
- 0, 0, 0);
- if (!OidIsValid(result))
- elog(ERROR, "No operator with oid %s", opr_name_or_oid);
PG_RETURN_OID(result);
}
/*
* regoperatorin - converts "oprname(args)" to operator OID
*
- * We also accept a numeric OID, mostly for historical reasons.
+ * We also accept a numeric OID, for symmetry with the output routine.
*
* '0' signifies unknown (OID 0). In all other cases, the input must
* match an existing pg_operator entry.
opr_name_or_oid[0] <= '9' &&
strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
{
- Oid searchOid;
-
- searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+ result = DatumGetObjectId(DirectFunctionCall1(oidin,
CStringGetDatum(opr_name_or_oid)));
- result = GetSysCacheOid(OPEROID,
- ObjectIdGetDatum(searchOid),
- 0, 0, 0);
- if (!OidIsValid(result))
- elog(ERROR, "No operator with oid %s", opr_name_or_oid);
PG_RETURN_OID(result);
}
/*
* regclassin - converts "classname" to class OID
*
- * We also accept a numeric OID, mostly for historical reasons.
+ * We also accept a numeric OID, for symmetry with the output routine.
*
* '-' signifies unknown (OID 0). In all other cases, the input must
* match an existing pg_class entry.
class_name_or_oid[0] <= '9' &&
strspn(class_name_or_oid, "0123456789") == strlen(class_name_or_oid))
{
- Oid searchOid;
-
- searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+ result = DatumGetObjectId(DirectFunctionCall1(oidin,
CStringGetDatum(class_name_or_oid)));
- result = GetSysCacheOid(RELOID,
- ObjectIdGetDatum(searchOid),
- 0, 0, 0);
- if (!OidIsValid(result))
- elog(ERROR, "No class with oid %s", class_name_or_oid);
PG_RETURN_OID(result);
}
/*
* regtypein - converts "typename" to type OID
*
- * We also accept a numeric OID, mostly for historical reasons.
+ * We also accept a numeric OID, for symmetry with the output routine.
*
* '-' signifies unknown (OID 0). In all other cases, the input must
* match an existing pg_type entry.
typ_name_or_oid[0] <= '9' &&
strspn(typ_name_or_oid, "0123456789") == strlen(typ_name_or_oid))
{
- Oid searchOid;
-
- searchOid = DatumGetObjectId(DirectFunctionCall1(oidin,
+ result = DatumGetObjectId(DirectFunctionCall1(oidin,
CStringGetDatum(typ_name_or_oid)));
- result = GetSysCacheOid(TYPEOID,
- ObjectIdGetDatum(searchOid),
- 0, 0, 0);
- if (!OidIsValid(result))
- elog(ERROR, "No type with oid %s", typ_name_or_oid);
PG_RETURN_OID(result);
}
* back to source text
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.121 2002/09/04 20:31:28 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.122 2002/09/18 21:35:23 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
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);
static void get_sublink_expr(Node *node, deparse_context *context);
static void get_from_clause(Query *query, deparse_context *context);
sep = ", ";
colno++;
- /* Do NOT use get_tle_expr here; see its comments! */
get_rule_expr(tle->expr, context);
/*
appendStringInfo(buf, sep);
sep = ", ";
- get_tle_expr(tle, context);
+ get_rule_expr(tle->expr, context);
}
appendStringInfoChar(buf, ')');
}
if (!tleIsArrayAssign(tle))
appendStringInfo(buf, "%s = ",
quote_identifier(tle->resdom->resname));
- get_tle_expr(tle, context);
+ get_rule_expr(tle->expr, context);
}
/* Add the FROM clause if needed */
case T_RelabelType:
{
RelabelType *relabel = (RelabelType *) node;
+ Node *arg = relabel->arg;
- appendStringInfoChar(buf, '(');
- get_rule_expr(relabel->arg, context);
- appendStringInfo(buf, ")::%s",
+ if (relabel->relabelformat == COERCE_IMPLICIT_CAST)
+ {
+ /* don't show an implicit cast */
+ get_rule_expr(arg, context);
+ }
+ else
+ {
+ /*
+ * Strip off any type coercions on the input, so we don't
+ * print redundancies like x::bpchar::character(8).
+ *
+ * XXX Are there any cases where this is a bad idea?
+ */
+ arg = strip_type_coercion(arg, relabel->resulttype);
+
+ appendStringInfoChar(buf, '(');
+ get_rule_expr(arg, context);
+ appendStringInfo(buf, ")::%s",
format_type_with_typemod(relabel->resulttype,
- relabel->resulttypmod));
+ relabel->resulttypmod));
+ }
}
break;
StringInfo buf = context->buf;
Func *func = (Func *) (expr->oper);
Oid funcoid = func->funcid;
- int32 coercedTypmod;
Oid argtypes[FUNC_MAX_ARGS];
int nargs;
List *l;
char *sep;
/*
- * Check to see if function is a length-coercion function for some
- * datatype. If so, display the operation as a type cast.
+ * If the function call came from an implicit coercion, then just show
+ * the first argument.
+ */
+ if (func->funcformat == COERCE_IMPLICIT_CAST)
+ {
+ get_rule_expr((Node *) lfirst(expr->args), context);
+ return;
+ }
+
+ /*
+ * If the function call came from an explicit cast, then show
+ * the first argument plus an explicit cast operation.
*/
- if (exprIsLengthCoercion((Node *) expr, &coercedTypmod))
+ if (func->funcformat == COERCE_EXPLICIT_CAST)
{
Node *arg = lfirst(expr->args);
- Oid rettype = get_func_rettype(funcoid);
- char *typdesc;
+ Oid rettype = expr->typeOid;
+ int32 coercedTypmod;
+
+ /* Get the typmod if this is a length-coercion function */
+ (void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
/*
* Strip off any type coercions on the input, so we don't print
appendStringInfoChar(buf, '(');
get_rule_expr(arg, context);
-
- /*
- * Show typename with appropriate length decoration. Note that
- * since exprIsLengthCoercion succeeded, the function's output
- * type is the right thing to report. Also note we don't need to
- * quote the result of format_type_with_typemod: it takes care of
- * double-quoting any identifier that needs it.
- */
- typdesc = format_type_with_typemod(rettype, coercedTypmod);
- appendStringInfo(buf, ")::%s", typdesc);
- pfree(typdesc);
+ appendStringInfo(buf, ")::%s",
+ format_type_with_typemod(rettype, coercedTypmod));
return;
}
/*
* strip_type_coercion
- * Strip any type coercions at the top of the given expression tree,
- * as long as they are coercions to the given datatype.
+ * Strip any type coercion at the top of the given expression tree,
+ * if it is a coercion 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 there is
- * a cast declared that uses it.
+ * We use this to avoid printing two levels of coercion in situations where
+ * the expression tree has a length-coercion node atop a type-coercion node.
*
- * XXX It'd be better if the parsetree retained some explicit indication
- * of the coercion, so we didn't need these heuristics.
+ * Note: avoid stripping a length-coercion node, since two successive
+ * coercions to different lengths aren't a no-op.
*/
static Node *
strip_type_coercion(Node *expr, Oid resultType)
if (expr == NULL || exprType(expr) != resultType)
return expr;
- if (IsA(expr, RelabelType))
- return strip_type_coercion(((RelabelType *) expr)->arg, resultType);
+ if (IsA(expr, RelabelType) &&
+ ((RelabelType *) expr)->resulttypmod == -1)
+ return ((RelabelType *) expr)->arg;
if (IsA(expr, Expr) &&
((Expr *) expr)->opType == FUNC_EXPR)
{
- Func *func;
- HeapTuple procTuple;
- HeapTuple castTuple;
- Form_pg_proc procStruct;
- Form_pg_cast castStruct;
+ Func *func = (Func *) (((Expr *) expr)->oper);
- func = (Func *) (((Expr *) expr)->oper);
Assert(IsA(func, Func));
- if (length(((Expr *) expr)->args) != 1)
- return expr;
- /* Lookup the function in pg_proc */
- procTuple = SearchSysCache(PROCOID,
- ObjectIdGetDatum(func->funcid),
- 0, 0, 0);
- if (!HeapTupleIsValid(procTuple))
- 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 */
- if (procStruct->pronargs != 1 ||
- procStruct->prorettype != resultType)
- {
- ReleaseSysCache(procTuple);
- return expr;
- }
- /* 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);
- return expr;
- }
- /* It must also be an implicit cast. */
- castStruct = (Form_pg_cast) GETSTRUCT(castTuple);
- if (!castStruct->castimplicit)
- {
- ReleaseSysCache(procTuple);
- ReleaseSysCache(castTuple);
+ if (func->funcformat != COERCE_EXPLICIT_CAST &&
+ func->funcformat != COERCE_IMPLICIT_CAST)
+ return expr; /* don't absorb into upper coercion */
+
+ if (exprIsLengthCoercion(expr, NULL))
return expr;
- }
- /* Okay, it is indeed a type-coercion function */
- ReleaseSysCache(procTuple);
- ReleaseSysCache(castTuple);
- return strip_type_coercion(lfirst(((Expr *) expr)->args), resultType);
+
+ return (Node *) lfirst(((Expr *) expr)->args);
}
return expr;
}
-/* ----------
- * get_tle_expr
- *
- * In an INSERT or UPDATE targetlist item, the parser may have inserted
- * a length-coercion function call to coerce the value to the right
- * length for the target column. We want to suppress the output of
- * that function call, otherwise dump/reload/dump... would blow up the
- * expression by adding more and more layers of length-coercion calls.
- *
- * As of 7.0, this hack is no longer absolutely essential, because the parser
- * is now smart enough not to add a redundant length coercion function call.
- * But we still suppress the function call just for neatness of displayed
- * rules.
- *
- * Note that this hack must NOT be applied to SELECT targetlist items;
- * any length coercion appearing there is something the user actually wrote.
- * ----------
- */
-static void
-get_tle_expr(TargetEntry *tle, deparse_context *context)
-{
- Expr *expr = (Expr *) (tle->expr);
- int32 coercedTypmod;
-
- /*
- * If top level is a length coercion to the correct length, suppress
- * it; else dump the expression normally.
- */
- if (tle->resdom->restypmod >= 0 &&
- exprIsLengthCoercion((Node *) expr, &coercedTypmod) &&
- coercedTypmod == tle->resdom->restypmod)
- get_rule_expr((Node *) lfirst(expr->args), context);
- else
- get_rule_expr(tle->expr, context);
-}
-
-
/* ----------
* get_const_expr
*
Form_pg_type typeStruct;
char *extval;
char *valptr;
+ bool isfloat = false;
+ bool needlabel;
if (constval->constisnull)
{
* NaN, so we need not get too crazy about pattern
* matching here.
*/
- if (strspn(extval, "0123456789 +-eE.") == strlen(extval))
+ if (strspn(extval, "0123456789+-eE.") == strlen(extval))
+ {
appendStringInfo(buf, extval);
+ if (strcspn(extval, "eE.") != strlen(extval))
+ isfloat = true; /* it looks like a float */
+ }
else
appendStringInfo(buf, "'%s'", extval);
}
pfree(extval);
+ /*
+ * Append ::typename unless the constant will be implicitly typed as
+ * the right type when it is read in. XXX this code has to be kept
+ * in sync with the behavior of the parser, especially make_const.
+ */
switch (constval->consttype)
{
case BOOLOID:
case INT4OID:
- case FLOAT8OID:
case UNKNOWNOID:
/* These types can be left unlabeled */
+ needlabel = false;
+ break;
+ case NUMERICOID:
+ /* Float-looking constants will be typed as numeric */
+ needlabel = !isfloat;
break;
default:
- appendStringInfo(buf, "::%s",
- format_type_with_typemod(constval->consttype,
- -1));
+ needlabel = true;
break;
}
+ if (needlabel)
+ appendStringInfo(buf, "::%s",
+ format_type_with_typemod(constval->consttype, -1));
ReleaseSysCache(typetup);
}
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/varbit.c,v 1.25 2002/09/04 20:31:29 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/varbit.c,v 1.26 2002/09/18 21:35:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* data section -- private data section for the bits data structures
* bitlength -- length of the bit string in bits
* bitdata -- bit string, most significant byte first
+ *
+ * The length of the bitdata vector should always be exactly as many
+ * bytes as are needed for the given bitlength. If the bitlength is
+ * not a multiple of 8, the extra low-order padding bits of the last
+ * byte must be zeroes.
*----------
*/
len = VARBITTOTALLEN(atttypmod);
result = (VarBit *) palloc(len);
/* set to 0 so that *r is always initialised and string is zero-padded */
- memset(result, 0, len);
+ MemSet(result, 0, len);
VARATT_SIZEP(result) = len;
VARBITLEN(result) = atttypmod;
/* bit()
* Converts a bit() type to a specific internal length.
* len is the bitlength specified in the column definition.
+ *
+ * If doing implicit cast, raise error when source data is wrong length.
+ * If doing explicit cast, silently truncate or zero-pad to specified length.
*/
Datum
bit(PG_FUNCTION_ARGS)
{
VarBit *arg = PG_GETARG_VARBIT_P(0);
int32 len = PG_GETARG_INT32(1);
+ bool isExplicit = PG_GETARG_BOOL(2);
+ VarBit *result;
+ int rlen;
+ int ipad;
+ bits8 mask;
/* No work if typmod is invalid or supplied data matches it already */
if (len <= 0 || len == VARBITLEN(arg))
PG_RETURN_VARBIT_P(arg);
- else
+
+ if (!isExplicit)
elog(ERROR, "Bit string length %d does not match type BIT(%d)",
VARBITLEN(arg), len);
- return 0; /* quiet compiler */
-}
-/* _bit()
- * Converts an array of bit() elements to a specific internal length.
- * len is the bitlength specified in the column definition.
- */
-Datum
-_bit(PG_FUNCTION_ARGS)
-{
- ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
- int32 len = PG_GETARG_INT32(1);
- FunctionCallInfoData locfcinfo;
+ rlen = VARBITTOTALLEN(len);
+ result = (VarBit *) palloc(rlen);
+ /* set to 0 so that string is zero-padded */
+ MemSet(result, 0, rlen);
+ VARATT_SIZEP(result) = rlen;
+ VARBITLEN(result) = len;
+
+ memcpy(VARBITS(result), VARBITS(arg),
+ Min(VARBITBYTES(result), VARBITBYTES(arg)));
/*
- * Since bit() is a built-in function, we should only need to look it
- * up once per run.
+ * Make sure last byte is zero-padded if needed. This is useless but
+ * safe if source data was shorter than target length (we assume the
+ * last byte of the source data was itself correctly zero-padded).
*/
- static FmgrInfo bit_finfo;
-
- if (bit_finfo.fn_oid == InvalidOid)
- fmgr_info_cxt(F_BIT, &bit_finfo, TopMemoryContext);
-
- MemSet(&locfcinfo, 0, sizeof(locfcinfo));
- locfcinfo.flinfo = &bit_finfo;
- locfcinfo.nargs = 2;
- /* We assume we are "strict" and need not worry about null inputs */
- locfcinfo.arg[0] = PointerGetDatum(v);
- locfcinfo.arg[1] = Int32GetDatum(len);
+ ipad = VARBITPAD(result);
+ if (ipad > 0)
+ {
+ mask = BITMASK << ipad;
+ *(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
+ }
- return array_map(&locfcinfo, BITOID, BITOID);
+ PG_RETURN_VARBIT_P(result);
}
/*
len = VARBITTOTALLEN(bitlen);
result = (VarBit *) palloc(len);
/* set to 0 so that *r is always initialised and string is zero-padded */
- memset(result, 0, len);
+ MemSet(result, 0, len);
VARATT_SIZEP(result) = len;
VARBITLEN(result) = Min(bitlen, atttypmod);
/* varbit()
* Converts a varbit() type to a specific internal length.
* len is the maximum bitlength specified in the column definition.
+ *
+ * If doing implicit cast, raise error when source data is too long.
+ * If doing explicit cast, silently truncate to max length.
*/
Datum
varbit(PG_FUNCTION_ARGS)
{
VarBit *arg = PG_GETARG_VARBIT_P(0);
int32 len = PG_GETARG_INT32(1);
+ bool isExplicit = PG_GETARG_BOOL(2);
VarBit *result;
int rlen;
+ int ipad;
+ bits8 mask;
/* No work if typmod is invalid or supplied data matches it already */
if (len <= 0 || len >= VARBITLEN(arg))
PG_RETURN_VARBIT_P(arg);
- if (len < VARBITLEN(arg))
+ if (!isExplicit)
elog(ERROR, "Bit string too long for type BIT VARYING(%d)", len);
rlen = VARBITTOTALLEN(len);
memcpy(VARBITS(result), VARBITS(arg), VARBITBYTES(result));
- PG_RETURN_VARBIT_P(result);
-}
-
-/* _varbit()
- * Converts an array of bit() elements to a specific internal length.
- * len is the maximum bitlength specified in the column definition.
- */
-Datum
-_varbit(PG_FUNCTION_ARGS)
-{
- ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
- int32 len = PG_GETARG_INT32(1);
- FunctionCallInfoData locfcinfo;
-
- /*
- * Since varbit() is a built-in function, we should only need to look
- * it up once per run.
- */
- static FmgrInfo varbit_finfo;
-
- if (varbit_finfo.fn_oid == InvalidOid)
- fmgr_info_cxt(F_VARBIT, &varbit_finfo, TopMemoryContext);
-
- MemSet(&locfcinfo, 0, sizeof(locfcinfo));
- locfcinfo.flinfo = &varbit_finfo;
- locfcinfo.nargs = 2;
- /* We assume we are "strict" and need not worry about null inputs */
- locfcinfo.arg[0] = PointerGetDatum(v);
- locfcinfo.arg[1] = Int32GetDatum(len);
+ /* Make sure last byte is zero-padded if needed */
+ ipad = VARBITPAD(result);
+ if (ipad > 0)
+ {
+ mask = BITMASK << ipad;
+ *(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
+ }
- return array_map(&locfcinfo, VARBITOID, VARBITOID);
+ PG_RETURN_VARBIT_P(result);
}
/* If we shifted all the bits out, return an all-zero string */
if (shft >= VARBITLEN(arg))
{
- memset(r, 0, VARBITBYTES(arg));
+ MemSet(r, 0, VARBITBYTES(arg));
PG_RETURN_VARBIT_P(result);
}
/* Special case: we can do a memcpy */
len = VARBITBYTES(arg) - byte_shift;
memcpy(r, p, len);
- memset(r + len, 0, byte_shift);
+ MemSet(r + len, 0, byte_shift);
}
else
{
/* If we shifted all the bits out, return an all-zero string */
if (shft >= VARBITLEN(arg))
{
- memset(r, 0, VARBITBYTES(arg));
+ MemSet(r, 0, VARBITBYTES(arg));
PG_RETURN_VARBIT_P(result);
}
p = VARBITS(arg);
/* Set the first part of the result to 0 */
- memset(r, 0, byte_shift);
+ MemSet(r, 0, byte_shift);
r += byte_shift;
if (ishift == 0)
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.94 2002/09/04 20:31:29 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.95 2002/09/18 21:35:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
- * Converts a CHARACTER type to the specified size. maxlen is the new
- * declared length plus VARHDRSZ bytes. Truncation
- * rules see bpcharin() above.
+ * Converts a CHARACTER type to the specified size.
+ *
+ * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes.
+ * isExplicit is true if this is for an explicit cast to char(N).
+ *
+ * Truncation rules: for an explicit cast, silently truncate to the given
+ * length; for an implicit cast, raise error unless extra characters are
+ * all spaces. (This is sort-of per SQL: the spec would actually have us
+ * raise a "completion condition" for the explicit cast case, but Postgres
+ * hasn't got such a concept.)
*/
Datum
bpchar(PG_FUNCTION_ARGS)
{
BpChar *source = PG_GETARG_BPCHAR_P(0);
int32 maxlen = PG_GETARG_INT32(1);
+ bool isExplicit = PG_GETARG_BOOL(2);
BpChar *result;
int32 len;
char *r;
char *s;
int i;
-
int charlen; /* number of charcters in the input string
* + VARHDRSZ */
charlen = pg_mbstrlen_with_len(VARDATA(source), len - VARHDRSZ) + VARHDRSZ;
/* No work if typmod is invalid or supplied data matches it already */
- if (maxlen < (int32) VARHDRSZ || len == maxlen)
+ if (maxlen < (int32) VARHDRSZ || charlen == maxlen)
PG_RETURN_BPCHAR_P(source);
if (charlen > maxlen)
maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ,
maxlen - VARHDRSZ) + VARHDRSZ;
- for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++)
- if (*(VARDATA(source) + i) != ' ')
- elog(ERROR, "value too long for type character(%d)",
- maxlen - VARHDRSZ);
+ if (!isExplicit)
+ {
+ for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++)
+ if (*(VARDATA(source) + i) != ' ')
+ elog(ERROR, "value too long for type character(%d)",
+ maxlen - VARHDRSZ);
+ }
len = maxmblen;
}
-/* _bpchar()
- * Converts an array of char() elements to a specific internal length.
- * len is the length specified in () plus VARHDRSZ bytes.
- */
-Datum
-_bpchar(PG_FUNCTION_ARGS)
-{
- ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
- int32 len = PG_GETARG_INT32(1);
- FunctionCallInfoData locfcinfo;
-
- /*
- * Since bpchar() is a built-in function, we should only need to look
- * it up once per run.
- */
- static FmgrInfo bpchar_finfo;
-
- if (bpchar_finfo.fn_oid == InvalidOid)
- fmgr_info_cxt(F_BPCHAR, &bpchar_finfo, TopMemoryContext);
-
- MemSet(&locfcinfo, 0, sizeof(locfcinfo));
- locfcinfo.flinfo = &bpchar_finfo;
- locfcinfo.nargs = 2;
- /* We assume we are "strict" and need not worry about null inputs */
- locfcinfo.arg[0] = PointerGetDatum(v);
- locfcinfo.arg[1] = Int32GetDatum(len);
-
- return array_map(&locfcinfo, BPCHAROID, BPCHAROID);
-}
-
-
/* char_bpchar()
* Convert char to bpchar(1).
*/
* Note that atttypmod is regarded as the number of characters, which
* is not necessarily the same as the number of bytes.
*
- * If the C string is too long,
- * raise an error, unless the extra characters are spaces, in which
- * case they're truncated. (per SQL) */
+ * If the C string is too long, raise an error, unless the extra characters
+ * are spaces, in which case they're truncated. (per SQL)
+ */
Datum
varcharin(PG_FUNCTION_ARGS)
{
/*
- * Converts a VARCHAR type to the specified size. maxlen is the new
- * declared length plus VARHDRSZ bytes. Truncation
- * rules see varcharin() above.
+ * Converts a VARCHAR type to the specified size.
+ *
+ * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes.
+ * isExplicit is true if this is for an explicit cast to varchar(N).
+ *
+ * Truncation rules: for an explicit cast, silently truncate to the given
+ * length; for an implicit cast, raise error unless extra characters are
+ * all spaces. (This is sort-of per SQL: the spec would actually have us
+ * raise a "completion condition" for the explicit cast case, but Postgres
+ * hasn't got such a concept.)
*/
Datum
varchar(PG_FUNCTION_ARGS)
{
VarChar *source = PG_GETARG_VARCHAR_P(0);
int32 maxlen = PG_GETARG_INT32(1);
+ bool isExplicit = PG_GETARG_BOOL(2);
VarChar *result;
int32 len;
+ size_t maxmblen;
int i;
len = VARSIZE(source);
/* only reach here if string is too long... */
- {
- size_t maxmblen;
-
- /* truncate multibyte string preserving multibyte boundary */
- maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ,
- maxlen - VARHDRSZ) + VARHDRSZ;
+ /* truncate multibyte string preserving multibyte boundary */
+ maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ,
+ maxlen - VARHDRSZ);
- for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++)
+ if (!isExplicit)
+ {
+ for (i = maxmblen; i < len - VARHDRSZ; i++)
if (*(VARDATA(source) + i) != ' ')
elog(ERROR, "value too long for type character varying(%d)",
maxlen - VARHDRSZ);
-
- len = maxmblen;
}
+ len = maxmblen + VARHDRSZ;
result = palloc(len);
VARATT_SIZEP(result) = len;
memcpy(VARDATA(result), VARDATA(source), len - VARHDRSZ);
}
-/* _varchar()
- * Converts an array of varchar() elements to the specified size.
- * len is the length specified in () plus VARHDRSZ bytes.
- */
-Datum
-_varchar(PG_FUNCTION_ARGS)
-{
- ArrayType *v = PG_GETARG_ARRAYTYPE_P(0);
- int32 len = PG_GETARG_INT32(1);
- FunctionCallInfoData locfcinfo;
-
- /*
- * Since varchar() is a built-in function, we should only need to look
- * it up once per run.
- */
- static FmgrInfo varchar_finfo;
-
- if (varchar_finfo.fn_oid == InvalidOid)
- fmgr_info_cxt(F_VARCHAR, &varchar_finfo, TopMemoryContext);
-
- MemSet(&locfcinfo, 0, sizeof(locfcinfo));
- locfcinfo.flinfo = &varchar_finfo;
- locfcinfo.nargs = 2;
- /* We assume we are "strict" and need not worry about null inputs */
- locfcinfo.arg[0] = PointerGetDatum(v);
- locfcinfo.arg[1] = Int32GetDatum(len);
-
- return array_map(&locfcinfo, VARCHAROID, VARCHAROID);
-}
-
-
-
/*****************************************************************************
* Exported functions
*****************************************************************************/
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.83 2002/09/04 20:31:30 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/cache/lsyscache.c,v 1.84 2002/09/18 21:35:23 tgl Exp $
*
* NOTES
* Eventually, the index information should go through here, too.
return typid;
}
-/*
- * getBaseTypeMod
- * If the given type is a domain, return the typmod it applies to
- * its base type; otherwise return the specified original typmod.
- */
-int32
-getBaseTypeMod(Oid typid, int32 typmod)
-{
- /*
- * We loop to find the bottom base type in a stack of domains.
- */
- for (;;)
- {
- HeapTuple tup;
- Form_pg_type typTup;
-
- tup = SearchSysCache(TYPEOID,
- ObjectIdGetDatum(typid),
- 0, 0, 0);
- if (!HeapTupleIsValid(tup))
- elog(ERROR, "getBaseTypeMod: failed to lookup type %u", typid);
- typTup = (Form_pg_type) GETSTRUCT(tup);
- if (typTup->typtype != 'd')
- {
- /* Not a domain, so done */
- ReleaseSysCache(tup);
- break;
- }
-
- /*
- * The typmod applied to a domain should always be -1.
- *
- * We substitute the domain's typmod as we switch attention to the
- * base type.
- */
- Assert(typmod < 0);
-
- typid = typTup->typbasetype;
- typmod = typTup->typtypmod;
- ReleaseSysCache(tup);
- }
-
- return typmod;
-}
-
/*
* get_typavgwidth
*
# 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.173 2002/09/05 19:56:57 tgl Exp $
+# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.174 2002/09/18 21:35:23 tgl Exp $
#
#-------------------------------------------------------------------------
# Create pg_conversion and support functions
$ECHO_N "creating conversions... "$ECHO_C
-cat $datadir/conversion_create.sql | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
+grep -v '^DROP CONVERSION' $datadir/conversion_create.sql | "$PGPATH"/postgres $PGSQL_OPT template1 > /dev/null || exit_nicely
echo "ok"
# Set most system catalogs and built-in functions as world-accessible.
-- We use the OID of template0 to determine lastsysoid
UPDATE pg_database SET datlastsysoid = \
- (SELECT oid - 1 FROM pg_database WHERE datname = 'template0');
+ (SELECT oid::int4 - 1 FROM pg_database WHERE datname = 'template0');
-- Explicitly revoke public create-schema and create-temp-table privileges
-- in template1 and template0; else the latter would be on by default
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.298 2002/09/07 16:14:33 petere Exp $
+ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.299 2002/09/18 21:35:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
selectSourceSchema("pg_catalog");
if (fout->remoteVersion >= 70300)
- appendPQExpBuffer(query, "SELECT oid, castsource, casttarget, castfunc, castimplicit FROM pg_cast ORDER BY 1,2,3;");
+ appendPQExpBuffer(query, "SELECT oid, castsource, casttarget, castfunc, castcontext 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;");
char *castsource = PQgetvalue(res, i, 1);
char *casttarget = PQgetvalue(res, i, 2);
char *castfunc = PQgetvalue(res, i, 3);
- char *castimplicit = PQgetvalue(res, i, 4);
+ char *castcontext = PQgetvalue(res, i, 4);
int fidx = -1;
const char *((*deps)[]);
appendPQExpBuffer(defqry, "WITH FUNCTION %s",
format_function_signature(&finfo[fidx], true));
- if (strcmp(castimplicit, "t") == 0)
+ if (strcmp(castcontext, "a") == 0)
appendPQExpBuffer(defqry, " AS ASSIGNMENT");
+ else if (strcmp(castcontext, "i") == 0)
+ appendPQExpBuffer(defqry, " AS IMPLICIT");
appendPQExpBuffer(defqry, ";\n");
ArchiveEntry(fout, castoid,
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: catversion.h,v 1.158 2002/09/02 06:24:15 momjian Exp $
+ * $Id: catversion.h,v 1.159 2002/09/18 21:35:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200209021
+#define CATALOG_VERSION_NO 200209181
#endif
*
* Copyright (c) 2002, PostgreSQL Global Development Group
*
- * $Id: pg_cast.h,v 1.3 2002/09/04 20:31:37 momjian Exp $
+ * $Id: pg_cast.h,v 1.4 2002/09/18 21:35:23 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
{
Oid castsource; /* source datatype for cast */
Oid casttarget; /* destination datatype for cast */
- Oid castfunc; /* 0 = binary compatible */
- bool castimplicit; /* allow implicit casting? */
+ Oid castfunc; /* cast function; 0 = binary coercible */
+ char castcontext; /* contexts in which cast can be used */
} FormData_pg_cast;
typedef FormData_pg_cast *Form_pg_cast;
+/*
+ * The allowable values for pg_cast.castcontext are specified by this enum.
+ * Since castcontext is stored as a "char", we use ASCII codes for human
+ * convenience in reading the table. Note that internally to the backend,
+ * these values are converted to the CoercionContext enum (see primnodes.h),
+ * which is defined to sort in a convenient order; the ASCII codes don't
+ * have to sort in any special order.
+ */
+
+typedef enum CoercionCodes
+{
+ COERCION_CODE_IMPLICIT = 'i', /* coercion in context of expression */
+ COERCION_CODE_ASSIGNMENT = 'a', /* coercion in context of assignment */
+ COERCION_CODE_EXPLICIT = 'e' /* explicit cast operation */
+} CoercionCodes;
+
+
+/* ----------------
+ * compiler constants for 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
+#define Anum_pg_cast_castcontext 4
/* ----------------
* initial contents of pg_cast
*/
/*
- * binary compatible casts
+ * Numeric category: implicit casts are allowed in the direction
+ * int2->int4->int8->numeric->float4->float8, while casts in the
+ * reverse direction are assignment-only.
*/
-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 ));
+DATA(insert ( 20 21 714 a ));
+DATA(insert ( 20 23 480 a ));
+DATA(insert ( 20 700 652 i ));
+DATA(insert ( 20 701 482 i ));
+DATA(insert ( 20 1700 1781 i ));
+DATA(insert ( 21 20 754 i ));
+DATA(insert ( 21 23 313 i ));
+DATA(insert ( 21 700 236 i ));
+DATA(insert ( 21 701 235 i ));
+DATA(insert ( 21 1700 1782 i ));
+DATA(insert ( 23 20 481 i ));
+DATA(insert ( 23 21 314 a ));
+DATA(insert ( 23 700 318 i ));
+DATA(insert ( 23 701 316 i ));
+DATA(insert ( 23 1700 1740 i ));
+DATA(insert ( 700 20 653 a ));
+DATA(insert ( 700 21 238 a ));
+DATA(insert ( 700 23 319 a ));
+DATA(insert ( 700 701 311 i ));
+DATA(insert ( 700 1700 1742 a ));
+DATA(insert ( 701 20 483 a ));
+DATA(insert ( 701 21 237 a ));
+DATA(insert ( 701 23 317 a ));
+DATA(insert ( 701 700 312 a ));
+DATA(insert ( 701 1700 1743 a ));
+DATA(insert ( 1700 20 1779 a ));
+DATA(insert ( 1700 21 1783 a ));
+DATA(insert ( 1700 23 1744 a ));
+DATA(insert ( 1700 700 1745 i ));
+DATA(insert ( 1700 701 1746 i ));
/*
- * 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:
+ * OID category: allow implicit conversion from any integral type (including
+ * int8, to support OID literals > 2G) to OID, as well as assignment coercion
+ * from OID to int4 or int8. Similarly for each OID-alias type. Also allow
+ * implicit coercions between OID and each OID-alias type, as well as
+ * regproc<->regprocedure and regoper<->regoperator. (Other coercions
+ * between alias types must pass through OID.)
+ */
+DATA(insert ( 20 26 1287 i ));
+DATA(insert ( 21 26 313 i ));
+DATA(insert ( 23 26 0 i ));
+DATA(insert ( 26 20 1288 a ));
+DATA(insert ( 26 23 0 a ));
+DATA(insert ( 26 24 0 i ));
+DATA(insert ( 24 26 0 i ));
+DATA(insert ( 20 24 1287 i ));
+DATA(insert ( 21 24 313 i ));
+DATA(insert ( 23 24 0 i ));
+DATA(insert ( 24 20 1288 a ));
+DATA(insert ( 24 23 0 a ));
+DATA(insert ( 24 2202 0 i ));
+DATA(insert ( 2202 24 0 i ));
+DATA(insert ( 26 2202 0 i ));
+DATA(insert ( 2202 26 0 i ));
+DATA(insert ( 20 2202 1287 i ));
+DATA(insert ( 21 2202 313 i ));
+DATA(insert ( 23 2202 0 i ));
+DATA(insert ( 2202 20 1288 a ));
+DATA(insert ( 2202 23 0 a ));
+DATA(insert ( 26 2203 0 i ));
+DATA(insert ( 2203 26 0 i ));
+DATA(insert ( 20 2203 1287 i ));
+DATA(insert ( 21 2203 313 i ));
+DATA(insert ( 23 2203 0 i ));
+DATA(insert ( 2203 20 1288 a ));
+DATA(insert ( 2203 23 0 a ));
+DATA(insert ( 2203 2204 0 i ));
+DATA(insert ( 2204 2203 0 i ));
+DATA(insert ( 26 2204 0 i ));
+DATA(insert ( 2204 26 0 i ));
+DATA(insert ( 20 2204 1287 i ));
+DATA(insert ( 21 2204 313 i ));
+DATA(insert ( 23 2204 0 i ));
+DATA(insert ( 2204 20 1288 a ));
+DATA(insert ( 2204 23 0 a ));
+DATA(insert ( 26 2205 0 i ));
+DATA(insert ( 2205 26 0 i ));
+DATA(insert ( 20 2205 1287 i ));
+DATA(insert ( 21 2205 313 i ));
+DATA(insert ( 23 2205 0 i ));
+DATA(insert ( 2205 20 1288 a ));
+DATA(insert ( 2205 23 0 a ));
+DATA(insert ( 26 2206 0 i ));
+DATA(insert ( 2206 26 0 i ));
+DATA(insert ( 20 2206 1287 i ));
+DATA(insert ( 21 2206 313 i ));
+DATA(insert ( 23 2206 0 i ));
+DATA(insert ( 2206 20 1288 a ));
+DATA(insert ( 2206 23 0 a ));
+
+/*
+ * String category: this needs to be tightened up
+ */
+DATA(insert ( 25 1042 0 i ));
+DATA(insert ( 25 1043 0 i ));
+DATA(insert ( 1042 25 0 i ));
+DATA(insert ( 1042 1043 0 i ));
+DATA(insert ( 1043 25 0 i ));
+DATA(insert ( 1043 1042 0 i ));
+DATA(insert ( 18 25 946 i ));
+DATA(insert ( 18 1042 860 i ));
+DATA(insert ( 19 25 406 i ));
+DATA(insert ( 19 1042 408 i ));
+DATA(insert ( 19 1043 1401 i ));
+DATA(insert ( 25 18 944 a ));
+DATA(insert ( 25 19 407 i ));
+DATA(insert ( 1042 19 409 i ));
+DATA(insert ( 1043 19 1400 i ));
+
+/*
+ * Datetime category
+ */
+DATA(insert ( 702 1082 1179 a ));
+DATA(insert ( 702 1083 1364 a ));
+DATA(insert ( 702 1114 2023 i ));
+DATA(insert ( 702 1184 1173 i ));
+DATA(insert ( 703 1186 1177 i ));
+DATA(insert ( 1082 1114 2024 i ));
+DATA(insert ( 1082 1184 1174 i ));
+DATA(insert ( 1083 1186 1370 i ));
+DATA(insert ( 1083 1266 2047 i ));
+DATA(insert ( 1114 702 2030 a ));
+DATA(insert ( 1114 1082 2029 a ));
+DATA(insert ( 1114 1083 1316 a ));
+DATA(insert ( 1114 1184 2028 i ));
+DATA(insert ( 1184 702 1180 a ));
+DATA(insert ( 1184 1082 1178 a ));
+DATA(insert ( 1184 1083 2019 a ));
+DATA(insert ( 1184 1114 2027 a ));
+DATA(insert ( 1184 1266 1388 a ));
+DATA(insert ( 1186 703 1194 a ));
+DATA(insert ( 1186 1083 1419 a ));
+DATA(insert ( 1266 1083 2046 a ));
+/* Cross-category casts between int4 and abstime, reltime */
+DATA(insert ( 23 702 0 e ));
+DATA(insert ( 702 23 0 e ));
+DATA(insert ( 23 703 0 e ));
+DATA(insert ( 703 23 0 e ));
+
+/*
+ * Geometric category
+ */
+DATA(insert ( 601 600 1532 e ));
+DATA(insert ( 602 600 1533 e ));
+DATA(insert ( 602 604 1449 a ));
+DATA(insert ( 603 600 1534 e ));
+DATA(insert ( 603 601 1541 e ));
+DATA(insert ( 603 604 1448 a ));
+DATA(insert ( 603 718 1479 e ));
+DATA(insert ( 604 600 1540 e ));
+DATA(insert ( 604 602 1447 a ));
+DATA(insert ( 604 603 1446 e ));
+DATA(insert ( 604 718 1474 e ));
+DATA(insert ( 718 600 1416 e ));
+DATA(insert ( 718 603 1480 e ));
+DATA(insert ( 718 604 1544 e ));
+
+/*
+ * INET category
+ */
+DATA(insert ( 650 869 0 i ));
+DATA(insert ( 869 650 0 i ));
+
+/*
+ * BitString category
+ */
+DATA(insert ( 1560 1562 0 i ));
+DATA(insert ( 1562 1560 0 i ));
+
+/*
+ * Cross-category casts to and from TEXT
*
- * 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;
+ * For historical reasons, most casts to TEXT are implicit. This is BAD
+ * and should be reined in.
*/
-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 ));
-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 t ));
-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 t ));
-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 ));
+DATA(insert ( 20 25 1289 i ));
+DATA(insert ( 25 20 1290 e ));
+DATA(insert ( 21 25 113 i ));
+DATA(insert ( 25 21 818 e ));
+DATA(insert ( 23 25 112 i ));
+DATA(insert ( 25 23 819 e ));
+DATA(insert ( 26 25 114 i ));
+DATA(insert ( 25 26 817 e ));
+DATA(insert ( 25 650 1714 e ));
+DATA(insert ( 700 25 841 i ));
+DATA(insert ( 25 700 839 e ));
+DATA(insert ( 701 25 840 i ));
+DATA(insert ( 25 701 838 e ));
+DATA(insert ( 829 25 752 e ));
+DATA(insert ( 25 829 767 e ));
+DATA(insert ( 869 25 730 e ));
+DATA(insert ( 25 869 1713 e ));
+DATA(insert ( 1082 25 749 i ));
+DATA(insert ( 25 1082 748 e ));
+DATA(insert ( 1083 25 948 i ));
+DATA(insert ( 25 1083 837 e ));
+DATA(insert ( 1114 25 2034 i ));
+DATA(insert ( 25 1114 2022 e ));
+DATA(insert ( 1184 25 1192 i ));
+DATA(insert ( 25 1184 1191 e ));
+DATA(insert ( 1186 25 1193 i ));
+DATA(insert ( 25 1186 1263 e ));
+DATA(insert ( 1266 25 939 i ));
+DATA(insert ( 25 1266 938 e ));
+DATA(insert ( 1700 25 1688 i ));
+DATA(insert ( 25 1700 1686 e ));
#endif /* PG_CAST_H */
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_operator.h,v 1.109 2002/09/04 20:31:37 momjian Exp $
+ * $Id: pg_operator.h,v 1.110 2002/09/18 21:35:23 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
DATA(insert OID = 1134 ( "<=" PGNSP PGUID b f 701 700 16 1125 1133 0 0 0 0 float84le scalarltsel scalarltjoinsel ));
DATA(insert OID = 1135 ( ">=" PGNSP PGUID b f 701 700 16 1124 1132 0 0 0 0 float84ge scalargtsel scalargtjoinsel ));
-/* int4 vs oid equality --- use oid (unsigned) comparison */
-DATA(insert OID = 1136 ( "=" PGNSP PGUID b t 23 26 16 1137 1656 0 0 0 0 oideq eqsel eqjoinsel ));
-DATA(insert OID = 1137 ( "=" PGNSP PGUID b t 26 23 16 1136 1661 0 0 0 0 oideq eqsel eqjoinsel ));
-
DATA(insert OID = 1158 ( "!" PGNSP PGUID r f 21 0 23 0 0 0 0 0 0 int2fac - - ));
DATA(insert OID = 1175 ( "!!" PGNSP PGUID l f 0 21 23 0 0 0 0 0 0 int2fac - - ));
#define OID_VARCHAR_ICLIKE_OP 1631
DATA(insert OID = 1632 ( "!~~*" PGNSP PGUID b f 1043 25 16 0 1631 0 0 0 0 texticnlike icnlikesel icnlikejoinsel ));
-/* int4 vs oid comparisons --- use oid (unsigned) comparison */
-DATA(insert OID = 1656 ( "<>" PGNSP PGUID b f 23 26 16 1661 1136 0 0 0 0 oidne neqsel neqjoinsel ));
-DATA(insert OID = 1657 ( "<" PGNSP PGUID b f 23 26 16 1663 1660 0 0 0 0 oidlt scalarltsel scalarltjoinsel ));
-DATA(insert OID = 1658 ( ">" PGNSP PGUID b f 23 26 16 1662 1659 0 0 0 0 oidgt scalargtsel scalargtjoinsel ));
-DATA(insert OID = 1659 ( "<=" PGNSP PGUID b f 23 26 16 1665 1658 0 0 0 0 oidle scalarltsel scalarltjoinsel ));
-DATA(insert OID = 1660 ( ">=" PGNSP PGUID b f 23 26 16 1664 1657 0 0 0 0 oidge scalargtsel scalargtjoinsel ));
-DATA(insert OID = 1661 ( "<>" PGNSP PGUID b f 26 23 16 1656 1137 0 0 0 0 oidne neqsel neqjoinsel ));
-DATA(insert OID = 1662 ( "<" PGNSP PGUID b f 26 23 16 1658 1665 0 0 0 0 oidlt scalarltsel scalarltjoinsel ));
-DATA(insert OID = 1663 ( ">" PGNSP PGUID b f 26 23 16 1657 1664 0 0 0 0 oidgt scalargtsel scalargtjoinsel ));
-DATA(insert OID = 1664 ( "<=" PGNSP PGUID b f 26 23 16 1660 1663 0 0 0 0 oidle scalarltsel scalarltjoinsel ));
-DATA(insert OID = 1665 ( ">=" PGNSP PGUID b f 26 23 16 1659 1662 0 0 0 0 oidge scalargtsel scalargtjoinsel ));
+/* regproc comparisons --- use oid (unsigned) comparison */
+DATA(insert OID = 1656 ( "=" PGNSP PGUID b t 24 24 16 1656 1657 1658 1658 1658 1659 oideq eqsel eqjoinsel ));
+DATA(insert OID = 1657 ( "<>" PGNSP PGUID b f 24 24 16 1657 1656 0 0 0 0 oidne neqsel neqjoinsel ));
+DATA(insert OID = 1658 ( "<" PGNSP PGUID b f 24 24 16 1659 1661 0 0 0 0 oidlt scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1659 ( ">" PGNSP PGUID b f 24 24 16 1658 1660 0 0 0 0 oidgt scalargtsel scalargtjoinsel ));
+DATA(insert OID = 1660 ( "<=" PGNSP PGUID b f 24 24 16 1661 1659 0 0 0 0 oidle scalarltsel scalarltjoinsel ));
+DATA(insert OID = 1661 ( ">=" PGNSP PGUID b f 24 24 16 1660 1658 0 0 0 0 oidge scalargtsel scalargtjoinsel ));
/* NUMERIC type - OID's 1700-1799 */
DATA(insert OID = 1751 ( "-" PGNSP PGUID l f 0 1700 1700 0 0 0 0 0 0 numeric_uminus - - ));
* 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.271 2002/09/12 00:21:24 momjian Exp $
+ * $Id: pg_proc.h,v 1.272 2002/09/18 21:35:23 tgl Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
DATA(insert OID = 483 ( int8 PGNSP PGUID 12 f f t f i 1 20 "701" dtoi8 - _null_ ));
DESCR("convert float8 to int8");
+/* OIDS 500 - 599 */
+
+/* OIDS 600 - 699 */
+
+DATA(insert OID = 652 ( float4 PGNSP PGUID 12 f f t f i 1 700 "20" i8tof - _null_ ));
+DESCR("convert int8 to float4");
+DATA(insert OID = 653 ( int8 PGNSP PGUID 12 f f t f i 1 20 "700" ftoi8 - _null_ ));
+DESCR("convert float4 to int8");
+
DATA(insert OID = 714 ( int2 PGNSP PGUID 12 f f t f i 1 21 "20" int82 - _null_ ));
DESCR("convert int8 to int2");
DATA(insert OID = 754 ( int8 PGNSP PGUID 12 f f t f i 1 20 "21" int28 - _null_ ));
DESCR("convert int2 to int8");
-/* OIDS 500 - 599 */
-
-/* OIDS 600 - 699 */
-
DATA(insert OID = 1285 ( int4notin PGNSP PGUID 12 f f t f s 2 16 "23 25" int4notin - _null_ ));
DESCR("not in");
DATA(insert OID = 1286 ( oidnotin PGNSP PGUID 12 f f t f s 2 16 "26 25" oidnotin - _null_ ));
DATA(insert OID = 659 ( namene PGNSP PGUID 12 f f t f i 2 16 "19 19" namene - _null_ ));
DESCR("not equal");
-DATA(insert OID = 668 ( bpchar PGNSP PGUID 12 f f t f i 2 1042 "1042 23" bpchar - _null_ ));
+DATA(insert OID = 668 ( bpchar PGNSP PGUID 12 f f t f i 3 1042 "1042 23 16" bpchar - _null_ ));
DESCR("adjust char() to typmod length");
-DATA(insert OID = 669 ( varchar PGNSP PGUID 12 f f t f i 2 1043 "1043 23" varchar - _null_ ));
+DATA(insert OID = 669 ( varchar PGNSP PGUID 12 f f t f i 3 1043 "1043 23 16" varchar - _null_ ));
DESCR("adjust varchar() to typmod length");
DATA(insert OID = 676 ( mktinterval PGNSP PGUID 12 f f t f i 2 704 "702 702" mktinterval - _null_ ));
DESCR("add");
DATA(insert OID = 1142 ( date_mii PGNSP PGUID 12 f f t f i 2 1082 "1082 23" date_mii - _null_ ));
DESCR("subtract");
-DATA(insert OID = 1143 ( time_in PGNSP PGUID 12 f f t f s 1 1083 "2275" time_in - _null_ ));
+DATA(insert OID = 1143 ( time_in PGNSP PGUID 12 f f t f s 3 1083 "2275 26 23" time_in - _null_ ));
DESCR("(internal)");
DATA(insert OID = 1144 ( time_out PGNSP PGUID 12 f f t f i 1 2275 "1083" time_out - _null_ ));
DESCR("(internal)");
DATA(insert OID = 1149 ( circle_div_pt PGNSP PGUID 12 f f t f i 2 718 "718 600" circle_div_pt - _null_ ));
DESCR("divide");
-DATA(insert OID = 1150 ( timestamptz_in PGNSP PGUID 12 f f t f s 1 1184 "2275" timestamptz_in - _null_ ));
+DATA(insert OID = 1150 ( timestamptz_in PGNSP PGUID 12 f f t f s 3 1184 "2275 26 23" timestamptz_in - _null_ ));
DESCR("(internal)");
DATA(insert OID = 1151 ( timestamptz_out PGNSP PGUID 12 f f t f s 1 2275 "1184" timestamptz_out - _null_ ));
DESCR("(internal)");
DATA(insert OID = 1159 ( timezone PGNSP PGUID 12 f f t f s 2 1114 "25 1184" timestamptz_zone - _null_ ));
DESCR("timestamp at a specified time zone");
-DATA(insert OID = 1160 ( interval_in PGNSP PGUID 12 f f t f s 1 1186 "2275" interval_in - _null_ ));
+DATA(insert OID = 1160 ( interval_in PGNSP PGUID 12 f f t f s 3 1186 "2275 26 23" interval_in - _null_ ));
DESCR("(internal)");
DATA(insert OID = 1161 ( interval_out PGNSP PGUID 12 f f t f i 1 2275 "1186" interval_out - _null_ ));
DESCR("(internal)");
DATA(insert OID = 1281 ( int48div PGNSP PGUID 12 f f t f i 2 20 "23 20" int48div - _null_ ));
DESCR("divide");
-DATA(insert OID = 1288 ( text PGNSP PGUID 12 f f t f i 1 25 "20" int8_text - _null_ ));
+DATA(insert OID = 1287 ( oid PGNSP PGUID 12 f f t f i 1 26 "20" i8tooid - _null_ ));
+DESCR("convert int8 to oid");
+DATA(insert OID = 1288 ( int8 PGNSP PGUID 12 f f t f i 1 20 "26" oidtoi8 - _null_ ));
+DESCR("convert oid to int8");
+
+DATA(insert OID = 1289 ( text PGNSP PGUID 12 f f t f i 1 25 "20" int8_text - _null_ ));
DESCR("convert int8 to text");
-DATA(insert OID = 1289 ( int8 PGNSP PGUID 12 f f t f i 1 20 "25" text_int8 - _null_ ));
+DATA(insert OID = 1290 ( int8 PGNSP PGUID 12 f f t f i 1 20 "25" text_int8 - _null_ ));
DESCR("convert text to int8");
-DATA(insert OID = 1290 ( _bpchar PGNSP PGUID 12 f f t f i 2 1014 "1014 23" _bpchar - _null_ ));
-DESCR("adjust char()[] to typmod length");
-DATA(insert OID = 1291 ( _varchar PGNSP PGUID 12 f f t f i 2 1015 "1015 23" _varchar - _null_ ));
-DESCR("adjust varchar()[] to typmod length");
+DATA(insert OID = 1291 ( array_length_coerce PGNSP PGUID 12 f f t f i 3 2277 "2277 23 16" array_length_coerce - _null_ ));
+DESCR("adjust any array to element typmod length");
DATA(insert OID = 1292 ( tideq PGNSP PGUID 12 f f t f i 2 16 "27 27" tideq - _null_ ));
DESCR("equal");
DATA(insert OID = 1311 ( overlaps PGNSP PGUID 14 f f f f i 4 16 "1083 1186 1083 1083" "select ($1, ($1 + $2)) overlaps ($3, $4)" - _null_ ));
DESCR("SQL92 interval comparison");
-DATA(insert OID = 1312 ( timestamp_in PGNSP PGUID 12 f f t f s 1 1114 "2275" timestamp_in - _null_ ));
+DATA(insert OID = 1312 ( timestamp_in PGNSP PGUID 12 f f t f s 3 1114 "2275 26 23" timestamp_in - _null_ ));
DESCR("(internal)");
DATA(insert OID = 1313 ( timestamp_out PGNSP PGUID 12 f f t f s 1 2275 "1114" timestamp_out - _null_ ));
DESCR("(internal)");
DESCR("print type names of oidvector field");
-DATA(insert OID = 1350 ( timetz_in PGNSP PGUID 12 f f t f s 1 1266 "2275" timetz_in - _null_ ));
+DATA(insert OID = 1350 ( timetz_in PGNSP PGUID 12 f f t f s 3 1266 "2275 26 23" timetz_in - _null_ ));
DESCR("(internal)");
DATA(insert OID = 1351 ( timetz_out PGNSP PGUID 12 f f t f i 1 2275 "1266" timetz_out - _null_ ));
DESCR("(internal)");
DATA(insert OID = 1556 ( npoints PGNSP PGUID 12 f f t f i 1 23 "604" poly_npoints - _null_ ));
DESCR("number of points in polygon");
-DATA(insert OID = 1564 ( bit_in PGNSP PGUID 12 f f t f i 1 1560 "2275" bit_in - _null_ ));
+DATA(insert OID = 1564 ( bit_in PGNSP PGUID 12 f f t f i 3 1560 "2275 26 23" bit_in - _null_ ));
DESCR("(internal)");
DATA(insert OID = 1565 ( bit_out PGNSP PGUID 12 f f t f i 1 2275 "1560" bit_out - _null_ ));
DESCR("(internal)");
DATA(insert OID = 1765 ( setval PGNSP PGUID 12 f f t f v 3 20 "25 20 16" setval_and_iscalled - _null_ ));
DESCR("set sequence value and iscalled status");
-DATA(insert OID = 1579 ( varbit_in PGNSP PGUID 12 f f t f i 1 1562 "2275" varbit_in - _null_ ));
+DATA(insert OID = 1579 ( varbit_in PGNSP PGUID 12 f f t f i 3 1562 "2275 26 23" varbit_in - _null_ ));
DESCR("(internal)");
DATA(insert OID = 1580 ( varbit_out PGNSP PGUID 12 f f t f i 1 2275 "1562" varbit_out - _null_ ));
DESCR("(internal)");
DATA(insert OID = 1618 ( interval_mul PGNSP PGUID 12 f f t f i 2 1186 "1186 701" interval_mul - _null_ ));
DESCR("multiply interval");
-DATA(insert OID = 1619 ( varchar PGNSP PGUID 12 f f t f i 1 1043 "23" int4_text - _null_ ));
-DESCR("convert int4 to varchar");
DATA(insert OID = 1620 ( ascii PGNSP PGUID 12 f f t f i 1 23 "25" ascii - _null_ ));
DESCR("convert first char to int4");
DATA(insert OID = 1622 ( repeat PGNSP PGUID 12 f f t f i 2 25 "25 23" repeat - _null_ ));
DESCR("replicate string int4 times");
-DATA(insert OID = 1623 ( varchar PGNSP PGUID 12 f f t f i 1 1043 "20" int8_text - _null_ ));
-DESCR("convert int8 to varchar");
DATA(insert OID = 1624 ( mul_d_interval PGNSP PGUID 12 f f t f i 2 1186 "701 1186" mul_d_interval - _null_ ));
DATA(insert OID = 1633 ( texticlike PGNSP PGUID 12 f f t f i 2 16 "25 25" texticlike - _null_ ));
DATA(insert OID = 2088 ( split_part PGNSP PGUID 12 f f t f i 3 25 "25 25 23" split_text - _null_ ));
DESCR("split string by field_sep and return field_num");
DATA(insert OID = 2089 ( to_hex PGNSP PGUID 12 f f t f i 1 25 "23" to_hex32 - _null_ ));
-DESCR("convert int32 number to hex");
+DESCR("convert int4 number to hex");
DATA(insert OID = 2090 ( to_hex PGNSP PGUID 12 f f t f i 1 25 "20" to_hex64 - _null_ ));
-DESCR("convert int64 number to hex");
+DESCR("convert int8 number to hex");
/* for character set encoding support */
DATA(insert OID = 1684 ( int4 PGNSP PGUID 12 f f t f i 1 23 "1560" bittoint4 - _null_ ));
DESCR("bitstring to int4");
-DATA(insert OID = 1685 ( bit PGNSP PGUID 12 f f t f i 2 1560 "1560 23" bit - _null_ ));
+DATA(insert OID = 1685 ( bit PGNSP PGUID 12 f f t f i 3 1560 "1560 23 16" bit - _null_ ));
DESCR("adjust bit() to typmod length");
-DATA(insert OID = 1686 ( _bit PGNSP PGUID 12 f f t f i 2 1561 "1561 23" _bit - _null_ ));
-DESCR("adjust bit()[] to typmod length");
-DATA(insert OID = 1687 ( varbit PGNSP PGUID 12 f f t f i 2 1562 "1562 23" varbit - _null_ ));
+DATA(insert OID = 1687 ( varbit PGNSP PGUID 12 f f t f i 3 1562 "1562 23 16" varbit - _null_ ));
DESCR("adjust varbit() to typmod length");
-DATA(insert OID = 1688 ( _varbit PGNSP PGUID 12 f f t f i 2 1563 "1563 23" _varbit - _null_ ));
-DESCR("adjust varbit()[] to typmod length");
DATA(insert OID = 1698 ( position PGNSP PGUID 12 f f t f i 2 23 "1560 1560" bitposition - _null_ ));
DESCR("return position of sub-bitstring");
DATA(insert OID = 1715 ( set_masklen PGNSP PGUID 12 f f t f i 2 869 "869 23" inet_set_masklen - _null_ ));
DESCR("change the netmask of an inet");
+DATA(insert OID = 1686 ( numeric PGNSP PGUID 12 f f t f i 1 1700 "25" text_numeric - _null_ ));
+DESCR("(internal)");
+DATA(insert OID = 1688 ( text PGNSP PGUID 12 f f t f i 1 25 "1700" numeric_text - _null_ ));
+DESCR("(internal)");
+
DATA(insert OID = 1690 ( time_mi_time PGNSP PGUID 12 f f t f i 2 1186 "1083 1083" time_mi_time - _null_ ));
DESCR("minus");
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: makefuncs.h,v 1.40 2002/09/04 20:31:43 momjian Exp $
+ * $Id: makefuncs.h,v 1.41 2002/09/18 21:35:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "nodes/parsenodes.h"
+
extern A_Expr *makeA_Expr(int oper, List *name, Node *lexpr, Node *rexpr);
extern A_Expr *makeSimpleA_Expr(int oper, const char *name,
extern Alias *makeAlias(const char *aliasname, List *colnames);
-extern RelabelType *makeRelabelType(Node *arg, Oid rtype, int32 rtypmod);
+extern RelabelType *makeRelabelType(Node *arg, Oid rtype, int32 rtypmod,
+ CoercionForm rformat);
extern RangeVar *makeRangeVar(char *schemaname, char *relname);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parsenodes.h,v 1.206 2002/09/04 20:31:43 momjian Exp $
+ * $Id: parsenodes.h,v 1.207 2002/09/18 21:35:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
TypeName *sourcetype;
TypeName *targettype;
FuncWithArgs *func;
- bool implicit;
+ CoercionContext context;
} CreateCastStmt;
/* ----------------------
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: primnodes.h,v 1.67 2002/09/04 20:31:44 momjian Exp $
+ * $Id: primnodes.h,v 1.68 2002/09/18 21:35:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* ----------------------------------------------------------------
*/
+/*
+ * CoercionContext - distinguishes the allowed set of type casts
+ *
+ * NB: ordering of the alternatives is significant; later (larger) values
+ * allow more casts than earlier ones.
+ */
+typedef enum CoercionContext
+{
+ COERCION_IMPLICIT, /* coercion in context of expression */
+ COERCION_ASSIGNMENT, /* coercion in context of assignment */
+ COERCION_EXPLICIT /* explicit cast operation */
+} CoercionContext;
+
+/*
+ * CoercionForm - information showing how to display a function-call node
+ */
+typedef enum CoercionForm
+{
+ COERCE_EXPLICIT_CALL, /* display as a function call */
+ COERCE_EXPLICIT_CAST, /* display as an explicit cast */
+ COERCE_IMPLICIT_CAST, /* implicit cast, so hide it */
+ COERCE_DONTCARE /* special case for pathkeys */
+} CoercionForm;
+
/*
* Expr
*/
Oid funcid; /* PG_PROC OID of the function */
Oid funcresulttype; /* PG_TYPE OID of result value */
bool funcretset; /* true if function returns set */
+ CoercionForm funcformat; /* how to display this function call */
FunctionCachePtr func_fcache; /* runtime state, or NULL */
} Func;
Node *arg; /* input expression */
Oid resulttype; /* output type of coercion expression */
int32 resulttypmod; /* output typmod (usually -1) */
+ CoercionForm relabelformat; /* how to display this node */
} RelabelType;
/*-------------------------------------------------------------------------
*
* parse_coerce.h
- *
* Routines for type coercion.
*
+ *
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_coerce.h,v 1.46 2002/09/04 20:31:45 momjian Exp $
+ * $Id: parse_coerce.h,v 1.47 2002/09/18 21:35:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
TIMESPAN_TYPE,
GEOMETRIC_TYPE,
NETWORK_TYPE,
- USER_TYPE,
- MIXED_TYPE
+ USER_TYPE
} CATEGORY;
-extern bool IsBinaryCompatible(Oid type1, Oid type2);
+extern bool IsBinaryCoercible(Oid srctype, Oid targettype);
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,
- bool isExplicit);
-extern Node *coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
- Oid targetTypeId, int32 atttypmod, bool isExplicit);
-extern Node *coerce_type_typmod(ParseState *pstate, Node *node,
- Oid targetTypeId, int32 atttypmod);
-extern Node *coerce_type_constraints(ParseState *pstate, Node *arg,
- Oid typeId, bool applyTypmod);
+extern Node *coerce_to_target_type(Node *expr, Oid exprtype,
+ Oid targettype, int32 targettypmod,
+ CoercionContext ccontext,
+ CoercionForm cformat);
+extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
+ CoercionContext ccontext);
+extern Node *coerce_type(Node *node, Oid inputTypeId, Oid targetTypeId,
+ CoercionContext ccontext, CoercionForm cformat);
+extern Node *coerce_type_constraints(Node *arg, Oid typeId,
+ CoercionForm cformat);
extern Node *coerce_to_boolean(Node *node, const char *constructName);
extern Oid select_common_type(List *typeids, const char *context);
-extern Node *coerce_to_common_type(ParseState *pstate, Node *node,
- Oid targetTypeId,
+extern Node *coerce_to_common_type(Node *node, Oid targetTypeId,
const char *context);
+extern Oid find_typmod_coercion_function(Oid typeId, int *nargs);
+
#endif /* PARSE_COERCE_H */
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_node.h,v 1.31 2002/06/20 20:29:51 momjian Exp $
+ * $Id: parse_node.h,v 1.32 2002/09/18 21:35:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern ArrayRef *transformArraySubscripts(ParseState *pstate,
Node *arrayBase,
Oid arrayType,
+ int32 arrayTypMod,
List *indirection,
bool forceSlice,
Node *assignFrom);
/*-------------------------------------------------------------------------
*
* parse_target.h
- *
+ * handle target lists
*
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_target.h,v 1.26 2002/09/04 20:31:45 momjian Exp $
+ * $Id: parse_target.h,v 1.27 2002/09/18 21:35:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "parser/parse_node.h"
+
extern List *transformTargetList(ParseState *pstate, List *targetlist);
extern TargetEntry *transformTargetEntry(ParseState *pstate,
Node *node, Node *expr,
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,
- bool isExplicit);
extern List *checkInsertTargets(ParseState *pstate, List *cols,
List **attrnos);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: array.h,v 1.34 2002/09/04 20:31:45 momjian Exp $
+ * $Id: array.h,v 1.35 2002/09/18 21:35:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
extern Datum array_in(PG_FUNCTION_ARGS);
extern Datum array_out(PG_FUNCTION_ARGS);
+extern Datum array_length_coerce(PG_FUNCTION_ARGS);
extern Datum array_eq(PG_FUNCTION_ARGS);
extern Datum array_dims(PG_FUNCTION_ARGS);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: builtins.h,v 1.199 2002/09/04 20:31:45 momjian Exp $
+ * $Id: builtins.h,v 1.200 2002/09/18 21:35:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern Datum bpcharin(PG_FUNCTION_ARGS);
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 name_bpchar(PG_FUNCTION_ARGS);
extern Datum bpchar_name(PG_FUNCTION_ARGS);
extern Datum varcharin(PG_FUNCTION_ARGS);
extern Datum varcharout(PG_FUNCTION_ARGS);
extern Datum varchar(PG_FUNCTION_ARGS);
-extern Datum _varchar(PG_FUNCTION_ARGS);
extern Datum varchareq(PG_FUNCTION_ARGS);
extern Datum varcharne(PG_FUNCTION_ARGS);
extern Datum varcharlt(PG_FUNCTION_ARGS);
extern Datum numeric_float8_no_overflow(PG_FUNCTION_ARGS);
extern Datum float4_numeric(PG_FUNCTION_ARGS);
extern Datum numeric_float4(PG_FUNCTION_ARGS);
+extern Datum text_numeric(PG_FUNCTION_ARGS);
+extern Datum numeric_text(PG_FUNCTION_ARGS);
extern Datum numeric_accum(PG_FUNCTION_ARGS);
extern Datum int2_accum(PG_FUNCTION_ARGS);
extern Datum int4_accum(PG_FUNCTION_ARGS);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: int8.h,v 1.34 2002/06/20 20:29:53 momjian Exp $
+ * $Id: int8.h,v 1.35 2002/09/18 21:35:25 tgl Exp $
*
* NOTES
* These data types are supported on all 64-bit architectures, and may
#define INT64_FORMAT "%ld"
#endif
+extern bool scanint8(const char *str, bool errorOK, int64 *result);
+
extern Datum int8in(PG_FUNCTION_ARGS);
extern Datum int8out(PG_FUNCTION_ARGS);
extern Datum i8tod(PG_FUNCTION_ARGS);
extern Datum dtoi8(PG_FUNCTION_ARGS);
+extern Datum i8tof(PG_FUNCTION_ARGS);
+extern Datum ftoi8(PG_FUNCTION_ARGS);
+
+extern Datum i8tooid(PG_FUNCTION_ARGS);
+extern Datum oidtoi8(PG_FUNCTION_ARGS);
+
extern Datum int8_text(PG_FUNCTION_ARGS);
extern Datum text_int8(PG_FUNCTION_ARGS);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: lsyscache.h,v 1.62 2002/09/04 20:31:45 momjian Exp $
+ * $Id: lsyscache.h,v 1.63 2002/09/18 21:35:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern bool getTypeOutputInfo(Oid type, Oid *typOutput, Oid *typElem,
bool *typIsVarlena);
extern Oid getBaseType(Oid typid);
-extern int32 getBaseTypeMod(Oid typid, int32 typmod);
extern int32 get_typavgwidth(Oid typid, int32 typmod);
extern int32 get_attavgwidth(Oid relid, AttrNumber attnum);
extern bool get_attstatsslot(HeapTuple statstuple,
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: varbit.h,v 1.15 2002/08/04 06:33:56 thomas Exp $
+ * $Id: varbit.h,v 1.16 2002/09/18 21:35:25 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern Datum varbit_in(PG_FUNCTION_ARGS);
extern Datum varbit_out(PG_FUNCTION_ARGS);
extern Datum bit(PG_FUNCTION_ARGS);
-extern Datum _bit(PG_FUNCTION_ARGS);
extern Datum varbit(PG_FUNCTION_ARGS);
-extern Datum _varbit(PG_FUNCTION_ARGS);
extern Datum biteq(PG_FUNCTION_ARGS);
extern Datum bitne(PG_FUNCTION_ARGS);
extern Datum bitlt(PG_FUNCTION_ARGS);
create domain domainnumeric numeric(8,2);
create domain domainint4 int4;
create domain domaintext text;
--- Test coercions
-SELECT cast('123456' as domainvarchar); -- fail
-ERROR: value too long for type character varying(5)
-SELECT cast('12345' as domainvarchar); -- pass
+-- Test explicit coercions --- these should succeed (and truncate)
+SELECT cast('123456' as domainvarchar);
+ domainvarchar
+---------------
+ 12345
+(1 row)
+
+SELECT cast('12345' as domainvarchar);
domainvarchar
---------------
12345
Sat Jan 01 10:00:00 1994
(1 row)
-SELECT date '1994-01-01' + time '11:00-5' AS "Jan_01_1994_8am";
-ERROR: Bad time external representation '11:00-5'
-SELECT "timestamp"(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_11am";
- Jan_01_1994_11am
---------------------------
- Sat Jan 01 11:00:00 1994
+SELECT date '1994-01-01' + timetz '11:00-5' AS "Jan_01_1994_8am";
+ Jan_01_1994_8am
+------------------------------
+ Sat Jan 01 08:00:00 1994 PST
+(1 row)
+
+SELECT timestamptz(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_8am";
+ Jan_01_1994_8am
+------------------------------
+ Sat Jan 01 08:00:00 1994 PST
(1 row)
SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
(1 row)
SELECT CAST(time with time zone '01:02-08' AS interval) AS "+00:01";
-ERROR: Cannot cast type 'time with time zone' to 'interval'
+ERROR: Cannot cast type time with time zone to interval
SELECT CAST(interval '02:03' AS time with time zone) AS "02:03:00-08";
-ERROR: Cannot cast type 'interval' to 'time with time zone'
+ERROR: Cannot cast type interval to time with time zone
SELECT time with time zone '01:30-08' - interval '02:01' AS "23:29:00-08";
23:29:00-08
-------------
Sat Jan 01 10:00:00 1994
(1 row)
-SELECT date '1994-01-01' + time '11:00-5' AS "Jan_01_1994_8am";
-ERROR: Bad time external representation '11:00-5'
-SELECT "timestamp"(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_11am";
- Jan_01_1994_11am
---------------------------
- Sat Jan 01 11:00:00 1994
+SELECT date '1994-01-01' + timetz '11:00-5' AS "Jan_01_1994_8am";
+ Jan_01_1994_8am
+------------------------------
+ Sat Jan 01 08:00:00 1994 PST
+(1 row)
+
+SELECT timestamptz(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_8am";
+ Jan_01_1994_8am
+------------------------------
+ Sat Jan 01 08:00:00 1994 PST
(1 row)
SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
(1 row)
SELECT CAST(time with time zone '01:02-08' AS interval) AS "+00:01";
-ERROR: Cannot cast type 'time with time zone' to 'interval'
+ERROR: Cannot cast type time with time zone to interval
SELECT CAST(interval '02:03' AS time with time zone) AS "02:03:00-08";
-ERROR: Cannot cast type 'interval' to 'time with time zone'
+ERROR: Cannot cast type interval to time with time zone
SELECT time with time zone '01:30-08' - interval '02:01' AS "23:29:00-08";
23:29:00-08
-------------
Sat Jan 01 10:00:00 1994
(1 row)
-SELECT date '1994-01-01' + time '11:00-5' AS "Jan_01_1994_8am";
-ERROR: Bad time external representation '11:00-5'
-SELECT "timestamp"(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_11am";
- Jan_01_1994_11am
---------------------------
- Sat Jan 01 11:00:00 1994
+SELECT date '1994-01-01' + timetz '11:00-5' AS "Jan_01_1994_8am";
+ Jan_01_1994_8am
+------------------------------
+ Sat Jan 01 08:00:00 1994 PST
+(1 row)
+
+SELECT timestamptz(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_8am";
+ Jan_01_1994_8am
+------------------------------
+ Sat Jan 01 08:00:00 1994 PST
(1 row)
SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
(1 row)
SELECT CAST(time with time zone '01:02-08' AS interval) AS "+00:01";
-ERROR: Cannot cast type 'time with time zone' to 'interval'
+ERROR: Cannot cast type time with time zone to interval
SELECT CAST(interval '02:03' AS time with time zone) AS "02:03:00-08";
-ERROR: Cannot cast type 'interval' to 'time with time zone'
+ERROR: Cannot cast type interval to time with time zone
SELECT time with time zone '01:30-08' - interval '02:01' AS "23:29:00-08";
23:29:00-08
-------------
-- **************** pg_cast ****************
-- Look for casts from and to the same type. This is not harmful, but
--- useless.
+-- useless. Also catch bogus values in pg_cast columns (other than
+-- cases detected by oidjoins test).
SELECT *
FROM pg_cast c
-WHERE c.castsource = c.casttarget;
- castsource | casttarget | castfunc | castimplicit
-------------+------------+----------+--------------
+WHERE castsource = casttarget OR castsource = 0 OR casttarget = 0
+ OR castcontext NOT IN ('e', 'a', 'i');
+ castsource | casttarget | castfunc | castcontext
+------------+------------+----------+-------------
(0 rows)
--- Look for cast functions with incorrect number or type of argument
--- or return value.
+-- Look for cast functions that don't have the right signature. The
+-- argument and result types in pg_proc must be the same as, or binary
+-- compatible with, what it says in pg_cast.
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
-------------+------------+----------+--------------
+ (p.pronargs <> 1
+ OR NOT (c.castsource = p.proargtypes[0] OR
+ EXISTS (SELECT 1 FROM pg_cast k
+ WHERE k.castfunc = 0 AND
+ k.castsource = c.castsource AND
+ k.casttarget = p.proargtypes[0]))
+ OR NOT (p.prorettype = c.casttarget OR
+ EXISTS (SELECT 1 FROM pg_cast k
+ WHERE k.castfunc = 0 AND
+ k.castsource = p.prorettype AND
+ k.casttarget = c.casttarget)));
+ castsource | casttarget | castfunc | castcontext
+------------+------------+----------+-------------
(0 rows)
-- Look for binary compatible casts that do not have the reverse
WHERE k.castfunc = 0 AND
k.castsource = c.casttarget AND
k.casttarget = c.castsource);
- castsource | casttarget | castfunc | castimplicit
-------------+------------+----------+--------------
+ castsource | casttarget | castfunc | castcontext
+------------+------------+----------+-------------
(0 rows)
-- **************** pg_operator ****************
-- Hashing only works on simple equality operators "type = sametype",
-- since the hash itself depends on the bitwise representation of the type.
-- Check that allegedly hashable operators look like they might be "=".
--- NOTE: in 7.2, this search finds int4eqoid, oideqint4, and xideqint4.
+-- NOTE: in 7.3, this search finds xideqint4.
-- Until we have some cleaner way of dealing with binary-equivalent types,
--- just leave those three tuples in the expected output.
+-- just leave that tuple in the expected output.
SELECT p1.oid, p1.oprname
FROM pg_operator AS p1
WHERE p1.oprcanhash AND NOT
(p1.oprkind = 'b' AND p1.oprresult = 'bool'::regtype AND
p1.oprleft = p1.oprright AND p1.oprname = '=' AND p1.oprcom = p1.oid);
- oid | oprname
-------+---------
- 353 | =
- 1136 | =
- 1137 | =
-(3 rows)
+ oid | oprname
+-----+---------
+ 353 | =
+(1 row)
-- In 6.5 we accepted hashable array equality operators when the array element
-- type is hashable. However, what we actually need to make hashjoin work on
ERROR: Wrong number of parameters, expected 6 but got 7
-- wrong param types
EXECUTE q3(5::smallint, 10.5::float, false, 500::oid, 4::bigint, 'bytea');
-ERROR: Parameter $2 of type double precision cannot be coerced into the expected type integer
+ERROR: Parameter $3 of type boolean cannot be coerced into the expected type double precision
You will need to rewrite or cast the expression
-- invalid type
PREPARE q4(nonexistenttype) AS SELECT $1;
rtest_nothn1 | rtest_nothn_r2 | CREATE RULE rtest_nothn_r2 AS ON INSERT TO rtest_nothn1 WHERE ((new.a >= 30) AND (new.a < 40)) DO INSTEAD NOTHING;
rtest_nothn2 | rtest_nothn_r3 | CREATE RULE rtest_nothn_r3 AS ON INSERT TO rtest_nothn2 WHERE (new.a >= 100) DO INSTEAD INSERT INTO rtest_nothn3 (a, b) VALUES (new.a, new.b);
rtest_nothn2 | rtest_nothn_r4 | CREATE RULE rtest_nothn_r4 AS ON INSERT TO rtest_nothn2 DO INSTEAD NOTHING;
- rtest_order1 | rtest_order_r1 | CREATE RULE rtest_order_r1 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, int4(nextval('rtest_seq'::text)), 'rule 1 - this should run 3rd or 4th'::text);
- rtest_order1 | rtest_order_r2 | CREATE RULE rtest_order_r2 AS ON INSERT TO rtest_order1 DO INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, int4(nextval('rtest_seq'::text)), 'rule 2 - this should run 1st'::text);
- rtest_order1 | rtest_order_r3 | CREATE RULE rtest_order_r3 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, int4(nextval('rtest_seq'::text)), 'rule 3 - this should run 3rd or 4th'::text);
- rtest_order1 | rtest_order_r4 | CREATE RULE rtest_order_r4 AS ON INSERT TO rtest_order1 WHERE (new.a < 100) DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, int4(nextval('rtest_seq'::text)), 'rule 4 - this should run 2nd'::text);
+ rtest_order1 | rtest_order_r1 | CREATE RULE rtest_order_r1 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 1 - this should run 3rd or 4th'::text);
+ rtest_order1 | rtest_order_r2 | CREATE RULE rtest_order_r2 AS ON INSERT TO rtest_order1 DO INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 2 - this should run 1st'::text);
+ rtest_order1 | rtest_order_r3 | CREATE RULE rtest_order_r3 AS ON INSERT TO rtest_order1 DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 3 - this should run 3rd or 4th'::text);
+ rtest_order1 | rtest_order_r4 | CREATE RULE rtest_order_r4 AS ON INSERT TO rtest_order1 WHERE (new.a < 100) DO INSTEAD INSERT INTO rtest_order2 (a, b, c) VALUES (new.a, nextval('rtest_seq'::text), 'rule 4 - this should run 2nd'::text);
rtest_person | rtest_pers_del | CREATE RULE rtest_pers_del AS ON DELETE TO rtest_person DO DELETE FROM rtest_admin WHERE (rtest_admin.pname = old.pname);
rtest_person | rtest_pers_upd | CREATE RULE rtest_pers_upd AS ON UPDATE TO rtest_person DO UPDATE rtest_admin SET pname = new.pname WHERE (rtest_admin.pname = old.pname);
rtest_system | rtest_sys_del | CREATE RULE rtest_sys_del AS ON DELETE TO rtest_system DO (DELETE FROM rtest_interface WHERE (rtest_interface.sysname = old.sysname); DELETE FROM rtest_admin WHERE (rtest_admin.sysname = old.sysname); );
namefield
(1 row)
-SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL; -- fail
-ERROR: value too long for type character(10)
+-- since this is an explicit cast, it should truncate w/o error:
+SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL;
+ char(text)
+------------
+ doh!
+ hi de ho n
+(2 rows)
+
+-- note: implicit-cast case is tested in char.sql
SELECT CAST(f1 AS char(20)) AS "char(text)" FROM TEXT_TBL;
char(text)
----------------------
SELECT 1.0 AS two UNION ALL SELECT 1;
two
-----
- 1
+ 1.0
1
(2 rows)
create domain domainint4 int4;
create domain domaintext text;
--- Test coercions
-SELECT cast('123456' as domainvarchar); -- fail
-SELECT cast('12345' as domainvarchar); -- pass
+-- Test explicit coercions --- these should succeed (and truncate)
+SELECT cast('123456' as domainvarchar);
+SELECT cast('12345' as domainvarchar);
-- Test tables using domains
create table basictest
-- to enable support for SQL99 timestamp type syntax.
SELECT date '1994-01-01' + time '11:00' AS "Jan_01_1994_11am";
SELECT date '1994-01-01' + time '10:00' AS "Jan_01_1994_10am";
-SELECT date '1994-01-01' + time '11:00-5' AS "Jan_01_1994_8am";
-SELECT "timestamp"(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_11am";
+SELECT date '1994-01-01' + timetz '11:00-5' AS "Jan_01_1994_8am";
+SELECT timestamptz(date '1994-01-01', time with time zone '11:00-5') AS "Jan_01_1994_8am";
SELECT '' AS "64", d1 + interval '1 year' AS one_year FROM TIMESTAMP_TBL;
SELECT '' AS "64", d1 - interval '1 year' AS one_year FROM TIMESTAMP_TBL;
-- **************** pg_cast ****************
-- Look for casts from and to the same type. This is not harmful, but
--- useless.
+-- useless. Also catch bogus values in pg_cast columns (other than
+-- cases detected by oidjoins test).
SELECT *
FROM pg_cast c
-WHERE c.castsource = c.casttarget;
+WHERE castsource = casttarget OR castsource = 0 OR casttarget = 0
+ OR castcontext NOT IN ('e', 'a', 'i');
--- Look for cast functions with incorrect number or type of argument
--- or return value.
+-- Look for cast functions that don't have the right signature. The
+-- argument and result types in pg_proc must be the same as, or binary
+-- compatible with, what it says in pg_cast.
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;
+ (p.pronargs <> 1
+ OR NOT (c.castsource = p.proargtypes[0] OR
+ EXISTS (SELECT 1 FROM pg_cast k
+ WHERE k.castfunc = 0 AND
+ k.castsource = c.castsource AND
+ k.casttarget = p.proargtypes[0]))
+ OR NOT (p.prorettype = c.casttarget OR
+ EXISTS (SELECT 1 FROM pg_cast k
+ WHERE k.castfunc = 0 AND
+ k.castsource = p.prorettype AND
+ k.casttarget = c.casttarget)));
-- Look for binary compatible casts that do not have the reverse
-- direction registered as well, or where the reverse direction is not
-- Hashing only works on simple equality operators "type = sametype",
-- since the hash itself depends on the bitwise representation of the type.
-- Check that allegedly hashable operators look like they might be "=".
--- NOTE: in 7.2, this search finds int4eqoid, oideqint4, and xideqint4.
+-- NOTE: in 7.3, this search finds xideqint4.
-- Until we have some cleaner way of dealing with binary-equivalent types,
--- just leave those three tuples in the expected output.
+-- just leave that tuple in the expected output.
SELECT p1.oid, p1.oprname
FROM pg_operator AS p1
SELECT CAST(name 'namefield' AS text) AS "text(name)";
-SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL; -- fail
+-- since this is an explicit cast, it should truncate w/o error:
+SELECT CAST(f1 AS char(10)) AS "char(text)" FROM TEXT_TBL;
+-- note: implicit-cast case is tested in char.sql
SELECT CAST(f1 AS char(20)) AS "char(text)" FROM TEXT_TBL;