Fix FetchRefcursors issues 1. Fix crash if error occurs when fetching noninitial...
authorAdrian Grucza <adrian.grucza@iress.com>
Wed, 30 Nov 2022 11:09:45 +0000 (20:09 +0900)
committerHiroshi Inoue <h-inoue@dream.email.ne.jp>
Wed, 30 Nov 2022 11:09:46 +0000 (20:09 +0900)
statement.c
test/expected/fetch-refcursors.out
test/src/fetch-refcursors-test.c

index e7f816fbd5c49af3d80ae9ef55c5393f0c070fe4..f45cd798d4225b626649aecbd1e28137bf35a510 100644 (file)
@@ -2304,6 +2304,7 @@ MYLOG(DETAIL_LOG_LEVEL, "!!SC_fetch return =%d\n", ret);
        {
            char            fetch[128];
            QResultClass    *last = NULL, *res;
+           BOOL            refcursor_found = FALSE;
 
            /* Iterate the columns in the result to look for refcursors */
            numcols = QR_NumResultCols(rhold.first);
@@ -2318,7 +2319,12 @@ MYLOG(DETAIL_LOG_LEVEL, "!!SC_fetch return =%d\n", ret);
                        break;
                    }
 
+                   refcursor_found = TRUE;
                    STR_TO_NAME(self->cursor_name, QR_get_value_backend_text(rhold.first, 0, i));
+                   /* Skip NULL refcursors (allows procedure to return a variable number of results) */
+                   if (!SC_cursor_is_valid(self))
+                       continue;
+
                    SC_set_fetchcursor(self);
                    qi.result_in = NULL;
                    qi.cursor = SC_cursor_name(self);
@@ -2339,19 +2345,23 @@ MYLOG(DETAIL_LOG_LEVEL, "!!SC_fetch return =%d\n", ret);
                            QR_concat(last, res);
                            self->multi_statement = TRUE;
                        }
+                       last = res;
                        if (!QR_command_maybe_successful(res))
                        {
                            SC_set_errorinfo(self, res, 0);
-                           QR_Destructor(rhold.first);
                            break;
                        }
-
-                       last = res;
                    }
                }
            }
-           if (last)
-               QR_Destructor(rhold.first);
+           if (refcursor_found)
+           {
+               /* Discard original result */
+               if (NULL == last)
+                   SC_set_Result(self, QR_Constructor());  /* return empty result */
+               else
+                   QR_Destructor(rhold.first);
+           }
        }
    }
 cleanup:
index fff9ee14a1cedb3436b939c5c067bb559f91744c..bfe6f85e6019f80e5550bf825eab3028c29b4e4e 100644 (file)
@@ -2,19 +2,47 @@ Creating procedure 'refproc'
 connected
 disconnecting
 
--- TEST using FetchRefcursors=0 and SQL_ATTR_AUTOCOMMIT=1
+-- TEST using FetchRefcursors=0, autocommit=1, numresults=2
 connected
 Output param num_cursor is 2
 --1 Result set:
-2  ref1    ref2
+2  <unnamed portal 1>  <unnamed portal 2>
 disconnecting
 
--- TEST using FetchRefcursors=1 and SQL_ATTR_AUTOCOMMIT=1
+-- TEST using FetchRefcursors=1, autocommit=1, numresults=2
 connected
 SQLExecute failed
 HY000=Query must be executed in a transaction when FetchRefcursors setting is enabled.
 
--- TEST using FetchRefcursors=1 and SQL_ATTR_AUTOCOMMIT=0
+-- TEST using FetchRefcursors=1, autocommit=0, numresults=0
+connected
+Output param num_cursor is 0
+--1 Result set:
+disconnecting
+
+-- TEST using FetchRefcursors=1, autocommit=0, numresults=1
+connected
+Output param num_cursor is 1
+--1 Result set:
+1  foo
+2  bar
+3  foobar
+disconnecting
+
+-- TEST using FetchRefcursors=1, autocommit=0, numresults=2
+connected
+Output param num_cursor is 2
+--1 Result set:
+1  foo
+2  bar
+3  foobar
+--2 Result set:
+foobar 3
+bar    2
+foo    1
+disconnecting
+
+-- TEST using FetchRefcursors=1, autocommit=0, numresults=3
 connected
 Output param num_cursor is 2
 --1 Result set:
