Folks,

Please find enclosed a WIP patch to add the ability for functions to
see the qualifiers of the query in which they're called.  It's not
working just yet, and I'm not sure how best to get it working, but I'd
like to see this as part of 8.4, as SQL/MED is just way too ambitious
given the time frame.

Any tips, hints, pointers, etc. would be much appreciated.

Also, PL/Perl shouldn't be the only language to have this capability.
How might we add similar capabilities to PL/PythonU and PL/Tcl?  To
the rest of the PLs?  Would it make any sense to have it in SQL
language functions?

Cheers,
David.
-- 
David Fetter <[EMAIL PROTECTED]> http://fetter.org/
Phone: +1 415 235 3778  AIM: dfetter666  Yahoo!: dfetter
Skype: davidfetter      XMPP: [EMAIL PROTECTED]

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate
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
   </para>
  </sect1>
 
+ <sect1 id="plperl-qualifiers">
+  <title>PL/Perl Qualifiers</title>
+
+  <para>
+   PL/Perl exposes qualifiers in the current query.  In a function,
+   the hash reference <varname>$_QUAL</varname> contains information
+   about the currently executing query.  <varname>$_QUAL</varname> is
+   a global variable, which gets a separate local value for each query.
+   The fields (currently just one) of <varname>$_QUAL</varname> are:
+
+    <variablelist>
+     <varlistentry>
+      <term><literal>$_TD-&gt;{qual_string}</literal></term>
+      <listitem>
+       <para>
+        A string containing all the qualifiers for the current query.
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
+  </para>
+  <para>
+   Here is an example of a function using <varname>$_QUAL</varname>.
+<programlisting>
+CREATE OR REPLACE FUNCTION show_quals()
+RETURNS TEXT
+LANGUAGE plperl
+AS $$
+return $_QUAL->{qual_string};
+$$;
+</programlisting>
+  </para>
+
+ </sect1>
+
  <sect1 id="plperl-missing">
   <title>Limitations and Missing Features</title>
 
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])
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to