pike.git / lib / modules / Sql.pmod / tds.pike

version» Context lines:

pike.git/lib/modules/Sql.pmod/tds.pike:1:   /* -  * $Id: tds.pike,v 1.23 2007/04/13 11:48:17 grubba Exp $ +  * $Id: tds.pike,v 1.24 2008/06/28 16:36:59 nilsson Exp $    *    * A Pike implementation of the TDS protocol.    *    * Henrik Grubbström 2006-02-08.    */      #pike __REAL_VERSION__      /* #define TDS_DEBUG */   /* #define TDS_CONVERT_DEBUG */
pike.git/lib/modules/Sql.pmod/tds.pike:26:   //! The TDS SQL-protocol.   //!   //! This protocol is used by Sybase and Microsoft's SQL-servers.   //!   //! @example   //! @tt{Sql.Sql con = Sql.Sql("tds://user:pass@@host/database");@}   //!   //! @seealso   //! @[Sql.Sql()]    - static int filter_noprint(int char) + protected int filter_noprint(int char)   {    return ((char == 32) || ((char != 0x7f) && (char & 0x60)))?char:'.';   }    - static string hex_dump(string data) { + protected 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 * "";   }      #if (__REAL_MAJOR__ > 7) || ((__REAL_MAJOR__ == 7) && (__REAL_MINOR__ >= 6))   // Static blocks affect nested classes in Pike 7.4.   // We don't want that... - static { + protected {   #endif /* Pike 7.6 or later */    constant DEF_MAJOR = 8;    constant DEF_MINOR = 0;    constant DEF_PORT = 1433;    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";   
pike.git/lib/modules/Sql.pmod/tds.pike:179:    string last_error;       //! Format and report an error.    void tds_error(string msg, mixed ... args)    {    if (sizeof(args)) msg = sprintf(msg, @args);    TDS_WERROR("ERROR: %s", msg);    predef::error(last_error = msg);    }    -  static object utf16enc = Locale.Charset.encoder("UTF16LE"); -  static string string_to_utf16(string s) +  protected object utf16enc = Locale.Charset.encoder("UTF16LE"); +  protected 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) +  protected object utf16dec = Locale.Charset.decoder("UTF16LE"); +  protected string utf16_to_string(string s)    {    return utf16dec->feed(s)->drain();    }       //! A connection to a TDS server.    class Connection {    int major_version = DEF_MAJOR;    int minor_version = DEF_MINOR;    int port = DEF_PORT;    int block_size = 4096;
pike.git/lib/modules/Sql.pmod/tds.pike:221:   #define FMT_INT "%-4c"   #define FMT_INT8 "%-4c"       //! An incoming packet from the TDS server.    class InPacket    {    int inpos = 0;    string inbuf = "";    int done;    -  static void fill_buf() +  protected void fill_buf()    {    if (done) {    TDS_WERROR("Filling buffer on finished packet!\n"    "%s\n", hex_dump(inbuf));    tds_error("Filling buffer on finished packet!\n");    }       string header = socket->read(8);    if (!header || sizeof(header) < 8) {    busy = !(done = 1);
pike.git/lib/modules/Sql.pmod/tds.pike:258:    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;    }    -  static void destroy() +  protected void destroy()    {    // Return the connection to the idle state.    while (!done) {    inbuf = "";    inpos = 0;    fill_buf();    }    }       string get_raw(int bytes)
pike.git/lib/modules/Sql.pmod/tds.pike:328:       void expect(string s)    {    string r = get_raw(sizeof(s));    if (r != s) {    tds_error("Expectation failed: Got %O, expected %O\n",    r, s);    }    }    -  static void create() +  protected void create()    {    if (busy) {    tds_error("Creating InPacket on busy connection!\n");    }    busy = 1;    }    }       //static InPacket login_answer;       //! An outgoing packet to the TDS server.    class Packet    {    array(string|int) segments = ({});    array(string) strings = ({});    int flags;    -  static void create(int|void flags) +  protected void create(int|void flags)    {    this_program::flags = flags;    }       void put_int8(int i)    {    segments += ({ sprintf("%-8c", i) });    }    void put_int(int i)    {
pike.git/lib/modules/Sql.pmod/tds.pike:483:    Disconnect();    predef::error("Failed to send packet.\n"    "raw: %O\n", raw);    }    }    //Stdio.write_file("packet.bin", raw);    if (last) return InPacket();    return 0;    }    -  static string crypt_pass(string password) +  protected 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;    });    }    -  static InPacket send_login() +  protected InPacket send_login()    {    password = password[..127];       Packet p = Packet(1);       p->put_raw(TDS8VERSION, 4); // TDS version    p->put_int(0); // block size    p->put_raw(CLIENTVERSION, 4); // client version    p->put_int(getpid()); // pid    p->put_raw(CONNECTIONID, 4); // connection identifier
pike.git/lib/modules/Sql.pmod/tds.pike:587:    Crypto.md4 md4 = Crypto.md4();   #else    predef::error("MD4 hashes not supported in this Pike.\n");    mixed md4;   #endif   #endif    md4->update(nt_passwd);    return encrypt_answer(md4->digest() + "\0"*16, nonce);    }    -  static void send_auth(string nonce) +  protected void send_auth(string nonce)    {    int out_flag = 0x11;    Packet p = Packet();    p->put_raw("NTLMSSP\0", 8);    p->put_int(3); /* sequence 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(""); /* Unknown */    p->put_int(0x8201); /* flags */       TDS_WERROR("Sending auth packet.\n");    send_packet(p, 0x11);    }    -  static void process_auth(InPacket inp) +  protected void process_auth(InPacket inp)    {    int pdu_size = inp->get_smallint();    if (pdu_size < 32) tds_error("Bad pdu size: %d\n", pdu_size);    inp->expect("NTLMSSP\0");    inp->get_int(); /* sequence -> 2 */    inp->get_int(); /* domain len * 2 */    inp->get_int(); /* domain offset */    inp->get_int(); /* flags */    string nonce = inp->get_raw(8);    /* Discard context, target and data info */    inp->get_raw(pdu_size - 32);    TDS_WERROR("Got nonce: %O\n", nonce);    send_auth(nonce);    }    -  static void process_msg(InPacket inp, int token_type) +  protected void process_msg(InPacket inp, int token_type)    {    TDS_WERROR("TDS_ERROR_TOKEN | TDS_INFO_TOKEN | TDS_EED_TOKEN\n");    int len = inp->get_smallint();    int no = inp->get_int();    int state = inp->get_byte();    int level = inp->get_byte();    int is_error = 0;    int has_eed = 0;    switch(token_type) {    case TDS_EED_TOKEN:
pike.git/lib/modules/Sql.pmod/tds.pike:678: Inside #if 0
   } else {   #if 0    last_error = sprintf("%d: %s:%s:%d %s\n",    level, proc_name, server, line, message);   #endif    TDS_WERROR("%d: %s:%s:%d %s\n",    level, proc_name, server, line, message);    }    }    -  static void process_env_chg(InPacket inp) +  protected void process_env_chg(InPacket inp)    {    int size = inp->get_smallint();    int env_type = inp->get_byte();    if (env_type == TDS_ENV_SQLCOLLATION) {    size = inp->get_byte();    string block = inp->get_raw(size);    if (size >= 5) {    string collation = block[..4];    int lcid;    sscanf(collation, "%-3c", lcid);
pike.git/lib/modules/Sql.pmod/tds.pike:887:    }    if (is_blob_type(res->cardinal_type)) {    TDS_WERROR("is_blob\n");    res->table = inp->get_string(inp->get_smallint());    }    res->name = inp->get_string(inp->get_byte());    TDS_WERROR("Column info: %O\n", res);    return res;    }    -  static array(mapping(string:mixed)) tds7_process_result(InPacket inp) +  protected array(mapping(string:mixed)) tds7_process_result(InPacket inp)    {    int num_cols = inp->get_smallint();    if (num_cols == 0xffff) {    TDS_WERROR("No meta data.\n");    return 0;    }    TDS_WERROR("%d columns in result.\n", num_cols);    array(mapping(string:mixed)) column_info = allocate(num_cols);    foreach(column_info; int col; ) {    column_info[col] = tds7_get_data_info(inp);    }    return column_info;    }    -  static void process_default_tokens(InPacket inp, int token_type) +  protected void process_default_tokens(InPacket inp, int token_type)    {    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:    process_msg(inp, token_type);    return;
pike.git/lib/modules/Sql.pmod/tds.pike:1039:    case TDS_ERROR_TOKEN:    case TDS_INFO_TOKEN:    case TDS_EED_TOKEN:    inp->get_byte();    process_default_tokens(inp, token_type);    break;    }    }    }    -  static string|int get_data(InPacket inp, +  protected string|int get_data(InPacket inp,    mapping(string:mixed) info, int col)    {    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) {
pike.git/lib/modules/Sql.pmod/tds.pike:1131:    }    }    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) +  protected string|int convert(string|int raw, mapping(string:mixed) info)    {    if (!raw) {    TDS_CONV_WERROR("%O ==> NULL\n", raw);    return raw; /* NULL */    }    int cardinal_type;    switch(cardinal_type = info->cardinal_type) {    case SYBCHAR:    case SYBVARCHAR:    case SYBTEXT:
pike.git/lib/modules/Sql.pmod/tds.pike:1270:    if (!l && !(year & 3) && ((year % 100) || !(year % 400)))    yday++;    string res = sprintf("%04d-%02d-%02dT%02d:%02d:%02d",    year, mon+1, mday, hour, min, sec);    TDS_CONV_WERROR("%O ==> %O\n", raw, res);    return res;    }    }    }    -  static array(string|int) process_row(InPacket inp, +  protected array(string|int) process_row(InPacket inp,    array(mapping(string:mixed)) col_info)    {    if (!col_info) return 0;    array(string|int) res = allocate(sizeof(col_info));    foreach(col_info; int i; mapping(string:mixed) info) {    res[i] = convert(get_data(inp, info, i), info);    }    return res;    }   
pike.git/lib/modules/Sql.pmod/tds.pike:1311:    if (!leave_end_token) inp->get_byte();    return 0;    default:    inp->get_byte();    process_default_tokens(inp, token_type);    break;    }    }    }    -  static void process_login_tokens(InPacket inp) +  protected void process_login_tokens(InPacket inp)    {    int ok = 0;    int token_type;    do {    token_type = inp->get_byte();    TDS_WERROR("Got token: %d\n", token_type);    switch(token_type) {    case TDS_DONE_TOKEN:    TDS_WERROR("TDS_DONE_TOKEN\n");    break;
pike.git/lib/modules/Sql.pmod/tds.pike:1415:       return send_packet(p, 0x03, 1);    }       void disconnect()    {    socket->close();    destruct();    }    -  static void create(string server, int port, string database, +  protected void create(string server, int port, string database,    string username, string auth)    {    string domain;    array(string) tmp = username/"\\";    if (sizeof(tmp) > 1) {    // Domain login.    domain = tmp[0];    username = tmp[1..]*"\\";    }   
pike.git/lib/modules/Sql.pmod/tds.pike:1486:    string query_string;    array(string) splitted_query;       array(mixed) params;       void parse_prepared_query()    {    // FIXME:    }    -  static array(string) split_query_on_placeholders(string query) +  protected 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");
pike.git/lib/modules/Sql.pmod/tds.pike:1546:    }    }    res += ({ query[j..] });    return map(res, string_to_utf16);    }       //! Compile a query.    //!    //! @seealso    //! @[big_query()] -  static void create(string query) +  protected void create(string query)    {    TDS_WERROR("Compiling query: %O\n", query);    splitted_query = split_query_on_placeholders(query);    n_param = sizeof(splitted_query)-1;    if (n_param) {    // Insert placeholders.    int i;    query_string = map((splitted_query/1)*({0}),    lambda(string segment) {    if (segment) return segment;
pike.git/lib/modules/Sql.pmod/tds.pike:1568:    })*"";    } else {    query_string = splitted_query[0];    }    }   }      //! A query result set.   class big_query   { -  static int row_no; -  static int eot; +  protected int row_no; +  protected int eot;    -  static Connection.InPacket result_packet; -  static array(mapping(string:mixed)) column_info; +  protected Connection.InPacket result_packet; +  protected array(mapping(string:mixed)) column_info;       //! Fetch the next row from the result set.    //!    //! @returns    //! Returns @expr{0@} (zero) if all rows have been returned.    //!    //! Otherwise returns an @expr{array(string|int)@} with one    //! entry for each field. If the field is @tt{NULL@} the    //! entry will be @expr{0@} (zero), otherwise the entry    //! will contain a string representing the value.
pike.git/lib/modules/Sql.pmod/tds.pike:1649:    }       //! Execute a query against the database.    //!    //! @param query    //! The query to execute. This can either be a string, or    //! a compiled query.    //!    //! @seealso    //! @[compile_query()] -  static void create(string|compile_query query) +  protected void create(string|compile_query query)    {    if (stringp(query)) {    query = compile_query(query);    }       query->parse_prepared_query();    if (busy) {    tds_error("Connection not idle.\n");    }    if (!query->n_param) {    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();    }   }    - static compile_query compiled_insert_id = + protected compile_query compiled_insert_id =    compile_query("SELECT @@identity AS insert_id");      //! Fetch the identity of the last insert (if available).   //!   //! This performs the query @expr{"SELECT @@@@identity AS insert_id"@}.   //!   //! @returns   //! Returns the identity of the last insert as an integer if available.   //! Otherwise returns @expr{0@} (zero).   int insert_id()
pike.git/lib/modules/Sql.pmod/tds.pike:1727:   //! An explicit domain may be specified by preceeding the user name   //! with the domain name and a @expr{'\\'@}.   //!   //! @param password   //! Password to access with.   //!   //! Usually accessed via @[Sql.Sql()].   //!   //! @seealso   //! @[Sql.Sql()] - static void create(string|void server, string|void database, + protected void create(string|void server, string|void database,    string|void user, string|void password)   {    if (con) {    Disconnect(1);    }    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 || "", password || "");   }