/* FreeTDS - Library of routines accessing Sybase and Microsoft databases
 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005  Brian Bruns
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#ifndef _tds_h_
#define _tds_h_

static const char rcsid_tds_h[] = "$Id: tds.h,v 1.245.2.1 2006/04/16 08:08:38 freddy77 Exp $";
static const void *const no_unused_tds_h_warn[] = { rcsid_tds_h, no_unused_tds_h_warn };

#include <stdio.h>
#include <stdarg.h>
#include <time.h>

/* forward declaration */
typedef struct tdsiconvinfo TDSICONV;
typedef struct tds_socket TDSSOCKET;

#include "tdsver.h"
#include "tds_sysdep_public.h"
#ifdef _FREETDS_LIBRARY_SOURCE
#include "tds_sysdep_private.h"
#endif /* _FREETDS_LIBRARY_SOURCE */

#ifdef __cplusplus
extern "C"
{
#if 0
}
#endif
#endif

/**
 * A structure to hold all the compile-time settings.
 * This structure is returned by tds_get_compiletime_settings
 */

typedef struct _tds_compiletime_settings
{
	const char *freetds_version;	/* release version of FreeTDS */
	const char *last_update;	/* latest software_version date among the modules */
	int msdblib;		/* for MS style dblib */
	int sybase_compat;	/* enable increased Open Client binary compatibility */
	int threadsafe;		/* compile for thread safety default=no */
	int libiconv;		/* search for libiconv in DIR/include and DIR/lib */
	const char *tdsver;	/* TDS protocol version (4.2/4.6/5.0/7.0/8.0) 5.0 */
	int iodbc;		/* build odbc driver against iODBC in DIR */
	int unixodbc;		/* build odbc driver against unixODBC in DIR */

} TDS_COMPILETIME_SETTINGS;

struct DSTR_STRUCT {
	/* keep always at last */
	char dstr_s[1];
};
typedef struct DSTR_STRUCT *DSTR;

/**
 * @file tds.h
 * Main include file for libtds
 */

/**
 * \defgroup libtds LibTDS API
 * Callable functions in \c libtds.
 * 
 * The \c libtds library is for use internal to \em FreeTDS.  It is not
 * intended for use by applications.  Although any use is \em permitted, you're
 * encouraged to use one of the established public APIs instead, because their
 * interfaces are stable and documented by the vendors.  
 */

/* 
 * All references to data that touch the wire should use the following typedefs.  
 *
 * If you have problems on 64-bit machines and the code is 
 * using a native datatype, please change it to use
 * these. (In the TDS layer only, the API layers have their
 * own typedefs which equate to these).
 */
typedef char TDS_CHAR;					/*  8-bit char     */
typedef unsigned char TDS_UCHAR;			/*  8-bit uchar    */
typedef unsigned char TDS_TINYINT;			/*  8-bit unsigned */
typedef tds_sysdep_int16_type TDS_SMALLINT;		/* 16-bit int      */
typedef unsigned tds_sysdep_int16_type TDS_USMALLINT;	/* 16-bit unsigned */
typedef tds_sysdep_int32_type TDS_INT;			/* 32-bit int      */
typedef unsigned tds_sysdep_int32_type TDS_UINT;	/* 32-bit unsigned */
typedef tds_sysdep_real32_type TDS_REAL;		/* 32-bit real     */
typedef tds_sysdep_real64_type TDS_FLOAT;		/* 64-bit real     */
typedef tds_sysdep_int64_type TDS_INT8;			/* 64-bit integer  */
typedef unsigned tds_sysdep_int64_type TDS_UINT8;	/* 64-bit unsigned */
typedef tds_sysdep_intptr_type TDS_INTPTR;

typedef struct tdsnumeric
{
	unsigned char precision;
	unsigned char scale;
	unsigned char array[33];
} TDS_NUMERIC;

typedef struct tdsoldmoney
{
	TDS_INT mnyhigh;
	TDS_UINT mnylow;
} TDS_OLD_MONEY;

typedef union tdsmoney
{
	TDS_OLD_MONEY tdsoldmoney;
	TDS_INT8 mny;
} TDS_MONEY;

typedef struct tdsmoney4
{
	TDS_INT mny4;
} TDS_MONEY4;

typedef struct tdsdatetime
{
	TDS_INT dtdays;
	TDS_INT dttime;
} TDS_DATETIME;

typedef struct tdsdatetime4
{
	TDS_USMALLINT days;
	TDS_USMALLINT minutes;
} TDS_DATETIME4;

typedef struct tdsvarbinary
{
	TDS_SMALLINT len;
	TDS_CHAR array[256];
} TDS_VARBINARY;
typedef struct tdsvarchar
{
	TDS_INT len;
	TDS_CHAR array[256];
} TDS_VARCHAR;

typedef struct tdsunique
{
	TDS_UINT Data1;
	TDS_USMALLINT Data2;
	TDS_USMALLINT Data3;
	TDS_UCHAR Data4[8];
} TDS_UNIQUE;

/** information on data, used by tds_datecrack */
typedef struct tdsdaterec
{
	TDS_INT year;	       /**< year */
	TDS_INT month;	       /**< month number (0-11) */
	TDS_INT day;	       /**< day of month (1-31) */
	TDS_INT dayofyear;     /**< day of year  (1-366) */
	TDS_INT weekday;       /**< day of week  (0-6, 0 = sunday) */
	TDS_INT hour;	       /**< 0-23 */
	TDS_INT minute;	       /**< 0-59 */
	TDS_INT second;	       /**< 0-59 */
	TDS_INT millisecond;   /**< 0-999 */
	TDS_INT tzone;
} TDSDATEREC;

/**
 * The following little table is indexed by precision and will
 * tell us the number of bytes required to store the specified
 * precision.
 */
extern const int tds_numeric_bytes_per_prec[];

#define TDS_SUCCEED          1
#define TDS_FAIL             0
#define TDS_NO_MORE_RESULTS  2
#define TDS_CANCELLED        3

#define TDS_INT_EXIT 0
#define TDS_INT_CONTINUE 1
#define TDS_INT_CANCEL 2
#define TDS_INT_TIMEOUT 3


#define TDS_NO_COUNT         -1

#define TDS_ROW_RESULT        4040
#define TDS_PARAM_RESULT      4042
#define TDS_STATUS_RESULT     4043
#define TDS_MSG_RESULT        4044
#define TDS_COMPUTE_RESULT    4045
#define TDS_CMD_DONE          4046
#define TDS_CMD_SUCCEED       4047
#define TDS_CMD_FAIL          4048
#define TDS_ROWFMT_RESULT     4049
#define TDS_COMPUTEFMT_RESULT 4050
#define TDS_DESCRIBE_RESULT   4051
#define TDS_DONE_RESULT       4052
#define TDS_DONEPROC_RESULT   4053
#define TDS_DONEINPROC_RESULT 4054
#define TDS_OTHERS_RESULT     4055

enum tds_token_results
{
	TDS_TOKEN_RES_OTHERS,
	TDS_TOKEN_RES_ROWFMT,
	TDS_TOKEN_RES_COMPUTEFMT,
	TDS_TOKEN_RES_PARAMFMT,
	TDS_TOKEN_RES_DONE,
	TDS_TOKEN_RES_ROW,
	TDS_TOKEN_RES_COMPUTE,
	TDS_TOKEN_RES_PROC,
	TDS_TOKEN_RES_MSG
};

#define TDS_TOKEN_FLAG(flag) TDS_RETURN_##flag = (1 << (TDS_TOKEN_RES_##flag*2)), TDS_STOPAT_##flag = (2 << (TDS_TOKEN_RES_##flag*2))

