Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 4d1e2ae

Browse files
Speed up COPY into tables with DEFAULT nextval()
Previously the presence of a nextval() prevented the use of batch-mode COPY. This patch introduces a special case just for nextval() functions. In future we will introduce a general case solution for labelling volatile functions as safe for use.
1 parent 74a72ec commit 4d1e2ae

File tree

3 files changed

+130
-2
lines changed

3 files changed

+130
-2
lines changed

src/backend/commands/copy.c

+13-2
Original file line numberDiff line numberDiff line change
@@ -2519,9 +2519,20 @@ BeginCopyFrom(Relation rel,
25192519
defmap[num_defaults] = attnum - 1;
25202520
num_defaults++;
25212521

2522-
/* Check to see if we have any volatile expressions */
2522+
/*
2523+
* If a default expression looks at the table being loaded, then
2524+
* it could give the wrong answer when using multi-insert. Since
2525+
* database access can be dynamic this is hard to test for
2526+
* exactly, so we use the much wider test of whether the
2527+
* default expression is volatile. We allow for the special case
2528+
* of when the default expression is the nextval() of a sequence
2529+
* which in this specific case is known to be safe for use with
2530+
* the multi-insert optimisation. Hence we use this special case
2531+
* function checker rather than the standard check for
2532+
* contain_volatile_functions().
2533+
*/
25232534
if (!volatile_defexprs)
2524-
volatile_defexprs = contain_volatile_functions((Node *) defexpr);
2535+
volatile_defexprs = contain_volatile_functions_not_nextval((Node *)defexpr);
25252536
}
25262537
}
25272538
}

src/backend/optimizer/util/clauses.c

+116
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "utils/acl.h"
4646
#include "utils/builtins.h"
4747
#include "utils/datum.h"
48+
#include "utils/fmgroids.h"
4849
#include "utils/lsyscache.h"
4950
#include "utils/memutils.h"
5051
#include "utils/syscache.h"
@@ -94,6 +95,7 @@ static bool expression_returns_set_rows_walker(Node *node, double *count);
9495
static bool contain_subplans_walker(Node *node, void *context);
9596
static bool contain_mutable_functions_walker(Node *node, void *context);
9697
static bool contain_volatile_functions_walker(Node *node, void *context);
98+
static bool contain_volatile_functions_not_nextval_walker(Node *node, void *context);
9799
static bool contain_nonstrict_functions_walker(Node *node, void *context);
98100
static bool contain_leaky_functions_walker(Node *node, void *context);
99101
static Relids find_nonnullable_rels_walker(Node *node, bool top_level);
@@ -971,6 +973,19 @@ contain_volatile_functions(Node *clause)
971973
return contain_volatile_functions_walker(clause, NULL);
972974
}
973975

976+
bool
977+
contain_volatile_functions_not_nextval(Node *clause)
978+
{
979+
return contain_volatile_functions_not_nextval_walker(clause, NULL);
980+
}
981+
982+
/*
983+
* General purpose code for checking expression volatility.
984+
*
985+
* Special purpose code for use in COPY is almost identical to this,
986+
* so any changes here may also be needed in other contain_volatile...
987+
* functions.
988+
*/
974989
static bool
975990
contain_volatile_functions_walker(Node *node, void *context)
976991
{
@@ -1072,6 +1087,107 @@ contain_volatile_functions_walker(Node *node, void *context)
10721087
context);
10731088
}
10741089

