mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-27 08:39:28 +08:00
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.
This commit is contained in:
parent
74a72ec208
commit
4d1e2aeb1a
@ -2519,9 +2519,20 @@ BeginCopyFrom(Relation rel,
|
||||
defmap[num_defaults] = attnum - 1;
|
||||
num_defaults++;
|
||||
|
||||
/* Check to see if we have any volatile expressions */
|
||||
/*
|
||||
* If a default expression looks at the table being loaded, then
|
||||
* it could give the wrong answer when using multi-insert. Since
|
||||
* database access can be dynamic this is hard to test for
|
||||
* exactly, so we use the much wider test of whether the
|
||||
* default expression is volatile. We allow for the special case
|
||||
* of when the default expression is the nextval() of a sequence
|
||||
* which in this specific case is known to be safe for use with
|
||||
* the multi-insert optimisation. Hence we use this special case
|
||||
* function checker rather than the standard check for
|
||||
* contain_volatile_functions().
|
||||
*/
|
||||
if (!volatile_defexprs)
|
||||
volatile_defexprs = contain_volatile_functions((Node *) defexpr);
|
||||
volatile_defexprs = contain_volatile_functions_not_nextval((Node *)defexpr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/datum.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/syscache.h"
|
||||
@ -94,6 +95,7 @@ static bool expression_returns_set_rows_walker(Node *node, double *count);
|
||||
static bool contain_subplans_walker(Node *node, void *context);
|
||||
static bool contain_mutable_functions_walker(Node *node, void *context);
|
||||
static bool contain_volatile_functions_walker(Node *node, void *context);
|
||||
static bool contain_volatile_functions_not_nextval_walker(Node *node, void *context);
|
||||
static bool contain_nonstrict_functions_walker(Node *node, void *context);
|
||||
static bool contain_leaky_functions_walker(Node *node, void *context);
|
||||
static Relids find_nonnullable_rels_walker(Node *node, bool top_level);
|
||||
@ -971,6 +973,19 @@ contain_volatile_functions(Node *clause)
|
||||
return contain_volatile_functions_walker(clause, NULL);
|
||||
}
|
||||
|
||||
bool
|
||||
contain_volatile_functions_not_nextval(Node *clause)
|
||||
{
|
||||
return contain_volatile_functions_not_nextval_walker(clause, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* General purpose code for checking expression volatility.
|
||||
*
|
||||
* Special purpose code for use in COPY is almost identical to this,
|
||||
* so any changes here may also be needed in other contain_volatile...
|
||||
* functions.
|
||||
*/
|
||||
static bool
|
||||
contain_volatile_functions_walker(Node *node, void *context)
|
||||
{
|
||||
@ -1072,6 +1087,107 @@ contain_volatile_functions_walker(Node *node, void *context)
|
||||
context);
|
||||
}
|
||||
|
||||
/*
|
||||
* Special purpose version of contain_volatile_functions for use in COPY
|
||||
*/
|
||||
static bool
|
||||
contain_volatile_functions_not_nextval_walker(Node *node, void *context)
|
||||
{
|
||||
if (node == NULL)
|
||||
return false;
|
||||
if (IsA(node, FuncExpr))
|
||||
{
|
||||
FuncExpr *expr = (FuncExpr *) node;
|
||||
|
||||
/*
|
||||
* For this case only, we want to ignore the volatility of the
|
||||
* nextval() function, since some callers want this.
|
||||
*/
|
||||
if (expr->funcid != F_NEXTVAL_OID &&
|
||||
func_volatile(expr->funcid) == PROVOLATILE_VOLATILE)
|
||||
return true;
|
||||
/* else fall through to check args */
|
||||
}
|
||||
else if (IsA(node, OpExpr))
|
||||
{
|
||||
OpExpr *expr = (OpExpr *) node;
|
||||
|
||||
set_opfuncid(expr);
|
||||
if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE)
|
||||
return true;
|
||||
/* else fall through to check args */
|
||||
}
|
||||
else if (IsA(node, DistinctExpr))
|
||||
{
|
||||
DistinctExpr *expr = (DistinctExpr *) node;
|
||||
|
||||
set_opfuncid((OpExpr *) expr); /* rely on struct equivalence */
|
||||
if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE)
|
||||
return true;
|
||||
/* else fall through to check args */
|
||||
}
|
||||
else if (IsA(node, NullIfExpr))
|
||||
{
|
||||
NullIfExpr *expr = (NullIfExpr *) node;
|
||||
|
||||
set_opfuncid((OpExpr *) expr); /* rely on struct equivalence */
|
||||
if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE)
|
||||
return true;
|
||||
/* else fall through to check args */
|
||||
}
|
||||
else if (IsA(node, ScalarArrayOpExpr))
|
||||
{
|
||||
ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) node;
|
||||
|
||||
set_sa_opfuncid(expr);
|
||||
if (func_volatile(expr->opfuncid) == PROVOLATILE_VOLATILE)
|
||||
return true;
|
||||
/* else fall through to check args */
|
||||
}
|
||||
else if (IsA(node, CoerceViaIO))
|
||||
{
|
||||
CoerceViaIO *expr = (CoerceViaIO *) node;
|
||||
Oid iofunc;
|
||||
Oid typioparam;
|
||||
bool typisvarlena;
|
||||
|
||||
/* check the result type's input function */
|
||||
getTypeInputInfo(expr->resulttype,
|
||||
&iofunc, &typioparam);
|
||||
if (func_volatile(iofunc) == PROVOLATILE_VOLATILE)
|
||||
return true;
|
||||
/* check the input type's output function */
|
||||
getTypeOutputInfo(exprType((Node *) expr->arg),
|
||||
&iofunc, &typisvarlena);
|
||||
if (func_volatile(iofunc) == PROVOLATILE_VOLATILE)
|
||||
return true;
|
||||
/* else fall through to check args */
|
||||
}
|
||||
else if (IsA(node, ArrayCoerceExpr))
|
||||
{
|
||||
ArrayCoerceExpr *expr = (ArrayCoerceExpr *) node;
|
||||
|
||||
if (OidIsValid(expr->elemfuncid) &&
|
||||
func_volatile(expr->elemfuncid) == PROVOLATILE_VOLATILE)
|
||||
return true;
|
||||
/* else fall through to check args */
|
||||
}
|
||||
else if (IsA(node, RowCompareExpr))
|
||||
{
|
||||
/* RowCompare probably can't have volatile ops, but check anyway */
|
||||
RowCompareExpr *rcexpr = (RowCompareExpr *) node;
|
||||
ListCell *opid;
|
||||
|
||||
foreach(opid, rcexpr->opnos)
|
||||
{
|
||||
if (op_volatile(lfirst_oid(opid)) == PROVOLATILE_VOLATILE)
|
||||
return true;
|
||||
}
|
||||
/* else fall through to check args */
|
||||
}
|
||||
return expression_tree_walker(node, contain_volatile_functions_not_nextval_walker,
|
||||
context);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Check clauses for nonstrict functions
|
||||
|
@ -61,6 +61,7 @@ extern bool contain_subplans(Node *clause);
|
||||
|
||||
extern bool contain_mutable_functions(Node *clause);
|
||||
extern bool contain_volatile_functions(Node *clause);
|
||||
extern bool contain_volatile_functions_not_nextval(Node *clause);
|
||||
extern bool contain_nonstrict_functions(Node *clause);
|
||||
extern bool contain_leaky_functions(Node *clause);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user