enum tds_token_flags
{
	TDS_HANDLE_ALL = 0,
	TDS_TOKEN_FLAG(OTHERS),
	TDS_TOKEN_FLAG(ROWFMT),
	TDS_TOKEN_FLAG(COMPUTEFMT),
	TDS_TOKEN_FLAG(PARAMFMT),
	TDS_TOKEN_FLAG(DONE),
	TDS_TOKEN_FLAG(ROW),
	TDS_TOKEN_FLAG(COMPUTE),
	TDS_TOKEN_FLAG(PROC),
	TDS_TOKEN_FLAG(MSG),
	TDS_TOKEN_RESULTS = TDS_RETURN_ROWFMT|TDS_RETURN_COMPUTEFMT|TDS_RETURN_DONE|TDS_STOPAT_ROW|TDS_STOPAT_COMPUTE|TDS_RETURN_PROC,
	TDS_TOKEN_TRAILING = TDS_STOPAT_ROWFMT|TDS_STOPAT_COMPUTEFMT|TDS_STOPAT_ROW|TDS_STOPAT_COMPUTE|TDS_STOPAT_MSG|TDS_STOPAT_OTHERS
};

enum tds_end
{
	  TDS_DONE_FINAL 	= 0x00	/* final result set, command completed successfully. */
	, TDS_DONE_MORE_RESULTS = 0x01	/* more results follow */
	, TDS_DONE_ERROR 	= 0x02	/* error occurred */
	, TDS_DONE_INXACT 	= 0x04	/* transaction in progress */
	, TDS_DONE_PROC 	= 0x08	/* results are from a stored procedure */
	, TDS_DONE_COUNT 	= 0x10	/* count field in packet is valid */
	, TDS_DONE_CANCELLED 	= 0x20	/* acknowledging an attention command (usually a cancel) */
	, TDS_DONE_EVENT 	= 0x40	/* part of an event notification. */
	, TDS_DONE_SRVERROR 	= 0x100	/* SQL server server error */
	
	/* after the above flags, a TDS_DONE packet has a field describing the state of the transaction */
	, TDS_DONE_NO_TRAN 	= 0	/* No transaction in effect */
	, TDS_DONE_TRAN_SUCCEED = 1	/* Transaction completed successfully */
	, TDS_DONE_TRAN_PROGRESS= 2	/* Transaction in progress */
	, TDS_DONE_STMT_ABORT 	= 3	/* A statement aborted */
	, TDS_DONE_TRAN_ABORT 	= 4	/* Transaction aborted */
};

/*
 * TDS_ERROR indicates a successful processing, but that a TDS_ERROR_TOKEN or TDS_EED_TOKEN error was encountered.  
 * TDS_FAIL indicates an unrecoverable failure.
 */
#define TDS_ERROR            3
#define TDS_DONT_RETURN      42

#define TDS5_PARAMFMT2_TOKEN       32	/* 0x20 */
#define TDS_LANGUAGE_TOKEN         33	/* 0x21    TDS 5.0 only              */
#define TDS_ORDERBY2_TOKEN         34	/* 0x22 */
#define TDS_ROWFMT2_TOKEN          97	/* 0x61    TDS 5.0 only              */
#define TDS_LOGOUT_TOKEN          113	/* 0x71    TDS 5.0 only? ct_close()  */
#define TDS_RETURNSTATUS_TOKEN    121	/* 0x79                              */
#define TDS_PROCID_TOKEN          124	/* 0x7C    TDS 4.2 only - TDS_PROCID */
#define TDS7_RESULT_TOKEN         129	/* 0x81    TDS 7.0 only              */
#define TDS7_COMPUTE_RESULT_TOKEN 136	/* 0x88    TDS 7.0 only              */
#define TDS_COLNAME_TOKEN         160	/* 0xA0    TDS 4.2 only              */
#define TDS_COLFMT_TOKEN          161	/* 0xA1    TDS 4.2 only - TDS_COLFMT */
#define TDS_DYNAMIC2_TOKEN        163	/* 0xA3 */
#define TDS_TABNAME_TOKEN         164	/* 0xA4 */
#define TDS_COLINFO_TOKEN         165	/* 0xA5 */
#define TDS_OPTIONCMD_TOKEN   	  166	/* 0xA6 */
#define TDS_COMPUTE_NAMES_TOKEN   167	/* 0xA7 */
#define TDS_COMPUTE_RESULT_TOKEN  168	/* 0xA8 */
#define TDS_ORDERBY_TOKEN         169	/* 0xA9    TDS_ORDER                 */
#define TDS_ERROR_TOKEN           170	/* 0xAA                              */
#define TDS_INFO_TOKEN            171	/* 0xAB                              */
#define TDS_PARAM_TOKEN           172	/* 0xAC    RETURNVALUE?              */
#define TDS_LOGINACK_TOKEN        173	/* 0xAD                              */
#define TDS_CONTROL_TOKEN         174	/* 0xAE    TDS_CONTROL               */
#define TDS_ROW_TOKEN             209	/* 0xD1                              */
#define TDS_CMP_ROW_TOKEN         211	/* 0xD3                              */
#define TDS5_PARAMS_TOKEN         215	/* 0xD7    TDS 5.0 only              */
#define TDS_CAPABILITY_TOKEN      226	/* 0xE2                              */
#define TDS_ENVCHANGE_TOKEN       227	/* 0xE3                              */
#define TDS_EED_TOKEN             229	/* 0xE5                              */
#define TDS_DBRPC_TOKEN           230	/* 0xE6                              */
#define TDS5_DYNAMIC_TOKEN        231	/* 0xE7    TDS 5.0 only              */
#define TDS5_PARAMFMT_TOKEN       236	/* 0xEC    TDS 5.0 only              */
#define TDS_AUTH_TOKEN            237	/* 0xED                              */
#define TDS_RESULT_TOKEN          238	/* 0xEE                              */
#define TDS_DONE_TOKEN            253	/* 0xFD    TDS_DONE                  */
#define TDS_DONEPROC_TOKEN        254	/* 0xFE    TDS_DONEPROC              */
#define TDS_DONEINPROC_TOKEN      255	/* 0xFF    TDS_DONEINPROC            */

/* CURSOR support: TDS 5.0 only*/
#define TDS_CURCLOSE_TOKEN        128  /* 0x80    TDS 5.0 only              */
#define TDS_CURFETCH_TOKEN        130  /* 0x82    TDS 5.0 only              */
#define TDS_CURINFO_TOKEN         131  /* 0x83    TDS 5.0 only              */
#define TDS_CUROPEN_TOKEN         132  /* 0x84    TDS 5.0 only              */
#define TDS_CURDECLARE_TOKEN      134  /* 0x86    TDS 5.0 only              */

enum {
	TDS_CUR_ISTAT_UNUSED    = 0x00,
	TDS_CUR_ISTAT_DECLARED  = 0x01,
	TDS_CUR_ISTAT_OPEN      = 0x02,
	TDS_CUR_ISTAT_CLOSED    = 0x04,
	TDS_CUR_ISTAT_RDONLY    = 0x08,
	TDS_CUR_ISTAT_UPDATABLE = 0x10,
	TDS_CUR_ISTAT_ROWCNT    = 0x20,
	TDS_CUR_ISTAT_DEALLOC   = 0x40
};

/* 
 * Cursor Declare, SetRows, Open and Close all return 0x83 token. 
 * But only SetRows includes the rowcount (4 byte) in the stream. 
 * So for Setrows we read the rowcount from the stream and not for others. 
 * These values are useful to determine when to read the rowcount from the packet
 */
#define IS_DECLARE  100
#define IS_CURROW   200
#define IS_OPEN     300
#define IS_CLOSE    400

/* states for tds_process_messages() */
#define PROCESS_ROWS    0
#define PROCESS_RESULTS 1
#define CANCEL_PROCESS  2
#define GOTO_1ST_ROW    3
#define LOGIN           4

/* environment type field */
#define TDS_ENV_DATABASE  	1
#define TDS_ENV_LANG      	2
#define TDS_ENV_CHARSET   	3
#define TDS_ENV_PACKSIZE  	4
#define TDS_ENV_LCID        	5
#define TDS_ENV_SQLCOLLATION	7

/* string types */
#define TDS_NULLTERM -9

/* Microsoft internal stored procedure id's */

