>From 8e10afb89d9f7de3e0e8f9e0cf206b44438284a4 Mon Sep 17 00:00:00 2001
From: Vinayak Pokale <vinpokale@gmail.com>
Date: Mon, 12 Jun 2017 13:03:21 +0900
Subject: [PATCH] WHENEVER statement DO CONTINUE support

---
 doc/src/sgml/ecpg.sgml                             |   12 ++
 src/interfaces/ecpg/preproc/ecpg.trailer           |    6 +
 src/interfaces/ecpg/preproc/output.c               |    3 +
 src/interfaces/ecpg/test/ecpg_schedule             |    1 +
 .../test/expected/preproc-whenever_do_continue.c   |  155 ++++++++++++++++++++
 .../expected/preproc-whenever_do_continue.stderr   |  116 +++++++++++++++
 .../expected/preproc-whenever_do_continue.stdout   |    2 +
 src/interfaces/ecpg/test/preproc/Makefile          |    1 +
 .../ecpg/test/preproc/whenever_do_continue.pgc     |   57 +++++++
 9 files changed, 353 insertions(+), 0 deletions(-)
 create mode 100644 src/interfaces/ecpg/test/expected/preproc-whenever_do_continue.c
 create mode 100644 src/interfaces/ecpg/test/expected/preproc-whenever_do_continue.stderr
 create mode 100644 src/interfaces/ecpg/test/expected/preproc-whenever_do_continue.stdout
 create mode 100644 src/interfaces/ecpg/test/preproc/whenever_do_continue.pgc

diff --git a/doc/src/sgml/ecpg.sgml b/doc/src/sgml/ecpg.sgml
index f13a0e9..3cb4001 100644
--- a/doc/src/sgml/ecpg.sgml
+++ b/doc/src/sgml/ecpg.sgml
@@ -4763,6 +4763,17 @@ EXEC SQL WHENEVER <replaceable>condition</replaceable> <replaceable>action</repl
      </varlistentry>
 
      <varlistentry>
+      <term><literal>DO CONTINUE</literal></term>
+      <listitem>
+       <para>
+        Execute the C statement <literal>continue</literal>.  This should
+        only be used in loops statements.  if executed, will cause the flow 
+        of control to return to the top of the loop.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
       <term><literal>CALL <replaceable>name</replaceable> (<replaceable>args</replaceable>)</literal></term>
       <term><literal>DO <replaceable>name</replaceable> (<replaceable>args</replaceable>)</literal></term>
       <listitem>
@@ -7799,6 +7810,7 @@ WHENEVER { NOT FOUND | SQLERROR | SQLWARNING } <replaceable class="PARAMETER">ac
 <programlisting>
 EXEC SQL WHENEVER NOT FOUND CONTINUE;
 EXEC SQL WHENEVER NOT FOUND DO BREAK;
+EXEC SQL WHENEVER NOT FOUND DO CONTINUE;
 EXEC SQL WHENEVER SQLWARNING SQLPRINT;
 EXEC SQL WHENEVER SQLWARNING DO warn();
 EXEC SQL WHENEVER SQLERROR sqlprint;
diff --git a/src/interfaces/ecpg/preproc/ecpg.trailer b/src/interfaces/ecpg/preproc/ecpg.trailer
index 1c10879..b42bca4 100644
--- a/src/interfaces/ecpg/preproc/ecpg.trailer
+++ b/src/interfaces/ecpg/preproc/ecpg.trailer
@@ -1454,6 +1454,12 @@ action : CONTINUE_P
 			$<action>$.command = NULL;
 			$<action>$.str = mm_strdup("break");
 		}
