/** * Allow install using regsvr32 */ HRESULT WINAPI DllRegisterServer(void) { TCHAR fn[MAX_PATH], full_fn[MAX_PATH]; LPTSTR name; WORD len_out; DWORD cnt; char *desc = NULL; BOOL b_res; if (!GetModuleFileName(hinstFreeTDS, fn, TDS_VECTOR_SIZE(fn))) return SELFREG_E_CLASS; if (!GetFullPathName(fn, TDS_VECTOR_SIZE(full_fn), full_fn, &name) || !name || full_fn == name) return SELFREG_E_CLASS; if (asprintf(&desc, "FreeTDS%c" "APILevel=2%c" "ConnectFunctions=YYN%c" "DriverODBCVer=03.00%c" "FileUsage=0%c" "SQLLevel=2%c" "Setup=%s%c" "Driver=%s%c", 0, 0, 0, 0, 0, 0, name, 0, name, 0 ) < 0) return SELFREG_E_CLASS; name[-1] = 0; b_res = SQLInstallDriverEx(desc, full_fn, fn, TDS_VECTOR_SIZE(fn), &len_out, ODBC_INSTALL_COMPLETE, &cnt); free(desc); if (!b_res) return SELFREG_E_CLASS; return S_OK; }
int tds_parse_boolean(const char *value, int default_value) { int p; for (p = 0; p < TDS_VECTOR_SIZE(boolean_values); ++p) { if (!strcasecmp(value, boolean_values[p].value)) return boolean_values[p].to_return; } return default_value; }
int tds_config_boolean(const char *value) { int p; for (p = 0; p < TDS_VECTOR_SIZE(boolean_values); ++p) { if (!strcasecmp(value, boolean_values[p].value)) return boolean_values[p].to_return; } tdsdump_log(TDS_DBG_INFO1, "UNRECOGNIZED boolean value: '%s'. Treating as 'no'.\n", value); return 0; }
int tds_config_boolean(const char *option, const char *value, TDSLOGIN *login) { int p; for (p = 0; p < TDS_VECTOR_SIZE(boolean_values); ++p) { if (!strcasecmp(value, boolean_values[p].value)) return boolean_values[p].to_return; } tdsdump_log(TDS_DBG_ERROR, "UNRECOGNIZED option value '%s' for boolean setting '%s'!\n", value, option); login->valid_configuration = 0; return 0; }
/** * Set state of TDS connection, with logging and checking. * \param tds state information for the socket and the TDS protocol * \param state the new state of the connection, cf. TDS_STATE. * \return the new state, which might not be \a state. */ TDS_STATE tds_set_state(TDSSOCKET * tds, TDS_STATE state) { const TDS_STATE prior_state = tds->state; static const char state_names[][10] = { "IDLE", "QUERYING", "PENDING", "READING", "DEAD" }; assert(state < TDS_VECTOR_SIZE(state_names)); assert(tds->state < TDS_VECTOR_SIZE(state_names)); if (state == tds->state) return state; switch(state) { /* transition to READING are valid only from PENDING */ case TDS_PENDING: if (tds->state != TDS_READING && tds->state != TDS_QUERYING) { tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n", state_names[prior_state], state_names[state]); return tds->state; } tds->state = state; break; case TDS_READING: if (tds->state != TDS_PENDING) { tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n", state_names[prior_state], state_names[state]); return tds->state; } tds->state = state; break; case TDS_IDLE: if (tds->state == TDS_DEAD && TDS_IS_SOCKET_INVALID(tds_get_s(tds))) { tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n", state_names[prior_state], state_names[state]); return tds->state; } case TDS_DEAD: tds->state = state; break; case TDS_QUERYING: CHECK_TDS_EXTRA(tds); if (tds->state == TDS_DEAD) { tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n", state_names[prior_state], state_names[state]); tdserror(tds_get_ctx(tds), tds, TDSEWRIT, 0); break; } else if (tds->state != TDS_IDLE) { tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n", state_names[prior_state], state_names[state]); tdserror(tds_get_ctx(tds), tds, TDSERPND, 0); break; } /* TODO check this code, copied from tds_submit_prepare */ tds_free_all_results(tds); tds->rows_affected = TDS_NO_COUNT; tds_release_cursor(tds, tds->cur_cursor); tds->cur_cursor = NULL; tds->internal_sp_called = 0; tds->state = state; break; default: assert(0); break; } tdsdump_log(TDS_DBG_ERROR, "Changed query state from %s to %s\n", state_names[prior_state], state_names[state]); CHECK_TDS_EXTRA(tds); return tds->state; }
char * tds_numeric_to_string(const TDS_NUMERIC * numeric, char *s) { const unsigned char *number; unsigned int packet[sizeof(numeric->array) / 2]; unsigned int *pnum, *packet_start; unsigned int *const packet_end = packet + TDS_VECTOR_SIZE(packet); unsigned int packet10k[(MAXPRECISION + 3) / 4]; unsigned int *p; int num_bytes; unsigned int remainder, n, i, m; /* a bit of debug */ #if ENABLE_EXTRA_CHECKS memset(packet, 0x55, sizeof(packet)); memset(packet10k, 0x55, sizeof(packet10k)); #endif /* set sign */ if (numeric->array[0] == 1) *s++ = '-'; /* put number in a 16bit array */ number = numeric->array; num_bytes = tds_numeric_bytes_per_prec[numeric->precision]; n = num_bytes - 1; pnum = packet_end; for (; n > 1; n -= 2) *--pnum = number[n - 1] * 256 + number[n]; if (n == 1) *--pnum = number[n]; while (!*pnum) { ++pnum; if (pnum == packet_end) { *s++ = '0'; if (numeric->scale) { *s++ = '.'; i = numeric->scale; do { *s++ = '0'; } while (--i); } *s++ = 0; return s; } } packet_start = pnum; /* transform 2^16 base number in 10^4 base number */ for (p = packet10k + TDS_VECTOR_SIZE(packet10k); packet_start != packet_end;) { pnum = packet_start; n = *pnum; remainder = n % 10000u; if (!(*pnum++ = (n / 10000u))) packet_start = pnum; for (; pnum != packet_end; ++pnum) { n = remainder * (256u * 256u) + *pnum; remainder = n % 10000u; *pnum = n / 10000u; } *--p = remainder; } /* transform to 10 base number and output */ i = 4 * ((packet10k + TDS_VECTOR_SIZE(packet10k)) - p); /* current digit */ /* skip leading zeroes */ n = 1000; remainder = *p; while (remainder < n) n /= 10, --i; if (i <= numeric->scale) { *s++ = '0'; *s++ = '.'; m = i; while (m < numeric->scale) *s++ = '0', ++m; } for (;;) { *s++ = (remainder / n) + '0'; --i; remainder %= n; n /= 10; if (!n) { n = 1000; if (++p == packet10k + TDS_VECTOR_SIZE(packet10k)) break; remainder = *p; } if (i == numeric->scale) *s++ = '.'; } *s++ = 0; return s; }
* precision can't be 0 but using a value > 0 assure no * core if for some bug it's 0... */ 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 6, 7, 7, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 18, 18, 19, 19, 19, 20, 20, 21, 21, 21, 22, 22, 23, 23, 24, 24, 24, 25, 25, 26, 26, 26, 27, 27, 28, 28, 28, 29, 29, 30, 30, 31, 31, 31, 32, 32, 33, 33, 33 }; TDS_COMPILE_CHECK(maxprecision, MAXPRECISION < TDS_VECTOR_SIZE(tds_numeric_bytes_per_prec) ); /* * money is a special case of numeric really...that why its here */ char * tds_money_to_string(const TDS_MONEY * money, char *s) { int frac; TDS_INT8 mymoney; TDS_UINT8 n; char *p; /* sometimes money it's only 4-byte aligned so always compute 64-bit */ mymoney = (((TDS_INT8) money->tdsoldmoney.mnyhigh) << 32) | money->tdsoldmoney.mnylow;
/** * Set state of TDS connection, with logging and checking. * \param tds state information for the socket and the TDS protocol * \param state the new state of the connection, cf. TDS_STATE. * \return the new state, which might not be \a state. */ TDS_STATE tds_set_state(TDSSOCKET * tds, TDS_STATE state) { TDS_STATE prior_state; static const char state_names[][8] = { "IDLE", "WRITING", "SENDING", "PENDING", "READING", "DEAD" }; assert(state < TDS_VECTOR_SIZE(state_names)); assert(tds->state < TDS_VECTOR_SIZE(state_names)); prior_state = tds->state; if (state == prior_state) return state; switch(state) { case TDS_PENDING: if (prior_state == TDS_READING || prior_state == TDS_WRITING) { tds->state = TDS_PENDING; tds_mutex_unlock(&tds->wire_mtx); break; } tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n", state_names[prior_state], state_names[state]); break; case TDS_READING: /* transition to READING are valid only from PENDING */ if (tds_mutex_trylock(&tds->wire_mtx)) return tds->state; if (tds->state != TDS_PENDING) { tds_mutex_unlock(&tds->wire_mtx); tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n", state_names[prior_state], state_names[state]); break; } tds->state = state; break; case TDS_SENDING: if (prior_state != TDS_READING && prior_state != TDS_WRITING) { tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n", state_names[prior_state], state_names[state]); break; } if (tds->state == TDS_READING) { /* TODO check this code, copied from tds_submit_prepare */ tds_free_all_results(tds); tds->rows_affected = TDS_NO_COUNT; tds_release_cursor(&tds->cur_cursor); tds_release_cur_dyn(tds); tds->current_op = TDS_OP_NONE; } tds_mutex_unlock(&tds->wire_mtx); tds->state = state; break; case TDS_IDLE: if (prior_state == TDS_DEAD && TDS_IS_SOCKET_INVALID(tds_get_s(tds))) { tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n", state_names[prior_state], state_names[state]); break; } case TDS_DEAD: if (prior_state == TDS_READING || prior_state == TDS_WRITING) tds_mutex_unlock(&tds->wire_mtx); tds->state = state; break; case TDS_WRITING: CHECK_TDS_EXTRA(tds); if (tds_mutex_trylock(&tds->wire_mtx)) return tds->state; if (tds->state == TDS_DEAD) { tds_mutex_unlock(&tds->wire_mtx); tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n", state_names[prior_state], state_names[state]); tdserror(tds_get_ctx(tds), tds, TDSEWRIT, 0); break; } else if (tds->state != TDS_IDLE && tds->state != TDS_SENDING) { tds_mutex_unlock(&tds->wire_mtx); tdsdump_log(TDS_DBG_ERROR, "logic error: cannot change query state from %s to %s\n", state_names[prior_state], state_names[state]); tdserror(tds_get_ctx(tds), tds, TDSERPND, 0); break; } if (tds->state == TDS_IDLE) { /* TODO check this code, copied from tds_submit_prepare */ tds_free_all_results(tds); tds->rows_affected = TDS_NO_COUNT; tds_release_cursor(&tds->cur_cursor); tds_release_cur_dyn(tds); tds->current_op = TDS_OP_NONE; } tds->state = state; break; default: assert(0); break; } state = tds->state; tdsdump_log(TDS_DBG_ERROR, "Changed query state from %s to %s\n", state_names[prior_state], state_names[state]); CHECK_TDS_EXTRA(tds); return state; }