#define TDS_SP_CURSOR           1
#define TDS_SP_CURSOROPEN       2
#define TDS_SP_CURSORPREPARE    3
#define TDS_SP_CURSOREXECUTE    4
#define TDS_SP_CURSORPREPEXEC   5
#define TDS_SP_CURSORUNPREPARE  6
#define TDS_SP_CURSORFETCH      7
#define TDS_SP_CURSOROPTION     8
#define TDS_SP_CURSORCLOSE      9
#define TDS_SP_EXECUTESQL      10
#define TDS_SP_PREPARE         11
#define TDS_SP_EXECUTE         12
#define TDS_SP_PREPEXEC        13
#define TDS_SP_PREPEXECRPC     14
#define TDS_SP_UNPREPARE       15
/* 
 * <rant> Sybase does an awful job of this stuff, non null ints of size 1 2 
 * and 4 have there own codes but nullable ints are lumped into INTN
 * sheesh! </rant>
 */
typedef enum
{
	SYBCHAR = 47,		/* 0x2F */
#define SYBCHAR	SYBCHAR
	SYBVARCHAR = 39,	/* 0x27 */
#define SYBVARCHAR	SYBVARCHAR
	SYBINTN = 38,		/* 0x26 */
#define SYBINTN	SYBINTN
	SYBINT1 = 48,		/* 0x30 */
#define SYBINT1	SYBINT1
	SYBINT2 = 52,		/* 0x34 */
#define SYBINT2	SYBINT2
	SYBINT4 = 56,		/* 0x38 */
#define SYBINT4	SYBINT4
	SYBINT8 = 127,		/* 0x7F */
#define SYBINT8	SYBINT8
	SYBFLT8 = 62,		/* 0x3E */
#define SYBFLT8	SYBFLT8
	SYBDATETIME = 61,	/* 0x3D */
#define SYBDATETIME	SYBDATETIME
	SYBBIT = 50,		/* 0x32 */
#define SYBBIT	SYBBIT
	SYBTEXT = 35,		/* 0x23 */
#define SYBTEXT	SYBTEXT
	SYBNTEXT = 99,		/* 0x63 */
#define SYBNTEXT	SYBNTEXT
	SYBIMAGE = 34,		/* 0x22 */
#define SYBIMAGE	SYBIMAGE
	SYBMONEY4 = 122,	/* 0x7A */
#define SYBMONEY4	SYBMONEY4
	SYBMONEY = 60,		/* 0x3C */
#define SYBMONEY	SYBMONEY
	SYBDATETIME4 = 58,	/* 0x3A */
#define SYBDATETIME4	SYBDATETIME4
	SYBREAL = 59,		/* 0x3B */
#define SYBREAL	SYBREAL
	SYBBINARY = 45,		/* 0x2D */
#define SYBBINARY	SYBBINARY
	SYBVOID = 31,		/* 0x1F */
#define SYBVOID	SYBVOID
	SYBVARBINARY = 37,	/* 0x25 */
#define SYBVARBINARY	SYBVARBINARY
	SYBNVARCHAR = 103,	/* 0x67 */
#define SYBNVARCHAR	SYBNVARCHAR
	SYBBITN = 104,		/* 0x68 */
#define SYBBITN	SYBBITN
	SYBNUMERIC = 108,	/* 0x6C */
#define SYBNUMERIC	SYBNUMERIC
	SYBDECIMAL = 106,	/* 0x6A */
#define SYBDECIMAL	SYBDECIMAL
	SYBFLTN = 109,		/* 0x6D */
#define SYBFLTN	SYBFLTN
	SYBMONEYN = 110,	/* 0x6E */
#define SYBMONEYN	SYBMONEYN
	SYBDATETIMN = 111,	/* 0x6F */
#define SYBDATETIMN	SYBDATETIMN
	XSYBCHAR = 175,		/* 0xAF */
#define XSYBCHAR	XSYBCHAR
	XSYBVARCHAR = 167,	/* 0xA7 */
#define XSYBVARCHAR	XSYBVARCHAR
	XSYBNVARCHAR = 231,	/* 0xE7 */
#define XSYBNVARCHAR	XSYBNVARCHAR
	XSYBNCHAR = 239,	/* 0xEF */
#define XSYBNCHAR	XSYBNCHAR
	XSYBVARBINARY = 165,	/* 0xA5 */
#define XSYBVARBINARY	XSYBVARBINARY
	XSYBBINARY = 173,	/* 0xAD */
#define XSYBBINARY	XSYBBINARY
	SYBLONGBINARY = 225,	/* 0xE1 */
#define SYBLONGBINARY	SYBLONGBINARY
	SYBSINT1 = 64,		/* 0x40 */
#define SYBSINT1	SYBSINT1
	SYBUINT2 = 65,		/* 0x41 */
#define SYBUINT2	SYBUINT2
	SYBUINT4 = 66,		/* 0x42 */
#define SYBUINT4	SYBUINT4
	SYBUINT8 = 67,		/* 0x43 */
#define SYBUINT8	SYBUINT8

	SYBUNIQUE = 36,		/* 0x24 */
#define SYBUNIQUE	SYBUNIQUE
	SYBVARIANT = 98 	/* 0x62 */
#define SYBVARIANT	SYBVARIANT
} TDS_SERVER_TYPE;


typedef enum
{
	USER_UNICHAR_TYPE = 34,		/* 0x22 */
	USER_UNIVARCHAR_TYPE = 35	/* 0x23 */
} TDS_USER_TYPE;

#define SYBAOPCNT  0x4b
#define SYBAOPCNTU 0x4c
#define SYBAOPSUM  0x4d
#define SYBAOPSUMU 0x4e
#define SYBAOPAVG  0x4f
#define SYBAOPAVGU 0x50
#define SYBAOPMIN  0x51
#define SYBAOPMAX  0x52

/* mssql2k compute operator */
#define SYBAOPCNT_BIG		0x09
#define SYBAOPSTDEV		0x30
#define SYBAOPSTDEVP		0x31
#define SYBAOPVAR		0x32
#define SYBAOPVARP		0x33
#define SYBAOPCHECKSUM_AGG	0x72


/** 
 * options that can be sent with a TDS_OPTIONCMD token
 */
typedef enum
{
	  TDS_OPT_SET = 1	/* Set an option. */
	, TDS_OPT_DEFAULT = 2	/* Set option to its default value. */
	, TDS_OPT_LIST = 3	/* Request current setting of a specific option. */
	, TDS_OPT_INFO = 4	/* Report current setting of a specific option. */
} TDS_OPTION_CMD;

typedef enum
{
	  TDS_OPT_DATEFIRST = 1		/* 0x01 */
	, TDS_OPT_TEXTSIZE = 2		/* 0x02 */
	, TDS_OPT_STAT_TIME = 3		/* 0x03 */
	, TDS_OPT_STAT_IO = 4		/* 0x04 */
	, TDS_OPT_ROWCOUNT = 5		/* 0x05 */
	, TDS_OPT_NATLANG = 6		/* 0x06 */
	, TDS_OPT_DATEFORMAT = 7	/* 0x07 */
	, TDS_OPT_ISOLATION = 8		/* 0x08 */
	, TDS_OPT_AUTHON = 9		/* 0x09 */
	, TDS_OPT_CHARSET = 10		/* 0x0a */
	, TDS_OPT_SHOWPLAN = 13		/* 0x0d */
	, TDS_OPT_NOEXEC = 14		/* 0x0e */
	, TDS_OPT_ARITHIGNOREON = 15	/* 0x0f */
	, TDS_OPT_ARITHABORTON = 17	/* 0x11 */
	, TDS_OPT_PARSEONLY = 18	/* 0x12 */
	, TDS_OPT_GETDATA = 20		/* 0x14 */
	, TDS_OPT_NOCOUNT = 21		/* 0x15 */
	, TDS_OPT_FORCEPLAN = 23	/* 0x17 */
	, TDS_OPT_FORMATONLY = 24	/* 0x18 */
	, TDS_OPT_CHAINXACTS = 25	/* 0x19 */
	, TDS_OPT_CURCLOSEONXACT = 26	/* 0x1a */
	, TDS_OPT_FIPSFLAG = 27		/* 0x1b */
	, TDS_OPT_RESTREES = 28		/* 0x1c */
	, TDS_OPT_IDENTITYON = 29	/* 0x1d */
	, TDS_OPT_CURREAD = 30		/* 0x1e */
	, TDS_OPT_CURWRITE = 31		/* 0x1f */
	, TDS_OPT_IDENTITYOFF = 32	/* 0x20 */
	, TDS_OPT_AUTHOFF = 33		/* 0x21 */
	, TDS_OPT_ANSINULL = 34		/* 0x22 */
	, TDS_OPT_QUOTED_IDENT = 35	/* 0x23 */
	, TDS_OPT_ARITHIGNOREOFF = 36	/* 0x24 */
	, TDS_OPT_ARITHABORTOFF = 37	/* 0x25 */
	, TDS_OPT_TRUNCABORT = 38	/* 0x26 */
} TDS_OPTION;

