📄 results.c
字号:
/* * Module: results.c * * Description: This module contains functions related to * retrieving result information through the ODBC API. * * Classes: n/a * * API functions: SQLRowCount, SQLNumResultCols, SQLDescribeCol, * SQLColAttributes, SQLGetData, SQLFetch, SQLExtendedFetch, * SQLMoreResults, SQLSetPos, SQLSetScrollOptions(NI), * SQLSetCursorName, SQLGetCursorName * * Comments: See "notice.txt" for copyright and license information. *------- */#include "psqlodbc.h"#include <string.h>#include "psqlodbc.h"#include "dlg_specific.h"#include "environ.h"#include "connection.h"#include "statement.h"#include "bind.h"#include "qresult.h"#include "convert.h"#include "pgtypes.h"#include <stdio.h>#include <limits.h>#include "pgapifunc.h"RETCODE SQL_APIPGAPI_RowCount( HSTMT hstmt, SQLLEN FAR * pcrow){ CSTR func = "PGAPI_RowCount"; StatementClass *stmt = (StatementClass *) hstmt; QResultClass *res; ConnInfo *ci; mylog("%s: entering...\n", func); if (!stmt) { SC_log_error(func, NULL_STRING, NULL); return SQL_INVALID_HANDLE; } ci = &(SC_get_conn(stmt)->connInfo); if (stmt->proc_return > 0) { if (pcrow){ *pcrow = 0;inolog("returning RowCount=%d\n", *pcrow);} return SQL_SUCCESS; } res = SC_get_Curres(stmt); if (res && pcrow) { if (stmt->status != STMT_FINISHED) { SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't get row count while statement is still executing.", func); return SQL_ERROR; } if (res->recent_processed_row_count >= 0) { *pcrow = res->recent_processed_row_count; mylog("**** %s: THE ROWS: *pcrow = %d\n", func, *pcrow); return SQL_SUCCESS; } else if (QR_NumResultCols(res) > 0) { *pcrow = SC_is_fetchcursor(stmt) ? -1 : QR_get_num_total_tuples(res) - res->dl_count; mylog("RowCount=%d\n", *pcrow); return SQL_SUCCESS; } } *pcrow = -1; return SQL_SUCCESS;}static BOOL SC_pre_execute_ok(StatementClass *stmt, BOOL build_fi, int col_idx, const char *func){ Int2 num_fields = SC_pre_execute(stmt); QResultClass *result = SC_get_Curres(stmt); BOOL exec_ok = TRUE; mylog("%s: result = %p, status = %d, numcols = %d\n", func, result, stmt->status, result != NULL ? QR_NumResultCols(result) : -1); /****if ((!result) || ((stmt->status != STMT_FINISHED) && (stmt->status != STMT_PREMATURE))) ****/ if (!QR_command_maybe_successful(result) || num_fields < 0) { /* no query has been executed on this statement */ SC_set_error(stmt, STMT_EXEC_ERROR, "No query has been executed with that handle", func); exec_ok = FALSE; } else if (col_idx >= 0 && col_idx < num_fields) { OID reloid = QR_get_relid(result, col_idx); IRDFields *irdflds = SC_get_IRDF(stmt); FIELD_INFO *fi; TABLE_INFO *ti = NULL;inolog("build_fi=%d reloid=%u\n", build_fi, reloid); if (build_fi && 0 != QR_get_attid(result, col_idx)) getCOLIfromTI(func, NULL, stmt, reloid, &ti);inolog("nfields=%d\n", irdflds->nfields); if (irdflds->fi && col_idx < (int) irdflds->nfields) { fi = irdflds->fi[col_idx]; if (fi) { if (ti) { if (NULL == fi->ti) fi->ti = ti; if (!FI_is_applicable(fi) && 0 != (ti->flags & TI_COLATTRIBUTE)) fi->flag |= FIELD_COL_ATTRIBUTE; } fi->basetype = QR_get_field_type(result, col_idx); if (0 == fi->columntype) fi->columntype = fi->basetype; } } } return exec_ok;}/* * This returns the number of columns associated with the database * attached to "hstmt". */RETCODE SQL_APIPGAPI_NumResultCols( HSTMT hstmt, SQLSMALLINT FAR * pccol){ CSTR func = "PGAPI_NumResultCols"; StatementClass *stmt = (StatementClass *) hstmt; QResultClass *result; char parse_ok; ConnInfo *ci; RETCODE ret = SQL_SUCCESS; mylog("%s: entering...\n", func); if (!stmt) { SC_log_error(func, NULL_STRING, NULL); return SQL_INVALID_HANDLE; } ci = &(SC_get_conn(stmt)->connInfo); SC_clear_error(stmt);#define return DONT_CALL_RETURN_FROM_HERE??? /* StartRollbackState(stmt); */ if (stmt->proc_return > 0) { *pccol = 0; goto cleanup; } parse_ok = FALSE; if (!stmt->catalog_result && SC_is_parse_forced(stmt) && stmt->statement_type == STMT_TYPE_SELECT) { if (SC_parsed_status(stmt) == STMT_PARSE_NONE) { mylog("%s: calling parse_statement on stmt=%p\n", func, stmt); parse_statement(stmt, FALSE); } if (SC_parsed_status(stmt) != STMT_PARSE_FATAL) { parse_ok = TRUE; *pccol = SC_get_IRDF(stmt)->nfields; mylog("PARSE: %s: *pccol = %d\n", func, *pccol); } } if (!parse_ok) { if (!SC_pre_execute_ok(stmt, FALSE, -1, func)) { ret = SQL_ERROR; goto cleanup; } result = SC_get_Curres(stmt); *pccol = QR_NumPublicResultCols(result); }cleanup:#undef return if (stmt->internal) ret = DiscardStatementSvp(stmt, ret, FALSE); return ret;}/* * Return information about the database column the user wants * information about. */RETCODE SQL_APIPGAPI_DescribeCol( HSTMT hstmt, SQLUSMALLINT icol, SQLCHAR FAR * szColName, SQLSMALLINT cbColNameMax, SQLSMALLINT FAR * pcbColName, SQLSMALLINT FAR * pfSqlType, SQLULEN FAR * pcbColDef, SQLSMALLINT FAR * pibScale, SQLSMALLINT FAR * pfNullable){ CSTR func = "PGAPI_DescribeCol"; /* gets all the information about a specific column */ StatementClass *stmt = (StatementClass *) hstmt; ConnectionClass *conn; IRDFields *irdflds; QResultClass *res = NULL; char *col_name = NULL; OID fieldtype = 0; SQLLEN column_size = 0; SQLINTEGER decimal_digits = 0; ConnInfo *ci; FIELD_INFO *fi; char buf[255]; int len = 0; RETCODE result = SQL_SUCCESS; mylog("%s: entering.%d..\n", func, icol); if (!stmt) { SC_log_error(func, NULL_STRING, NULL); return SQL_INVALID_HANDLE; } conn = SC_get_conn(stmt); ci = &(conn->connInfo); SC_clear_error(stmt);#define return DONT_CALL_RETURN_FROM_HERE??? irdflds = SC_get_IRDF(stmt);#if (ODBCVER >= 0x0300) if (0 == icol) /* bookmark column */ { SQLSMALLINT fType = stmt->options.use_bookmarks == SQL_UB_VARIABLE ? SQL_BINARY : SQL_INTEGER;inolog("answering bookmark info\n"); if (szColName && cbColNameMax > 0) *szColName = '\0'; if (pcbColName) *pcbColName = 0; if (pfSqlType) *pfSqlType = fType; if (pcbColDef) *pcbColDef = 10; if (pibScale) *pibScale = 0; if (pfNullable) *pfNullable = SQL_NO_NULLS; result = SQL_SUCCESS; goto cleanup; }#endif /* ODBCVER */ /* * Dont check for bookmark column. This is the responsibility of the * driver manager. */ icol--; /* use zero based column numbers */ fi = NULL; if (icol < irdflds->nfields && irdflds->fi) fi = irdflds->fi[icol]; if (!FI_is_applicable(fi) && !stmt->catalog_result && SC_is_parse_forced(stmt) && STMT_TYPE_SELECT == stmt->statement_type) { if (SC_parsed_status(stmt) == STMT_PARSE_NONE) { mylog("%s: calling parse_statement on stmt=%p\n", func, stmt); parse_statement(stmt, FALSE); } mylog("PARSE: DescribeCol: icol=%d, stmt=%p, stmt->nfld=%d, stmt->fi=%p\n", icol, stmt, irdflds->nfields, irdflds->fi); if (SC_parsed_status(stmt) != STMT_PARSE_FATAL && irdflds->fi) { if (icol < irdflds->nfields) fi = irdflds->fi[icol]; else { SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.", func); result = SQL_ERROR; goto cleanup; } mylog("DescribeCol: getting info for icol=%d\n", icol); } } if (!FI_is_applicable(fi)) { /* * If couldn't parse it OR the field being described was not parsed * (i.e., because it was a function or expression, etc, then do it the * old fashioned way. */ BOOL build_fi = PROTOCOL_74(ci) && (NULL != pfNullable || NULL != pfSqlType); fi = NULL; if (!SC_pre_execute_ok(stmt, build_fi, icol, func)) { result = SQL_ERROR; goto cleanup; } res = SC_get_Curres(stmt); if (icol >= QR_NumPublicResultCols(res)) { SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR, "Invalid column number in DescribeCol.", NULL); snprintf(buf, sizeof(buf), "Col#=%d, #Cols=%d,%d keys=%d", icol, QR_NumResultCols(res), QR_NumPublicResultCols(res), res->num_key_fields); SC_log_error(func, buf, stmt); result = SQL_ERROR; goto cleanup; } if (icol < irdflds->nfields && irdflds->fi) fi = irdflds->fi[icol]; } if (FI_is_applicable(fi)) { fieldtype = (conn->lobj_type == fi->columntype) ? fi->columntype : FI_type(fi); if (NAME_IS_VALID(fi->column_alias)) col_name = GET_NAME(fi->column_alias); else col_name = GET_NAME(fi->column_name); column_size = fi->column_size; decimal_digits = fi->decimal_digits; mylog("PARSE: fieldtype=%d, col_name='%s', column_size=%d\n", fieldtype, col_name, column_size); } else { col_name = QR_get_fieldname(res, icol); fieldtype = QR_get_field_type(res, icol); /* atoi(ci->unknown_sizes) */ column_size = pgtype_column_size(stmt, fieldtype, icol, ci->drivers.unknown_sizes); decimal_digits = pgtype_decimal_digits(stmt, fieldtype, icol); } mylog("describeCol: col %d fieldname = '%s'\n", icol, col_name); mylog("describeCol: col %d fieldtype = %d\n", icol, fieldtype); mylog("describeCol: col %d column_size = %d\n", icol, column_size); result = SQL_SUCCESS; /* * COLUMN NAME */ len = (int) strlen(col_name); if (pcbColName) *pcbColName = len; if (szColName && cbColNameMax > 0) { strncpy_null(szColName, col_name, cbColNameMax); if (len >= cbColNameMax) { result = SQL_SUCCESS_WITH_INFO; SC_set_error(stmt, STMT_TRUNCATED, "The buffer was too small for the colName.", func); } } /* * CONCISE(SQL) TYPE */ if (pfSqlType) { *pfSqlType = pgtype_to_concise_type(stmt, fieldtype, icol); mylog("describeCol: col %d *pfSqlType = %d\n", icol, *pfSqlType); } /* * COLUMN SIZE(PRECISION in 2.x) */ if (pcbColDef) { if (column_size < 0) column_size = 0; /* "I dont know" */ *pcbColDef = column_size; mylog("describeCol: col %d *pcbColDef = %d\n", icol, *pcbColDef); } /* * DECIMAL DIGITS(SCALE in 2.x) */ if (pibScale) { if (decimal_digits < 0) decimal_digits = 0; *pibScale = (SQLSMALLINT) decimal_digits; mylog("describeCol: col %d *pibScale = %d\n", icol, *pibScale); } /* * NULLABILITY */ if (pfNullable) { if (SC_has_outer_join(stmt)) *pfNullable = TRUE; else *pfNullable = fi ? fi->nullable : pgtype_nullable(stmt, fieldtype); mylog("describeCol: col %d *pfNullable = %d\n", icol, *pfNullable); }cleanup:#undef return if (stmt->internal) result = DiscardStatementSvp(stmt, result, FALSE); return result;}/* Returns result column descriptor information for a result set. */RETCODE SQL_APIPGAPI_ColAttributes( HSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType, PTR rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT FAR * pcbDesc, SQLLEN FAR * pfDesc){ CSTR func = "PGAPI_ColAttributes"; StatementClass *stmt = (StatementClass *) hstmt; IRDFields *irdflds; OID field_type = 0; Int2 col_idx; ConnectionClass *conn; ConnInfo *ci; int unknown_sizes; int cols = 0; RETCODE result; const char *p = NULL; SQLLEN value = 0; const FIELD_INFO *fi = NULL; const TABLE_INFO *ti = NULL; QResultClass *res; mylog("%s: entering..col=%d %d len=%d.\n", func, icol, fDescType, cbDescMax); if (!stmt) { SC_log_error(func, NULL_STRING, NULL); return SQL_INVALID_HANDLE; } if (pcbDesc) *pcbDesc = 0; irdflds = SC_get_IRDF(stmt); conn = SC_get_conn(stmt); ci = &(conn->connInfo); /* * Dont check for bookmark column. This is the responsibility of the * driver manager. For certain types of arguments, the column number * is ignored anyway, so it may be 0. */ res = SC_get_Curres(stmt);#if (ODBCVER >= 0x0300) if (0 == icol && SQL_DESC_COUNT != fDescType) /* bookmark column */ {inolog("answering bookmark info\n"); switch (fDescType) { case SQL_DESC_OCTET_LENGTH: if (pfDesc) *pfDesc = 4; break; case SQL_DESC_TYPE: if (pfDesc) *pfDesc = stmt->options.use_bookmarks == SQL_UB_VARIABLE ? SQL_BINARY : SQL_INTEGER; break; } return SQL_SUCCESS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -