mirror of
https://github.com/postgres/postgres.git
synced 2025-07-08 11:42:09 +03: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:
@ -2519,9 +2519,20 @@ BeginCopyFrom(Relation rel,
|
|||||||
defmap[num_defaults] = attnum - 1;
|
defmap[num_defaults] = attnum - 1;
|
||||||
num_defaults++;
|
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)
|
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/acl.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/datum.h"
|
#include "utils/datum.h"
|
||||||
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
#include "utils/syscache.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_subplans_walker(Node *node, void *context);
|
||||||
static bool contain_mutable_functions_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_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_nonstrict_functions_walker(Node *node, void *context);
|
||||||
static bool contain_leaky_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);
|
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);
|
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
|
static bool
|
||||||
contain_volatile_functions_walker(Node *node, void *context)
|
contain_volatile_functions_walker(Node *node, void *context)
|
||||||
{
|
{
|
||||||
@ -1072,6 +1087,107 @@ contain_volatile_functions_walker(Node *node, void *context)
|
|||||||
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
|
* 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_mutable_functions(Node *clause);
|
||||||
extern bool contain_volatile_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_nonstrict_functions(Node *clause);
|
||||||
extern bool contain_leaky_functions(Node *clause);
|
extern bool contain_leaky_functions(Node *clause);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user