Commit b26dfb95 authored by Tom Lane's avatar Tom Lane

Extend pg_cast castimplicit column to a three-way value; this allows us

to be flexible about assignment casts without introducing ambiguity in
operator/function resolution.  Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
parent cc70ba2e
<!--
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">
......@@ -841,9 +841,8 @@
<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>
......@@ -879,17 +878,25 @@
<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">
......@@ -823,8 +823,19 @@ CREATE TABLE <replaceable class="parameter">tablename</replaceable> (
<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>
......@@ -897,12 +908,14 @@ INSERT INTO test2 VALUES ('ok');
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>
......@@ -932,7 +945,7 @@ SELECT b, char_length(b) FROM test2;
</para>
<table tocentry="1">
<title>Specialty Character Type</title>
<title>Specialty Character Types</title>
<tgroup cols="3">
<thead>
<row>
......@@ -2832,29 +2845,39 @@ SELECT * FROM test1 WHERE a;
<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>
......@@ -2874,9 +2897,16 @@ CREATE TABLE test (a BIT(3), b BIT VARYING(5));
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>
......@@ -15,11 +15,11 @@
<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>
......@@ -49,20 +49,44 @@ SELECT CAST(42 AS text);
</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>
......@@ -74,10 +98,11 @@ INSERT INTO foo(f1) VALUES(42);
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>
......@@ -138,7 +163,18 @@ INSERT INTO foo(f1) VALUES(42);
<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>
......@@ -163,10 +199,10 @@ INSERT INTO foo(f1) VALUES(42);
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>
......@@ -191,7 +227,8 @@ CREATE CAST (text AS int4) WITH FUNCTION int4(text);
<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">
......@@ -24,6 +24,8 @@ CDATA means the content is "SGML-free", so you can write without
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
......
......@@ -804,13 +804,9 @@ If the non-unknown inputs are not all of the same type category, fail.
<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">
......@@ -842,15 +838,16 @@ Here, the unknown-type literal <literal>'b'</literal> will be resolved as type t
<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>
......@@ -858,27 +855,18 @@ the preferred type in the numeric category, so that type is used.
<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>
......
......@@ -8,7 +8,7 @@
*
*
* 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
......@@ -51,7 +51,6 @@
#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"
......@@ -1705,17 +1704,16 @@ cookDefault(ParseState *pstate,
{
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));
}
/*
......
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -95,7 +95,7 @@ AggregateCreate(const char *aggName,
*/
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);
......
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -369,7 +369,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
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));
}
......@@ -388,7 +388,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
if (tlistlen == 1)
{
restype = ((TargetEntry *) lfirst(tlist))->resdom->restype;
if (IsBinaryCompatible(restype, rettype))
if (IsBinaryCoercible(restype, rettype))
return;
}
......@@ -426,7 +426,7 @@ checkretval(Oid rettype, char fn_typtype, List *queryTreeList)
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),
......
......@@ -9,7 +9,7 @@
*
*
* 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
......@@ -601,14 +601,11 @@ CreateCast(CreateCastStmt *stmt)
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;
......@@ -648,24 +645,17 @@ CreateCast(CreateCastStmt *stmt)
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);
......@@ -687,18 +677,51 @@ CreateCast(CreateCastStmt *stmt)
}
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);
......@@ -706,6 +729,7 @@ CreateCast(CreateCastStmt *stmt)
CatalogUpdateIndexes(relation, tuple);
/* make dependency entries */
myself.classId = RelationGetRelid(relation);
myself.objectId = HeapTupleGetOid(tuple);
myself.objectSubId = 0;
......@@ -732,6 +756,7 @@ CreateCast(CreateCastStmt *stmt)
}
heap_freetuple(tuple);
heap_close(relation, RowExclusiveLock);
}
......
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -335,8 +335,8 @@ FuncIndexArgs(IndexInfo *indexInfo,
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");
}
......@@ -464,7 +464,7 @@ GetAttrOpClass(IndexElem *attribute, Oid attrType,
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));
......@@ -508,7 +508,7 @@ GetDefaultOpClass(Oid attrType, Oid accessMethodId)
nexact++;
exactOid = opclass->oid;
}
else if (IsBinaryCompatible(opclass->opcintype, attrType))
else if (IsBinaryCoercible(attrType, opclass->opcintype))
{
ncompatible++;
compatibleOid = opclass->oid;
......
......@@ -46,7 +46,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeAgg.c,v 1.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 $
*
*-------------------------------------------------------------------------
*/
......@@ -913,7 +913,7 @@ ExecInitAgg(Agg *node, EState *estate, Plan *parent)
*/
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);
}
......
......@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.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 $
*
*-------------------------------------------------------------------------
*/
......@@ -850,6 +850,7 @@ _copyFunc(Func *from)
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;
......@@ -931,6 +932,7 @@ _copyRelabelType(RelabelType *from)
Node_Copy(from, newnode, arg);
newnode->resulttype = from->resulttype;
newnode->resulttypmod = from->resulttypmod;
newnode->relabelformat = from->relabelformat;
return newnode;
}
......@@ -2634,7 +2636,7 @@ _copyCreateCastStmt(CreateCastStmt *from)
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;
}
......
......@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.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 $
*
*-------------------------------------------------------------------------
*/
......@@ -217,6 +217,15 @@ _equalFunc(Func *a, Func *b)
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;
......@@ -302,6 +311,14 @@ _equalRelabelType(RelabelType *a, RelabelType *b)
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;
}
......@@ -1475,7 +1492,7 @@ _equalCreateCastStmt(CreateCastStmt *a, CreateCastStmt *b)
return false;
if (!equal(a->func, b->func))
return false;
if (a->implicit != b->implicit)
if (a->context != b->context)
return false;
return true;
......
......@@ -8,7 +8,7 @@
*
*
* 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"
......@@ -215,13 +215,14 @@ makeAlias(const char *aliasname, List *colnames)
* 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;
}
......
......@@ -5,7 +5,7 @@
* 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
......@@ -860,10 +860,11 @@ static void
_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);
}
/*
......@@ -914,9 +915,11 @@ _outRelabelType(StringInfo str, RelabelType *node)
{
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);
}
/*
......
......@@ -8,7 +8,7 @@
*
*
* 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
......@@ -1129,6 +1129,10 @@ _readFunc(void)
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;
......@@ -1335,6 +1339,10 @@ _readRelabelType(void)
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;
}
......
......@@ -9,7 +9,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -825,32 +825,15 @@ match_clause_to_indexkey(RelOptInfo *rel,
* 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)
......@@ -860,83 +843,10 @@ indexable_operator(Expr *clause, Oid opclass, bool 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;
}
......
......@@ -11,7 +11,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -520,6 +520,7 @@ build_index_pathkeys(Query *root,
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)
......
......@@ -10,7 +10,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -1027,8 +1027,7 @@ fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index,
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");
......@@ -1061,23 +1060,13 @@ fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index,
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));
}
......
......@@ -15,7 +15,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -187,8 +187,9 @@ expand_targetlist(List *tlist, int command_type,
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 */
......
......@@ -14,7 +14,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -420,8 +420,7 @@ generate_setop_tlist(List *colTypes, int flag,
}
else
{
expr = coerce_to_common_type(NULL,
expr,
expr = coerce_to_common_type(expr,
colType,
"UNION/INTERSECT/EXCEPT");
colTypmod = -1;
......
......@@ -6,7 +6,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -2565,24 +2565,20 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
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);
......
......@@ -11,7 +11,7 @@
*
*
* 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
......@@ -161,8 +161,8 @@ static void doNegateFloat(Value *v);
%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
......@@ -349,7 +349,7 @@ static void doNegateFloat(Value *v);
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,
......@@ -3230,29 +3230,30 @@ any_operator:
*****************************************************************************/
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; }
;
......@@ -7061,6 +7062,7 @@ unreserved_keyword:
| HOUR_P
| IMMEDIATE
| IMMUTABLE
| IMPLICIT_P
| INCREMENT
| INDEX
| INHERITS
......
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -147,6 +147,7 @@ static const ScanKeyword ScanKeywords[] = {
{"ilike", ILIKE},
{"immediate", IMMEDIATE},
{"immutable", IMMUTABLE},
{"implicit", IMPLICIT_P},
{"in", IN_P},
{"increment", INCREMENT},
{"index", INDEX},
......
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -872,20 +872,24 @@ buildMergedJoinVar(JoinType jointype, Var *l_colvar, Var *r_colvar)
* 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;
......
This diff is collapsed.
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -28,7 +28,6 @@
#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"
......@@ -40,9 +39,7 @@ static int expr_depth_counter = 0;
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);
......@@ -145,10 +142,9 @@ transformExpr(ParseState *pstate, Node *expr)
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:
......@@ -175,7 +171,7 @@ transformExpr(ParseState *pstate, Node *expr)
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:
......@@ -562,8 +558,7 @@ transformExpr(ParseState *pstate, Node *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");
......@@ -572,8 +567,7 @@ transformExpr(ParseState *pstate, Node *expr)
{
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");
}
......@@ -671,8 +665,12 @@ transformIndirection(ParseState *pstate, Node *basenode, List *indirection)
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 *
......@@ -1037,23 +1035,13 @@ exprTypmod(Node *expr)
*
* 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 */
......@@ -1067,62 +1055,26 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
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.
......@@ -1130,79 +1082,17 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
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;
......@@ -1212,23 +1102,14 @@ parser_typecast_expression(ParseState *pstate,
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;
}
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -32,15 +32,12 @@
#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);
......@@ -137,7 +134,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
* 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;
}
......@@ -243,8 +240,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
* 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)
{
......@@ -296,7 +293,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
}
/* 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)
......@@ -307,6 +304,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
funcnode->funcid = funcid;
funcnode->funcresulttype = rettype;
funcnode->funcretset = retset;
funcnode->funcformat = COERCE_EXPLICIT_CALL;
funcnode->func_fcache = NULL;
expr->typeOid = rettype;
......@@ -367,7 +365,7 @@ match_argtypes(int nargs,
{
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;
......@@ -470,7 +468,7 @@ func_select_candidate(int nargs,
{
if (input_typeids[i] != UNKNOWNOID)
{
if (IsBinaryCompatible(current_typeids[i], input_typeids[i]))
if (IsBinaryCoercible(input_typeids[i], current_typeids[i]))
nmatch++;
}
}
......@@ -776,7 +774,7 @@ func_get_detail(List *funcname,
Node *arg1 = lfirst(fargs);
if ((sourceType == UNKNOWNOID && IsA(arg1, Const)) ||
IsBinaryCompatible(sourceType, targetType))
IsBinaryCoercible(sourceType, targetType))
{
/* Yup, it's a type coercion */
*funcid = InvalidOid;
......@@ -1120,8 +1118,7 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
* 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)
......@@ -1136,11 +1133,11 @@ make_arguments(ParseState *pstate,
/* 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);
}
}
}
......@@ -1179,9 +1176,7 @@ setup_field_select(Node *input, char *attname, Oid relid)
* 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"
......@@ -29,14 +24,11 @@
#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()
......@@ -70,8 +62,8 @@ make_operand(Node *tree, Oid orig_typeId, Oid target_typeId)
{
/* 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;
}
......@@ -191,6 +183,7 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno)
* 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.
......@@ -199,6 +192,7 @@ ArrayRef *
transformArraySubscripts(ParseState *pstate,
Node *arrayBase,
Oid arrayType,
int32 arrayTypMod,
List *indirection,
bool forceSlice,
Node *assignFrom)
......@@ -286,8 +280,10 @@ transformArraySubscripts(ParseState *pstate,
{
subexpr = transformExpr(pstate, ai->lidx);
/* If it's not int4 already, try to coerce */
subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr),
INT4OID, -1, 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");
}
......@@ -306,8 +302,10 @@ transformArraySubscripts(ParseState *pstate,
}
subexpr = transformExpr(pstate, ai->uidx);
/* If it's not int4 already, try to coerce */
subexpr = CoerceTargetExpr(pstate, subexpr, exprType(subexpr),
INT4OID, -1, 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);
......@@ -323,19 +321,16 @@ transformArraySubscripts(ParseState *pstate,
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));
}
}
......@@ -344,7 +339,7 @@ transformArraySubscripts(ParseState *pstate,
*/
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;
......@@ -373,21 +368,16 @@ transformArraySubscripts(ParseState *pstate,
* 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;
......@@ -404,12 +394,13 @@ make_const(Value *value)
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
......@@ -470,46 +461,3 @@ make_const(Value *value)
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;
}
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -273,7 +273,7 @@ oper_select_candidate(int nargs,
current_candidate = current_candidate->next)
{
if (can_coerce_type(nargs, input_typeids, current_candidate->args,
false))
COERCION_IMPLICIT))
{
if (last_candidate == NULL)
{
......@@ -362,7 +362,7 @@ oper_select_candidate(int nargs,
{
if (input_typeids[i] != UNKNOWNOID)
{
if (IsBinaryCompatible(current_typeids[i], input_typeids[i]))
if (IsBinaryCoercible(input_typeids[i], current_typeids[i]))
nmatch++;
}
}
......@@ -696,8 +696,8 @@ compatible_oper(List *op, Oid arg1, Oid arg2, bool noError)
/* 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... */
......
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -274,6 +274,7 @@ updateTargetListEntry(ParseState *pstate,
aref = transformArraySubscripts(pstate,
arrayBase,
attrtype,
attrtypmod,
indirection,
pstate->p_is_insert,
tle->expr);
......@@ -284,30 +285,21 @@ updateTargetListEntry(ParseState *pstate,
/*
* 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));
}
}
......@@ -324,46 +316,6 @@ updateTargetListEntry(ParseState *pstate,
}
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
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteHandler.c,v 1.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 $
*
*-------------------------------------------------------------------------
*/
......@@ -25,7 +25,6 @@
#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"
......@@ -474,29 +473,21 @@ build_column_default(Relation rel, int attrno)
*/
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;
}
......
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -19,6 +19,7 @@
#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"
......@@ -755,6 +756,72 @@ array_out(PG_FUNCTION_ARGS)
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"
......
......@@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -48,14 +48,16 @@
* 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;
......@@ -63,8 +65,11 @@ int8in(PG_FUNCTION_ARGS)
* 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 == '-')
{
......@@ -79,28 +84,61 @@ int8in(PG_FUNCTION_ARGS)
#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);
}
......@@ -747,7 +785,7 @@ i8tod(PG_FUNCTION_ARGS)
}
/* dtoi8()
* Convert double float to 8-byte integer.
* Convert float8 to 8-byte integer.
*/
Datum
dtoi8(PG_FUNCTION_ARGS)
......@@ -771,8 +809,66 @@ 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)
{
......@@ -793,9 +889,6 @@ text_int8(PG_FUNCTION_ARGS)
return result;
}
/* int8_text()
*/
Datum
int8_text(PG_FUNCTION_ARGS)
{
......
......@@ -5,7 +5,7 @@
*
* 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 $
*
* ----------
*/
......@@ -1709,6 +1709,50 @@ numeric_float4(PG_FUNCTION_ARGS)
}
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
......
......@@ -13,7 +13,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -49,7 +49,7 @@ static void parseNameAndArgTypes(const char *string, const char *caller,
/*
* 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.
......@@ -71,15 +71,8 @@ regprocin(PG_FUNCTION_ARGS)
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);
}
......@@ -211,7 +204,7 @@ regprocout(PG_FUNCTION_ARGS)
/*
* 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.
......@@ -235,15 +228,8 @@ regprocedurein(PG_FUNCTION_ARGS)
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);
}
......@@ -361,7 +347,7 @@ regprocedureout(PG_FUNCTION_ARGS)
/*
* 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.
......@@ -383,15 +369,8 @@ regoperin(PG_FUNCTION_ARGS)
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);
}
......@@ -531,7 +510,7 @@ regoperout(PG_FUNCTION_ARGS)
/*
* 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.
......@@ -556,15 +535,8 @@ regoperatorin(PG_FUNCTION_ARGS)
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);
}
......@@ -698,7 +670,7 @@ regoperatorout(PG_FUNCTION_ARGS)
/*
* 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.
......@@ -719,15 +691,8 @@ regclassin(PG_FUNCTION_ARGS)
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);
}
......@@ -843,7 +808,7 @@ regclassout(PG_FUNCTION_ARGS)
/*
* 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.
......@@ -870,15 +835,8 @@ regtypein(PG_FUNCTION_ARGS)
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);
}
......
This diff is collapsed.
......@@ -9,7 +9,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -35,6 +35,11 @@
* 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.
*----------
*/
......@@ -104,7 +109,7 @@ bit_in(PG_FUNCTION_ARGS)
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;
......@@ -203,50 +208,52 @@ bit_out(PG_FUNCTION_ARGS)
/* 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);
}
/*
......@@ -311,7 +318,7 @@ varbit_in(PG_FUNCTION_ARGS)
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);
......@@ -406,20 +413,26 @@ varbit_out(PG_FUNCTION_ARGS)
/* 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);
......@@ -429,37 +442,15 @@ varbit(PG_FUNCTION_ARGS)
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);
}
......@@ -978,7 +969,7 @@ bitshiftleft(PG_FUNCTION_ARGS)
/* 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);
}
......@@ -991,7 +982,7 @@ bitshiftleft(PG_FUNCTION_ARGS)
/* 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
{
......@@ -1037,7 +1028,7 @@ bitshiftright(PG_FUNCTION_ARGS)
/* 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);
}
......@@ -1046,7 +1037,7 @@ bitshiftright(PG_FUNCTION_ARGS)
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)
......
......@@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -165,21 +165,28 @@ bpcharout(PG_FUNCTION_ARGS)
/*
* 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 */
......@@ -188,7 +195,7 @@ bpchar(PG_FUNCTION_ARGS)
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)
......@@ -199,10 +206,13 @@ bpchar(PG_FUNCTION_ARGS)
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;
......@@ -238,37 +248,6 @@ bpchar(PG_FUNCTION_ARGS)
}
/* _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).
*/
......@@ -354,9 +333,9 @@ name_bpchar(PG_FUNCTION_ARGS)
* 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)
{
......@@ -428,17 +407,26 @@ varcharout(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);
......@@ -448,21 +436,19 @@ varchar(PG_FUNCTION_ARGS)
/* 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);
......@@ -471,38 +457,6 @@ varchar(PG_FUNCTION_ARGS)
}
/* _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
*****************************************************************************/
......
......@@ -7,7 +7,7 @@
* 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.
......@@ -1073,51 +1073,6 @@ getBaseType(Oid typid)
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
*
......
......@@ -27,7 +27,7 @@
# Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
# $Header: /cvsroot/pgsql/src/bin/initdb/Attic/initdb.sh,v 1.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 $
#
#-------------------------------------------------------------------------
......@@ -1018,7 +1018,7 @@ echo "ok"
# 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.
......@@ -1063,7 +1063,7 @@ UPDATE pg_database SET \
-- 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
......
......@@ -22,7 +22,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -3797,7 +3797,7 @@ dumpCasts(Archive *fout,
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;");
......@@ -3816,7 +3816,7 @@ dumpCasts(Archive *fout,
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)[]);
......@@ -3859,8 +3859,10 @@ dumpCasts(Archive *fout,
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,
......
......@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: catversion.h,v 1.158 2002/09/02 06:24:15 momjian Exp $
* $Id: catversion.h,v 1.159 2002/09/18 21:35:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200209021
#define CATALOG_VERSION_NO 200209181
#endif
This diff is collapsed.
......@@ -8,7 +8,7 @@
* 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
......@@ -526,10 +526,6 @@ DATA(insert OID = 1133 ( ">" PGNSP PGUID b f 701 700 16 1122 1134 0 0 0 0 f
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 - - ));
......@@ -723,17 +719,13 @@ DATA(insert OID = 1631 ( "~~*" PGNSP PGUID b f 1043 25 16 0 1632 0 0 0 0 tex
#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 - - ));
......
This diff is collapsed.
......@@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -16,6 +16,7 @@
#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,
......@@ -52,7 +53,8 @@ extern Const *makeNullConst(Oid consttype);
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);
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: parsenodes.h,v 1.206 2002/09/04 20:31:43 momjian Exp $
* $Id: parsenodes.h,v 1.207 2002/09/18 21:35:24 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1632,7 +1632,7 @@ typedef struct CreateCastStmt
TypeName *sourcetype;
TypeName *targettype;
FuncWithArgs *func;
bool implicit;
CoercionContext context;
} CreateCastStmt;
/* ----------------------
......
......@@ -10,7 +10,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -139,6 +139,30 @@ typedef struct RangeVar
* ----------------------------------------------------------------
*/
/*
* 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
*/
......@@ -194,6 +218,7 @@ typedef struct Func
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;
......@@ -460,6 +485,7 @@ typedef struct RelabelType
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 $
*
*-------------------------------------------------------------------------
*/
......@@ -29,29 +29,31 @@ typedef enum CATEGORY
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 */
......@@ -6,7 +6,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -57,6 +57,7 @@ extern Var *make_var(ParseState *pstate, RangeTblEntry *rte, int attrno);
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 $
*
*-------------------------------------------------------------------------
*/
......@@ -16,6 +16,7 @@
#include "parser/parse_node.h"
extern List *transformTargetList(ParseState *pstate, List *targetlist);
extern TargetEntry *transformTargetEntry(ParseState *pstate,
Node *node, Node *expr,
......@@ -23,9 +24,6 @@ extern TargetEntry *transformTargetEntry(ParseState *pstate,
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);
......
......@@ -10,7 +10,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -82,6 +82,7 @@ typedef struct
*/
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);
......
This diff is collapsed.
This diff is collapsed.
......@@ -6,7 +6,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
......@@ -58,7 +58,6 @@ extern void getTypeInputInfo(Oid type, Oid *typInput, Oid *typElem);
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,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -75,7 +75,7 @@ EXECUTE q3('bytea', 5::smallint, 10.5::float, false, 500::oid, 4::bigint, true);
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;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment