]> granicus.if.org Git - postgresql/commitdiff
Add a transform function for varbit typmod coercisions.
authorRobert Haas <rhaas@postgresql.org>
Tue, 7 Feb 2012 17:41:42 +0000 (12:41 -0500)
committerRobert Haas <rhaas@postgresql.org>
Tue, 7 Feb 2012 17:42:50 +0000 (12:42 -0500)
This enables ALTER TABLE to skip table and index rebuilds when the
new type is unconstraint varbit, or when the allowable number of bits
is not decreasing.

Noah Misch, with review and a fix for an OID collision by me.

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

index adb08369ed28ab6b52aa2cd5213bcd5b4d8de7ad..1227e5a5082b03ba89100b2f7218e9368ab6a1d4 100644 (file)
@@ -18,6 +18,8 @@
 
 #include "access/htup.h"
 #include "libpq/pqformat.h"
+#include "nodes/nodeFuncs.h"
+#include "parser/parse_clause.h"
 #include "utils/array.h"
 #include "utils/varbit.h"
 
@@ -645,6 +647,39 @@ varbit_send(PG_FUNCTION_ARGS)
        PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
+/*
+ * varbit_transform()
+ * Flatten calls to our length coercion function that leave the new maximum
+ * length >= the previous maximum length.  We ignore the isExplicit argument,
+ * which only affects truncation.
+ */
+Datum
+varbit_transform(PG_FUNCTION_ARGS)
+{
+       FuncExpr   *expr = (FuncExpr *) PG_GETARG_POINTER(0);
+       Node       *typmod;
+       Node       *ret = NULL;
+
+       if (!IsA(expr, FuncExpr))
+               PG_RETURN_POINTER(ret);
+
+       Assert(list_length(expr->args) == 3);
+       typmod = lsecond(expr->args);
+
+       if (IsA(typmod, Const))
+       {
+               Node       *source = linitial(expr->args);
+               int32           new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
+               int32           old_max = exprTypmod(source);
+               int32           new_max = new_typmod;
+
+               if (new_max <= 0 || (old_max >= 0 && old_max <= new_max))
+                       ret = relabel_to_typmod(source, new_typmod);
+       }
+
+       PG_RETURN_POINTER(ret);
+}
+
 /*
  * varbit()
  * Converts a varbit() type to a specific internal length.
index a748c5e623ec78a2e8bbbacd9e98786e28446dda..ae4e5f5ae6b5fce71dfa2cd5a8c772664f01ee54 100644 (file)
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     201202071
+#define CATALOG_VERSION_NO     201202072
 
 #endif
index 006ed171824bb788192fdb22b15edba1c2a09764..f8d01fbba49de0b31ad62997e7861ab3e87ba529 100644 (file)
@@ -2009,7 +2009,9 @@ DESCR("convert bitstring to int4");
 
 DATA(insert OID = 1685 (  bit                     PGNSP PGUID 12 1 0 0 0 f f f t f i 3 0 1560 "1560 23 16" _null_ _null_ _null_ _null_ bit _null_ _null_ _null_ ));
 DESCR("adjust bit() to typmod length");
-DATA(insert OID = 1687 (  varbit                  PGNSP PGUID 12 1 0 0 0 f f f t f i 3 0 1562 "1562 23 16" _null_ _null_ _null_ _null_ varbit _null_ _null_ _null_ ));
+DATA(insert OID = 3158 ( varbit_transform  PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ varbit_transform _null_ _null_ _null_ ));
+DESCR("transform a varbit length coercion");
+DATA(insert OID = 1687 (  varbit                  PGNSP PGUID 12 1 0 0 3158 f f f t f i 3 0 1562 "1562 23 16" _null_ _null_ _null_ _null_ varbit _null_ _null_ _null_ ));
 DESCR("adjust varbit() to typmod length");
 
 DATA(insert OID = 1698 (  position                PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 23 "1560 1560" _null_ _null_ _null_ _null_ bitposition _null_ _null_ _null_ ));
index f268ca5853defea4b680731085d944c9dabd150b..52dca8b5d293ab3d50c123e369ce9797cbd1840f 100644 (file)
@@ -72,6 +72,7 @@ extern Datum varbit_send(PG_FUNCTION_ARGS);
 extern Datum varbittypmodin(PG_FUNCTION_ARGS);
 extern Datum varbittypmodout(PG_FUNCTION_ARGS);
 extern Datum bit(PG_FUNCTION_ARGS);
+extern Datum varbit_transform(PG_FUNCTION_ARGS);
 extern Datum varbit(PG_FUNCTION_ARGS);
 extern Datum biteq(PG_FUNCTION_ARGS);
 extern Datum bitne(PG_FUNCTION_ARGS);