typedef union tds_option_arg
{
	TDS_TINYINT ti;
	TDS_INT i;
	TDS_CHAR *c;
} TDS_OPTION_ARG;

enum {
	TDS_OPT_ARITHOVERFLOW = 0x01,
	TDS_OPT_NUMERICTRUNC = 0x02
};

enum TDS_OPT_DATEFIRST_CHOICE
{
	TDS_OPT_MONDAY = 1, TDS_OPT_TUESDAY = 2, TDS_OPT_WEDNESDAY = 3, TDS_OPT_THURSDAY = 4, TDS_OPT_FRIDAY = 5, TDS_OPT_SATURDAY =
		6, TDS_OPT_SUNDAY = 7
};

enum TDS_OPT_DATEFORMAT_CHOICE
{
	TDS_OPT_FMTMDY = 1, TDS_OPT_FMTDMY = 2, TDS_OPT_FMTYMD = 3, TDS_OPT_FMTYDM = 4, TDS_OPT_FMTMYD = 5, TDS_OPT_FMTDYM = 6
};
enum TDS_OPT_ISOLATION_CHOICE
{
	TDS_OPT_LEVEL1 = 1, TDS_OPT_LEVEL3 = 3
};

typedef enum tds_packet_type
{
	TDS_QUERY = 1,
	TDS_RPC = 3,
	TDS_CANCEL = 6,
	TDS_BULK = 7,
	TDS_NORMAL = 15
} TDS_PACKET_TYPE;


#define TDS_ZERO_FREE(x) do {free((x)); (x) = NULL;} while(0)
#define TDS_VECTOR_SIZE(x) (sizeof(x)/sizeof(x[0]))

/*
 * TODO use system macros for optimization
 * See mcrypt for reference and linux kernel source for optimization
 * check if unaligned access and use fast write/read when implemented
 */
#define TDS_BYTE_SWAP16(value)                 \
         (((((unsigned short)value)<<8) & 0xFF00)   | \
          ((((unsigned short)value)>>8) & 0x00FF))

#define TDS_BYTE_SWAP32(value)                     \
         (((((unsigned long)value)<<24) & 0xFF000000)  | \
          ((((unsigned long)value)<< 8) & 0x00FF0000)  | \
          ((((unsigned long)value)>> 8) & 0x0000FF00)  | \
          ((((unsigned long)value)>>24) & 0x000000FF))

#define is_end_token(x) (x==TDS_DONE_TOKEN    || \
			x==TDS_DONEPROC_TOKEN    || \
			x==TDS_DONEINPROC_TOKEN)

#define is_hard_end_token(x) (x==TDS_DONE_TOKEN    || \
			x==TDS_DONEPROC_TOKEN)

#define is_msg_token(x) (x==TDS_INFO_TOKEN    || \
			x==TDS_ERROR_TOKEN    || \
			x==TDS_EED_TOKEN)

#define is_result_token(x) (x==TDS_RESULT_TOKEN || \
			x==TDS_ROWFMT2_TOKEN    || \
			x==TDS7_RESULT_TOKEN    || \
			x==TDS_COLFMT_TOKEN     || \
			x==TDS_COLNAME_TOKEN    || \
			x==TDS_RETURNSTATUS_TOKEN)

/* FIX ME -- not a complete list */
#define is_fixed_type(x) (x==SYBINT1    || \
			x==SYBINT2      || \
			x==SYBINT4      || \
			x==SYBINT8      || \
			x==SYBREAL      || \
			x==SYBFLT8      || \
			x==SYBDATETIME  || \
			x==SYBDATETIME4 || \
			x==SYBBIT       || \
			x==SYBMONEY     || \
			x==SYBMONEY4    || \
			x==SYBVOID      || \
			x==SYBUNIQUE)
#define is_nullable_type(x) ( \
			x==SYBBITN      || \
                     x==SYBINTN      || \
                     x==SYBFLTN      || \
                     x==SYBMONEYN    || \
                     x==SYBDATETIMN  || \
                     x==SYBVARCHAR   || \
                     x==SYBBINARY    || \
                     x==SYBVARBINARY || \
                     x==SYBTEXT      || \
                     x==SYBNTEXT     || \
                     x==SYBIMAGE)

#define is_blob_type(x) (x==SYBTEXT || x==SYBIMAGE || x==SYBNTEXT)
/* large type means it has a two byte size field */
/* define is_large_type(x) (x>128) */
#define is_numeric_type(x) (x==SYBNUMERIC || x==SYBDECIMAL)
#define is_unicode_type(x) (x==XSYBNVARCHAR || x==XSYBNCHAR || x==SYBNTEXT)
#define is_collate_type(x) (x==XSYBVARCHAR || x==XSYBCHAR || x==SYBTEXT || x==XSYBNVARCHAR || x==XSYBNCHAR || x==SYBNTEXT)
#define is_ascii_type(x) ( x==XSYBCHAR || x==XSYBVARCHAR || x==SYBTEXT || x==SYBCHAR || x==SYBVARCHAR)
#define is_binary_type(x) (x==SYBLONGBINARY)
#define is_char_type(x) (is_unicode_type(x) || is_ascii_type(x))
#define is_similar_type(x, y) ((is_char_type(x) && is_char_type(y)) || ((is_unicode_type(x) && is_unicode_type(y))))


#define TDS_MAX_CAPABILITY	22
#define MAXPRECISION 		80
#define TDS_MAX_CONN		4096
#define TDS_MAX_DYNID_LEN	30

/* defaults to use if no others are found */
#define TDS_DEF_SERVER		"SYBASE"
#define TDS_DEF_BLKSZ		512
#define TDS_DEF_CHARSET		"iso_1"
#define TDS_DEF_LANG		"us_english"
#if TDS42
#define TDS_DEF_MAJOR		4
#define TDS_DEF_MINOR		2
#define TDS_DEF_PORT		1433
#elif TDS46
#define TDS_DEF_MAJOR		4
#define TDS_DEF_MINOR		6
#define TDS_DEF_PORT		4000
#elif TDS70
#define TDS_DEF_MAJOR		7
#define TDS_DEF_MINOR		0
#define TDS_DEF_PORT		1433
#elif TDS80
#define TDS_DEF_MAJOR		8
#define TDS_DEF_MINOR		0
#define TDS_DEF_PORT		1433
#else
#define TDS_DEF_MAJOR		5
#define TDS_DEF_MINOR		0
#define TDS_DEF_PORT		4000
#endif

/* normalized strings from freetds.conf file */
#define TDS_STR_VERSION  "tds version"
#define TDS_STR_BLKSZ    "initial block size"
#define TDS_STR_SWAPDT   "swap broken dates"
#define TDS_STR_SWAPMNY  "swap broken money"
#define TDS_STR_DUMPFILE "dump file"
#define TDS_STR_DEBUGLVL "debug level"
#define TDS_STR_DEBUGFLAGS "debug flags"
#define TDS_STR_TIMEOUT  "timeout"
#define TDS_STR_QUERY_TIMEOUT  "query timeout"
#define TDS_STR_CONNTIMEOUT "connect timeout"
#define TDS_STR_HOSTNAME "hostname"
#define TDS_STR_HOST     "host"
#define TDS_STR_PORT     "port"
#define TDS_STR_TEXTSZ   "text size"
/* for big endian hosts */
#define TDS_STR_EMUL_LE	"emulate little endian"
#define TDS_STR_CHARSET	"charset"
#define TDS_STR_CLCHARSET	"client charset"
#define TDS_STR_LANGUAGE	"language"
#define TDS_STR_APPENDMODE	"dump file append"
#define TDS_STR_DATEFMT	"date format"
#define TDS_STR_INSTANCE "instance"

