execute.c
来自「postgresql-odbc,跨平台应用」· C语言 代码 · 共 1,696 行 · 第 1/3 页
C
1,696 行
{ BOOL need_savep = FALSE; if (stmt->internal) { if (PG_VERSION_GE(conn, 8.0)) SC_start_rb_stmt(stmt); else SC_start_tc_stmt(stmt); } if (SC_is_rb_stmt(stmt)) { if (CC_is_in_trans(conn)) { need_savep = TRUE; } } if (need_savep) { sprintf(esavepoint, "_EXEC_SVP_%p", stmt); snprintf(cmd, sizeof(cmd), "SAVEPOINT %s", esavepoint); res = CC_send_query(conn, cmd, NULL, 0, NULL); if (QR_command_maybe_successful(res)) { SC_set_accessed_db(stmt); SC_start_rbpoint(stmt); ret = SQL_SUCCESS; } else { SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal SAVEPOINT failed", func); ret = SQL_ERROR; } QR_Destructor(res); } else SC_set_accessed_db(stmt); }inolog("%s:%p->accessed=%d\n", func, stmt, SC_accessed_db(stmt)); return ret;}RETCODEDiscardStatementSvp(StatementClass *stmt, RETCODE ret, BOOL errorOnly){ CSTR func = "DiscardStatementSvp"; char esavepoint[32], cmd[64]; ConnectionClass *conn = SC_get_conn(stmt); QResultClass *res; BOOL cmd_success, start_stmt = FALSE; inolog("%s:%p->accessed=%d is_in=%d is_rb=%d is_tc=%d\n", func, stmt, SC_accessed_db(stmt),CC_is_in_trans(conn), SC_is_rb_stmt(stmt), SC_is_tc_stmt(stmt)); switch (ret) { case SQL_NEED_DATA: break; case SQL_ERROR: start_stmt = TRUE; break; default: if (!errorOnly) start_stmt = TRUE; break; } if (!SC_accessed_db(stmt) || !CC_is_in_trans(conn)) goto cleanup; if (!SC_is_rb_stmt(stmt) && !SC_is_tc_stmt(stmt)) goto cleanup; sprintf(esavepoint, "_EXEC_SVP_%p", stmt); if (SQL_ERROR == ret) { if (SC_started_rbpoint(stmt)) { snprintf(cmd, sizeof(cmd), "ROLLBACK to %s", esavepoint); res = CC_send_query(conn, cmd, NULL, IGNORE_ABORT_ON_CONN, NULL); cmd_success = QR_command_maybe_successful(res); QR_Destructor(res); if (!cmd_success) { SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal ROLLBACK failed", func); CC_abort(conn); goto cleanup; } } else { CC_abort(conn); goto cleanup; } } else if (errorOnly) return ret;inolog("ret=%d\n", ret); if (SQL_NEED_DATA != ret && SC_started_rbpoint(stmt)) { snprintf(cmd, sizeof(cmd), "RELEASE %s", esavepoint); res = CC_send_query(conn, cmd, NULL, IGNORE_ABORT_ON_CONN, NULL); cmd_success = QR_command_maybe_successful(res); QR_Destructor(res); if (!cmd_success) { SC_set_error(stmt, STMT_INTERNAL_ERROR, "internal RELEASE failed", func); CC_abort(conn); ret = SQL_ERROR; } }cleanup: if (SQL_NEED_DATA != ret) SC_forget_unnamed(stmt); /* unnamed plan is no longer reliable */ if (!SC_is_prepare_statement(stmt) && ONCE_DESCRIBED == stmt->prepared) SC_set_prepared(stmt, NOT_YET_PREPARED); if (start_stmt || SQL_ERROR == ret) { if (stmt->lock_CC_for_rb > 0) { LEAVE_CONN_CS(conn); stmt->lock_CC_for_rb--; } SC_start_stmt(stmt); } return ret;}voidSC_setInsertedTable(StatementClass *stmt, RETCODE retval){ const char *cmd = stmt->statement, *ptr; ConnectionClass *conn; size_t len; if (STMT_TYPE_INSERT != stmt->statement_type) return; if (SQL_NEED_DATA == retval) return; conn = SC_get_conn(stmt);#ifdef NOT_USED /* give up the use of lastval() */ if (PG_VERSION_GE(conn, 8.1)) /* lastval() is available */ return;#endif /* NOT_USED */ /*if (!CC_fake_mss(conn)) return;*/ while (isspace((UCHAR) *cmd)) cmd++; if (!*cmd) return; len = 6; if (strnicmp(cmd, "insert", len)) return; cmd += len; while (isspace((UCHAR) *(++cmd))); if (!*cmd) return; len = 4; if (strnicmp(cmd, "into", len)) return; cmd += len; while (isspace((UCHAR) *(++cmd))); if (!*cmd) return; NULL_THE_NAME(conn->schemaIns); NULL_THE_NAME(conn->tableIns); if (!SQL_SUCCEEDED(retval)) return; ptr = NULL; if (IDENTIFIER_QUOTE == *cmd) { if (ptr = strchr(cmd + 1, IDENTIFIER_QUOTE), NULL == ptr) return; if ('.' == ptr[1]) { len = ptr - cmd - 1; STRN_TO_NAME(conn->schemaIns, cmd + 1, len); cmd = ptr + 2; ptr = NULL; } } else { if (ptr = strchr(cmd + 1, '.'), NULL != ptr) { len = ptr - cmd; STRN_TO_NAME(conn->schemaIns, cmd, len); cmd = ptr + 1; ptr = NULL; } } if (IDENTIFIER_QUOTE == *cmd && NULL == ptr) { if (ptr = strchr(cmd + 1, IDENTIFIER_QUOTE), NULL == ptr) return; } if (IDENTIFIER_QUOTE == *cmd) { len = ptr - cmd - 1; STRN_TO_NAME(conn->tableIns, cmd + 1, len); } else { ptr = cmd; while (*ptr && !isspace((UCHAR) *ptr)) ptr++; len = ptr - cmd; STRN_TO_NAME(conn->tableIns, cmd, len); }}/* Execute a prepared SQL statement */RETCODE SQL_APIPGAPI_Execute(HSTMT hstmt, UWORD flag){ CSTR func = "PGAPI_Execute"; StatementClass *stmt = (StatementClass *) hstmt; RETCODE retval = SQL_SUCCESS; ConnectionClass *conn; APDFields *apdopts; IPDFields *ipdopts; SQLLEN i, start_row, end_row; BOOL exec_end, recycled = FALSE, recycle = TRUE; SQLSMALLINT num_params; mylog("%s: entering...%x\n", func, flag); if (!stmt) { SC_log_error(func, "", NULL); mylog("%s: NULL statement so return SQL_INVALID_HANDLE\n", func); return SQL_INVALID_HANDLE; } conn = SC_get_conn(stmt); apdopts = SC_get_APDF(stmt); /* * If the statement is premature, it means we already executed it from * an SQLPrepare/SQLDescribeCol type of scenario. So just return * success. */ if (stmt->prepare && stmt->status == STMT_PREMATURE) { if (stmt->inaccurate_result) { stmt->exec_current_row = -1; SC_recycle_statement(stmt); } else { stmt->status = STMT_FINISHED; if (NULL == SC_get_errormsg(stmt)) { mylog("%s: premature statement but return SQL_SUCCESS\n", func); retval = SQL_SUCCESS; goto cleanup; } else { SC_set_error(stmt,STMT_INTERNAL_ERROR, "premature statement so return SQL_ERROR", func); retval = SQL_ERROR; goto cleanup; } } } mylog("%s: clear errors...\n", func); SC_clear_error(stmt); if (!stmt->statement) { SC_set_error(stmt, STMT_NO_STMTSTRING, "This handle does not have a SQL statement stored in it", func); mylog("%s: problem with handle\n", func); return SQL_ERROR; }#define return DONT_CALL_RETURN_FROM_HERE??? if (stmt->exec_current_row > 0) { /* * executing an array of parameters. * Don't recycle the statement. */ recycle = FALSE; } else if (PREPARED_PERMANENTLY == stmt->prepared || PREPARED_TEMPORARILY == stmt->prepared) { QResultClass *res; /* * re-executing an prepared statement. * Don't recycle the statement but * discard the old result. */ recycle = FALSE; if (res = SC_get_Result(stmt), res) QR_close_result(res, FALSE); } /* * If SQLExecute is being called again, recycle the statement. Note * this should have been done by the application in a call to * SQLFreeStmt(SQL_CLOSE) or SQLCancel. */ else if (stmt->status == STMT_FINISHED) { mylog("%s: recycling statement (should have been done by app)...\n", func);/******** Is this really NEEDED ? ******/ SC_recycle_statement(stmt); recycled = TRUE; } /* Check if the statement is in the correct state */ else if ((stmt->prepare && stmt->status != STMT_READY) || (stmt->status != STMT_ALLOCATED && stmt->status != STMT_READY)) { SC_set_error(stmt, STMT_STATUS_ERROR, "The handle does not point to a statement that is ready to be executed", func); mylog("%s: problem with statement\n", func); retval = SQL_ERROR; goto cleanup; } if (start_row = stmt->exec_start_row, start_row < 0) start_row = 0; if (end_row = stmt->exec_end_row, end_row < 0) end_row = (SQLINTEGER) apdopts->paramset_size - 1; if (stmt->exec_current_row < 0) stmt->exec_current_row = start_row; ipdopts = SC_get_IPDF(stmt); num_params = stmt->num_params; if (num_params < 0) PGAPI_NumParams(stmt, &num_params); if (stmt->exec_current_row == start_row) { /* We sometimes need to know about the PG type of binding parameters even in case of non-prepared statements. */ BOOL bCallPrepare = FALSE; ConnInfo *ci = &(conn->connInfo); if (NOT_YET_PREPARED == stmt->prepared && PROTOCOL_74(ci) && ci->use_server_side_prepare && (ci->bytea_as_longvarbinary || /* both lo and bytea are LO */ ci->cvt_null_date_string)) { SQLSMALLINT num_params = stmt->num_params; if (num_params < 0) PGAPI_NumParams(stmt, &num_params); if (num_params > 0) { int param_number = -1; ParameterInfoClass *apara; ParameterImplClass *ipara; BOOL reqOK = FALSE; switch (decideHowToPrepare(stmt, TRUE)) { case NAMED_PARSE_REQUEST: case PARSE_TO_EXEC_ONCE: case PARSE_REQ_FOR_INFO: reqOK = TRUE; } while (reqOK) { SC_param_next(stmt, ¶m_number, &apara, &ipara); if (!ipara || !apara) break; if (SQL_LONGVARBINARY == ipara->SQLType) { if (ci->bytea_as_longvarbinary) { bCallPrepare = TRUE; break; } } else if (SQL_CHAR == ipara->SQLType) { if (SQL_C_CHAR == apara->CType && ci->cvt_null_date_string) { bCallPrepare = TRUE; break; } } } } } if (bCallPrepare) { if (retval = prepareParameters(stmt), SQL_ERROR == retval) goto cleanup; }mylog("prepareParameters %d end\n", stmt->prepare); if (ipdopts->param_processed_ptr) *ipdopts->param_processed_ptr = 0;#if (ODBCVER >= 0x0300) /* * Initialize the param_status_ptr */ if (ipdopts->param_status_ptr) { for (i = 0; i <= end_row; i++) ipdopts->param_status_ptr[i] = SQL_PARAM_UNUSED; }#endif /* ODBCVER */ if (recycle && !recycled) SC_recycle_statement(stmt); }next_param_row:#if (ODBCVER >= 0x0300) if (apdopts->param_operation_ptr) { while (apdopts->param_operation_ptr[stmt->exec_current_row] == SQL_PARAM_IGNORE) { if (stmt->exec_current_row >= end_row) { stmt->exec_current_row = -1; retval = SQL_SUCCESS; goto cleanup; } ++stmt->exec_current_row; } } /* * Initialize the current row status */ if (ipdopts->param_status_ptr) ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR;#endif /* ODBCVER */ /* * Check if statement has any data-at-execute parameters when it is * not in SC_pre_execute. */ if (!stmt->pre_executing) { /* * The bound parameters could have possibly changed since the last * execute of this statement? Therefore check for params and * re-copy. */ SQLULEN offset = apdopts->param_offset_ptr ? *apdopts->param_offset_ptr : 0; SQLINTEGER bind_size = apdopts->param_bind_type; SQLLEN current_row = stmt->exec_current_row < 0 ? 0 : stmt->exec_current_row; Int4 num_p = num_params < apdopts->allocated ? num_params : apdopts->allocated; /* * Increment the number of currently processed rows */ if (ipdopts->param_processed_ptr) (*ipdopts->param_processed_ptr)++; stmt->data_at_exec = -1; for (i = 0; i < num_p; i++) { SQLLEN *pcVal = apdopts->parameters[i].used; apdopts->parameters[i].data_at_exec = FALSE; if (pcVal) { if (bind_size > 0) pcVal = (SQLLEN *)((char *)pcVal + offset + bind_size * current_row); else pcVal = (SQLLEN *)((char *)pcVal + offset + sizeof(SDWORD) * current_row); if (*pcVal == SQL_DATA_AT_EXEC || *pcVal <= SQL_LEN_DATA_AT_EXEC_OFFSET) apdopts->parameters[i].data_at_exec = TRUE; } /* Check for data at execution parameters */ if (apdopts->parameters[i].data_at_exec) { if (stmt->data_at_exec < 0) stmt->data_at_exec = 1; else stmt->data_at_exec++; } } /* * If there are some data at execution parameters, return need * data */ /* * SQLParamData and SQLPutData will be used to send params and * execute the statement. */ if (stmt->data_at_exec > 0) { retval = SQL_NEED_DATA; goto cleanup; } } if (0 != (flag & PODBC_WITH_HOLD)) SC_set_with_hold(stmt); retval = Exec_with_parameters_resolved(stmt, &exec_end); if (!exec_end) goto next_param_row;cleanup:mylog("retval=%d\n", retval); SC_setInsertedTable(stmt, retval);#undef return if (stmt->internal) retval = DiscardStatementSvp(stmt, retval, FALSE); return retval;}RETCODE SQL_APIPGAPI_Transact( HENV henv, HDBC hdbc, SQLUSMALLINT fType){ CSTR func = "PGAPI_Transact"; ConnectionClass *conn; QResultClass *res; char ok, *stmt_string; int lf; mylog("entering %s: hdbc=%p, henv=%p\n", func, hdbc, henv); if (hdbc == SQL_NULL_HDBC && henv == SQL_NULL_HENV) { CC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } /* * If hdbc is null and henv is valid, it means transact all * connections on that henv. */ if (hdbc == SQL_NULL_HDBC && henv != SQL_NULL_HENV) { ConnectionClass * const *conns = getConnList(); const int conn_count = getConnCount(); for (lf = 0; lf < conn_count; lf++) { conn = conns[lf]; if (conn && conn->henv == henv) if (PGAPI_Transact(henv, (HDBC) conn, fType) != SQL_SUCCESS) return SQL_ERROR; } return SQL_SUCCESS; } conn = (ConnectionClass *) hdbc; if (fType == SQL_COMMIT) stmt_string = "COMMIT"; else if (fType == SQL_ROLLBACK) stmt_string = "ROLLBACK"; else { CC_set_error(conn, CONN_INVALID_ARGUMENT_NO, "PGAPI_Transact can only be called with SQL_COMMIT or SQL_ROLLBACK as parameter", func); return SQL_ERROR; } /* If manual commit and in transaction, then proceed. */ if (!CC_is_in_autocommit(conn) && CC_is_in_trans(conn)) { mylog("PGAPI_Transact: sending on conn %d '%s'\n", conn, stmt_string); res = CC_send_query(conn, stmt_string, NULL, 0, NULL); ok = QR_command_maybe_successful(res); QR_Destructor(res); if (!ok) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?