static void ARDFields_free(ARDFields * self) { inolog("ARDFields_free %p bookmark=%p", self, self->bookmark); if (self->bookmark) { free(self->bookmark); self->bookmark = NULL; } inolog(" hey"); /* * the memory pointed to by the bindings is not deallocated by the * driver but by the application that uses that driver, so we don't * have to care */ ARD_unbind_cols(self, TRUE); }
void TI_Destructor(TABLE_INFO **ti, int count) { int i; inolog("TI_Destructor count=%d\n", count); if (ti) { for (i = 0; i < count; i++) { if (ti[i]) { COL_INFO *coli = ti[i]->col_info; if (coli) { mylog("!!!refcnt %p:%d -> %d\n", coli, coli->refcnt, coli->refcnt - 1); coli->refcnt--; if (coli->refcnt <= 0 && 0 == coli->acc_time) /* acc_time == 0 means the table is dropped */ free_col_info_contents(coli); } NULL_THE_NAME(ti[i]->schema_name); NULL_THE_NAME(ti[i]->table_name); NULL_THE_NAME(ti[i]->table_alias); NULL_THE_NAME(ti[i]->bestitem); NULL_THE_NAME(ti[i]->bestqual); free(ti[i]); ti[i] = NULL; } } } }
void TI_Destructor(TABLE_INFO **ti, int count) { int i; inolog("TI_Destructor count=%d\n", count); if (ti) { for (i = 0; i < count; i++) { if (ti[i]) { COL_INFO *coli = ti[i]->col_info; if (coli) { mylog("!!!refcnt %p:%d -> %d\n", coli, coli->refcnt, coli->refcnt - 1); coli->refcnt--; } NULL_THE_NAME(ti[i]->schema_name); NULL_THE_NAME(ti[i]->table_name); NULL_THE_NAME(ti[i]->table_alias); NULL_THE_NAME(ti[i]->bestitem); NULL_THE_NAME(ti[i]->bestqual); free(ti[i]); ti[i] = NULL; } } } }
void FI_Destructor(FIELD_INFO **fi, int count, BOOL freeFI) { int i; inolog("FI_Destructor count=%d\n", count); if (fi) { for (i = 0; i < count; i++) { if (fi[i]) { NULL_THE_NAME(fi[i]->column_name); NULL_THE_NAME(fi[i]->column_alias); NULL_THE_NAME(fi[i]->schema_name); NULL_THE_NAME(fi[i]->before_dot); if (freeFI) { free(fi[i]); fi[i] = NULL; } } } if (freeFI) free(fi); } }
/* * This function should really talk to the dbms to determine the number of * "parameter markers" (not bound parameters) in the statement. But, since * Postgres doesn't support that, the driver should just count the number of markers * and return that. The reason the driver just can't say this function is unsupported * like it does for SQLDescribeParam is that some applications don't care and try * to call it anyway. * If the statement does not have parameters, it should just return 0. */ RETCODE SQL_API PGAPI_NumParams( HSTMT hstmt, SQLSMALLINT FAR * pcpar) { StatementClass *stmt = (StatementClass *) hstmt; CSTR func = "PGAPI_NumParams"; mylog("%s: entering...\n", func); if (!stmt) { SC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } if (pcpar) *pcpar = 0; else { SC_set_error(stmt, STMT_EXEC_ERROR, "parameter count address is null", func); return SQL_ERROR; } inolog("num_params=%d,%d\n", stmt->num_params, stmt->proc_return); if (stmt->num_params >= 0) *pcpar = stmt->num_params; else if (!stmt->statement) { /* no statement has been allocated */ SC_set_error(stmt, STMT_SEQUENCE_ERROR, "PGAPI_NumParams called with no statement ready.", func); return SQL_ERROR; } else { po_ind_t multi = FALSE, proc_return = 0; stmt->proc_return = 0; SC_scanQueryAndCountParams(stmt->statement, SC_get_conn(stmt), NULL, pcpar, &multi, &proc_return); stmt->num_params = *pcpar; stmt->proc_return = proc_return; stmt->multi_statement = multi; if (multi) SC_no_parse_tricky(stmt); } inolog("num_params=%d,%d\n", stmt->num_params, stmt->proc_return); return SQL_SUCCESS; }
/* Performs the equivalent of SQLPrepare, followed by SQLExecute. */ RETCODE SQL_API PGAPI_ExecDirect( HSTMT hstmt, const SQLCHAR FAR * szSqlStr, SQLINTEGER cbSqlStr, UWORD flag) { StatementClass *stmt = (StatementClass *) hstmt; RETCODE result; CSTR func = "PGAPI_ExecDirect"; const ConnectionClass *conn = SC_get_conn(stmt); mylog("%s: entering...%x\n", func, flag); if (result = SC_initialize_and_recycle(stmt), SQL_SUCCESS != result) return result; /* * keep a copy of the un-parametrized statement, in case they try to * execute this statement again */ stmt->statement = make_string(szSqlStr, cbSqlStr, NULL, 0); inolog("a2\n"); if (!stmt->statement) { SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "No memory available to store statement", func); return SQL_ERROR; } mylog("**** %s: hstmt=%p, statement='%s'\n", func, hstmt, stmt->statement); if (0 != (flag & PODBC_WITH_HOLD)) SC_set_with_hold(stmt); /* * If an SQLPrepare was performed prior to this, but was left in the * premature state because an error occurred prior to SQLExecute then * set the statement to finished so it can be recycled. */ if (stmt->status == STMT_PREMATURE) stmt->status = STMT_FINISHED; stmt->statement_type = statement_type(stmt->statement); /* Check if connection is onlyread (only selects are allowed) */ if (CC_is_onlyread(conn) && STMT_UPDATE(stmt)) { SC_set_error(stmt, STMT_EXEC_ERROR, "Connection is readonly, only select statements are allowed.", func); return SQL_ERROR; } mylog("%s: calling PGAPI_Execute...\n", func); flag = SC_is_with_hold(stmt) ? PODBC_WITH_HOLD : 0; result = PGAPI_Execute(hstmt, flag); mylog("%s: returned %hd from PGAPI_Execute\n", func, result); return result; }
void FI_Constructor(FIELD_INFO *self, BOOL reuse) { inolog("FI_Constructor reuse=%d\n", reuse); if (reuse) FI_Destructor(&self, 1, FALSE); memset(self, 0, sizeof(FIELD_INFO)); self->nullable = TRUE; self->columnkey = -1; }
void ARD_unbind_cols(ARDFields *self, BOOL freeall) { Int2 lf; inolog("ARD_unbind_cols freeall=%d allocated=%d bindings=%p", freeall, self->allocated, self->bindings); for (lf = 1; lf <= self->allocated; lf++) reset_a_column_binding(self, lf); if (freeall) { if (self->bindings) free(self->bindings); self->bindings = NULL; self->allocated = 0; } }
/* * recv more than 1 bytes using SSL. */ static int SOCK_SSL_recv(SocketClass *sock, void *buffer, int len) { CSTR func = "SOCK_SSL_recv"; int n, err, gerrno, retry_count = 0; retry: n = SSL_read(sock->ssl, buffer, len); err = SSL_get_error(sock->ssl, len); gerrno = SOCK_ERRNO; inolog("%s: %d get_error=%d Lasterror=%d\n", func, n, err, gerrno); switch (err) { case SSL_ERROR_NONE: break; case SSL_ERROR_WANT_READ: retry_count++; if (SOCK_wait_for_ready(sock, FALSE, retry_count) >= 0) goto retry; n = -1; break; case SSL_ERROR_WANT_WRITE: goto retry; break; case SSL_ERROR_SYSCALL: if (-1 != n) { n = -1; SOCK_ERRNO_SET(ECONNRESET); } break; case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: n = -1; SOCK_ERRNO_SET(ECONNRESET); break; default: n = -1; } return n; }
void GDATA_unbind_cols(GetDataInfo *self, BOOL freeall) { Int2 lf; inolog("GDATA_unbind_cols freeall=%d allocated=%d gdata=%p", freeall, self->allocated, self->gdata); if (self->fdata.ttlbuf) { free(self->fdata.ttlbuf); self->fdata.ttlbuf = NULL; } self->fdata.ttlbuflen = self->fdata.ttlbufused = 0; self->fdata.data_left = -1; for (lf = 1; lf <= self->allocated; lf++) reset_a_getdata_info(self, lf); if (freeall) { if (self->gdata) free(self->gdata); self->gdata = NULL; self->allocated = 0; } }
/* * 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); #define return DONT_CALL_RETURN_FROM_HERE??? #define RETURN(code) { retval = code; goto cleanup; } ENTER_CONN_CS(conn); /* 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 */ }
void TI_Destructor(TABLE_INFO **ti, int count) { int i; inolog("TI_Destructor count=%d\n", count); if (ti) { for (i = 0; i < count; i++) { if (ti[i]) { NULL_THE_NAME(ti[i]->schema_name); NULL_THE_NAME(ti[i]->table_name); NULL_THE_NAME(ti[i]->table_alias); NULL_THE_NAME(ti[i]->bestitem); NULL_THE_NAME(ti[i]->bestqual); free(ti[i]); ti[i] = NULL; } } } }
/* SQLAllocConnect/SQLAllocEnv/SQLAllocStmt -> SQLAllocHandle */ RETCODE SQL_API SQLAllocHandle(SQLSMALLINT HandleType, SQLHANDLE InputHandle, SQLHANDLE * OutputHandle) { CSTR func = "SQLAllocHandle"; RETCODE ret; ConnectionClass *conn; mylog("[[%s]]", func); switch (HandleType) { case SQL_HANDLE_ENV: ret = PGAPI_AllocEnv(OutputHandle); break; case SQL_HANDLE_DBC: ENTER_ENV_CS((EnvironmentClass *) InputHandle); ret = PGAPI_AllocConnect(InputHandle, OutputHandle); LEAVE_ENV_CS((EnvironmentClass *) InputHandle); break; case SQL_HANDLE_STMT: ENTER_CONN_CS((ConnectionClass *) InputHandle); ret = PGAPI_AllocStmt(InputHandle, OutputHandle); LEAVE_CONN_CS((ConnectionClass *) InputHandle); break; case SQL_HANDLE_DESC: conn = (ConnectionClass *) InputHandle; ENTER_CONN_CS(conn); ret = PGAPI_AllocDesc(InputHandle, OutputHandle); LEAVE_CONN_CS(conn); inolog("OutputHandle=%p\n", *OutputHandle); break; default: ret = SQL_ERROR; break; } return ret; }
int StartRollbackState(StatementClass *stmt) { CSTR func = "StartRollbackState"; int ret; ConnectionClass *conn; ConnInfo *ci = NULL; inolog("%s:%p->internal=%d\n", func, stmt, stmt->internal); conn = SC_get_conn(stmt); if (conn) ci = &conn->connInfo; ret = 0; if (!ci || ci->rollback_on_error < 0) /* default */ { if (conn && PG_VERSION_GE(conn, 8.0)) ret = 2; /* statement rollback */ else ret = 1; /* transaction rollback */ } else { ret = ci->rollback_on_error; if (2 == ret && PG_VERSION_LT(conn, 8.0)) ret = 1; } switch (ret) { case 1: SC_start_tc_stmt(stmt); break; case 2: SC_start_rb_stmt(stmt); break; } return ret; }
RETCODE SQL_API PGAPI_CopyDesc(SQLHDESC SourceDescHandle, SQLHDESC TargetDescHandle) { CSTR func = "PGAPI_CopyDesc"; RETCODE ret = SQL_ERROR; DescriptorClass *src, *target; ARDFields *ard_src, *ard_tgt; APDFields *apd_src, *apd_tgt; IPDFields *ipd_src, *ipd_tgt; mylog("%s: entering...\n", func); src = (DescriptorClass *) SourceDescHandle; target = (DescriptorClass *) TargetDescHandle; if (!src->type_defined) { mylog("source type undefined\n"); DC_set_error(target, DESC_EXEC_ERROR, "source handle type undefined"); return ret; } if (target->type_defined) { inolog("source type=%d -> target type=%d\n", src->desc_type, target->desc_type); if (SQL_ATTR_IMP_ROW_DESC == target->desc_type) { mylog("can't modify IRD\n"); DC_set_error(target, DESC_EXEC_ERROR, "can't copy to IRD"); return ret; } else if (target->desc_type != src->desc_type) { mylog("src type != target type\n"); DC_set_error(target, DESC_EXEC_ERROR, "src descriptor != target type"); return ret; } DC_Destructor(target); } ret = SQL_SUCCESS; switch (src->desc_type) { case SQL_ATTR_APP_ROW_DESC: inolog("src=%p target=%p type=%d", src, target, src->desc_type); if (!target->type_defined) { target->desc_type = src->desc_type; } ard_src = (ARDFields *) (src + 1); inolog(" rowset_size=%d bind_size=%d ope_ptr=%p off_ptr=%p\n", ard_src->size_of_rowset, ard_src->bind_size, ard_src->row_operation_ptr, ard_src->row_offset_ptr); ard_tgt = (ARDFields *) (target + 1); inolog(" target=%p", ard_tgt); ARDFields_copy(ard_src, ard_tgt); inolog(" offset_ptr=%p\n", ard_tgt->row_offset_ptr); break; case SQL_ATTR_APP_PARAM_DESC: if (!target->type_defined) { target->desc_type = src->desc_type; } apd_src = (APDFields *) (src + 1); apd_tgt = (APDFields *) (target + 1); APDFields_copy(apd_src, apd_tgt); break; case SQL_ATTR_IMP_PARAM_DESC: if (!target->type_defined) { target->desc_type = src->desc_type; } ipd_src = (IPDFields *) (src + 1); ipd_tgt = (IPDFields *) (target + 1); IPDFields_copy(ipd_src, ipd_tgt); break; default: mylog("invalid descriptor handle type=%d\n", src->desc_type); DC_set_error(target, DESC_EXEC_ERROR, "invalid descriptor type"); ret = SQL_ERROR; } if (SQL_SUCCESS == ret) target->type_defined = TRUE; return ret; }
/* Associate a user-supplied buffer with a database column. */ RETCODE SQL_API PGAPI_BindCol(HSTMT hstmt, SQLUSMALLINT icol, SQLSMALLINT fCType, PTR rgbValue, SQLLEN cbValueMax, SQLLEN FAR * pcbValue) { StatementClass *stmt = (StatementClass *) hstmt; CSTR func = "PGAPI_BindCol"; ARDFields *opts; GetDataInfo *gdata_info; BindInfoClass *bookmark; RETCODE ret = SQL_SUCCESS; mylog("%s: entering...\n", func); mylog("**** PGAPI_BindCol: stmt = %p, icol = %d\n", stmt, icol); mylog("**** : fCType=%d rgb=%p valusMax=%d pcb=%p\n", fCType, rgbValue, cbValueMax, pcbValue); if (!stmt) { SC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } opts = SC_get_ARDF(stmt); if (stmt->status == STMT_EXECUTING) { SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Can't bind columns while statement is still executing.", func); return SQL_ERROR; } #define return DONT_CALL_RETURN_FROM_HERE ??? SC_clear_error(stmt); /* If the bookmark column is being bound, then just save it */ if (icol == 0) { bookmark = opts->bookmark; if (rgbValue == NULL) { if (bookmark) { bookmark->buffer = NULL; bookmark->used = bookmark->indicator = NULL; } } else { /* Make sure it is the bookmark data type */ switch (fCType) { case SQL_C_BOOKMARK: #if (ODBCVER >= 0x0300) case SQL_C_VARBOOKMARK: #endif /* ODBCVER */ break; default: SC_set_error(stmt, STMT_PROGRAM_TYPE_OUT_OF_RANGE, "Bind column 0 is not of type SQL_C_BOOKMARK", func); inolog("Bind column 0 is type %d not of type SQL_C_BOOKMARK", fCType); ret = SQL_ERROR; goto cleanup; } bookmark = ARD_AllocBookmark(opts); bookmark->buffer = rgbValue; bookmark->used = bookmark->indicator = pcbValue; bookmark->buflen = cbValueMax; bookmark->returntype = fCType; } goto cleanup; } /* * Allocate enough bindings if not already done. Most likely, * execution of a statement would have setup the necessary bindings. * But some apps call BindCol before any statement is executed. */ if (icol > opts->allocated) extend_column_bindings(opts, icol); gdata_info = SC_get_GDTI(stmt); if (icol > gdata_info->allocated) extend_getdata_info(gdata_info, icol, FALSE); /* check to see if the bindings were allocated */ if (!opts->bindings) { SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Could not allocate memory for bindings.", func); ret = SQL_ERROR; goto cleanup; } /* use zero based col numbers from here out */ icol--; /* Reset for SQLGetData */ gdata_info->gdata[icol].data_left = -1; if (rgbValue == NULL) { /* we have to unbind the column */ opts->bindings[icol].buflen = 0; opts->bindings[icol].buffer = NULL; opts->bindings[icol].used = opts->bindings[icol].indicator = NULL; opts->bindings[icol].returntype = SQL_C_CHAR; opts->bindings[icol].precision = 0; opts->bindings[icol].scale = 0; if (gdata_info->gdata[icol].ttlbuf) free(gdata_info->gdata[icol].ttlbuf); gdata_info->gdata[icol].ttlbuf = NULL; gdata_info->gdata[icol].ttlbuflen = 0; gdata_info->gdata[icol].ttlbufused = 0; } else { /* ok, bind that column */ opts->bindings[icol].buflen = cbValueMax; opts->bindings[icol].buffer = rgbValue; opts->bindings[icol].used = opts->bindings[icol].indicator = pcbValue; opts->bindings[icol].returntype = fCType; opts->bindings[icol].precision = 0; #if (ODBCVER >= 0x0300) switch (fCType) { case SQL_C_NUMERIC: opts->bindings[icol].precision = 32; break; case SQL_C_TIMESTAMP: case SQL_C_INTERVAL_DAY_TO_SECOND: case SQL_C_INTERVAL_HOUR_TO_SECOND: case SQL_C_INTERVAL_MINUTE_TO_SECOND: case SQL_C_INTERVAL_SECOND: opts->bindings[icol].precision = 6; break; } #endif /* ODBCVER */ opts->bindings[icol].scale = 0; mylog(" bound buffer[%d] = %p\n", icol, opts->bindings[icol].buffer); } cleanup: #undef return if (stmt->internal) ret = DiscardStatementSvp(stmt, ret, FALSE); return ret; }
/* * Returns the description of a parameter marker. * This function is listed as not being supported by SQLGetFunctions() because it is * used to describe "parameter markers" (not bound parameters), in which case, * the dbms should return info on the markers. Since Postgres doesn't support that, * it is best to say this function is not supported and let the application assume a * data type (most likely varchar). */ RETCODE SQL_API PGAPI_DescribeParam(HSTMT hstmt, SQLUSMALLINT ipar, SQLSMALLINT FAR * pfSqlType, SQLULEN FAR * pcbParamDef, SQLSMALLINT FAR * pibScale, SQLSMALLINT FAR * pfNullable) { StatementClass *stmt = (StatementClass *) hstmt; CSTR func = "PGAPI_DescribeParam"; IPDFields *ipdopts; RETCODE ret = SQL_SUCCESS; int num_params; OID pgtype; mylog("%s: entering...%d\n", func, ipar); if (!stmt) { SC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } SC_clear_error(stmt); ipdopts = SC_get_IPDF(stmt); /*if ((ipar < 1) || (ipar > ipdopts->allocated))*/ num_params = stmt->num_params; if (num_params < 0) { SQLSMALLINT num_p; PGAPI_NumParams(stmt, &num_p); num_params = num_p; } if ((ipar < 1) || (ipar > num_params)) { inolog("num_params=%d\n", stmt->num_params); SC_set_error(stmt, STMT_BAD_PARAMETER_NUMBER_ERROR, "Invalid parameter number for PGAPI_DescribeParam.", func); return SQL_ERROR; } extend_iparameter_bindings(ipdopts, stmt->num_params); #define return DONT_CALL_RETURN_FROM_HERE??? /* StartRollbackState(stmt); */ if (NOT_YET_PREPARED == stmt->prepared) { decideHowToPrepare(stmt, FALSE); inolog("howTo=%d\n", SC_get_prepare_method(stmt)); switch (SC_get_prepare_method(stmt)) { case NAMED_PARSE_REQUEST: case PARSE_TO_EXEC_ONCE: case PARSE_REQ_FOR_INFO: if (ret = prepareParameters(stmt), SQL_ERROR == ret) goto cleanup; } } ipar--; pgtype = PIC_get_pgtype(ipdopts->parameters[ipar]); /* * This implementation is not very good, since it is supposed to * describe */ /* parameter markers, not bound parameters. */ if (pfSqlType) { inolog("[%d].SQLType=%d .PGType=%d\n", ipar, ipdopts->parameters[ipar].SQLType, pgtype); if (ipdopts->parameters[ipar].SQLType) *pfSqlType = ipdopts->parameters[ipar].SQLType; else if (pgtype) *pfSqlType = pgtype_to_concise_type(stmt, pgtype, PG_STATIC); else { ret = SQL_ERROR; SC_set_error(stmt, STMT_EXEC_ERROR, "Unfortunatley couldn't get this paramater's info", func); goto cleanup; } } if (pcbParamDef) { *pcbParamDef = 0; if (ipdopts->parameters[ipar].SQLType) *pcbParamDef = ipdopts->parameters[ipar].column_size; if (0 == *pcbParamDef && pgtype) *pcbParamDef = pgtype_column_size(stmt, pgtype, PG_STATIC, PG_STATIC); } if (pibScale) { *pibScale = 0; if (ipdopts->parameters[ipar].SQLType) *pibScale = ipdopts->parameters[ipar].decimal_digits; else if (pgtype) *pibScale = pgtype_scale(stmt, pgtype, -1); } if (pfNullable) *pfNullable = pgtype_nullable(SC_get_conn(stmt), ipdopts->parameters[ipar].paramType); cleanup: #undef return if (stmt->internal) ret = DiscardStatementSvp(stmt, ret, FALSE); return ret; }
void makeConnectString(char *connect_string, const ConnInfo *ci, UWORD len) { char got_dsn = (ci->dsn[0] != '\0'); char encoded_item[LARGE_REGISTRY_LEN]; ssize_t hlen, nlen, olen; /*BOOL abbrev = (len <= 400);*/ BOOL abbrev = (len < 1024) || 0 < ci->force_abbrev_connstr; UInt4 flag; inolog("force_abbrev=%d abbrev=%d\n", ci->force_abbrev_connstr, abbrev); encode(ci->password, encoded_item, sizeof(encoded_item)); /* fundamental info */ nlen = MAX_CONNECT_STRING; olen = snprintf(connect_string, nlen, "%s=%s;DATABASE=%s;SERVER=%s;PORT=%s;UID=%s;PWD=%s", got_dsn ? "DSN" : "DRIVER", got_dsn ? ci->dsn : ci->drivername, ci->database, ci->server, ci->port, ci->username, encoded_item); if (olen < 0 || olen >= nlen) { connect_string[0] = '\0'; return; } encode(ci->conn_settings, encoded_item, sizeof(encoded_item)); /* extra info */ hlen = strlen(connect_string); nlen = MAX_CONNECT_STRING - hlen; inolog("hlen=%d", hlen); if (!abbrev) { char protocol_and[16]; if (ci->rollback_on_error >= 0) snprintf(protocol_and, sizeof(protocol_and), "%s-%d", ci->protocol, ci->rollback_on_error); else strncpy_null(protocol_and, ci->protocol, sizeof(protocol_and)); olen = snprintf(&connect_string[hlen], nlen, ";" INI_SSLMODE "=%s;" INI_READONLY "=%s;" INI_PROTOCOL "=%s;" INI_FAKEOIDINDEX "=%s;" INI_SHOWOIDCOLUMN "=%s;" INI_ROWVERSIONING "=%s;" INI_SHOWSYSTEMTABLES "=%s;" INI_CONNSETTINGS "=%s;" INI_FETCH "=%d;" INI_SOCKET "=%d;" INI_UNKNOWNSIZES "=%d;" INI_MAXVARCHARSIZE "=%d;" INI_MAXLONGVARCHARSIZE "=%d;" INI_DEBUG "=%d;" INI_COMMLOG "=%d;" INI_OPTIMIZER "=%d;" INI_KSQO "=%d;" INI_USEDECLAREFETCH "=%d;" INI_TEXTASLONGVARCHAR "=%d;" INI_UNKNOWNSASLONGVARCHAR "=%d;" INI_BOOLSASCHAR "=%d;" INI_PARSE "=%d;" INI_CANCELASFREESTMT "=%d;" INI_EXTRASYSTABLEPREFIXES "=%s;" INI_LFCONVERSION "=%d;" INI_UPDATABLECURSORS "=%d;" INI_DISALLOWPREMATURE "=%d;" INI_TRUEISMINUS1 "=%d;" INI_INT8AS "=%d;" INI_BYTEAASLONGVARBINARY "=%d;" INI_USESERVERSIDEPREPARE "=%d;" INI_LOWERCASEIDENTIFIER "=%d;" INI_GREENPLUM "=%d;" #ifdef WIN32 INI_GSSAUTHUSEGSSAPI "=%d;" #endif /* WIN32 */ #ifdef _HANDLE_ENLIST_IN_DTC_ INI_XAOPT "=%d" /* XAOPT */ #endif /* _HANDLE_ENLIST_IN_DTC_ */ ,ci->sslmode ,ci->onlyread ,protocol_and ,ci->fake_oid_index ,ci->show_oid_column ,ci->row_versioning ,ci->show_system_tables ,encoded_item ,ci->drivers.fetch_max ,ci->drivers.socket_buffersize ,ci->drivers.unknown_sizes ,ci->drivers.max_varchar_size ,ci->drivers.max_longvarchar_size ,ci->drivers.debug ,ci->drivers.commlog ,ci->drivers.disable_optimizer ,ci->drivers.ksqo ,ci->drivers.use_declarefetch ,ci->drivers.text_as_longvarchar ,ci->drivers.unknowns_as_longvarchar ,ci->drivers.bools_as_char ,ci->drivers.parse ,ci->drivers.cancel_as_freestmt ,ci->drivers.extra_systable_prefixes ,ci->lf_conversion ,ci->allow_keyset ,ci->disallow_premature ,ci->true_is_minus1 ,ci->int8_as ,ci->bytea_as_longvarbinary ,ci->use_server_side_prepare ,ci->lower_case_identifier ,ci->greenplum #ifdef WIN32 ,ci->gssauth_use_gssapi #endif /* WIN32 */ #ifdef _HANDLE_ENLIST_IN_DTC_ ,ci->xa_opt #endif /* _HANDLE_ENLIST_IN_DTC_ */ ); } /* Abbreviation is needed ? */ if (abbrev || olen >= nlen || olen < 0) { flag = 0; if (ci->disallow_premature) flag |= BIT_DISALLOWPREMATURE; if (ci->allow_keyset) flag |= BIT_UPDATABLECURSORS; if (ci->lf_conversion) flag |= BIT_LFCONVERSION; if (ci->drivers.unique_index) flag |= BIT_UNIQUEINDEX; if (PROTOCOL_74(ci)) flag |= (BIT_PROTOCOL_64 | BIT_PROTOCOL_63); else if (PROTOCOL_64(ci)) flag |= BIT_PROTOCOL_64; else if (PROTOCOL_63(ci)) flag |= BIT_PROTOCOL_63; switch (ci->drivers.unknown_sizes) { case UNKNOWNS_AS_DONTKNOW: flag |= BIT_UNKNOWN_DONTKNOW; break; case UNKNOWNS_AS_MAX: flag |= BIT_UNKNOWN_ASMAX; break; } if (ci->drivers.disable_optimizer) flag |= BIT_OPTIMIZER; if (ci->drivers.ksqo) flag |= BIT_KSQO; if (ci->drivers.commlog) flag |= BIT_COMMLOG; if (ci->drivers.debug) flag |= BIT_DEBUG; if (ci->drivers.parse) flag |= BIT_PARSE; if (ci->drivers.cancel_as_freestmt) flag |= BIT_CANCELASFREESTMT; if (ci->drivers.use_declarefetch) flag |= BIT_USEDECLAREFETCH; if (ci->onlyread[0] == '1') flag |= BIT_READONLY; if (ci->drivers.text_as_longvarchar) flag |= BIT_TEXTASLONGVARCHAR; if (ci->drivers.unknowns_as_longvarchar) flag |= BIT_UNKNOWNSASLONGVARCHAR; if (ci->drivers.bools_as_char) flag |= BIT_BOOLSASCHAR; if (ci->row_versioning[0] == '1') flag |= BIT_ROWVERSIONING; if (ci->show_system_tables[0] == '1') flag |= BIT_SHOWSYSTEMTABLES; if (ci->show_oid_column[0] == '1') flag |= BIT_SHOWOIDCOLUMN; if (ci->fake_oid_index[0] == '1') flag |= BIT_FAKEOIDINDEX; if (ci->true_is_minus1) flag |= BIT_TRUEISMINUS1; if (ci->bytea_as_longvarbinary) flag |= BIT_BYTEAASLONGVARBINARY; if (ci->use_server_side_prepare) flag |= BIT_USESERVERSIDEPREPARE; if (ci->lower_case_identifier) flag |= BIT_LOWERCASEIDENTIFIER; if (ci->gssauth_use_gssapi) flag |= BIT_GSSAUTHUSEGSSAPI; if (ci->greenplum) flag |= BIT_GREENPLUM; if (ci->sslmode[0]) { char abbrevmode[sizeof(ci->sslmode)]; olen = snprintf(&connect_string[hlen], nlen, ";" ABBR_SSLMODE "=%s", abbrev_sslmode(ci->sslmode, abbrevmode)); } hlen = strlen(connect_string); nlen = MAX_CONNECT_STRING - hlen; olen = snprintf(&connect_string[hlen], nlen, ";" ABBR_CONNSETTINGS "=%s;" ABBR_FETCH "=%d;" ABBR_SOCKET "=%d;" ABBR_MAXVARCHARSIZE "=%d;" ABBR_MAXLONGVARCHARSIZE "=%d;" INI_INT8AS "=%d;" ABBR_EXTRASYSTABLEPREFIXES "=%s;" INI_ABBREVIATE "=%02x%x", encoded_item, ci->drivers.fetch_max, ci->drivers.socket_buffersize, ci->drivers.max_varchar_size, ci->drivers.max_longvarchar_size, ci->int8_as, ci->drivers.extra_systable_prefixes, EFFECTIVE_BIT_COUNT, flag); if (olen < nlen && (PROTOCOL_74(ci) || ci->rollback_on_error >= 0)) { hlen = strlen(connect_string); nlen = MAX_CONNECT_STRING - hlen; /* * The PROTOCOL setting must be placed after CX flag * so that this option can override the CX setting. */ if (ci->rollback_on_error >= 0) olen = snprintf(&connect_string[hlen], nlen, ";" ABBR_PROTOCOL "=%s-%d", ci->protocol, ci->rollback_on_error); else olen = snprintf(&connect_string[hlen], nlen, ";" ABBR_PROTOCOL "=%s", ci->protocol); } } if (olen < nlen) { flag = getExtraOptions(ci); if (0 != flag) { hlen = strlen(connect_string); nlen = MAX_CONNECT_STRING - hlen; olen = snprintf(&connect_string[hlen], nlen, ";" INI_EXTRAOPTIONS "=%x;", flag); } } if (olen < 0 || olen >= nlen) /* failed */ connect_string[0] = '\0'; }
RETCODE DiscardStatementSvp(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; }
/* * Must be in a transaction or the subsequent execution * invokes a transaction. */ RETCODE SetStatementSvp(StatementClass *stmt) { CSTR func = "SetStatementSvp"; char esavepoint[32], cmd[64]; ConnectionClass *conn = SC_get_conn(stmt); QResultClass *res; RETCODE ret = SQL_SUCCESS_WITH_INFO; if (CC_is_in_error_trans(conn)) return ret; if (0 == stmt->lock_CC_for_rb) { ENTER_CONN_CS(conn); stmt->lock_CC_for_rb++; } switch (stmt->statement_type) { case STMT_TYPE_SPECIAL: case STMT_TYPE_TRANSACTION: return ret; } if (!SC_accessed_db(stmt)) { 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; }
/* * 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; }
/* Perform a Prepare on the SQL statement */ RETCODE SQL_API PGAPI_Prepare(HSTMT hstmt, const SQLCHAR FAR * szSqlStr, SQLINTEGER cbSqlStr) { CSTR func = "PGAPI_Prepare"; StatementClass *self = (StatementClass *) hstmt; RETCODE retval = SQL_SUCCESS; mylog("%s: entering...\n", func); #define return DONT_CALL_RETURN_FROM_HERE??? /* StartRollbackState(self); */ if (!self) { SC_log_error(func, "", NULL); retval = SQL_INVALID_HANDLE; goto cleanup; } /* * According to the ODBC specs it is valid to call SQLPrepare multiple * times. In that case, the bound SQL statement is replaced by the new * one */ SC_set_prepared(self, NOT_YET_PREPARED); switch (self->status) { case STMT_PREMATURE: mylog("**** PGAPI_Prepare: STMT_PREMATURE, recycle\n"); SC_recycle_statement(self); /* recycle the statement, but do * not remove parameter bindings */ break; case STMT_FINISHED: mylog("**** PGAPI_Prepare: STMT_FINISHED, recycle\n"); SC_recycle_statement(self); /* recycle the statement, but do * not remove parameter bindings */ break; case STMT_ALLOCATED: mylog("**** PGAPI_Prepare: STMT_ALLOCATED, copy\n"); self->status = STMT_READY; break; case STMT_READY: mylog("**** PGAPI_Prepare: STMT_READY, change SQL\n"); break; case STMT_EXECUTING: mylog("**** PGAPI_Prepare: STMT_EXECUTING, error!\n"); SC_set_error(self, STMT_SEQUENCE_ERROR, "PGAPI_Prepare(): The handle does not point to a statement that is ready to be executed", func); retval = SQL_ERROR; goto cleanup; default: SC_set_error(self, STMT_INTERNAL_ERROR, "An Internal Error has occured -- Unknown statement status.", func); retval = SQL_ERROR; goto cleanup; } SC_initialize_stmts(self, TRUE); if (!szSqlStr) { SC_set_error(self, STMT_NO_MEMORY_ERROR, "the query is NULL", func); retval = SQL_ERROR; goto cleanup; } if (!szSqlStr[0]) self->statement = strdup(""); else self->statement = make_string(szSqlStr, cbSqlStr, NULL, 0); if (!self->statement) { SC_set_error(self, STMT_NO_MEMORY_ERROR, "No memory available to store statement", func); retval = SQL_ERROR; goto cleanup; } self->prepare = PREPARE_STATEMENT; self->statement_type = statement_type(self->statement); /* Check if connection is onlyread (only selects are allowed) */ if (CC_is_onlyread(SC_get_conn(self)) && STMT_UPDATE(self)) { SC_set_error(self, STMT_EXEC_ERROR, "Connection is readonly, only select statements are allowed.", func); retval = SQL_ERROR; goto cleanup; } cleanup: #undef return inolog("SQLPrepare return=%d\n", retval); if (self->internal) retval = DiscardStatementSvp(self, retval, FALSE); return retval; }
UCHAR SOCK_get_next_byte(SocketClass *self, BOOL peek) { int retry_count = 0, gerrno; BOOL maybeEOF = FALSE; if (!self) return 0; if (self->buffer_read_in >= self->buffer_filled_in) { /* * there are no more bytes left in the buffer so reload the buffer */ self->buffer_read_in = 0; retry: #ifdef USE_SSL if (self->ssl) self->buffer_filled_in = SOCK_SSL_recv(self, (char *) self->buffer_in, self->buffer_size); else #endif /* USE_SSL */ self->buffer_filled_in = SOCK_SSPI_recv(self, (char *) self->buffer_in, self->buffer_size); gerrno = SOCK_ERRNO; mylog("read %d, global_socket_buffersize=%d\n", self->buffer_filled_in, self->buffer_size); if (self->buffer_filled_in < 0) { mylog("Lasterror=%d\n", gerrno); switch (gerrno) { case EINTR: goto retry; break; #ifdef EAGAIN case EAGAIN: #endif /* EAGAIN */ #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: #endif /* EWOULDBLOCK */ retry_count++; if (SOCK_wait_for_ready(self, FALSE, retry_count) >= 0) goto retry; break; case ECONNRESET: inolog("ECONNRESET\n"); maybeEOF = TRUE; SOCK_set_error(self, SOCKET_CLOSED, "Connection reset by peer."); break; } if (0 == self->errornumber) SOCK_set_error(self, SOCKET_READ_ERROR, "Error while reading from the socket."); self->buffer_filled_in = 0; return 0; } if (self->buffer_filled_in == 0) { if (!maybeEOF) { int nbytes = SOCK_wait_for_ready(self, FALSE, 0); if (nbytes > 0) { maybeEOF = TRUE; goto retry; } else if (0 == nbytes) maybeEOF = TRUE; } if (maybeEOF) SOCK_set_error(self, SOCKET_CLOSED, "Socket has been closed."); else SOCK_set_error(self, SOCKET_READ_ERROR, "Error while reading from the socket."); return 0; } } if (peek) return self->buffer_in[self->buffer_read_in]; if (PG_PROTOCOL_74 == self->pversion) self->reslen--; return self->buffer_in[self->buffer_read_in++]; }
const char * pgtype_attr_to_name(const ConnectionClass *conn, OID type, int atttypmod, BOOL auto_increment) { const char *tname = NULL; switch (type) { case PG_TYPE_CHAR: return "char"; case PG_TYPE_INT8: return auto_increment ? "bigserial" : "int8"; case PG_TYPE_NUMERIC: return "numeric"; case PG_TYPE_VARCHAR: return "varchar"; case PG_TYPE_BPCHAR: return "char"; case PG_TYPE_TEXT: return "text"; case PG_TYPE_NAME: return "name"; case PG_TYPE_REFCURSOR: return "refcursor"; case PG_TYPE_INT2: return "int2"; case PG_TYPE_OID: return OID_NAME; case PG_TYPE_XID: return "xid"; case PG_TYPE_INT4: inolog("pgtype_to_name int4\n"); return auto_increment ? "serial" : "int4"; case PG_TYPE_FLOAT4: return "float4"; case PG_TYPE_FLOAT8: return "float8"; case PG_TYPE_DATE: return "date"; case PG_TYPE_TIME: return "time"; case PG_TYPE_ABSTIME: return "abstime"; case PG_TYPE_DATETIME: return "timestamptz"; case PG_TYPE_TIMESTAMP_NO_TMZONE: return "timestamp without time zone"; case PG_TYPE_TIMESTAMP: return "timestamp"; case PG_TYPE_MONEY: return "money"; case PG_TYPE_BOOL: return "bool"; case PG_TYPE_BYTEA: return "bytea"; case PG_TYPE_XML: return "xml"; case PG_TYPE_MACADDR: return "macaddr"; case PG_TYPE_INET: return "inet"; case PG_TYPE_CIDR: return "cidr"; case PG_TYPE_UUID: return "uuid"; case PG_TYPE_INTERVAL: get_interval_type(atttypmod, &tname); return tname; case PG_TYPE_LO_UNDEFINED: return PG_TYPE_LO_NAME; default: /* hack until permanent type is available */ if (type == conn->lobj_type) return PG_TYPE_LO_NAME; /* * "unknown" can actually be used in alter table because it is * a real PG type! */ return "unknown"; } }
const char * pgtype_to_name(StatementClass *stmt, OID type, BOOL auto_increment) { ConnectionClass *conn = SC_get_conn(stmt); switch (type) { case PG_TYPE_CHAR: return "char"; case PG_TYPE_CHAR2: return "char2"; case PG_TYPE_CHAR4: return "char4"; case PG_TYPE_CHAR8: return "char8"; case PG_TYPE_INT8: return auto_increment ? "bigserial" : "int8"; case PG_TYPE_NUMERIC: return "numeric"; case PG_TYPE_VARCHAR: return "varchar"; case PG_TYPE_BPCHAR: return "char"; case PG_TYPE_TEXT: return "text"; case PG_TYPE_NAME: return "name"; case PG_TYPE_INT2: return "int2"; case PG_TYPE_OID: return OID_NAME; case PG_TYPE_XID: return "xid"; case PG_TYPE_INT4: inolog("pgtype_to_name int4\n"); return auto_increment ? "serial" : "int4"; case PG_TYPE_FLOAT4: return "float4"; case PG_TYPE_FLOAT8: return "float8"; case PG_TYPE_DATE: return "date"; case PG_TYPE_TIME: return "time"; case PG_TYPE_ABSTIME: return "abstime"; case PG_TYPE_DATETIME: if (PG_VERSION_GT(conn, 7.1)) return "timestamptz"; else if (PG_VERSION_LT(conn, 7.0)) return "datetime"; else return "timestamp"; case PG_TYPE_TIMESTAMP_NO_TMZONE: return "timestamp without time zone"; case PG_TYPE_TIMESTAMP: return "timestamp"; case PG_TYPE_MONEY: return "money"; case PG_TYPE_BOOL: return "bool"; case PG_TYPE_BYTEA: return "bytea"; case PG_TYPE_XML: return "xml"; case PG_TYPE_MACADDR: return "macaddr"; case PG_TYPE_INET: return "inet"; case PG_TYPE_CIDR: return "cidr"; case PG_TYPE_UUID: return "uuid"; case PG_TYPE_LO_UNDEFINED: return PG_TYPE_LO_NAME; default: /* hack until permanent type is available */ if (type == stmt->hdbc->lobj_type) return PG_TYPE_LO_NAME; /* * "unknown" can actually be used in alter table because it is * a real PG type! */ return "unknown"; } }
RETCODE SQL_API SQLDriverConnectW(HDBC hdbc, HWND hwnd, SQLWCHAR *szConnStrIn, SQLSMALLINT cbConnStrIn, SQLWCHAR *szConnStrOut, SQLSMALLINT cbConnStrOutMax, SQLSMALLINT *pcbConnStrOut, SQLUSMALLINT fDriverCompletion) { CSTR func = "SQLDriverConnectW"; char *szIn, *szOut = NULL; SQLSMALLINT maxlen, obuflen = 0; SQLLEN inlen; SQLSMALLINT olen, *pCSO; RETCODE ret; ConnectionClass *conn = (ConnectionClass *) hdbc; mylog("[%s]", func); CC_examine_global_transaction(conn); ENTER_CONN_CS(conn); CC_clear_error(conn); CC_set_in_unicode_driver(conn); szIn = ucs2_to_utf8(szConnStrIn, cbConnStrIn, &inlen, FALSE); maxlen = cbConnStrOutMax; pCSO = NULL; olen = 0; if (maxlen > 0) { obuflen = maxlen + 1; szOut = malloc(obuflen); if (!szOut) { CC_set_error(conn, CONN_NO_MEMORY_ERROR, "Could not allocate memory for output buffer", func); ret = SQL_ERROR; goto cleanup; } pCSO = &olen; } else if (pcbConnStrOut) pCSO = &olen; ret = PGAPI_DriverConnect(hdbc, hwnd, (SQLCHAR *) szIn, (SQLSMALLINT) inlen, (SQLCHAR *) szOut, maxlen, pCSO, fDriverCompletion); if (ret != SQL_ERROR && NULL != pCSO) { SQLLEN outlen = olen; if (olen < obuflen) outlen = utf8_to_ucs2(szOut, olen, szConnStrOut, cbConnStrOutMax); else utf8_to_ucs2(szOut, maxlen, szConnStrOut, cbConnStrOutMax); if (outlen >= cbConnStrOutMax && NULL != szConnStrOut && NULL != pcbConnStrOut) { inolog("cbConnstrOutMax=%d pcb=%p\n", cbConnStrOutMax, pcbConnStrOut); if (SQL_SUCCESS == ret) { CC_set_error(conn, CONN_TRUNCATED, "the ConnStrOut is too small", func); ret = SQL_SUCCESS_WITH_INFO; } } if (pcbConnStrOut) *pcbConnStrOut = (SQLSMALLINT) outlen; } cleanup: LEAVE_CONN_CS(conn); if (szOut) free(szOut); if (szIn) free(szIn); return ret; }
RETCODE SQL_API PGAPI_DriverConnect( HDBC hdbc, HWND hwnd, const SQLCHAR FAR * szConnStrIn, SQLSMALLINT cbConnStrIn, SQLCHAR FAR * szConnStrOut, SQLSMALLINT cbConnStrOutMax, SQLSMALLINT FAR * pcbConnStrOut, SQLUSMALLINT fDriverCompletion) { CSTR func = "PGAPI_DriverConnect"; ConnectionClass *conn = (ConnectionClass *) hdbc; ConnInfo *ci; #ifdef WIN32 RETCODE dialog_result; #endif BOOL paramRequired, didUI = FALSE; RETCODE result; char *connStrIn = NULL; char connStrOut[MAX_CONNECT_STRING]; int retval; char salt[5]; char password_required = AUTH_REQ_OK; ssize_t len = 0; SQLSMALLINT lenStrout; mylog("%s: entering...\n", func); if (!conn) { CC_log_error(func, "", NULL); return SQL_INVALID_HANDLE; } connStrIn = make_string(szConnStrIn, cbConnStrIn, NULL, 0); #ifdef FORCE_PASSWORD_DISPLAY mylog("**** PGAPI_DriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, connStrIn); qlog("conn=%p, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, connStrIn, fDriverCompletion); #else if (get_qlog() || get_mylog()) { char *hide_str = hide_password(connStrIn); mylog("**** PGAPI_DriverConnect: fDriverCompletion=%d, connStrIn='%s'\n", fDriverCompletion, NULL_IF_NULL(hide_str)); qlog("conn=%p, PGAPI_DriverConnect( in)='%s', fDriverCompletion=%d\n", conn, NULL_IF_NULL(hide_str), fDriverCompletion); if (hide_str) free(hide_str); } #endif /* FORCE_PASSWORD_DISPLAY */ ci = &(conn->connInfo); /* Parse the connect string and fill in conninfo for this hdbc. */ dconn_get_connect_attributes(connStrIn, ci); /* * If the ConnInfo in the hdbc is missing anything, this function will * fill them in from the registry (assuming of course there is a DSN * given -- if not, it does nothing!) */ getDSNinfo(ci, CONN_DONT_OVERWRITE); dconn_get_common_attributes(connStrIn, ci); logs_on_off(1, ci->drivers.debug, ci->drivers.commlog); if (connStrIn) { free(connStrIn); connStrIn = NULL; } /* Fill in any default parameters if they are not there. */ getDSNdefaults(ci); /* initialize pg_version */ CC_initialize_pg_version(conn); memset(salt, 0, sizeof(salt)); #ifdef WIN32 dialog: #endif ci->focus_password = password_required; inolog("DriverCompletion=%d\n", fDriverCompletion); switch (fDriverCompletion) { #ifdef WIN32 case SQL_DRIVER_PROMPT: dialog_result = dconn_DoDialog(hwnd, ci); didUI = TRUE; if (dialog_result != SQL_SUCCESS) return dialog_result; break; case SQL_DRIVER_COMPLETE_REQUIRED: /* Fall through */ case SQL_DRIVER_COMPLETE: paramRequired = password_required; /* Password is not a required parameter. */ if (ci->database[0] == '\0') paramRequired = TRUE; else if (ci->port[0] == '\0') paramRequired = TRUE; #ifdef WIN32 else if (ci->server[0] == '\0') paramRequired = TRUE; #endif /* WIN32 */ if (paramRequired) { dialog_result = dconn_DoDialog(hwnd, ci); didUI = TRUE; if (dialog_result != SQL_SUCCESS) return dialog_result; } break; #else case SQL_DRIVER_PROMPT: case SQL_DRIVER_COMPLETE: case SQL_DRIVER_COMPLETE_REQUIRED: #endif case SQL_DRIVER_NOPROMPT: break; } /* * Password is not a required parameter unless authentication asks for * it. For now, I think it's better to just let the application ask * over and over until a password is entered (the user can always hit * Cancel to get out) */ paramRequired = FALSE; if (ci->database[0] == '\0') paramRequired = TRUE; else if (ci->port[0] == '\0') paramRequired = TRUE; #ifdef WIN32 else if (ci->server[0] == '\0') paramRequired = TRUE; #endif /* WIN32 */ if (paramRequired) { if (didUI) return SQL_NO_DATA_FOUND; CC_set_error(conn, CONN_OPENDB_ERROR, "connction string lacks some options", func); return SQL_ERROR; } inolog("before CC_connect\n"); /* do the actual connect */ retval = CC_connect(conn, password_required, salt); if (retval < 0) { /* need a password */ if (fDriverCompletion == SQL_DRIVER_NOPROMPT) { CC_log_error(func, "Need password but Driver_NoPrompt", conn); return SQL_ERROR; /* need a password but not allowed to * prompt so error */ } else { #ifdef WIN32 password_required = -retval; goto dialog; #else return SQL_ERROR; /* until a better solution is found. */ #endif } } else if (retval == 0) { /* error msg filled in above */ CC_log_error(func, "Error from CC_Connect", conn); return SQL_ERROR; } /* * Create the Output Connection String */ result = SQL_SUCCESS; lenStrout = cbConnStrOutMax; if (conn->ms_jet && lenStrout > 255) lenStrout = 255; makeConnectString(connStrOut, ci, lenStrout); len = strlen(connStrOut); if (szConnStrOut) { /* * Return the completed string to the caller. The correct method * is to only construct the connect string if a dialog was put up, * otherwise, it should just copy the connection input string to * the output. However, it seems ok to just always construct an * output string. There are possible bad side effects on working * applications (Access) by implementing the correct behavior, * anyway. */ /*strncpy_null(szConnStrOut, connStrOut, cbConnStrOutMax);*/ strncpy(szConnStrOut, connStrOut, cbConnStrOutMax); if (len >= cbConnStrOutMax) { int clen; for (clen = cbConnStrOutMax - 1; clen >= 0 && szConnStrOut[clen] != ';'; clen--) szConnStrOut[clen] = '\0'; result = SQL_SUCCESS_WITH_INFO; CC_set_error(conn, CONN_TRUNCATED, "The buffer was too small for the ConnStrOut.", func); } } if (pcbConnStrOut) *pcbConnStrOut = (SQLSMALLINT) len; #ifdef FORCE_PASSWORD_DISPLAY if (cbConnStrOutMax > 0) { mylog("szConnStrOut = '%s' len=%d,%d\n", NULL_IF_NULL(szConnStrOut), len, cbConnStrOutMax); qlog("conn=%p, PGAPI_DriverConnect(out)='%s'\n", conn, NULL_IF_NULL(szConnStrOut)); } #else if (get_qlog() || get_mylog()) { char *hide_str = NULL; if (cbConnStrOutMax > 0) hide_str = hide_password(szConnStrOut); mylog("szConnStrOut = '%s' len=%d,%d\n", NULL_IF_NULL(hide_str), len, cbConnStrOutMax); qlog("conn=%p, PGAPI_DriverConnect(out)='%s'\n", conn, NULL_IF_NULL(hide_str)); if (hide_str) free(hide_str); } #endif /* FORCE_PASSWORD_DISPLAY */ if (connStrIn) free(connStrIn); mylog("PGAPI_DriverConnect: returning %d\n", result); return result; }
/* * Supplies parameter data at execution time. * Used in conjuction with SQLPutData. */ RETCODE SQL_API PGAPI_ParamData( HSTMT hstmt, PTR FAR * prgbValue) { CSTR func = "PGAPI_ParamData"; StatementClass *stmt = (StatementClass *) hstmt, *estmt; APDFields *apdopts; IPDFields *ipdopts; RETCODE retval; int i; Int2 num_p; ConnectionClass *conn = NULL; mylog("%s: entering...\n", func); if (!stmt) { SC_log_error(func, "", NULL); retval = SQL_INVALID_HANDLE; goto cleanup; } conn = SC_get_conn(stmt); estmt = stmt->execute_delegate ? stmt->execute_delegate : stmt; apdopts = SC_get_APDF(estmt); mylog("%s: data_at_exec=%d, params_alloc=%d\n", func, estmt->data_at_exec, apdopts->allocated); #define return DONT_CALL_RETURN_FROM_HERE??? if (SC_AcceptedCancelRequest(stmt)) { SC_set_error(stmt, STMT_OPERATION_CANCELLED, "Cancel the statement, sorry", func); retval = SQL_ERROR; goto cleanup; } if (estmt->data_at_exec < 0) { SC_set_error(stmt, STMT_SEQUENCE_ERROR, "No execution-time parameters for this statement", func); retval = SQL_ERROR; goto cleanup; } if (estmt->data_at_exec > apdopts->allocated) { SC_set_error(stmt, STMT_SEQUENCE_ERROR, "Too many execution-time parameters were present", func); retval = SQL_ERROR; goto cleanup; } /* close the large object */ if (estmt->lobj_fd >= 0) { odbc_lo_close(conn, estmt->lobj_fd); /* commit transaction if needed */ if (!CC_cursor_count(conn) && CC_does_autocommit(conn)) { if (!CC_commit(conn)) { SC_set_error(stmt, STMT_EXEC_ERROR, "Could not commit (in-line) a transaction", func); retval = SQL_ERROR; goto cleanup; } } estmt->lobj_fd = -1; } /* Done, now copy the params and then execute the statement */ ipdopts = SC_get_IPDF(estmt); inolog("ipdopts=%p\n", ipdopts); if (estmt->data_at_exec == 0) { BOOL exec_end; UWORD flag = SC_is_with_hold(stmt) ? PODBC_WITH_HOLD : 0; retval = Exec_with_parameters_resolved(estmt, &exec_end); if (exec_end) { /**SC_reset_delegate(retval, stmt);**/ retval = dequeueNeedDataCallback(retval, stmt); goto cleanup; } if (retval = PGAPI_Execute(estmt, flag), SQL_NEED_DATA != retval) { goto cleanup; } } /* * Set beginning param; if first time SQLParamData is called , start * at 0. Otherwise, start at the last parameter + 1. */ i = estmt->current_exec_param >= 0 ? estmt->current_exec_param + 1 : 0; num_p = estmt->num_params; if (num_p < 0) PGAPI_NumParams(estmt, &num_p); inolog("i=%d allocated=%d num_p=%d\n", i, apdopts->allocated, num_p); if (num_p > apdopts->allocated) num_p = apdopts->allocated; /* At least 1 data at execution parameter, so Fill in the token value */ for (; i < num_p; i++) { inolog("i=%d", i); if (apdopts->parameters[i].data_at_exec) { inolog(" at exec buffer=%p", apdopts->parameters[i].buffer); estmt->data_at_exec--; estmt->current_exec_param = i; estmt->put_data = FALSE; if (prgbValue) { /* returns token here */ if (stmt->execute_delegate) { SQLULEN offset = apdopts->param_offset_ptr ? *apdopts->param_offset_ptr : 0; SQLLEN perrow = apdopts->param_bind_type > 0 ? apdopts->param_bind_type : apdopts->parameters[i].buflen; inolog(" offset=%d perrow=%d", offset, perrow); *prgbValue = apdopts->parameters[i].buffer + offset + estmt->exec_current_row * perrow; } else *prgbValue = apdopts->parameters[i].buffer; } break; } inolog("\n"); } retval = SQL_NEED_DATA; inolog("return SQL_NEED_DATA\n"); cleanup: #undef return SC_setInsertedTable(stmt, retval); if (stmt->internal) retval = DiscardStatementSvp(stmt, retval, FALSE); mylog("%s: returning %d\n", func, retval); return retval; }
static int SOCK_get_next_n_bytes(SocketClass *self, int n, char *buf) { int retry_count = 0, gerrno, rest, rlen; BOOL maybeEOF = FALSE; if (!self || !n) return 0; for (rest = n; 0 < rest;) { if (self->buffer_read_in >= self->buffer_filled_in) { /* * there are no more bytes left in the buffer so reload the buffer */ self->buffer_read_in = 0; retry: #ifdef USE_SSL if (self->ssl) self->buffer_filled_in = SOCK_SSL_recv(self, (char *) self->buffer_in, self->buffer_size); else #endif /* USE_SSL */ self->buffer_filled_in = SOCK_SSPI_recv(self, (char *) self->buffer_in, self->buffer_size); gerrno = SOCK_ERRNO; mylog("read %d, global_socket_buffersize=%d\n", self->buffer_filled_in, self->buffer_size); if (self->buffer_filled_in < 0) { mylog("Lasterror=%d\n", gerrno); switch (gerrno) { case EINTR: goto retry; break; #ifdef EAGAIN case EAGAIN: #endif /* EAGAIN */ #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: #endif /* EWOULDBLOCK */ retry_count++; if (SOCK_wait_for_ready(self, FALSE, retry_count) >= 0) goto retry; break; case ECONNRESET: inolog("ECONNRESET\n"); maybeEOF = TRUE; SOCK_set_error(self, SOCKET_CLOSED, "Connection reset by peer."); break; } if (0 == self->errornumber) SOCK_set_error(self, SOCKET_READ_ERROR, "Error while reading from the socket."); self->buffer_filled_in = 0; return -1; } if (self->buffer_filled_in == 0) { if (!maybeEOF) { int nready = SOCK_wait_for_ready(self, FALSE, 0); if (nready > 0) { maybeEOF = TRUE; goto retry; } else if (0 == nready) maybeEOF = TRUE; } if (maybeEOF) { SOCK_set_error(self, SOCKET_CLOSED, "Socket has been closed."); break; } else { SOCK_set_error(self, SOCKET_READ_ERROR, "Error while reading from the socket."); return -1; } } } rlen = self->buffer_filled_in - self->buffer_read_in; if (rlen > rest) rlen = rest; if (buf) memcpy(buf + n - rest, self->buffer_in + self->buffer_read_in, rlen); rest -= rlen; if (PG_PROTOCOL_74 == self->pversion) self->reslen -= rlen; self->buffer_read_in += rlen; } return n - rest; }
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; }