Int4 getCharColumnSize(StatementClass *stmt, OID type, int col, int handle_unknown_size_as) { CSTR func = "getCharColumnSize"; int p = -1, attlen = -1, adtsize = -1, maxsize; QResultClass *result; ConnectionClass *conn = SC_get_conn(stmt); ConnInfo *ci = &(conn->connInfo); mylog("%s: type=%d, col=%d, unknown = %d\n", func, type, col, handle_unknown_size_as); /* Assign Maximum size based on parameters */ switch (type) { case PG_TYPE_TEXT: if (ci->drivers.text_as_longvarchar) maxsize = ci->drivers.max_longvarchar_size; else maxsize = ci->drivers.max_varchar_size; break; case PG_TYPE_VARCHAR: case PG_TYPE_BPCHAR: maxsize = ci->drivers.max_varchar_size; break; default: if (ci->drivers.unknowns_as_longvarchar) maxsize = ci->drivers.max_longvarchar_size; else maxsize = ci->drivers.max_varchar_size; break; } #ifdef UNICODE_SUPPORT if (CC_is_in_unicode_driver(conn) && isSqlServr() && maxsize > 4000) maxsize = 4000; #endif /* UNICODE_SUPPORT */ if (maxsize == TEXT_FIELD_SIZE + 1) /* magic length for testing */ { if (PG_VERSION_GE(SC_get_conn(stmt), 7.1)) maxsize = 0; else maxsize = TEXT_FIELD_SIZE; } /* * Static ColumnSize (i.e., the Maximum ColumnSize of the datatype) This * has nothing to do with a result set. */ if (col < 0) return maxsize; if (result = SC_get_Curres(stmt), NULL == result) return maxsize; /* * Catalog Result Sets -- use assigned column width (i.e., from * set_tuplefield_string) */ adtsize = QR_get_fieldsize(result, col); if (stmt->catalog_result) { if (adtsize > 0) return adtsize; return maxsize; } p = QR_get_display_size(result, col); /* longest */ attlen = QR_get_atttypmod(result, col); /* Size is unknown -- handle according to parameter */ if (attlen > 0) /* maybe the length is known */ { if (attlen >= p) return attlen; switch (type) { case PG_TYPE_VARCHAR: case PG_TYPE_BPCHAR: #if (ODBCVER >= 0x0300) return attlen; #else if (CC_is_in_unicode_driver(conn) || conn->ms_jet) return attlen; return p; #endif /* ODBCVER */ } } /* The type is really unknown */ switch (handle_unknown_size_as) { case UNKNOWNS_AS_DONTKNOW: return -1; case UNKNOWNS_AS_LONGEST: mylog("%s: LONGEST: p = %d\n", func, p); if (p > 0) return p; break; case UNKNOWNS_AS_MAX: break; default: return -1; } if (maxsize <= 0) return maxsize; switch (type) { case PG_TYPE_BPCHAR: case PG_TYPE_VARCHAR: case PG_TYPE_TEXT: return maxsize; } if (p > maxsize) maxsize = p; return maxsize; }
/* Execute a prepared SQL statement */ RETCODE SQL_API PGAPI_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. */ int nCallParse = doNothing; if (NOT_YET_PREPARED == stmt->prepared) { switch (nCallParse = HowToPrepareBeforeExec(stmt, TRUE)) { case shouldParse: if (retval = prepareParameters(stmt, TRUE), SQL_ERROR == retval) goto cleanup; break; } } mylog("prepareParameters was %s called, prepare state:%d\n", shouldParse == nCallParse ? "" : "not", 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); if (isSqlServr() && !stmt->internal && 0 != stmt->prepare && PG_VERSION_LT(conn, 8.4) && SC_can_parse_statement(stmt)) parse_sqlsvr(stmt); } /* * Clear any old result sets before executing. The prepare stage might've * created one. */ SC_set_Result(stmt, NULL); 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 = LENADDR_SHIFT(pcVal, offset + bind_size * current_row); else pcVal = LENADDR_SHIFT(pcVal, offset) + 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) { mylog("The %dth parameter of %d-row is data at exec(%d)\n", i, current_row, *pcVal); 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) { stmt->curr_param_result = 0; 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; }
static Int4 getCharColumnSizeX(const ConnectionClass *conn, OID type, int atttypmod, int adtsize_or_longestlen, int handle_unknown_size_as) { int p = -1, maxsize; const ConnInfo *ci = &(conn->connInfo); mylog("%s: type=%d, atttypmod=%d, adtsize_or=%d, unknown = %d\n", __FUNCTION__, type, atttypmod, adtsize_or_longestlen, handle_unknown_size_as); /* Assign Maximum size based on parameters */ switch (type) { case PG_TYPE_TEXT: if (ci->drivers.text_as_longvarchar) maxsize = ci->drivers.max_longvarchar_size; else maxsize = ci->drivers.max_varchar_size; break; case PG_TYPE_VARCHAR: case PG_TYPE_BPCHAR: maxsize = ci->drivers.max_varchar_size; break; default: if (ci->drivers.unknowns_as_longvarchar) maxsize = ci->drivers.max_longvarchar_size; else maxsize = ci->drivers.max_varchar_size; break; } #ifdef UNICODE_SUPPORT if (CC_is_in_unicode_driver(conn) && isSqlServr() && maxsize > 4000) maxsize = 4000; #endif /* UNICODE_SUPPORT */ if (maxsize == TEXT_FIELD_SIZE + 1) /* magic length for testing */ maxsize = 0; /* * Static ColumnSize (i.e., the Maximum ColumnSize of the datatype) This * has nothing to do with a result set. */ inolog("!!! atttypmod < 0 ?\n"); if (atttypmod < 0 && adtsize_or_longestlen < 0) return maxsize; inolog("!!! adtsize_or_logngest=%d\n", adtsize_or_longestlen); p = adtsize_or_longestlen; /* longest */ /* * Catalog Result Sets -- use assigned column width (i.e., from * set_tuplefield_string) */ inolog("!!! catalog_result=%d\n", handle_unknown_size_as); if (UNKNOWNS_AS_LONGEST == handle_unknown_size_as) { mylog("%s: LONGEST: p = %d\n", __FUNCTION__, p); if (p > 0 && (atttypmod < 0 || atttypmod > p)) return p; } if (TYPE_MAY_BE_ARRAY(type)) { if (p > 0) return p; return maxsize; } /* Size is unknown -- handle according to parameter */ if (atttypmod > 0) /* maybe the length is known */ { return atttypmod; } /* The type is really unknown */ switch (handle_unknown_size_as) { case UNKNOWNS_AS_DONTKNOW: return -1; case UNKNOWNS_AS_LONGEST: case UNKNOWNS_AS_MAX: break; default: return -1; } if (maxsize <= 0) return maxsize; switch (type) { case PG_TYPE_BPCHAR: case PG_TYPE_VARCHAR: case PG_TYPE_TEXT: return maxsize; } if (p > maxsize) maxsize = p; return maxsize; }