Skip to content

Commit f7d7dad

Browse files
committed
Add a transform function for varbit typmod coercisions.
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.
1 parent 3cc0800 commit f7d7dad

File tree

4 files changed

+40
-2
lines changed

4 files changed

+40
-2
lines changed

src/backend/utils/adt/varbit.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
#include "access/htup.h"
2020
#include "libpq/pqformat.h"
21+
#include "nodes/nodeFuncs.h"
22+
#include "parser/parse_clause.h"
2123
#include "utils/array.h"
2224
#include "utils/varbit.h"
2325

@@ -645,6 +647,39 @@ varbit_send(PG_FUNCTION_ARGS)
645647
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
646648
}
647649

650+
/*
651+
* varbit_transform()
652+
* Flatten calls to our length coercion function that leave the new maximum
653+
* length >= the previous maximum length. We ignore the isExplicit argument,
654+
* which only affects truncation.
655+
*/
656+
Datum
657+
varbit_transform(PG_FUNCTION_ARGS)
658+
{
659+
FuncExpr *expr = (FuncExpr *) PG_GETARG_POINTER(0);
660+
Node *typmod;
661+
Node *ret = NULL;
662+
663+
if (!IsA(expr, FuncExpr))
664+
PG_RETURN_POINTER(ret);
665+
666+
Assert(list_length(expr->args) == 3);
667+
typmod = lsecond(expr->args);
668+
669+
if (IsA(typmod, Const))
670+
{
671+
Node *source = linitial(expr->args);
672+
int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
673+
int32 old_max = exprTypmod(source);
674+
int32 new_max = new_typmod;
675+
676+
if (new_max <= 0 || (old_max >= 0 && old_max <= new_max))
677+
ret = relabel_to_typmod(source, new_typmod);
678+
}
679+
680+
PG_RETURN_POINTER(ret);
681+
}
682+
648683
/*
649684
* varbit()
650685
* Converts a varbit() type to a specific internal length.

src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201202071
56+
#define CATALOG_VERSION_NO 201202072
5757

5858
#endif

src/include/catalog/pg_proc.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2009,7 +2009,9 @@ DESCR("convert bitstring to int4");
20092009

20102010
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_ ));
20112011
DESCR("adjust bit() to typmod length");
2012-
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_ ));
2012+
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_ ));
2013+
DESCR("transform a varbit length coercion");
2014+
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_ ));
20132015
DESCR("adjust varbit() to typmod length");
20142016

20152017
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_ ));

src/include/utils/varbit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ extern Datum varbit_send(PG_FUNCTION_ARGS);
7272
extern Datum varbittypmodin(PG_FUNCTION_ARGS);
7373
extern Datum varbittypmodout(PG_FUNCTION_ARGS);
7474
extern Datum bit(PG_FUNCTION_ARGS);
75+
extern Datum varbit_transform(PG_FUNCTION_ARGS);
7576
extern Datum varbit(PG_FUNCTION_ARGS);
7677
extern Datum biteq(PG_FUNCTION_ARGS);
7778
extern Datum bitne(PG_FUNCTION_ARGS);

0 commit comments

Comments
 (0)