From 70b0831387bcc76667e3e67a7a37b992c28420bd Mon Sep 17 00:00:00 2001 From: Hiroshi Inoue Date: Fri, 14 Sep 2001 06:30:37 +0000 Subject: [PATCH] 1) Improve the implementation of *Disallow Premature* for older versions of servers. 2) Implement SQLProcedures. Hiroshi Inoue --- src/interfaces/odbc/convert.c | 13 +++--- src/interfaces/odbc/execute.c | 38 ++++++++++++++--- src/interfaces/odbc/info.c | 74 +++++++++++++++++++++++---------- src/interfaces/odbc/statement.c | 6 +-- 4 files changed, 95 insertions(+), 36 deletions(-) diff --git a/src/interfaces/odbc/convert.c b/src/interfaces/odbc/convert.c index 84f99b40e3..f39a34f4c1 100644 --- a/src/interfaces/odbc/convert.c +++ b/src/interfaces/odbc/convert.c @@ -994,7 +994,7 @@ copy_statement_with_parameters(StatementClass *stmt) unsigned int declare_pos = 0; ConnectionClass *conn = SC_get_conn(stmt); ConnInfo *ci = &(conn->connInfo); - BOOL prepare_dummy_cursor = FALSE; + BOOL prepare_dummy_cursor = FALSE, begin_first = FALSE; char token_save[32]; int token_len; BOOL prev_token_end; @@ -1055,8 +1055,11 @@ copy_statement_with_parameters(StatementClass *stmt) { if (prepare_dummy_cursor) { - if (!CC_is_in_trans(conn)) - strcpy(new_statement, "begin;"); + if (!CC_is_in_trans(conn) && PG_VERSION_GE(conn, 7.1)) + { + strcpy(new_statement, "BEGIN;"); + begin_first = TRUE; + } } else if (ci->drivers.use_declarefetch) SC_set_fetchcursor(stmt); @@ -1718,8 +1721,8 @@ copy_statement_with_parameters(StatementClass *stmt) char fetchstr[128]; sprintf(fetchstr, ";fetch backward in %s;close %s;", stmt->cursor_name, stmt->cursor_name); - if (!CC_is_in_trans(conn)) - strcat(fetchstr, "commit;"); + if (begin_first && CC_is_in_autocommit(conn)) + strcat(fetchstr, "COMMIT;"); CVT_APPEND_STR(fetchstr); stmt->inaccurate_result = TRUE; } diff --git a/src/interfaces/odbc/execute.c b/src/interfaces/odbc/execute.c index b57a98b34c..d13a37e8ef 100644 --- a/src/interfaces/odbc/execute.c +++ b/src/interfaces/odbc/execute.c @@ -349,10 +349,29 @@ PGAPI_Execute( if (SC_is_pre_executable(stmt)) { BOOL in_trans = CC_is_in_trans(conn); + BOOL issued_begin = FALSE, begin_included = FALSE; QResultClass *res; + + if (strnicmp(stmt->stmt_with_params, "BEGIN;", 6) == 0) + begin_included = TRUE; + else if (!in_trans) + { + res = CC_send_query(conn, "BEGIN", NULL); + if (res && !QR_aborted(res)) + issued_begin = TRUE; + if (res) + QR_Destructor(res); + if (!issued_begin) + { + stmt->errornumber = STMT_EXEC_ERROR; + stmt->errormsg = "Handle prepare error"; + return SQL_ERROR; + } + } + /* we are now in a transaction */ CC_set_in_trans(conn); stmt->result = res = CC_send_query(conn, stmt->stmt_with_params, NULL); - if (res && QR_aborted(res)) + if (!res || QR_aborted(res)) { CC_abort(conn); stmt->errornumber = STMT_EXEC_ERROR; @@ -361,8 +380,18 @@ PGAPI_Execute( } else { - if (!in_trans) - CC_set_no_trans(conn); + if (CC_is_in_autocommit(conn)) + { + if (issued_begin) + { + res = CC_send_query(conn, "COMMIT", NULL); + CC_set_no_trans(conn); + if (res) + QR_Destructor(res); + } + else if (!in_trans && begin_included) + CC_set_no_trans(conn); + } stmt->status =STMT_FINISHED; return SQL_SUCCESS; } @@ -650,6 +679,7 @@ PGAPI_ParamData( return SQL_ERROR; } ok = QR_command_successful(res); + CC_set_no_trans(stmt->hdbc); QR_Destructor(res); if (!ok) { @@ -658,8 +688,6 @@ PGAPI_ParamData( SC_log_error(func, "", stmt); return SQL_ERROR; } - - CC_set_no_trans(stmt->hdbc); } stmt->lobj_fd = -1; } diff --git a/src/interfaces/odbc/info.c b/src/interfaces/odbc/info.c index 54d97304bc..431a9b1d14 100644 --- a/src/interfaces/odbc/info.c +++ b/src/interfaces/odbc/info.c @@ -832,7 +832,8 @@ PGAPI_GetFunctions( UWORD FAR *pfExists) { static char *func = "PGAPI_GetFunctions"; - ConnInfo *ci = &(((ConnectionClass *)hdbc)->connInfo); + ConnectionClass *conn = (ConnectionClass *)hdbc; + ConnInfo *ci = &(conn->connInfo); mylog("%s: entering...%u\n", func, fFunction); @@ -915,7 +916,10 @@ PGAPI_GetFunctions( pfExists[SQL_API_SQLPARAMOPTIONS] = FALSE; pfExists[SQL_API_SQLPRIMARYKEYS] = TRUE; pfExists[SQL_API_SQLPROCEDURECOLUMNS] = FALSE; - pfExists[SQL_API_SQLPROCEDURES] = FALSE; + if (PG_VERSION_LT(conn, 6.5)) + pfExists[SQL_API_SQLPROCEDURES] = FALSE; + else + pfExists[SQL_API_SQLPROCEDURES] = TRUE; pfExists[SQL_API_SQLSETPOS] = TRUE; pfExists[SQL_API_SQLSETSCROLLOPTIONS] = TRUE; /* odbc 1.0 */ pfExists[SQL_API_SQLTABLEPRIVILEGES] = FALSE; @@ -1090,7 +1094,10 @@ PGAPI_GetFunctions( *pfExists = FALSE; break; case SQL_API_SQLPROCEDURES: - *pfExists = FALSE; + if (PG_VERSION_LT(conn, 6.5)) + *pfExists = FALSE; + else + *pfExists = TRUE; break; case SQL_API_SQLSETPOS: *pfExists = TRUE; @@ -3615,30 +3622,53 @@ PGAPI_Procedures( { static char *func = "PGAPI_Procedures"; StatementClass *stmt = (StatementClass *) hstmt; - Int2 result_cols; + ConnectionClass *conn = SC_get_conn(stmt); + char proc_query[INFO_INQUIRY_LEN]; + QResultClass *res; mylog("%s: entering...\n", func); + + if (PG_VERSION_LT(conn, 6.5)) + { + stmt->errornumber = STMT_NOT_IMPLEMENTED_ERROR; + stmt->errormsg = "Version is too old"; + SC_log_error(func, "Function not implemented", (StatementClass *) hstmt); + return SQL_ERROR; + } + if (!SC_recycle_statement(stmt)) + return SQL_ERROR; + /* + * The following seems the simplest implementation + */ + strcpy(proc_query, "select '' as ""PROCEDURE_CAT"", '' as ""PROCEDURE_SCHEM""," + " proname as ""PROCEDURE_NAME"", '' as ""NUM_INPUT_PARAMS""," + " '' as ""NUM_OUTPUT_PARAMS"", '' as ""NUM_RESULT_SETS""," + " '' as ""REMARKS""," + " case when prorettype =0 then 1::int2 else 2::int2 end as ""PROCEDURE_TYPE"" from pg_proc"); + my_strcat(proc_query, " where proname like '%.*s'", szProcName, cbProcName); + res = CC_send_query(conn, proc_query, NULL); + if (!res || QR_aborted(res)) + { + if (res) + QR_Destructor(res); + stmt->errornumber = STMT_EXEC_ERROR; + stmt->errormsg = "PGAPI_Procedures query error"; + return SQL_ERROR; + } + stmt->result = res; /* - * a statement is actually executed, so we'll have to do this - * ourselves. - */ - result_cols = 8; - extend_bindings(stmt, result_cols); + * also, things need to think that this statement is finished so the + * results can be retrieved. + */ + stmt->status = STMT_FINISHED; + extend_bindings(stmt, 8); + /* set up the current tuple pointer for SQLFetch */ + stmt->currTuple = -1; + stmt->rowset_start = -1; + stmt->current_col = -1; - /* set the field names */ - QR_set_num_fields(stmt->result, result_cols); - QR_set_field_info(stmt->result, 0, "PROCEDURE_CAT", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 1, "PROCEDURE_SCHEM", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 2, "PROCEDURE_NAME", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 3, "NUM_INPUT_PARAMS", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 4, "NUM_OUTPUT_PARAMS", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 5, "NUM_RESULT_SET", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 6, "REMARKS", PG_TYPE_TEXT, MAX_INFO_STRING); - QR_set_field_info(stmt->result, 7, "PROCEDURE_TYPE", PG_TYPE_INT2, 2); - - SC_log_error(func, "Function not implemented", (StatementClass *) hstmt); - return SQL_ERROR; + return SQL_SUCCESS; } diff --git a/src/interfaces/odbc/statement.c b/src/interfaces/odbc/statement.c index 584d5a710d..9efd4fb52c 100644 --- a/src/interfaces/odbc/statement.c +++ b/src/interfaces/odbc/statement.c @@ -468,10 +468,8 @@ SC_recycle_statement(StatementClass *self) conn = SC_get_conn(self); if (!CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) { - QResultClass *res = CC_send_query(conn, "ABORT", NULL); - - QR_Destructor(res); - CC_set_no_trans(conn); + if (SC_is_pre_executable(self) && !conn->connInfo.disallow_premature) + CC_abort(conn); } break; -- 2.40.0