Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 4d1e2ae

Browse filesBrowse 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
Copy full SHA for 4d1e2ae

File tree

Expand file treeCollapse file tree

3 files changed

+130
-2
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+130
-2
lines changed

‎src/backend/commands/copy.c

Copy file name to clipboardExpand all lines: src/backend/commands/copy.c
+13-2Lines changed: 13 additions & 2 deletions
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

Copy file name to clipboardExpand all lines: src/backend/optimizer/util/clauses.c
+116Lines changed: 116 additions & 0 deletions
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

Copy file name to clipboardExpand all lines: src/include/optimizer/clauses.h
+1Lines changed: 1 addition & 0 deletions
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 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.