summaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/varchar.c
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2011-06-21 22:15:24 -0400
committerRobert Haas <rhaas@postgresql.org>2011-06-21 22:21:24 -0400
commit8f9fe6edce358f7904e0db119416b4d1080a83aa (patch)
treea0a828d221e85af6c6bf5bc74a6c6c7190352cbf /src/backend/utils/adt/varchar.c
parent771a9f69f70e0b4fa95347df7ab346e5bdbc85f2 (diff)
downloadpostgresql-8f9fe6edce358f7904e0db119416b4d1080a83aa.tar.gz
Add notion of a "transform function" that can simplify function calls.
Initially, we use this only to eliminate calls to the varchar() function in cases where the length is not being reduced and, therefore, the function call is equivalent to a RelabelType operation. The most significant effect of this is that we can avoid a table rewrite when changing a varchar(X) column to a varchar(Y) column, where Y > X. Noah Misch, reviewed by me and Alexey Klyukin
Diffstat (limited to 'src/backend/utils/adt/varchar.c')
-rw-r--r--src/backend/utils/adt/varchar.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c
index 1c0ef921a7..efa483d638 100644
--- a/src/backend/utils/adt/varchar.c
+++ b/src/backend/utils/adt/varchar.c
@@ -18,6 +18,8 @@
#include "access/hash.h"
#include "access/tuptoaster.h"
#include "libpq/pqformat.h"
+#include "nodes/nodeFuncs.h"
+#include "parser/parse_clause.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "mb/pg_wchar.h"
@@ -549,6 +551,38 @@ varcharsend(PG_FUNCTION_ARGS)
/*
+ * 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
+varchar_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) - VARHDRSZ;
+ int32 new_max = new_typmod - VARHDRSZ;
+
+ if (new_max < 0 || (old_max >= 0 && old_max <= new_max))
+ ret = relabel_to_typmod(source, new_typmod);
+ }
+
+ PG_RETURN_POINTER(ret);
+}
+
+/*
* Converts a VARCHAR type to the specified size.
*
* maxlen is the typmod, ie, declared length plus VARHDRSZ bytes.