Header And Logo

PostgreSQL
| The world's most advanced open source database.

varchar.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * varchar.c
00004  *    Functions for the built-in types char(n) and varchar(n).
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/utils/adt/varchar.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 #include "postgres.h"
00016 
00017 
00018 #include "access/hash.h"
00019 #include "access/tuptoaster.h"
00020 #include "libpq/pqformat.h"
00021 #include "nodes/nodeFuncs.h"
00022 #include "utils/array.h"
00023 #include "utils/builtins.h"
00024 #include "mb/pg_wchar.h"
00025 
00026 
00027 /* common code for bpchartypmodin and varchartypmodin */
00028 static int32
00029 anychar_typmodin(ArrayType *ta, const char *typename)
00030 {
00031     int32       typmod;
00032     int32      *tl;
00033     int         n;
00034 
00035     tl = ArrayGetIntegerTypmods(ta, &n);
00036 
00037     /*
00038      * we're not too tense about good error message here because grammar
00039      * shouldn't allow wrong number of modifiers for CHAR
00040      */
00041     if (n != 1)
00042         ereport(ERROR,
00043                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00044                  errmsg("invalid type modifier")));
00045 
00046     if (*tl < 1)
00047         ereport(ERROR,
00048                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00049                  errmsg("length for type %s must be at least 1", typename)));
00050     if (*tl > MaxAttrSize)
00051         ereport(ERROR,
00052                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00053                  errmsg("length for type %s cannot exceed %d",
00054                         typename, MaxAttrSize)));
00055 
00056     /*
00057      * For largely historical reasons, the typmod is VARHDRSZ plus the number
00058      * of characters; there is enough client-side code that knows about that
00059      * that we'd better not change it.
00060      */
00061     typmod = VARHDRSZ + *tl;
00062 
00063     return typmod;
00064 }
00065 
00066 /* common code for bpchartypmodout and varchartypmodout */
00067 static char *
00068 anychar_typmodout(int32 typmod)
00069 {
00070     char       *res = (char *) palloc(64);
00071 
00072     if (typmod > VARHDRSZ)
00073         snprintf(res, 64, "(%d)", (int) (typmod - VARHDRSZ));
00074     else
00075         *res = '\0';
00076 
00077     return res;
00078 }
00079 
00080 
00081 /*
00082  * CHAR() and VARCHAR() types are part of the SQL standard. CHAR()
00083  * is for blank-padded string whose length is specified in CREATE TABLE.
00084  * VARCHAR is for storing string whose length is at most the length specified
00085  * at CREATE TABLE time.
00086  *
00087  * It's hard to implement these types because we cannot figure out
00088  * the length of the type from the type itself. I changed (hopefully all) the
00089  * fmgr calls that invoke input functions of a data type to supply the
00090  * length also. (eg. in INSERTs, we have the tupleDescriptor which contains
00091  * the length of the attributes and hence the exact length of the char() or
00092  * varchar(). We pass this to bpcharin() or varcharin().) In the case where
00093  * we cannot determine the length, we pass in -1 instead and the input
00094  * converter does not enforce any length check.
00095  *
00096  * We actually implement this as a varlena so that we don't have to pass in
00097  * the length for the comparison functions. (The difference between these
00098  * types and "text" is that we truncate and possibly blank-pad the string
00099  * at insertion time.)
00100  *
00101  *                                                            - ay 6/95
00102  */
00103 
00104 
00105 /*****************************************************************************
00106  *   bpchar - char()                                                         *
00107  *****************************************************************************/
00108 
00109 /*
00110  * bpchar_input -- common guts of bpcharin and bpcharrecv
00111  *
00112  * s is the input text of length len (may not be null-terminated)
00113  * atttypmod is the typmod value to apply
00114  *
00115  * Note that atttypmod is measured in characters, which
00116  * is not necessarily the same as the number of bytes.
00117  *
00118  * If the input string is too long, raise an error, unless the extra
00119  * characters are spaces, in which case they're truncated.  (per SQL)
00120  */
00121 static BpChar *
00122 bpchar_input(const char *s, size_t len, int32 atttypmod)
00123 {
00124     BpChar     *result;
00125     char       *r;
00126     size_t      maxlen;
00127 
00128     /* If typmod is -1 (or invalid), use the actual string length */
00129     if (atttypmod < (int32) VARHDRSZ)
00130         maxlen = len;
00131     else
00132     {
00133         size_t      charlen;    /* number of CHARACTERS in the input */
00134 
00135         maxlen = atttypmod - VARHDRSZ;
00136         charlen = pg_mbstrlen_with_len(s, len);
00137         if (charlen > maxlen)
00138         {
00139             /* Verify that extra characters are spaces, and clip them off */
00140             size_t      mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
00141             size_t      j;
00142 
00143             /*
00144              * at this point, len is the actual BYTE length of the input
00145              * string, maxlen is the max number of CHARACTERS allowed for this
00146              * bpchar type, mbmaxlen is the length in BYTES of those chars.
00147              */
00148             for (j = mbmaxlen; j < len; j++)
00149             {
00150                 if (s[j] != ' ')
00151                     ereport(ERROR,
00152                             (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
00153                              errmsg("value too long for type character(%d)",
00154                                     (int) maxlen)));
00155             }
00156 
00157             /*
00158              * Now we set maxlen to the necessary byte length, not the number
00159              * of CHARACTERS!
00160              */
00161             maxlen = len = mbmaxlen;
00162         }
00163         else
00164         {
00165             /*
00166              * Now we set maxlen to the necessary byte length, not the number
00167              * of CHARACTERS!
00168              */
00169             maxlen = len + (maxlen - charlen);
00170         }
00171     }
00172 
00173     result = (BpChar *) palloc(maxlen + VARHDRSZ);
00174     SET_VARSIZE(result, maxlen + VARHDRSZ);
00175     r = VARDATA(result);
00176     memcpy(r, s, len);
00177 
00178     /* blank pad the string if necessary */
00179     if (maxlen > len)
00180         memset(r + len, ' ', maxlen - len);
00181 
00182     return result;
00183 }
00184 
00185 /*
00186  * Convert a C string to CHARACTER internal representation.  atttypmod
00187  * is the declared length of the type plus VARHDRSZ.
00188  */
00189 Datum
00190 bpcharin(PG_FUNCTION_ARGS)
00191 {
00192     char       *s = PG_GETARG_CSTRING(0);
00193 
00194 #ifdef NOT_USED
00195     Oid         typelem = PG_GETARG_OID(1);
00196 #endif
00197     int32       atttypmod = PG_GETARG_INT32(2);
00198     BpChar     *result;
00199 
00200     result = bpchar_input(s, strlen(s), atttypmod);
00201     PG_RETURN_BPCHAR_P(result);
00202 }
00203 
00204 
00205 /*
00206  * Convert a CHARACTER value to a C string.
00207  *
00208  * Uses the text conversion functions, which is only appropriate if BpChar
00209  * and text are equivalent types.
00210  */
00211 Datum
00212 bpcharout(PG_FUNCTION_ARGS)
00213 {
00214     Datum       txt = PG_GETARG_DATUM(0);
00215 
00216     PG_RETURN_CSTRING(TextDatumGetCString(txt));
00217 }
00218 
00219 /*
00220  *      bpcharrecv          - converts external binary format to bpchar
00221  */
00222 Datum
00223 bpcharrecv(PG_FUNCTION_ARGS)
00224 {
00225     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
00226 
00227 #ifdef NOT_USED
00228     Oid         typelem = PG_GETARG_OID(1);
00229 #endif
00230     int32       atttypmod = PG_GETARG_INT32(2);
00231     BpChar     *result;
00232     char       *str;
00233     int         nbytes;
00234 
00235     str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
00236     result = bpchar_input(str, nbytes, atttypmod);
00237     pfree(str);
00238     PG_RETURN_BPCHAR_P(result);
00239 }
00240 
00241 /*
00242  *      bpcharsend          - converts bpchar to binary format
00243  */
00244 Datum
00245 bpcharsend(PG_FUNCTION_ARGS)
00246 {
00247     /* Exactly the same as textsend, so share code */
00248     return textsend(fcinfo);
00249 }
00250 
00251 
00252 /*
00253  * Converts a CHARACTER type to the specified size.
00254  *
00255  * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes.
00256  * isExplicit is true if this is for an explicit cast to char(N).
00257  *
00258  * Truncation rules: for an explicit cast, silently truncate to the given
00259  * length; for an implicit cast, raise error unless extra characters are
00260  * all spaces.  (This is sort-of per SQL: the spec would actually have us
00261  * raise a "completion condition" for the explicit cast case, but Postgres
00262  * hasn't got such a concept.)
00263  */
00264 Datum
00265 bpchar(PG_FUNCTION_ARGS)
00266 {
00267     BpChar     *source = PG_GETARG_BPCHAR_PP(0);
00268     int32       maxlen = PG_GETARG_INT32(1);
00269     bool        isExplicit = PG_GETARG_BOOL(2);
00270     BpChar     *result;
00271     int32       len;
00272     char       *r;
00273     char       *s;
00274     int         i;
00275     int         charlen;        /* number of characters in the input string +
00276                                  * VARHDRSZ */
00277 
00278     /* No work if typmod is invalid */
00279     if (maxlen < (int32) VARHDRSZ)
00280         PG_RETURN_BPCHAR_P(source);
00281 
00282     maxlen -= VARHDRSZ;
00283 
00284     len = VARSIZE_ANY_EXHDR(source);
00285     s = VARDATA_ANY(source);
00286 
00287     charlen = pg_mbstrlen_with_len(s, len);
00288 
00289     /* No work if supplied data matches typmod already */
00290     if (charlen == maxlen)
00291         PG_RETURN_BPCHAR_P(source);
00292 
00293     if (charlen > maxlen)
00294     {
00295         /* Verify that extra characters are spaces, and clip them off */
00296         size_t      maxmblen;
00297 
00298         maxmblen = pg_mbcharcliplen(s, len, maxlen);
00299 
00300         if (!isExplicit)
00301         {
00302             for (i = maxmblen; i < len; i++)
00303                 if (s[i] != ' ')
00304                     ereport(ERROR,
00305                             (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
00306                              errmsg("value too long for type character(%d)",
00307                                     maxlen)));
00308         }
00309 
00310         len = maxmblen;
00311 
00312         /*
00313          * At this point, maxlen is the necessary byte length, not the number
00314          * of CHARACTERS!
00315          */
00316         maxlen = len;
00317     }
00318     else
00319     {
00320         /*
00321          * At this point, maxlen is the necessary byte length, not the number
00322          * of CHARACTERS!
00323          */
00324         maxlen = len + (maxlen - charlen);
00325     }
00326 
00327     Assert(maxlen >= len);
00328 
00329     result = palloc(maxlen + VARHDRSZ);
00330     SET_VARSIZE(result, maxlen + VARHDRSZ);
00331     r = VARDATA(result);
00332 
00333     memcpy(r, s, len);
00334 
00335     /* blank pad the string if necessary */
00336     if (maxlen > len)
00337         memset(r + len, ' ', maxlen - len);
00338 
00339     PG_RETURN_BPCHAR_P(result);
00340 }
00341 
00342 
00343 /* char_bpchar()
00344  * Convert char to bpchar(1).
00345  */
00346 Datum
00347 char_bpchar(PG_FUNCTION_ARGS)
00348 {
00349     char        c = PG_GETARG_CHAR(0);
00350     BpChar     *result;
00351 
00352     result = (BpChar *) palloc(VARHDRSZ + 1);
00353 
00354     SET_VARSIZE(result, VARHDRSZ + 1);
00355     *(VARDATA(result)) = c;
00356 
00357     PG_RETURN_BPCHAR_P(result);
00358 }
00359 
00360 
00361 /* bpchar_name()
00362  * Converts a bpchar() type to a NameData type.
00363  */
00364 Datum
00365 bpchar_name(PG_FUNCTION_ARGS)
00366 {
00367     BpChar     *s = PG_GETARG_BPCHAR_PP(0);
00368     char       *s_data;
00369     Name        result;
00370     int         len;
00371 
00372     len = VARSIZE_ANY_EXHDR(s);
00373     s_data = VARDATA_ANY(s);
00374 
00375     /* Truncate oversize input */
00376     if (len >= NAMEDATALEN)
00377         len = pg_mbcliplen(s_data, len, NAMEDATALEN - 1);
00378 
00379     /* Remove trailing blanks */
00380     while (len > 0)
00381     {
00382         if (s_data[len - 1] != ' ')
00383             break;
00384         len--;
00385     }
00386 
00387     /* We use palloc0 here to ensure result is zero-padded */
00388     result = (Name) palloc0(NAMEDATALEN);
00389     memcpy(NameStr(*result), s_data, len);
00390 
00391     PG_RETURN_NAME(result);
00392 }
00393 
00394 /* name_bpchar()
00395  * Converts a NameData type to a bpchar type.
00396  *
00397  * Uses the text conversion functions, which is only appropriate if BpChar
00398  * and text are equivalent types.
00399  */
00400 Datum
00401 name_bpchar(PG_FUNCTION_ARGS)
00402 {
00403     Name        s = PG_GETARG_NAME(0);
00404     BpChar     *result;
00405 
00406     result = (BpChar *) cstring_to_text(NameStr(*s));
00407     PG_RETURN_BPCHAR_P(result);
00408 }
00409 
00410 Datum
00411 bpchartypmodin(PG_FUNCTION_ARGS)
00412 {
00413     ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
00414 
00415     PG_RETURN_INT32(anychar_typmodin(ta, "char"));
00416 }
00417 
00418 Datum
00419 bpchartypmodout(PG_FUNCTION_ARGS)
00420 {
00421     int32       typmod = PG_GETARG_INT32(0);
00422 
00423     PG_RETURN_CSTRING(anychar_typmodout(typmod));
00424 }
00425 
00426 
00427 /*****************************************************************************
00428  *   varchar - varchar(n)
00429  *
00430  * Note: varchar piggybacks on type text for most operations, and so has no
00431  * C-coded functions except for I/O and typmod checking.
00432  *****************************************************************************/
00433 
00434 /*
00435  * varchar_input -- common guts of varcharin and varcharrecv
00436  *
00437  * s is the input text of length len (may not be null-terminated)
00438  * atttypmod is the typmod value to apply
00439  *
00440  * Note that atttypmod is measured in characters, which
00441  * is not necessarily the same as the number of bytes.
00442  *
00443  * If the input string is too long, raise an error, unless the extra
00444  * characters are spaces, in which case they're truncated.  (per SQL)
00445  *
00446  * Uses the C string to text conversion function, which is only appropriate
00447  * if VarChar and text are equivalent types.
00448  */
00449 static VarChar *
00450 varchar_input(const char *s, size_t len, int32 atttypmod)
00451 {
00452     VarChar    *result;
00453     size_t      maxlen;
00454 
00455     maxlen = atttypmod - VARHDRSZ;
00456 
00457     if (atttypmod >= (int32) VARHDRSZ && len > maxlen)
00458     {
00459         /* Verify that extra characters are spaces, and clip them off */
00460         size_t      mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
00461         size_t      j;
00462 
00463         for (j = mbmaxlen; j < len; j++)
00464         {
00465             if (s[j] != ' ')
00466                 ereport(ERROR,
00467                         (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
00468                       errmsg("value too long for type character varying(%d)",
00469                              (int) maxlen)));
00470         }
00471 
00472         len = mbmaxlen;
00473     }
00474 
00475     result = (VarChar *) cstring_to_text_with_len(s, len);
00476     return result;
00477 }
00478 
00479 /*
00480  * Convert a C string to VARCHAR internal representation.  atttypmod
00481  * is the declared length of the type plus VARHDRSZ.
00482  */
00483 Datum
00484 varcharin(PG_FUNCTION_ARGS)
00485 {
00486     char       *s = PG_GETARG_CSTRING(0);
00487 
00488 #ifdef NOT_USED
00489     Oid         typelem = PG_GETARG_OID(1);
00490 #endif
00491     int32       atttypmod = PG_GETARG_INT32(2);
00492     VarChar    *result;
00493 
00494     result = varchar_input(s, strlen(s), atttypmod);
00495     PG_RETURN_VARCHAR_P(result);
00496 }
00497 
00498 
00499 /*
00500  * Convert a VARCHAR value to a C string.
00501  *
00502  * Uses the text to C string conversion function, which is only appropriate
00503  * if VarChar and text are equivalent types.
00504  */
00505 Datum
00506 varcharout(PG_FUNCTION_ARGS)
00507 {
00508     Datum       txt = PG_GETARG_DATUM(0);
00509 
00510     PG_RETURN_CSTRING(TextDatumGetCString(txt));
00511 }
00512 
00513 /*
00514  *      varcharrecv         - converts external binary format to varchar
00515  */
00516 Datum
00517 varcharrecv(PG_FUNCTION_ARGS)
00518 {
00519     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
00520 
00521 #ifdef NOT_USED
00522     Oid         typelem = PG_GETARG_OID(1);
00523 #endif
00524     int32       atttypmod = PG_GETARG_INT32(2);
00525     VarChar    *result;
00526     char       *str;
00527     int         nbytes;
00528 
00529     str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
00530     result = varchar_input(str, nbytes, atttypmod);
00531     pfree(str);
00532     PG_RETURN_VARCHAR_P(result);
00533 }
00534 
00535 /*
00536  *      varcharsend         - converts varchar to binary format
00537  */
00538 Datum
00539 varcharsend(PG_FUNCTION_ARGS)
00540 {
00541     /* Exactly the same as textsend, so share code */
00542     return textsend(fcinfo);
00543 }
00544 
00545 
00546 /*
00547  * varchar_transform()
00548  * Flatten calls to varchar's length coercion function that set the new maximum
00549  * length >= the previous maximum length.  We can ignore the isExplicit
00550  * argument, since that only affects truncation cases.
00551  */
00552 Datum
00553 varchar_transform(PG_FUNCTION_ARGS)
00554 {
00555     FuncExpr   *expr = (FuncExpr *) PG_GETARG_POINTER(0);
00556     Node       *ret = NULL;
00557     Node       *typmod;
00558 
00559     Assert(IsA(expr, FuncExpr));
00560     Assert(list_length(expr->args) >= 2);
00561 
00562     typmod = (Node *) lsecond(expr->args);
00563 
00564     if (IsA(typmod, Const) &&!((Const *) typmod)->constisnull)
00565     {
00566         Node       *source = (Node *) linitial(expr->args);
00567         int32       old_typmod = exprTypmod(source);
00568         int32       new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
00569         int32       old_max = old_typmod - VARHDRSZ;
00570         int32       new_max = new_typmod - VARHDRSZ;
00571 
00572         if (new_typmod < 0 || (old_typmod >= 0 && old_max <= new_max))
00573             ret = relabel_to_typmod(source, new_typmod);
00574     }
00575 
00576     PG_RETURN_POINTER(ret);
00577 }
00578 
00579 /*
00580  * Converts a VARCHAR type to the specified size.
00581  *
00582  * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes.
00583  * isExplicit is true if this is for an explicit cast to varchar(N).
00584  *
00585  * Truncation rules: for an explicit cast, silently truncate to the given
00586  * length; for an implicit cast, raise error unless extra characters are
00587  * all spaces.  (This is sort-of per SQL: the spec would actually have us
00588  * raise a "completion condition" for the explicit cast case, but Postgres
00589  * hasn't got such a concept.)
00590  */
00591 Datum
00592 varchar(PG_FUNCTION_ARGS)
00593 {
00594     VarChar    *source = PG_GETARG_VARCHAR_PP(0);
00595     int32       typmod = PG_GETARG_INT32(1);
00596     bool        isExplicit = PG_GETARG_BOOL(2);
00597     int32       len,
00598                 maxlen;
00599     size_t      maxmblen;
00600     int         i;
00601     char       *s_data;
00602 
00603     len = VARSIZE_ANY_EXHDR(source);
00604     s_data = VARDATA_ANY(source);
00605     maxlen = typmod - VARHDRSZ;
00606 
00607     /* No work if typmod is invalid or supplied data fits it already */
00608     if (maxlen < 0 || len <= maxlen)
00609         PG_RETURN_VARCHAR_P(source);
00610 
00611     /* only reach here if string is too long... */
00612 
00613     /* truncate multibyte string preserving multibyte boundary */
00614     maxmblen = pg_mbcharcliplen(s_data, len, maxlen);
00615 
00616     if (!isExplicit)
00617     {
00618         for (i = maxmblen; i < len; i++)
00619             if (s_data[i] != ' ')
00620                 ereport(ERROR,
00621                         (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
00622                       errmsg("value too long for type character varying(%d)",
00623                              maxlen)));
00624     }
00625 
00626     PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text_with_len(s_data,
00627                                                              maxmblen));
00628 }
00629 
00630 Datum
00631 varchartypmodin(PG_FUNCTION_ARGS)
00632 {
00633     ArrayType  *ta = PG_GETARG_ARRAYTYPE_P(0);
00634 
00635     PG_RETURN_INT32(anychar_typmodin(ta, "varchar"));
00636 }
00637 
00638 Datum
00639 varchartypmodout(PG_FUNCTION_ARGS)
00640 {
00641     int32       typmod = PG_GETARG_INT32(0);
00642 
00643     PG_RETURN_CSTRING(anychar_typmodout(typmod));
00644 }
00645 
00646 
00647 /*****************************************************************************
00648  * Exported functions
00649  *****************************************************************************/
00650 
00651 /* "True" length (not counting trailing blanks) of a BpChar */
00652 static int
00653 bcTruelen(BpChar *arg)
00654 {
00655     char       *s = VARDATA_ANY(arg);
00656     int         i;
00657     int         len;
00658 
00659     len = VARSIZE_ANY_EXHDR(arg);
00660     for (i = len - 1; i >= 0; i--)
00661     {
00662         if (s[i] != ' ')
00663             break;
00664     }
00665     return i + 1;
00666 }
00667 
00668 Datum
00669 bpcharlen(PG_FUNCTION_ARGS)
00670 {
00671     BpChar     *arg = PG_GETARG_BPCHAR_PP(0);
00672     int         len;
00673 
00674     /* get number of bytes, ignoring trailing spaces */
00675     len = bcTruelen(arg);
00676 
00677     /* in multibyte encoding, convert to number of characters */
00678     if (pg_database_encoding_max_length() != 1)
00679         len = pg_mbstrlen_with_len(VARDATA_ANY(arg), len);
00680 
00681     PG_RETURN_INT32(len);
00682 }
00683 
00684 Datum
00685 bpcharoctetlen(PG_FUNCTION_ARGS)
00686 {
00687     Datum       arg = PG_GETARG_DATUM(0);
00688 
00689     /* We need not detoast the input at all */
00690     PG_RETURN_INT32(toast_raw_datum_size(arg) - VARHDRSZ);
00691 }
00692 
00693 
00694 /*****************************************************************************
00695  *  Comparison Functions used for bpchar
00696  *
00697  * Note: btree indexes need these routines not to leak memory; therefore,
00698  * be careful to free working copies of toasted datums.  Most places don't
00699  * need to be so careful.
00700  *****************************************************************************/
00701 
00702 Datum
00703 bpchareq(PG_FUNCTION_ARGS)
00704 {
00705     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
00706     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
00707     int         len1,
00708                 len2;
00709     bool        result;
00710 
00711     len1 = bcTruelen(arg1);
00712     len2 = bcTruelen(arg2);
00713 
00714     /*
00715      * Since we only care about equality or not-equality, we can avoid all the
00716      * expense of strcoll() here, and just do bitwise comparison.
00717      */
00718     if (len1 != len2)
00719         result = false;
00720     else
00721         result = (memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) == 0);
00722 
00723     PG_FREE_IF_COPY(arg1, 0);
00724     PG_FREE_IF_COPY(arg2, 1);
00725 
00726     PG_RETURN_BOOL(result);
00727 }
00728 
00729 Datum
00730 bpcharne(PG_FUNCTION_ARGS)
00731 {
00732     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
00733     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
00734     int         len1,
00735                 len2;
00736     bool        result;
00737 
00738     len1 = bcTruelen(arg1);
00739     len2 = bcTruelen(arg2);
00740 
00741     /*
00742      * Since we only care about equality or not-equality, we can avoid all the
00743      * expense of strcoll() here, and just do bitwise comparison.
00744      */
00745     if (len1 != len2)
00746         result = true;
00747     else
00748         result = (memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) != 0);
00749 
00750     PG_FREE_IF_COPY(arg1, 0);
00751     PG_FREE_IF_COPY(arg2, 1);
00752 
00753     PG_RETURN_BOOL(result);
00754 }
00755 
00756 Datum
00757 bpcharlt(PG_FUNCTION_ARGS)
00758 {
00759     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
00760     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
00761     int         len1,
00762                 len2;
00763     int         cmp;
00764 
00765     len1 = bcTruelen(arg1);
00766     len2 = bcTruelen(arg2);
00767 
00768     cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
00769                      PG_GET_COLLATION());
00770 
00771     PG_FREE_IF_COPY(arg1, 0);
00772     PG_FREE_IF_COPY(arg2, 1);
00773 
00774     PG_RETURN_BOOL(cmp < 0);
00775 }
00776 
00777 Datum
00778 bpcharle(PG_FUNCTION_ARGS)
00779 {
00780     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
00781     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
00782     int         len1,
00783                 len2;
00784     int         cmp;
00785 
00786     len1 = bcTruelen(arg1);
00787     len2 = bcTruelen(arg2);
00788 
00789     cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
00790                      PG_GET_COLLATION());
00791 
00792     PG_FREE_IF_COPY(arg1, 0);
00793     PG_FREE_IF_COPY(arg2, 1);
00794 
00795     PG_RETURN_BOOL(cmp <= 0);
00796 }
00797 
00798 Datum
00799 bpchargt(PG_FUNCTION_ARGS)
00800 {
00801     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
00802     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
00803     int         len1,
00804                 len2;
00805     int         cmp;
00806 
00807     len1 = bcTruelen(arg1);
00808     len2 = bcTruelen(arg2);
00809 
00810     cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
00811                      PG_GET_COLLATION());
00812 
00813     PG_FREE_IF_COPY(arg1, 0);
00814     PG_FREE_IF_COPY(arg2, 1);
00815 
00816     PG_RETURN_BOOL(cmp > 0);
00817 }
00818 
00819 Datum
00820 bpcharge(PG_FUNCTION_ARGS)
00821 {
00822     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
00823     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
00824     int         len1,
00825                 len2;
00826     int         cmp;
00827 
00828     len1 = bcTruelen(arg1);
00829     len2 = bcTruelen(arg2);
00830 
00831     cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
00832                      PG_GET_COLLATION());
00833 
00834     PG_FREE_IF_COPY(arg1, 0);
00835     PG_FREE_IF_COPY(arg2, 1);
00836 
00837     PG_RETURN_BOOL(cmp >= 0);
00838 }
00839 
00840 Datum
00841 bpcharcmp(PG_FUNCTION_ARGS)
00842 {
00843     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
00844     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
00845     int         len1,
00846                 len2;
00847     int         cmp;
00848 
00849     len1 = bcTruelen(arg1);
00850     len2 = bcTruelen(arg2);
00851 
00852     cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
00853                      PG_GET_COLLATION());
00854 
00855     PG_FREE_IF_COPY(arg1, 0);
00856     PG_FREE_IF_COPY(arg2, 1);
00857 
00858     PG_RETURN_INT32(cmp);
00859 }
00860 
00861 Datum
00862 bpchar_larger(PG_FUNCTION_ARGS)
00863 {
00864     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
00865     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
00866     int         len1,
00867                 len2;
00868     int         cmp;
00869 
00870     len1 = bcTruelen(arg1);
00871     len2 = bcTruelen(arg2);
00872 
00873     cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
00874                      PG_GET_COLLATION());
00875 
00876     PG_RETURN_BPCHAR_P((cmp >= 0) ? arg1 : arg2);
00877 }
00878 
00879 Datum
00880 bpchar_smaller(PG_FUNCTION_ARGS)
00881 {
00882     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
00883     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
00884     int         len1,
00885                 len2;
00886     int         cmp;
00887 
00888     len1 = bcTruelen(arg1);
00889     len2 = bcTruelen(arg2);
00890 
00891     cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
00892                      PG_GET_COLLATION());
00893 
00894     PG_RETURN_BPCHAR_P((cmp <= 0) ? arg1 : arg2);
00895 }
00896 
00897 
00898 /*
00899  * bpchar needs a specialized hash function because we want to ignore
00900  * trailing blanks in comparisons.
00901  *
00902  * Note: currently there is no need for locale-specific behavior here,
00903  * but if we ever change the semantics of bpchar comparison to trust
00904  * strcoll() completely, we'd need to do something different in non-C locales.
00905  */
00906 Datum
00907 hashbpchar(PG_FUNCTION_ARGS)
00908 {
00909     BpChar     *key = PG_GETARG_BPCHAR_PP(0);
00910     char       *keydata;
00911     int         keylen;
00912     Datum       result;
00913 
00914     keydata = VARDATA_ANY(key);
00915     keylen = bcTruelen(key);
00916 
00917     result = hash_any((unsigned char *) keydata, keylen);
00918 
00919     /* Avoid leaking memory for toasted inputs */
00920     PG_FREE_IF_COPY(key, 0);
00921 
00922     return result;
00923 }
00924 
00925 
00926 /*
00927  * The following operators support character-by-character comparison
00928  * of bpchar datums, to allow building indexes suitable for LIKE clauses.
00929  * Note that the regular bpchareq/bpcharne comparison operators are assumed
00930  * to be compatible with these!
00931  */
00932 
00933 static int
00934 internal_bpchar_pattern_compare(BpChar *arg1, BpChar *arg2)
00935 {
00936     int         result;
00937     int         len1,
00938                 len2;
00939 
00940     len1 = bcTruelen(arg1);
00941     len2 = bcTruelen(arg2);
00942 
00943     result = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
00944     if (result != 0)
00945         return result;
00946     else if (len1 < len2)
00947         return -1;
00948     else if (len1 > len2)
00949         return 1;
00950     else
00951         return 0;
00952 }
00953 
00954 
00955 Datum
00956 bpchar_pattern_lt(PG_FUNCTION_ARGS)
00957 {
00958     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
00959     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
00960     int         result;
00961 
00962     result = internal_bpchar_pattern_compare(arg1, arg2);
00963 
00964     PG_FREE_IF_COPY(arg1, 0);
00965     PG_FREE_IF_COPY(arg2, 1);
00966 
00967     PG_RETURN_BOOL(result < 0);
00968 }
00969 
00970 
00971 Datum
00972 bpchar_pattern_le(PG_FUNCTION_ARGS)
00973 {
00974     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
00975     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
00976     int         result;
00977 
00978     result = internal_bpchar_pattern_compare(arg1, arg2);
00979 
00980     PG_FREE_IF_COPY(arg1, 0);
00981     PG_FREE_IF_COPY(arg2, 1);
00982 
00983     PG_RETURN_BOOL(result <= 0);
00984 }
00985 
00986 
00987 Datum
00988 bpchar_pattern_ge(PG_FUNCTION_ARGS)
00989 {
00990     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
00991     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
00992     int         result;
00993 
00994     result = internal_bpchar_pattern_compare(arg1, arg2);
00995 
00996     PG_FREE_IF_COPY(arg1, 0);
00997     PG_FREE_IF_COPY(arg2, 1);
00998 
00999     PG_RETURN_BOOL(result >= 0);
01000 }
01001 
01002 
01003 Datum
01004 bpchar_pattern_gt(PG_FUNCTION_ARGS)
01005 {
01006     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
01007     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
01008     int         result;
01009 
01010     result = internal_bpchar_pattern_compare(arg1, arg2);
01011 
01012     PG_FREE_IF_COPY(arg1, 0);
01013     PG_FREE_IF_COPY(arg2, 1);
01014 
01015     PG_RETURN_BOOL(result > 0);
01016 }
01017 
01018 
01019 Datum
01020 btbpchar_pattern_cmp(PG_FUNCTION_ARGS)
01021 {
01022     BpChar     *arg1 = PG_GETARG_BPCHAR_PP(0);
01023     BpChar     *arg2 = PG_GETARG_BPCHAR_PP(1);
01024     int         result;
01025 
01026     result = internal_bpchar_pattern_compare(arg1, arg2);
01027 
01028     PG_FREE_IF_COPY(arg1, 0);
01029     PG_FREE_IF_COPY(arg2, 1);
01030 
01031     PG_RETURN_INT32(result);
01032 }