/* * 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) */ static VarChar * varchar_input(const char *s, size_t len, int32 atttypmod) { VarChar *result; size_t maxlen; /* verify encoding */ pg_verifymbstr(s, len, false); 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] != ' ') ereport(ERROR, (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), errmsg("value too long for type character varying(%d)", (int) maxlen))); } len = mbmaxlen; } result = (VarChar *) palloc(len + VARHDRSZ); VARATT_SIZEP(result) = len + VARHDRSZ; memcpy(VARDATA(result), s, len); return result; }
/* * 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); /* No work if typmod is invalid or supplied data fits it already */ if (maxlen < (int32) VARHDRSZ || len <= maxlen) PG_RETURN_VARCHAR_P(source); /* 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) { for (i = maxmblen; i < len - VARHDRSZ; i++) if (*(VARDATA(source) + i) != ' ') ereport(ERROR, (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), errmsg("value too long for type character varying(%d)", maxlen - VARHDRSZ))); } len = maxmblen + VARHDRSZ; result = palloc(len); VARATT_SIZEP(result) = len; memcpy(VARDATA(result), VARDATA(source), len - VARHDRSZ); PG_RETURN_VARCHAR_P(result); }
/* * Converts a NVARCHAR2 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 nvarchar2(N). * * Truncation rules: for an explicit cast, silently truncate to the given * length; for an implicit cast, raise error if length limit is exceeded */ Datum nvarchar2(PG_FUNCTION_ARGS) { VarChar *source = PG_GETARG_VARCHAR_PP(0); int32 typmod = PG_GETARG_INT32(1); bool isExplicit = PG_GETARG_BOOL(2); int32 len, maxlen; size_t maxmblen; 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... */ /* truncate multibyte string preserving multibyte boundary */ maxmblen = pg_mbcharcliplen(s_data, len, maxlen); /* error out if value too long unless it's an explicit cast */ if (!isExplicit) { /* if there is still data beyond maxmblen, error out * * Remember - no blankspace truncation on implicit cast */ if (len > maxmblen) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("input value too long for type nvarchar2(%d)", maxlen))); } PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text_with_len(s_data, maxmblen)); }
/* * 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; /* verify encoding */ pg_verifymbstr(s, len, false); /* 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); VARATT_SIZEP(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; }
/* * 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 characters in the input string + * VARHDRSZ */ /* No work if typmod is invalid */ if (maxlen < (int32) VARHDRSZ) PG_RETURN_BPCHAR_P(source); len = VARSIZE(source); charlen = pg_mbstrlen_with_len(VARDATA(source), len - VARHDRSZ) + VARHDRSZ; /* 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(VARDATA(source), len - VARHDRSZ, maxlen - VARHDRSZ) + VARHDRSZ; if (!isExplicit) { for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++) if (*(VARDATA(source) + i) != ' ') ereport(ERROR, (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), errmsg("value too long for type character(%d)", maxlen - VARHDRSZ))); } len = maxmblen; /* * XXX: at this point, maxlen is the necessary byte length+VARHDRSZ, * not the number of CHARACTERS! */ maxlen = len; } else { /* * XXX: at this point, maxlen is the necessary byte length+VARHDRSZ, * not the number of CHARACTERS! */ maxlen = len + (maxlen - charlen); } s = VARDATA(source); result = palloc(maxlen); VARATT_SIZEP(result) = maxlen; r = VARDATA(result); memcpy(r, s, len - VARHDRSZ); /* blank pad the string if necessary */ if (maxlen > len) memset(r + len - VARHDRSZ, ' ', maxlen - len); PG_RETURN_BPCHAR_P(result); }