31 #include <freetds/tds.h>
32 #include <freetds/iconv.h>
33 #include <freetds/tls.h>
34 #include <freetds/checks.h>
36 #include "replacements.h"
37 #include <freetds/enum_cap.h>
40 #include <sys/socket.h>
51 #ifdef HAVE_LANGINFO_H
60 #define TEST_MALLOC(dest,type) \
61 {if (!(dest = (type*)calloc(1, sizeof(type)))) goto Cleanup;}
64 #define TEST_CALLOC(dest,type,n) \
65 {if (!(dest = (type*)calloc((n), sizeof(type)))) goto Cleanup;}
106 *p++ = (char) (
'a' + (
n % 26u));
108 for (
i = 0;
i < 9; ++
i) {
109 c = (char) (
'0' + (
n % 36u));
110 *p++ = (c < (
'0' + 10)) ? c : c + (
'a' -
'0' - 10);
226 victim = &
conn->dyns;
227 while (*victim != dyn) {
228 if (*victim ==
NULL) {
232 victim = &(*victim)->
next;
296 param_info = old_param;
323 if (!param_info || param_info->
num_cols <= 0)
404 info->num_cols = num_cols;
405 for (col = 0; col < num_cols; col++)
411 info->by_cols = by_cols;
442 comp_info[
n] = cur_comp_info;
460 for (col = 0; col < num_cols; col++)
490 info->attached_to->current_results =
NULL;
491 info->attached_to->in_row =
false;
502 if (!res_info || !
row)
532 for (
i = 0;
i < num_cols; ++
i) {
543 ptr =
tds_new0(
unsigned char, row_size ? row_size : 1);
551 for (
i = 0;
i < num_cols; ++
i) {
591 for (
i = 0;
i < num_comp;
i++) {
592 if (comp_info && comp_info[
i]) {
676 #if defined(_WIN32) || defined(_WIN64)
677 static bool initialized =
false;
694 erc = WSAStartup(MAKEWORD(2, 2), &wsa_data);
695 initialized = (erc == 0);
758 #define SUPPORTED_REQ_CAP(i) \
759 REQ(i,LANG) REQ(i,RPC) REQ(i,EVT) REQ(i,MSTMT) REQ(i,BCP) REQ(i,CURSOR) REQ(i,DYNF) \
760 REQ(i,MSG) REQ(i,PARAM) REQ(i,DATA_INT1) REQ(i,DATA_INT2) REQ(i,DATA_INT4) REQ(i,DATA_BIT) \
761 REQ(i,DATA_CHAR) REQ(i,DATA_VCHAR) REQ(i,DATA_BIN) REQ(i,DATA_VBIN) REQ(i,DATA_MNY8) \
762 REQ(i,DATA_MNY4) REQ(i,DATA_DATE8) REQ(i,DATA_DATE4) REQ(i,DATA_FLT4) REQ(i,DATA_FLT8) \
763 REQ(i,DATA_NUM) REQ(i,DATA_TEXT) REQ(i,DATA_IMAGE) REQ(i,DATA_DEC) REQ(i,DATA_LCHAR) \
764 REQ(i,DATA_LBIN) REQ(i,DATA_INTN) REQ(i,DATA_DATETIMEN) REQ(i,DATA_MONEYN) \
765 REQ(i,CSR_PREV) REQ(i,CSR_FIRST) REQ(i,CSR_LAST) REQ(i,CSR_ABS) REQ(i,CSR_REL) \
766 REQ(i,CSR_MULTI) REQ(i,CON_INBAND) REQ(i,PROTO_TEXT) REQ(i,PROTO_BULK) \
767 REQ(i,DATA_SENSITIVITY) REQ(i,DATA_BOUNDARY) REQ(i,PROTO_DYNPROC) REQ(i,DATA_FLTN) \
768 REQ(i,DATA_BITN) REQ(i,DATA_INT8) REQ(i,WIDETABLE) \
769 REQ(i,DATA_UINT2) REQ(i,DATA_UINT4) REQ(i,DATA_UINT8) REQ(i,DATA_UINTN) REQ(i,LARGEIDENT) \
770 REQ(i,SRVPKTSIZE) REQ(i,DATA_DATE) REQ(i,DATA_TIME) REQ(i,DATA_BIGTIME) REQ(i,DATA_BIGDATETIME)
771 #define REQ(i,n) |(((TDS_REQ_ ## n / 8) == i)?(1<<(TDS_REQ_ ## n & 7)):0)
772 #define REQB(i) 0 SUPPORTED_REQ_CAP(i)
775 #define SUPPORTED_RES_CAP(i) \
776 RES(i,CON_NOOOB) RES(i,PROTO_NOTEXT) RES(i,PROTO_NOBULK) RES(i,NOTDSDEBUG)
777 #define RES(i,n) |(((TDS_RES_ ## n / 8) == i)?(1<<(TDS_RES_ ## n & 7)):0)
778 #define RESB(i) 0 SUPPORTED_RES_CAP(i)
801 #if HAVE_NL_LANGINFO && defined(CODESET)
804 char *lc_all, *tok =
NULL;
816 #if HAVE_NL_LANGINFO && defined(CODESET)
817 charset = nl_langinfo(CODESET);
819 charset =
"ISO-8859-1";
833 if (encoding && atoi(encoding) > 0) {
835 if (
asprintf(&p,
"CP%s", encoding) >= 0) {
837 lc_all = encoding = p;
855 if (
locale->server_charset)
863 memset(hostname,
'\0',
sizeof(hostname));
864 gethostname(hostname,
sizeof(hostname));
865 hostname[
sizeof(hostname) - 1] =
'\0';
878 const char *
query,
size_t querylen)
900 pcursor->
next = cursor;
922 victim = &
conn->cursors;
923 while (*victim != cursor) {
924 if (*victim ==
NULL) {
928 victim = &(*victim)->
next;
932 *victim = cursor->
next;
1007 if (use_environment) {
1009 if ((s=getenv(
"DSQUERY")) !=
NULL)
1012 if ((s=getenv(
"TDSQUERY")) !=
NULL)
1096 for (; packet; packet =
next) {
1105 if (
conn->authentication)
1106 conn->authentication->free(
conn,
conn->authentication);
1110 while (
conn->cursors)
1120 #if ENABLE_ODBC_MARS
1135 conn->use_iconv = 1;
1144 #if ENABLE_ODBC_MARS
1148 conn->num_sessions = 64;
1183 #ifdef ENABLE_ODBC_MARS
1197 #if ENABLE_ODBC_MARS
1218 tds_free_connection(
conn);
1223 tds_alloc_socket_base(
unsigned int bufsize)
1252 tds_free_connection(
conn);
1263 tds = tds_alloc_socket_base(
conn->env.block_size);
1316 #if ENABLE_ODBC_MARS
1323 if (
tds->sid >= 0 &&
tds->sid <
conn->num_sessions)
1325 for (
n = 0;
n <
conn->num_sessions; ++
n)
1326 if (TDSSOCKET_VALID(
conn->sessions[
n])) {
1341 tds_free_connection(
conn);
1354 #if ENABLE_EXTRA_CHECKS
1366 #if ENABLE_EXTRA_CHECKS
1379 #if ENABLE_ODBC_MARS
1404 if (
conn->env.language)
1406 if (
conn->env.charset)
1408 if (
conn->env.database)
1428 #define SQLS_ENTRY(number,state) case number: p = state; break
1433 const char *p =
NULL;
1459 const char *p =
NULL;
1747 if (memcmp(q,
"42S", 3) == 0)
1748 memcpy(q,
"S00", 3);
1762 if (column_size > 4 * 1024)
1763 column_size = 4 * 1024;
1839 p = realloc(*pp, new_size);
static CS_CONNECTION * conn
#define CHECK_COLUMN_EXTRA(column)
#define CHECK_CONN_EXTRA(conn)
static DLIST_TYPE *DLIST_NAME() next(DLIST_LIST_TYPE *list, DLIST_TYPE *item)
@ TDS_CUR_CONCUR_OPTIMISTIC
#define TDS_ADDITIONAL_SPACE
#define sock_strerror_free(s)
#define TDS_IS_MSSQL(x)
Check if product is Microsft SQL Server.
#define TDS_OFFSET(str, field)
tds_sysdep_int32_type TDS_INT
static void tds_release_cur_dyn(TDSSOCKET *tds)
tds_sysdep_intptr_type TDS_INTPTR
#define TDS_MAX_DYNID_LEN
@ TDS_IDLE
no data expected
tds_sysdep_int16_type TDS_SMALLINT
#define tds_new0(type, n)
tds_sysdep_uint16_type TDS_USMALLINT
#define TDS_RESIZE(p, n_elem)
tds_sysdep_uint32_type TDS_UINT
#define TDS_MAX_CAPABILITY
#define tds_mutex_free(x)
#define tds_mutex_lock(x)
#define tds_mutex_unlock(x)
#define tds_mutex_init(x)
static void tds_ssl_deinit(TDSCONNECTION *conn)
#define TEST_CALLOC(dest, type, n)
#define TEST_MALLOC(dest, type)
#define tds_connection_close
#define tds_init_write_buf
#define tds_lookup_dynamic
#define tds_canonical_charset_name
#define TDS_MUTEX_INITIALIZER
#define tds_alloc_additional_socket
void tds_dstr_zero(DSTR *s)
clear all string filling with zeroes (mainly for security reason)
static void tds_dstr_init(DSTR *s)
init a string with empty
void tds_dstr_free(DSTR *s)
free string
DSTR * tds_dstr_copy(DSTR *s, const char *src) TDS_WUR
copy a string from another
static int tds_dstr_isempty(DSTR *s)
test if string is empty
static TDSSOCKET * tds_init_socket(TDSSOCKET *tds_socket, unsigned int bufsize)
static TDSCONNECTION * tds_init_connection(TDSCONNECTION *conn, TDSCONTEXT *context, unsigned int bufsize)
TDSRESULTINFO * tds_alloc_results(TDS_USMALLINT num_cols)
TDSRET tds_alloc_compute_row(TDSCOMPUTEINFO *res_info)
void tds_free_bcp_column_data(BCPCOLDATA *coldata)
TDSRET tds_alloc_row(TDSRESULTINFO *res_info)
Allocate space for row store return NULL on out of memory.
TDSLOGIN * tds_alloc_login(int use_environment)
static volatile unsigned int inc_num
void tds_detach_results(TDSRESULTINFO *info)
Detach result info from it current socket.
TDSPACKET * tds_realloc_packet(TDSPACKET *packet, unsigned len)
void * tds_alloc_param_data(TDSCOLUMN *curparam)
Allocate data for a parameter.
static void tds_deinit_connection(TDSCONNECTION *conn)
static void tds_free_env(TDSCONNECTION *conn)
TDSLOGIN * tds_init_login(TDSLOGIN *login, TDSLOCALE *locale)
Initialize login structure with locale information and other stuff for connection.
TDSDYNAMIC * tds_alloc_dynamic(TDSCONNECTION *conn, const char *id)
Allocate a dynamic statement.
static void tds_row_free(TDSRESULTINFO *res_info, unsigned char *row)
static TDSCOLUMN * tds_alloc_column(void)
TDSSOCKET * tds_realloc_socket(TDSSOCKET *tds, unsigned int bufsize)
char * tds_alloc_lookup_sqlstate(TDSSOCKET *tds, int msgno)
static char * tds_get_dynid(TDSCONNECTION *conn, char *id)
Get an id for dynamic query based on TDS information.
static void tds_free_compute_result(TDSCOMPUTEINFO *comp_info)
TDSPACKET * tds_alloc_packet(void *buf, unsigned len)
TDSCONTEXT * tds_alloc_context(void *parent)
#define SQLS_ENTRY(number, state)
static int winsock_initialized(void)
void tds_free_param_results(TDSPARAMINFO *param_info)
void tds_free_param_result(TDSPARAMINFO *param_info)
Delete latest parameter.
TDSLOCALE * tds_alloc_locale(void)
static void tds_param_free(TDSCOLUMN *col)
static const TDS_CAPABILITIES defaultcaps
const TDSCOLUMNFUNCS tds_invalid_funcs
TDSPARAMINFO * tds_alloc_param_result(TDSPARAMINFO *old_param)
Adds a output parameter to TDSPARAMINFO.
void tds_set_current_results(TDSSOCKET *tds, TDSRESULTINFO *info)
void tds_free_all_results(TDSSOCKET *tds)
TDSBCPINFO * tds_alloc_bcpinfo(void)
void * tds_realloc(void **pp, size_t new_size)
Reallocate a pointer and update it if success.
void tds_free_context(TDSCONTEXT *context)
void tds_release_cursor(TDSCURSOR **pcursor)
void tds_cursor_deallocated(TDSCONNECTION *conn, TDSCURSOR *cursor)
TDSCURSOR * tds_alloc_cursor(TDSSOCKET *tds, const char *name, size_t namelen, const char *query, size_t querylen)
void tds_free_row(TDSRESULTINFO *res_info, unsigned char *row)
BCPCOLDATA * tds_alloc_bcp_column_data(unsigned int column_size)
TDS_COMPILE_CHECK(tds_values_len, sizeof(defaultcaps.types[0].values)==14)
TDSSOCKET * tds_alloc_socket(TDSCONTEXT *context, unsigned int bufsize)
void tds_free_input_params(TDSDYNAMIC *dyn)
Frees all allocated input parameters of a dynamic statement.
void tds_release_dynamic(TDSDYNAMIC **pdyn)
Frees dynamic statement.
static void tds_free_compute_results(TDSSOCKET *tds)
void tds_dynamic_deallocated(TDSCONNECTION *conn, TDSDYNAMIC *dyn)
void tds_free_bcpinfo(TDSBCPINFO *bcpinfo)
void tds_free_login(TDSLOGIN *login)
void tds_free_msg(TDSMESSAGE *message)
void tds_free_locale(TDSLOCALE *locale)
static void tds_free_column(TDSCOLUMN *col)
char * tds_alloc_client_sqlstate(int msgno)
void tds_deinit_bcpinfo(TDSBCPINFO *bcpinfo)
static TDSCOMPUTEINFO * tds_alloc_compute_result(TDS_USMALLINT num_cols, TDS_USMALLINT by_cols)
Allocate memory for storing compute info return NULL on out of memory.
void tds_free_packets(TDSPACKET *packet)
void tds_free_results(TDSRESULTINFO *res_info)
static void tds_connection_remove_socket(TDSCONNECTION *conn, TDSSOCKET *tds)
TDSCOMPUTEINFO ** tds_alloc_compute_results(TDSSOCKET *tds, TDS_USMALLINT num_cols, TDS_USMALLINT by_cols)
void tds_free_socket(TDSSOCKET *tds)
if(yy_accept[yy_current_state])
int strcmp(const char *str1, const char *str2)
static const char * locale
static PCRE2_SIZE bufsize
#define row(bind, expected)
Information about blobs (e.g.
TDS_CAPABILITY_TYPE types[2]
unsigned char values[32/2-2]
tds_func_row_len * row_len
Metadata about columns in regular and compute rows.
BCPCOLDATA * bcp_column_data
void(* column_data_free)(struct tds_column *column)
const TDSCOLUMNFUNCS * funcs
unsigned char * column_data
unsigned char * column_default
TDS_CHAR * bcp_terminator
TDSENV env
environment is shared between all sessions
TDSCURSOR * cursors
linked list of cursors allocated for this connection contains only cursors allocated on the server
TDSDYNAMIC * dyns
list of dynamic allocated for this connection contains only dynamic allocated on the server
Holds informations about a cursor.
char * cursor_name
name of the cursor
TDS_INT ref_count
reference counter so client can retain safely a pointer
TDS_INT cursor_id
cursor id returned by the server after cursor declare
TDS_INT type
row fetched from this cursor
struct tds_cursor * next
next in linked list, keep first
Holds information for a dynamic (also called prepared) query.
struct tds_dynamic * next
next in linked list, keep first
TDS_INT ref_count
reference counter so client can retain safely a pointer
char id[30]
id of dynamic.
char * query
saved query, we need to know original query if prepare is impossible
TDSPARAMINFO * params
query parameters.
TDSPARAMINFO * res_info
query results
TDS_INT num_id
numeric id for mssql7+
int block_size
packet size (512-65535)
DSTR crlfile
certificate revocation file
unsigned int check_ssl_hostname
DSTR server_realm_name
server realm name (in freetds.conf)
DSTR user_name
account for login
struct addrinfo * ip_addrs
ip(s) of server
DSTR password
password of account login
DSTR db_filename
database filename to attach (MSSQL)
TDS_CAPABILITIES capabilities
unsigned char option_flag2
unsigned int valid_configuration
DSTR server_name
server name (in freetds.conf)
DSTR server_charset
charset of server e.g.
TDS_USMALLINT tds_version
TDS version.
DSTR new_password
new password to set (TDS 7.2+)
struct addrinfo * connected_addr
unsigned int bulk_copy
if bulk copy should be enabled
DSTR cafile
certificate authorities file
DSTR server_spn
server SPN (in freetds.conf)
TDS_TINYINT priv_msg_type
Hold information for any results.
unsigned char * current_row
void(* row_free)(struct tds_result_info *result, unsigned char *row)
Information for a server connection.
void(* env_chg_func)(TDSSOCKET *tds, int type, char *oldval, char *newval)
TDSCOMPUTEINFO ** comp_info
TDS_INT ret_status
return status from store procedure
unsigned out_pos
current position in out_buf
TDSCURSOR * cur_cursor
cursor in use
unsigned char * out_buf
Output buffer.
TDS_TINYINT has_status
true is ret_status is valid
TDSPACKET * send_packet
packet we are preparing to send
unsigned char * in_buf
Input buffer.
TDSDYNAMIC * cur_dyn
dynamic structure in use
bool in_row
true if we are getting rows
TDSRESULTINFO * current_results
Current query information.
unsigned int out_buf_max
Maximum size of packet pointed by out_buf.
TDSPARAMINFO * param_info
static CS_CONTEXT * context