/* TODO do a better check for alignment than this */
typedef union
{
	void *p;
	int i;
} tds_align_struct;

#define TDS_ALIGN_SIZE sizeof(tds_align_struct)

#define TDS_MAX_LOGIN_STR_SZ 30
typedef struct tds_login
{
	DSTR server_name;
	DSTR server_addr;
	int port;
	TDS_TINYINT major_version;	/* TDS version */
	TDS_TINYINT minor_version;	/* TDS version */
	int block_size;
	DSTR language;		/* ie us-english */
	DSTR server_charset;	/*  ie iso_1 */
	TDS_INT connect_timeout;
	DSTR host_name;
	DSTR app_name;
	DSTR user_name;
	DSTR password;
	
	DSTR library;	/* Ct-Library, DB-Library,  TDS-Library or ODBC */
	TDS_TINYINT bulk_copy;
	TDS_TINYINT suppress_language;
	TDS_TINYINT encrypted;

	TDS_INT query_timeout;
	unsigned char capabilities[TDS_MAX_CAPABILITY];
	DSTR client_charset;
} TDSLOGIN;

typedef struct tds_connection
{
	/* first part of structure is the same of login one */
	DSTR server_name; /**< server name (in freetds.conf) */
	int port;	   /**< port of database service */
	TDS_TINYINT major_version;
	TDS_TINYINT minor_version;
	int block_size;
	DSTR language;
	DSTR server_charset;	/**< charset of server */
	TDS_INT connect_timeout;
	DSTR host_name;	    /**< client hostname */
	DSTR app_name;
	DSTR user_name;	    /**< account for login */
	DSTR password;	    /**< password of account login */
	DSTR library;
	TDS_TINYINT bulk_copy;
	TDS_TINYINT suppress_language;
	TDS_TINYINT encrypted;

	TDS_INT query_timeout;
	unsigned char capabilities[TDS_MAX_CAPABILITY];
	DSTR client_charset;

	DSTR ip_addr;	  /**< ip of server */
	DSTR instance_name;
	DSTR database;
	DSTR dump_file;
	int debug_flags;
	int text_size;
	int broken_dates;
	int broken_money;
	int emul_little_endian;
} TDSCONNECTION;

typedef struct tds_locale
{
	char *language;
	char *server_charset;
	char *client_charset;
	char *date_fmt;
} TDSLOCALE;

/** 
 * Information about blobs (e.g. text or image).
 * current_row contains this structure.
 */
typedef struct tds_blob
{
	TDS_CHAR *textvalue;
	TDS_CHAR textptr[16];
	TDS_CHAR timestamp[8];
} TDSBLOB;

/** 
 * TDS 8.0 collation information.
 */
typedef struct
{
	TDS_USMALLINT locale_id;	/* master..syslanguages.lcid */
	TDS_USMALLINT flags;
	TDS_UCHAR charset_id;		/* or zero */
} TDS8_COLLATION;

/* SF stands for "sort flag" */
#define TDS_SF_BIN                   (TDS_USMALLINT) 0x100
#define TDS_SF_WIDTH_INSENSITIVE     (TDS_USMALLINT) 0x080
#define TDS_SF_KATATYPE_INSENSITIVE  (TDS_USMALLINT) 0x040
#define TDS_SF_ACCENT_SENSITIVE      (TDS_USMALLINT) 0x020
#define TDS_SF_CASE_INSENSITIVE      (TDS_USMALLINT) 0x010

/* UT stands for user type */
#define TDS_UT_TIMESTAMP             80


/**
 * Information relevant to libiconv.  The name is an iconv name, not 
 * the same as found in master..syslanguages. 
 */
typedef struct _tds_encoding
{
	const char *name;
	unsigned char min_bytes_per_char;
	unsigned char max_bytes_per_char;
} TDS_ENCODING;

typedef struct _tds_bcpcoldata
{
	TDS_UCHAR *data;
	TDS_INT    datalen;
	TDS_INT    null_column;
} BCPCOLDATA;


enum
{ TDS_SYSNAME_SIZE = 512 };

/** 
 * Metadata about columns in regular and compute rows 
 */
typedef struct tds_column
{
	TDS_SMALLINT column_type;	/**< This type can be different from wire type because 
	 				 * conversion (e.g. UCS-2->Ascii) can be applied.    
					 * I'm beginning to wonder about the wisdom of this, however. 
					 * April 2003 jkl
					 */
	TDS_INT column_usertype;
	TDS_INT column_flags;

	TDS_INT column_size;		/**< maximun size of data. For fixed is the size. */

	TDS_TINYINT column_varint_size;	/**< size of length when reading from wire (0, 1, 2 or 4) */

	TDS_TINYINT column_prec;	/**< precision for decimal/numeric */
	TDS_TINYINT column_scale;	/**< scale for decimal/numeric */

	TDS_SMALLINT column_namelen;	/**< length of column name */
	TDS_SMALLINT table_namelen;
	struct
	{
		TDS_SMALLINT column_type;	/**< type of data, saved from wire */
		TDS_INT column_size;
	} on_server;

	const TDSICONV *char_conv;	/**< refers to previously allocated iconv information */

	TDS_CHAR table_name[TDS_SYSNAME_SIZE];
	TDS_CHAR column_name[TDS_SYSNAME_SIZE];

	TDS_INT column_offset;		/**< offset into row buffer for store data */
	unsigned int column_nullable:1;
	unsigned int column_writeable:1;
	unsigned int column_identity:1;
	unsigned int column_key:1;
	unsigned int column_hidden:1;
	unsigned int column_output:1;
	unsigned int column_timestamp:1;
	TDS_UCHAR column_collation[5];

	/* additional fields flags for compute results */
	TDS_TINYINT column_operator;
	TDS_SMALLINT column_operand;

	/* FIXME this is data related, not column */
	/** size written in variable (ie: char, text, binary). -1 if NULL. */
	TDS_INT column_cur_size;

	/* related to binding or info stored by client libraries */
	/* FIXME find a best place to store these data, some are unused */
	TDS_SMALLINT column_bindtype;
	TDS_SMALLINT column_bindfmt;
	TDS_UINT column_bindlen;
	TDS_SMALLINT *column_nullbind;
	TDS_CHAR *column_varaddr;
	TDS_INT *column_lenbind;
	TDS_INT column_textpos;
	TDS_INT column_text_sqlgetdatapos;

	BCPCOLDATA *bcp_column_data;
	/**
	 * The length, in bytes, of any length prefix this column may have.
	 * For example, strings in some non-C programming languages are
	 * made up of a one-byte length prefix, followed by the string
	 * data itself.
	 * If the data does not have a length prefix, set prefixlen to 0.
	 * Currently not very used in code, however do not remove.
	 */
	TDS_INT bcp_prefix_len;
	TDS_INT bcp_term_len;
	TDS_CHAR *bcp_terminator;
} TDSCOLUMN;


/** Hold information for any results */
typedef struct tds_result_info
{
	/* TODO those fields can became a struct */
	TDS_SMALLINT num_cols;
	TDSCOLUMN **columns;
	TDS_INT row_size;
	TDS_INT ref_count;
	unsigned char *current_row;

	TDS_SMALLINT rows_exist;
	/* TODO remove ?? used only in dblib */
	TDS_INT row_count;
	/* TODO remove ?? used only in dblib */
	TDS_TINYINT more_results;
	TDS_SMALLINT computeid;
	TDS_SMALLINT *bycolumns;
	TDS_SMALLINT by_cols;
} TDSRESULTINFO;

/* values for tds->state */
typedef enum _TDS_STATE
{
	TDS_IDLE,
	TDS_QUERYING,
	TDS_PENDING,
	TDS_READING,
	TDS_DEAD
} TDS_STATE;

