/* * The execution after all parameters were resolved. */ static RETCODE Exec_with_parameters_resolved(StatementClass *stmt, BOOL *exec_end) { CSTR func = "Exec_with_parameters_resolved"; RETCODE retval; SQLLEN end_row; SQLINTEGER cursor_type, scroll_concurrency; ConnectionClass *conn; QResultClass *res; APDFields *apdopts; IPDFields *ipdopts; BOOL prepare_before_exec = FALSE; *exec_end = FALSE; conn = SC_get_conn(stmt); mylog("%s: copying statement params: trans_status=%d, len=%d, stmt='%s'\n", func, conn->transact_status, strlen(stmt->statement), stmt->statement); /* save the cursor's info before the execution */ cursor_type = stmt->options.cursor_type; scroll_concurrency = stmt->options.scroll_concurrency; /* Prepare the statement if possible at backend side */ if (!stmt->inaccurate_result) { if (HowToPrepareBeforeExec(stmt, FALSE) >= allowParse) prepare_before_exec = TRUE; } inolog("prepare_before_exec=%d srv=%d\n", prepare_before_exec, conn->connInfo.use_server_side_prepare); /* Create the statement with parameters substituted. */ retval = copy_statement_with_parameters(stmt, prepare_before_exec); stmt->current_exec_param = -1; if (retval != SQL_SUCCESS) { stmt->exec_current_row = -1; *exec_end = TRUE; return retval; /* error msg is passed from the above */ } mylog(" stmt_with_params = '%s'\n", stmt->stmt_with_params); /* * Dummy exection to get the column info. */ if (stmt->inaccurate_result && SC_is_parse_tricky(stmt)) { BOOL in_trans = CC_is_in_trans(conn); BOOL issued_begin = FALSE; QResultClass *curres; stmt->exec_current_row = -1; *exec_end = TRUE; if (!SC_is_pre_executable(stmt)) return SQL_SUCCESS; if (strnicmp(stmt->stmt_with_params, "BEGIN;", 6) == 0) { /* do nothing */ } else if (!in_trans) { if (issued_begin = CC_begin(conn), !issued_begin) { SC_set_error(stmt, STMT_EXEC_ERROR, "Handle prepare error", func); return SQL_ERROR; } } /* we are now in a transaction */ res = CC_send_query(conn, stmt->stmt_with_params, NULL, 0, SC_get_ancestor(stmt)); if (!QR_command_maybe_successful(res)) { #ifndef _LEGACY_MODE_ if (PG_VERSION_LT(conn, 8.0)) CC_abort(conn); #endif /* LEGACY_MODE_ */ SC_set_error(stmt, STMT_EXEC_ERROR, "Handle prepare error", func); QR_Destructor(res); return SQL_ERROR; } SC_set_Result(stmt, res); for (curres = res; !curres->num_fields; curres = curres->next) ; SC_set_Curres(stmt, curres); if (CC_does_autocommit(conn)) { if (issued_begin) CC_commit(conn); } stmt->status = STMT_FINISHED; return SQL_SUCCESS; } /* * The real execution. */ mylog("about to begin SC_execute\n"); retval = SC_execute(stmt); if (retval == SQL_ERROR) { stmt->exec_current_row = -1; *exec_end = TRUE; return retval; } res = SC_get_Result(stmt); /* special handling of result for keyset driven cursors */ if (SQL_CURSOR_KEYSET_DRIVEN == stmt->options.cursor_type && SQL_CONCUR_READ_ONLY != stmt->options.scroll_concurrency) { QResultClass *kres; if (kres = res->next, kres) { if (kres->fields) CI_Destructor(kres->fields); kres->fields = res->fields; res->fields = NULL; kres->num_fields = res->num_fields; res->next = NULL; SC_set_Result(stmt, kres); res = kres; } } #ifdef NOT_USED else if (SC_is_concat_prepare_exec(stmt)) { if (res && QR_command_maybe_successful(res)) { QResultClass *kres; kres = res->next; inolog("res->next=%p\n", kres); res->next = NULL; SC_set_Result(stmt, kres); res = kres; SC_set_prepared(stmt, PREPARED_PERMANENTLY); } else { retval = SQL_ERROR; if (stmt->execute_statement) free(stmt->execute_statement); stmt->execute_statement = NULL; } } #endif /* NOT_USED */ #if (ODBCVER >= 0x0300) ipdopts = SC_get_IPDF(stmt); if (ipdopts->param_status_ptr) { switch (retval) { case SQL_SUCCESS: ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS; break; case SQL_SUCCESS_WITH_INFO: ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_SUCCESS_WITH_INFO; break; default: ipdopts->param_status_ptr[stmt->exec_current_row] = SQL_PARAM_ERROR; break; } } #endif /* ODBCVER */ if (end_row = stmt->exec_end_row, end_row < 0) { apdopts = SC_get_APDF(stmt); end_row = (SQLINTEGER) apdopts->paramset_size - 1; } if (stmt->inaccurate_result || stmt->exec_current_row >= end_row) { *exec_end = TRUE; stmt->exec_current_row = -1; } else stmt->exec_current_row++; if (res) { #if (ODBCVER >= 0x0300) EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn); const char *cmd = QR_get_command(res); SQLLEN start_row; if (start_row = stmt->exec_start_row, start_row < 0) start_row = 0; if (retval == SQL_SUCCESS && NULL != cmd && start_row >= end_row && NULL != env && EN_is_odbc3(env)) { int count; if (sscanf(cmd , "UPDATE %d", &count) == 1) ; else if (sscanf(cmd , "DELETE %d", &count) == 1) ; else count = -1; if (0 == count) retval = SQL_NO_DATA; } #endif /* ODBCVER */ stmt->diag_row_count = res->recent_processed_row_count; } /* * The cursor's info was changed ? */ if (retval == SQL_SUCCESS && (stmt->options.cursor_type != cursor_type || stmt->options.scroll_concurrency != scroll_concurrency)) { SC_set_error(stmt, STMT_OPTION_VALUE_CHANGED, "cursor updatability changed", func); retval = SQL_SUCCESS_WITH_INFO; } return retval; }
RETCODE SQL_API PGAPI_Transact( HENV henv, HDBC hdbc, SQLUSMALLINT fType) { CSTR func = "PGAPI_Transact"; ConnectionClass *conn; char ok; 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 && CC_get_env(conn) == henv) if (PGAPI_Transact(henv, (HDBC) conn, fType) != SQL_SUCCESS) return SQL_ERROR; } return SQL_SUCCESS; } conn = (ConnectionClass *) hdbc; if (fType != SQL_COMMIT && fType != SQL_ROLLBACK) { 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_loves_visible_trans(conn) && CC_is_in_trans(conn)) { mylog("PGAPI_Transact: sending on conn %p '%d'\n", conn, fType); ok = (SQL_COMMIT == fType) ? CC_commit(conn) : CC_abort(conn); if (!ok) { /* error msg will be in the connection */ CC_on_abort(conn, NO_TRANS); CC_log_error(func, "", conn); return SQL_ERROR; } } return SQL_SUCCESS; }
SQLSMALLINT pgtype_to_ctype(StatementClass *stmt, OID type) { ConnectionClass *conn = SC_get_conn(stmt); ConnInfo *ci = &(conn->connInfo); #if (ODBCVER >= 0x0300) EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn); #endif /* ODBCVER */ switch (type) { case PG_TYPE_INT8: #if (ODBCVER >= 0x0300) if (!conn->ms_jet) return ALLOWED_C_BIGINT; #endif /* ODBCVER */ return SQL_C_CHAR; case PG_TYPE_NUMERIC: return SQL_C_CHAR; case PG_TYPE_INT2: return SQL_C_SSHORT; case PG_TYPE_OID: case PG_TYPE_XID: return SQL_C_ULONG; case PG_TYPE_INT4: return SQL_C_SLONG; case PG_TYPE_FLOAT4: return SQL_C_FLOAT; case PG_TYPE_FLOAT8: return SQL_C_DOUBLE; case PG_TYPE_DATE: #if (ODBCVER >= 0x0300) if (EN_is_odbc3(env)) return SQL_C_TYPE_DATE; #endif /* ODBCVER */ return SQL_C_DATE; case PG_TYPE_TIME: #if (ODBCVER >= 0x0300) if (EN_is_odbc3(env)) return SQL_C_TYPE_TIME; #endif /* ODBCVER */ return SQL_C_TIME; case PG_TYPE_ABSTIME: case PG_TYPE_DATETIME: case PG_TYPE_TIMESTAMP_NO_TMZONE: case PG_TYPE_TIMESTAMP: #if (ODBCVER >= 0x0300) if (EN_is_odbc3(env)) return SQL_C_TYPE_TIMESTAMP; #endif /* ODBCVER */ return SQL_C_TIMESTAMP; case PG_TYPE_MONEY: return SQL_C_FLOAT; case PG_TYPE_BOOL: return ci->drivers.bools_as_char ? SQL_C_CHAR : SQL_C_BIT; case PG_TYPE_BYTEA: return SQL_C_BINARY; case PG_TYPE_LO_UNDEFINED: return SQL_C_BINARY; #ifdef UNICODE_SUPPORT case PG_TYPE_BPCHAR: case PG_TYPE_VARCHAR: case PG_TYPE_TEXT: if (CC_is_in_unicode_driver(conn) #ifdef NOT_USED && ! stmt->catalog_result #endif /* NOT USED */ ) return SQL_C_WCHAR; return SQL_C_CHAR; #endif /* UNICODE_SUPPORT */ case PG_TYPE_UUID: #if (ODBCVER >= 0x0350) if (!conn->ms_jet) return SQL_C_GUID; #endif /* ODBCVER */ return SQL_C_CHAR; default: /* hack until permanent type is available */ if (type == stmt->hdbc->lobj_type) return SQL_C_BINARY; /* Experimental, Does this work ? */ #ifdef EXPERIMENTAL_CURRENTLY if (ALLOW_WCHAR(conn)) return SQL_C_WCHAR; #endif /* EXPERIMENTAL_CURRENTLY */ return SQL_C_CHAR; } }
/* * There are two ways of calling this function: * * 1. When going through the supported PG types (SQLGetTypeInfo) * * 2. When taking any type id (SQLColumns, SQLGetData) * * The first type will always work because all the types defined are returned here. * The second type will return a default based on global parameter when it does not * know. This allows for supporting * types that are unknown. All other pg routines in here return a suitable default. */ SQLSMALLINT pgtype_to_concise_type(StatementClass *stmt, OID type, int col) { ConnectionClass *conn = SC_get_conn(stmt); ConnInfo *ci = &(conn->connInfo); #if (ODBCVER >= 0x0300) EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn); #endif /* ODBCVER */ switch (type) { case PG_TYPE_CHAR: case PG_TYPE_CHAR2: case PG_TYPE_CHAR4: case PG_TYPE_CHAR8: return ALLOW_WCHAR(conn) ? SQL_WCHAR : SQL_CHAR; case PG_TYPE_NAME: return ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR; #ifdef UNICODE_SUPPORT case PG_TYPE_BPCHAR: if (col >= 0 && getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size) return ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR; return ALLOW_WCHAR(conn) ? SQL_WCHAR : SQL_CHAR; case PG_TYPE_VARCHAR: if (col >= 0 && getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size) return ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR; return ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR; case PG_TYPE_TEXT: return ci->drivers.text_as_longvarchar ? (ALLOW_WCHAR(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR) : (ALLOW_WCHAR(conn) ? SQL_WVARCHAR : SQL_VARCHAR); #else case PG_TYPE_BPCHAR: if (col >= 0 && getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size) return SQL_LONGVARCHAR; return SQL_CHAR; case PG_TYPE_VARCHAR: if (col >= 0 && getCharColumnSize(stmt, type, col, UNKNOWNS_AS_MAX) > ci->drivers.max_varchar_size) return SQL_LONGVARCHAR; return SQL_VARCHAR; case PG_TYPE_TEXT: return ci->drivers.text_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR; #endif /* UNICODE_SUPPORT */ case PG_TYPE_BYTEA: if (ci->bytea_as_longvarbinary) return SQL_LONGVARBINARY; else return SQL_VARBINARY; case PG_TYPE_LO_UNDEFINED: return SQL_LONGVARBINARY; case PG_TYPE_INT2: return SQL_SMALLINT; case PG_TYPE_OID: case PG_TYPE_XID: case PG_TYPE_INT4: return SQL_INTEGER; /* Change this to SQL_BIGINT for ODBC v3 bjm 2001-01-23 */ case PG_TYPE_INT8: if (ci->int8_as != 0) return ci->int8_as; if (conn->ms_jet) return SQL_NUMERIC; /* maybe a little better than SQL_VARCHAR */ #if (ODBCVER >= 0x0300) return SQL_BIGINT; #else return SQL_VARCHAR; #endif /* ODBCVER */ case PG_TYPE_NUMERIC: return SQL_NUMERIC; case PG_TYPE_FLOAT4: return SQL_REAL; case PG_TYPE_FLOAT8: return SQL_FLOAT; case PG_TYPE_DATE: #if (ODBCVER >= 0x0300) if (EN_is_odbc3(env)) return SQL_TYPE_DATE; #endif /* ODBCVER */ return SQL_DATE; case PG_TYPE_TIME: #if (ODBCVER >= 0x0300) if (EN_is_odbc3(env)) return SQL_TYPE_TIME; #endif /* ODBCVER */ return SQL_TIME; case PG_TYPE_ABSTIME: case PG_TYPE_DATETIME: case PG_TYPE_TIMESTAMP_NO_TMZONE: case PG_TYPE_TIMESTAMP: #if (ODBCVER >= 0x0300) if (EN_is_odbc3(env)) return SQL_TYPE_TIMESTAMP; #endif /* ODBCVER */ return SQL_TIMESTAMP; case PG_TYPE_MONEY: return SQL_FLOAT; case PG_TYPE_BOOL: return ci->drivers.bools_as_char ? SQL_CHAR : SQL_BIT; case PG_TYPE_XML: return CC_is_in_unicode_driver(conn) ? SQL_WLONGVARCHAR : SQL_LONGVARCHAR; case PG_TYPE_INET: case PG_TYPE_CIDR: case PG_TYPE_MACADDR: return CC_is_in_unicode_driver(conn) ? SQL_WVARCHAR : SQL_VARCHAR; case PG_TYPE_UUID: #if (ODBCVER >= 0x0350) return SQL_GUID; #endif /* ODBCVER */ return CC_is_in_unicode_driver(conn) ? SQL_WVARCHAR : SQL_VARCHAR; default: /* * first, check to see if 'type' is in list. If not, look up * with query. Add oid, name to list. If it's already in * list, just return. */ /* hack until permanent type is available */ if (type == stmt->hdbc->lobj_type) return SQL_LONGVARBINARY; #ifdef EXPERIMENTAL_CURRENTLY if (ALLOW_WCHAR(conn)) return ci->drivers.unknowns_as_longvarchar ? SQL_WLONGVARCHAR : SQL_WVARCHAR; #endif /* EXPERIMENTAL_CURRENTLY */ return ci->drivers.unknowns_as_longvarchar ? SQL_LONGVARCHAR : SQL_VARCHAR; } }
SQLSMALLINT pgtype_attr_to_ctype(const ConnectionClass *conn, OID type, int atttypmod) { const ConnInfo *ci = &(conn->connInfo); EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn); #ifdef PG_INTERVAL_AS_SQL_INTERVAL SQLSMALLINT ctype; #endif /* PG_INTERVAL_A_SQL_INTERVAL */ switch (type) { case PG_TYPE_INT8: if (!conn->ms_jet) return ALLOWED_C_BIGINT; return SQL_C_CHAR; case PG_TYPE_NUMERIC: return SQL_C_CHAR; case PG_TYPE_INT2: return SQL_C_SSHORT; case PG_TYPE_OID: case PG_TYPE_XID: return SQL_C_ULONG; case PG_TYPE_INT4: return SQL_C_SLONG; case PG_TYPE_FLOAT4: return SQL_C_FLOAT; case PG_TYPE_FLOAT8: return SQL_C_DOUBLE; case PG_TYPE_DATE: if (EN_is_odbc3(env)) return SQL_C_TYPE_DATE; return SQL_C_DATE; case PG_TYPE_TIME: if (EN_is_odbc3(env)) return SQL_C_TYPE_TIME; return SQL_C_TIME; case PG_TYPE_ABSTIME: case PG_TYPE_DATETIME: case PG_TYPE_TIMESTAMP_NO_TMZONE: case PG_TYPE_TIMESTAMP: if (EN_is_odbc3(env)) return SQL_C_TYPE_TIMESTAMP; return SQL_C_TIMESTAMP; case PG_TYPE_MONEY: return SQL_C_FLOAT; case PG_TYPE_BOOL: return ci->drivers.bools_as_char ? SQL_C_CHAR : SQL_C_BIT; case PG_TYPE_BYTEA: return SQL_C_BINARY; case PG_TYPE_LO_UNDEFINED: return SQL_C_BINARY; case PG_TYPE_BPCHAR: case PG_TYPE_VARCHAR: case PG_TYPE_TEXT: return ansi_to_wtype(conn, SQL_C_CHAR); case PG_TYPE_UUID: if (!conn->ms_jet) return SQL_C_GUID; return ansi_to_wtype(conn, SQL_C_CHAR); case PG_TYPE_INTERVAL: #ifdef PG_INTERVAL_AS_SQL_INTERVAL if (ctype = get_interval_type(atttypmod, NULL), 0 != ctype) return ctype; #endif /* PG_INTERVAL_AS_SQL_INTERVAL */ return ansi_to_wtype(conn, SQL_CHAR); default: /* hack until permanent type is available */ if (type == conn->lobj_type) return SQL_C_BINARY; /* Experimental, Does this work ? */ #ifdef EXPERIMENTAL_CURRENTLY return ansi_to_wtype(conn, SQL_C_CHAR); #endif /* EXPERIMENTAL_CURRENTLY */ return SQL_C_CHAR; } }
SQLSMALLINT pgtype_attr_to_concise_type(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as) { const ConnInfo *ci = &(conn->connInfo); EnvironmentClass *env = (EnvironmentClass *) CC_get_env(conn); #ifdef PG_INTERVAL_AS_SQL_INTERVAL SQLSMALLINT sqltype; #endif /* PG_INTERVAL_AS_SQL_INTERVAL */ BOOL bLongVarchar, bFixed = FALSE; switch (type) { case PG_TYPE_CHAR: return ansi_to_wtype(conn, SQL_CHAR); case PG_TYPE_NAME: case PG_TYPE_REFCURSOR: return ansi_to_wtype(conn, SQL_VARCHAR); case PG_TYPE_BPCHAR: bFixed = TRUE; case PG_TYPE_VARCHAR: if (getCharColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as) > ci->drivers.max_varchar_size) bLongVarchar = TRUE; else bLongVarchar = FALSE; return ansi_to_wtype(conn, bLongVarchar ? SQL_LONGVARCHAR : (bFixed ? SQL_CHAR : SQL_VARCHAR)); case PG_TYPE_TEXT: bLongVarchar = ci->drivers.text_as_longvarchar; if (bLongVarchar) { int column_size = getCharColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as); if (column_size > 0 && column_size <= ci->drivers.max_varchar_size) bLongVarchar = FALSE; } return ansi_to_wtype(conn, bLongVarchar ? SQL_LONGVARCHAR : SQL_VARCHAR); case PG_TYPE_BYTEA: if (ci->bytea_as_longvarbinary) return SQL_LONGVARBINARY; else return SQL_VARBINARY; case PG_TYPE_LO_UNDEFINED: return SQL_LONGVARBINARY; case PG_TYPE_INT2: return SQL_SMALLINT; case PG_TYPE_OID: case PG_TYPE_XID: case PG_TYPE_INT4: return SQL_INTEGER; /* Change this to SQL_BIGINT for ODBC v3 bjm 2001-01-23 */ case PG_TYPE_INT8: if (ci->int8_as != 0) return ci->int8_as; if (conn->ms_jet) return SQL_NUMERIC; /* maybe a little better than SQL_VARCHAR */ return SQL_BIGINT; case PG_TYPE_NUMERIC: return SQL_NUMERIC; case PG_TYPE_FLOAT4: return SQL_REAL; case PG_TYPE_FLOAT8: return SQL_FLOAT; case PG_TYPE_DATE: if (EN_is_odbc3(env)) return SQL_TYPE_DATE; return SQL_DATE; case PG_TYPE_TIME: if (EN_is_odbc3(env)) return SQL_TYPE_TIME; return SQL_TIME; case PG_TYPE_ABSTIME: case PG_TYPE_DATETIME: case PG_TYPE_TIMESTAMP_NO_TMZONE: case PG_TYPE_TIMESTAMP: if (EN_is_odbc3(env)) return SQL_TYPE_TIMESTAMP; return SQL_TIMESTAMP; case PG_TYPE_MONEY: return SQL_FLOAT; case PG_TYPE_BOOL: return ci->drivers.bools_as_char ? SQL_VARCHAR : SQL_BIT; case PG_TYPE_XML: return ansi_to_wtype(conn, SQL_LONGVARCHAR); case PG_TYPE_INET: case PG_TYPE_CIDR: case PG_TYPE_MACADDR: return ansi_to_wtype(conn, SQL_VARCHAR); case PG_TYPE_UUID: return SQL_GUID; case PG_TYPE_INTERVAL: #ifdef PG_INTERVAL_AS_SQL_INTERVAL if (sqltype = get_interval_type(atttypmod, NULL), 0 != sqltype) return sqltype; #endif /* PG_INTERVAL_AS_SQL_INTERVAL */ return ansi_to_wtype(conn, SQL_VARCHAR); default: /* * first, check to see if 'type' is in list. If not, look up * with query. Add oid, name to list. If it's already in * list, just return. */ /* hack until permanent type is available */ if (type == conn->lobj_type) return SQL_LONGVARBINARY; bLongVarchar = ci->drivers.unknowns_as_longvarchar; if (bLongVarchar) { int column_size = getCharColumnSizeX(conn, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as); if (column_size > 0 && column_size <= ci->drivers.max_varchar_size) bLongVarchar = FALSE; } #ifdef EXPERIMENTAL_CURRENTLY return ansi_to_wtype(conn, bLongVarchar ? SQL_LONGVARCHAR : SQL_VARCHAR); #endif /* EXPERIMENTAL_CURRENTLY */ return bLongVarchar ? SQL_LONGVARCHAR : SQL_VARCHAR; } }