1090+
/*
1091+
* Special purpose version of contain_volatile_functions for use in COPY
1092+
*/
1093+
static bool
1094+
contain_volatile_functions_not_nextval_walker(Node *node, void *context)
1095+
{
1096+
if (node == NULL)
1097+
return false;
1098+
if (IsA(node, FuncExpr))
1099+
{
1100+
FuncExpr *expr = (FuncExpr *) node;
1101+
1102+
/*
1103+
* For this case only, we want to ignore the volatility of the
1104+
* nextval() function, since some callers want this.
1105+
*/
1106+
if (expr->funcid != F_NEXTVAL_OID &&
1107+
func_volatile(expr->funcid) == PROVOLATILE_VOLATILE)
1108+
return true;
1109+
/* else fall through to check args */
1110+
}
1111+
else if (IsA(node, OpExpr))
1112+
{
1113+
OpExpr *expr = (OpExpr *) node;
1114+
1115+
set_opfuncid(expr);
1116+
if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE)
1117+
return true;
1118+
/* else fall through to check args */
1119+
}
1120+
else if (IsA(node, DistinctExpr))
1121+
{
1122+
DistinctExpr *expr = (DistinctExpr *) node;
1123+
1124+
set_opfuncid((OpExpr *) expr); /* rely on struct equivalence */
1125+
if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE)
1126+
return true;
1127+
/* else fall through to check args */
1128+
}
1129+
else if (IsA(node, NullIfExpr))
1130+
{
1131+
NullIfExpr *expr = (NullIfExpr *) node;
1132+
1133+
set_opfuncid((OpExpr *) expr); /* rely on struct equivalence */
1134+
if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE)
1135+
return true;
1136+
/* else fall through to check args */
1137+
}
1138+
else if (IsA(node, ScalarArrayOpExpr))
1139+
{
1140+
ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
1141+
1142+
set_sa_opfuncid(expr);
1143+
if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE)
1144+
return true;
1145+
/* else fall through to check args */
1146+
}
1147+
else if (IsA(node, CoerceViaIO))
1148+
{
1149+
CoerceViaIO *expr = (CoerceViaIO *) node;
1150+
Oid iofunc;
1151+
Oid typioparam;
1152+
bool typisvarlena;
1153+
1154+
/* check the result type's input function */
1155+
getTypeInputInfo(expr->resulttype,
1156+
&iofunc, &typioparam);
1157+
if (func_volatile(iofunc) == PROVOLATILE_VOLATILE)
1158+
return true;
1159+
/* check the input type's output function */
1160+
getTypeOutputInfo(exprType((Node *) expr->arg),
1161+
&iofunc, &typisvarlena);
1162+
if (func_volatile(iofunc) == PROVOLATILE_VOLATILE)
1163+
return true;
1164+
/* else fall through to check args */
1165+
}
1166+
else if (IsA(node, ArrayCoerceExpr))
1167+
{
1168+
ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node;
1169+
1170+
if (OidIsValid(expr->elemfuncid) &&
1171+
func_volatile(expr->elemfuncid) == PROVOLATILE_VOLATILE)
1172+
return true;
1173+
/* else fall through to check args */
1174+
}
1175+
else if (IsA(node, RowCompareExpr))
1176+
{
1177+
/* RowCompare probably can't have volatile ops, but check anyway */
1178+
RowCompareExpr *rcexpr = (RowCompareExpr *) node;
1179+
ListCell *opid;
1180+
1181+
foreach(opid, rcexpr->opnos)
1182+
{
1183+
if (op_volatile(lfirst_oid(opid)) == PROVOLATILE_VOLATILE)
1184+
return true;
1185+
}
1186+
/* else fall through to check args */
1187+
}
1188+
return expression_tree_walker(node, contain_volatile_functions_not_nextval_walker,
1189+
context);
1190+
}
10751191

10761192
/*****************************************************************************
10771193
* Check clauses for nonstrict functions

src/include/optimizer/clauses.h

+1
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ extern bool contain_subplans(Node *clause);
6161

6262
extern bool contain_mutable_functions(Node *clause);
6363
extern bool contain_volatile_functions(Node *clause);
64+
extern bool contain_volatile_functions_not_nextval(Node *clause);
6465
extern bool contain_nonstrict_functions(Node *clause);
6566
extern bool contain_leaky_functions(Node *clause);
6667

0 commit comments

Comments
 (0)