diff --git a/contrib/dblink/dblink.c b/contrib/dblink/dblink.c
index 7a9ddcd..c5b35be 100644
--- a/contrib/dblink/dblink.c
+++ b/contrib/dblink/dblink.c
@@ -728,6 +728,7 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
char *conname = NULL;
remoteConn *rconn = NULL;
bool fail = true; /* default to backward compatible */
+ ReturnSetInfo *rsi; /* set up for qual-pushing */
/* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT();
@@ -802,6 +803,17 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
elog(ERROR, "wrong number of arguments");
}
+ if (sql && rsi->qual) /* add qualifiers if available. */
+ {
+ char *quals = rsinfo_get_qual_str(rsi);
+ char *qualifiedQuery = palloc(strlen(sql) + strlen(" WHERE ") +
+ strlen(quals) + 1);
+
+ sprintf(qualifiedQuery, "%s WHERE %s", sql, quals);
+
+ sql = qualifiedQuery;
+ }
+
if (!conn)
DBLINK_CONN_NOT_AVAIL;
diff --git a/doc/src/sgml/plperl.sgml b/doc/src/sgml/plperl.sgml
index 2f2e53b..f0c6587 100644
--- a/doc/src/sgml/plperl.sgml
+++ b/doc/src/sgml/plperl.sgml
@@ -873,6 +873,41 @@ CREATE TRIGGER test_valid_id_trig
+
+ PL/Perl Qualifiers
+
+
+ PL/Perl exposes qualifiers in the current query. In a function,
+ the hash reference $_QUAL contains information
+ about the currently executing query. $_QUAL is
+ a global variable, which gets a separate local value for each query.
+ The fields (currently just one) of $_QUAL are:
+
+
+
+ $_TD->{qual_string}
+
+
+ A string containing all the qualifiers for the current query.
+
+
+
+
+
+
+ Here is an example of a function using $_QUAL.
+
+CREATE OR REPLACE FUNCTION show_quals()
+RETURNS TEXT
+LANGUAGE plperl
+AS $$
+return $_QUAL->{qual_string};
+$$;
+
+
+
+
+
Limitations and Missing Features
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index 4c4742d..d6f7ef8 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -45,6 +45,7 @@
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
+#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
#include "pgstat.h"
#include "utils/acl.h"
@@ -1693,6 +1694,27 @@ ExecMakeFunctionResultNoSets(FuncExprState *fcache,
return result;
}
+/*
+ *
+ * rsinfo_get_qual_str
+ *
+ * Get either an empty string or a batch of qualifiers.
+ *
+ */
+char *
+rsinfo_get_qual_str(ReturnSetInfo *rsinfo)
+{
+ Node *qual;
+ List *context;
+
+ if (rsinfo->qual == NIL)
+ return pstrdup("");
+
+ qual = (Node *) make_ands_explicit(rsinfo->qual);
+ context = deparse_context_for_plan(NULL, NULL, rsinfo->rtable, NULL);
+
+ return deparse_expression(qual, context, false, false);
+}
/*
* ExecMakeTableFunctionResult
@@ -1703,6 +1725,7 @@ ExecMakeFunctionResultNoSets(FuncExprState *fcache,
Tuplestorestate *
ExecMakeTableFunctionResult(ExprState *funcexpr,
ExprContext *econtext,
+ List *qual, List *rtable,
TupleDesc expectedDesc,
bool randomAccess)
{
@@ -1736,6 +1759,8 @@ ExecMakeTableFunctionResult(ExprState *funcexpr,
InitFunctionCallInfoData(fcinfo, NULL, 0, NULL, (Node *) &rsinfo);
rsinfo.type = T_ReturnSetInfo;
rsinfo.econtext = econtext;
+ rsinfo.qual = qual;
+ rsinfo.rtable = rtable;
rsinfo.expectedDesc = expectedDesc;
rsinfo.allowedModes = (int) (SFRM_ValuePerCall | SFRM_Materialize);
if (randomAccess)
diff --git a/src/backend/executor/nodeFunctionscan.c b/src/backend/executor/nodeFunctionscan.c
index 1e5086f..c4c0ef5 100644
--- a/src/backend/executor/nodeFunctionscan.c
+++ b/src/backend/executor/nodeFunctionscan.c
@@ -64,6 +64,8 @@ FunctionNext(FunctionScanState *node)
node->tuplestorestate = tuplestorestate =
ExecMakeTableFunctionResult(node->funcexpr,
node->ss.ps.ps_ExprContext,
+ node->ss.ps.plan->qual,
+ estate->es_range_table,
node->tupdesc,
node->eflags & EXEC_FLAG_BACKWARD);
}
diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h
index 1078a78..8259795 100644
--- a/src/include/executor/executor.h
+++ b/src/include/executor/executor.h
@@ -178,6 +178,7 @@ extern Datum GetAttributeByName(HeapTupleHeader tuple, const char *attname,
bool *isNull);
extern Tuplestorestate *ExecMakeTableFunctionResult(ExprState *funcexpr,
ExprContext *econtext,
+ List *qual, List *rtable,
TupleDesc expectedDesc,
bool randomAccess);
extern Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econtext,
@@ -189,6 +190,7 @@ extern int ExecTargetListLength(List *targetlist);
extern int ExecCleanTargetListLength(List *targetlist);
extern TupleTableSlot *ExecProject(ProjectionInfo *projInfo,
ExprDoneCond *isDone);
+extern char *rsinfo_get_qual_str(ReturnSetInfo *rsinfo);
/*
* prototypes from functions in execScan.c
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index a4065d7..258dcb3 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -173,6 +173,8 @@ typedef struct ReturnSetInfo
ExprContext *econtext; /* context function is being called in */
TupleDesc expectedDesc; /* tuple descriptor expected by caller */
int allowedModes; /* bitmask: return modes caller can handle */
+ List *qual; /* any quals to be applied to the result */
+ List *rtable;
/* result status from function (but pre-initialized by caller): */
SetFunctionReturnMode returnMode; /* actual return mode */
ExprDoneCond isDone; /* status for ValuePerCall mode */
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 9dc184e..db2ee38 100644
--- a/src/pl/plperl/plperl.c
+++ b/src/pl/plperl/plperl.c
@@ -956,7 +956,7 @@ plperl_create_sub(char *proname, char *s, bool trusted)
ENTER;
SAVETMPS;
PUSHMARK(SP);
- XPUSHs(sv_2mortal(newSVstring("our $_TD; local $_TD=$_[0]; shift;")));
+ XPUSHs(sv_2mortal(newSVstring("our $_TD; local $_TD=$_[0]; shift; our $_QUAL; local $_QUAL=$_[0]; shift;")));
XPUSHs(sv_2mortal(newSVstring(s)));
PUTBACK;
@@ -1064,6 +1064,19 @@ plperl_call_perl_func(plperl_proc_desc *desc, FunctionCallInfo fcinfo)
XPUSHs(&PL_sv_undef); /* no trigger data */
+ /* set a qualifier string, if available */
+ if (fcinfo->resultinfo && ((ReturnSetInfo *)fcinfo->resultinfo)->qual)
+ {
+ ReturnSetInfo *rsi = (ReturnSetInfo *)fcinfo->resultinfo;
+ HV *hv = newHV();
+
+ hv_store_string(hv, "qual_string", newSVstring(rsinfo_get_qual_str(rsi)));
+
+ XPUSHs(newRV_noinc((SV *)hv));
+ }
+ else
+ XPUSHs(&PL_sv_undef); /* no qualifier string */
+
for (i = 0; i < desc->nargs; i++)
{
if (fcinfo->argnull[i])