#define TDS_DBG_FUNC    __FILE__, ((__LINE__ << 4) | 7)
#define TDS_DBG_INFO2   __FILE__, ((__LINE__ << 4) | 6)
#define TDS_DBG_INFO1   __FILE__, ((__LINE__ << 4) | 5)
#define TDS_DBG_NETWORK __FILE__, ((__LINE__ << 4) | 4)
#define TDS_DBG_WARN    __FILE__, ((__LINE__ << 4) | 3)
#define TDS_DBG_ERROR   __FILE__, ((__LINE__ << 4) | 2)
#define TDS_DBG_SEVERE  __FILE__, ((__LINE__ << 4) | 1)

#define TDS_DBGFLAG_FUNC    0x80
#define TDS_DBGFLAG_INFO2   0x40
#define TDS_DBGFLAG_INFO1   0x20
#define TDS_DBGFLAG_NETWORK 0x10
#define TDS_DBGFLAG_WARN    0x08
#define TDS_DBGFLAG_ERROR   0x04
#define TDS_DBGFLAG_SEVERE  0x02
#define TDS_DBGFLAG_ALLLVL  0xfff
#define TDS_DBGFLAG_PID     0x1000
#define TDS_DBGFLAG_TIME    0x2000
#define TDS_DBGFLAG_SOURCE  0x4000
#define TDS_DBGFLAG_THREAD  0x8000

/**
 * An attempt at better logging.
 * Using these bitmapped values, various logging features can be turned on and off.
 * It can be especially helpful to turn packet data on/off for security reasons.
 */
enum TDS_DBG_LOG_STATE
{
	  TDS_DBG_LOGIN = 1		/* for diagnosing login problems;                                       
				 	   otherwise the username/password information is suppressed. */
	, TDS_DBG_API =    (1 << 1)	/* Log calls to client libraries */
	, TDS_DBG_ASYNC =  (1 << 2)	/* Log asynchronous function starts or completes. */
	, TDS_DBG_DIAG =   (1 << 3)	/* Log client- and server-generated messages */
	, TDS_DBG_error =  (1 << 4)
	/* TODO:  ^^^^^ make upper case when old #defines (above) are removed */
	/* Log FreeTDS runtime/logic error occurs. */
	, TDS_DBG_PACKET = (1 << 5)	/* Log hex dump of packets to/from the server. */
	, TDS_DBG_LIBTDS = (1 << 6)	/* Log calls to (and in) libtds */
	, TDS_DBG_CONFIG = (1 << 7)	/* replaces TDSDUMPCONFIG */
	, TDS_DBG_DEFAULT = 0xFE	/* all above except login packets */
};

typedef struct tds_result_info TDSCOMPUTEINFO;

typedef TDSRESULTINFO TDSPARAMINFO;

typedef struct tds_message
{
	TDS_SMALLINT priv_msg_type;
	TDS_SMALLINT line_number;
	TDS_UINT msgno;
	TDS_SMALLINT state;
	TDS_SMALLINT severity;
	TDS_CHAR *server;
	TDS_CHAR *message;
	TDS_CHAR *proc_name;
	TDS_CHAR *sql_state;
} TDSMESSAGE;

typedef struct tds_upd_col
{
	struct tds_upd_col *next;	
	TDS_INT colnamelength;
	char * columnname;
} TDSUPDCOL;

typedef enum {
	  TDS_CURSOR_STATE_UNACTIONED = 0   /* initial value */
	, TDS_CURSOR_STATE_REQUESTED = 1	/* called by ct_cursor */ 
	, TDS_CURSOR_STATE_SENT = 2		/* sent to server */
	, TDS_CURSOR_STATE_ACTIONED = 3		/* acknowledged by server */
} TDS_CURSOR_STATE;

typedef struct _tds_cursor_status
{
	TDS_CURSOR_STATE declare;
	TDS_CURSOR_STATE cursor_row;
	TDS_CURSOR_STATE open;
	TDS_CURSOR_STATE fetch;
	TDS_CURSOR_STATE close; 
	TDS_CURSOR_STATE dealloc;
} TDS_CURSOR_STATUS;

typedef struct _tds_cursor 
{
	struct _tds_cursor *next;	/**< next in linked list, keep first */
	TDS_INT length;			/**< total length of the remaining datastream */
	TDS_TINYINT cursor_name_len;	/**< length of cursor name > 0 and <= 30  */
	char *cursor_name;		/**< name of the cursor */
	TDS_INT cursor_id;		/**< cursor id returned by the server after cursor declare */
	TDS_TINYINT options;		/**< read only|updatable */
	TDS_TINYINT hasargs;		/**< cursor parameters exists ? */
	TDS_USMALLINT query_len;	/**< SQL query length */
	char *query;                 	/**< SQL query */
	/* TODO for updatable columns */
	TDS_TINYINT number_upd_cols;	/**< number of updatable columns */
	TDS_INT cursor_rows;		/**< number of cursor rows to fetch */
	/*TODO when cursor has parameters*/
	/*TDS_PARAM *param_list;	 cursor parameter */
	TDSUPDCOL *cur_col_list;	/**< updatable column list */
	TDS_CURSOR_STATUS status;
	TDS_SMALLINT srv_status;
	TDSRESULTINFO *res_info;
} TDSCURSOR;

/*
 * Current environment as reported by the server
 */
typedef struct tds_env
{
	int block_size;
	char *language;
	char *charset;
	char *database;
} TDSENV;

typedef struct tds_dynamic
{
	struct tds_dynamic *next;	/**< next in linked list, keep first */
	char id[30];
	int dyn_state;
	/** numeric id for mssql7+*/
	TDS_INT num_id;
	TDSPARAMINFO *res_info;
	TDSPARAMINFO *params;
	int emulated;
	/** saved query, we need to know original query if prepare is impossible*/
	char *query;
} TDSDYNAMIC;

typedef enum {
	TDS_MULTIPLE_QUERY,
	TDS_MULTIPLE_EXECUTE,
	TDS_MULTIPLE_RPC
} TDS_MULTIPLE_TYPE;

typedef struct tds_multiple
{
	TDS_MULTIPLE_TYPE type;
	unsigned int flags;
} TDSMULTIPLE;

/* forward declaration */
typedef struct tds_context TDSCONTEXT;

struct tds_context
{
	TDSLOCALE *locale;
	void *parent;
	/* handler */
	int (*msg_handler) (const TDSCONTEXT *, TDSSOCKET *, TDSMESSAGE *);
	int (*err_handler) (const TDSCONTEXT *, TDSSOCKET *, TDSMESSAGE *);
};

enum TDS_ICONV_ENTRY
{ 
	  client2ucs2
	, client2server_chardata
	, iso2server_metadata
	, initial_char_conv_count	/* keep last */
};

struct tds_socket
{
	/* fixed and connect time */
	TDS_SYS_SOCKET s;
	TDS_SMALLINT major_version;
	TDS_SMALLINT minor_version;
	/** version of product (Sybase/MS and full version) */
	TDS_UINT product_version;
	char *product_name;
	unsigned char capabilities[TDS_MAX_CAPABILITY];
	unsigned char broken_dates;
	unsigned char option_flag2;
	/* in/out buffers */
	unsigned char *in_buf;
	unsigned char *out_buf;
	unsigned int in_buf_max;
	unsigned in_pos;
	unsigned out_pos;
	unsigned in_len;
	/* TODO remove blocksize from env and use out_len ?? */
/*	unsigned out_len; */
	unsigned char in_flag;
	unsigned char out_flag;
	unsigned char last_packet;
	void *parent;
	/**
	 * info about current query. 
	 * Contain information in process, even normal results and compute.
	 * This pointer shouldn't be freed it's just an alias to another structure.
	 */
	TDSRESULTINFO *current_results;
	TDSRESULTINFO *res_info;
	TDS_INT num_comp_info;
	TDSCOMPUTEINFO **comp_info;
	TDSPARAMINFO *param_info;
	TDSCURSOR *cur_cursor;	/**< cursor in use */
	TDSCURSOR *cursors;	/**< linked list of cursors allocated for this connection */
	TDS_TINYINT has_status;
	TDS_INT ret_status;
	TDS_STATE state;
	volatile unsigned char in_cancel;
	int rows_affected;
	/* timeout stuff from Jeff */
	TDS_INT query_timeout;
	int (*query_timeout_func) (void *param, unsigned int total_timeout);
	void *query_timeout_param;
	time_t query_start_time;
	TDSENV env;

