📄 varchar.c
字号:
/*------------------------------------------------------------------------- * * varchar.c * Functions for the built-in types char(n) and varchar(n). * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/utils/adt/varchar.c,v 1.126 2008/01/01 19:45:53 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/hash.h"#include "access/tuptoaster.h"#include "libpq/pqformat.h"#include "utils/array.h"#include "utils/builtins.h"#include "mb/pg_wchar.h"/* common code for bpchartypmodin and varchartypmodin */static int32anychar_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 ANSI 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) */static BpChar *bpchar_input(const char *s, size_t len, int32 atttypmod){ 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] != ' ') ereport(ERROR, (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. */Datumbpcharin(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); PG_RETURN_BPCHAR_P(result);}/* * Convert a CHARACTER value to a C string. */Datumbpcharout(PG_FUNCTION_ARGS){ BpChar *s = PG_GETARG_BPCHAR_PP(0); char *result; int len; /* copy and add null term */ len = VARSIZE_ANY_EXHDR(s); result = (char *) palloc(len + 1); memcpy(result, VARDATA_ANY(s), len); result[len] = '\0'; PG_RETURN_CSTRING(result);}/* * bpcharrecv - converts external binary format to bpchar */Datumbpcharrecv(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); pfree(str); PG_RETURN_BPCHAR_P(result);}/* * bpcharsend - converts bpchar to binary format */Datumbpcharsend(PG_FUNCTION_ARGS){ /* Exactly the same as textsend, so share code */ return textsend(fcinfo);}/* * 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.) */Datumbpchar(PG_FUNCTION_ARGS){ BpChar *source = PG_GETARG_BPCHAR_PP(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 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); 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))); } 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). */Datumchar_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. */Datumbpchar_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 to max length for a Name */ if (len >= NAMEDATALEN) len = NAMEDATALEN - 1; /* Remove trailing blanks */ while (len > 0) { if (s_data[len - 1] != ' ') break; len--; } result = (NameData *) palloc(NAMEDATALEN); memcpy(NameStr(*result), s_data, len); /* Now null pad to full length... */ while (len < NAMEDATALEN) { *(NameStr(*result) + len) = '\0'; len++; } PG_RETURN_NAME(result);}/* name_bpchar() * Converts a NameData type to a bpchar type. */Datumname_bpchar(PG_FUNCTION_ARGS){ Name s = PG_GETARG_NAME(0); BpChar *result; int len; len = strlen(NameStr(*s)); result = (BpChar *) palloc(VARHDRSZ + len); memcpy(VARDATA(result), NameStr(*s), len); SET_VARSIZE(result, VARHDRSZ + len); PG_RETURN_BPCHAR_P(result);}Datumbpchartypmodin(PG_FUNCTION_ARGS){ ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0); PG_RETURN_INT32(anychar_typmodin(ta, "char"));}Datumbpchartypmodout(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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -