Handle remote parameters correctly by sending then down to the remote nodes in
authorPavan Deolasee <[email protected]>
Thu, 29 Sep 2016 05:27:19 +0000 (10:57 +0530)
committerPavan Deolasee <[email protected]>
Thu, 29 Sep 2016 05:28:14 +0000 (10:58 +0530)
the correct order and correction position

Per report and test-case by Daniel Bunford-Jones

src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/pgxc/pool/execRemote.c
src/include/pgxc/execRemote.h
src/test/regress/expected/plpgsql_1.out
src/test/regress/sql/plpgsql.sql

index 1ac38343e3db1d60f3e58c6eff70bfb6f3a8eb1e..e15d84e387a6044b0fc727b0fa9143cf16f3ce27 100644 (file)
@@ -1466,6 +1466,9 @@ _outRemoteStmt(StringInfo str, const RemoteStmt *node)
                appendStringInfo(str, " :paramid");
                appendStringInfo(str, " %d", rparam->paramid);
 
+               appendStringInfo(str, " :paramused");
+               appendStringInfo(str, " %d", rparam->paramused);
+
                appendStringInfo(str, " :paramtype");
                if (portable_output)
                {
index 98ac7bd44e1c1f18428539e2ccd25122aebd0e58..7503b02c38cfb3ea7e7b45f6411c41bd0516fa03 100644 (file)
@@ -3209,6 +3209,10 @@ _readRemoteStmt(void)
                        token = pg_strtok(&length);
                        rparam->paramid = atoi(token);
 
+                       token = pg_strtok(&length); /* skip  :paramused */
+                       token = pg_strtok(&length);
+                       rparam->paramused = atoi(token);
+
                        token = pg_strtok(&length); /* skip  :paramtype */
                        if (portable_input)
                        {
index c756c1ae6458150ae04907b1ed3f50c8a67de588..7aa2ba96c3377b73d21e862af3ba8ed55757b40a 100644 (file)
@@ -5383,16 +5383,32 @@ ExecInitRemoteSubplan(RemoteSubplan *node, EState *estate, int eflags)
                                         */
                                        if (!OidIsValid(param->ptype) && ext_params->paramFetch)
                                                (*ext_params->paramFetch) (ext_params, i + 1);
+
                                        /*
-                                        * If parameter type is still not defined assume it is
-                                        * unused
+                                        * If the parameter type is still not defined, assume that
+                                        * it is unused. But we put a default INT4OID type for such
+                                        * unused parameters to keep the parameter pushdown code
+                                        * happy.
+                                        *
+                                        * These unused parameters are never accessed during
+                                        * execution and we will just a null value for these
+                                        * "dummy" parameters. But including them here ensures that
+                                        * we send down the parameters in the correct order and at
+                                        * the position that the datanode needs
                                         */
-                                       if (!OidIsValid(param->ptype))
-                                               continue;
+                                       if (OidIsValid(param->ptype))
+                                       {
+                                               rstmt.remoteparams[paramno].paramused = 1;
+                                               rstmt.remoteparams[paramno].paramtype = param->ptype;
+                                       }
+                                       else
+                                       {
+                                               rstmt.remoteparams[paramno].paramused = 0;
+                                               rstmt.remoteparams[paramno].paramtype = INT4OID;
+                                       }
 
                                        rstmt.remoteparams[paramno].paramkind = PARAM_EXTERN;
                                        rstmt.remoteparams[paramno].paramid = i + 1;
-                                       rstmt.remoteparams[paramno].paramtype = param->ptype;
                                        paramno++;
                                }
                                /* store actual number of parameters */
@@ -5411,6 +5427,7 @@ ExecInitRemoteSubplan(RemoteSubplan *node, EState *estate, int eflags)
                                        rstmt.remoteparams[paramno].paramkind = PARAM_EXEC;
                                        rstmt.remoteparams[paramno].paramid = i;
                                        rstmt.remoteparams[paramno].paramtype = prmdata->ptype;
+                                       rstmt.remoteparams[paramno].paramused = 1;
                                        /* Will scan plan tree to find out data type of the param */
                                        if (prmdata->ptype == InvalidOid)
                                                defineParams = bms_add_member(defineParams, i);
@@ -5624,10 +5641,14 @@ ExecFinishInitRemoteSubplan(RemoteSubplanState *node)
 
 
 static void
-append_param_data(StringInfo buf, Oid ptype, Datum value, bool isnull)
+append_param_data(StringInfo buf, Oid ptype, int pused, Datum value, bool isnull)
 {
        uint32 n32;
 
+       /* Assume unused parameters to have null values */
+       if (!pused)
+               ptype = INT4OID;
+
        if (isnull)
        {
                n32 = htonl(-1);
@@ -5693,11 +5714,12 @@ static int encode_parameters(int nparams, RemoteParam *remoteparams,
        {
                RemoteParam *rparam = &remoteparams[i];
                int ptype = rparam->paramtype;
+               int pused = rparam->paramused;
                if (rparam->paramkind == PARAM_EXTERN)
                {
                        ParamExternData *param;
                        param = &(estate->es_param_list_info->params[rparam->paramid - 1]);
-                       append_param_data(&buf, ptype, param->value, param->isnull);
+                       append_param_data(&buf, ptype, pused, param->value, param->isnull);
                }
                else
                {
@@ -5713,7 +5735,7 @@ static int encode_parameters(int nparams, RemoteParam *remoteparams,
                        }
                        if (!param->done)
                                param->isnull = true;
-                       append_param_data(&buf, ptype, param->value, param->isnull);
+                       append_param_data(&buf, ptype, pused, param->value, param->isnull);
 
                }
        }
index 4cbcbec4ad7057d61e1aaaba7a0f509298006def..eda1ac4e99b1662f5a0e0bb52b976e9db539c646 100644 (file)
@@ -160,6 +160,7 @@ typedef struct RemoteParam
        ParamKind       paramkind;              /* kind of parameter */
        int                     paramid;                /* numeric ID for parameter */
        Oid                     paramtype;              /* pg_type OID of parameter's datatype */
+       int                     paramused;              /* is param used */
 } RemoteParam;
 
 
index 55a288a04893ff6e961154073bccf9de182bdca0..379cd8b318c1ff53c1c452757519d0f6a1ab8010 100644 (file)
@@ -5599,3 +5599,26 @@ end;
 $$;
 ERROR:  Internal subtransactions not supported in Postgres-XL
 CONTEXT:  PL/pgSQL function inline_code_block line 2 during statement block entry
+-- Check parameter handling
+BEGIN;
+DROP TABLE IF EXISTS testcase_13;
+NOTICE:  table "testcase_13" does not exist, skipping
+CREATE TABLE testcase_13 (patient_id integer);
+INSERT INTO testcase_13 VALUES (1);
+DO $$
+DECLARE
+ r RECORD;
+BEGIN
+FOR r IN SELECT * FROM testcase_13 LOOP
+    RAISE INFO 'r.patient_id=%', r.patient_id;
+    IF   (SELECT EXISTS (
+            SELECT FROM testcase_13 WHERE patient_id = r.patient_id
+        ))
+       THEN
+          RAISE INFO 'condition true';
+    END IF;
+  END LOOP;
+END $$;
+INFO:  r.patient_id=1
+INFO:  condition true
+ROLLBACK;
index f41ee0e4da74584bf89c07db41779e851b5f6ace..54a1c42be4d4dca0ade5e7be24dab7c3e05b89bb 100644 (file)
@@ -4477,3 +4477,25 @@ exception when others then
   null; -- do nothing
 end;
 $$;
+
+
+-- Check parameter handling
+BEGIN;
+DROP TABLE IF EXISTS testcase_13;
+CREATE TABLE testcase_13 (patient_id integer);
+INSERT INTO testcase_13 VALUES (1);
+DO $$
+DECLARE
+ r RECORD;
+BEGIN
+FOR r IN SELECT * FROM testcase_13 LOOP
+    RAISE INFO 'r.patient_id=%', r.patient_id;
+    IF   (SELECT EXISTS (
+            SELECT FROM testcase_13 WHERE patient_id = r.patient_id
+        ))
+       THEN
+          RAISE INFO 'condition true';
+    END IF;
+  END LOOP;
+END $$;
+ROLLBACK;