+		| DO CONTINUE_P
+		{
+			$<action>$.code = W_CONTINUE;
+			$<action>$.command = NULL;
+			$<action>$.str = mm_strdup("continue");
+		}
 		| SQL_CALL name '(' c_args ')'
 		{
 			$<action>$.code = W_DO;
diff --git a/src/interfaces/ecpg/preproc/output.c b/src/interfaces/ecpg/preproc/output.c
index 59d5d30..14d7066 100644
--- a/src/interfaces/ecpg/preproc/output.c
+++ b/src/interfaces/ecpg/preproc/output.c
@@ -51,6 +51,9 @@ print_action(struct when * w)
 		case W_BREAK:
 			fprintf(base_yyout, "break;");
 			break;
+		case W_CONTINUE:
+			fprintf(base_yyout, "continue;");
+			break;
 		default:
 			fprintf(base_yyout, "{/* %d not implemented yet */}", w->code);
 			break;
diff --git a/src/interfaces/ecpg/test/ecpg_schedule b/src/interfaces/ecpg/test/ecpg_schedule
index c3ec125..cff4eeb 100644
--- a/src/interfaces/ecpg/test/ecpg_schedule
+++ b/src/interfaces/ecpg/test/ecpg_schedule
@@ -28,6 +28,7 @@ test: preproc/type
 test: preproc/variable
 test: preproc/outofscope
 test: preproc/whenever
+test: preproc/whenever_do_continue
 test: sql/array
 test: sql/binary
 test: sql/code100
diff --git a/src/interfaces/ecpg/test/expected/preproc-whenever_do_continue.c b/src/interfaces/ecpg/test/expected/preproc-whenever_do_continue.c
new file mode 100644
index 0000000..2c9d16f
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/preproc-whenever_do_continue.c
@@ -0,0 +1,155 @@
+/* Processed by ecpg (regression mode) */
+/* These include files are added by the preprocessor */
+#include <ecpglib.h>
+#include <ecpgerrno.h>
+#include <sqlca.h>
+/* End of automatic include section */
+#define ECPGdebug(X,Y) ECPGdebug((X)+100,(Y))
+
+#line 1 "whenever_do_continue.pgc"
+#include <stdlib.h>
+
+
+#line 1 "regression.h"
+
+
+
+
+
+
+#line 3 "whenever_do_continue.pgc"
+
+
+/* exec sql whenever sqlerror  sqlprint ; */
+#line 5 "whenever_do_continue.pgc"
+
+
+int main(void)
+{
+	/* exec sql begin declare section */
+    
+    
+         
+         
+         
+     
+	
+	 
+    
+#line 15 "whenever_do_continue.pgc"
+ struct { 
+#line 12 "whenever_do_continue.pgc"
+ char ename [ 12 ] ;
+ 
+#line 13 "whenever_do_continue.pgc"
+ float sal ;
+ 
+#line 14 "whenever_do_continue.pgc"
+ float comm ;
+ } emp ;
+ 
+#line 17 "whenever_do_continue.pgc"
+ char msg [ 128 ] ;
+/* exec sql end declare section */
+#line 18 "whenever_do_continue.pgc"
+
+
+    ECPGdebug(1, stderr);
+	
+	strcpy(msg, "connect");
+    { ECPGconnect(__LINE__, 0, "ecpg1_regression" , NULL, NULL , NULL, 0); 
+#line 23 "whenever_do_continue.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 23 "whenever_do_continue.pgc"
+
+	
+	strcpy(msg, "create");
+    { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "create table emp ( ename varchar , sal double precision , comm double precision )", ECPGt_EOIT, ECPGt_EORT);
+#line 26 "whenever_do_continue.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 26 "whenever_do_continue.pgc"
+
+	
+	strcpy(msg, "insert");
+    { ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into emp values ( 'Ram' , 111100 , 21 )", ECPGt_EOIT, ECPGt_EORT);
+#line 29 "whenever_do_continue.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 29 "whenever_do_continue.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into emp values ( 'aryan' , 11110 , null )", ECPGt_EOIT, ECPGt_EORT);
+#line 30 "whenever_do_continue.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 30 "whenever_do_continue.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into emp values ( 'josh' , 10000 , 10 )", ECPGt_EOIT, ECPGt_EORT);
+#line 31 "whenever_do_continue.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 31 "whenever_do_continue.pgc"
+
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "insert into emp values ( 'tom' , 20000 , null )", ECPGt_EOIT, ECPGt_EORT);
+#line 32 "whenever_do_continue.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 32 "whenever_do_continue.pgc"
+
+
+	/* declare c cursor for select ename , sal , comm from emp order by ename asc */
+#line 34 "whenever_do_continue.pgc"
+
+	
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "declare c cursor for select ename , sal , comm from emp order by ename asc", ECPGt_EOIT, ECPGt_EORT);
+#line 36 "whenever_do_continue.pgc"
+
+if (sqlca.sqlcode < 0) sqlprint();}
+#line 36 "whenever_do_continue.pgc"
+
+	
+	/* exec sql whenever not found  break ; */
+#line 38 "whenever_do_continue.pgc"
+
+	
+	/* exec sql whenever sqlerror  continue ; */
+#line 40 "whenever_do_continue.pgc"
+
+	
+	while (1)
+	{
+		{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "fetch c", ECPGt_EOIT, 
+	ECPGt_char,&(emp.ename),(long)12,(long)1,(12)*sizeof(char), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_float,&(emp.sal),(long)1,(long)1,sizeof(float), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, 
+	ECPGt_float,&(emp.comm),(long)1,(long)1,sizeof(float), 
+	ECPGt_NO_INDICATOR, NULL , 0L, 0L, 0L, ECPGt_EORT);
+#line 44 "whenever_do_continue.pgc"
+
+if (sqlca.sqlcode == ECPG_NOT_FOUND) break;
+#line 44 "whenever_do_continue.pgc"
+
+if (sqlca.sqlcode < 0) continue;}
+#line 44 "whenever_do_continue.pgc"
+
+		 printf("%s %7.2f %9.2f\n", emp.ename, emp.sal, emp.comm);
+	}
+	
+	/* exec sql whenever sqlerror  continue ; */
+#line 48 "whenever_do_continue.pgc"
+
+	
+	strcpy(msg, "drop");
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "drop table emp", ECPGt_EOIT, ECPGt_EORT);}
+#line 51 "whenever_do_continue.pgc"
+
+	
+	{ ECPGdo(__LINE__, 0, 1, NULL, 0, ECPGst_normal, "close c", ECPGt_EOIT, ECPGt_EORT);}
+#line 53 "whenever_do_continue.pgc"
+
+	
+	exit(0);
+}
+
diff --git a/src/interfaces/ecpg/test/expected/preproc-whenever_do_continue.stderr b/src/interfaces/ecpg/test/expected/preproc-whenever_do_continue.stderr
new file mode 100644
index 0000000..d0cdec5
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/preproc-whenever_do_continue.stderr
@@ -0,0 +1,116 @@
+[NO_PID]: ECPGdebug: set to 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ECPGconnect: opening database ecpg1_regression on <DEFAULT> port <DEFAULT>  
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 26: query: create table emp ( ename varchar , sal double precision , comm double precision ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 26: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 26: OK: CREATE TABLE
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 29: query: insert into emp values ( 'Ram' , 111100 , 21 ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 29: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 29: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 30: query: insert into emp values ( 'aryan' , 11110 , null ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 30: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 30: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: query: insert into emp values ( 'josh' , 10000 , 10 ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 31: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 31: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 32: query: insert into emp values ( 'tom' , 20000 , null ); with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 32: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 32: OK: INSERT 0 1
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 36: query: declare c cursor for select ename , sal , comm from emp order by ename asc; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 36: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 36: OK: DECLARE CURSOR
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 44: query: fetch c; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 44: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 44: correctly got 1 tuples with 3 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: aryan offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: 11110 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT:  offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlcode -213 on line 44: null value without indicator on line 44
+[NO_PID]: sqlca: code: -213, state: 22002
+[NO_PID]: ecpg_execute on line 44: query: fetch c; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 44: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 44: correctly got 1 tuples with 3 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: josh offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: 10000 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: 10 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 44: query: fetch c; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 44: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 44: correctly got 1 tuples with 3 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: Ram offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: 111100 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: 21 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 44: query: fetch c; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 44: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 44: correctly got 1 tuples with 3 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: tom offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT: 20000 offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_get_data on line 44: RESULT:  offset: -1; array: no
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlcode -213 on line 44: null value without indicator on line 44
+[NO_PID]: sqlca: code: -213, state: 22002
+[NO_PID]: ecpg_execute on line 44: query: fetch c; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 44: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_process_output on line 44: correctly got 0 tuples with 3 fields
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlcode 100 on line 44: no data found on line 44
+[NO_PID]: sqlca: code: 100, state: 02000
+[NO_PID]: ecpg_execute on line 51: query: drop table emp; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 51: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_check_PQresult on line 51: bad response - ERROR:  cannot DROP TABLE "emp" because it is being used by active queries in this session
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlstate 55006 (sqlcode -400): cannot DROP TABLE "emp" because it is being used by active queries in this session on line 51
+[NO_PID]: sqlca: code: -400, state: 55006
+[NO_PID]: ecpg_execute on line 53: query: close c; with 0 parameter(s) on connection ecpg1_regression
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_execute on line 53: using PQexec
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: ecpg_check_PQresult on line 53: bad response - ERROR:  current transaction is aborted, commands ignored until end of transaction block
+[NO_PID]: sqlca: code: 0, state: 00000
+[NO_PID]: raising sqlstate 25P02 (sqlcode -400): current transaction is aborted, commands ignored until end of transaction block on line 53
+[NO_PID]: sqlca: code: -400, state: 25P02
diff --git a/src/interfaces/ecpg/test/expected/preproc-whenever_do_continue.stdout b/src/interfaces/ecpg/test/expected/preproc-whenever_do_continue.stdout
new file mode 100644
index 0000000..75fb6ce
--- /dev/null
+++ b/src/interfaces/ecpg/test/expected/preproc-whenever_do_continue.stdout
@@ -0,0 +1,2 @@
+josh 10000.00     10.00
+Ram 111100.00     21.00
diff --git a/src/interfaces/ecpg/test/preproc/Makefile b/src/interfaces/ecpg/test/preproc/Makefile
index d658a4d..39b1974 100644
--- a/src/interfaces/ecpg/test/preproc/Makefile
+++ b/src/interfaces/ecpg/test/preproc/Makefile
@@ -15,6 +15,7 @@ TESTS = array_of_struct array_of_struct.c \
 	type type.c \
 	variable variable.c \
 	whenever whenever.c \
+	whenever_do_continue whenever_do_continue.c \
 	pointer_to_struct pointer_to_struct.c
 
 all: $(TESTS)
diff --git a/src/interfaces/ecpg/test/preproc/whenever_do_continue.pgc b/src/interfaces/ecpg/test/preproc/whenever_do_continue.pgc
new file mode 100644
index 0000000..f3c8a10
--- /dev/null
+++ b/src/interfaces/ecpg/test/preproc/whenever_do_continue.pgc
@@ -0,0 +1,57 @@
+#include <stdlib.h>
+
+exec sql include ../regression;
+
+exec sql whenever sqlerror sqlprint;
+
+int main(void)
+{
+	exec sql begin declare section;
+    struct
+    {
+        char ename[12];
+        float sal;
+        float comm;
+    } emp;
+	
+	char msg[128];
+    exec sql end declare section;
+
+    ECPGdebug(1, stderr);
+	
+	strcpy(msg, "connect");
+    exec sql connect to REGRESSDB1;
+	
+	strcpy(msg, "create");
+    exec sql  create table emp(ename varchar,sal double precision, comm double precision);
+	
+	strcpy(msg, "insert");
+    exec sql insert into emp values ('Ram',111100,21);
+	exec sql insert into emp values ('aryan',11110,null);
+	exec sql insert into emp values ('josh',10000,10);
+	exec sql insert into emp values ('tom',20000,null);
+
+	exec sql declare c cursor for select ename, sal, comm from emp order by ename asc;
+	
+	exec sql open c;
+	
+	exec sql whenever not found do break;
+	
+	exec sql whenever sqlerror do continue;
+	
+	while (1)
+	{
+		exec sql fetch c into :emp;
+		 printf("%s %7.2f %9.2f\n", emp.ename, emp.sal, emp.comm);
+	}
+	
+	exec sql whenever sqlerror continue;
+	
+	strcpy(msg, "drop");
+	exec sql drop table emp;
+	
+	exec sql close c;
+	
+	exit(0);
+}
+
-- 
1.7.1

