mirror of
https://github.com/postgres/postgres.git
synced 2025-11-10 17:42:29 +03:00
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.
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* back to source text
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.121 2002/09/04 20:31:28 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.122 2002/09/18 21:35:23 tgl Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
@@ -152,7 +152,6 @@ static void get_oper_expr(Expr *expr, deparse_context *context);
|
||||
static void get_func_expr(Expr *expr, deparse_context *context);
|
||||
static void get_agg_expr(Aggref *aggref, deparse_context *context);
|
||||
static Node *strip_type_coercion(Node *expr, Oid resultType);
|
||||
static void get_tle_expr(TargetEntry *tle, deparse_context *context);
|
||||
static void get_const_expr(Const *constval, deparse_context *context);
|
||||
static void get_sublink_expr(Node *node, deparse_context *context);
|
||||
static void get_from_clause(Query *query, deparse_context *context);
|
||||
@@ -1430,7 +1429,6 @@ get_basic_select_query(Query *query, deparse_context *context,
|
||||
sep = ", ";
|
||||
colno++;
|
||||
|
||||
/* Do NOT use get_tle_expr here; see its comments! */
|
||||
get_rule_expr(tle->expr, context);
|
||||
|
||||
/*
|
||||
@@ -1644,7 +1642,7 @@ get_insert_query_def(Query *query, deparse_context *context)
|
||||
|
||||
appendStringInfo(buf, sep);
|
||||
sep = ", ";
|
||||
get_tle_expr(tle, context);
|
||||
get_rule_expr(tle->expr, context);
|
||||
}
|
||||
appendStringInfoChar(buf, ')');
|
||||
}
|
||||
@@ -1694,7 +1692,7 @@ get_update_query_def(Query *query, deparse_context *context)
|
||||
if (!tleIsArrayAssign(tle))
|
||||
appendStringInfo(buf, "%s = ",
|
||||
quote_identifier(tle->resdom->resname));
|
||||
get_tle_expr(tle, context);
|
||||
get_rule_expr(tle->expr, context);
|
||||
}
|
||||
|
||||
/* Add the FROM clause if needed */
|
||||
@@ -2106,12 +2104,29 @@ get_rule_expr(Node *node, deparse_context *context)
|
||||
case T_RelabelType:
|
||||
{
|
||||
RelabelType *relabel = (RelabelType *) node;
|
||||
Node *arg = relabel->arg;
|
||||
|
||||
appendStringInfoChar(buf, '(');
|
||||
get_rule_expr(relabel->arg, context);
|
||||
appendStringInfo(buf, ")::%s",
|
||||
if (relabel->relabelformat == COERCE_IMPLICIT_CAST)
|
||||
{
|
||||
/* don't show an implicit cast */
|
||||
get_rule_expr(arg, context);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Strip off any type coercions on the input, so we don't
|
||||
* print redundancies like x::bpchar::character(8).
|
||||
*
|
||||
* XXX Are there any cases where this is a bad idea?
|
||||
*/
|
||||
arg = strip_type_coercion(arg, relabel->resulttype);
|
||||
|
||||
appendStringInfoChar(buf, '(');
|
||||
get_rule_expr(arg, context);
|
||||
appendStringInfo(buf, ")::%s",
|
||||
format_type_with_typemod(relabel->resulttype,
|
||||
relabel->resulttypmod));
|
||||
relabel->resulttypmod));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2305,21 +2320,33 @@ get_func_expr(Expr *expr, deparse_context *context)
|
||||
StringInfo buf = context->buf;
|
||||
Func *func = (Func *) (expr->oper);
|
||||
Oid funcoid = func->funcid;
|
||||
int32 coercedTypmod;
|
||||
Oid argtypes[FUNC_MAX_ARGS];
|
||||
int nargs;
|
||||
List *l;
|
||||
char *sep;
|
||||
|
||||
/*
|
||||
* Check to see if function is a length-coercion function for some
|
||||
* datatype. If so, display the operation as a type cast.
|
||||
* If the function call came from an implicit coercion, then just show
|
||||
* the first argument.
|
||||
*/
|
||||
if (exprIsLengthCoercion((Node *) expr, &coercedTypmod))
|
||||
if (func->funcformat == COERCE_IMPLICIT_CAST)
|
||||
{
|
||||
get_rule_expr((Node *) lfirst(expr->args), context);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the function call came from an explicit cast, then show
|
||||
* the first argument plus an explicit cast operation.
|
||||
*/
|
||||
if (func->funcformat == COERCE_EXPLICIT_CAST)
|
||||
{
|
||||
Node *arg = lfirst(expr->args);
|
||||
Oid rettype = get_func_rettype(funcoid);
|
||||
char *typdesc;
|
||||
Oid rettype = expr->typeOid;
|
||||
int32 coercedTypmod;
|
||||
|
||||
/* Get the typmod if this is a length-coercion function */
|
||||
(void) exprIsLengthCoercion((Node *) expr, &coercedTypmod);
|
||||
|
||||
/*
|
||||
* Strip off any type coercions on the input, so we don't print
|
||||
@@ -2331,17 +2358,8 @@ get_func_expr(Expr *expr, deparse_context *context)
|
||||
|
||||
appendStringInfoChar(buf, '(');
|
||||
get_rule_expr(arg, context);
|
||||
|
||||
/*
|
||||
* Show typename with appropriate length decoration. Note that
|
||||
* since exprIsLengthCoercion succeeded, the function's output
|
||||
* type is the right thing to report. Also note we don't need to
|
||||
* quote the result of format_type_with_typemod: it takes care of
|
||||
* double-quoting any identifier that needs it.
|
||||
*/
|
||||
typdesc = format_type_with_typemod(rettype, coercedTypmod);
|
||||
appendStringInfo(buf, ")::%s", typdesc);
|
||||
pfree(typdesc);
|
||||
appendStringInfo(buf, ")::%s",
|
||||
format_type_with_typemod(rettype, coercedTypmod));
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -2393,15 +2411,14 @@ get_agg_expr(Aggref *aggref, deparse_context *context)
|
||||
|
||||
/*
|
||||
* strip_type_coercion
|
||||
* Strip any type coercions at the top of the given expression tree,
|
||||
* as long as they are coercions to the given datatype.
|
||||
* Strip any type coercion at the top of the given expression tree,
|
||||
* if it is a coercion to the given datatype.
|
||||
*
|
||||
* A RelabelType node is always a type coercion. A function call is
|
||||
* also considered a type coercion if it has one argument and there is
|
||||
* a cast declared that uses it.
|
||||
* We use this to avoid printing two levels of coercion in situations where
|
||||
* the expression tree has a length-coercion node atop a type-coercion node.
|
||||
*
|
||||
* XXX It'd be better if the parsetree retained some explicit indication
|
||||
* of the coercion, so we didn't need these heuristics.
|
||||
* Note: avoid stripping a length-coercion node, since two successive
|
||||
* coercions to different lengths aren't a no-op.
|
||||
*/
|
||||
static Node *
|
||||
strip_type_coercion(Node *expr, Oid resultType)
|
||||
@@ -2409,101 +2426,30 @@ strip_type_coercion(Node *expr, Oid resultType)
|
||||
if (expr == NULL || exprType(expr) != resultType)
|
||||
return expr;
|
||||
|
||||
if (IsA(expr, RelabelType))
|
||||
return strip_type_coercion(((RelabelType *) expr)->arg, resultType);
|
||||
if (IsA(expr, RelabelType) &&
|
||||
((RelabelType *) expr)->resulttypmod == -1)
|
||||
return ((RelabelType *) expr)->arg;
|
||||
|
||||
if (IsA(expr, Expr) &&
|
||||
((Expr *) expr)->opType == FUNC_EXPR)
|
||||
{
|
||||
Func *func;
|
||||
HeapTuple procTuple;
|
||||
HeapTuple castTuple;
|
||||
Form_pg_proc procStruct;
|
||||
Form_pg_cast castStruct;
|
||||
Func *func = (Func *) (((Expr *) expr)->oper);
|
||||
|
||||
func = (Func *) (((Expr *) expr)->oper);
|
||||
Assert(IsA(func, Func));
|
||||
if (length(((Expr *) expr)->args) != 1)
|
||||
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;
|
||||
/* Lookup the function in pg_proc */
|
||||
procTuple = SearchSysCache(PROCOID,
|
||||
ObjectIdGetDatum(func->funcid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(procTuple))
|
||||
elog(ERROR, "cache lookup for proc %u failed", func->funcid);
|
||||
procStruct = (Form_pg_proc) GETSTRUCT(procTuple);
|
||||
/* Double-check func has one arg and correct result type */
|
||||
if (procStruct->pronargs != 1 ||
|
||||
procStruct->prorettype != resultType)
|
||||
{
|
||||
ReleaseSysCache(procTuple);
|
||||
return expr;
|
||||
}
|
||||
/* See if function has is actually declared as a cast */
|
||||
castTuple = SearchSysCache(CASTSOURCETARGET,
|
||||
ObjectIdGetDatum(procStruct->proargtypes[0]),
|
||||
ObjectIdGetDatum(procStruct->prorettype),
|
||||
0, 0);
|
||||
if (!HeapTupleIsValid(castTuple))
|
||||
{
|
||||
ReleaseSysCache(procTuple);
|
||||
return expr;
|
||||
}
|
||||
/* It must also be an implicit cast. */
|
||||
castStruct = (Form_pg_cast) GETSTRUCT(castTuple);
|
||||
if (!castStruct->castimplicit)
|
||||
{
|
||||
ReleaseSysCache(procTuple);
|
||||
ReleaseSysCache(castTuple);
|
||||
return expr;
|
||||
}
|
||||
/* Okay, it is indeed a type-coercion function */
|
||||
ReleaseSysCache(procTuple);
|
||||
ReleaseSysCache(castTuple);
|
||||
return strip_type_coercion(lfirst(((Expr *) expr)->args), resultType);
|
||||
|
||||
return (Node *) lfirst(((Expr *) expr)->args);
|
||||
}
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
||||
/* ----------
|
||||
* get_tle_expr
|
||||
*
|
||||
* In an INSERT or UPDATE targetlist item, the parser may have inserted
|
||||
* a length-coercion function call to coerce the value to the right
|
||||
* length for the target column. We want to suppress the output of
|
||||
* that function call, otherwise dump/reload/dump... would blow up the
|
||||
* expression by adding more and more layers of length-coercion calls.
|
||||
*
|
||||
* As of 7.0, this hack is no longer absolutely essential, because the parser
|
||||
* is now smart enough not to add a redundant length coercion function call.
|
||||
* But we still suppress the function call just for neatness of displayed
|
||||
* rules.
|
||||
*
|
||||
* Note that this hack must NOT be applied to SELECT targetlist items;
|
||||
* any length coercion appearing there is something the user actually wrote.
|
||||
* ----------
|
||||
*/
|
||||
static void
|
||||
get_tle_expr(TargetEntry *tle, deparse_context *context)
|
||||
{
|
||||
Expr *expr = (Expr *) (tle->expr);
|
||||
int32 coercedTypmod;
|
||||
|
||||
/*
|
||||
* If top level is a length coercion to the correct length, suppress
|
||||
* it; else dump the expression normally.
|
||||
*/
|
||||
if (tle->resdom->restypmod >= 0 &&
|
||||
exprIsLengthCoercion((Node *) expr, &coercedTypmod) &&
|
||||
coercedTypmod == tle->resdom->restypmod)
|
||||
get_rule_expr((Node *) lfirst(expr->args), context);
|
||||
else
|
||||
get_rule_expr(tle->expr, context);
|
||||
}
|
||||
|
||||
|
||||
/* ----------
|
||||
* get_const_expr
|
||||
*
|
||||
@@ -2518,6 +2464,8 @@ get_const_expr(Const *constval, deparse_context *context)
|
||||
Form_pg_type typeStruct;
|
||||
char *extval;
|
||||
char *valptr;
|
||||
bool isfloat = false;
|
||||
bool needlabel;
|
||||
|
||||
if (constval->constisnull)
|
||||
{
|
||||
@@ -2563,8 +2511,12 @@ get_const_expr(Const *constval, deparse_context *context)
|
||||
* NaN, so we need not get too crazy about pattern
|
||||
* matching here.
|
||||
*/
|
||||
if (strspn(extval, "0123456789 +-eE.") == strlen(extval))
|
||||
if (strspn(extval, "0123456789+-eE.") == strlen(extval))
|
||||
{
|
||||
appendStringInfo(buf, extval);
|
||||
if (strcspn(extval, "eE.") != strlen(extval))
|
||||
isfloat = true; /* it looks like a float */
|
||||
}
|
||||
else
|
||||
appendStringInfo(buf, "'%s'", extval);
|
||||
}
|
||||
@@ -2609,20 +2561,30 @@ get_const_expr(Const *constval, deparse_context *context)
|
||||
|
||||
pfree(extval);
|
||||
|
||||
/*
|
||||
* Append ::typename unless the constant will be implicitly typed as
|
||||
* the right type when it is read in. XXX this code has to be kept
|
||||
* in sync with the behavior of the parser, especially make_const.
|
||||
*/
|
||||
switch (constval->consttype)
|
||||
{
|
||||
case BOOLOID:
|
||||
case INT4OID:
|
||||
case FLOAT8OID:
|
||||
case UNKNOWNOID:
|
||||
/* These types can be left unlabeled */
|
||||
needlabel = false;
|
||||
break;
|
||||
case NUMERICOID:
|
||||
/* Float-looking constants will be typed as numeric */
|
||||
needlabel = !isfloat;
|
||||
break;
|
||||
default:
|
||||
appendStringInfo(buf, "::%s",
|
||||
format_type_with_typemod(constval->consttype,
|
||||
-1));
|
||||
needlabel = true;
|
||||
break;
|
||||
}
|
||||
if (needlabel)
|
||||
appendStringInfo(buf, "::%s",
|
||||
format_type_with_typemod(constval->consttype, -1));
|
||||
|
||||
ReleaseSysCache(typetup);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
ipad = VARBITPAD(result);
|
||||
if (ipad > 0)
|
||||
{
|
||||
mask = BITMASK << ipad;
|
||||
*(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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,39 +442,17 @@ varbit(PG_FUNCTION_ARGS)
|
||||
|
||||
memcpy(VARBITS(result), VARBITS(arg), VARBITBYTES(result));
|
||||
|
||||
/* Make sure last byte is zero-padded if needed */
|
||||
ipad = VARBITPAD(result);
|
||||
if (ipad > 0)
|
||||
{
|
||||
mask = BITMASK << ipad;
|
||||
*(VARBITS(result) + VARBITBYTES(result) - 1) &= mask;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
return array_map(&locfcinfo, VARBITOID, VARBITOID);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Comparison operators
|
||||
@@ -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... */
|
||||
|
||||
/* truncate multibyte string preserving multibyte boundary */
|
||||
maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ,
|
||||
maxlen - VARHDRSZ);
|
||||
|
||||
if (!isExplicit)
|
||||
{
|
||||
size_t maxmblen;
|
||||
|
||||
/* truncate multibyte string preserving multibyte boundary */
|
||||
maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ,
|
||||
maxlen - VARHDRSZ) + VARHDRSZ;
|
||||
|
||||
for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++)
|
||||
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
|
||||
*****************************************************************************/
|
||||
|
||||
Reference in New Issue
Block a user