aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/varchar.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/varchar.c')
-rw-r--r--src/backend/utils/adt/varchar.c165
1 files changed, 111 insertions, 54 deletions
diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c
index 6d89b3df2f7..5c5c1075c71 100644
--- a/src/backend/utils/adt/varchar.c
+++ b/src/backend/utils/adt/varchar.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/varchar.c,v 1.110 2005/05/29 20:15:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/varchar.c,v 1.111 2005/07/10 21:13:59 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,6 +16,8 @@
#include "access/hash.h"
#include "catalog/pg_type.h"
+#include "lib/stringinfo.h"
+#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "utils/array.h"
#include "utils/builtins.h"
@@ -53,28 +55,25 @@
*****************************************************************************/
/*
- * Convert a C string to CHARACTER internal representation. atttypmod
- * is the declared length of the type plus VARHDRSZ.
+ * 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
*
- * If the C string is too long, raise an error, unless the extra
+ * 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)
*/
-Datum
-bpcharin(PG_FUNCTION_ARGS)
+static BpChar *
+bpchar_input(const char *s, size_t len, int32 atttypmod)
{
- char *s = PG_GETARG_CSTRING(0);
-
-#ifdef NOT_USED
- Oid typelem = PG_GETARG_OID(1);
-#endif
- int32 atttypmod = PG_GETARG_INT32(2);
BpChar *result;
char *r;
- size_t len,
- maxlen;
+ size_t maxlen;
/* verify encoding */
- len = strlen(s);
pg_verifymbstr(s, len, false);
/* If typmod is -1 (or invalid), use the actual string length */
@@ -85,30 +84,32 @@ bpcharin(PG_FUNCTION_ARGS)
size_t charlen; /* number of CHARACTERS in the input */
maxlen = atttypmod - VARHDRSZ;
- charlen = pg_mbstrlen(s);
+ 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.
+ * bpchar type, mbmaxlen is the length in BYTES of those chars.
*/
- if (strspn(s + mbmaxlen, " ") == len - mbmaxlen)
- len = mbmaxlen;
- else
- ereport(ERROR,
- (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
- errmsg("value too long for type character(%d)",
- (int) maxlen)));
+ 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;
+ maxlen = len = mbmaxlen;
}
else
{
@@ -120,7 +121,7 @@ bpcharin(PG_FUNCTION_ARGS)
}
}
- result = palloc(maxlen + VARHDRSZ);
+ result = (BpChar *) palloc(maxlen + VARHDRSZ);
VARATT_SIZEP(result) = maxlen + VARHDRSZ;
r = VARDATA(result);
memcpy(r, s, len);
@@ -129,6 +130,24 @@ bpcharin(PG_FUNCTION_ARGS)
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);
PG_RETURN_BPCHAR_P(result);
}
@@ -158,8 +177,19 @@ bpcharout(PG_FUNCTION_ARGS)
Datum
bpcharrecv(PG_FUNCTION_ARGS)
{
- /* Exactly the same as textrecv, so share code */
- return textrecv(fcinfo);
+ 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);
}
/*
@@ -344,30 +374,24 @@ name_bpchar(PG_FUNCTION_ARGS)
*****************************************************************************/
/*
- * Convert a C string to VARCHAR internal representation. atttypmod
- * is the declared length of the type plus VARHDRSZ.
+ * 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 regarded as the number of characters, which
+ * Note that atttypmod is measured in 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 input 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)
+static VarChar *
+varchar_input(const char *s, size_t len, int32 atttypmod)
{
- char *s = PG_GETARG_CSTRING(0);
-
-#ifdef NOT_USED
- Oid typelem = PG_GETARG_OID(1);
-#endif
- int32 atttypmod = PG_GETARG_INT32(2);
VarChar *result;
- size_t len,
- maxlen;
+ size_t maxlen;
/* verify encoding */
- len = strlen(s);
pg_verifymbstr(s, len, false);
maxlen = atttypmod - VARHDRSZ;
@@ -376,20 +400,42 @@ varcharin(PG_FUNCTION_ARGS)
{
/* Verify that extra characters are spaces, and clip them off */
size_t mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
+ size_t j;
- if (strspn(s + mbmaxlen, " ") == len - mbmaxlen)
- len = mbmaxlen;
- else
- ereport(ERROR,
- (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
- errmsg("value too long for type character varying(%d)",
- (int) maxlen)));
+ 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 = palloc(len + VARHDRSZ);
+ result = (VarChar *) palloc(len + VARHDRSZ);
VARATT_SIZEP(result) = len + VARHDRSZ;
memcpy(VARDATA(result), 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);
PG_RETURN_VARCHAR_P(result);
}
@@ -419,8 +465,19 @@ varcharout(PG_FUNCTION_ARGS)
Datum
varcharrecv(PG_FUNCTION_ARGS)
{
- /* Exactly the same as textrecv, so share code */
- return textrecv(fcinfo);
+ 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);
+ pfree(str);
+ PG_RETURN_VARCHAR_P(result);
}
/*