| /*---------------------------------------------------------------------------- |
| * |
| * nvarchar2.c |
| * NVARCHAR2 type for PostgreSQL. |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| |
| #include "postgres.h" |
| #include "access/hash.h" |
| #include "libpq/pqformat.h" |
| #include "nodes/nodeFuncs.h" |
| #include "utils/array.h" |
| #include "utils/builtins.h" |
| #include "mb/pg_wchar.h" |
| #include "fmgr.h" |
| |
| #include "orafce.h" |
| #include "builtins.h" |
| |
| |
| PG_FUNCTION_INFO_V1(nvarchar2in); |
| PG_FUNCTION_INFO_V1(nvarchar2out); |
| PG_FUNCTION_INFO_V1(nvarchar2); |
| PG_FUNCTION_INFO_V1(nvarchar2recv); |
| |
| /* |
| * nvarchar2_input -- common guts of nvarchar2in and nvarchar2recv |
| * |
| * s is the input text of length len (may not be null-terminated) |
| * atttypmod is the typmod value to apply |
| * |
| * If the input string is too long, raise an error |
| * |
| * Uses the C string to text conversion function, which is only appropriate |
| * if VarChar and text are equivalent types. |
| */ |
| |
| static VarChar * |
| nvarchar2_input(const char *s, size_t len, int32 atttypmod) |
| { |
| VarChar *result; /* input data */ |
| size_t maxlen; |
| |
| maxlen = atttypmod - VARHDRSZ; |
| |
| /* |
| * Perform the typmod check; error out if value too long for NVARCHAR2 |
| */ |
| if (atttypmod >= (int32) VARHDRSZ && len > maxlen) |
| { |
| /* Verify that input length is within typmod limit. |
| * |
| * NOTE: blankspace is not truncated |
| */ |
| size_t mbmaxlen = pg_mbstrlen(s); |
| |
| if (mbmaxlen > maxlen) |
| ereport(ERROR, |
| (errcode(ERRCODE_INVALID_PARAMETER_VALUE), |
| errmsg("input value length is %zd; too long for type nvarchar2(%zd)", mbmaxlen , maxlen))); |
| } |
| |
| result = (VarChar *) cstring_to_text_with_len(s, size2int(len)); |
| return result; |
| } |
| |
| /* |
| * Converts a C string to NVARCHAR2 internal representation. atttypmod |
| * is the declared length of the type plus VARHDRSZ. |
| */ |
| Datum |
| nvarchar2in(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 = nvarchar2_input(s, strlen(s), atttypmod); |
| PG_RETURN_VARCHAR_P(result); |
| } |
| |
| |
| /* |
| * converts a NVARCHAR2 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 |
| nvarchar2out(PG_FUNCTION_ARGS) |
| { |
| Datum txt = PG_GETARG_DATUM(0); |
| |
| PG_RETURN_CSTRING(TextDatumGetCString(txt)); |
| } |
| |
| /* |
| * converts external binary format to nvarchar |
| */ |
| Datum |
| nvarchar2recv(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); /* typmod of the receiving column */ |
| VarChar *result; |
| char *str; /* received data */ |
| int nbytes; /* length in bytes of recived data */ |
| |
| str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); |
| result = nvarchar2_input(str, nbytes, atttypmod); |
| pfree(str); |
| PG_RETURN_VARCHAR_P(result); |
| } |
| |
| |
| /* |
| * nvarchar2send -- convert nvarchar2 to binary value |
| * |
| * just use varcharsend() |
| */ |
| |
| /* |
| * nvarchar2_transform() |
| * Flatten calls to varchar's length coercion function that set the new maximum |
| * length >= the previous maximum length. We can ignore the isExplicit |
| * argument, since that only affects truncation cases. |
| * |
| * just use varchar_transform() |
| */ |
| |
| /* |
| * 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; |
| int 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, size2int(maxmblen))); |
| } |
| |
| |
| /* |
| * nvarchar2typmodin -- type modifier input function |
| * |
| * just use varchartypmodin() |
| */ |
| |
| /* |
| * nvarchar2typmodout -- type modifier output function |
| * |
| * just use varchartypmodout() |
| */ |