Commit d70a42e6 authored by Tom Lane's avatar Tom Lane

Represent type-specific length coercion functions as pg_cast entries,

eliminating the former hard-wired convention about their names.  Allow
pg_cast entries to represent both type coercion and length coercion in
a single step --- this is represented by a function that takes an
extra typmod argument, just like a length coercion function.  This
nicely merges the type and length coercion mechanisms into something
at least a little cleaner than we had before.  Make use of the single-
coercion-step behavior to fix integer-to-bit coercion so that coercing
to bit(n) yields the rightmost n bits of the integer instead of the
leftmost n bits.  This should fix recurrent complaints about the odd
behavior of this coercion.  Clean up the documentation of the bit string
functions, and try to put it where people might actually find it.
Also, get rid of the unreliable heuristics in ruleutils.c about whether
to display nested coercion steps; instead require parse_coerce.c to
label them properly in the first place.
parent 8e7349b7
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.86 2004/06/07 04:04:47 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.87 2004/06/16 01:26:33 tgl Exp $
-->
<chapter id="catalogs">
......@@ -934,7 +934,7 @@
<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>CAST</> or <literal>::</> 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
......@@ -944,6 +944,39 @@
</tbody>
</tgroup>
</table>
<para>
The cast functions listed in <structname>pg_cast</structname> must
always take the cast source type as their first argument type, and
return the cast destination type as their result type. A cast
function can have up to three arguments. The second argument,
if present, must be type <type>integer</>; it receives the type
modifier associated with the destination type, or <literal>-1</>
if there is none. The third argument,
if present, must be type <type>boolean</>; it receives <literal>true</>
if the cast is an explicit cast, <literal>false</> otherwise.
</para>
<para>
It is legitimate to create a <structname>pg_cast</structname> entry
in which the source and target types are the same, if the associated
function takes more than one argument. Such entries represent
<quote>length coercion functions</> that coerce values of the type
to be legal for a particular type modifier value. Note however that
at present there is no support for associating non-default type
modifiers with user-created data types, and so this facility is only
of use for the small number of built-in types that have type modifier
syntax built into the grammar.
</para>
<para>
When a <structname>pg_cast</structname> entry has different source and
target types and a function that takes more than one argument, it
represents converting from one type to another and applying a length
coercion in a single step. When no such entry is available, coercion
to a type that uses a type modifier involves two steps, one to
convert between datatypes and a second to apply the modifier.
</para>
</sect1>
<sect1 id="catalog-pg-class">
......
<!--
$PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.145 2004/06/07 04:04:47 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.146 2004/06/16 01:26:35 tgl Exp $
-->
<chapter id="datatype">
......@@ -2851,7 +2851,7 @@ SELECT * FROM test1 WHERE a;
linkend="sql-syntax-bit-strings"> for information about the syntax
of bit string constants. Bit-logical operators and string
manipulation functions are available; see <xref
linkend="functions">.
linkend="functions-bitstring">.
</para>
<example>
......
<!--
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.208 2004/06/14 19:01:09 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.209 2004/06/16 01:26:36 tgl Exp $
PostgreSQL documentation
-->
......@@ -488,55 +488,13 @@ PostgreSQL documentation
</table>
<para>
The bitwise operators are also available for the bit
The bitwise operators work only on integral data types, whereas
the others are available for all numeric data types. The bitwise
operators are also available for the bit
string types <type>bit</type> and <type>bit varying</type>, as
shown in <xref linkend="functions-math-bit-table">.
Bit string operands of <literal>&amp;</literal>, <literal>|</literal>,
and <literal>#</literal> must be of equal length. When bit
shifting, the original length of the string is preserved, as shown
in the table.
shown in <xref linkend="functions-bit-string-op-table">.
</para>
<table id="functions-math-bit-table">
<title>Bit String Bitwise Operators</title>
<tgroup cols="2">
<thead>
<row>
<entry>Example</entry>
<entry>Result</entry>
</row>
</thead>
<tbody>
<row>
<entry><literal>B'10001' &amp; B'01101'</literal></entry>
<entry><literal>00001</literal></entry>
</row>
<row>
<entry><literal>B'10001' | B'01101'</literal></entry>
<entry><literal>11101</literal></entry>
</row>
<row>
<entry><literal>B'10001' # B'01101'</literal></entry>
<entry><literal>11110</literal></entry>
</row>
<row>
<entry><literal>~ B'10001'</literal></entry>
<entry><literal>01110</literal></entry>
</row>
<row>
<entry><literal>B'10001' &lt;&lt; 3</literal></entry>
<entry><literal>01000</literal></entry>
</row>
<row>
<entry><literal>B'10001' &gt;&gt; 2</literal></entry>
<entry><literal>00100</literal></entry>
</row>
</tbody>
</tgroup>
</table>
<para>
<xref linkend="functions-math-func-table"> shows the available
mathematical functions. In the table, <literal>dp</literal>
......@@ -2337,6 +2295,130 @@ PostgreSQL documentation
</sect1>
<sect1 id="functions-bitstring">
<title>Bit String Functions and Operators</title>
<indexterm zone="functions-bitstring">
<primary>bit strings</primary>
<secondary>functions</secondary>
</indexterm>
<para>
This section describes functions and operators for examining and
manipulating bit strings, that is values of the types
<type>bit</type> and <type>bit varying</type>. Aside from the
usual comparison operators, the operators
shown in <xref linkend="functions-bit-string-op-table"> can be used.
Bit string operands of <literal>&amp;</literal>, <literal>|</literal>,
and <literal>#</literal> must be of equal length. When bit
shifting, the original length of the string is preserved, as shown
in the examples.
</para>
<table id="functions-bit-string-op-table">
<title>Bit String Operators</title>
<tgroup cols="4">
<thead>
<row>
<entry>Operator</entry>
<entry>Description</entry>
<entry>Example</entry>
<entry>Result</entry>
</row>
</thead>
<tbody>
<row>
<entry> <literal>||</literal> </entry>
<entry>concatenation</entry>
<entry><literal>B'10001' || B'011'</literal></entry>
<entry><literal>10001011</literal></entry>
</row>
<row>
<entry> <literal>&amp;</literal> </entry>
<entry>bitwise AND</entry>
<entry><literal>B'10001' &amp; B'01101'</literal></entry>
<entry><literal>00001</literal></entry>
</row>
<row>
<entry> <literal>|</literal> </entry>
<entry>bitwise OR</entry>
<entry><literal>B'10001' | B'01101'</literal></entry>
<entry><literal>11101</literal></entry>
</row>
<row>
<entry> <literal>#</literal> </entry>
<entry>bitwise XOR</entry>
<entry><literal>B'10001' # B'01101'</literal></entry>
<entry><literal>11100</literal></entry>
</row>
<row>
<entry> <literal>~</literal> </entry>
<entry>bitwise NOT</entry>
<entry><literal>~ B'10001'</literal></entry>
<entry><literal>01110</literal></entry>
</row>
<row>
<entry> <literal>&lt;&lt;</literal> </entry>
<entry>bitwise shift left</entry>
<entry><literal>B'10001' &lt;&lt; 3</literal></entry>
<entry><literal>01000</literal></entry>
</row>
<row>
<entry> <literal>&gt;&gt;</literal> </entry>
<entry>bitwise shift right</entry>
<entry><literal>B'10001' &gt;&gt; 2</literal></entry>
<entry><literal>00100</literal></entry>
</row>
</tbody>
</tgroup>
</table>
<para>
The following <acronym>SQL</acronym>-standard functions work on bit
strings as well as character strings:
<literal><function>length</function></literal>,
<literal><function>bit_length</function></literal>,
<literal><function>octet_length</function></literal>,
<literal><function>position</function></literal>,
<literal><function>substring</function></literal>.
</para>
<para>
In addition, it is possible to cast integral values to and from type
<type>bit</>.
Some examples:
<programlisting>
44::bit(10) <lineannotation>0000101100</lineannotation>
44::bit(3) <lineannotation>100</lineannotation>
cast(-44 as bit(12)) <lineannotation>111111010100</lineannotation>
'1110'::bit(4)::integer <lineannotation>14</lineannotation>
</programlisting>
Note that casting to just <quote>bit</> means casting to
<literal>bit(1)</>, and so it will deliver only the least significant
bit of the integer.
</para>
<note>
<para>
Prior to <productname>PostgreSQL</productname> 7.5, casting an
integer to <type>bit(n)</> would copy the leftmost <literal>n</>
bits of the integer, whereas now it copies the rightmost <literal>n</>
bits. Also, casting an integer to a bit string width wider than
the integer itself will sign-extend on the left.
</para>
</note>
</sect1>
<sect1 id="functions-matching">
<title>Pattern Matching</title>
......@@ -7628,14 +7710,13 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<function>bit_and(<replaceable class="parameter">expression</replaceable>)</function>
</entry>
<entry>
<type>smallint</type>, <type>integer</type>, <type>bigint</type> or
<type>bit</type>,
<type>smallint</type>, <type>integer</type>, <type>bigint</type>, or
<type>bit</type>
</entry>
<entry>
same as argument data type.
</entry>
<entry>the bitwise-and of all non-null input values, or null if empty
same as argument data type
</entry>
<entry>the bitwise AND of all non-null input values, or null if none</entry>
</row>
<row>
......@@ -7646,14 +7727,13 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<function>bit_or(<replaceable class="parameter">expression</replaceable>)</function>
</entry>
<entry>
<type>smallint</type>, <type>integer</type>, <type>bigint</type> or
<type>bit</type>,
<type>smallint</type>, <type>integer</type>, <type>bigint</type>, or
<type>bit</type>
</entry>
<entry>
same as argument data type.
</entry>
<entry>the bitwise-or of all non-null input values, or null if empty.
same as argument data type
</entry>
<entry>the bitwise OR of all non-null input values, or null if none</entry>
</row>
<row>
......@@ -7669,9 +7749,7 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<entry>
<type>bool</type>
</entry>
<entry>true if all input values are true, otherwise false.
Also known as <function>bool_and</function>.
</entry>
<entry>true if all input values are true, otherwise false</entry>
</row>
<row>
......@@ -7720,9 +7798,7 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<entry>
<type>bool</type>
</entry>
<entry>true if all input values are true, otherwise false.
Also known as <function>bool_and</function>.
</entry>
<entry>equivalent to <function>bool_and</function></entry>
</row>
<row>
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/create_cast.sgml,v 1.16 2004/02/15 06:27:37 neilc Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/ref/create_cast.sgml,v 1.17 2004/06/16 01:26:40 tgl Exp $ -->
<refentry id="SQL-CREATECAST">
<refmeta>
......@@ -18,7 +18,7 @@
<refsynopsisdiv>
<synopsis>
CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
WITH FUNCTION <replaceable>funcname</replaceable> (<replaceable>argtype</replaceable>)
WITH FUNCTION <replaceable>funcname</replaceable> (<replaceable>argtypes</replaceable>)
[ AS ASSIGNMENT | AS IMPLICIT ]
CREATE CAST (<replaceable>sourcetype</replaceable> AS <replaceable>targettype</replaceable>)
......@@ -55,9 +55,9 @@ SELECT CAST(42 AS text);
<para>
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</>) construct.
<replaceable>typename</>)</literal> or
<replaceable>x</><literal>::</><replaceable>typename</>
construct.
</para>
<para>
......@@ -141,15 +141,14 @@ SELECT 'The time is ' || CAST(now() AS text);
</varlistentry>
<varlistentry>
<term><replaceable>funcname</replaceable>(<replaceable>argtype</replaceable>)</term>
<term><replaceable>funcname</replaceable>(<replaceable>argtypes</replaceable>)</term>
<listitem>
<para>
The function used to perform the cast. The function name may
be schema-qualified. If it is not, the function will be looked
up in the schema search path. The argument type must be
identical to the source type and the result data type must
match the target type of the cast.
up in the schema search path. The function's result data type must
match the target type of the cast. Its arguments are discussed below.
</para>
</listitem>
</varlistentry>
......@@ -187,6 +186,42 @@ SELECT 'The time is ' || CAST(now() AS text);
</varlistentry>
</variablelist>
<para>
Cast implementation functions may have one to three arguments.
The first argument type must be identical to the cast's source type.
The second argument,
if present, must be type <type>integer</>; it receives the type
modifier associated with the destination type, or <literal>-1</>
if there is none. The third argument,
if present, must be type <type>boolean</>; it receives <literal>true</>
if the cast is an explicit cast, <literal>false</> otherwise.
(Bizarrely, the SQL spec demands different behaviors for explicit and
implicit casts in some cases. This argument is supplied for functions
that must implement such casts. It is not recommended that you design
your own datatypes so that this matters.)
</para>
<para>
Ordinarily a cast must have different source and target data types.
However, it is allowed to declare a cast with identical source and
target types if it has a cast implementation function with more than one
argument. This is used to represent type-specific length coercion
functions in the system catalogs. The named function is used to
coerce a value of the type to the type modifier value given by its
second argument. (Since the grammar presently permits only certain
built-in data types to have type modifiers, this feature is of no
use for user-defined target types, but we mention it for completeness.)
</para>
<para>
When a cast has different source and
target types and a function that takes more than one argument, it
represents converting from one type to another and applying a length
coercion in a single step. When no such entry is available, coercion
to a type that uses a type modifier involves two steps, one to
convert between datatypes and a second to apply the modifier.
</para>
</refsect1>
<refsect1 id="sql-createcast-notes">
......@@ -207,10 +242,40 @@ SELECT 'The time is ' || CAST(now() AS text);
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
system catalogs. (The built-in cast functions still follow this naming
scheme, but they have to be shown as casts in the system catalog <literal>pg_cast</>
now.)
system catalogs. The built-in cast functions still follow this naming
scheme, but they have to be shown as casts in the system catalog
<structname>pg_cast</> as well.
</para>
<para>
While not required, it is recommended that you continue to follow this old
convention of naming cast implementation functions after the target data
type. Many users are used to being able to cast datatypes using a
function-style notation, that is
<replaceable>typename</>(<replaceable>x</>). This notation is in fact
nothing more nor less than a call of the cast implementation function; it
is not specially treated as a cast. If your conversion functions are not
named to support this convention then you will have surprised users.
Since <productname>PostgreSQL</> allows overloading of the same function
name with different argument types, there is no difficulty in having
multiple conversion functions from different types that all use the
target type's name.
</para>
<note>
<para>
There is one small lie in the preceding paragraph: there is still one
case in which <structname>pg_cast</> will be used to resolve the
meaning of an apparent function call. If a
function call <replaceable>name</>(<replaceable>x</>) matches no
actual function, but <replaceable>name</> is the name of a data type
and <structname>pg_cast</> shows a binary-compatible cast to this
type from the type of <replaceable>x</>, then the call will be construed
as an explicit cast. This exception is made so that binary-compatible
casts can be invoked using functional syntax, even though they lack
any function.
</para>
</note>
</refsect1>
......@@ -234,7 +299,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. <literal>AS IMPLICIT</> is a <productname>PostgreSQL</productname>
types or extra arguments to implementation functions.
<literal>AS IMPLICIT</> is a <productname>PostgreSQL</productname>
extension, too.
</para>
</refsect1>
......
<!--
$PostgreSQL: pgsql/doc/src/sgml/syntax.sgml,v 1.93 2004/06/07 04:04:47 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/syntax.sgml,v 1.94 2004/06/16 01:26:38 tgl Exp $
-->
<chapter id="sql-syntax">
......@@ -1319,7 +1319,7 @@ CAST ( <replaceable>expression</replaceable> AS <replaceable>type</replaceable>
<para>
When a cast is applied to a value expression of a known type, it
represents a run-time type conversion. The cast will succeed only
if a suitable type conversion function is available. Notice that this
if a suitable type conversion operation has been defined. Notice that this
is subtly different from the use of casts with constants, as shown in
<xref linkend="sql-syntax-constants-generic">. A cast applied to an
unadorned string literal represents the initial assignment of a type
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.226 2004/06/06 00:41:26 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.227 2004/06/16 01:26:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1565,7 +1565,7 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
node = coerce_to_domain((Node *) prm,
prm->paramtype,
attr[attnum - 1]->atttypid,
COERCE_IMPLICIT_CAST);
COERCE_IMPLICIT_CAST, false);
constraintexprs[attnum - 1] = ExecPrepareExpr((Expr *) node,
estate);
......
......@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.47 2004/05/26 04:41:11 neilc Exp $
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.48 2004/06/16 01:26:42 tgl Exp $
*
* DESCRIPTION
* These routines take the parse tree and pick out the
......@@ -809,6 +809,7 @@ CreateCast(CreateCastStmt *stmt)
Oid sourcetypeid;
Oid targettypeid;
Oid funcid;
int nargs;
char castcontext;
Relation relation;
HeapTuple tuple;
......@@ -831,11 +832,6 @@ CreateCast(CreateCastStmt *stmt)
errmsg("target data type %s does not exist",
TypeNameToString(stmt->targettype))));
if (sourcetypeid == targettypeid)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("source data type and target data type are the same")));
/* No shells, no pseudo-types allowed */
if (!get_typisdefined(sourcetypeid))
ereport(ERROR,
......@@ -885,14 +881,23 @@ CreateCast(CreateCastStmt *stmt)
elog(ERROR, "cache lookup failed for function %u", funcid);
procstruct = (Form_pg_proc) GETSTRUCT(tuple);
if (procstruct->pronargs != 1)
nargs = procstruct->pronargs;
if (nargs < 1 || nargs > 3)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("cast function must take one argument")));
errmsg("cast function must take one to three arguments")));
if (procstruct->proargtypes[0] != sourcetypeid)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("argument of cast function must match source data type")));
if (nargs > 1 && procstruct->proargtypes[1] != INT4OID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("second argument of cast function must be type integer")));
if (nargs > 2 && procstruct->proargtypes[2] != BOOLOID)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("third argument of cast function must be type boolean")));
if (procstruct->prorettype != targettypeid)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
......@@ -931,6 +936,7 @@ CreateCast(CreateCastStmt *stmt)
/* indicates binary coercibility */
funcid = InvalidOid;
nargs = 0;
/*
* Must be superuser to create binary-compatible casts, since
......@@ -957,6 +963,15 @@ CreateCast(CreateCastStmt *stmt)
errmsg("source and target data types are not physically compatible")));
}
/*
* Allow source and target types to be same only for length coercion
* functions. We assume a multi-arg function does length coercion.
*/
if (sourcetypeid == targettypeid && nargs < 2)
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("source data type and target data type are the same")));
/* convert CoercionContext enum to char value for castcontext */
switch (stmt->context)
{
......
......@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.68 2004/05/30 23:40:29 neilc Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.69 2004/06/16 01:26:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -199,7 +199,8 @@ expand_targetlist(List *tlist, int command_type,
new_expr = coerce_to_domain(new_expr,
InvalidOid,
atttype,
COERCE_IMPLICIT_CAST);
COERCE_IMPLICIT_CAST,
false);
}
else
{
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.132 2004/06/09 19:08:17 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.133 2004/06/16 01:26:44 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -915,11 +915,11 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
* Insert coercion functions if needed. Note that a difference in
* typmod can only happen if input has typmod but outcoltypmod is -1.
* In that case we insert a RelabelType to clearly mark that result's
* typmod is not same as input.
* typmod is not same as input. We never need coerce_type_typmod.
*/
if (l_colvar->vartype != outcoltype)
l_node = coerce_type(pstate, (Node *) l_colvar, l_colvar->vartype,
outcoltype,
outcoltype, outcoltypmod,
COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
else if (l_colvar->vartypmod != outcoltypmod)
l_node = (Node *) makeRelabelType((Expr *) l_colvar,
......@@ -930,7 +930,7 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
if (r_colvar->vartype != outcoltype)
r_node = coerce_type(pstate, (Node *) r_colvar, r_colvar->vartype,
outcoltype,
outcoltype, outcoltypmod,
COERCION_IMPLICIT, COERCE_IMPLICIT_CAST);
else if (r_colvar->vartypmod != outcoltypmod)
r_node = (Node *) makeRelabelType((Expr *) r_colvar,
......@@ -1276,7 +1276,7 @@ transformGroupClause(ParseState *pstate, List *grouplist,
if (restype == UNKNOWNOID)
{
tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr,
restype, TEXTOID,
restype, TEXTOID, -1,
COERCION_IMPLICIT,
COERCE_IMPLICIT_CAST);
restype = tle->resdom->restype = TEXTOID;
......@@ -1528,7 +1528,7 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
if (restype == UNKNOWNOID && resolveUnknown)
{
tle->expr = (Expr *) coerce_type(pstate, (Node *) tle->expr,
restype, TEXTOID,
restype, TEXTOID, -1,
COERCION_IMPLICIT,
COERCE_IMPLICIT_CAST);
restype = tle->resdom->restype = TEXTOID;
......
This diff is collapsed.
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.173 2004/06/09 19:08:17 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.174 2004/06/16 01:26:44 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1578,6 +1578,9 @@ 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.
*
* Note that a combined type-and-length coercion will be treated as a
* length coercion by this routine.
*/
bool
exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.170 2004/05/30 23:40:35 neilc Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.171 2004/06/16 01:26:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -150,7 +150,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
* these cases, so why duplicate code...
*/
return coerce_type(pstate, linitial(fargs),
actual_arg_types[0], rettype,
actual_arg_types[0], rettype, -1,
COERCION_EXPLICIT, COERCE_EXPLICIT_CALL);
}
else if (fdresult == FUNCDETAIL_NORMAL)
......@@ -726,11 +726,12 @@ func_get_detail(List *funcname,
{
Oid sourceType = argtypes[0];
Node *arg1 = linitial(fargs);
Oid cfuncid;
if ((sourceType == UNKNOWNOID && IsA(arg1, Const)) ||
(find_coercion_pathway(targetType, sourceType,
COERCION_EXPLICIT, funcid) &&
*funcid == InvalidOid))
COERCION_EXPLICIT, &cfuncid) &&
cfuncid == InvalidOid))
{
/* Yup, it's a type coercion */
*funcid = InvalidOid;
......@@ -1122,7 +1123,7 @@ make_fn_arguments(ParseState *pstate,
lfirst(current_fargs) = coerce_type(pstate,
lfirst(current_fargs),
actual_arg_types[i],
declared_arg_types[i],
declared_arg_types[i], -1,
COERCION_IMPLICIT,
COERCE_IMPLICIT_CAST);
}
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.139 2004/06/09 19:08:17 tgl Exp $
* $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.140 2004/06/16 01:26:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -367,7 +367,8 @@ rewriteTargetList(Query *parsetree, Relation target_relation)
new_expr = coerce_to_domain(new_expr,
InvalidOid,
att_tup->atttypid,
COERCE_IMPLICIT_CAST);
COERCE_IMPLICIT_CAST,
false);
}
}
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.104 2004/06/08 20:28:21 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.105 2004/06/16 01:26:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -109,6 +109,11 @@ static void array_insert_slice(int ndim, int *dim, int *lb,
int *st, int *endp, char *srcPtr,
int typlen, bool typbyval, char typalign);
static int array_cmp(FunctionCallInfo fcinfo);
static Datum array_type_length_coerce_internal(ArrayType *src,
int32 desttypmod,
bool isExplicit,
FmgrInfo *fmgr_info);
/*---------------------------------------------------------------------
* array_in :
......@@ -1174,82 +1179,6 @@ array_send(PG_FUNCTION_ARGS)
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
/*-------------------------------------------------------------------------
* 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;
typedef struct
{
Oid elemtype;
FmgrInfo coerce_finfo;
} alc_extra;
alc_extra *my_extra;
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, assuming the element type doesn't change
* underneath us.
*/
my_extra = (alc_extra *) fmgr_info->fn_extra;
if (my_extra == NULL)
{
fmgr_info->fn_extra = MemoryContextAlloc(fmgr_info->fn_mcxt,
sizeof(alc_extra));
my_extra = (alc_extra *) fmgr_info->fn_extra;
my_extra->elemtype = InvalidOid;
}
if (my_extra->elemtype != ARR_ELEMTYPE(v))
{
Oid funcId;
int nargs;
funcId = find_typmod_coercion_function(ARR_ELEMTYPE(v), &nargs);
if (OidIsValid(funcId))
fmgr_info_cxt(funcId, &my_extra->coerce_finfo, fmgr_info->fn_mcxt);
else
my_extra->coerce_finfo.fn_oid = InvalidOid;
my_extra->elemtype = ARR_ELEMTYPE(v);
}
/*
* 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 (my_extra->coerce_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 = &my_extra->coerce_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"
......@@ -2879,6 +2808,9 @@ array_insert_slice(int ndim,
* array_type_coerce -- allow explicit or assignment coercion from
* one array type to another.
*
* array_type_length_coerce -- the same, for cases where both type and length
* coercion are done by a single function on the element type.
*
* Caller should have already verified that the source element type can be
* coerced into the target element type.
*/
......@@ -2886,8 +2818,30 @@ Datum
array_type_coerce(PG_FUNCTION_ARGS)
{
ArrayType *src = PG_GETARG_ARRAYTYPE_P(0);
Oid src_elem_type = ARR_ELEMTYPE(src);
FmgrInfo *fmgr_info = fcinfo->flinfo;
return array_type_length_coerce_internal(src, -1, false, fmgr_info);
}
Datum
array_type_length_coerce(PG_FUNCTION_ARGS)
{
ArrayType *src = PG_GETARG_ARRAYTYPE_P(0);
int32 desttypmod = PG_GETARG_INT32(1);
bool isExplicit = PG_GETARG_BOOL(2);
FmgrInfo *fmgr_info = fcinfo->flinfo;
return array_type_length_coerce_internal(src, desttypmod,
isExplicit, fmgr_info);
}
static Datum
array_type_length_coerce_internal(ArrayType *src,
int32 desttypmod,
bool isExplicit,
FmgrInfo *fmgr_info)
{
Oid src_elem_type = ARR_ELEMTYPE(src);
typedef struct
{
Oid srctype;
......@@ -2946,7 +2900,8 @@ array_type_coerce(PG_FUNCTION_ARGS)
{
/* should never happen, but check anyway */
elog(ERROR, "no conversion function from %s to %s",
format_type_be(src_elem_type), format_type_be(tgt_elem_type));
format_type_be(src_elem_type),
format_type_be(tgt_elem_type));
}
if (OidIsValid(funcId))
fmgr_info_cxt(funcId, &my_extra->coerce_finfo, fmgr_info->fn_mcxt);
......@@ -2962,23 +2917,103 @@ array_type_coerce(PG_FUNCTION_ARGS)
*/
if (my_extra->coerce_finfo.fn_oid == InvalidOid)
{
ArrayType *result = DatumGetArrayTypePCopy(PG_GETARG_DATUM(0));
ArrayType *result;
result = (ArrayType *) DatumGetPointer(datumCopy(PointerGetDatum(src),
false, -1));
ARR_ELEMTYPE(result) = my_extra->desttype;
PG_RETURN_ARRAYTYPE_P(result);
}
/*
* Use array_map to apply the function to each array element.
*
* We pass on the desttypmod and isExplicit flags whether or not the
* function wants them.
*/
MemSet(&locfcinfo, 0, sizeof(locfcinfo));
locfcinfo.flinfo = &my_extra->coerce_finfo;
locfcinfo.nargs = 1;
locfcinfo.nargs = 3;
locfcinfo.arg[0] = PointerGetDatum(src);
locfcinfo.arg[1] = Int32GetDatum(desttypmod);
locfcinfo.arg[2] = BoolGetDatum(isExplicit);
return array_map(&locfcinfo, my_extra->srctype, my_extra->desttype);
}
/*
* 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 desttypmod = PG_GETARG_INT32(1);
bool isExplicit = PG_GETARG_BOOL(2);
FmgrInfo *fmgr_info = fcinfo->flinfo;
typedef struct
{
Oid elemtype;
FmgrInfo coerce_finfo;
} alc_extra;
alc_extra *my_extra;
FunctionCallInfoData locfcinfo;
/* If no typmod is provided, shortcircuit the whole thing */
if (desttypmod < 0)
PG_RETURN_ARRAYTYPE_P(v);
/*
* We arrange to look up the element type's coercion function only
* once per series of calls, assuming the element type doesn't change
* underneath us.
*/
my_extra = (alc_extra *) fmgr_info->fn_extra;
if (my_extra == NULL)
{
fmgr_info->fn_extra = MemoryContextAlloc(fmgr_info->fn_mcxt,
sizeof(alc_extra));
my_extra = (alc_extra *) fmgr_info->fn_extra;
my_extra->elemtype = InvalidOid;
}
if (my_extra->elemtype != ARR_ELEMTYPE(v))
{
Oid funcId;
funcId = find_typmod_coercion_function(ARR_ELEMTYPE(v));
if (OidIsValid(funcId))
fmgr_info_cxt(funcId, &my_extra->coerce_finfo, fmgr_info->fn_mcxt);
else
my_extra->coerce_finfo.fn_oid = InvalidOid;
my_extra->elemtype = ARR_ELEMTYPE(v);
}
/*
* 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 (my_extra->coerce_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 = &my_extra->coerce_finfo;
locfcinfo.nargs = 3;
locfcinfo.arg[0] = PointerGetDatum(v);
locfcinfo.arg[1] = Int32GetDatum(desttypmod);
locfcinfo.arg[2] = BoolGetDatum(isExplicit);
return array_map(&locfcinfo, ARR_ELEMTYPE(v), ARR_ELEMTYPE(v));
}
/*
* accumArrayResult - accumulate one (more) Datum for an array result
*
......
......@@ -3,7 +3,7 @@
* back to source text
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.171 2004/06/09 19:08:18 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.172 2004/06/16 01:26:47 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
......@@ -194,7 +194,6 @@ static void get_oper_expr(OpExpr *expr, deparse_context *context);
static void get_func_expr(FuncExpr *expr, deparse_context *context,
bool showimplicit);
static void get_agg_expr(Aggref *aggref, deparse_context *context);
static Node *strip_type_coercion(Node *expr, Oid resultType);
static void get_const_expr(Const *constval, deparse_context *context);
static void get_sublink_expr(SubLink *sublink, deparse_context *context);
static void get_from_clause(Query *query, deparse_context *context);
......@@ -2983,22 +2982,13 @@ get_rule_expr(Node *node, deparse_context *context,
!showimplicit)
{
/* don't show the implicit cast */
get_rule_expr_paren(arg, context, showimplicit, node);
get_rule_expr_paren(arg, context, false, node);
}
else
{
/*
* Strip off any type coercions on the input, so we
* don't print redundancies like
* x::bpchar::character(8).
*
* XXX Are there any cases where this is a bad idea?
*/
arg = strip_type_coercion(arg, relabel->resulttype);
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, '(');
get_rule_expr_paren(arg, context, showimplicit, node);
get_rule_expr_paren(arg, context, false, node);
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')');
appendStringInfo(buf, "::%s",
......@@ -3206,11 +3196,6 @@ get_rule_expr(Node *node, deparse_context *context,
CoerceToDomain *ctest = (CoerceToDomain *) node;
Node *arg = (Node *) ctest->arg;
/*
* Any implicit coercion at the top level of the argument
* is presumably due to the domain's own internal typmod
* coercion, so do not force it to be shown.
*/
if (ctest->coercionformat == COERCE_IMPLICIT_CAST &&
!showimplicit)
{
......@@ -3331,7 +3316,7 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
if (expr->funcformat == COERCE_IMPLICIT_CAST && !showimplicit)
{
get_rule_expr_paren((Node *) linitial(expr->args), context,
showimplicit, (Node *) expr);
false, (Node *) expr);
return;
}
......@@ -3349,17 +3334,9 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
/* Get the typmod if this is a length-coercion function */
(void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
/*
* Strip off any type coercions on the input, so we don't print
* redundancies like x::bpchar::character(8).
*
* XXX Are there any cases where this is a bad idea?
*/
arg = strip_type_coercion(arg, rettype);
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, '(');
get_rule_expr_paren(arg, context, showimplicit, (Node *) expr);
get_rule_expr_paren(arg, context, false, (Node *) expr);
if (!PRETTY_PAREN(context))
appendStringInfoChar(buf, ')');
appendStringInfo(buf, "::%s",
......@@ -3413,46 +3390,6 @@ get_agg_expr(Aggref *aggref, deparse_context *context)
}
/*
* strip_type_coercion
* Strip any type coercion at the top of the given expression tree,
* if it is a coercion to the given datatype.
*
* We use this to avoid printing two levels of coercion in situations where
* the expression tree has a length-coercion node atop a type-coercion node.
*
* Note: avoid stripping a length-coercion node, since two successive
* coercions to different lengths aren't a no-op. Also, never strip a
* CoerceToDomain node, even though it might be effectively just RelabelType.
*/
static Node *
strip_type_coercion(Node *expr, Oid resultType)
{
if (expr == NULL || exprType(expr) != resultType)
return expr;
if (IsA(expr, RelabelType) &&
((RelabelType *) expr)->resulttypmod == -1)
return (Node *) ((RelabelType *) expr)->arg;
if (IsA(expr, FuncExpr))
{
FuncExpr *func = (FuncExpr *) expr;
if (func->funcformat != COERCE_EXPLICIT_CAST &&
func->funcformat != COERCE_IMPLICIT_CAST)
return expr; /* don't absorb into upper coercion */
if (exprIsLengthCoercion(expr, NULL))
return expr;
return (Node *) linitial(func->args);
}
return expr;
}
/* ----------
* get_const_expr
*
......
......@@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.38 2003/11/29 19:51:59 pgsql Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.39 2004/06/16 01:26:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1166,32 +1166,58 @@ bitshiftright(PG_FUNCTION_ARGS)
PG_RETURN_VARBIT_P(result);
}
/* This is not defined in any standard. We retain the natural ordering of
/*
* This is not defined in any standard. We retain the natural ordering of
* bits here, as it just seems more intuitive.
*/
Datum
bitfromint4(PG_FUNCTION_ARGS)
{
int32 a = PG_GETARG_INT32(0);
int32 typmod = PG_GETARG_INT32(1);
VarBit *result;
bits8 *r;
int len;
int rlen;
int destbitsleft,
srcbitsleft;
/* allocate enough space for the bits in an int4 */
len = VARBITTOTALLEN(sizeof(int4) * BITS_PER_BYTE);
result = (VarBit *) palloc(len);
VARATT_SIZEP(result) = len;
VARBITLEN(result) = sizeof(int4) * BITS_PER_BYTE;
if (typmod <= 0)
typmod = 1; /* default bit length */
rlen = VARBITTOTALLEN(typmod);
result = (VarBit *) palloc(rlen);
VARATT_SIZEP(result) = rlen;
VARBITLEN(result) = typmod;
/*
* masks and shifts here are just too painful and we know that an int4
* has got 4 bytes
*/
r = VARBITS(result);
r[0] = (bits8) ((a >> (3 * BITS_PER_BYTE)) & BITMASK);
r[1] = (bits8) ((a >> (2 * BITS_PER_BYTE)) & BITMASK);
r[2] = (bits8) ((a >> (1 * BITS_PER_BYTE)) & BITMASK);
r[3] = (bits8) (a & BITMASK);
destbitsleft = typmod;
srcbitsleft = 32;
/* drop any input bits that don't fit */
srcbitsleft = Min(srcbitsleft, destbitsleft);
/* sign-fill any excess bytes in output */
while (destbitsleft >= srcbitsleft + 8)
{
*r++ = (bits8) ((a < 0) ? BITMASK : 0);
destbitsleft -= 8;
}
/* store first fractional byte */
if (destbitsleft > srcbitsleft)
{
*r++ = (bits8) ((a >> (srcbitsleft - 8)) & BITMASK);
destbitsleft -= 8;
}
/* Now srcbitsleft and destbitsleft are the same, need not track both */
/* store whole bytes */
while (destbitsleft >= 8)
{
*r++ = (bits8) ((a >> (destbitsleft - 8)) & BITMASK);
destbitsleft -= 8;
}
/* store last fractional byte */
if (destbitsleft > 0)
{
*r = (bits8) ((a << (8 - destbitsleft)) & BITMASK);
}
PG_RETURN_VARBIT_P(result);
}
......@@ -1204,7 +1230,7 @@ bittoint4(PG_FUNCTION_ARGS)
bits8 *r;
/* Check that the bit string is not too long */
if (VARBITLEN(arg) > sizeof(int4) * BITS_PER_BYTE)
if (VARBITLEN(arg) > sizeof(result) * BITS_PER_BYTE)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
......@@ -1224,46 +1250,62 @@ bittoint4(PG_FUNCTION_ARGS)
Datum
bitfromint8(PG_FUNCTION_ARGS)
{
#ifndef INT64_IS_BUSTED
int64 a = PG_GETARG_INT64(0);
int32 typmod = PG_GETARG_INT32(1);
VarBit *result;
bits8 *r;
int len;
int rlen;
int destbitsleft,
srcbitsleft;
/* allocate enough space for the bits in an int64 */
len = VARBITTOTALLEN(sizeof(a) * BITS_PER_BYTE);
result = (VarBit *) palloc(len);
VARATT_SIZEP(result) = len;
VARBITLEN(result) = sizeof(a) * BITS_PER_BYTE;
if (typmod <= 0)
typmod = 1; /* default bit length */
/*
* masks and shifts here are just too painful and we know that an
* int64 has got 8 bytes
*/
r = VARBITS(result);
r[0] = (bits8) ((a >> (7 * BITS_PER_BYTE)) & BITMASK);
r[1] = (bits8) ((a >> (6 * BITS_PER_BYTE)) & BITMASK);
r[2] = (bits8) ((a >> (5 * BITS_PER_BYTE)) & BITMASK);
r[3] = (bits8) ((a >> (4 * BITS_PER_BYTE)) & BITMASK);
r[4] = (bits8) ((a >> (3 * BITS_PER_BYTE)) & BITMASK);
r[5] = (bits8) ((a >> (2 * BITS_PER_BYTE)) & BITMASK);
r[6] = (bits8) ((a >> (1 * BITS_PER_BYTE)) & BITMASK);
r[7] = (bits8) (a & BITMASK);
rlen = VARBITTOTALLEN(typmod);
result = (VarBit *) palloc(rlen);
VARATT_SIZEP(result) = rlen;
VARBITLEN(result) = typmod;
PG_RETURN_VARBIT_P(result);
r = VARBITS(result);
destbitsleft = typmod;
#ifndef INT64_IS_BUSTED
srcbitsleft = 64;
#else
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("64-bit integers not supported on this platform")));
PG_RETURN_NULL();
srcbitsleft = 32; /* don't try to shift more than 32 */
#endif
/* drop any input bits that don't fit */
srcbitsleft = Min(srcbitsleft, destbitsleft);
/* sign-fill any excess bytes in output */
while (destbitsleft >= srcbitsleft + 8)
{
*r++ = (bits8) ((a < 0) ? BITMASK : 0);
destbitsleft -= 8;
}
/* store first fractional byte */
if (destbitsleft > srcbitsleft)
{
*r++ = (bits8) ((a >> (srcbitsleft - 8)) & BITMASK);
destbitsleft -= 8;
}
/* Now srcbitsleft and destbitsleft are the same, need not track both */
/* store whole bytes */
while (destbitsleft >= 8)
{
*r++ = (bits8) ((a >> (destbitsleft - 8)) & BITMASK);
destbitsleft -= 8;
}
/* store last fractional byte */
if (destbitsleft > 0)
{
*r = (bits8) ((a << (8 - destbitsleft)) & BITMASK);
}
PG_RETURN_VARBIT_P(result);
}
Datum
bittoint8(PG_FUNCTION_ARGS)
{
#ifndef INT64_IS_BUSTED
VarBit *arg = PG_GETARG_VARBIT_P(0);
uint64 result;
bits8 *r;
......@@ -1284,13 +1326,6 @@ bittoint8(PG_FUNCTION_ARGS)
result >>= VARBITPAD(arg);
PG_RETURN_INT64(result);
#else
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("64-bit integers not supported on this platform")));
PG_RETURN_NULL();
#endif
}
......
......@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.235 2004/06/13 21:57:25 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.236 2004/06/16 01:26:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200406131
#define CATALOG_VERSION_NO 200406151
#endif
......@@ -4,10 +4,13 @@
* definition of the system "type casts" relation (pg_cast)
* along with the relation's initial contents.
*
* As of Postgres 7.5, pg_cast describes not only type coercion functions
* but also length coercion functions.
*
*
* Copyright (c) 2002-2003, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.11 2004/03/15 01:13:41 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_cast.h,v 1.12 2004/06/16 01:26:49 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
......@@ -361,4 +364,18 @@ DATA(insert ( 1042 1266 938 e ));
DATA(insert ( 1700 1042 1688 a ));
DATA(insert ( 1042 1700 1686 e ));
/*
* Length-coercion functions
*/
DATA(insert ( 1042 1042 668 i ));
DATA(insert ( 1043 1043 669 i ));
DATA(insert ( 1083 1083 1968 i ));
DATA(insert ( 1114 1114 1961 i ));
DATA(insert ( 1184 1184 1967 i ));
DATA(insert ( 1186 1186 1200 i ));
DATA(insert ( 1266 1266 1969 i ));
DATA(insert ( 1560 1560 1685 i ));
DATA(insert ( 1562 1562 1687 i ));
DATA(insert ( 1700 1700 1703 i ));
#endif /* PG_CAST_H */
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.337 2004/06/13 21:57:26 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.338 2004/06/16 01:26:49 tgl Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
......@@ -1028,8 +1028,8 @@ DATA(insert OID = 379 ( array_prepend PGNSP PGUID 12 f f t f i 2 2277 "2283
DESCR("prepend element onto front of array");
DATA(insert OID = 383 ( array_cat PGNSP PGUID 12 f f t f i 2 2277 "2277 2277" _null_ array_cat - _null_ ));
DESCR("concatenate two arrays");
DATA(insert OID = 384 ( array_coerce PGNSP PGUID 12 f f t f i 1 2277 "2277" _null_ array_type_coerce - _null_ ));
DESCR("coerce array type to another array type");
DATA(insert OID = 384 ( array_coerce PGNSP PGUID 12 f f t f s 1 2277 "2277" _null_ array_type_coerce - _null_ ));
DESCR("coerce array to another array type");
DATA(insert OID = 394 ( string_to_array PGNSP PGUID 12 f f t f i 2 1009 "25 25" _null_ text_to_array - _null_ ));
DESCR("split delimited text into text[]");
DATA(insert OID = 395 ( array_to_string PGNSP PGUID 12 f f t f i 2 25 "2277 25" _null_ array_to_text - _null_ ));
......@@ -1587,8 +1587,8 @@ DESCR("convert int8 to text");
DATA(insert OID = 1290 ( int8 PGNSP PGUID 12 f f t f i 1 20 "25" _null_ text_int8 - _null_ ));
DESCR("convert text to int8");
DATA(insert OID = 1291 ( array_length_coerce PGNSP PGUID 12 f f t f i 3 2277 "2277 23 16" _null_ array_length_coerce - _null_ ));
DESCR("adjust any array to element typmod length");
DATA(insert OID = 1291 ( array_length_coerce PGNSP PGUID 12 f f t f s 3 2277 "2277 23 16" _null_ array_length_coerce - _null_ ));
DESCR("adjust any array to new element typmod");
DATA(insert OID = 1292 ( tideq PGNSP PGUID 12 f f t f i 2 16 "27 27" _null_ tideq - _null_ ));
DESCR("equal");
......@@ -1722,6 +1722,9 @@ DESCR("convert time to interval");
DATA(insert OID = 1372 ( char_length PGNSP PGUID 12 f f t f i 1 23 "1042" _null_ bpcharlen - _null_ ));
DESCR("character length");
DATA(insert OID = 1373 ( array_type_length_coerce PGNSP PGUID 12 f f t f s 3 2277 "2277 23 16" _null_ array_type_length_coerce - _null_ ));
DESCR("coerce array to another type and adjust element typmod");
DATA(insert OID = 1374 ( octet_length PGNSP PGUID 12 f f t f i 1 23 "25" _null_ textoctetlen - _null_ ));
DESCR("octet length");
DATA(insert OID = 1375 ( octet_length PGNSP PGUID 12 f f t f i 1 23 "1042" _null_ bpcharoctetlen - _null_ ));
......@@ -2298,7 +2301,7 @@ DATA(insert OID = 1681 ( length PGNSP PGUID 12 f f t f i 1 23 "1560" _null_ b
DESCR("bitstring length");
DATA(insert OID = 1682 ( octet_length PGNSP PGUID 12 f f t f i 1 23 "1560" _null_ bitoctetlength - _null_ ));
DESCR("octet length");
DATA(insert OID = 1683 ( bit PGNSP PGUID 12 f f t f i 1 1560 "23" _null_ bitfromint4 - _null_ ));
DATA(insert OID = 1683 ( bit PGNSP PGUID 12 f f t f i 2 1560 "23 23" _null_ bitfromint4 - _null_ ));
DESCR("int4 to bitstring");
DATA(insert OID = 1684 ( int4 PGNSP PGUID 12 f f t f i 1 23 "1560" _null_ bittoint4 - _null_ ));
DESCR("bitstring to int4");
......@@ -2968,7 +2971,7 @@ DESCR("extracts text matching regular expression");
DATA(insert OID = 2074 ( substring PGNSP PGUID 14 f f t f i 3 25 "25 25 25" _null_ "select pg_catalog.substring($1, pg_catalog.similar_escape($2, $3))" - _null_ ));
DESCR("extracts text matching SQL99 regular expression");
DATA(insert OID = 2075 ( bit PGNSP PGUID 12 f f t f i 1 1560 "20" _null_ bitfromint8 - _null_ ));
DATA(insert OID = 2075 ( bit PGNSP PGUID 12 f f t f i 2 1560 "20 23" _null_ bitfromint8 - _null_ ));
DESCR("int8 to bitstring");
DATA(insert OID = 2076 ( int8 PGNSP PGUID 12 f f t f i 1 20 "1560" _null_ bittoint8 - _null_ ));
DESCR("bitstring to int8");
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.56 2003/11/29 22:41:09 pgsql Exp $
* $PostgreSQL: pgsql/src/include/parser/parse_coerce.h,v 1.57 2004/06/16 01:26:53 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -47,10 +47,10 @@ extern Node *coerce_to_target_type(ParseState *pstate,
extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
CoercionContext ccontext);
extern Node *coerce_type(ParseState *pstate, Node *node,
Oid inputTypeId, Oid targetTypeId,
Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod,
CoercionContext ccontext, CoercionForm cformat);
extern Node *coerce_to_domain(Node *arg, Oid baseTypeId, Oid typeId,
CoercionForm cformat);
CoercionForm cformat, bool hideInputCoercion);
extern Node *coerce_to_boolean(ParseState *pstate, Node *node,
const char *constructName);
......@@ -76,6 +76,6 @@ extern Oid resolve_generic_type(Oid declared_type,
extern bool find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId,
CoercionContext ccontext,
Oid *funcid);
extern Oid find_typmod_coercion_function(Oid typeId, int *nargs);
extern Oid find_typmod_coercion_function(Oid typeId);
#endif /* PARSE_COERCE_H */
......@@ -10,7 +10,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/array.h,v 1.47 2004/06/06 00:41:28 tgl Exp $
* $PostgreSQL: pgsql/src/include/utils/array.h,v 1.48 2004/06/16 01:26:55 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -116,7 +116,6 @@ extern Datum array_in(PG_FUNCTION_ARGS);
extern Datum array_out(PG_FUNCTION_ARGS);
extern Datum array_recv(PG_FUNCTION_ARGS);
extern Datum array_send(PG_FUNCTION_ARGS);
extern Datum array_length_coerce(PG_FUNCTION_ARGS);
extern Datum array_eq(PG_FUNCTION_ARGS);
extern Datum array_ne(PG_FUNCTION_ARGS);
extern Datum array_lt(PG_FUNCTION_ARGS);
......@@ -128,6 +127,8 @@ extern Datum array_dims(PG_FUNCTION_ARGS);
extern Datum array_lower(PG_FUNCTION_ARGS);
extern Datum array_upper(PG_FUNCTION_ARGS);
extern Datum array_type_coerce(PG_FUNCTION_ARGS);
extern Datum array_type_length_coerce(PG_FUNCTION_ARGS);
extern Datum array_length_coerce(PG_FUNCTION_ARGS);
extern Datum array_ref(ArrayType *array, int nSubscripts, int *indx,
int arraylen, int elmlen, bool elmbyval, char elmalign,
......
......@@ -225,13 +225,28 @@ WHERE p1.prorettype = 'internal'::regtype AND NOT
(1 row)
-- **************** pg_cast ****************
-- Look for casts from and to the same type. This is not harmful, but
-- useless. Also catch bogus values in pg_cast columns (other than
-- cases detected by oidjoins test).
-- Catch bogus values in pg_cast columns (other than cases detected by
-- oidjoins test).
SELECT *
FROM pg_cast c
WHERE castsource = casttarget OR castsource = 0 OR casttarget = 0
OR castcontext NOT IN ('e', 'a', 'i');
WHERE castsource = 0 OR casttarget = 0 OR castcontext NOT IN ('e', 'a', 'i');
castsource | casttarget | castfunc | castcontext
------------+------------+----------+-------------
(0 rows)
-- Look for casts to/from the same type that aren't length coercion functions.
-- (We assume they are length coercions if they take multiple arguments.)
-- Such entries are not necessarily harmful, but they are useless.
SELECT *
FROM pg_cast c
WHERE castsource = casttarget AND castfunc = 0;
castsource | casttarget | castfunc | castcontext
------------+------------+----------+-------------
(0 rows)
SELECT c.*
FROM pg_cast c, pg_proc p
WHERE c.castfunc = p.oid AND p.pronargs < 2 AND castsource = casttarget;
castsource | casttarget | castfunc | castcontext
------------+------------+----------+-------------
(0 rows)
......@@ -246,7 +261,7 @@ WHERE castsource = casttarget OR castsource = 0 OR casttarget = 0
SELECT c.*
FROM pg_cast c, pg_proc p
WHERE c.castfunc = p.oid AND
(p.pronargs <> 1
(p.pronargs < 1 OR p.pronargs > 3
OR NOT (binary_coercible(c.castsource, p.proargtypes[0])
OR (c.castsource = 'character'::regtype AND
p.proargtypes[0] = 'text'::regtype))
......@@ -255,6 +270,15 @@ WHERE c.castfunc = p.oid AND
------------+------------+----------+-------------
(0 rows)
SELECT c.*
FROM pg_cast c, pg_proc p
WHERE c.castfunc = p.oid AND
((p.pronargs > 1 AND p.proargtypes[1] != 'int4'::regtype) OR
(p.pronargs > 2 AND p.proargtypes[2] != 'bool'::regtype));
castsource | casttarget | castfunc | castcontext
------------+------------+----------+-------------
(0 rows)
-- Look for binary compatible casts that do not have the reverse
-- direction registered as well, or where the reverse direction is not
-- also binary compatible. This is legal, but usually not intended.
......
......@@ -184,14 +184,24 @@ WHERE p1.prorettype = 'internal'::regtype AND NOT
-- **************** pg_cast ****************
-- Look for casts from and to the same type. This is not harmful, but
-- useless. Also catch bogus values in pg_cast columns (other than
-- cases detected by oidjoins test).
-- Catch bogus values in pg_cast columns (other than cases detected by
-- oidjoins test).
SELECT *
FROM pg_cast c
WHERE castsource = casttarget OR castsource = 0 OR casttarget = 0
OR castcontext NOT IN ('e', 'a', 'i');
WHERE castsource = 0 OR casttarget = 0 OR castcontext NOT IN ('e', 'a', 'i');
-- Look for casts to/from the same type that aren't length coercion functions.
-- (We assume they are length coercions if they take multiple arguments.)
-- Such entries are not necessarily harmful, but they are useless.
SELECT *
FROM pg_cast c
WHERE castsource = casttarget AND castfunc = 0;
SELECT c.*
FROM pg_cast c, pg_proc p
WHERE c.castfunc = p.oid AND p.pronargs < 2 AND castsource = casttarget;
-- Look for cast functions that don't have the right signature. The
-- argument and result types in pg_proc must be the same as, or binary
......@@ -204,12 +214,18 @@ WHERE castsource = casttarget OR castsource = 0 OR casttarget = 0
SELECT c.*
FROM pg_cast c, pg_proc p
WHERE c.castfunc = p.oid AND
(p.pronargs <> 1
(p.pronargs < 1 OR p.pronargs > 3
OR NOT (binary_coercible(c.castsource, p.proargtypes[0])
OR (c.castsource = 'character'::regtype AND
p.proargtypes[0] = 'text'::regtype))
OR NOT binary_coercible(p.prorettype, c.casttarget));
SELECT c.*
FROM pg_cast c, pg_proc p
WHERE c.castfunc = p.oid AND
((p.pronargs > 1 AND p.proargtypes[1] != 'int4'::regtype) OR
(p.pronargs > 2 AND p.proargtypes[2] != 'bool'::regtype));
-- Look for binary compatible casts that do not have the reverse
-- direction registered as well, or where the reverse direction is not
-- also binary compatible. This is legal, but usually not intended.
......
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