	/* dynamic placeholder stuff */
	TDSDYNAMIC *cur_dyn;	/**< dynamic structure in use */
	TDSDYNAMIC *dyns;	/**< list of dynamic allocate for this connection */

	int emul_little_endian;
	char *date_fmt;
	const TDSCONTEXT *tds_ctx;
	int char_conv_count;
	TDSICONV **char_convs;

	/** config for login stuff. After login this field is NULL */
	TDSCONNECTION *connection;

	int spid;
	TDS_UCHAR collation[5];
	void (*env_chg_func) (TDSSOCKET * tds, int type, char *oldval, char *newval);
	int internal_sp_called;

	void *tls_session;
	void *tls_credentials;
	int option_value;
};

int tds_init_write_buf(TDSSOCKET * tds);
void tds_free_result_info(TDSRESULTINFO * info);
void tds_free_socket(TDSSOCKET * tds);
void tds_free_connection(TDSCONNECTION * connection);
void tds_free_all_results(TDSSOCKET * tds);
void tds_free_results(TDSRESULTINFO * res_info);
void tds_free_param_results(TDSPARAMINFO * param_info);
void tds_free_param_result(TDSPARAMINFO * param_info);
void tds_free_msg(TDSMESSAGE * message);
void tds_free_cursor(TDSSOCKET * tds, TDSCURSOR * cursor);
void tds_free_bcp_column_data(BCPCOLDATA * coldata);

int tds_put_n(TDSSOCKET * tds, const void *buf, int n);
int tds_put_string(TDSSOCKET * tds, const char *buf, int len);
int tds_put_int(TDSSOCKET * tds, TDS_INT i);
int tds_put_int8(TDSSOCKET * tds, TDS_INT8 i);
int tds_put_smallint(TDSSOCKET * tds, TDS_SMALLINT si);
/** Output a tinyint value */
#define tds_put_tinyint(tds, ti) tds_put_byte(tds,ti)
int tds_put_byte(TDSSOCKET * tds, unsigned char c);
TDSRESULTINFO *tds_alloc_results(int num_cols);
TDSCOMPUTEINFO **tds_alloc_compute_results(TDSSOCKET * tds, int num_cols, int by_cols);
TDSCONTEXT *tds_alloc_context(void * parent);
void tds_free_context(TDSCONTEXT * locale);
TDSSOCKET *tds_alloc_socket(TDSCONTEXT * context, int bufsize);

/* config.c */
const TDS_COMPILETIME_SETTINGS *tds_get_compiletime_settings(void);
typedef void (*TDSCONFPARSE) (const char *option, const char *value, void *param);
int tds_read_conf_section(FILE * in, const char *section, TDSCONFPARSE tds_conf_parse, void *parse_param);
int tds_read_conf_file(TDSCONNECTION * connection, const char *server);
TDSCONNECTION *tds_read_config_info(TDSSOCKET * tds, TDSLOGIN * login, TDSLOCALE * locale);
void tds_fix_connection(TDSCONNECTION * connection);
void tds_config_verstr(const char *tdsver, TDSCONNECTION * connection);
void tds_lookup_host(const char *servername, char *ip);
int tds_set_interfaces_file_loc(const char *interfloc);

TDSLOCALE *tds_get_locale(void);
unsigned char *tds_alloc_row(TDSRESULTINFO * res_info);
unsigned char *tds_alloc_compute_row(TDSCOMPUTEINFO * res_info);
BCPCOLDATA * tds_alloc_bcp_column_data(int column_size);
int tds_alloc_get_string(TDSSOCKET * tds, char **string, int len);
unsigned char *tds7_crypt_pass(const unsigned char *clear_pass, int len, unsigned char *crypt_pass);
TDSDYNAMIC *tds_lookup_dynamic(TDSSOCKET * tds, char *id);
const char *tds_prtype(int token);



/* iconv.c */
void tds_iconv_open(TDSSOCKET * tds, const char *charset);
void tds_iconv_close(TDSSOCKET * tds);
void tds_srv_charset_changed(TDSSOCKET * tds, const char *charset);
void tds7_srv_charset_changed(TDSSOCKET * tds, int sql_collate, int lcid);
int tds_iconv_alloc(TDSSOCKET * tds);
void tds_iconv_free(TDSSOCKET * tds);
TDSICONV *tds_iconv_from_collate(TDSSOCKET * tds, int sql_collate, int lcid);

/* threadsafe.c */
char *tds_timestamp_str(char *str, int maxlen);
struct hostent *tds_gethostbyname_r(const char *servername, struct hostent *result, char *buffer, int buflen, int *h_errnop);
struct hostent *tds_gethostbyaddr_r(const char *addr, int len, int type, struct hostent *result, char *buffer, int buflen,
				    int *h_errnop);
struct servent *tds_getservbyname_r(const char *name, const char *proto, struct servent *result, char *buffer, int buflen);
#ifdef INADDR_NONE
const char *tds_inet_ntoa_r(struct in_addr iaddr, char *ip, size_t len);
#endif
char *tds_get_homedir(void);

/* mem.c */
TDSPARAMINFO *tds_alloc_param_result(TDSPARAMINFO * old_param);
void tds_free_input_params(TDSDYNAMIC * dyn);
void tds_free_dynamic(TDSSOCKET * tds, TDSDYNAMIC * dyn);
TDSSOCKET *tds_realloc_socket(TDSSOCKET * tds, int bufsize);
unsigned char *tds_alloc_param_row(TDSPARAMINFO * info, TDSCOLUMN * curparam);
char *tds_alloc_client_sqlstate(int msgno);
char *tds_alloc_lookup_sqlstate(TDSSOCKET * tds, int msgno);
TDSLOGIN *tds_alloc_login(void);
TDSDYNAMIC *tds_alloc_dynamic(TDSSOCKET * tds, const char *id);
void tds_free_login(TDSLOGIN * login);
TDSCONNECTION *tds_alloc_connection(TDSLOCALE * locale);
TDSLOCALE *tds_alloc_locale(void);
void tds_free_locale(TDSLOCALE * locale);
TDSCURSOR * tds_alloc_cursor(TDSSOCKET * tds, const char *name, TDS_INT namelen, const char *query, TDS_INT querylen);
void tds_free_row(const TDSRESULTINFO * res_info, unsigned char *row);

/* login.c */
int tds7_send_auth(TDSSOCKET * tds, const unsigned char *challenge);
void tds_set_packet(TDSLOGIN * tds_login, int packet_size);
void tds_set_port(TDSLOGIN * tds_login, int port);
void tds_set_passwd(TDSLOGIN * tds_login, const char *password);
void tds_set_bulk(TDSLOGIN * tds_login, TDS_TINYINT enabled);
void tds_set_user(TDSLOGIN * tds_login, const char *username);
void tds_set_app(TDSLOGIN * tds_login, const char *application);
void tds_set_host(TDSLOGIN * tds_login, const char *hostname);
void tds_set_server_addr(TDSLOGIN * tds_login, const char *server_addr);
void tds_set_library(TDSLOGIN * tds_login, const char *library);
void tds_set_server(TDSLOGIN * tds_login, const char *server);
void tds_set_client_charset(TDSLOGIN * tds_login, const char *charset);
void tds_set_language(TDSLOGIN * tds_login, const char *language);
void tds_set_version(TDSLOGIN * tds_login, short major_ver, short minor_ver);
void tds_set_capabilities(TDSLOGIN * tds_login, unsigned char *capabilities, int size);
int tds_connect(TDSSOCKET * tds, TDSCONNECTION * connection);

