20140326_error_rollback.patch
text/plain
Filename: 20140326_error_rollback.patch
Type: text/plain
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| connection.c | 10 | 8 |
| connection.h | 22 | 1 |
| dlg_specific.c | 59 | 26 |
| dlg_specific.h | 2 | 0 |
| docs/config.html | 22 | 14 |
| docs/config-opt.html | 11 | 0 |
| execute.c | 2 | 2 |
| src/error-rollback-test.c | 55 | 29 |
| test/expected/error-rollback.out | 67 | 3 |
diff --git a/connection.c b/connection.c
index 8601cb7..9407619 100644
--- a/connection.c
+++ b/connection.c
@@ -288,7 +288,8 @@ CC_conninfo_init(ConnInfo *conninfo, UInt4 option)
conninfo->bytea_as_longvarbinary = -1;
conninfo->use_server_side_prepare = -1;
conninfo->lower_case_identifier = -1;
- conninfo->rollback_on_error = -1;
+ conninfo->rollback_error_value = -1;
+ conninfo->is_rollback_error = -1;
conninfo->force_abbrev_connstr = -1;
conninfo->bde_environment = -1;
conninfo->fake_mss = -1;
@@ -341,7 +342,8 @@ CC_copy_conninfo(ConnInfo *ci, const ConnInfo *sci)
CORR_VALCPY(bytea_as_longvarbinary);
CORR_VALCPY(use_server_side_prepare);
CORR_VALCPY(lower_case_identifier);
- CORR_VALCPY(rollback_on_error);
+ CORR_VALCPY(rollback_error_value);
+ CORR_VALCPY(is_rollback_error);
CORR_VALCPY(force_abbrev_connstr);
CORR_VALCPY(bde_environment);
CORR_VALCPY(fake_mss);
@@ -2733,7 +2735,7 @@ CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UD
BOOL ignore_abort_on_conn = ((flag & IGNORE_ABORT_ON_CONN) != 0),
create_keyset = ((flag & CREATE_KEYSET) != 0),
issue_begin = ((flag & GO_INTO_TRANSACTION) != 0 && !CC_is_in_trans(self)),
- rollback_on_error, query_rollback, end_with_commit;
+ rollback_error_value, query_rollback, end_with_commit;
const char *wq;
char swallow, *ptr;
@@ -2844,13 +2846,13 @@ CC_send_query_append(ConnectionClass *self, const char *query, QueryInfo *qi, UD
return res;
}
- rollback_on_error = (flag & ROLLBACK_ON_ERROR) != 0;
+ rollback_error_value = (flag & ROLLBACK_ON_ERROR) != 0;
end_with_commit = (flag & END_WITH_COMMIT) != 0;
#define return DONT_CALL_RETURN_FROM_HERE???
consider_rollback = (issue_begin || (CC_is_in_trans(self) && !CC_is_in_error_trans(self)) || strnicmp(query, "begin", 5) == 0);
- if (rollback_on_error)
- rollback_on_error = consider_rollback;
- query_rollback = (rollback_on_error && !end_with_commit && PG_VERSION_GE(self, 8.0));
+ if (rollback_error_value)
+ rollback_error_value = consider_rollback;
+ query_rollback = (rollback_error_value && !end_with_commit && PG_VERSION_GE(self, 8.0));
if (!query_rollback && consider_rollback && !end_with_commit)
{
if (stmt)
@@ -3341,7 +3343,7 @@ cleanup:
CC_on_abort(self, CONN_DEAD);
retres = NULL;
}
- if (rollback_on_error && CC_is_in_trans(self) && !discard_next_savepoint)
+ if (rollback_error_value && CC_is_in_trans(self) && !discard_next_savepoint)
{
char cmd[64];
diff --git a/connection.h b/connection.h
index e92ff61..453ed5b 100644
--- a/connection.h
+++ b/connection.h
@@ -287,7 +287,16 @@ typedef struct
char database[MEDIUM_REGISTRY_LEN];
char username[MEDIUM_REGISTRY_LEN];
pgNAME password;
+
+ /*
+ * Protocol number, this can be used as well to define the behavior
+ * of rollback in case of error.
+ */
char protocol[SMALL_REGISTRY_LEN];
+
+ /* Value of RollbackError */
+ char rollback_error[SMALL_REGISTRY_LEN];
+
char port[SMALL_REGISTRY_LEN];
char sslmode[16];
char onlyread[SMALL_REGISTRY_LEN];
@@ -308,7 +317,19 @@ typedef struct
signed char bytea_as_longvarbinary;
signed char use_server_side_prepare;
signed char lower_case_identifier;
- signed char rollback_on_error;
+
+ /*
+ * Control behavior of rollback on error.
+ *
+ * rollback_error_value is used to store the value given by either
+ * Protovol (as an extension of the protocol number) or RollbackError.
+ * is_rollback_error is set to true if the value set is obtained with
+ * RollbackError and not as an extension of Protocol. Priority is given
+ * to RollbackError if both Protocol and RollbackError are set.
+ */
+ signed char rollback_error_value;
+ signed char is_rollback_error;
+
signed char force_abbrev_connstr;
signed char bde_environment;
signed char fake_mss;
diff --git a/dlg_specific.c b/dlg_specific.c
index 8e051af..ff6066b 100644
--- a/dlg_specific.c
+++ b/dlg_specific.c
@@ -229,16 +229,11 @@ inolog("force_abbrev=%d abbrev=%d\n", ci->force_abbrev_connstr, abbrev);
inolog("hlen=%d", hlen);
if (!abbrev)
{
- char protocol_and[16];
-
- if (ci->rollback_on_error >= 0)
- snprintf(protocol_and, sizeof(protocol_and), "%s-%d", ci->protocol, ci->rollback_on_error);
- else
- strncpy_null(protocol_and, ci->protocol, sizeof(protocol_and));
olen = snprintf(&connect_string[hlen], nlen, ";"
INI_SSLMODE "=%s;"
INI_READONLY "=%s;"
INI_PROTOCOL "=%s;"
+ INI_ROLLBACK_ON_ERROR "=%d;"
INI_FAKEOIDINDEX "=%s;"
INI_SHOWOIDCOLUMN "=%s;"
INI_ROWVERSIONING "=%s;"
@@ -276,7 +271,8 @@ inolog("hlen=%d", hlen);
#endif /* _HANDLE_ENLIST_IN_DTC_ */
,ci->sslmode
,ci->onlyread
- ,protocol_and
+ ,ci->protocol
+ ,ci->rollback_error_value
,ci->fake_oid_index
,ci->show_oid_column
,ci->row_versioning
@@ -408,22 +404,22 @@ inolog("hlen=%d", hlen);
ci->int8_as,
ci->drivers.extra_systable_prefixes,
EFFECTIVE_BIT_COUNT, flag);
- if (olen < nlen && (PROTOCOL_74(ci) || ci->rollback_on_error >= 0))
+ if (olen < nlen && (PROTOCOL_74(ci) || ci->rollback_error_value >= 0))
{
hlen = strlen(connect_string);
nlen = MAX_CONNECT_STRING - hlen;
/*
* The PROTOCOL setting must be placed after CX flag
* so that this option can override the CX setting.
+ * Complete it with RollbackError.
*/
- if (ci->rollback_on_error >= 0)
+ if (ci->rollback_error_value >= 0)
olen = snprintf(&connect_string[hlen], nlen, ";"
- ABBR_PROTOCOL "=%s-%d",
- ci->protocol, ci->rollback_on_error);
+ ABBR_PROTOCOL "=%s;" ABBR_ROLLBACK_ON_ERROR "=%d",
+ ci->protocol, ci->rollback_error_value);
else
olen = snprintf(&connect_string[hlen], nlen, ";"
- ABBR_PROTOCOL "=%s",
- ci->protocol);
+ ABBR_PROTOCOL "=%s", ci->protocol);
}
}
if (olen < nlen)
@@ -541,22 +537,33 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value)
else if (stricmp(attribute, INI_PROTOCOL) == 0 || stricmp(attribute, ABBR_PROTOCOL) == 0)
{
char *ptr;
-
ptr = strchr(value, '-');
- if (ptr)
+
+ /*
+ * Copy value controlling rollback on error if an extension of
+ * Protocol is found and if it is not set already by RollbackError.
+ */
+ if (ptr && ci->is_rollback_error < 0)
{
if ('-' != *value)
{
*ptr = '\0';
strcpy(ci->protocol, value);
}
- ci->rollback_on_error = atoi(ptr + 1);
- mylog("rollback_on_error=%d\n", ci->rollback_on_error);
+ ci->rollback_error_value = atoi(ptr + 1);
+ mylog("rollback_error_value=%d\n", ci->rollback_error_value);
}
else
strcpy(ci->protocol, value);
}
+ else if (stricmp(attribute, INI_ROLLBACK_ON_ERROR) == 0 ||
+ stricmp(attribute, ABBR_ROLLBACK_ON_ERROR) == 0)
+ {
+ ci->rollback_error_value = atoi(value);
+ ci->is_rollback_error = 0;
+ }
+
else if (stricmp(attribute, INI_SHOWOIDCOLUMN) == 0 || stricmp(attribute, ABBR_SHOWOIDCOLUMN) == 0)
strcpy(ci->show_oid_column, value);
@@ -663,7 +670,7 @@ copyAttributes(ConnInfo *ci, const char *attribute, const char *value)
else
found = FALSE;
- mylog("%s: DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',onlyread='%s',protocol='%s',conn_settings='%s',disallow_premature=%d)\n", func, ci->dsn, ci->server, ci->database, ci->username, NAME_IS_VALID(ci->password) ? "xxxxx" : "", ci->port, ci->onlyread, ci->protocol, ci->conn_settings, ci->disallow_premature);
+ mylog("%s: DSN='%s',server='%s',dbase='%s',user='%s',passwd='%s',port='%s',onlyread='%s',protocol='%s',rollback_error='%s',conn_settings='%s',disallow_premature=%d)\n", func, ci->dsn, ci->server, ci->database, ci->username, NAME_IS_VALID(ci->password) ? "xxxxx" : "", ci->port, ci->onlyread, ci->protocol, ci->rollback_error, ci->conn_settings, ci->disallow_premature);
return found;
}
@@ -893,21 +900,45 @@ getDSNinfo(ConnInfo *ci, char overwrite)
if (ci->show_system_tables[0] == '\0' || overwrite)
SQLGetPrivateProfileString(DSN, INI_SHOWSYSTEMTABLES, "", ci->show_system_tables, sizeof(ci->show_system_tables), ODBC_INI);
+ /*
+ * Set up value for Protocol. Error on rollback
+ */
if (ci->protocol[0] == '\0' || overwrite)
{
char *ptr;
SQLGetPrivateProfileString(DSN, INI_PROTOCOL, "", ci->protocol, sizeof(ci->protocol), ODBC_INI);
- if (ptr = strchr(ci->protocol, '-'), NULL != ptr)
+
+ /*
+ * Check if behavior of rollback on error is set as an extension
+ * of Protocol. Note that if this parameter has already been set
+ * by RollbackError, we simply ignore the value set here.
+ */
+ if (ptr = strchr(ci->protocol, '-'), NULL != ptr &&
+ ci->is_rollback_error < 0)
{
*ptr = '\0';
- if (overwrite || ci->rollback_on_error < 0)
+ if (overwrite || ci->rollback_error_value < 0)
{
- ci->rollback_on_error = atoi(ptr + 1);
- mylog("rollback_on_error=%d\n", ci->rollback_on_error);
+ ci->rollback_error_value = atoi(ptr + 1);
+ mylog("rollback_error_value=%d\n", ci->rollback_error_value);
}
}
}
+ /*
+ * Set up value for RollbackError. This gets priority over Protocol.
+ */
+ if (ci->rollback_error[0] == '\0' || overwrite)
+ {
+ if ((ci->rollback_error_value < 0 && ci->is_rollback_error < 0)
+ || overwrite)
+ {
+ ci->rollback_error_value = atoi(ci->rollback_error);
+ ci->is_rollback_error = 0;
+ mylog("rollback_error_value=%d\n", ci->rollback_error_value);
+ }
+ }
+
if (NAME_IS_NULL(ci->conn_settings) || overwrite)
{
SQLGetPrivateProfileString(DSN, INI_CONNSETTINGS, "", encoded_item, sizeof(encoded_item), ODBC_INI);
@@ -1205,12 +1236,14 @@ writeDSNinfo(const ConnInfo *ci)
ci->show_system_tables,
ODBC_INI);
- if (ci->rollback_on_error >= 0)
- sprintf(temp, "%s-%d", ci->protocol, ci->rollback_on_error);
- else
- strncpy_null(temp, ci->protocol, sizeof(temp));
SQLWritePrivateProfileString(DSN,
INI_PROTOCOL,
+ ci->protocol,
+ ODBC_INI);
+
+ sprintf(temp, "%d", ci->rollback_error_value);
+ SQLWritePrivateProfileString(DSN,
+ INI_ROLLBACK_ON_ERROR,
temp,
ODBC_INI);
diff --git a/dlg_specific.h b/dlg_specific.h
index c73bb64..d2d1575 100644
--- a/dlg_specific.h
+++ b/dlg_specific.h
@@ -75,6 +75,8 @@ extern "C" {
#define ABBR_COMMLOG "B3"
#define INI_PROTOCOL "Protocol" /* What protocol (6.2) */
#define ABBR_PROTOCOL "A1"
+#define INI_ROLLBACK_ON_ERROR "RollbackError" /* Rollback on error */
+#define ABBR_ROLLBACK_ON_ERROR "AA"
#define INI_OPTIMIZER "Optimizer" /* Use backend genetic
* optimizer */
#define ABBR_OPTIMIZER "B4"
diff --git a/docs/config-opt.html b/docs/config-opt.html
index 6673bc2..bba3266 100644
--- a/docs/config-opt.html
+++ b/docs/config-opt.html
@@ -146,6 +146,17 @@
</TR>
<TR>
<TD WIDTH=38%>
+ Rollback on error
+ </TD>
+ <TD WIDTH=31%>
+ RollbackError
+ </TD>
+ <TD WIDTH=31%>
+ AA
+ </TD>
+ </TR>
+ <TR>
+ <TD WIDTH=38%>
Backend enetic optimizer
</TD>
<TD WIDTH=31%>
diff --git a/docs/config.html b/docs/config.html
index cb1c326..b0b727a 100644
--- a/docs/config.html
+++ b/docs/config.html
@@ -238,23 +238,31 @@ with 6.4 and higher backends.<br /> </li>
with 7.4 and higher backends.<br /> </li>
</ul></li>
-<li><b>Level of rollback on errors:</b> Specifies what to rollback should an
-error occur.<br />
+<li><b>RollbackError</b>: Level of rollback on errors, specifies what to
+rollback should an error occur.<br />
<ul>
<li><i>Nop(0):</i> Don't rollback anything and let the application handle the
-error.<br /> </li>
-
-<li><i>Transaction(1):</i> Rollback the entire transaction.<br /> </li>
-
-<li><i>Statement(2):</i> Rollback the statement.<br /> </li>
-<br>
-<b>Notes in a setup: This specification is set up with a PROTOCOL option parameter.</b><br><br>
-PROTOCOL=[6.2|6.3|6.4|7.4][-(0|1|2)]<br>
-default value is a sentence unit (it is a transaction unit before 8.0).<br>
-<br>
-
-</ul></li>
+error.<br /></li>
+
+<li><i>Transaction(1):</i> Rollback the entire transaction.<br /></li>
+
+<li><i>Statement(2):</i> Rollback the statement.<br /></li>
+<b>Notes:</b>
+ <ul>
+ <li>
+ This parameter can be set as an extension of PROTOCOL option
+ parameter.<br />
+ PROTOCOL=[6.2|6.3|6.4|7.4][-(0|1|2)]<br />
+ Default value is a sentence unit (it is a transaction unit
+ before 8.0).<br />
+ </li>
+ <li>
+ This parameter can be set with ROLLBACKERROR as well. This takes
+ precedence on PROTOCOL.<bt />
+ </li>
+ </ul>
+</ul>.<br /> </li>
<li><b>OID Options:</b><br />
diff --git a/execute.c b/execute.c
index 1cc4f04..d502df2 100644
--- a/execute.c
+++ b/execute.c
@@ -652,7 +652,7 @@ inolog("%s:%p->internal=%d\n", func, stmt, stmt->internal);
if (conn)
ci = &conn->connInfo;
ret = 0;
- if (!ci || ci->rollback_on_error < 0) /* default */
+ if (!ci || ci->rollback_error_value < 0) /* default */
{
if (conn && PG_VERSION_GE(conn, 8.0))
ret = 2; /* statement rollback */
@@ -661,7 +661,7 @@ inolog("%s:%p->internal=%d\n", func, stmt, stmt->internal);
}
else
{
- ret = ci->rollback_on_error;
+ ret = ci->rollback_error_value;
if (2 == ret && PG_VERSION_LT(conn, 8.0))
ret = 1;
}
diff --git a/test/expected/error-rollback.out b/test/expected/error-rollback.out
index 436a328..da9cdf3 100644
--- a/test/expected/error-rollback.out
+++ b/test/expected/error-rollback.out
@@ -1,5 +1,5 @@
\! ./src/error-rollback-test
-Test for rollback protocol 0
+Test for Protocol=7.4-0
connected
Executing query that will succeed
Executing query that will fail
@@ -10,7 +10,7 @@ Executing query that will succeed
Result set:
1
disconnecting
-Test for rollback protocol 1
+Test for Protocol=7.4-1
connected
Executing query that will succeed
Executing query that will fail
@@ -20,7 +20,71 @@ Executing query that will succeed
Result set:
1
disconnecting
-Test for rollback protocol 2
+Test for Protocol=7.4-2
+connected
+Executing query that will succeed
+Executing query that will fail
+Failed to execute statement
+22P02=ERROR: invalid input syntax for integer: "foo"
+Executing query that will succeed
+Result set:
+1
+1
+disconnecting
+Test for RollbackError=0
+connected
+Executing query that will succeed
+Executing query that will fail
+Failed to execute statement
+22P02=ERROR: invalid input syntax for integer: "foo"
+Rolling back with SQLEndTran
+Executing query that will succeed
+Result set:
+1
+disconnecting
+Test for RollbackError=1
+connected
+Executing query that will succeed
+Executing query that will fail
+Failed to execute statement
+22P02=ERROR: invalid input syntax for integer: "foo"
+Executing query that will succeed
+Result set:
+1
+disconnecting
+Test for RollbackError=2
+connected
+Executing query that will succeed
+Executing query that will fail
+Failed to execute statement
+22P02=ERROR: invalid input syntax for integer: "foo"
+Executing query that will succeed
+Result set:
+1
+1
+disconnecting
+Test for RollbackError=0;Protocol=7.4-2
+connected
+Executing query that will succeed
+Executing query that will fail
+Failed to execute statement
+22P02=ERROR: invalid input syntax for integer: "foo"
+Rolling back with SQLEndTran
+Executing query that will succeed
+Result set:
+1
+disconnecting
+Test for RollbackError=1;Protocol=7.4-0
+connected
+Executing query that will succeed
+Executing query that will fail
+Failed to execute statement
+22P02=ERROR: invalid input syntax for integer: "foo"
+Executing query that will succeed
+Result set:
+1
+disconnecting
+Test for RollbackError=2;Protocol=7.4-1
connected
Executing query that will succeed
Executing query that will fail
diff --git a/test/src/error-rollback-test.c b/test/src/error-rollback-test.c
index 01c0f0c..bbff007 100644
--- a/test/src/error-rollback-test.c
+++ b/test/src/error-rollback-test.c
@@ -142,18 +142,19 @@ error_rollback_print(void)
print_result(hstmt);
}
-int
-main(int argc, char **argv)
+/*
+ * Test for rollback protocol 0.
+ *
+ * Additional options can be specified to play with combinations of
+ * Protocol and RollbackError. With protocol 0, it is the responsability
+ * of application to issue rollbacks.
+ */
+void
+error_rollback_test_0(char *options)
{
SQLRETURN rc;
- /*
- * Test for protocol at 0.
- * Do nothing when error occurs and let application do necessary
- * ROLLBACK on error.
- */
- printf("Test for rollback protocol 0\n");
- error_rollback_init("Protocol=7.4-0");
+ error_rollback_init(options);
/* Insert a row correctly */
error_rollback_exec_success();
@@ -181,17 +182,25 @@ main(int argc, char **argv)
/* Clean up */
error_rollback_clean();
+}
- /*
- * Test for rollback protocol 1
- * In case of an error rollback the entire transaction.
- */
- printf("Test for rollback protocol 1\n");
- error_rollback_init("Protocol=7.4-1");
+/*
+ * Test for rollback protocols 1 or 2
+ *
+ * Options can be specified to manipulate the protocol used with Protocol
+ * and RollbackError. When priting results, there should be one row for
+ * protocol 1 as rollback is done for an entire transaction is case of
+ * failure. There will be two rows for protocol 2 as tollback is issued
+ * for each statement.
+ */
+void
+error_rollback_test_12(char *options)
+{
+ error_rollback_init(options);
/*
- * Insert a row, trigger an error, and re-insert a row. Only one
- * row should be visible here.
+ * Insert a row, trigger an error, and re-insert a row. Depending
+ * on the protocol, one or two rows should be visible.
*/
error_rollback_exec_success();
error_rollback_exec_failure();
@@ -200,23 +209,40 @@ main(int argc, char **argv)
/* Clean up */
error_rollback_clean();
+}
+int
+main(int argc, char **argv)
+{
/*
- * Test for rollback protocol 2
- * In the case of an error rollback only the latest statement.
+ * Test for Protocol only
*/
- printf("Test for rollback protocol 2\n");
- error_rollback_init("Protocol=7.4-2");
+ printf("Test for Protocol=7.4-0\n");
+ error_rollback_test_0("Protocol=7.4-0");
+ printf("Test for Protocol=7.4-1\n");
+ error_rollback_test_12("Protocol=7.4-1");
+ printf("Test for Protocol=7.4-2\n");
+ error_rollback_test_12("Protocol=7.4-2");
/*
- * Similarly to previous case, do insert, error and insert. This
- * time two rows should be visible.
+ * Now do the same tests as previously, but this time for
+ * RollbackError.
*/
- error_rollback_exec_success();
- error_rollback_exec_failure();
- error_rollback_exec_success();
- error_rollback_print();
+ printf("Test for RollbackError=0\n");
+ error_rollback_test_0("RollbackError=0");
+ printf("Test for RollbackError=1\n");
+ error_rollback_test_12("RollbackError=1");
+ printf("Test for RollbackError=2\n");
+ error_rollback_test_12("RollbackError=2");
- /* Clean up */
- error_rollback_clean();
+ /*
+ * Combinations of RollbackError and Protocol, the former
+ * should have the priority.
+ */
+ printf("Test for RollbackError=0;Protocol=7.4-2\n");
+ error_rollback_test_0("RollbackError=0;Protocol=7.4-2");
+ printf("Test for RollbackError=1;Protocol=7.4-0\n");
+ error_rollback_test_12("RollbackError=1;Protocol=7.4-0\n"); /* 1 row */
+ printf("Test for RollbackError=2;Protocol=7.4-1\n");
+ error_rollback_test_12("RollbackError=2;Protocol=7.4-1\n"); /* 2 rows */
}