|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* varchar.c
|
|
|
|
|
* Functions for the built-in types char(n) and varchar(n).
|
|
|
|
|
*
|
|
|
|
|
* Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
|
|
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* IDENTIFICATION
|
|
|
|
|
* src/backend/utils/adt/varchar.c
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
|
|
#include "access/detoast.h"
|
Split up guc.c for better build speed and ease of maintenance.
guc.c has grown to be one of our largest .c files, making it
a bottleneck for compilation. It's also acquired a bunch of
knowledge that'd be better kept elsewhere, because of our not
very good habit of putting variable-specific check hooks here.
Hence, split it up along these lines:
* guc.c itself retains just the core GUC housekeeping mechanisms.
* New file guc_funcs.c contains the SET/SHOW interfaces and some
SQL-accessible functions for GUC manipulation.
* New file guc_tables.c contains the data arrays that define the
built-in GUC variables, along with some already-exported constant
tables.
* GUC check/assign/show hook functions are moved to the variable's
home module, whenever that's clearly identifiable. A few hard-
to-classify hooks ended up in commands/variable.c, which was
already a home for miscellaneous GUC hook functions.
To avoid cluttering a lot more header files with #include "guc.h",
I also invented a new header file utils/guc_hooks.h and put all
the GUC hook functions' declarations there, regardless of their
originating module. That allowed removal of #include "guc.h"
from some existing headers. The fallout from that (hopefully
all caught here) demonstrates clearly why such inclusions are
best minimized: there are a lot of files that, for example,
were getting array.h at two or more levels of remove, despite
not having any connection at all to GUCs in themselves.
There is some very minor code beautification here, such as
renaming a couple of inconsistently-named hook functions
and improving some comments. But mostly this just moves
code from point A to point B and deals with the ensuing
needs for #include adjustments and exporting a few functions
that previously weren't exported.
Patch by me, per a suggestion from Andres Freund; thanks also
to Michael Paquier for the idea to invent guc_funcs.c.
Discussion: https://postgr.es/m/587607.1662836699@sss.pgh.pa.us
3 years ago
|
|
|
#include "access/htup_details.h"
|
|
|
|
|
#include "catalog/pg_collation.h"
|
Make type "name" collation-aware.
The "name" comparison operators now all support collations, making them
functionally equivalent to "text" comparisons, except for the different
physical representation of the datatype. They do, in fact, mostly share
the varstr_cmp and varstr_sortsupport infrastructure, which has been
slightly enlarged to handle the case.
To avoid changes in the default behavior of the datatype, set name's
typcollation to C_COLLATION_OID not DEFAULT_COLLATION_OID, so that
by default comparisons to a name value will continue to use strcmp
semantics. (This would have been the case for system catalog columns
anyway, because of commit 6b0faf723, but doing this makes it true for
user-created name columns as well. In particular, this avoids
locale-dependent changes in our regression test results.)
In consequence, tweak a couple of places that made assumptions about
collatable base types always having typcollation DEFAULT_COLLATION_OID.
I have not, however, attempted to relax the restriction that user-
defined collatable types must have that. Hence, "name" doesn't
behave quite like a user-defined type; it acts more like a domain
with COLLATE "C". (Conceivably, if we ever get rid of the need for
catalog name columns to be fixed-length, "name" could actually become
such a domain over text. But that'd be a pretty massive undertaking,
and I'm not volunteering.)
Discussion: https://postgr.es/m/15938.1544377821@sss.pgh.pa.us
7 years ago
|
|
|
#include "catalog/pg_type.h"
|
|
|
|
|
#include "common/hashfn.h"
|
|
|
|
|
#include "libpq/pqformat.h"
|
|
|
|
|
#include "mb/pg_wchar.h"
|
|
|
|
|
#include "nodes/nodeFuncs.h"
|
|
|
|
|
#include "nodes/supportnodes.h"
|
|
|
|
|
#include "utils/array.h"
|
|
|
|
|
#include "utils/builtins.h"
|
|
|
|
|
#include "utils/pg_locale.h"
|
|
|
|
|
#include "utils/varlena.h"
|
|
|
|
|
|
|
|
|
|
/* common code for bpchartypmodin and varchartypmodin */
|
|
|
|
|
static int32
|
|
|
|
|
anychar_typmodin(ArrayType *ta, const char *typename)
|
|
|
|
|
{
|
|
|
|
|
int32 typmod;
|
|
|
|
|
int32 *tl;
|
|
|
|
|
int n;
|
|
|
|
|
|
|
|
|
|
tl = ArrayGetIntegerTypmods(ta, &n);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* we're not too tense about good error message here because grammar
|
|
|
|
|
* shouldn't allow wrong number of modifiers for CHAR
|
|
|
|
|
*/
|
|
|
|
|
if (n != 1)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
|
errmsg("invalid type modifier")));
|
|
|
|
|
|
|
|
|
|
if (*tl < 1)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
|
errmsg("length for type %s must be at least 1", typename)));
|
|
|
|
|
if (*tl > MaxAttrSize)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
|
|
|
|
errmsg("length for type %s cannot exceed %d",
|
|
|
|
|
typename, MaxAttrSize)));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* For largely historical reasons, the typmod is VARHDRSZ plus the number
|
|
|
|
|
* of characters; there is enough client-side code that knows about that
|
|
|
|
|
* that we'd better not change it.
|
|
|
|
|
*/
|
|
|
|
|
typmod = VARHDRSZ + *tl;
|
|
|
|
|
|
|
|
|
|
return typmod;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* common code for bpchartypmodout and varchartypmodout */
|
|
|
|
|
static char *
|
|
|
|
|
anychar_typmodout(int32 typmod)
|
|
|
|
|
{
|
|
|
|
|
char *res = (char *) palloc(64);
|
|
|
|
|
|
|
|
|
|
if (typmod > VARHDRSZ)
|
|
|
|
|
snprintf(res, 64, "(%d)", (int) (typmod - VARHDRSZ));
|
|
|
|
|
else
|
|
|
|
|
*res = '\0';
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* CHAR() and VARCHAR() types are part of the SQL standard. CHAR()
|
|
|
|
|
* is for blank-padded string whose length is specified in CREATE TABLE.
|
|
|
|
|
* VARCHAR is for storing string whose length is at most the length specified
|
|
|
|
|
* at CREATE TABLE time.
|
|
|
|
|
*
|
|
|
|
|
* It's hard to implement these types because we cannot figure out
|
|
|
|
|
* the length of the type from the type itself. I changed (hopefully all) the
|
|
|
|
|
* fmgr calls that invoke input functions of a data type to supply the
|
|
|
|
|
* length also. (eg. in INSERTs, we have the tupleDescriptor which contains
|
|
|
|
|
* the length of the attributes and hence the exact length of the char() or
|
|
|
|
|
* varchar(). We pass this to bpcharin() or varcharin().) In the case where
|
|
|
|
|
* we cannot determine the length, we pass in -1 instead and the input
|
|
|
|
|
* converter does not enforce any length check.
|
|
|
|
|
*
|
|
|
|
|
* We actually implement this as a varlena so that we don't have to pass in
|
|
|
|
|
* the length for the comparison functions. (The difference between these
|
|
|
|
|
* types and "text" is that we truncate and possibly blank-pad the string
|
|
|
|
|
* at insertion time.)
|
|
|
|
|
*
|
|
|
|
|
* - ay 6/95
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
|
* bpchar - char() *
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* bpchar_input -- common guts of bpcharin and bpcharrecv
|
|
|
|
|
*
|
|
|
|
|
* s is the input text of length len (may not be null-terminated)
|
|
|
|
|
* atttypmod is the typmod value to apply
|
|
|
|
|
*
|
|
|
|
|
* Note that atttypmod is measured in characters, which
|
|
|
|
|
* is not necessarily the same as the number of bytes.
|
|
|
|
|
*
|
|
|
|
|
* If the input string is too long, raise an error, unless the extra
|
|
|
|
|
* characters are spaces, in which case they're truncated. (per SQL)
|
|
|
|
|
*
|
|
|
|
|
* If escontext points to an ErrorSaveContext node, that is filled instead
|
|
|
|
|
* of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
|
|
|
|
|
* to detect errors.
|
|
|
|
|
*/
|
|
|
|
|
static BpChar *
|
|
|
|
|
bpchar_input(const char *s, size_t len, int32 atttypmod, Node *escontext)
|
|
|
|
|
{
|
|
|
|
|
BpChar *result;
|
|
|
|
|
char *r;
|
|
|
|
|
size_t maxlen;
|
|
|
|
|
|
|
|
|
|
/* If typmod is -1 (or invalid), use the actual string length */
|
|
|
|
|
if (atttypmod < (int32) VARHDRSZ)
|
|
|
|
|
maxlen = len;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
size_t charlen; /* number of CHARACTERS in the input */
|
|
|
|
|
|
|
|
|
|
maxlen = atttypmod - VARHDRSZ;
|
|
|
|
|
charlen = pg_mbstrlen_with_len(s, len);
|
|
|
|
|
if (charlen > maxlen)
|
|
|
|
|
{
|
|
|
|
|
/* Verify that extra characters are spaces, and clip them off */
|
|
|
|
|
size_t mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
|
|
|
|
|
size_t j;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* at this point, len is the actual BYTE length of the input
|
|
|
|
|
* string, maxlen is the max number of CHARACTERS allowed for this
|
|
|
|
|
* bpchar type, mbmaxlen is the length in BYTES of those chars.
|
|
|
|
|
*/
|
|
|
|
|
for (j = mbmaxlen; j < len; j++)
|
|
|
|
|
{
|
|
|
|
|
if (s[j] != ' ')
|
|
|
|
|
ereturn(escontext, NULL,
|
|
|
|
|
(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
|
|
|
|
|
errmsg("value too long for type character(%d)",
|
|
|
|
|
(int) maxlen)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Now we set maxlen to the necessary byte length, not the number
|
|
|
|
|
* of CHARACTERS!
|
|
|
|
|
*/
|
|
|
|
|
maxlen = len = mbmaxlen;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Now we set maxlen to the necessary byte length, not the number
|
|
|
|
|
* of CHARACTERS!
|
|
|
|
|
*/
|
|
|
|
|
maxlen = len + (maxlen - charlen);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = (BpChar *) palloc(maxlen + VARHDRSZ);
|
|
|
|
|
SET_VARSIZE(result, maxlen + VARHDRSZ);
|
|
|
|
|
r = VARDATA(result);
|
|
|
|
|
memcpy(r, s, len);
|
|
|
|
|
|
|
|
|
|
/* blank pad the string if necessary */
|
|
|
|
|
if (maxlen > len)
|
|
|
|
|
memset(r + len, ' ', maxlen - len);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Convert a C string to CHARACTER internal representation. atttypmod
|
|
|
|
|
* is the declared length of the type plus VARHDRSZ.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
bpcharin(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
char *s = PG_GETARG_CSTRING(0);
|
|
|
|
|
#ifdef NOT_USED
|
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
|
#endif
|
|
|
|
|
int32 atttypmod = PG_GETARG_INT32(2);
|
|
|
|
|
BpChar *result;
|
|
|
|
|
|
|
|
|
|
result = bpchar_input(s, strlen(s), atttypmod, fcinfo->context);
|
|
|
|
|
PG_RETURN_BPCHAR_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Convert a CHARACTER value to a C string.
|
|
|
|
|
*
|
|
|
|
|
* Uses the text conversion functions, which is only appropriate if BpChar
|
|
|
|
|
* and text are equivalent types.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
bpcharout(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Datum txt = PG_GETARG_DATUM(0);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_CSTRING(TextDatumGetCString(txt));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* bpcharrecv - converts external binary format to bpchar
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
bpcharrecv(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
|
|
|
|
#ifdef NOT_USED
|
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
|
#endif
|
|
|
|
|
int32 atttypmod = PG_GETARG_INT32(2);
|
|
|
|
|
BpChar *result;
|
|
|
|
|
char *str;
|
|
|
|
|
int nbytes;
|
|
|
|
|
|
|
|
|
|
str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
|
|
|
|
|
result = bpchar_input(str, nbytes, atttypmod, NULL);
|
|
|
|
|
pfree(str);
|
|
|
|
|
PG_RETURN_BPCHAR_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* bpcharsend - converts bpchar to binary format
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
bpcharsend(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
/* Exactly the same as textsend, so share code */
|
|
|
|
|
return textsend(fcinfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
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.
24 years ago
|
|
|
* 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
|
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.
24 years ago
|
|
|
* 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_PP(0);
|
|
|
|
|
int32 maxlen = PG_GETARG_INT32(1);
|
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.
24 years ago
|
|
|
bool isExplicit = PG_GETARG_BOOL(2);
|
|
|
|
|
BpChar *result;
|
|
|
|
|
int32 len;
|
|
|
|
|
char *r;
|
|
|
|
|
char *s;
|
|
|
|
|
int i;
|
|
|
|
|
int charlen; /* number of characters in the input string +
|
|
|
|
|
* VARHDRSZ */
|
|
|
|
|
|
|
|
|
|
/* No work if typmod is invalid */
|
|
|
|
|
if (maxlen < (int32) VARHDRSZ)
|
|
|
|
|
PG_RETURN_BPCHAR_P(source);
|
|
|
|
|
|
|
|
|
|
maxlen -= VARHDRSZ;
|
|
|
|
|
|
|
|
|
|
len = VARSIZE_ANY_EXHDR(source);
|
|
|
|
|
s = VARDATA_ANY(source);
|
|
|
|
|
|
|
|
|
|
charlen = pg_mbstrlen_with_len(s, len);
|
|
|
|
|
|
|
|
|
|
/* No work if supplied data matches typmod already */
|
|
|
|
|
if (charlen == maxlen)
|
|
|
|
|
PG_RETURN_BPCHAR_P(source);
|
|
|
|
|
|
|
|
|
|
if (charlen > maxlen)
|
|
|
|
|
{
|
|
|
|
|
/* Verify that extra characters are spaces, and clip them off */
|
|
|
|
|
size_t maxmblen;
|
|
|
|
|
|
|
|
|
|
maxmblen = pg_mbcharcliplen(s, len, maxlen);
|
|
|
|
|
|
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.
24 years ago
|
|
|
if (!isExplicit)
|
|
|
|
|
{
|
|
|
|
|
for (i = maxmblen; i < len; i++)
|
|
|
|
|
if (s[i] != ' ')
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
|
|
|
|
|
errmsg("value too long for type character(%d)",
|
|
|
|
|
maxlen)));
|
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.
24 years ago
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len = maxmblen;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* At this point, maxlen is the necessary byte length, not the number
|
|
|
|
|
* of CHARACTERS!
|
|
|
|
|
*/
|
|
|
|
|
maxlen = len;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* At this point, maxlen is the necessary byte length, not the number
|
|
|
|
|
* of CHARACTERS!
|
|
|
|
|
*/
|
|
|
|
|
maxlen = len + (maxlen - charlen);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Assert(maxlen >= len);
|
|
|
|
|
|
|
|
|
|
result = palloc(maxlen + VARHDRSZ);
|
|
|
|
|
SET_VARSIZE(result, maxlen + VARHDRSZ);
|
|
|
|
|
r = VARDATA(result);
|
|
|
|
|
|
|
|
|
|
memcpy(r, s, len);
|
|
|
|
|
|
|
|
|
|
/* blank pad the string if necessary */
|
|
|
|
|
if (maxlen > len)
|
|
|
|
|
memset(r + len, ' ', maxlen - len);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BPCHAR_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* char_bpchar()
|
|
|
|
|
* Convert char to bpchar(1).
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
char_bpchar(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
char c = PG_GETARG_CHAR(0);
|
|
|
|
|
BpChar *result;
|
|
|
|
|
|
|
|
|
|
result = (BpChar *) palloc(VARHDRSZ + 1);
|
|
|
|
|
|
|
|
|
|
SET_VARSIZE(result, VARHDRSZ + 1);
|
|
|
|
|
*(VARDATA(result)) = c;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BPCHAR_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* bpchar_name()
|
|
|
|
|
* Converts a bpchar() type to a NameData type.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
bpchar_name(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *s = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
char *s_data;
|
|
|
|
|
Name result;
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
len = VARSIZE_ANY_EXHDR(s);
|
|
|
|
|
s_data = VARDATA_ANY(s);
|
|
|
|
|
|
|
|
|
|
/* Truncate oversize input */
|
|
|
|
|
if (len >= NAMEDATALEN)
|
|
|
|
|
len = pg_mbcliplen(s_data, len, NAMEDATALEN - 1);
|
|
|
|
|
|
|
|
|
|
/* Remove trailing blanks */
|
|
|
|
|
while (len > 0)
|
|
|
|
|
{
|
|
|
|
|
if (s_data[len - 1] != ' ')
|
|
|
|
|
break;
|
|
|
|
|
len--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* We use palloc0 here to ensure result is zero-padded */
|
|
|
|
|
result = (Name) palloc0(NAMEDATALEN);
|
|
|
|
|
memcpy(NameStr(*result), s_data, len);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_NAME(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* name_bpchar()
|
|
|
|
|
* Converts a NameData type to a bpchar type.
|
|
|
|
|
*
|
|
|
|
|
* Uses the text conversion functions, which is only appropriate if BpChar
|
|
|
|
|
* and text are equivalent types.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
name_bpchar(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Name s = PG_GETARG_NAME(0);
|
|
|
|
|
BpChar *result;
|
|
|
|
|
|
|
|
|
|
result = (BpChar *) cstring_to_text(NameStr(*s));
|
|
|
|
|
PG_RETURN_BPCHAR_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpchartypmodin(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT32(anychar_typmodin(ta, "char"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpchartypmodout(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int32 typmod = PG_GETARG_INT32(0);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_CSTRING(anychar_typmodout(typmod));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
|
* varchar - varchar(n)
|
|
|
|
|
*
|
|
|
|
|
* Note: varchar piggybacks on type text for most operations, and so has no
|
|
|
|
|
* C-coded functions except for I/O and typmod checking.
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* varchar_input -- common guts of varcharin and varcharrecv
|
|
|
|
|
*
|
|
|
|
|
* s is the input text of length len (may not be null-terminated)
|
|
|
|
|
* atttypmod is the typmod value to apply
|
|
|
|
|
*
|
|
|
|
|
* Note that atttypmod is measured in characters, which
|
|
|
|
|
* is not necessarily the same as the number of bytes.
|
|
|
|
|
*
|
|
|
|
|
* If the input string is too long, raise an error, unless the extra
|
|
|
|
|
* characters are spaces, in which case they're truncated. (per SQL)
|
|
|
|
|
*
|
|
|
|
|
* If escontext points to an ErrorSaveContext node, that is filled instead
|
|
|
|
|
* of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
|
|
|
|
|
* to detect errors.
|
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.
24 years ago
|
|
|
*/
|
|
|
|
|
static VarChar *
|
|
|
|
|
varchar_input(const char *s, size_t len, int32 atttypmod, Node *escontext)
|
|
|
|
|
{
|
|
|
|
|
VarChar *result;
|
|
|
|
|
size_t maxlen;
|
|
|
|
|
|
|
|
|
|
maxlen = atttypmod - VARHDRSZ;
|
|
|
|
|
|
|
|
|
|
if (atttypmod >= (int32) VARHDRSZ && len > maxlen)
|
|
|
|
|
{
|
|
|
|
|
/* Verify that extra characters are spaces, and clip them off */
|
|
|
|
|
size_t mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
|
|
|
|
|
size_t j;
|
|
|
|
|
|
|
|
|
|
for (j = mbmaxlen; j < len; j++)
|
|
|
|
|
{
|
|
|
|
|
if (s[j] != ' ')
|
|
|
|
|
ereturn(escontext, NULL,
|
|
|
|
|
(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
9 years ago
|
|
|
errmsg("value too long for type character varying(%d)",
|
|
|
|
|
(int) maxlen)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
len = mbmaxlen;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We can use cstring_to_text_with_len because VarChar and text are
|
|
|
|
|
* binary-compatible types.
|
|
|
|
|
*/
|
|
|
|
|
result = (VarChar *) cstring_to_text_with_len(s, len);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Convert a C string to VARCHAR internal representation. atttypmod
|
|
|
|
|
* is the declared length of the type plus VARHDRSZ.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
varcharin(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
char *s = PG_GETARG_CSTRING(0);
|
|
|
|
|
#ifdef NOT_USED
|
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
|
#endif
|
|
|
|
|
int32 atttypmod = PG_GETARG_INT32(2);
|
|
|
|
|
VarChar *result;
|
|
|
|
|
|
|
|
|
|
result = varchar_input(s, strlen(s), atttypmod, fcinfo->context);
|
|
|
|
|
PG_RETURN_VARCHAR_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Convert a VARCHAR value to a C string.
|
|
|
|
|
*
|
|
|
|
|
* Uses the text to C string conversion function, which is only appropriate
|
|
|
|
|
* if VarChar and text are equivalent types.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
varcharout(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Datum txt = PG_GETARG_DATUM(0);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_CSTRING(TextDatumGetCString(txt));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* varcharrecv - converts external binary format to varchar
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
varcharrecv(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
|
|
|
|
#ifdef NOT_USED
|
|
|
|
|
Oid typelem = PG_GETARG_OID(1);
|
|
|
|
|
#endif
|
|
|
|
|
int32 atttypmod = PG_GETARG_INT32(2);
|
|
|
|
|
VarChar *result;
|
|
|
|
|
char *str;
|
|
|
|
|
int nbytes;
|
|
|
|
|
|
|
|
|
|
str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
|
|
|
|
|
result = varchar_input(str, nbytes, atttypmod, NULL);
|
|
|
|
|
pfree(str);
|
|
|
|
|
PG_RETURN_VARCHAR_P(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* varcharsend - converts varchar to binary format
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
varcharsend(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
/* Exactly the same as textsend, so share code */
|
|
|
|
|
return textsend(fcinfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* varchar_support()
|
|
|
|
|
*
|
|
|
|
|
* Planner support function for the varchar() length coercion function.
|
|
|
|
|
*
|
|
|
|
|
* Currently, the only interesting thing we can do is flatten calls that set
|
|
|
|
|
* the new maximum length >= the previous maximum length. We can ignore the
|
|
|
|
|
* isExplicit argument, since that only affects truncation cases.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
varchar_support(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Node *rawreq = (Node *) PG_GETARG_POINTER(0);
|
|
|
|
|
Node *ret = NULL;
|
|
|
|
|
|
|
|
|
|
if (IsA(rawreq, SupportRequestSimplify))
|
|
|
|
|
{
|
|
|
|
|
SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
|
|
|
|
|
FuncExpr *expr = req->fcall;
|
|
|
|
|
Node *typmod;
|
|
|
|
|
|
|
|
|
|
Assert(list_length(expr->args) >= 2);
|
|
|
|
|
|
|
|
|
|
typmod = (Node *) lsecond(expr->args);
|
|
|
|
|
|
|
|
|
|
if (IsA(typmod, Const) && !((Const *) typmod)->constisnull)
|
|
|
|
|
{
|
|
|
|
|
Node *source = (Node *) linitial(expr->args);
|
|
|
|
|
int32 old_typmod = exprTypmod(source);
|
|
|
|
|
int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
|
|
|
|
|
int32 old_max = old_typmod - VARHDRSZ;
|
|
|
|
|
int32 new_max = new_typmod - VARHDRSZ;
|
|
|
|
|
|
|
|
|
|
if (new_typmod < 0 || (old_typmod >= 0 && old_max <= new_max))
|
|
|
|
|
ret = relabel_to_typmod(source, new_typmod);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(ret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
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.
24 years ago
|
|
|
* 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
|
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.
24 years ago
|
|
|
* 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_PP(0);
|
|
|
|
|
int32 typmod = PG_GETARG_INT32(1);
|
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.
24 years ago
|
|
|
bool isExplicit = PG_GETARG_BOOL(2);
|
|
|
|
|
int32 len,
|
|
|
|
|
maxlen;
|
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.
24 years ago
|
|
|
size_t maxmblen;
|
|
|
|
|
int i;
|
|
|
|
|
char *s_data;
|
|
|
|
|
|
|
|
|
|
len = VARSIZE_ANY_EXHDR(source);
|
|
|
|
|
s_data = VARDATA_ANY(source);
|
|
|
|
|
maxlen = typmod - VARHDRSZ;
|
|
|
|
|
|
|
|
|
|
/* No work if typmod is invalid or supplied data fits it already */
|
|
|
|
|
if (maxlen < 0 || len <= maxlen)
|
|
|
|
|
PG_RETURN_VARCHAR_P(source);
|
|
|
|
|
|
|
|
|
|
/* only reach here if string is too long... */
|
|
|
|
|
|
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.
24 years ago
|
|
|
/* truncate multibyte string preserving multibyte boundary */
|
|
|
|
|
maxmblen = pg_mbcharcliplen(s_data, len, maxlen);
|
|
|
|
|
|
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.
24 years ago
|
|
|
if (!isExplicit)
|
|
|
|
|
{
|
|
|
|
|
for (i = maxmblen; i < len; i++)
|
|
|
|
|
if (s_data[i] != ' ')
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
9 years ago
|
|
|
errmsg("value too long for type character varying(%d)",
|
|
|
|
|
maxlen)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text_with_len(s_data,
|
|
|
|
|
maxmblen));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
varchartypmodin(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT32(anychar_typmodin(ta, "varchar"));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
varchartypmodout(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int32 typmod = PG_GETARG_INT32(0);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_CSTRING(anychar_typmodout(typmod));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
|
* Exported functions
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
/* "True" length (not counting trailing blanks) of a BpChar */
|
|
|
|
|
static inline int
|
|
|
|
|
bcTruelen(BpChar *arg)
|
|
|
|
|
{
|
|
|
|
|
return bpchartruelen(VARDATA_ANY(arg), VARSIZE_ANY_EXHDR(arg));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
bpchartruelen(char *s, int len)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Note that we rely on the assumption that ' ' is a singleton unit on
|
|
|
|
|
* every supported multibyte server encoding.
|
|
|
|
|
*/
|
|
|
|
|
for (i = len - 1; i >= 0; i--)
|
|
|
|
|
{
|
|
|
|
|
if (s[i] != ' ')
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return i + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpcharlen(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *arg = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
/* get number of bytes, ignoring trailing spaces */
|
|
|
|
|
len = bcTruelen(arg);
|
|
|
|
|
|
|
|
|
|
/* in multibyte encoding, convert to number of characters */
|
|
|
|
|
if (pg_database_encoding_max_length() != 1)
|
|
|
|
|
len = pg_mbstrlen_with_len(VARDATA_ANY(arg), len);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT32(len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpcharoctetlen(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Datum arg = PG_GETARG_DATUM(0);
|
|
|
|
|
|
|
|
|
|
/* We need not detoast the input at all */
|
|
|
|
|
PG_RETURN_INT32(toast_raw_datum_size(arg) - VARHDRSZ);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
|
* Comparison Functions used for bpchar
|
|
|
|
|
*
|
|
|
|
|
* Note: btree indexes need these routines not to leak memory; therefore,
|
|
|
|
|
* be careful to free working copies of toasted datums. Most places don't
|
|
|
|
|
* need to be so careful.
|
|
|
|
|
*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
check_collation_set(Oid collid)
|
|
|
|
|
{
|
|
|
|
|
if (!OidIsValid(collid))
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* This typically means that the parser could not resolve a conflict
|
|
|
|
|
* of implicit collations, so report it that way.
|
|
|
|
|
*/
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INDETERMINATE_COLLATION),
|
|
|
|
|
errmsg("could not determine which collation to use for string comparison"),
|
|
|
|
|
errhint("Use the COLLATE clause to set the collation explicitly.")));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpchareq(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
|
|
|
|
|
int len1,
|
|
|
|
|
len2;
|
|
|
|
|
bool result;
|
|
|
|
|
Oid collid = PG_GET_COLLATION();
|
|
|
|
|
pg_locale_t mylocale;
|
|
|
|
|
|
|
|
|
|
check_collation_set(collid);
|
|
|
|
|
|
|
|
|
|
len1 = bcTruelen(arg1);
|
|
|
|
|
len2 = bcTruelen(arg2);
|
|
|
|
|
|
|
|
|
|
mylocale = pg_newlocale_from_collation(collid);
|
|
|
|
|
|
|
|
|
|
if (mylocale->deterministic)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Since we only care about equality or not-equality, we can avoid all
|
|
|
|
|
* the expense of strcoll() here, and just do bitwise comparison.
|
|
|
|
|
*/
|
|
|
|
|
if (len1 != len2)
|
|
|
|
|
result = false;
|
|
|
|
|
else
|
|
|
|
|
result = (memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) == 0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
result = (varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
|
|
|
|
|
collid) == 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpcharne(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
|
|
|
|
|
int len1,
|
|
|
|
|
len2;
|
|
|
|
|
bool result;
|
|
|
|
|
Oid collid = PG_GET_COLLATION();
|
|
|
|
|
pg_locale_t mylocale;
|
|
|
|
|
|
|
|
|
|
check_collation_set(collid);
|
|
|
|
|
|
|
|
|
|
len1 = bcTruelen(arg1);
|
|
|
|
|
len2 = bcTruelen(arg2);
|
|
|
|
|
|
|
|
|
|
mylocale = pg_newlocale_from_collation(collid);
|
|
|
|
|
|
|
|
|
|
if (mylocale->deterministic)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Since we only care about equality or not-equality, we can avoid all
|
|
|
|
|
* the expense of strcoll() here, and just do bitwise comparison.
|
|
|
|
|
*/
|
|
|
|
|
if (len1 != len2)
|
|
|
|
|
result = true;
|
|
|
|
|
else
|
|
|
|
|
result = (memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) != 0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
result = (varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
|
|
|
|
|
collid) != 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpcharlt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
|
|
|
|
|
int len1,
|
|
|
|
|
len2;
|
|
|
|
|
int cmp;
|
|
|
|
|
|
|
|
|
|
len1 = bcTruelen(arg1);
|
|
|
|
|
len2 = bcTruelen(arg2);
|
|
|
|
|
|
|
|
|
|
cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
|
|
|
|
|
PG_GET_COLLATION());
|
|
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(cmp < 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpcharle(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
|
|
|
|
|
int len1,
|
|
|
|
|
len2;
|
|
|
|
|
int cmp;
|
|
|
|
|
|
|
|
|
|
len1 = bcTruelen(arg1);
|
|
|
|
|
len2 = bcTruelen(arg2);
|
|
|
|
|
|
|
|
|
|
cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
|
|
|
|
|
PG_GET_COLLATION());
|
|
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(cmp <= 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpchargt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
|
|
|
|
|
int len1,
|
|
|
|
|
len2;
|
|
|
|
|
int cmp;
|
|
|
|
|
|
|
|
|
|
len1 = bcTruelen(arg1);
|
|
|
|
|
len2 = bcTruelen(arg2);
|
|
|
|
|
|
|
|
|
|
cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
|
|
|
|
|
PG_GET_COLLATION());
|
|
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(cmp > 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpcharge(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
|
|
|
|
|
int len1,
|
|
|
|
|
len2;
|
|
|
|
|
int cmp;
|
|
|
|
|
|
|
|
|
|
len1 = bcTruelen(arg1);
|
|
|
|
|
len2 = bcTruelen(arg2);
|
|
|
|
|
|
|
|
|
|
cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
|
|
|
|
|
PG_GET_COLLATION());
|
|
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(cmp >= 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpcharcmp(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
|
|
|
|
|
int len1,
|
|
|
|
|
len2;
|
|
|
|
|
int cmp;
|
|
|
|
|
|
|
|
|
|
len1 = bcTruelen(arg1);
|
|
|
|
|
len2 = bcTruelen(arg2);
|
|
|
|
|
|
|
|
|
|
cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
|
|
|
|
|
PG_GET_COLLATION());
|
|
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT32(cmp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpchar_sortsupport(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
|
|
|
|
|
Oid collid = ssup->ssup_collation;
|
|
|
|
|
MemoryContext oldcontext;
|
|
|
|
|
|
|
|
|
|
oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
|
|
|
|
|
|
|
|
|
|
/* Use generic string SortSupport */
|
Make type "name" collation-aware.
The "name" comparison operators now all support collations, making them
functionally equivalent to "text" comparisons, except for the different
physical representation of the datatype. They do, in fact, mostly share
the varstr_cmp and varstr_sortsupport infrastructure, which has been
slightly enlarged to handle the case.
To avoid changes in the default behavior of the datatype, set name's
typcollation to C_COLLATION_OID not DEFAULT_COLLATION_OID, so that
by default comparisons to a name value will continue to use strcmp
semantics. (This would have been the case for system catalog columns
anyway, because of commit 6b0faf723, but doing this makes it true for
user-created name columns as well. In particular, this avoids
locale-dependent changes in our regression test results.)
In consequence, tweak a couple of places that made assumptions about
collatable base types always having typcollation DEFAULT_COLLATION_OID.
I have not, however, attempted to relax the restriction that user-
defined collatable types must have that. Hence, "name" doesn't
behave quite like a user-defined type; it acts more like a domain
with COLLATE "C". (Conceivably, if we ever get rid of the need for
catalog name columns to be fixed-length, "name" could actually become
such a domain over text. But that'd be a pretty massive undertaking,
and I'm not volunteering.)
Discussion: https://postgr.es/m/15938.1544377821@sss.pgh.pa.us
7 years ago
|
|
|
varstr_sortsupport(ssup, BPCHAROID, collid);
|
|
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpchar_larger(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
|
|
|
|
|
int len1,
|
|
|
|
|
len2;
|
|
|
|
|
int cmp;
|
|
|
|
|
|
|
|
|
|
len1 = bcTruelen(arg1);
|
|
|
|
|
len2 = bcTruelen(arg2);
|
|
|
|
|
|
|
|
|
|
cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
|
|
|
|
|
PG_GET_COLLATION());
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BPCHAR_P((cmp >= 0) ? arg1 : arg2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpchar_smaller(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
|
|
|
|
|
int len1,
|
|
|
|
|
len2;
|
|
|
|
|
int cmp;
|
|
|
|
|
|
|
|
|
|
len1 = bcTruelen(arg1);
|
|
|
|
|
len2 = bcTruelen(arg2);
|
|
|
|
|
|
|
|
|
|
cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
|
|
|
|
|
PG_GET_COLLATION());
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BPCHAR_P((cmp <= 0) ? arg1 : arg2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* bpchar needs a specialized hash function because we want to ignore
|
|
|
|
|
* trailing blanks in comparisons.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
hashbpchar(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *key = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
Oid collid = PG_GET_COLLATION();
|
|
|
|
|
char *keydata;
|
|
|
|
|
int keylen;
|
|
|
|
|
pg_locale_t mylocale;
|
|
|
|
|
Datum result;
|
|
|
|
|
|
|
|
|
|
if (!collid)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INDETERMINATE_COLLATION),
|
|
|
|
|
errmsg("could not determine which collation to use for string hashing"),
|
|
|
|
|
errhint("Use the COLLATE clause to set the collation explicitly.")));
|
|
|
|
|
|
|
|
|
|
keydata = VARDATA_ANY(key);
|
|
|
|
|
keylen = bcTruelen(key);
|
|
|
|
|
|
|
|
|
|
mylocale = pg_newlocale_from_collation(collid);
|
|
|
|
|
|
|
|
|
|
if (mylocale->deterministic)
|
|
|
|
|
{
|
|
|
|
|
result = hash_any((unsigned char *) keydata, keylen);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Size bsize,
|
|
|
|
|
rsize;
|
|
|
|
|
char *buf;
|
|
|
|
|
|
|
|
|
|
bsize = pg_strnxfrm(NULL, 0, keydata, keylen, mylocale);
|
|
|
|
|
buf = palloc(bsize + 1);
|
|
|
|
|
|
|
|
|
|
rsize = pg_strnxfrm(buf, bsize + 1, keydata, keylen, mylocale);
|
|
|
|
|
|
|
|
|
|
/* the second call may return a smaller value than the first */
|
|
|
|
|
if (rsize > bsize)
|
|
|
|
|
elog(ERROR, "pg_strnxfrm() returned unexpected result");
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* In principle, there's no reason to include the terminating NUL
|
|
|
|
|
* character in the hash, but it was done before and the behavior must
|
|
|
|
|
* be preserved.
|
|
|
|
|
*/
|
|
|
|
|
result = hash_any((uint8_t *) buf, bsize + 1);
|
|
|
|
|
|
|
|
|
|
pfree(buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Avoid leaking memory for toasted inputs */
|
|
|
|
|
PG_FREE_IF_COPY(key, 0);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
hashbpcharextended(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *key = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
Oid collid = PG_GET_COLLATION();
|
|
|
|
|
char *keydata;
|
|
|
|
|
int keylen;
|
|
|
|
|
pg_locale_t mylocale;
|
|
|
|
|
Datum result;
|
|
|
|
|
|
|
|
|
|
if (!collid)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INDETERMINATE_COLLATION),
|
|
|
|
|
errmsg("could not determine which collation to use for string hashing"),
|
|
|
|
|
errhint("Use the COLLATE clause to set the collation explicitly.")));
|
|
|
|
|
|
|
|
|
|
keydata = VARDATA_ANY(key);
|
|
|
|
|
keylen = bcTruelen(key);
|
|
|
|
|
|
|
|
|
|
mylocale = pg_newlocale_from_collation(collid);
|
|
|
|
|
|
|
|
|
|
if (mylocale->deterministic)
|
|
|
|
|
{
|
|
|
|
|
result = hash_any_extended((unsigned char *) keydata, keylen,
|
|
|
|
|
PG_GETARG_INT64(1));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Size bsize,
|
|
|
|
|
rsize;
|
|
|
|
|
char *buf;
|
|
|
|
|
|
|
|
|
|
bsize = pg_strnxfrm(NULL, 0, keydata, keylen, mylocale);
|
|
|
|
|
buf = palloc(bsize + 1);
|
|
|
|
|
|
|
|
|
|
rsize = pg_strnxfrm(buf, bsize + 1, keydata, keylen, mylocale);
|
|
|
|
|
|
|
|
|
|
/* the second call may return a smaller value than the first */
|
|
|
|
|
if (rsize > bsize)
|
|
|
|
|
elog(ERROR, "pg_strnxfrm() returned unexpected result");
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* In principle, there's no reason to include the terminating NUL
|
|
|
|
|
* character in the hash, but it was done before and the behavior must
|
|
|
|
|
* be preserved.
|
|
|
|
|
*/
|
|
|
|
|
result = hash_any_extended((uint8_t *) buf, bsize + 1,
|
|
|
|
|
PG_GETARG_INT64(1));
|
|
|
|
|
|
|
|
|
|
pfree(buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(key, 0);
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* The following operators support character-by-character comparison
|
|
|
|
|
* of bpchar datums, to allow building indexes suitable for LIKE clauses.
|
|
|
|
|
* Note that the regular bpchareq/bpcharne comparison operators, and
|
|
|
|
|
* regular support functions 1 and 2 with "C" collation are assumed to be
|
|
|
|
|
* compatible with these!
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
static int
|
Fix up handling of nondeterministic collations with pattern_ops opclasses.
text_pattern_ops and its siblings can't be used with nondeterministic
collations, because they use the text_eq operator which will not behave
as bitwise equality if applied with a nondeterministic collation. The
initial implementation of that restriction was to insert a run-time test
in the related comparison functions, but that is inefficient, may throw
misleading errors, and will throw errors in some cases that would work.
It seems sufficient to just prevent the combination during CREATE INDEX,
so do that instead.
Lacking any better way to identify the opclasses involved, we need to
hard-wire tests for them, which requires hand-assigned values for their
OIDs, which forces a catversion bump because they previously had OIDs
that would be assigned automatically. That's slightly annoying in the
v12 branch, but fortunately we're not at rc1 yet, so just do it.
Back-patch to v12 where nondeterministic collations were added.
In passing, run make reformat-dat-files, which found some unrelated
whitespace issues (slightly different ones in HEAD and v12).
Peter Eisentraut, with small corrections by me
Discussion: https://postgr.es/m/22566.1568675619@sss.pgh.pa.us
6 years ago
|
|
|
internal_bpchar_pattern_compare(BpChar *arg1, BpChar *arg2)
|
|
|
|
|
{
|
|
|
|
|
int result;
|
|
|
|
|
int len1,
|
|
|
|
|
len2;
|
|
|
|
|
|
|
|
|
|
len1 = bcTruelen(arg1);
|
|
|
|
|
len2 = bcTruelen(arg2);
|
|
|
|
|
|
|
|
|
|
result = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
|
|
|
|
|
if (result != 0)
|
|
|
|
|
return result;
|
|
|
|
|
else if (len1 < len2)
|
|
|
|
|
return -1;
|
|
|
|
|
else if (len1 > len2)
|
|
|
|
|
return 1;
|
|
|
|
|
else
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpchar_pattern_lt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
|
|
|
|
|
int result;
|
|
|
|
|
|
Fix up handling of nondeterministic collations with pattern_ops opclasses.
text_pattern_ops and its siblings can't be used with nondeterministic
collations, because they use the text_eq operator which will not behave
as bitwise equality if applied with a nondeterministic collation. The
initial implementation of that restriction was to insert a run-time test
in the related comparison functions, but that is inefficient, may throw
misleading errors, and will throw errors in some cases that would work.
It seems sufficient to just prevent the combination during CREATE INDEX,
so do that instead.
Lacking any better way to identify the opclasses involved, we need to
hard-wire tests for them, which requires hand-assigned values for their
OIDs, which forces a catversion bump because they previously had OIDs
that would be assigned automatically. That's slightly annoying in the
v12 branch, but fortunately we're not at rc1 yet, so just do it.
Back-patch to v12 where nondeterministic collations were added.
In passing, run make reformat-dat-files, which found some unrelated
whitespace issues (slightly different ones in HEAD and v12).
Peter Eisentraut, with small corrections by me
Discussion: https://postgr.es/m/22566.1568675619@sss.pgh.pa.us
6 years ago
|
|
|
result = internal_bpchar_pattern_compare(arg1, arg2);
|
|
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(result < 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpchar_pattern_le(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
|
|
|
|
|
int result;
|
|
|
|
|
|
Fix up handling of nondeterministic collations with pattern_ops opclasses.
text_pattern_ops and its siblings can't be used with nondeterministic
collations, because they use the text_eq operator which will not behave
as bitwise equality if applied with a nondeterministic collation. The
initial implementation of that restriction was to insert a run-time test
in the related comparison functions, but that is inefficient, may throw
misleading errors, and will throw errors in some cases that would work.
It seems sufficient to just prevent the combination during CREATE INDEX,
so do that instead.
Lacking any better way to identify the opclasses involved, we need to
hard-wire tests for them, which requires hand-assigned values for their
OIDs, which forces a catversion bump because they previously had OIDs
that would be assigned automatically. That's slightly annoying in the
v12 branch, but fortunately we're not at rc1 yet, so just do it.
Back-patch to v12 where nondeterministic collations were added.
In passing, run make reformat-dat-files, which found some unrelated
whitespace issues (slightly different ones in HEAD and v12).
Peter Eisentraut, with small corrections by me
Discussion: https://postgr.es/m/22566.1568675619@sss.pgh.pa.us
6 years ago
|
|
|
result = internal_bpchar_pattern_compare(arg1, arg2);
|
|
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(result <= 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpchar_pattern_ge(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
|
|
|
|
|
int result;
|
|
|
|
|
|
Fix up handling of nondeterministic collations with pattern_ops opclasses.
text_pattern_ops and its siblings can't be used with nondeterministic
collations, because they use the text_eq operator which will not behave
as bitwise equality if applied with a nondeterministic collation. The
initial implementation of that restriction was to insert a run-time test
in the related comparison functions, but that is inefficient, may throw
misleading errors, and will throw errors in some cases that would work.
It seems sufficient to just prevent the combination during CREATE INDEX,
so do that instead.
Lacking any better way to identify the opclasses involved, we need to
hard-wire tests for them, which requires hand-assigned values for their
OIDs, which forces a catversion bump because they previously had OIDs
that would be assigned automatically. That's slightly annoying in the
v12 branch, but fortunately we're not at rc1 yet, so just do it.
Back-patch to v12 where nondeterministic collations were added.
In passing, run make reformat-dat-files, which found some unrelated
whitespace issues (slightly different ones in HEAD and v12).
Peter Eisentraut, with small corrections by me
Discussion: https://postgr.es/m/22566.1568675619@sss.pgh.pa.us
6 years ago
|
|
|
result = internal_bpchar_pattern_compare(arg1, arg2);
|
|
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(result >= 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
bpchar_pattern_gt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
|
|
|
|
|
int result;
|
|
|
|
|
|
Fix up handling of nondeterministic collations with pattern_ops opclasses.
text_pattern_ops and its siblings can't be used with nondeterministic
collations, because they use the text_eq operator which will not behave
as bitwise equality if applied with a nondeterministic collation. The
initial implementation of that restriction was to insert a run-time test
in the related comparison functions, but that is inefficient, may throw
misleading errors, and will throw errors in some cases that would work.
It seems sufficient to just prevent the combination during CREATE INDEX,
so do that instead.
Lacking any better way to identify the opclasses involved, we need to
hard-wire tests for them, which requires hand-assigned values for their
OIDs, which forces a catversion bump because they previously had OIDs
that would be assigned automatically. That's slightly annoying in the
v12 branch, but fortunately we're not at rc1 yet, so just do it.
Back-patch to v12 where nondeterministic collations were added.
In passing, run make reformat-dat-files, which found some unrelated
whitespace issues (slightly different ones in HEAD and v12).
Peter Eisentraut, with small corrections by me
Discussion: https://postgr.es/m/22566.1568675619@sss.pgh.pa.us
6 years ago
|
|
|
result = internal_bpchar_pattern_compare(arg1, arg2);
|
|
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(result > 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
btbpchar_pattern_cmp(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
|
|
|
|
|
BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
|
|
|
|
|
int result;
|
|
|
|
|
|
Fix up handling of nondeterministic collations with pattern_ops opclasses.
text_pattern_ops and its siblings can't be used with nondeterministic
collations, because they use the text_eq operator which will not behave
as bitwise equality if applied with a nondeterministic collation. The
initial implementation of that restriction was to insert a run-time test
in the related comparison functions, but that is inefficient, may throw
misleading errors, and will throw errors in some cases that would work.
It seems sufficient to just prevent the combination during CREATE INDEX,
so do that instead.
Lacking any better way to identify the opclasses involved, we need to
hard-wire tests for them, which requires hand-assigned values for their
OIDs, which forces a catversion bump because they previously had OIDs
that would be assigned automatically. That's slightly annoying in the
v12 branch, but fortunately we're not at rc1 yet, so just do it.
Back-patch to v12 where nondeterministic collations were added.
In passing, run make reformat-dat-files, which found some unrelated
whitespace issues (slightly different ones in HEAD and v12).
Peter Eisentraut, with small corrections by me
Discussion: https://postgr.es/m/22566.1568675619@sss.pgh.pa.us
6 years ago
|
|
|
result = internal_bpchar_pattern_compare(arg1, arg2);
|
|
|
|
|
|
|
|
|
|
PG_FREE_IF_COPY(arg1, 0);
|
|
|
|
|
PG_FREE_IF_COPY(arg2, 1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT32(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
btbpchar_pattern_sortsupport(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
|
|
|
|
|
MemoryContext oldcontext;
|
|
|
|
|
|
|
|
|
|
oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
|
|
|
|
|
|
|
|
|
|
/* Use generic string SortSupport, forcing "C" collation */
|
Make type "name" collation-aware.
The "name" comparison operators now all support collations, making them
functionally equivalent to "text" comparisons, except for the different
physical representation of the datatype. They do, in fact, mostly share
the varstr_cmp and varstr_sortsupport infrastructure, which has been
slightly enlarged to handle the case.
To avoid changes in the default behavior of the datatype, set name's
typcollation to C_COLLATION_OID not DEFAULT_COLLATION_OID, so that
by default comparisons to a name value will continue to use strcmp
semantics. (This would have been the case for system catalog columns
anyway, because of commit 6b0faf723, but doing this makes it true for
user-created name columns as well. In particular, this avoids
locale-dependent changes in our regression test results.)
In consequence, tweak a couple of places that made assumptions about
collatable base types always having typcollation DEFAULT_COLLATION_OID.
I have not, however, attempted to relax the restriction that user-
defined collatable types must have that. Hence, "name" doesn't
behave quite like a user-defined type; it acts more like a domain
with COLLATE "C". (Conceivably, if we ever get rid of the need for
catalog name columns to be fixed-length, "name" could actually become
such a domain over text. But that'd be a pretty massive undertaking,
and I'm not volunteering.)
Discussion: https://postgr.es/m/15938.1544377821@sss.pgh.pa.us
7 years ago
|
|
|
varstr_sortsupport(ssup, BPCHAROID, C_COLLATION_OID);
|
|
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_VOID();
|
|
|
|
|
}
|