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 @@