diff options
| author | Mason Sharp | 2010-12-09 16:42:58 +0000 |
|---|---|---|
| committer | Pavan Deolasee | 2011-05-19 16:45:24 +0000 |
| commit | 44f83040767b619bd9e4bf4088c6eb00d994b620 (patch) | |
| tree | e615984b9d3fb5fdfa91b0e956a3af77ca9088e0 /src | |
| parent | 4d5d43f2fe273c4c7b1a45176267085b39a0de61 (diff) | |
This fixes a couple of issues noticed after the last commit,
which added checking for expressions in the SELECT clause.
Fxied a bug with expression checking because of context
recursion depth.
Also, we now allow built-in volatile expressions in statements
to be pushed down. Without this, having NOW() in DML was
causing a problem in DBT-1.
We should go back and examine this more carefully to make
sure the built-in ones are all safe.
Also, we still make the false assumption that immutable
functions will not write to the database. This could be addressed
by either a more thorough analysis of functions at
creation time or additional tags at creation time (preferably
in standard PostgreSQL). Ideally such functionality could be
committed back to standard PostgreSQL.
Diffstat (limited to 'src')
| -rw-r--r-- | src/backend/pgxc/plan/planner.c | 76 |
1 files changed, 71 insertions, 5 deletions
diff --git a/src/backend/pgxc/plan/planner.c b/src/backend/pgxc/plan/planner.c index 83ee829c50..02b863a4c1 100644 --- a/src/backend/pgxc/plan/planner.c +++ b/src/backend/pgxc/plan/planner.c @@ -150,6 +150,8 @@ static bool examine_conditions_walker(Node *expr_node, XCWalkerContext *context) static int handle_limit_offset(RemoteQuery *query_step, Query *query, PlannedStmt *plan_stmt); static void InitXCWalkerContext(XCWalkerContext *context); static void validate_part_col_updatable(const Query *query); +static bool is_pgxc_safe_func(Oid funcid); + /* * Find position of specified substring in the string @@ -850,7 +852,6 @@ examine_conditions_walker(Node *expr_node, XCWalkerContext *context) return false; } } - else if (IsA(expr_node, BoolExpr)) { BoolExpr *boolexpr = (BoolExpr *) expr_node; @@ -1082,7 +1083,7 @@ examine_conditions_walker(Node *expr_node, XCWalkerContext *context) /* See if the function is immutable, otherwise give up */ if (IsA(expr_node, FuncExpr)) { - if (!is_immutable_func(((FuncExpr*) expr_node)->funcid)) + if (!is_pgxc_safe_func(((FuncExpr*) expr_node)->funcid)) return true; } @@ -1273,10 +1274,16 @@ get_plan_nodes_walker(Node *query_node, XCWalkerContext *context) */ if (query->targetList) { + ExecNodes *save_nodes = context->query_step->exec_nodes; + int save_varno = context->varno; + foreach(item, query->targetList) { TargetEntry *target = (TargetEntry *) lfirst(item); + context->query_step->exec_nodes = NULL; + context->varno = 0; + if (examine_conditions_walker((Node*)target->expr, context)) return true; @@ -1290,11 +1297,11 @@ get_plan_nodes_walker(Node *query_node, XCWalkerContext *context) return true; pfree(context->query_step->exec_nodes); - context->query_step->exec_nodes = NULL; } } + context->query_step->exec_nodes = save_nodes; + context->varno = save_varno; } - /* Look for JOIN syntax joins */ foreach(item, query->jointree->fromlist) { @@ -2554,7 +2561,7 @@ pgxc_planner(Query *query, int cursorOptions, ParamListInfo boundParams) { ereport(ERROR, (errcode(ERRCODE_STATEMENT_TOO_COMPLEX), - (errmsg("Complex and correlated UPDATE and DELETE not yet supported")))); + (errmsg("UPDATE and DELETE that are correlated or use non-immutable functions not yet supported")))); } /* @@ -2940,3 +2947,62 @@ validate_part_col_updatable(const Query *query) } } } + +/* + * See if it is safe to use this function in single step. + * + * Based on is_immutable_func from postgresql_fdw.c + * We add an exeption for base postgresql functions, to + * allow now() and others to still execute as part of single step + * queries. + * + * PGXCTODO - we currently make the false assumption that immutable + * functions will not write to the database. This could be addressed + * by either a more thorough analysis of functions at + * creation time or additional tags at creation time (preferably + * in standard PostgreSQL). Ideally such functionality could be + * committed back to standard PostgreSQL. + */ +bool +is_pgxc_safe_func(Oid funcid) +{ + HeapTuple tp; + bool isnull; + Datum datum; + bool ret_val = false; + + tp = SearchSysCache(PROCOID, ObjectIdGetDatum(funcid), 0, 0, 0); + if (!HeapTupleIsValid(tp)) + elog(ERROR, "cache lookup failed for function %u", funcid); + +#ifdef DEBUG_FDW + /* print function name and its immutability */ + { + char *proname; + datum = SysCacheGetAttr(PROCOID, tp, Anum_pg_proc_proname, &isnull); + proname = pstrdup(DatumGetName(datum)->data); + elog(DEBUG1, "func %s(%u) is%s immutable", proname, funcid, + (DatumGetChar(datum) == PROVOLATILE_IMMUTABLE) ? "" : " not"); + pfree(proname); + } +#endif + + datum = SysCacheGetAttr(PROCOID, tp, Anum_pg_proc_provolatile, &isnull); + + if (DatumGetChar(datum) == PROVOLATILE_IMMUTABLE) + ret_val = true; + /* + * Also allow stable and volatile ones that are in the PG_CATALOG_NAMESPACE + * this allows now() and others that do not update the database + * PGXCTODO - examine default functions carefully for those that may + * write to the database. + */ + else + { + datum = SysCacheGetAttr(PROCOID, tp, Anum_pg_proc_pronamespace, &isnull); + if (DatumGetObjectId(datum) == PG_CATALOG_NAMESPACE) + ret_val = true; + } + ReleaseSysCache(tp); + return ret_val; +} |