index ed9a47a878ab0381566073ed7c883f4e52fd422a..01e58e4f5f11361415c266535d8bd2e9c5856441 100644 (file)
@@ -33,13 +33,19 @@ static void setup_procedure()
    CHECK_CONN_RESULT(rc, "failed to allocate stmt handle", conn);
 
    rc = SQLExecDirect(hstmt, "create or replace procedure refproc"
-           "(inout num_cursor integer, inout ref1 refcursor default 'ref1', inout ref2 refcursor default 'ref2') as "
+           "(inout num_cursor integer, inout ref1 refcursor default null, inout ref2 refcursor default null) as "
            "$procedure$ \n"
            "DECLARE \n"
            "BEGIN \n"
-           "num_cursor := 2; \n"
-           "OPEN ref1 FOR SELECT id, t FROM testtab1 ORDER BY id ASC; \n"
-           "OPEN ref2 FOR SELECT t, id FROM testtab1 ORDER BY id DESC; \n"
+           "IF num_cursor > 0 THEN \n"
+           "    OPEN ref1 FOR SELECT id, t FROM testtab1 ORDER BY id ASC; \n"
+           "END IF; \n"
+           "IF num_cursor > 1 THEN \n"
+           "    OPEN ref2 FOR SELECT t, id FROM testtab1 ORDER BY id DESC; \n"
+           "END IF; \n"
+           "IF num_cursor > 2 THEN \n"
+           "    num_cursor := 2; \n"
+           "END IF; \n"
            "END; \n"
            "$procedure$ \n"
            "LANGUAGE plpgsql\n"
@@ -52,13 +58,13 @@ static void setup_procedure()
    test_disconnect();
 }
 
-static void refcursor_test(char* connectparams, SQLUINTEGER autocommit)
+static void refcursor_test(char* connectparams, SQLUINTEGER autocommit, int numresults)
 {
    SQLRETURN   rc;
    HSTMT       hstmt = SQL_NULL_HSTMT;
-   int         num_cursor = 0;
+   int         num_cursor = numresults;
 
-   printf("\n-- TEST using %s and SQL_ATTR_AUTOCOMMIT=%u\n", connectparams, autocommit);
+   printf("\n-- TEST using %s, autocommit=%u, numresults=%d\n", connectparams, autocommit, numresults);
 
    test_connect_ext(connectparams);
 
@@ -102,9 +108,12 @@ int main(int argc, char **argv)
 {
    setup_procedure();
 
-   refcursor_test("FetchRefcursors=0", SQL_AUTOCOMMIT_ON);
-   refcursor_test("FetchRefcursors=1", SQL_AUTOCOMMIT_ON);
-   refcursor_test("FetchRefcursors=1", SQL_AUTOCOMMIT_OFF);
+   refcursor_test("FetchRefcursors=0", SQL_AUTOCOMMIT_ON, 2);
+   refcursor_test("FetchRefcursors=1", SQL_AUTOCOMMIT_ON, 2);
+   refcursor_test("FetchRefcursors=1", SQL_AUTOCOMMIT_OFF, 0);
+   refcursor_test("FetchRefcursors=1", SQL_AUTOCOMMIT_OFF, 1);
+   refcursor_test("FetchRefcursors=1", SQL_AUTOCOMMIT_OFF, 2);
+   refcursor_test("FetchRefcursors=1", SQL_AUTOCOMMIT_OFF, 3);
 
    return 0;
 }