Fix 3-parameter form of bit substring() to throw error for negative length,
authorTom Lane <[email protected]>
Thu, 7 Jan 2010 20:17:44 +0000 (20:17 +0000)
committerTom Lane <[email protected]>
Thu, 7 Jan 2010 20:17:44 +0000 (20:17 +0000)
as required by SQL standard.

src/backend/utils/adt/varbit.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/utils/varbit.h

index e5228caad0f62e8ee8de58721548a9540e700f91..576b872ff0ec359a455881c7152e030cd4b32b5e 100644 (file)
@@ -23,6 +23,9 @@
 
 #define HEXDIG(z)   ((z)<10 ? ((z)+'0') : ((z)-10+'A'))
 
+static VarBit *bitsubstring(VarBit *arg, int32 s, int32 l,
+                           bool length_not_specified);
+
 
 /* common code for bittypmodin and varbittypmodin */
 static int32
@@ -927,9 +930,23 @@ bitcat(PG_FUNCTION_ARGS)
 Datum
 bitsubstr(PG_FUNCTION_ARGS)
 {
-   VarBit     *arg = PG_GETARG_VARBIT_P(0);
-   int32       s = PG_GETARG_INT32(1);
-   int32       l = PG_GETARG_INT32(2);
+   PG_RETURN_VARBIT_P(bitsubstring(PG_GETARG_VARBIT_P(0),
+                                   PG_GETARG_INT32(1),
+                                   PG_GETARG_INT32(2),
+                                   false));
+}
+
+Datum
+bitsubstr_no_len(PG_FUNCTION_ARGS)
+{
+   PG_RETURN_VARBIT_P(bitsubstring(PG_GETARG_VARBIT_P(0),
+                                   PG_GETARG_INT32(1),
+                                   -1, true));
+}
+
+static VarBit *
+bitsubstring(VarBit *arg, int32 s, int32 l, bool length_not_specified)
+{
    VarBit     *result;
    int         bitlen,
                rbitlen,
@@ -947,14 +964,17 @@ bitsubstr(PG_FUNCTION_ARGS)
    bitlen = VARBITLEN(arg);
    s1 = Max(s, 1);
    /* If we do not have an upper bound, use end of string */
-   if (l < 0)
+   if (length_not_specified)
    {
        e1 = bitlen + 1;
    }
    else
    {
        e = s + l;
-       /* guard against overflow, even though we don't allow L<0 here */
+       /*
+        * A negative value for L is the only way for the end position
+        * to be before the start. SQL99 says to throw an error.
+        */
        if (e < s)
            ereport(ERROR,
                    (errcode(ERRCODE_SUBSTRING_ERROR),
@@ -1011,7 +1031,7 @@ bitsubstr(PG_FUNCTION_ARGS)
        }
    }
 
-   PG_RETURN_VARBIT_P(result);
+   return result;
 }
 
 /* bitlength, bitoctetlength
index e318793ba2141b4d38174437ffb151e62966066d..7aa8e067b563584a2c0cdfa089d23627866d4e8e 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 201001061
+#define CATALOG_VERSION_NO 201001071
 
 #endif
index ae6219ca5f02d3a783a69ce149554e64cbddeea4..a8efed9a6c4edb2e3ab804c93076675375d83579 100644 (file)
@@ -2400,7 +2400,7 @@ DESCR("adjust varbit() to typmod length");
 
 DATA(insert OID = 1698 (  position        PGNSP PGUID 12 1 0 0 f f f t f i 2 0 23 "1560 1560" _null_ _null_ _null_ _null_ bitposition _null_ _null_ _null_ ));
 DESCR("return position of sub-bitstring");
-DATA(insert OID = 1699 (  substring            PGNSP PGUID 14 1 0 0 f f f t f i 2 0 1560 "1560 23" _null_ _null_ _null_ _null_ "select pg_catalog.substring($1, $2, -1)" _null_ _null_ _null_ ));
+DATA(insert OID = 1699 (  substring            PGNSP PGUID 12 1 0 0 f f f t f i 2 0 1560 "1560 23" _null_ _null_ _null_ _null_ bitsubstr_no_len _null_ _null_ _null_ ));
 DESCR("return portion of bitstring");
 
 
index 36fd58f0706b1892b658a7c94166cee96ca583bc..57efc34bf6242162bd024bdf0aa27ee076e6bc11 100644 (file)
@@ -88,6 +88,7 @@ extern Datum bitshiftleft(PG_FUNCTION_ARGS);
 extern Datum bitshiftright(PG_FUNCTION_ARGS);
 extern Datum bitcat(PG_FUNCTION_ARGS);
 extern Datum bitsubstr(PG_FUNCTION_ARGS);
+extern Datum bitsubstr_no_len(PG_FUNCTION_ARGS);
 extern Datum bitlength(PG_FUNCTION_ARGS);
 extern Datum bitoctetlength(PG_FUNCTION_ARGS);
 extern Datum bitfromint4(PG_FUNCTION_ARGS);