/* query.c */
int tds_submit_query(TDSSOCKET * tds, const char *query);
int tds_submit_query_params(TDSSOCKET * tds, const char *query, TDSPARAMINFO * params);
int tds_submit_queryf(TDSSOCKET * tds, const char *queryf, ...);
int tds_submit_prepare(TDSSOCKET * tds, const char *query, const char *id, TDSDYNAMIC ** dyn_out, TDSPARAMINFO * params);
int tds_submit_execdirect(TDSSOCKET * tds, const char *query, TDSPARAMINFO * params);
int tds_submit_execute(TDSSOCKET * tds, TDSDYNAMIC * dyn);
int tds_send_cancel(TDSSOCKET * tds);
const char *tds_next_placeholder(const char *start);
int tds_count_placeholders(const char *query);
int tds_get_dynid(TDSSOCKET * tds, char **id);
int tds_submit_unprepare(TDSSOCKET * tds, TDSDYNAMIC * dyn);
int tds_submit_rpc(TDSSOCKET * tds, const char *rpc_name, TDSPARAMINFO * params);
int tds_submit_optioncmd(TDSSOCKET * tds, TDS_OPTION_CMD command, TDS_OPTION option, TDS_OPTION_ARG *param, TDS_INT param_size);
int tds_quote_id(TDSSOCKET * tds, char *buffer, const char *id, int idlen);
int tds_quote_string(TDSSOCKET * tds, char *buffer, const char *str, int len);
const char *tds_skip_quoted(const char *s);

int tds_cursor_declare(TDSSOCKET * tds, TDSCURSOR * cursor, int *send);
int tds_cursor_setrows(TDSSOCKET * tds, TDSCURSOR * cursor, int *send);
int tds_cursor_open(TDSSOCKET * tds, TDSCURSOR * cursor, int *send);
int tds_cursor_fetch(TDSSOCKET * tds, TDSCURSOR * cursor);
int tds_cursor_close(TDSSOCKET * tds, TDSCURSOR * cursor);
int tds_cursor_dealloc(TDSSOCKET * tds, TDSCURSOR * cursor);

int tds_multiple_init(TDSSOCKET *tds, TDSMULTIPLE *multiple, TDS_MULTIPLE_TYPE type);
int tds_multiple_done(TDSSOCKET *tds, TDSMULTIPLE *multiple);
int tds_multiple_query(TDSSOCKET *tds, TDSMULTIPLE *multiple, const char *query, TDSPARAMINFO * params);
int tds_multiple_execute(TDSSOCKET *tds, TDSMULTIPLE *multiple, TDSDYNAMIC * dyn);

/* token.c */
int tds_process_cancel(TDSSOCKET * tds);
void tds_swap_datatype(int coltype, unsigned char *buf);
void tds_swap_numeric(TDS_NUMERIC *num);
int tds_get_token_size(int marker);
int tds_process_login_tokens(TDSSOCKET * tds);
void tds_add_row_column_size(TDSRESULTINFO * info, TDSCOLUMN * curcol);
int tds_process_simple_query(TDSSOCKET * tds);
int tds5_send_optioncmd(TDSSOCKET * tds, TDS_OPTION_CMD tds_command, TDS_OPTION tds_option, TDS_OPTION_ARG * tds_argument,
			TDS_INT * tds_argsize);
int tds_client_msg(const TDSCONTEXT * tds_ctx, TDSSOCKET * tds, int msgno, int severity, int state, int line, const char *message);
int tds_process_tokens(TDSSOCKET * tds, TDS_INT * result_type, int *done_flags, unsigned flag);

/* data.c */
void tds_set_param_type(TDSSOCKET * tds, TDSCOLUMN * curcol, TDS_SERVER_TYPE type);
void tds_set_column_type(TDSCOLUMN * curcol, int type);


/* tds_convert.c */
TDS_INT tds_datecrack(TDS_INT datetype, const void *di, TDSDATEREC * dr);
int tds_get_conversion_type(int srctype, int colsize);
extern const char tds_hex_digits[];

/* write.c */
int tds_flush_packet(TDSSOCKET * tds);
int tds_put_buf(TDSSOCKET * tds, const unsigned char *buf, int dsize, int ssize);

/* read.c */
unsigned char tds_get_byte(TDSSOCKET * tds);
void tds_unget_byte(TDSSOCKET * tds);
unsigned char tds_peek(TDSSOCKET * tds);
TDS_SMALLINT tds_get_smallint(TDSSOCKET * tds);
TDS_INT tds_get_int(TDSSOCKET * tds);
int tds_get_string(TDSSOCKET * tds, int string_len, char *dest, size_t dest_size);
int tds_get_char_data(TDSSOCKET * tds, char *dest, size_t wire_size, TDSCOLUMN * curcol);
void *tds_get_n(TDSSOCKET * tds, void *dest, int n);
int tds_get_size_by_type(int servertype);


/* util.c */
TDS_STATE tds_set_state(TDSSOCKET * tds, TDS_STATE state);
void tds_set_parent(TDSSOCKET * tds, void *the_parent);
void *tds_get_parent(TDSSOCKET * tds);
int tds_swap_bytes(unsigned char *buf, int bytes);
int tds_version(TDSSOCKET * tds_socket, char *pversion_string);
void tdsdump_off(void);
void tdsdump_on(void);
int tdsdump_open(const char *filename);
void tdsdump_close(void);
void tdsdump_dump_buf(const char* file, unsigned int level_line, const char *msg, const void *buf, int length);
void tdsdump_log(const char* file, unsigned int level_line, const char *fmt, ...) 
#if defined(__GNUC__) && __GNUC__ >= 2
	__attribute__ ((__format__ (__printf__, 3, 4)))
#endif
;
extern int tds_debug_flags;

/* net.c */
int tds_open_socket(TDSSOCKET * tds, const char *ip_addr, unsigned int port, int timeout);
int tds_close_socket(TDSSOCKET * tds);
int tds_read_packet(TDSSOCKET * tds);
int tds_write_packet(TDSSOCKET * tds, unsigned char final);
int tds7_get_instance_port(const char *ip_addr, const char *instance);
int tds_ssl_init(TDSSOCKET *tds);
void tds_ssl_deinit(TDSSOCKET *tds);



/* vstrbuild.c */
int tds_vstrbuild(char *buffer, int buflen, int *resultlen, char *text, int textlen, const char *formats, int formatlen,
		  va_list ap);

/* numeric.c */
char *tds_money_to_string(const TDS_MONEY * money, char *s);
TDS_INT tds_numeric_to_string(const TDS_NUMERIC * numeric, char *s);
TDS_INT tds_numeric_change_prec_scale(TDS_NUMERIC * numeric, unsigned char new_prec, unsigned char new_scale);

/* getmac.c */
void tds_getmac(int s, unsigned char mac[6]);

typedef struct tds_answer
{
	unsigned char lm_resp[24];
	unsigned char nt_resp[24];
} TDSANSWER;
void tds_answer_challenge(const char *passwd, const unsigned char *challenge, TDSANSWER * answer);

#define IS_TDS42(x) (x->major_version==4 && x->minor_version==2)
#define IS_TDS46(x) (x->major_version==4 && x->minor_version==6)
#define IS_TDS50(x) (x->major_version==5 && x->minor_version==0)
#define IS_TDS70(x) (x->major_version==7 && x->minor_version==0)
#define IS_TDS80(x) (x->major_version==8 && x->minor_version==0)

#define IS_TDS7_PLUS(x) ( IS_TDS70(x) || IS_TDS80(x) )

#define IS_TDSDEAD(x) (((x) == NULL) || TDS_IS_SOCKET_INVALID((x)->s))

/** Check if product is Sybase (such as Adaptive Server Enterrprice). x should be a TDS_SOCKET*. */
#define TDS_IS_SYBASE(x) (!(x->product_version & 0x80000000u))
/** Check if product is Microsft SQL Server. x should be a TDS_SOCKET*. */
#define TDS_IS_MSSQL(x) ((x->product_version & 0x80000000u)!=0)

/** Calc a version number for mssql. Use with TDS_MS_VER(7,0,842).
 * For test for a range of version you can use check like
 * if (tds->product_version >= TDS_MS_VER(7,0,0) && tds->product_version < TDS_MS_VER(8,0,0)) */
#define TDS_MS_VER(maj,min,x) (0x80000000u|((maj)<<24)|((min)<<16)|(x))

/* TODO test if not similar to ms one*/
/** Calc a version number for Sybase. */
#define TDS_SYB_VER(maj,min,x) (((maj)<<24)|((min)<<16)|(x)<<8)

#ifdef __cplusplus
#if 0
{
#endif
}
#endif

#endif /* _tds_h_ */
