From 50626efe0aef19fa31fd9ccf79570a24b84bbf01 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Thu, 7 Jan 2010 20:17:44 +0000
Subject: [PATCH] Fix 3-parameter form of bit substring() to throw error for
 negative length, as required by SQL standard.

---
 src/backend/utils/adt/varbit.c   | 34 +++++++++++++++++++++++++-------
 src/include/catalog/catversion.h |  4 ++--
 src/include/catalog/pg_proc.h    |  4 ++--
 src/include/utils/varbit.h       |  3 ++-
 4 files changed, 33 insertions(+), 12 deletions(-)

diff --git a/src/backend/utils/adt/varbit.c b/src/backend/utils/adt/varbit.c
index d98a8a613ee..7f39866f005 100644
--- a/src/backend/utils/adt/varbit.c
+++ b/src/backend/utils/adt/varbit.c
@@ -9,7 +9,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.62 2010/01/07 19:53:11 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/varbit.c,v 1.63 2010/01/07 20:17:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index b6505feeefd..b81a777e0b3 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.569 2010/01/06 05:18:18 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.570 2010/01/07 20:17:43 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	201001061
+#define CATALOG_VERSION_NO	201001071
 
 #endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 17172969516..b39c02f7f28 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.559 2010/01/05 01:06:56 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.560 2010/01/07 20:17:44 tgl Exp $
  *
  * NOTES
  *	  The script catalog/genbki.pl reads this file and generates .bki
@@ -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");
 
 
diff --git a/src/include/utils/varbit.h b/src/include/utils/varbit.h
index a7aaa57902a..df51c9b4159 100644
--- a/src/include/utils/varbit.h
+++ b/src/include/utils/varbit.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/varbit.h,v 1.29 2010/01/02 16:58:10 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/varbit.h,v 1.30 2010/01/07 20:17:44 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -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);
-- 
GitLab