Skip to content

Commit 3cc0800

Browse files
committed
Add a transform function for numeric typmod coercisions.
This enables ALTER TABLE to skip table and index rebuilds when a column is changed to an unconstrained numeric, or when the scale is unchanged and the precision does not decrease. Noah Misch, with a few stylistic changes and a fix for an OID collision by me.
1 parent af7914c commit 3cc0800

File tree

4 files changed

+53
-2
lines changed

4 files changed

+53
-2
lines changed

src/backend/utils/adt/numeric.c

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
#include "catalog/pg_type.h"
3131
#include "libpq/pqformat.h"
3232
#include "miscadmin.h"
33+
#include "nodes/nodeFuncs.h"
34+
#include "parser/parse_clause.h"
3335
#include "utils/array.h"
3436
#include "utils/builtins.h"
3537
#include "utils/int8.h"
@@ -712,6 +714,52 @@ numeric_send(PG_FUNCTION_ARGS)
712714
}
713715

714716

717+
/*
718+
* numeric_transform() -
719+
*
720+
* Flatten calls to our length coercion function that solely represent
721+
* increases in allowable precision. Scale changes mutate every datum, so
722+
* they are unoptimizable. Some values, e.g. 1E-1001, can only fit into an
723+
* unconstrained numeric, so a change from an unconstrained numeric to any
724+
* constrained numeric is also unoptimizable.
725+
*/
726+
Datum
727+
numeric_transform(PG_FUNCTION_ARGS)
728+
{
729+
FuncExpr *expr = (FuncExpr *) PG_GETARG_POINTER(0);
730+
Node *typmod;
731+
Node *ret = NULL;
732+
733+
if (!IsA(expr, FuncExpr))
734+
PG_RETURN_POINTER(ret);
735+
736+
Assert(list_length(expr->args) == 2);
737+
typmod = lsecond(expr->args);
738+
739+
if (IsA(typmod, Const))
740+
{
741+
Node *source = linitial(expr->args);
742+
int32 old_typmod = exprTypmod(source);
743+
int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
744+
int32 old_scale = (old_typmod - VARHDRSZ) & 0xffff;
745+
int32 new_scale = (new_typmod - VARHDRSZ) & 0xffff;
746+
int32 old_precision = (old_typmod - VARHDRSZ) >> 16 & 0xffff;
747+
int32 new_precision = (new_typmod - VARHDRSZ) >> 16 & 0xffff;
748+
749+
/*
750+
* If new_typmod < VARHDRSZ, the destination is unconstrained; that's
751+
* always OK. If old_typmod >= VARHDRSZ, the source is constained.
752+
* and we're OK if the scale is unchanged and the precison is not
753+
* decreasing. See further nodes in function header comment.
754+
*/
755+
if (new_typmod < VARHDRSZ || (old_typmod >= VARHDRSZ &&
756+
new_scale == old_scale && new_precision >= old_precision))
757+
ret = relabel_to_typmod(source, new_typmod);
758+
}
759+
760+
PG_RETURN_POINTER(ret);
761+
}
762+
715763
/*
716764
* numeric() -
717765
*

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 201201311
56+
#define CATALOG_VERSION_NO 201202071
5757

5858
#endif

src/include/catalog/pg_proc.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2142,8 +2142,10 @@ DATA(insert OID = 2917 ( numerictypmodin PGNSP PGUID 12 1 0 0 0 f f f t f i 1
21422142
DESCR("I/O typmod");
21432143
DATA(insert OID = 2918 ( numerictypmodout PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 2275 "23" _null_ _null_ _null_ _null_ numerictypmodout _null_ _null_ _null_ ));
21442144
DESCR("I/O typmod");
2145-
DATA(insert OID = 1703 ( numeric PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 1700 "1700 23" _null_ _null_ _null_ _null_ numeric _null_ _null_ _null_ ));
2145+
DATA(insert OID = 1703 ( numeric PGNSP PGUID 12 1 0 0 3157 f f f t f i 2 0 1700 "1700 23" _null_ _null_ _null_ _null_ numeric _null_ _null_ _null_ ));
21462146
DESCR("adjust numeric to typmod precision/scale");
2147+
DATA(insert OID = 3157 ( numeric_transform PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 2281 "2281" _null_ _null_ _null_ _null_ numeric_transform _null_ _null_ _null_ ));
2148+
DESCR("transform a numeric length coercion");
21472149
DATA(insert OID = 1704 ( numeric_abs PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 1700 "1700" _null_ _null_ _null_ _null_ numeric_abs _null_ _null_ _null_ ));
21482150
DATA(insert OID = 1705 ( abs PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 1700 "1700" _null_ _null_ _null_ _null_ numeric_abs _null_ _null_ _null_ ));
21492151
DESCR("absolute value");

src/include/utils/builtins.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,7 @@ extern Datum numeric_recv(PG_FUNCTION_ARGS);
913913
extern Datum numeric_send(PG_FUNCTION_ARGS);
914914
extern Datum numerictypmodin(PG_FUNCTION_ARGS);
915915
extern Datum numerictypmodout(PG_FUNCTION_ARGS);
916+
extern Datum numeric_transform(PG_FUNCTION_ARGS);
916917
extern Datum numeric (PG_FUNCTION_ARGS);
917918
extern Datum numeric_abs(PG_FUNCTION_ARGS);
918919
extern Datum numeric_uminus(PG_FUNCTION_ARGS);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy