a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | |
c5c154 | 2006-02-14 | Henrik Grubbström (Grubba) | | * $Id: tds.pike,v 1.11 2006/02/14 10:20:34 grubba Exp $
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | *
* A Pike implementation of the TDS protocol.
*
* Henrik Grubbström 2006-02-08.
*/
|
c5c154 | 2006-02-14 | Henrik Grubbström (Grubba) | |
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | |
#ifdef TDS_DEBUG
#define TDS_WERROR(X...) werror("TDS:" + X)
#else
#define TDS_WERROR(X...)
#endif
|
5495b4 | 2006-02-13 | Henrik Grubbström (Grubba) | | #ifdef TDS_CONVERT_DEBUG
#define TDS_CONV_WERROR(X...) werror("TDS: Convert: " + X)
#else
#define TDS_CONV_WERROR(X...)
#endif
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | |
static int filter_noprint(int char)
{
return ((char == 32) || ((char != 0x7f) && (char & 0x60)))?char:'.';
}
static string hex_dump(string data) {
array(string) lines = data/16.0;
int off;
foreach(lines; int i; string line) {
array(array(int)) halves = (array(array(int)))((line + ("\0"*16))/8);
lines[i] = sprintf("%04x:%{ %02x%}:%{%02x %} %s:%s\n",
off, halves[0], halves[1],
(string)map(halves[0], filter_noprint),
(string)map(halves[1], filter_noprint));
off += 16;
}
return lines * "";
}
|
26d74c | 2006-02-10 | Henrik Grubbström (Grubba) | | #if (__REAL_MAJOR__ > 7) || ((__REAL_MAJOR__ == 7) && (__REAL_MINOR__ >= 6))
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | static {
|
26d74c | 2006-02-10 | Henrik Grubbström (Grubba) | | #endif /* Pike 7.6 or later */
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | constant DEF_MAJOR = 8;
constant DEF_MINOR = 0;
constant DEF_PORT = 1433;
constant DEF_DOMAIN = "";
constant DEFAULT_CAPABILITIES =
"\x01\x09\x00\x00\x06\x6d\x7f\xff"
"\xff\xff\xfe\x02\x09\x00\x00\x00"
"\x00\x0a\x68\x00\x00\x00";
constant TDS8VERSION = "\x01\x00\x00\x71";
constant CLIENTVERSION = "\x06\x83\xf2\xf8";
constant CONNECTIONID = "\0\0\0\0";
constant TIMEZONE = "\x88\xff\xff\xff";
constant COLLATION = "\x36\x04\x00\x00";
enum Token {
TDS_ERROR = 3,
TDS_DONT_RETURN = 42,
TDS5_PARAMFMT2_TOKEN = 32,
TDS_LANGUAGE_TOKEN = 33,
TDS_ORDERBY2_TOKEN = 34,
TDS_ROWFMT2_TOKEN = 97,
TDS_LOGOUT_TOKEN = 113,
TDS_RETURNSTATUS_TOKEN = 121,
TDS_PROCID_TOKEN = 124,
TDS7_RESULT_TOKEN = 129,
TDS7_COMPUTE_RESULT_TOKEN = 136,
TDS_COLNAME_TOKEN = 160,
TDS_COLFMT_TOKEN = 161,
TDS_DYNAMIC2_TOKEN = 163,
TDS_TABNAME_TOKEN = 164,
TDS_COLINFO_TOKEN = 165,
TDS_OPTIONCMD_TOKEN = 166,
TDS_COMPUTE_NAMES_TOKEN = 167,
TDS_COMPUTE_RESULT_TOKEN = 168,
TDS_ORDERBY_TOKEN = 169,
TDS_ERROR_TOKEN = 170,
TDS_INFO_TOKEN = 171,
TDS_PARAM_TOKEN = 172,
TDS_LOGINACK_TOKEN = 173,
TDS_CONTROL_TOKEN = 174,
TDS_ROW_TOKEN = 209,
TDS_CMP_ROW_TOKEN = 211,
TDS5_PARAMS_TOKEN = 215,
TDS_CAPABILITY_TOKEN = 226,
TDS_ENVCHANGE_TOKEN = 227,
TDS_EED_TOKEN = 229,
TDS_DBRPC_TOKEN = 230,
TDS5_DYNAMIC_TOKEN = 231,
TDS5_PARAMFMT_TOKEN = 236,
TDS_AUTH_TOKEN = 237,
TDS_RESULT_TOKEN = 238,
TDS_DONE_TOKEN = 253,
TDS_DONEPROC_TOKEN = 254,
TDS_DONEINPROC_TOKEN = 255,
TDS_CURCLOSE_TOKEN = 128,
TDS_CURFETCH_TOKEN = 130,
TDS_CURINFO_TOKEN = 131,
TDS_CUROPEN_TOKEN = 132,
TDS_CURDECLARE_TOKEN = 134,
};
enum EnvType {
TDS_ENV_DATABASE = 1,
TDS_ENV_LANG = 2,
TDS_ENV_CHARSET = 3,
TDS_ENV_PACKSIZE = 4,
TDS_ENV_LCID = 5,
TDS_ENV_SQLCOLLATION = 7,
};
enum ColType {
SYBBINARY = 45,
SYBBIT = 50,
SYBBITN = 104,
SYBCHAR = 47,
SYBDATETIME = 61,
SYBDATETIME4 = 58,
SYBDATETIMN = 111,
SYBDECIMAL = 106,
SYBFLT8 = 62,
SYBFLTN = 109,
SYBIMAGE = 34,
SYBINT1 = 48,
SYBINT2 = 52,
SYBINT4 = 56,
SYBINT8 = 127,
SYBINTN = 38,
SYBLONGBINARY = 225,
SYBMONEY = 60,
SYBMONEY4 = 122,
SYBMONEYN = 110,
SYBNTEXT = 99,
SYBNUMERIC = 108,
SYBNVARCHAR = 103,
SYBREAL = 59,
SYBSINT1 = 64,
SYBTEXT = 35,
SYBUINT2 = 65,
SYBUINT4 = 66,
SYBUINT8 = 67,
SYBUNIQUE = 36,
SYBVARBINARY = 37,
SYBVARCHAR = 39,
SYBVARIANT = 98,
SYBVOID = 31,
XSYBBINARY = 173,
XSYBCHAR = 175,
XSYBNCHAR = 239,
XSYBNVARCHAR = 231,
XSYBVARBINARY = 165,
XSYBVARCHAR = 167,
TDS_UT_TIMESTAMP = 80,
};
enum ResultTypes {
TDS_ROW_RESULT = 4040,
TDS_PARAM_RESULT = 4042,
TDS_STATUS_RESULT = 4043,
TDS_MSG_RESULT = 4044,
TDS_COMPUTE_RESULT = 4045,
TDS_CMD_DONE = 4046,
TDS_CMD_SUCCEED = 4047,
TDS_CMD_FAIL = 4048,
TDS_ROWFMT_RESULT = 4049,
TDS_COMPUTEFMT_RESULT = 4050,
TDS_DESCRIBE_RESULT = 4051,
TDS_DONE_RESULT = 4052,
TDS_DONEPROC_RESULT = 4053,
TDS_DONEINPROC_RESULT = 4054,
};
string server_data;
string last_error;
void tds_error(string msg, mixed ... args)
{
if (sizeof(args)) msg = sprintf(msg, @args);
|
9e76f0 | 2006-02-10 | Henrik Grubbström (Grubba) | | predef::error(last_error = msg);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
static object utf16enc = Locale.Charset.encoder("UTF16LE");
static string string_to_utf16(string s)
{
return utf16enc->feed(s)->drain();
}
static object utf16dec = Locale.Charset.decoder("UTF16LE");
static string utf16_to_string(string s)
{
return utf16dec->feed(s)->drain();
}
class Connection {
int major_version = DEF_MAJOR;
int minor_version = DEF_MINOR;
int port = DEF_PORT;
int block_size = 4096;
string server = "";
string server_charset = "";
string hostname = gethostname();
string appname = "";
string username = "";
string password = "";
string language = "";
string library_name = "TDS-Library";
string database = "";
string domain;
string capabilities = DEFAULT_CAPABILITIES;
Stdio.File socket;
#define FMT_SMALLINT "%-2c"
#define FMT_INT "%-4c"
#define FMT_INT8 "%-4c"
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | class InPacket
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | {
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | int inpos = 0;
string inbuf = "";
int done;
|
9e76f0 | 2006-02-10 | Henrik Grubbström (Grubba) | |
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | static void fill_buf()
{
if (done) {
TDS_WERROR("Filling buffer on finished packet!\n"
"%s\n", hex_dump(inbuf));
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | tds_error("Filling buffer on finished packet!\n");
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | }
|
9e76f0 | 2006-02-10 | Henrik Grubbström (Grubba) | |
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | string header = socket->read(8);
if (!header || sizeof(header) < 8) {
busy = !(done = 1);
tds_error("Failed to read packet header: %O, %s.\n",
header, strerror(socket->errno()));
}
TDS_WERROR("Read header:\n%s\n", hex_dump(header));
int packet_type;
int last_packet;
int len;
sscanf(header, "%-1c%-1c%2c", packet_type, last_packet, len);
len -= 8;
busy = !(done = last_packet);
string data = socket->read(len);
if (!data || sizeof(data) < len) {
tds_error("Failed to read packet data (%d bytes), got %O (%d bytes), %s\n",
len, data, sizeof(data||""), strerror(socket->errno()));
}
TDS_WERROR("Read packet with %d bytes.\n%s\n",
sizeof(data), hex_dump(data));
inbuf = inbuf[inpos..] + data;
inpos = 0;
}
|
9e76f0 | 2006-02-10 | Henrik Grubbström (Grubba) | |
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | static void destroy()
{
while (!done) {
inbuf = "";
inpos = 0;
fill_buf();
}
}
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | string get_raw(int bytes)
{
while (inpos + bytes > sizeof(inbuf)) {
fill_buf();
}
string raw = inbuf[inpos..inpos + bytes - 1];
inpos += bytes;
return raw;
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | string peek_raw(int bytes)
{
while (inpos + bytes > sizeof(inbuf)) {
fill_buf();
}
string raw = inbuf[inpos..inpos + bytes - 1];
return raw;
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | int get_int8()
{
return array_sscanf(get_raw(8), "%-8c")[0];
}
int get_int()
{
return array_sscanf(get_raw(4), "%-4c")[0];
}
int get_int_be()
{
return array_sscanf(get_raw(4), "%4c")[0];
}
int get_smallint()
{
return array_sscanf(get_raw(2), "%-2c")[0];
}
int get_byte()
{
return array_sscanf(get_raw(1), "%-1c")[0];
}
int peek_byte()
{
return array_sscanf(peek_raw(1), "%-1c")[0];
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | string get_string(int len)
{
if (!len) return "";
TDS_WERROR("get_string(%d)...\n", len);
return utf16_to_string(get_raw(len*2));
}
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | |
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | void expect(string s)
{
string r = get_raw(sizeof(s));
if (r != s) {
tds_error("Expectation failed: Got %O, expected %O\n",
r, s);
}
}
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | |
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | static void create()
{
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | if (busy) {
tds_error("Creating InPacket on busy connection!\n");
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | }
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | busy = 1;
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
}
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | |
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | class Packet
{
array(string|int) segments = ({});
array(string) strings = ({});
int flags;
static void create(int|void flags)
{
this_program::flags = flags;
}
void put_int8(int i)
{
segments += ({ sprintf("%-8c", i) });
}
void put_int(int i)
{
segments += ({ sprintf("%-4c", i) });
}
void put_smallint(int i)
{
segments += ({ sprintf("%-2c", i) });
}
void put_byte(int i)
{
segments += ({ sprintf("%-1c", i) });
}
void put_raw(string raw, int len)
{
if (sizeof(raw) != len) {
tds_error("Internal error: unexpected raw length: %O (expected %d)\n",
raw, len);
}
segments += ({raw});
}
void put_raw_string(string s)
{
if (1 || sizeof(s)) {
segments += ({ sizeof(strings) });
strings += ({ s });
} else {
segments += ({ sprintf("%-2c%-2c", 0, 0) });
}
}
void put_string(string s)
{
put_raw_string(string_to_utf16(s));
}
void put_long_raw_string(string s)
{
if (sizeof(s)) {
segments += ({ ~sizeof(strings) });
strings += ({ s });
} else {
segments += ({ sprintf("%-2c%-2c%-4c", 0, 0, 0) });
}
}
void put_long_string(string s)
{
put_long_raw_string(string_to_utf16(s));
}
void put_domain_login(string domain, string hostname)
{
string raw = sprintf("NTLMSSP\0s%-4c%-4c%-2c%-2c%-4c%-2c%-2c%-4c%s%s",
1, 0xb201,
sizeof(domain), sizeof(domain),
32 + sizeof(hostname),
sizeof(hostname), sizeof(hostname),
32,
hostname, domain);
segments += ({ sizeof(strings) });
strings += ({ raw });
}
mixed cast(string s)
{
int trailer_start = flags && 4;
foreach(segments, string|int seg) {
trailer_start += stringp(seg)?sizeof(seg):(seg<0)?8:4;
}
foreach(segments; int i; string|int seg) {
if (intp(seg)) {
if (seg < 0) {
seg = ~seg;
segments[i] = sprintf("%-2c%-2c%-4c",
sizeof(strings[seg]),
sizeof(strings[seg]),
trailer_start);
TDS_WERROR("Long string %O at offset %d\n",
strings[seg], trailer_start);
} else {
segments[i] = sprintf("%-2c%-2c",
trailer_start, sizeof(strings[seg])/2);
TDS_WERROR("Short string %O at offset %d\n",
strings[seg], trailer_start);
}
segments += ({ strings[seg] });
trailer_start += sizeof(strings[seg]);
}
}
string res = segments * "";
TDS_WERROR("Generated packet: %O (%d bytes)\n",
res, sizeof(res));
if (!flags) return res;
return sprintf("%-4c%s", sizeof(res)+4, res);
}
}
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | InPacket send_packet(Packet p, int flag, int|void last)
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | {
|
9e76f0 | 2006-02-10 | Henrik Grubbström (Grubba) | | if (busy) {
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | tds_error("Sending packet on busy connection!\n");
|
9e76f0 | 2006-02-10 | Henrik Grubbström (Grubba) | | }
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | |
|
95b516 | 2006-02-10 | Henrik Grubbström (Grubba) | | array(string) packets = ((string) p)/32768.0;
|
9855ff | 2006-02-10 | Henrik Grubbström (Grubba) | | foreach(packets; int i; string raw) {
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | |
raw = sprintf("%1c%1c%2c\0\0%1c\0%s",
|
9855ff | 2006-02-10 | Henrik Grubbström (Grubba) | | flag, (i == (sizeof(packets)-1)) && last,
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | sizeof(raw) + 8,
1,
raw);
TDS_WERROR("Wrapped packet: %O\n%s\n", raw, hex_dump(raw));
if (socket->write(raw) != sizeof(raw)) {
socket->close();
socket = 0;
tds_error("Failed to send packet.\n"
"raw: %O\n", raw);
}
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | |
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | if (last) return InPacket();
return 0;
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
static string crypt_pass(string password)
{
password = string_to_utf16(password);
password ^= "\x5a"*sizeof(password);
return (string)map((array)password,
lambda(int byte) {
return ((byte >> 4) | (byte << 4)) & 0xff;
});
}
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | static InPacket send_login()
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | {
password = password[..127];
Packet p = Packet(1);
p->put_raw(TDS8VERSION, 4);
p->put_int(0);
p->put_raw(CLIENTVERSION, 4);
p->put_int(getpid());
p->put_raw(CONNECTIONID, 4);
p->put_byte(0x80|0x40|0x20);
p->put_byte(3|(domain && 0x80));
p->put_byte(0);
p->put_byte(0);
p->put_raw(TIMEZONE, 4);
p->put_raw(COLLATION, 4);
p->put_string(hostname);
if (domain) {
p->put_string("");
p->put_string("");
} else {
p->put_string(username);
p->put_raw_string(crypt_pass(password));
}
p->put_string(appname);
p->put_string(server);
p->put_smallint(0);
p->put_smallint(0);
p->put_string("");
p->put_string(language);
p->put_string(database);
p->put_raw("\0"*6, 6);
if (domain) {
p->put_domain_login(domain, hostname);
} else {
p->put_string("");
}
p->put_string("");
TDS_WERROR("Sending login packet.\n");
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | return send_packet(p, 0x10, 1);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
string ecb_encrypt(string data, string key)
{
|
26d74c | 2006-02-10 | Henrik Grubbström (Grubba) | | #if constant(Crypto.DES)
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | Crypto.DES des = Crypto.DES();
des->set_encrypt_key(des->fix_parity(key));
|
26d74c | 2006-02-10 | Henrik Grubbström (Grubba) | | #else
Crypto.des des = Crypto.des();
des->set_encrypt_key(Crypto.des_parity(key));
#endif
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | return des->crypt(data);
}
string encrypt_answer(string hash, string nonce)
{
return ecb_encrypt(nonce, hash[..6]) +
ecb_encrypt(nonce, hash[7..13]) +
ecb_encrypt(nonce, hash[14..]);
}
string answer_lan_mgr_challenge(string passwd, string nonce)
{
string magic = "KGS!@#$%";
passwd = upper_case((passwd + "\0"*14)[..13]);
string hash =
ecb_encrypt(magic, passwd[..6]) +
ecb_encrypt(magic, passwd[7..]);
return encrypt_answer(hash, nonce);
}
string answer_nt_challenge(string passwd, string nonce)
{
string nt_passwd = string_to_utf16(passwd);
|
26d74c | 2006-02-10 | Henrik Grubbström (Grubba) | | #if constant(Crypto.MD4)
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | Crypto.MD4 md4 = Crypto.MD4();
|
26d74c | 2006-02-10 | Henrik Grubbström (Grubba) | | #else
Crypto.md4 md4 = Crypto.md4();
#endif
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | md4->update(nt_passwd);
return encrypt_answer(md4->digest() + "\0"*16, nonce);
}
static void send_auth(string nonce)
{
int out_flag = 0x11;
Packet p = Packet();
p->put_raw("NTLMSSP\0", 8);
p->put_int(3);
p->put_long_raw_string(answer_lan_mgr_challenge(password, nonce));
p->put_long_raw_string(answer_nt_challenge(password, nonce));
p->put_long_string(domain);
p->put_long_string(username);
p->put_long_string(hostname);
p->put_long_string("");
p->put_int(0x8201);
TDS_WERROR("Sending auth packet.\n");
send_packet(p, 0x11);
}
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | static void process_auth(InPacket inp)
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | {
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | int pdu_size = inp->get_smallint();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | if (pdu_size < 32) tds_error("Bad pdu size: %d\n", pdu_size);
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | inp->expect("NTLMSSP\0");
inp->get_int();
inp->get_int();
inp->get_int();
inp->get_int();
string nonce = inp->get_raw(8);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | |
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | inp->get_raw(pdu_size - 32);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | TDS_WERROR("Got nonce: %O\n", nonce);
send_auth(nonce);
}
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | static void process_msg(InPacket inp, int token_type)
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | {
TDS_WERROR("TDS_ERROR_TOKEN | TDS_INFO_TOKEN | TDS_EED_TOKEN\n");
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | int len = inp->get_smallint();
int no = inp->get_int();
int state = inp->get_byte();
int level = inp->get_byte();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | int is_error = 0;
int has_eed = 0;
switch(token_type) {
case TDS_EED_TOKEN:
TDS_WERROR("TDS_EED_TOKEN\n");
if (level > 10) is_error = 1;
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | int state_len = inp->get_byte();
string state = inp->get_raw(state_len);
has_eed = inp->get_byte();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | |
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | inp->get_smallint();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | break;
case TDS_INFO_TOKEN:
TDS_WERROR("TDS_INFO_TOKEN\n");
break;
case TDS_ERROR_TOKEN:
TDS_WERROR("TDS_ERROR_TOKEN\n");
is_error = 1;
break;
}
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | string message = inp->get_string(inp->get_smallint());
string server = inp->get_string(inp->get_byte());
string proc_name = inp->get_string(inp->get_byte());
int line = inp->get_smallint();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | if (has_eed) {
while (1) {
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | switch(inp->peek_byte()) {
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | case TDS5_PARAMFMT_TOKEN:
case TDS5_PARAMFMT2_TOKEN:
case TDS5_PARAMS_TOKEN:
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | process_default_tokens(inp, inp->get_byte());
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | continue;
}
break;
}
}
if (is_error) {
tds_error("%d: %s:%s:%d %s\n",
level, proc_name, server, line, message);
} else {
|
c5c154 | 2006-02-14 | Henrik Grubbström (Grubba) | | last_error = sprintf("%d: %s:%s:%d %s\n",
level, proc_name, server, line, message);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | TDS_WERROR("%d: %s:%s:%d %s\n",
level, proc_name, server, line, message);
}
}
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | static void process_env_chg(InPacket inp)
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | {
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | int size = inp->get_smallint();
int env_type = inp->get_byte();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | if (env_type == TDS_ENV_SQLCOLLATION) {
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | size = inp->get_byte();
string block = inp->get_raw(size);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | if (size >= 5) {
string collation = block[..4];
int lcid;
sscanf(collation, "%-3c", lcid);
}
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | inp->get_raw(inp->get_byte());
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | return;
}
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | string new_val = inp->get_string(inp->get_byte());
string old_val = inp->get_string(inp->get_byte());
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | switch(env_type) {
case TDS_ENV_PACKSIZE:
int new_block_size = (int)new_val;
TDS_WERROR("Change block size from %O to %O\n", old_val, new_val);
break;
case TDS_ENV_DATABASE:
TDS_WERROR("Database changed to %O\n", new_val);
break;
case TDS_ENV_LANG:
TDS_WERROR("Language changed to %O from %O\n", new_val, old_val);
break;
case TDS_ENV_CHARSET:
TDS_WERROR("Charset changed from %O to %O\n", new_val, old_val);
break;
}
}
int get_size_by_type(int col_type)
{
switch (col_type) {
case SYBINT1:
case SYBBIT:
case SYBBITN:
return 1;
case SYBINT2:
return 2;
case SYBINT4:
case SYBREAL:
case SYBDATETIME4:
case SYBMONEY4:
return 4;
case SYBINT8:
case SYBFLT8:
case SYBDATETIME:
case SYBMONEY:
return 8;
case SYBUNIQUE:
return 16;
default:
return -1;
}
}
int get_cardinal_type(int col_type)
{
|
c5c154 | 2006-02-14 | Henrik Grubbström (Grubba) | |
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | switch (col_type) {
case XSYBVARBINARY:
return SYBVARBINARY;
case XSYBBINARY:
return SYBBINARY;
case SYBNTEXT:
return SYBTEXT;
case XSYBNVARCHAR:
case XSYBVARCHAR:
return SYBVARCHAR;
case XSYBNCHAR:
case XSYBCHAR:
return SYBCHAR;
}
return col_type;
}
int get_varint_size(int col_type)
{
switch (col_type) {
case SYBLONGBINARY:
case SYBTEXT:
case SYBNTEXT:
case SYBIMAGE:
case SYBVARIANT:
return 4;
case SYBVOID:
case SYBINT1:
case SYBBIT:
case SYBINT2:
case SYBINT4:
case SYBINT8:
case SYBDATETIME4:
case SYBREAL:
case SYBMONEY:
case SYBDATETIME:
case SYBFLT8:
case SYBMONEY4:
case SYBSINT1:
case SYBUINT2:
case SYBUINT4:
case SYBUINT8:
return 0;
case XSYBNCHAR:
case XSYBNVARCHAR:
case XSYBCHAR:
case XSYBVARCHAR:
case XSYBBINARY:
case XSYBVARBINARY:
return 2;
default:
return 1;
}
}
int is_unicode_type(int col_type)
{
return (col_type == XSYBNVARCHAR) ||
(col_type == XSYBNCHAR) ||
(col_type == SYBNTEXT);
}
int is_ascii_type(int col_type)
{
return (<XSYBCHAR,XSYBVARCHAR,SYBTEXT,SYBCHAR,SYBVARCHAR>)[col_type];
}
int is_char_type(int col_type)
{
return is_unicode_type(col_type) || is_ascii_type(col_type);
}
int is_blob_type(int col_type)
{
return (col_type == SYBTEXT) ||
(col_type == SYBIMAGE) ||
(col_type == SYBNTEXT);
}
int is_collate_type(int col_type)
{
return (col_type==XSYBVARCHAR) ||
(col_type==XSYBCHAR) ||
(col_type==SYBTEXT) ||
(col_type==XSYBNVARCHAR) ||
(col_type==XSYBNCHAR) ||
(col_type==SYBNTEXT);
}
int is_numeric_type(int col_type)
{
return (col_type == SYBNUMERIC) || (col_type == SYBDECIMAL);
}
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | mapping(string:mixed) tds7_get_data_info(InPacket inp)
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | {
mapping(string:mixed) res = ([
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | "usertype":inp->get_smallint(),
"flags":inp->get_smallint(),
"column_type":inp->get_byte(),
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | ]);
res->nullable == res->flags & 0x01;
res->writeable == !!(res->flags & 0x08);
res->identity == !!(res->flags & 0x10);
res->cardinal_type = get_cardinal_type(res->column_type);
res->varint_size = get_varint_size(res->column_type);
switch(res->varint_size) {
case 0:
res->column_size = get_size_by_type(res->column_type);
break;
case 4:
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | res->column_size = inp->get_int();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | break;
case 2:
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | res->column_size = inp->get_smallint();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | break;
case 1:
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | res->column_size = inp->get_byte();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | break;
}
res->timestamp = (res->cardinal_type == SYBBINARY) ||
(res->cardinal_type == TDS_UT_TIMESTAMP);
if (is_numeric_type(res->cardinal_type)) {
TDS_WERROR("is_numeric\n");
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | res->column_prec = inp->get_byte();
res->column_scale = inp->get_byte();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
if (is_collate_type(res->column_type)) {
TDS_WERROR("is_collate\n");
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | inp->get_raw(4);
inp->get_byte();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
if (is_blob_type(res->cardinal_type)) {
TDS_WERROR("is_blob\n");
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | res->table = inp->get_string(inp->get_smallint());
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | res->name = inp->get_string(inp->get_byte());
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | TDS_WERROR("Column info: %O\n", res);
return res;
}
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | static array(mapping(string:mixed)) tds7_process_result(InPacket inp)
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | {
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | int num_cols = inp->get_smallint();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | if (num_cols == 0xffff) {
TDS_WERROR("No meta data.\n");
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | return 0;
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
TDS_WERROR("%d columns in result.\n", num_cols);
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | array(mapping(string:mixed)) column_info = allocate(num_cols);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | foreach(column_info; int col; ) {
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | column_info[col] = tds7_get_data_info(inp);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | return column_info;
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | static void process_default_tokens(InPacket inp, int token_type)
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | {
if (token_type == TDS_DONE_TOKEN) return;
switch(token_type) {
case TDS_DONE_TOKEN:
return;
case TDS_ERROR_TOKEN:
case TDS_INFO_TOKEN:
case TDS_EED_TOKEN:
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | process_msg(inp, token_type);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | return;
case TDS_ENVCHANGE_TOKEN:
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | process_env_chg(inp);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | return;
case TDS7_RESULT_TOKEN:
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | tds_error("TDS7_RESULT_TOKEN in default handler!\n");
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | break;
|
faa3c7 | 2006-02-10 | Henrik Grubbström (Grubba) | | case TDS5_DYNAMIC_TOKEN:
case TDS_LOGINACK_TOKEN:
case TDS_ORDERBY_TOKEN:
case TDS_CONTROL_TOKEN:
case TDS_TABNAME_TOKEN:
TDS_WERROR("Skipping token: %d\n", token_type);
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | inp->get_raw(inp->get_smallint());
|
faa3c7 | 2006-02-10 | Henrik Grubbström (Grubba) | | break;
default:
|
c5c154 | 2006-02-14 | Henrik Grubbström (Grubba) | | werror("TDS: WARNING: Got unknown token in process_default_tokens: %d\n",
token_type);
|
faa3c7 | 2006-02-10 | Henrik Grubbström (Grubba) | | break;
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
}
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | array(mapping(string:mixed)) process_result_tokens(InPacket inp)
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | {
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | array(mapping(string:mixed)) column_info;
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | while (1) {
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | int token_type = inp->peek_byte();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | TDS_WERROR("Got result token %d\n", token_type);
switch(token_type) {
case TDS7_RESULT_TOKEN:
TDS_WERROR("TDS7_RESULT_TOKEN\n");
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | inp->get_byte();
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | column_info = tds7_process_result(inp);
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | if (inp->peek_byte() == TDS_TABNAME_TOKEN) {
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | TDS_WERROR("TDS_TABNAME_TOKEN\n");
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | process_default_tokens(inp, inp->get_byte());
if (inp->peek_byte() == TDS_COLINFO_TOKEN) {
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | TDS_WERROR("TDS_COLINFO_TOKEN\n");
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | inp->get_byte();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | |
}
}
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | break;
|
9e76f0 | 2006-02-10 | Henrik Grubbström (Grubba) | | case TDS_DONE_TOKEN:
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | TDS_WERROR(" TDS_DONE_TOKEN pending\n");
return column_info;
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | case TDS_ROW_TOKEN:
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | TDS_WERROR(" TDS_ROW_TOKEN pending\n");
return column_info;
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | default:
|
c5c154 | 2006-02-14 | Henrik Grubbström (Grubba) | | werror("TDS: WARNING: Unhandled token in process_result_tokens: %d\n",
token_type);
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | |
case TDS_ORDERBY_TOKEN:
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | |
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | inp->get_byte();
process_default_tokens(inp, token_type);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | break;
}
}
}
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | static string|int get_data(InPacket inp,
mapping(string:mixed) info, int col)
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | {
TDS_WERROR("get_data for column %d info:%O\n", col, info);
mapping blobinfo;
int colsize = 0;
outer:
switch(info->varint_size) {
case 4:
switch(info->cardinal_type) {
case SYBVARIANT:
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | int sz = inp->get_int();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | if (!sz) return 0;
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | return inp->get_raw(sz);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | case SYBLONGBINARY:
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | colsize = inp->get_int();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | break outer;
}
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | int len = inp->get_byte();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | if (len == 16) {
blobinfo = ([
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | "textptr":inp->get_raw(16),
"timestamp":inp->get_raw(8),
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | ]);
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | colsize = inp->get_int();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | TDS_WERROR("BLOB: size:%d info:%O\n", colsize, blobinfo);
}
break;
case 2:
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | colsize = inp->get_smallint();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | if (!colsize) {
return "";
}
if (colsize == 0xffff) colsize = 0;
break;
|
faa3c7 | 2006-02-10 | Henrik Grubbström (Grubba) | | case 1:
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | colsize = inp->get_byte();
|
faa3c7 | 2006-02-10 | Henrik Grubbström (Grubba) | | break;
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | case 0:
colsize = get_size_by_type(info->cardinal_type);
break;
}
TDS_WERROR("Column size is %d\n", colsize);
if (!colsize) return 0;
if (is_numeric_type(info->cardinal_type)) {
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | string arr = inp->get_raw(colsize);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | TDS_WERROR("NUMERIC: %O\n", arr);
return arr;
} else if (is_blob_type(info->cardinal_type)) {
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | string raw = inp->get_raw(colsize);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | TDS_WERROR("BLOB. colsize:%d, raw: %O\n", colsize, raw);
if (is_char_type(info->cardinal_type)) {
|
c5c154 | 2006-02-14 | Henrik Grubbström (Grubba) | |
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | return utf16_to_string(raw);
}
return raw;
} else {
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | string raw = inp->get_raw(colsize);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | TDS_WERROR("Got raw data: %O\ncolumn_size:%d colsize:%d\n%s\n",
raw, info->column_size, colsize, hex_dump(raw));
|
9e76f0 | 2006-02-10 | Henrik Grubbström (Grubba) | | if (is_unicode_type(info->column_type)) {
|
c5c154 | 2006-02-14 | Henrik Grubbström (Grubba) | |
|
9e76f0 | 2006-02-10 | Henrik Grubbström (Grubba) | | raw = utf16_to_string(raw);
}
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | if (colsize < info->column_size) {
switch(info->cardinal_type) {
case SYBLONGBINARY:
break;
case SYBCHAR:
case XSYBCHAR:
raw += " "*(info->column_size - colsize);
break;
case SYBBINARY:
case XSYBBINARY:
raw += "\0"*(info->column_size - colsize);
break;
}
}
if (info->cardinal_type == SYBDATETIME4) {
TDS_WERROR("Datetime4:%{ %d}\n", (array)raw);
}
TDS_WERROR("ROW: %O\n", raw);
return raw;
}
}
static string|int convert(string|int raw, mapping(string:mixed) info)
{
|
5495b4 | 2006-02-13 | Henrik Grubbström (Grubba) | | if (!raw) {
TDS_CONV_WERROR("%O ==> NULL\n", raw);
return raw;
}
|
636372 | 2006-02-10 | Henrik Grubbström (Grubba) | | int cardinal_type;
switch(cardinal_type = info->cardinal_type) {
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | case SYBCHAR:
case SYBVARCHAR:
case SYBTEXT:
case XSYBCHAR:
case XSYBVARCHAR:
case SYBNVARCHAR:
case SYBNTEXT:
case SYBLONGBINARY:
case SYBBINARY:
case SYBVARBINARY:
case SYBIMAGE:
case XSYBBINARY:
case XSYBVARBINARY:
|
c5c154 | 2006-02-14 | Henrik Grubbström (Grubba) | |
|
5495b4 | 2006-02-13 | Henrik Grubbström (Grubba) | | TDS_CONV_WERROR("%O ==> %O\n", raw, raw);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | return raw;
|
5495b4 | 2006-02-13 | Henrik Grubbström (Grubba) | | case SYBMONEYN:
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | case SYBMONEY4:
case SYBMONEY:
{
int val;
string sgn = "";
|
5495b4 | 2006-02-13 | Henrik Grubbström (Grubba) | | if (sizeof(raw) == 8) {
sscanf(raw, "%-8c", val);
} else {
sscanf(raw, "%-4c", val);
}
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | if (val < 0) {
sgn = "-";
val = -val;
}
int cents = (val + 50)/100;
|
5495b4 | 2006-02-13 | Henrik Grubbström (Grubba) | | string res = sprintf("%s%d.%02d", sgn, cents/100, cents%100);
TDS_CONV_WERROR("%O ==> %O\n", raw, res);
return res;
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
case SYBNUMERIC:
|
5495b4 | 2006-02-13 | Henrik Grubbström (Grubba) | | {
string res =
sprintf("%d", array_sscanf(raw[1..],
"%-" + (sizeof(raw)-1) + "c")[0]);
int scale = info->column_scale;
if (sizeof(res) < scale) {
res = "0." + ("0" * (scale - sizeof(res))) + res;
} else if (sizeof(res) == scale) {
res = "0." + res;
} else if (scale) {
res = res[..sizeof(res)-(scale+1)] + "." +
res[sizeof(res)-scale..];
}
if (!res[0]) {
res = "-" + res;
}
TDS_CONV_WERROR("%O (scale: %d) ==> %O\n",
raw, scale, res);
return res;
}
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | case SYBDECIMAL:
case SYBREAL:
case SYBFLT8:
case SYBUNIQUE:
default:
|
5495b4 | 2006-02-13 | Henrik Grubbström (Grubba) | | TDS_CONV_WERROR("Not yet supported: %d (%O)\n",
info->cardinal_type, raw);
|
c5c154 | 2006-02-14 | Henrik Grubbström (Grubba) | | werror("TDS: WARNING: Datatype %d not yet supported. raw: %O\n",
info->cardinal_type, raw);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | return raw;
case SYBBIT:
case SYBBITN:
|
5495b4 | 2006-02-13 | Henrik Grubbström (Grubba) | | TDS_CONV_WERROR("%O ==> \"%d\"", raw, !!raw[0]);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | return raw[0]?"1":"0";
case SYBINT1:
case SYBINT2:
case SYBINT4:
case SYBINT8:
|
9e76f0 | 2006-02-10 | Henrik Grubbström (Grubba) | | case SYBINTN:
{
int val;
if (raw[-1]& 0x80) {
val = ~array_sscanf((~raw) + ("\x00"*8), "%-8c")[0];
} else {
val = array_sscanf(raw + ("\x00"*8), "%-8c")[0];
}
|
c5c154 | 2006-02-14 | Henrik Grubbström (Grubba) | | TDS_CONV_WERROR("%O ==> \"%d\"\n", raw, val);
|
9e76f0 | 2006-02-10 | Henrik Grubbström (Grubba) | | return sprintf("%d", val);
}
|
636372 | 2006-02-10 | Henrik Grubbström (Grubba) | | case SYBDATETIMN:
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | case SYBDATETIME:
case SYBDATETIME4:
{
int day, min, sec, sec_300;
|
5495b4 | 2006-02-13 | Henrik Grubbström (Grubba) | | if (sizeof(raw) == 8) {
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | sscanf(raw, "%-4c%-4c", day, sec_300);
sec = sec_300/300;
sec_300 %= 300;
min = sec/60;
sec %= 60;
} else {
sscanf(raw, "%-2c%-2c", day, min);
}
int hour = min/60;
min %= 60;
int l = day + 146038;
int century = (l * 4)/146097;
l -= (century*146097 + 3)/4;
int year = ((l + 1)*4000)/1461001;
l -= (year * 1461)/4;
int yday = (l > 306)?(l - 305):(l + 60);
l += 31;
int j = (l * 80)/2447;
int mday = l - (j * 2447)/80;
l = j/11;
int mon = j + 1 - l*12;
year += (century + 15)*100 + l;
if (!l && !(year & 3) && ((year % 100) || !(year % 400)))
yday++;
|
5495b4 | 2006-02-13 | Henrik Grubbström (Grubba) | | string res = sprintf("%04d-%02d-%02dT%02d:%02d:%02d",
year, mon, mday, hour, min, sec);
TDS_CONV_WERROR("%O ==> %O\n", raw, res);
return res;
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
}
}
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | static array(string|int) process_row(InPacket inp,
array(mapping(string:mixed)) col_info)
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | {
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | if (!col_info) return 0;
array(string|int) res = allocate(sizeof(col_info));
foreach(col_info; int i; mapping(string:mixed) info) {
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | res[i] = convert(get_data(inp, info, i), info);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
return res;
}
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | array(string|int) process_row_tokens(InPacket inp,
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | array(mapping(string:mixed)) col_info,
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | int|void leave_end_token)
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | {
|
9e76f0 | 2006-02-10 | Henrik Grubbström (Grubba) | |
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | while (1) {
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | int token_type = inp->peek_byte();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | TDS_WERROR("Process row tokens: Token type: %d\n", token_type);
switch(token_type) {
case TDS_RESULT_TOKEN:
case TDS_ROWFMT2_TOKEN:
case TDS7_RESULT_TOKEN:
return 0;
case TDS_ROW_TOKEN:
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | inp->get_byte();
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | return process_row(inp, col_info);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | break;
case TDS_DONE_TOKEN:
case TDS_DONEPROC_TOKEN:
case TDS_DONEINPROC_TOKEN:
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | if (!leave_end_token) inp->get_byte();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | return 0;
default:
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | inp->get_byte();
process_default_tokens(inp, token_type);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | break;
}
}
}
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | static void process_login_tokens(InPacket inp)
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | {
int ok = 0;
int token_type;
do {
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | token_type = inp->get_byte();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | TDS_WERROR("Got token: %d\n", token_type);
switch(token_type) {
case TDS_DONE_TOKEN:
TDS_WERROR("TDS_DONE_TOKEN\n");
break;
case TDS_AUTH_TOKEN:
TDS_WERROR("TDS_AUTH_TOKEN\n");
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | process_auth(inp);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | break;
case TDS_LOGINACK_TOKEN:
TDS_WERROR("TDS_LOGINACK_TOKEN\n");
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | int len = inp->get_smallint();
int ack = inp->get_byte();
int major = inp->get_byte();
int minor = inp->get_byte();
inp->get_smallint();
inp->get_byte();
server_product_name = inp->get_string((len-10)/2);
int product_version = inp->get_int_be();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | if ((major == 4) && (minor == 2) &&
((product_version & 0xff0000ff) == 0x5f0000ff)) {
product_version = (product_version & 0xffff00) | 0x800000000;
}
if ((ack == 5) || (ack == 1)) ok = 1;
TDS_WERROR(" ok:%d ack:%d %s major:%d minor:%d version:%08x\n",
ok, ack,
server_product_name, major, minor, product_version);
server_product_name = (server_product_name/"\0")[0];
server_data = sprintf("%s %d.%d.%d.%d",
server_product_name,
product_version>>24,
product_version & 0xffffff,
major, minor);
break;
default:
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | process_default_tokens(inp, token_type);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | break;
}
} while (token_type != TDS_DONE_TOKEN);
if (!ok) tds_error("Login failed.\n");
TDS_WERROR("Login ok!\n");
}
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | InPacket submit_query(compile_query query, void|array(mixed) params)
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | {
Packet p = Packet();
if (!query->n_param || !params || !sizeof(params)) {
string raw = query->splitted_query*"?";
p->put_raw(raw, sizeof(raw));
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | return send_packet(p, 0x01, 1);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | } else {
tds_error("parametrized queries not supported yet.\n");
}
}
static void disconnect()
{
socket->close();
destruct();
}
static void create(string server, int port, string database,
string username, string auth)
{
string domain;
array(string) tmp = username/"\\";
if (sizeof(tmp) > 1) {
domain = tmp[0];
username = tmp[1..]*"\\";
}
this_program::server = server;
this_program::port = port;
this_program::database = database;
this_program::username = username;
this_program::password = auth;
this_program::domain = domain;
|
5495b4 | 2006-02-13 | Henrik Grubbström (Grubba) | | TDS_WERROR("Connecting to %s:%d with TDS version %d.%d\n",
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | server, port, major_version, minor_version);
socket = Stdio.File();
if (!socket->connect(server, port)) {
socket = 0;
tds_error("Failed to connect to %s:%d\n", server, port);
}
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | process_login_tokens(send_login());
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
}
object(Connection) con;
int affected_rows;
string server_product_name = "";
int busy;
void Disconnect()
{
con->disconnect();
con = 0;
}
void Connect(string server, int port, string database,
string uid, string password)
{
con = Connection(server, port, database, uid, password);
}
|
26d74c | 2006-02-10 | Henrik Grubbström (Grubba) | | #if (__REAL_MAJOR__ > 7) || ((__REAL_MAJOR__ == 7) && (__REAL_MINOR__ >= 6))
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | };
|
26d74c | 2006-02-10 | Henrik Grubbström (Grubba) | | #endif /* Pike 7.6 or later */
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | |
class compile_query
{
int n_param;
array(string) splitted_query;
array(mixed) params;
void parse_prepared_query()
{
}
static array(string) split_query_on_placeholders(string query)
{
array(string) res = ({});
int i;
int j = 0;
for (i = 0; i < sizeof(query); i++) {
switch(query[i]) {
case '\'':
i = search(query, "\'", i+1);
if (i == -1) {
TDS_WERROR("Bad quoting!\n");
i = sizeof(query);
}
break;
case '\"':
i = search(query, "\"", i+1);
if (i == -1) {
TDS_WERROR("Bad quoting!\n");
i = sizeof(query);
}
break;
case '[':
i = search(query, "]", i+1);
if (i == -1) {
TDS_WERROR("Bad quoting!\n");
i = sizeof(query);
}
break;
case '-':
if (query[i..i+1] == "--") {
i = search(query, "\n", i+1);
if (i == -1) {
TDS_WERROR("Unterminated comment.\n");
i = sizeof(query);
}
}
break;
case '/':
if (query[i..i+1] == "/*") {
i = search(query, "*/", i+2);
if (i == -1) {
TDS_WERROR("Unterminated comment.\n");
i = sizeof(query);
}
}
break;
case '?':
res += ({ query[j..i-1] });
j = i+1;
break;
}
}
res += ({ query[j..] });
return map(res, string_to_utf16);
}
static void create(string query)
{
|
9e76f0 | 2006-02-10 | Henrik Grubbström (Grubba) | | TDS_WERROR("Compiling query: %O\n", query);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | splitted_query = split_query_on_placeholders(query);
n_param = sizeof(splitted_query)-1;
}
}
class big_query
{
static int row_no;
static int eot;
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | | static Connection.InPacket result_packet;
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | static array(mapping(string:mixed)) column_info;
|
ce7127 | 2006-02-10 | Henrik Grubbström (Grubba) | |
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | int|array(string|int) fetch_row()
{
if (eot) return 0;
TDS_WERROR("fetch_row()::::::::::::::::::::::::::::::::::::::::::\n");
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | int|array(string|int) res = con->process_row_tokens(result_packet,
column_info);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | eot = !res;
row_no++;
return res;
}
array(mapping(string:mixed)) fetch_fields()
{
TDS_WERROR("fetch_fields()::::::::::::::::::::::::::::::::::::::::::\n");
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | | return copy_value(column_info);
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
static void create(string|compile_query query)
{
if (stringp(query)) {
query = compile_query(query);
}
|
db22f4 | 2006-02-10 | Henrik Grubbström (Grubba) | |
query->parse_prepared_query();
if (busy) {
tds_error("Connection not idle.\n");
}
if (!query->params) {
result_packet = con->submit_query(query);
} else {
result_packet = con->submit_execdirect(query, query->params);
}
column_info = con->process_result_tokens(result_packet);
if (!column_info) destruct();
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | }
}
|
5495b4 | 2006-02-13 | Henrik Grubbström (Grubba) | | static compile_query compiled_insert_id =
compile_query("SELECT @@identity AS insert_id");
int insert_id()
{
object res = big_query(compiled_insert_id);
array(mapping(string:mixed)) field_info =
res->fetch_fields();
if (!field_info) return 0;
array(string|int) row = res->fetch_row();
if (!row) return 0;
foreach(field_info->name; int i; string name) {
if (name == "insert_id") return (int)row[i];
}
return 0;
}
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | string server_info()
{
return server_data;
}
|
9e76f0 | 2006-02-10 | Henrik Grubbström (Grubba) | | string error()
{
return last_error;
}
|
a451ba | 2006-02-09 | Henrik Grubbström (Grubba) | | static void create(string|void server, string|void database,
string|void user, string|void pwd)
{
if (con) {
Disconnect();
}
int port = DEF_PORT;
if (server) {
array(string) tmp = server/":";
if (sizeof(tmp) > 1) {
port = (int)tmp[-1];
server = tmp[..sizeof(tmp)-2]*":";
}
} else {
server = "127.0.0.1";
}
Connect(server, port, database || "default",
user || "", pwd || "");
|
26d74c | 2006-02-10 | Henrik Grubbström (Grubba) | | }
|