Changeset 81

Show
Ignore:
Timestamp:
01/30/08 10:46:52 (10 months ago)
Author:
aaronc542
Message:

Fixing problems with building MySQL on Windows and Linux with a most unfortunate hack - a imp.d and imp_win.d file which have one difference - extern(Windows) versus extern(C).

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/dbi/DBIException.d

    r76 r81  
    1 /** 
     1/** 
    22 * Authors: The D DBI project 
    33 * Copyright: BSD license 
  • trunk/dbi/Database.d

    r76 r81  
    216216} 
    217217 
     218debug(UnitTest) { 
     219 
    218220unittest { 
    219221    void s1 (char[] s) { 
     
    233235    assert (keywords["host"] == "local"); 
    234236} 
     237} 
  • trunk/dbi/PreparedStatement.d

    r74 r81  
    11module dbi.PreparedStatement; 
    22 
    3 version (Phobos) { 
    4     static assert(false, "Phobos version of prepared statements not implemented yet"); 
    5 } else { 
    6     public import tango.util.time.DateTime; 
    7 
     3public import tango.group.time; 
    84 
    9 enum BindType { Null, Bool, Byte, Short, Int, Long, UByte, UShort, UInt, ULong, Float, Double, String, Binary, Time }; 
     5enum BindType : ubyte { Null, Bool, Byte, Short, Int, Long, UByte, UShort, UInt, ULong, Float, Double, String, Binary, Time, DateTime }; 
    106 
    117interface IPreparedStatementProvider 
    128{ 
    13     IPreparedStatement prepare(string sql); 
     9    IPreparedStatement prepare(char[] sql); 
     10    void beginTransact(); 
     11    void rollback(); 
     12    void commit(); 
    1413} 
    1514 
     
    3433    BindType type; 
    3534} 
     35 
     36BindType getBindType(T)() 
     37{ 
     38    static if(is(T == byte)) 
     39    { 
     40        return BindType.Byte; 
     41    } 
     42    else static if(is(T == ubyte)) 
     43    { 
     44        return BindType.UByte; 
     45    } 
     46    else static if(is(T == short)) 
     47    { 
     48        return BindType.Short; 
     49    } 
     50    else static if(is(T == ushort)) 
     51    { 
     52        return BindType.UShort; 
     53    } 
     54    else static if(is(T == int)) 
     55    { 
     56        return BindType.Int; 
     57    } 
     58    else static if(is(T == uint)) 
     59    { 
     60        return BindType.UInt; 
     61    } 
     62    else static if(is(T == long)) 
     63    { 
     64        return BindType.Long; 
     65    } 
     66    else static if(is(T == ulong)) 
     67    { 
     68        return BindType.ULong; 
     69    } 
     70    else static if (is(T == float)) 
     71    { 
     72        return BindType.Float; 
     73    } 
     74    else static if (is(T == double)) 
     75    { 
     76        return BindType.Double; 
     77    } 
     78    else static if (is(T == char[])) 
     79    { 
     80        return BindType.String; 
     81    } 
     82    else static if (is(T == ubyte[]) || is(T == void[])) 
     83    { 
     84        return BindType.Binary; 
     85    } 
     86    else static if (is(T == Time)) 
     87    { 
     88        return BindType.Time; 
     89    } 
     90    else static if (is(T == DateTime)) 
     91    { 
     92        return BindType.DateTime; 
     93    } 
     94    else return BindType.Null; 
     95} 
  • trunk/dbi/Row.d

    r77 r81  
    55module dbi.Row; 
    66 
    7 private static import tango.io.Stdout; 
    87private import dbi.DBIException; 
    98 
     
    183182} 
    184183 
     184debug(UnitTest) { 
     185static import tango.io.Stdout; 
     186 
    185187unittest { 
    186     version (Phobos) { 
    187         void s1 (char[] s) { 
    188             std.stdio.writefln("%s", s); 
    189         } 
    190  
    191         void s2 (char[] s) { 
    192             std.stdio.writefln("   ...%s", s); 
    193         } 
    194     } else { 
    195         void s1 (char[] s) { 
    196             tango.io.Stdout.Stdout(s).newline(); 
    197         } 
    198  
    199         void s2 (char[] s) { 
    200             tango.io.Stdout.Stdout("   ..." ~ s).newline(); 
    201         } 
     188 
     189    void s1 (char[] s) { 
     190        tango.io.Stdout.Stdout(s).newline(); 
     191    } 
     192 
     193    void s2 (char[] s) { 
     194        tango.io.Stdout.Stdout("   ..." ~ s).newline(); 
    202195    } 
    203196 
     
    228221    assert (r1.getFieldDecl(1) == "integer"); 
    229222} 
     223} 
  • trunk/dbi/Statement.d

    r70 r81  
    232232} 
    233233 
     234debug(UnitTest) { 
    234235unittest { 
    235236    version (Phobos) { 
     
    281282    assert (stmt.getSql() == resultingSql); 
    282283} 
     284} 
  • trunk/dbi/mysql/MysqlDatabase.d

    r79 r81  
    1 /** 
     1/** 
    22 * Authors: The D DBI project 
    33 * Copyright: BSD license 
     
    88 
    99private import tango.stdc.stringz : toDString = fromUtf8z, toCString = toStringz; 
    10 private import tango.io.Console; 
     10    private import tango.io.Console; 
    1111private static import tango.text.Util; 
    1212private static import tango.text.convert.Integer; 
    13 debug (UnitTest) private static import tango.io.Stdout; 
     13debug(UnitTest) import tango.io.Stdout; 
    1414 
    1515private import dbi.Database, dbi.DBIException, dbi.Result, dbi.Row, dbi.Statement, dbi.Registry; 
    16 private import dbi.mysql.imp, dbi.mysql.MysqlError, dbi.mysql.MysqlResult; 
     16version(Windows) { 
     17    private import dbi.mysql.imp_win; 
     18
     19else { 
     20    private import dbi.mysql.imp; 
     21
     22private import dbi.mysql.MysqlError, dbi.mysql.MysqlResult; 
    1723 
    1824static this() { 
     
    251257} 
    252258 
     259debug(UnitTest) { 
    253260unittest { 
    254261 
     
    307314    db.close();+/ 
    308315} 
    309  
    310 
     316
     317 
     318
  • trunk/dbi/mysql/MysqlPreparedStatement.d

    r74 r81  
    33version(dbi_mysql) { 
    44 
    5     version (Phobos) { 
    6         private static import std.conv, std.string; 
    7         private alias std.string.toString toDString; 
    8         private alias std.string.toStringz toCString; 
    9         debug (UnitTest) private static import std.stdio; 
    10     } else { 
    11         private import tango.stdc.string; 
    12         private import tango.stdc.stringz : toDString = fromUtf8z, toCString = toUtf8z; 
    13             private import tango.io.Console; 
    14         private static import tango.text.Util; 
    15         private import Integer = tango.text.convert.Integer; 
    16         debug(UnitTest) { 
    17             import tango.stdc.stringz; 
    18             import tango.io.Stdout; 
    19             import tango.util.log.ConsoleAppender; 
    20         } 
     5    import tango.stdc.string; 
     6    import tango.stdc.stringz : toDString = fromUtf8z, toCString = toStringz; 
     7    static import tango.text.Util; 
     8    import Integer = tango.text.convert.Integer; 
     9    debug(UnitTest) { 
     10        import tango.stdc.stringz; 
     11        import tango.io.Stdout; 
     12        debug = Log; 
    2113    } 
    2214    debug(Log) { 
     15        import tango.util.log.ConsoleAppender; 
    2316        import tango.util.log.Log; 
    2417    } 
    2518     
    2619import dbi.mysql.MysqlDatabase; 
    27 import dbi.mysql.imp; 
    28 import dbi.PreparedStatement; 
     20version(Windows) { 
     21    private import dbi.mysql.imp_win; 
     22
     23else { 
     24    private import dbi.mysql.imp; 
     25
     26public import dbi.PreparedStatement, dbi.Metadata; 
    2927 
    30 class MysqlPreparedStatementProvider : IPreparedStatementProvider 
    31 
    32     debug(Log) 
    33     { 
    34         static Logger log; 
    35         static this() 
    36         { 
    37             log = Log.getLogger("dbi.mysql.MysqlPreparedStatement.MysqlPreparedStatementProvider"); 
    38         } 
    39     } 
    40      
     28class MysqlPreparedStatementProvider : IPreparedStatementProvider, IMetadataProvider 
     29{    
    4130    this(MysqlDatabase db) 
    4231    { 
     
    4736    private MYSQL* mysql; 
    4837     
    49     IPreparedStatement prepare(string sql) 
     38    IPreparedStatement prepare(char[] sql) 
    5039    { 
    5140        MYSQL_STMT* stmt = mysql_stmt_init(mysql); 
     
    6049        return new MysqlPreparedStatement(stmt); 
    6150    } 
     51     
     52    void beginTransact() 
     53    { 
     54        const char[] sql = "START TRANSACTION"; 
     55        mysql_real_query(mysql, sql.ptr, sql.length); 
     56    } 
     57     
     58    void rollback() 
     59    { 
     60        mysql_rollback(mysql); 
     61    } 
     62     
     63    void commit() 
     64    { 
     65        mysql_commit(mysql); 
     66    } 
     67     
     68    bool hasTable(char[] tablename) 
     69    { 
     70        MYSQL_RES* res = mysql_list_tables(mysql, toCString(tablename)); 
     71        if(!res) { 
     72            debug(Log) { 
     73                log.warn("mysql_list_tables returned null in method tableExists()"); 
     74                logError; 
     75            } 
     76            return false; 
     77        } 
     78        bool exists = mysql_fetch_row(res) ? true : false; 
     79        mysql_free_result(res); 
     80        return exists; 
     81    } 
     82     
     83    bool getTableInfo(char[] tablename, inout TableInfo info) 
     84    { 
     85        char[] q = "SHOW COLUMNS FROM `" ~ tablename ~ "`";  
     86        auto ret = mysql_real_query(mysql, q.ptr, q.length); 
     87        if(ret != 0) { 
     88            debug(Log) { 
     89                log.warn("Unable to SHOW COLUMNS for table " ~ tablename); 
     90                logError; 
     91            } 
     92            return false; 
     93        } 
     94        MYSQL_RES* res = mysql_store_result(mysql); 
     95        if(!res) { 
     96            debug(Log) { 
     97                log.warn("Unable to store result for " ~ q); 
     98                logError; 
     99            } 
     100            return false; 
     101        } 
     102        if(mysql_num_fields(res) < 1) { 
     103            debug(Log) 
     104            log.warn("Result stored, but query " ~ q ~ " has no fields"); 
     105            return false; 
     106        } 
     107        info.fieldNames = null; 
     108        MYSQL_ROW row = mysql_fetch_row(res); 
     109        while(row != null) { 
     110            char[] dbCol = toDString(row[0]).dup; 
     111            info.fieldNames ~= dbCol; 
     112            char[] keyCol = toDString(row[3]); 
     113            if(keyCol == "PRI") info.primaryKeyFields ~= dbCol; 
     114            row = mysql_fetch_row(res); 
     115        } 
     116        mysql_free_result(res); 
     117        return true; 
     118    } 
     119     
     120    debug(Log) 
     121    { 
     122        static Logger log; 
     123        static this() 
     124        { 
     125            log = Log.getLogger("dbi.mysql.MysqlPreparedStatement.MysqlPreparedStatementProvider"); 
     126        } 
     127         
     128        private void logError() 
     129        { 
     130            char* err = mysql_error(mysql); 
     131            log.trace(toDString(err)); 
     132        } 
     133    } 
    62134} 
    63135 
     
    83155        for(uint i = 0; i < nFields; i++) 
    84156        { 
    85             metadata[i].name = fields[i].name[0 .. fields[i].name_length]
     157            metadata[i].name = fields[i].name[0 .. fields[i].name_length].dup
    86158            metadata[i].type = fromMysqlType(fields[i].type, fields[i].flags); 
    87159        } 
     
    113185        for(uint i = 0; i < len; ++i) 
    114186        { 
    115             with(enum_field_types) 
    116             { 
    117             switch(paramBind[i].buffer_type) 
    118             { 
    119             case(MYSQL_TYPE_STRING): 
    120             case(MYSQL_TYPE_BLOB): 
     187            switch(paramHelper.types[i]) 
     188            { 
     189            case(BindType.String): 
     190            case(BindType.Binary): 
    121191                ubyte[]* arr = cast(ubyte[]*)(bind[i]); 
    122192                paramBind[i].buffer = (*arr).ptr; 
     
    125195                paramHelper.len[i] = l; 
    126196                break; 
    127         /*  case(BindType.Date): 
    128                 auto date = *cast(Date*)(paramPtr + paramCols[i].offset); 
    129                 paramHelper.time[i].year = date.year; 
    130                 paramHelper.time[i].month = date.month; 
    131                 paramHelper.time[i].day = date.day; 
    132                 paramHelper.time[i].hour = date.hour; 
    133                 paramHelper.time[i].minute = date.min; 
    134                 paramHelper.time[i].second = date.sec; 
    135                 break;*/ 
    136             case(MYSQL_TYPE_DATETIME): 
     197            case(BindType.Time): 
     198                auto time = *cast(Time*)(bind[i]); 
     199                auto dateTime = Clock.toDate(time);  
     200                paramHelper.time[i].year = dateTime.date.year; 
     201                paramHelper.time[i].month = dateTime.date.month; 
     202                paramHelper.time[i].day = dateTime.date.day; 
     203                paramHelper.time[i].hour = dateTime.time.hours; 
     204                paramHelper.time[i].minute = dateTime.time.minutes; 
     205                paramHelper.time[i].second = dateTime.time.seconds; 
     206                break; 
     207            case(BindType.DateTime): 
    137208                auto dateTime = *cast(DateTime*)(bind[i]); 
    138                 paramHelper.time[i].year = dateTime.year; 
    139                 paramHelper.time[i].month = dateTime.month; 
    140                 paramHelper.time[i].day = dateTime.day; 
    141                 paramHelper.time[i].hour = dateTime.hour
    142                 paramHelper.time[i].minute = dateTime.minute
    143                 paramHelper.time[i].second = dateTime.second
     209                paramHelper.time[i].year = dateTime.date.year; 
     210                paramHelper.time[i].month = dateTime.date.month; 
     211                paramHelper.time[i].day = dateTime.date.day; 
     212                paramHelper.time[i].hour = dateTime.time.hours
     213                paramHelper.time[i].minute = dateTime.time.minutes
     214                paramHelper.time[i].second = dateTime.time.seconds
    144215                break; 
    145216            default: 
    146217                paramBind[i].buffer = bind[i]; 
    147218                break; 
    148             } 
    149219            } 
    150220        } 
     
    214284        foreach(i, mysqlTime; resHelper.time) 
    215285        { 
    216             DateTime* dateTime = cast(DateTime*)(bind[i]); 
    217             *dateTime = DateTime(mysqlTime.year, mysqlTime.month, mysqlTime.day); 
    218             (*dateTime).addHours(mysqlTime.hour); 
    219             (*dateTime).addMinutes(mysqlTime.minute); 
    220             (*dateTime).addSeconds(mysqlTime.second); 
    221         } 
    222          
    223         /*  case Type.Date: 
    224         Date* date = cast(Date*)(bind[i]); 
    225         (*date).year = resHelper.time[i].year; 
    226         (*date).month = resHelper.time[i].month; 
    227         (*date).day = resHelper.time[i].day; 
    228         (*date).hour = resHelper.time[i].hour; 
    229         (*date).min = resHelper.time[i].minute; 
    230         (*date).sec = resHelper.time[i].second;                      
    231         break;*/ 
     286            if(resHelper.types[i] == BindType.Time) { 
     287                Time* time = cast(Time*)(bind[i]); 
     288                DateTime dt; 
     289                dt.date.year = mysqlTime.year; 
     290                dt.date.month = mysqlTime.month; 
     291                dt.date.day = mysqlTime.day; 
     292                dt.time.hours = mysqlTime.hour; 
     293                dt.time.minutes = mysqlTime.minute; 
     294                dt.time.seconds = mysqlTime.second; 
     295                *time = Clock.fromDate(dt); 
     296            } 
     297            else if(resHelper.types[i] == BindType.DateTime) { 
     298                DateTime* dt = cast(DateTime*)(bind[i]); 
     299                (*dt).date.year = mysqlTime.year; 
     300                (*dt).date.month = mysqlTime.month; 
     301                (*dt).date.day = mysqlTime.day; 
     302                (*dt).time.hours = mysqlTime.hour; 
     303                (*dt).time.minutes = mysqlTime.minute; 
     304                (*dt).time.seconds = mysqlTime.second; 
     305            } 
     306        } 
     307         
    232308        if(res == 0) { 
    233             /+for(uint i = 0; i < resBind.length; ++i) 
    234             { 
    235                 if(resBind[i].buffer_type != enum_field_types.MYSQL_TYPE_STRING || 
    236                        resBind[i].buffer_type != enum_field_types.MYSQL_TYPE_BLOB) 
    237                 { 
    238                     ubyte[]* arr = cast(ubyte[]*)(bind[i]); 
    239                     //(*arr) = (*arr)[0 .. resHelper.len[i]]; 
    240                     uint l = resHelper.len[i]; 
    241                     *arr = resHelper.buffer[i][0 .. l]; 
    242                 } 
    243                  
    244             }+/ 
    245309            foreach(i, buf; resHelper.buffer) 
    246310            { 
     
    272336                *arr = buf[0 .. l]; 
    273337            } 
    274         /+  for(uint i = 0; i < resBind.length; ++i) 
    275             { 
    276                 if(*(resBind[i].error)) 
    277                 { 
    278                     if(resBind[i].buffer_type != enum_field_types.MYSQL_TYPE_STRING || 
    279                        resBind[i].buffer_type != enum_field_types.MYSQL_TYPE_BLOB) 
    280                     { 
    281                         debug(Log) { 
    282                             log.error("Error in column that is not String of Binary type"); 
    283                             logError; 
    284                         } 
    285                         return false; 
    286                     } 
    287                      
    288                      
    289                     ubyte[]* arr = cast(ubyte[]*)(bind[i]); 
    290                     if(!arr) { 
    291                         debug(Log) { 
    292                             log.error("Error retrieving String of Binary in bind parameters"); 
    293                             logError; 
    294                         } 
    295                         return false; 
    296                     } 
    297                     //(*arr).length = *(resBind[i].length); 
    298                     //resBind[i].buffer_length = *(resBind[i].length); 
    299                     uint l = resHelper.len[i]; 
    300                     resHelper.buffer[i].length = l; 
    301                     resBind[i].buffer_length = l; 
    302                     resBind[i].buffer = resHelper.buffer[i].ptr; 
    303                     if(mysql_stmt_fetch_column(stmt, &resBind[i], i, 0) != 0) { 
    304                         debug(Log) { 
    305                             log.error("Error fetching String of Binary that failed due to truncation"); 
    306                             logError; 
    307                         } 
    308                         return false; 
    309                     } 
    310                 } 
    311             }+/ 
    312338            return true; 
    313339        } 
     
    324350    { 
    325351        mysql_stmt_free_result(stmt); 
    326         //mysql_stmt_reset(stmt); 
    327352    } 
    328353     
     
    382407        MYSQL_TIME[uint] time; 
    383408        ubyte[][uint] buffer; 
     409        BindType[] types; 
    384410    } 
    385411     
     
    411437            case MYSQL_TYPE_TIME: 
    412438            case MYSQL_TYPE_DATETIME: 
    413                 return Time; 
     439                return DateTime; 
    414440            case MYSQL_TYPE_VAR_STRING: 
    415441            case MYSQL_TYPE_STRING: 
     
    506532                bind[i].is_unsigned = false; 
    507533                break; 
    508             //case(BindType.Date): 
    509             //case(BindType.DateTime): 
    510534            case(BindType.Time): 
    511535                helper.time[i] = MYSQL_TIME(); 
     
    514538                bind[i].is_unsigned = false; 
    515539                break; 
     540            case(BindType.DateTime): 
     541                helper.time[i] = MYSQL_TIME(); 
     542                bind[i].buffer = &helper.time[i]; 
     543                bind[i].buffer_type = enum_field_types.MYSQL_TYPE_DATETIME; 
     544                bind[i].is_unsigned = false; 
     545                break; 
     546            case(BindType.Null): 
     547                bind[i].buffer_type = enum_field_types.MYSQL_TYPE_NULL; 
     548                break; 
    516549            default: 
    517                 assert(false, "Unhandled bind type"); //TODO more detailed information; 
     550                debug assert(false, "Unhandled bind type"); //TODO more detailed information; 
     551                bind[i].buffer_type = enum_field_types.MYSQL_TYPE_NULL; 
     552                break; 
    518553            } 
    519554             
     
    522557            bind[i].is_null = &helper.is_null[i]; 
    523558        } 
     559         
     560        helper.types = types; 
    524561    } 
    525562     
     
    539576    } 
    540577} 
     578debug(UnitTest) { 
    541579 
    542580unittest 
     
    558596    uint id; 
    559597    char[] name; 
    560     DateTime dateofbirth; 
     598    Time dateofbirth; 
    561599    BindType[] resTypes; 
    562600    resTypes ~= BindType.UInt; 
     
    571609    assert(st.execute); 
    572610    assert(st.fetch(bind)); 
    573     Stdout.formatln("id:{},name:{},dateofbirth:{}",id,name,dateofbirth.year); 
     611    Stdout.formatln("id:{},name:{},dateofbirth:{}",id,name,dateofbirth.ticks); 
    574612    assert(!st.fetch(bind)); 
    575613     
     
    585623    assert(st2.execute(pBind)); 
    586624    assert(st2.fetch(bind)); 
    587     Stdout.formatln("id:{},name:{},dateofbirth:{}",id,name,dateofbirth.year); 
     625    Stdout.formatln("id:{},name:{},dateofbirth:{}",id,name,dateofbirth.ticks); 
     626    st2.reset; 
     627     
     628    assert(provider.hasTable("test")); 
     629    TableInfo ti; 
     630    assert(provider.getTableInfo("test", ti)); 
     631    assert(ti.fieldNames.length == 3); 
     632    assert(ti.primaryKeyFields.length == 1); 
     633    foreach(f; ti.fieldNames) 
     634    { 
     635        Stdout.formatln("Field Name:{}", f); 
     636    } 
     637     
     638    foreach(f; ti.primaryKeyFields) 
     639    { 
     640        Stdout.formatln("Primary Key:{}", f); 
     641    } 
     642     
     643    db.close; 
    588644} 
    589645 
    590646} 
     647} 
  • trunk/dbi/mysql/MysqlResult.d

    r70 r81  
    1313} 
    1414private import dbi.DBIException, dbi.Result, dbi.Row; 
    15 private import dbi.mysql.imp; 
     15version(Windows) { 
     16    private import dbi.mysql.imp_win; 
     17
     18else { 
     19    private import dbi.mysql.imp; 
     20
    1621 
    1722/** 
  • trunk/dbi/mysql/imp.d

    r74 r81  
    88 
    99extern (C): 
    10 version (Windows) extern (Windows): 
    1110 
    1211version (Windows) { 
  • trunk/dbi/sqlite/SqliteDatabase.d

    r70 r81  
    1515    private import tango.util.log.Log; 
    1616} 
    17 private import dbi.Database, dbi.DBIException, dbi.Result, dbi.Row, dbi.Statement, dbi.Registry
     17private import dbi.Database, dbi.DBIException, dbi.Result, dbi.Row, dbi.Statement, dbi.Registry, dbi.PreparedStatemt
    1818private import dbi.sqlite.imp, dbi.sqlite.SqliteError, dbi.sqlite.SqliteResult; 
    1919 
     
    272272        return false; 
    273273    } 
     274     
     275    IPreparedStatement createStatement(char[] statement) 
     276    { 
     277        sqlite3_stmt* stmt; 
     278        char* pzTail; 
     279        int res; 
     280        if((res = sqlite3_prepare_v2(database, toCString(statement), statement.length, &stmt, &pzTail)) != SQLITE_OK) { 
     281            char* errmsg = sqlite3_errmsg(db_); 
     282            logger.error("sqlite3_prepare_v2 for statement: \"" ~ statement ~ "\" returned: " ~ Integer.toUtf8(res) ~ ", errmsg: " ~ toDString(errmsg)); 
     283            return null; 
     284        } 
     285        return new SqlitePreparedStatement(stmt, database); 
     286    } 
    274287} 
    275288 
     
    289302        logger.trace("creating Sqlite database: " ~ url); 
    290303        return new SqliteDatabase(url); 
     304    } 
     305} 
     306 
     307class SqlitePreparedStatement : IPreparedStatement 
     308{ 
     309    static Logger logger; 
     310    static this() 
     311    { 
     312        logger = Log.getLogger("sendero.data.backends.Sqlite.SqlitePreparedStatement"); 
     313    } 
     314     
     315    private this(sqlite3_stmt* stmt, sqlite3* db) 
     316    { 
     317        this.stmt = stmt; 
     318        this.db = db; 
     319    } 
     320     
     321    ~this() 
     322    { 
     323        sqlite3_finalize(stmt); 
     324    } 
     325     
     326     
     327    private sqlite3_stmt* stmt; 
     328    package sqlite3* db; 
     329    private BindType[] paramTypes; 
     330    private BindType[] resTypes; 
     331    private bool row = false; 
     332    private bool wasReset = false; 
     333     
     334    int setParamTypes(BindType[] paramTypes) 
     335    { 
     336        this.paramTypes = paramTypes; 
     337    } 
     338     
     339    int setResultTypes(BindType[] resTypes) 
     340    { 
     341        this.resTypes = resTypes;    
     342    } 
     343     
     344    bool execute(StatementBinder binder) 
     345    { 
     346        uint i = 0; 
     347        foreach(p; paramTypes) 
     348        { 
     349            void* x; 
     350            size_t len; 
     351            binder(i, p, x, len); 
     352            switch(p) 
     353            { 
     354            case BindType.Bool: 
     355                if(sqlite3_bind_int(stmt, index + 1, *(cast(bool*)x)) != SQLITE_OK) return false; 
     356                break; 
     357            case BindType.Byte: 
     358                if(sqlite3_bind_int(stmt, index + 1, *(cast(byte*)x)) != SQLITE_OK) return false; 
     359                break; 
     360            case BindType.Short: 
     361                if(sqlite3_bind_int(stmt, index + 1, *(cast(short*)x)) != SQLITE_OK) return false; 
     362                break; 
     363            case BindType.Int: 
     364                if(sqlite3_bind_int(stmt, index + 1, *(cast(int*)x)) != SQLITE_OK) return false; 
     365                break; 
     366            case BindType.Long: 
     367                if(sqlite3_bind_int64(stmt, index + 1, *(cast(long*)x)) != SQLITE_OK) return false; 
     368                break; 
     369            case BindType.UByte: 
     370                if(sqlite3_bind_int(stmt, index + 1, *(cast(bool*)x)) != SQLITE_OK) return false; 
     371                break; 
     372            case BindType.UShort: 
     373                if(sqlite3_bind_int(stmt, index + 1, *(cast(ubyte*)x)) != SQLITE_OK) return false; 
     374                break; 
     375            case BindType.UInt: 
     376                if(sqlite3_bind_int64(stmt, index + 1, *(cast(uint*)x)) != SQLITE_OK) return false; 
     377                break; 
     378            case BindType.ULong: 
     379                if(sqlite3_bind_int64(stmt, index + 1, *(cast(ulong*)x)) != SQLITE_OK) return false; 
     380                break; 
     381            case BindType.Float: 
     382                if(sqlite3_bind_double(stmt, index + 1,  *(cast(float*)x)) != SQLITE_OK) return false; 
     383                break; 
     384            case BindType.Double: 
     385                if(sqlite3_bind_double(stmt, index + 1,  *(cast(double*)x)) != SQLITE_OK) return false; 
     386                break; 
     387            case BindType.String: 
     388                if(sqlite3_bind_text(stmt, index + 1, *cast(char**)x, len, null) != SQLITE_OK) return false; 
     389                break; 
     390            case BindType.UByteArray: 
     391            case BindType.VoidArray: 
     392                if(sqlite3_bind_blob(stmt, index + 1, *cast(void**)x, len, null) != SQLITE_OK) return false; 
     393                break; 
     394            case BindType.DateTime: 
     395                break; 
     396            case BindType.Date: 
     397                break; 
     398            case BindType.Time: 
     399                break; 
     400            default: 
     401                debug assert(false); 
     402                break; 
     403            } 
     404            ++i; 
     405        } 
     406         
     407        int ret = sqlite3_step(stmt); 
     408        wasReset = false; 
     409        switch(ret) 
     410        { 
     411            case SQLITE_ROW: 
     412                row = true; 
     413                return true; 
     414            case SQLITE_DONE: 
     415                row = false; 
     416                return true; 
     417            case SQLITE_BUSY: 
     418            default: 
     419                row = false; 
     420                return false; 
     421        } 
     422    } 
     423     
     424    bool fetch(StatementBinder binder) 
     425    { 
     426        if(!row) return false; 
     427        int ret = sqlite3_step(stmt); 
     428        wasReset = false; 
     429         
     430        uint index = 0; 
     431        foreach(r; resTypes) 
     432        { 
     433            void* x; 
     434            size_t len; 
     435            binder(index, r, x, len); 
     436            switch(p) 
     437            { 
     438            case BindType.Bool: 
     439                int z = sqlite3_column_int(stmt, index); 
     440                *cast(bool*)x = cast(bool)z; 
     441                break; 
     442            case BindType.Byte: 
     443                int z = sqlite3_column_int(stmt, index); 
     444                *cast(byte*)x = cast(byte)z; 
     445                break; 
     446            case BindType.Short: 
     447                int z = sqlite3_column_int(stmt, index); 
     448                *cast(short*)x = cast(short)z; 
     449                break; 
     450            case BindType.Int: 
     451                int z = sqlite3_column_int(stmt, index); 
     452                *cast(int*)x = z; 
     453                break; 
     454            case BindType.Long: 
     455                long z = sqlite3_column_int64(stmt, index); 
     456                *cast(long*)x = z; 
     457                break; 
     458            case BindType.UByte: 
     459                int z = sqlite3_column_int(stmt, index); 
     460                *cast(ubyte*)x = cast(ubyte)z; 
     461                break; 
     462            case BindType.UShort: 
     463                int z = sqlite3_column_int(stmt, index); 
     464                *cast(ushort*)x = cast(ushort)z; 
     465                break; 
     466            case BindType.UInt: 
     467                long z = sqlite3_column_int64(stmt, index); 
     468                *cast(uint*)x = cast(uint)z; 
     469                break; 
     470            case BindType.ULong: 
     471                long z = sqlite3_column_int64(stmt, index); 
     472                *cast(ulong*)x = cast(ulong)z; 
     473                break; 
     474            case BindType.Float: 
     475                double z = sqlite3_column_int(stmt, index); 
     476                *cast(float*)x = cast(float)z; 
     477                break; 
     478            case BindType.Double: 
     479                double z = sqlite3_column_int(stmt, index); 
     480                *cast(double*)x = z; 
     481                break; 
     482            case BindType.String: 
     483                char[] z = fromCStringz(sqlite3_column_text(stmt, index)); 
     484                *cast(char**)x = z.ptr; 
     485                len = z.length; 
     486                break; 
     487            case BindType.UByteArray: 
     488            case BindType.VoidArray: 
     489                void* res = sqlite3_column_blob(stmt, index); 
     490                len = sqlite3_column_bytes(stmt, index); 
     491                *cast(char**)x = len ? res[0 .. len] : null; 
     492                break; 
     493            case BindType.DateTime: 
     494                break; 
     495            case BindType.Date: 
     496                break; 
     497            case BindType.Time: 
     498                break; 
     499            default: 
     500                debug assert(false); 
     501                break; 
     502            } 
     503            ++i; 
     504        } 
     505         
     506        row = (ret == SQLITE_ROW); 
     507        return true; 
     508    } 
     509     
     510    void reset() 
     511    { 
     512        if(!wasReset) { 
     513            sqlite3_reset(stmt); 
     514            wasReset = true; 
     515        } 
     516    } 
     517     
     518    ulong getLastInsertID() 
     519    { 
     520        long id = sqlite3_last_insert_rowid(db); 
     521        return cast(ulong)id; 
    291522    } 
    292523}