• Main Page
  • Namespaces
  • Classes
  • Files
  • File List

mysqlpl.d

Go to the documentation of this file.
00001 module mysqlpl;
00002 
00003  //
00004  // mysqlpl.d
00005  //
00006  // Copyright (c) 2007 Martin Fuchs <martin-fuchs@gmx.net>
00007  //
00008 
00009  /// \file mysqlpl.d
00010  /// MySQLPL/D implementation file
00011 
00012 
00013 /*
00014 
00015   All rights reserved.
00016 
00017   Redistribution and use in source and binary forms, with or without
00018   modification, are permitted provided that the following conditions are met:
00019 
00020   * Redistributions of source code must retain the above copyright
00021     notice, this list of conditions and the following disclaimer.
00022   * Redistributions in binary form must reproduce the above copyright
00023     notice, this list of conditions and the following disclaimer in
00024     the documentation and/or other materials provided with the
00025     distribution.
00026 
00027   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00028   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00029   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00030   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00031   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00032   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00033   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00034   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00035   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00036   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00037   POSSIBILITY OF SUCH DAMAGE.
00038 
00039 */
00040 
00041 version(XMLSTORAGE) {
00042   import xmlstorage;
00043 }
00044 
00045 import std.stdio;
00046 import std.stream;
00047 import std.string;
00048 
00049 import std.c.string; // strlen()
00050 //static import std.c.stdlib; // atoll(), malloc()
00051 
00052 
00053    // C wrapper for MySQL API
00054 
00055   extern (C) {
00056 
00057     struct MYSQL;
00058     struct MYSQL_STMT;
00059     struct MYSQL_FIELD;
00060     struct MYSQL_RES;
00061     struct MYSQL_BIND;
00062 
00063     alias ulong my_ulonglong;
00064     alias char my_bool;
00065     alias char** MYSQL_ROW;
00066     alias long LONGLONG;
00067 
00068 
00069     enum MYSQL_FIELD_TYPES { // enum_field_types
00070         MYSQL_TYPE_DECIMAL,
00071         MYSQL_TYPE_TINY,
00072         MYSQL_TYPE_SHORT,
00073         MYSQL_TYPE_LONG,
00074         MYSQL_TYPE_FLOAT,
00075         MYSQL_TYPE_DOUBLE,
00076         MYSQL_TYPE_NULL,
00077         MYSQL_TYPE_TIMESTAMP,
00078         MYSQL_TYPE_LONGLONG,
00079         MYSQL_TYPE_INT24,
00080         MYSQL_TYPE_DATE,
00081         MYSQL_TYPE_TIME,
00082         MYSQL_TYPE_DATETIME,
00083         MYSQL_TYPE_YEAR,
00084         MYSQL_TYPE_NEWDATE, // since MySQL 5.0
00085         MYSQL_TYPE_VARCHAR, // since MySQL 5.0
00086         MYSQL_TYPE_BIT,
00087         MYSQL_TYPE_NEWDECIMAL   = 246,
00088         MYSQL_TYPE_ENUM         = 247,
00089         MYSQL_TYPE_SET          = 248,
00090         MYSQL_TYPE_TINY_BLOB    = 249,
00091         MYSQL_TYPE_MEDIUM_BLOB  = 250,
00092         MYSQL_TYPE_LONG_BLOB    = 251,
00093         MYSQL_TYPE_BLOB         = 252,
00094         MYSQL_TYPE_VAR_STRING   = 253,
00095         MYSQL_TYPE_STRING       = 254,
00096         MYSQL_TYPE_GEOMETRY     = 255
00097     };
00098 
00099     enum MYSQL_TIMESTAMP_TYPE {
00100         MYSQL_TIMESTAMP_NONE    = -2,
00101         MYSQL_TIMESTAMP_ERROR   = -1,
00102         MYSQL_TIMESTAMP_DATE    =  0,
00103         MYSQL_TIMESTAMP_DATETIME= 1,
00104         MYSQL_TIMESTAMP_TIME    = 2
00105     };
00106 
00107 
00108     const int MYSQL_NO_DATA         = 100;
00109     const int MYSQL_DATA_TRUNCATED  = 101;
00110 
00111 
00112     const int MYSQL_NOT_NULL_FLAG = 1;  // MySQL field can't be null
00113 
00114     bool IS_NOT_NULL(int flags)
00115     {
00116         return (flags&MYSQL_NOT_NULL_FLAG) != 0;
00117     }
00118 
00119 
00120     const int MYSQL_BINARY_FLAG = 128;  // MySQL result set field is binary
00121 
00122 
00123      // interface to mysqlpl_fwd.cpp
00124 
00125     MYSQL* mysqlpl_init(MYSQL*);
00126     MYSQL_FIELD* mysqlpl_next_field(MYSQL_FIELD*);  // increment MYSQL_FIELD pointer using the correct structure size according to the mysql header files
00127 
00128     char* mysqlpl_field_get_table(in MYSQL_FIELD*);
00129     char* mysqlpl_field_get_name(in MYSQL_FIELD*);
00130     MYSQL_FIELD_TYPES mysqlpl_field_get_type(in MYSQL_FIELD*);
00131     int mysqlpl_field_get_length(in MYSQL_FIELD*);
00132     int mysqlpl_field_get_decimals(in MYSQL_FIELD*);
00133     int mysqlpl_field_get_flags(in MYSQL_FIELD*);
00134 
00135     void bindvector_free(MYSQL_BIND*);
00136     MYSQL_BIND* bindvector_resize(MYSQL_BIND*, int length);
00137     MYSQL_BIND* bindvector_next(MYSQL_BIND*);
00138     void bindvector_bind(MYSQL_BIND*, void* ptr, MYSQL_FIELD_TYPES type, int len, my_bool* pind, uint* plen);
00139 
00140   } // extern (C)
00141 
00142   extern (Windows) {
00143     MYSQL*      (*mysqlpl_real_connect) (MYSQL* mysql, char* host, char* user, char* passwd,
00144                                         char* db, uint port, char* unix_socket, uint clientflag);
00145     void        (*mysqlpl_close)        (MYSQL*);
00146 
00147     char*       (*mysqlpl_info)         (MYSQL* db);
00148     uint        (*mysqlpl_errno)        (MYSQL* db);
00149     char*       (*mysqlpl_error)        (MYSQL* db);
00150     uint        (*mysqlpl_warning_count)(MYSQL* db);
00151 
00152     MYSQL_RES*  (*mysqlpl_store_result) (MYSQL* db);
00153     void        (*mysqlpl_free_result)  (MYSQL_RES*);
00154 
00155     my_ulonglong (*mysqlpl_affected_rows)   (MYSQL* db);
00156     uint        (*mysqlpl_num_fields)       (MYSQL_RES* res);
00157     MYSQL_FIELD* (*mysqlpl_fetch_fields)    (MYSQL_RES*);
00158     MYSQL_FIELD* (*mysqlpl_fetch_field_direct)(MYSQL_RES*, int);
00159 
00160   version(MYSQLPL_PREP_STMT) {
00161     char*       (*mysqlpl_sqlstate)             (MYSQL* db);
00162     uint        (*mysqlpl_stmt_errno)           (MYSQL_STMT* s);
00163     char*       (*mysqlpl_stmt_error)           (MYSQL_STMT* s);
00164     char*       (*mysqlpl_stmt_sqlstate)        (MYSQL_STMT* s);
00165     my_bool     (*mysqlpl_autocommit)           (MYSQL* db, uint);
00166     MYSQL_STMT* (*mysqlpl_stmt_init)            (MYSQL*);
00167     int         (*mysqlpl_stmt_prepare)         (MYSQL_STMT*, char* sql, int length);
00168     void        (*mysqlpl_stmt_close)           (MYSQL_STMT*);
00169     int         (*mysqlpl_stmt_execute)         (MYSQL_STMT*);
00170     int         (*mysqlpl_stmt_fetch)           (MYSQL_STMT*);
00171     MYSQL_RES*  (*mysqlpl_stmt_store_result)    (MYSQL_STMT* s);
00172     my_bool     (*mysqlpl_stmt_bind_param)      (MYSQL_STMT*, MYSQL_BIND*);
00173     my_bool     (*mysqlpl_stmt_bind_result)     (MYSQL_STMT* s, MYSQL_BIND*);
00174     int         (*mysqlpl_stmt_affected_rows)   (MYSQL_STMT* s);
00175     MYSQL_RES*  (*mysqlpl_stmt_result_metadata) (MYSQL_STMT* s);
00176   }
00177 
00178     my_bool     (*mysqlpl_commit)       (MYSQL* db);
00179     my_bool     (*mysqlpl_rollback)     (MYSQL* db);
00180 
00181     my_bool     (*mysqlpl_query)        (MYSQL* db, char* sql);
00182     MYSQL_ROW   (*mysqlpl_fetch_row)    (MYSQL_RES* res);
00183     my_ulonglong (*mysqlpl_insert_id)   (MYSQL* db);
00184 
00185   } // extern (Windows)
00186 
00187 
00188 class vector(T)
00189 {
00190 public:
00191     this()
00192     {
00193     }
00194 
00195     this(int size)
00196     {
00197         _entries.length = size;
00198 
00199         for(int i=0; i<size; ++i)
00200             _entries[i] = new T;
00201     }
00202 
00203     void push_back(T entry)
00204     {
00205         _entries.length = _entries.length + 1;
00206         _entries[_entries.length-1] = entry;
00207     }
00208 
00209     T front()
00210     {
00211         assert(_entries.length>0);
00212         return _entries[0];
00213     }
00214 
00215     T back()
00216     {
00217         assert(_entries.length>0);
00218         return _entries[_entries.length-1];
00219     }
00220 
00221     bool empty()
00222     {
00223         return !_entries.length;
00224     }
00225 
00226     int length()
00227     {
00228         return _entries.length;
00229     }
00230 
00231     void resize(int l)
00232     {
00233         _entries.length = l;
00234     }
00235 
00236     void clear()
00237     {
00238         foreach(entry; _entries)
00239             delete entry;
00240 
00241         _entries = null;
00242     }
00243 
00244     T opIndex(int idx)
00245     {
00246         return _entries[idx];
00247     }
00248 
00249     void opIndexAssign(int idx, T value)
00250     {
00251         _entries[idx] = value;
00252     }
00253 
00254     int opApply(int delegate(inout T) dg)
00255     {
00256         int result = 0;
00257 
00258         foreach(e; _entries) {
00259             result = dg(e);
00260 
00261             if (result)
00262                 break;
00263         }
00264 
00265         return result;
00266     }
00267 
00268 protected:
00269     T[] _entries;
00270 };
00271 
00272 
00273  /// MySQL Errorhandling
00274 
00275 class MSqlException : public Exception
00276 {
00277     this(MYSQL* db/*, in char[] file, int line*/)
00278     {
00279         _sql_error_code = mysqlpl_errno(db);
00280         char* error_str = mysqlpl_error(db);
00281 
00282       version(MYSQLPL_PREP_STMT) {
00283         char* state_str = mysqlpl_sqlstate(db);
00284 
00285         super(format("MySQL error %d - SQLSTATE %s: %s",
00286                 _sql_error_code, state_str[0..strlen(state_str)], error_str[0..strlen(error_str)]));
00287 
00288         _sqlstate = state_str[0 .. state_str?strlen(state_str):0];
00289       } else {
00290         super(format("MySQL error %d: %s", _sql_error_code, error_str));
00291       }
00292 
00293     //  _file = file;
00294     //  _line = line;
00295     }
00296 
00297   version(MYSQLPL_PREP_STMT) {
00298     this(MYSQL_STMT* s/*, in char[] file, int line*/)
00299     {
00300         _sql_error_code = mysqlpl_stmt_errno(s);
00301         char* error_str = mysqlpl_stmt_error(s);
00302 
00303       version(MYSQLPL_PREP_STMT) {
00304         char* state_str = mysqlpl_stmt_sqlstate(s);
00305 
00306         super(format("MySQL error %d - SQLSTATE %s: %s",
00307                 _sql_error_code, state_str[0..strlen(state_str)], error_str[0..strlen(error_str)]));
00308 
00309         _sqlstate = state_str[0 .. state_str?strlen(state_str):0];
00310       } else {
00311         super(format("MySQL error %d: %s", _sql_error_code, error_str));
00312       }
00313 
00314     //  _file = file;
00315     //  _line = line;
00316     }
00317 
00318     this(MYSQL_STMT* s, SqlStatement stmt/*, in char[] file, int line*/)
00319     {
00320         _sql_error_code = mysqlpl_stmt_errno(s);
00321         char* error_str = mysqlpl_stmt_error(s);
00322         char* state_str = mysqlpl_stmt_sqlstate(s);
00323 
00324         char[] msg = format("MySQL error %d - SQLSTATE %s: %s",
00325                         _sql_error_code, state_str[0..strlen(state_str)], error_str[0..strlen(error_str)]);
00326 
00327         _last_sql = stmt.get_last_sql();
00328 
00329         if (_last_sql.length)
00330             msg ~= format("\nlast SQL statement:\n%s\n", _last_sql);
00331 
00332         super(msg);
00333 
00334         _sqlstate = state_str[0 .. state_str?strlen(state_str):0];
00335 
00336     //  _file = file;
00337     //  _line = line;
00338     }
00339 
00340   } // MYSQLPL_PREP_STMT
00341 
00342     this(in char[] msg/*, in char* file, int line*/)
00343     {
00344         super(msg);
00345 
00346     //  _file = file;
00347     //  _line = line;
00348     }
00349 
00350     uint    _sql_error_code;
00351 
00352   version(MYSQLPL_PREP_STMT) {
00353     char[]  _sqlstate;
00354   }
00355 
00356     char[]  _last_sql;
00357 //  char[]  _file;
00358 //  int     _line;
00359 };
00360 
00361 
00362  /// error handling functions
00363 
00364 void mysqlpl_check_error(MYSQL* db)
00365 {
00366     uint error = mysqlpl_errno(db);
00367 
00368     if (error != 0)
00369         throw new MSqlException(db);
00370 }
00371 
00372 void mysqlpl_check_error(MYSQL* db, int res)
00373 {
00374     if (res) {
00375         uint error = mysqlpl_errno(db);
00376 
00377         if (error != 0)
00378             throw new MSqlException(db);
00379     }
00380 }
00381 
00382 void mysqlpl_check_error(MYSQL* db, my_bool b)
00383 {
00384     if (b) {
00385         uint error = mysqlpl_errno(db);
00386 
00387         if (error != 0)
00388             throw new MSqlException(db);
00389     }
00390 }
00391 
00392 version(MYSQLPL_PREP_STMT) {
00393 void mysqlpl_check_error(MYSQL_STMT* s)
00394 {
00395     uint error = mysqlpl_stmt_errno(s);
00396 
00397     if (error != 0)
00398         throw new MSqlException(s);
00399 }
00400 
00401 void mysqlpl_check_error(MYSQL_STMT* s, int res)
00402 {
00403     if (res) {
00404         uint error = mysqlpl_stmt_errno(s);
00405 
00406         if (error != 0)
00407             throw new MSqlException(s);
00408     }
00409 }
00410 
00411 void mysqlpl_check_error(MYSQL_STMT* s, my_bool b)
00412 {
00413     if (b) {
00414         uint error = mysqlpl_stmt_errno(s);
00415 
00416         if (error != 0)
00417             throw new MSqlException(s);
00418     }
00419 }
00420 } // version(MYSQLPL_PREP_STMT)
00421 
00422 
00423 class MSqlEnv
00424 {
00425     this(MYSQL* mysql=null)
00426     {
00427         _mysql = mysqlpl_init(null);
00428     }
00429 
00430     ~this()
00431     {
00432         mysqlpl_close(_mysql);
00433     }
00434 
00435     MYSQL* opCast() {return _mysql;}
00436     MYSQL* opCall() {return _mysql;}
00437 
00438 protected:
00439     MYSQL*  _mysql;
00440 };
00441 
00442 
00443  /// simple MySQL login to database
00444 
00445 class MSqlConnection
00446 {
00447     this(MSqlEnv env, in char[] username, in char[] password, in char[] db_name,
00448                     in char[] host="localhost", uint port=3306, uint clientflag=0)
00449     {
00450         _env = env;
00451         _db = null;
00452         _connected = false;
00453 
00454         connect(username, password, db_name, host, port, clientflag);
00455     }
00456 
00457     void connect(in char[] username, in char[] password, in char[] db_name,
00458                     in char[] host="localhost", uint port=3306, uint clientflag=0)
00459     {
00460         _connected = false;
00461 
00462         _db = mysqlpl_real_connect(_env(), toStringz(host), toStringz(username), toStringz(password), toStringz(db_name), port, null, clientflag);
00463 
00464         if (!_db)
00465             throw new MSqlException(_env());
00466 
00467         _connected = true;
00468 
00469       version(MYSQLPL_PREP_STMT) {
00470          // disable auto commit mode
00471         my_bool res = mysqlpl_autocommit(_db, 0);
00472         mysqlpl_check_error(_env(), res);
00473       } else {
00474         (new SqlStatement(this)).execute("set autocommit=0");   // "set autocommit=0" is not supported before MySQL 4.1
00475       }
00476     }
00477 
00478     ~this()
00479     {
00480         /*see MSqlEnv::~MSqlEnv()
00481         if (_connected)
00482             mysqlpl_close(_mysql);
00483         */
00484     }
00485 
00486 
00487   version(MYSQLPL_PREP_STMT) {
00488      // get warnings
00489     uint get_warnings_count()
00490     {
00491         uint res = mysqlpl_warning_count(_db);
00492 
00493         if (res == -1)
00494             throw new MSqlException(_db);
00495 
00496         return res;
00497     }
00498 
00499     char[] get_info()
00500     {
00501         char* info = mysqlpl_info(_db);
00502 
00503         if (!info)
00504             throw new MSqlException(_db);
00505 
00506         return info[0 .. info?strlen(info):0];
00507     }
00508 
00509     void print_warnings(Stream o)
00510     {
00511         while(get_warnings_count())
00512             o.writeString(get_info() ~ '\n');
00513     }
00514   } else { // version(MYSQLPL_PREP_STMT)
00515     char[] get_info()
00516     {
00517         char* ret = mysqlpl_info(_db);
00518 
00519         return ret[0 .. ret?strlen(ret):0];
00520     }
00521 
00522     void print_warnings(Stream o)
00523     {
00524         char[] info = get_info();
00525 
00526         if (info.length)
00527             o.writeString(info ~ '\n');
00528     }
00529   }
00530 
00531      // get last generated insert ID
00532     my_ulonglong get_insert_id()
00533     {
00534         return mysqlpl_insert_id(_db);
00535     }
00536 
00537 
00538     void commit()
00539     {
00540       version(MYSQLPL_PREP_STMT) {
00541         my_bool res = mysqlpl_commit(_db);
00542       } else {
00543         my_bool res = mysqlpl_query(_db, "commit");
00544       }
00545         mysqlpl_check_error(_env(), res);
00546     }
00547 
00548     void rollback()
00549     {
00550       version(MYSQLPL_PREP_STMT) {//@@
00551         my_bool res = mysqlpl_rollback(_db);
00552       } else {
00553         my_bool res = mysqlpl_query(_db, "rollback");
00554       }
00555         mysqlpl_check_error(_env(), res);
00556     }
00557 
00558     MYSQL* opCast() {return _db;}
00559     MYSQL* opCall() {return _db;}
00560 
00561 protected:
00562     MSqlEnv _env;
00563     MYSQL*  _db;
00564 
00565     bool    _connected;
00566 };
00567 
00568 
00569  /// column description
00570 
00571 class ColumnType
00572 {
00573     char[]  _table_name;
00574     char[]  _name;
00575     MYSQL_FIELD_TYPES _data_type;
00576     int     _width;
00577     int     _decimals;
00578     int     _flags;
00579 
00580     this()
00581     {
00582         _data_type = cast(MYSQL_FIELD_TYPES)-1;
00583         _width = 0;
00584         _decimals = 0;
00585         _flags = 0;
00586     }
00587 
00588     char[] get_type_str(bool show_null=false)
00589     {
00590         char[] str;
00591 
00592         switch(_data_type) {
00593           case MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING:
00594             str = format("char(%d)", _width);
00595             break;
00596 
00597           case MYSQL_FIELD_TYPES.MYSQL_TYPE_VAR_STRING:
00598             str = format("varchar(%d)", _width);
00599             break;
00600 
00601           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DECIMAL:
00602             if (_width == 0)
00603                 str = "decimal";
00604             else
00605                 str = format("decimal(%d,%d)", _width-1, _decimals);
00606             break;
00607 
00608           case MYSQL_FIELD_TYPES.MYSQL_TYPE_NEWDECIMAL: // MYSQL_VERSION_ID>=50000
00609             if (_width == 0)
00610                 str = "newdecimal";
00611             else
00612                 str = format("newdecimal(%d,%d)", _width-1, _decimals);
00613             break;
00614 
00615           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TINY:
00616             str = format("tinyint(%d)", _width);
00617             break;
00618           case MYSQL_FIELD_TYPES.MYSQL_TYPE_SHORT:
00619             str = format("shortint(%d)", _width);
00620             break;
00621           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG:
00622             str = format("int(%d)", _width);
00623             break;
00624           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONGLONG:
00625             str = format("bigint(%d)", _width);
00626             break;
00627 
00628           case MYSQL_FIELD_TYPES.MYSQL_TYPE_ENUM:
00629             str = "enum";
00630             break;
00631 
00632           case MYSQL_FIELD_TYPES.MYSQL_TYPE_FLOAT:
00633             if (_width == 12)
00634                 str = "float";
00635             else
00636                 str = format("float(%d,%d)", _width, _decimals);
00637             break;
00638 
00639           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE:
00640             if (_width == 22)
00641                 str = "double";
00642             else
00643                 str = format("double(%d,%d)", _width, _decimals);
00644             break;
00645 
00646           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATE:
00647             str = "date";
00648             break;
00649 
00650           case MYSQL_FIELD_TYPES.MYSQL_TYPE_NEWDATE:    // MYSQL_VERSION_ID>=50000
00651             str = "newdate";
00652             break;
00653 
00654           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATETIME:
00655             str = "datetime";
00656             break;
00657           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TIME:
00658             str = "time";
00659             break;
00660           case MYSQL_FIELD_TYPES.MYSQL_TYPE_YEAR:
00661             str = format("year(%d)", _width);
00662             break;
00663 
00664           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TINY_BLOB:
00665             if (_flags & MYSQL_BINARY_FLAG)
00666                 str = "tinyblob";
00667             else
00668                 str = "tinytext";
00669             break;
00670           case MYSQL_FIELD_TYPES.MYSQL_TYPE_MEDIUM_BLOB:
00671             if (_flags & MYSQL_BINARY_FLAG)
00672                 str = "mediumblob";
00673             else
00674                 str = "mediumtext";
00675             break;
00676           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG_BLOB:
00677             if (_flags & MYSQL_BINARY_FLAG)
00678                 str = "longblob";
00679             else
00680                 str = "longtext";
00681             break;
00682           case MYSQL_FIELD_TYPES.MYSQL_TYPE_BLOB:
00683             if (_flags & MYSQL_BINARY_FLAG)
00684                 str = "blob";
00685             else
00686                 str = "text";
00687             break;
00688 
00689           default:
00690             str = "unknown";
00691         }
00692 
00693         if (show_null)
00694             if (IS_NOT_NULL(_flags))
00695                 str ~= " not null";
00696             else
00697                 str ~= " null";
00698 
00699         return str;
00700     }
00701 
00702     void init(in MYSQL_FIELD* field)
00703     {
00704         char* table = mysqlpl_field_get_table(field);
00705         char* name = mysqlpl_field_get_name(field);
00706 
00707          // get column name
00708         _table_name = table[0 .. strlen(table)];
00709         _name       = name[0 .. strlen(name)];
00710 
00711          // get column data type
00712         _data_type  = mysqlpl_field_get_type(field);
00713 
00714         _width      = mysqlpl_field_get_length(field);
00715         _decimals   = mysqlpl_field_get_decimals(field);
00716 
00717          // get null-ability, binary, ... flags
00718         _flags      = mysqlpl_field_get_flags(field);
00719     }
00720 };
00721 
00722 
00723 class ColumnData {
00724     this()
00725     {
00726         _type = new ColumnType;
00727     }
00728 
00729     ColumnType  _type;
00730 
00731   version(MYSQLPL_PREP_STMT) {
00732     SqlVariant  _column;
00733   }
00734 };
00735 
00736 
00737 class BindVector : public vector!(BindPar)
00738 {
00739     void bind(int idx, in BindPar par)
00740     {
00741         _entries[idx] = par;
00742     }
00743 };
00744 
00745 
00746 version(MYSQLPL_PREP_STMT) {
00747 
00748 void mysqlpl_bind_param(in BindPar par, MYSQL_BIND* bind)
00749 {
00750     bindvector_bind(bind, par._ptr, par._type, par._len, par._pind, par._plen);
00751 
00752 /* ersetzt
00753     memset(&bind, 0, sizeof(bind));
00754 
00755     bind.buffer = par._ptr;
00756     bind.buffer_type = par._type;
00757     bind.buffer_length = par._len;
00758     bind.is_null = par._pind;
00759     bind.length = par._plen;
00760 */
00761 }
00762 
00763 }
00764 
00765 
00766 alias vector!(ColumnData) ColumnDataVector;
00767 
00768 
00769  /// a record to hold return columns for a given statement
00770 
00771 class SqlRecord
00772 {
00773     this(SqlStatement stmt)
00774     {
00775         _stmt = stmt;
00776 
00777         int column_cnt = stmt.get_column_count();
00778 
00779         _columns = new ColumnDataVector(column_cnt);
00780 
00781         MYSQL_FIELD* fields = mysqlpl_fetch_fields(stmt.get_meta_res());
00782 
00783         foreach(ColumnData col; _columns) {
00784             col._type.init(fields);
00785 
00786             fields = mysqlpl_next_field(fields);
00787 
00788           version(MYSQLPL_PREP_STMT) {
00789             col._column = new SqlVariant(col._type._data_type);
00790           }
00791         }
00792 
00793         //_name_map.clear();
00794     }
00795 
00796     int get_column_count()
00797     {
00798         return _columns.length;
00799     }
00800 
00801   version(MYSQLPL_PREP_STMT) {
00802     SqlVariant get_column(int idx)
00803     {
00804         return _columns[idx]._column;
00805     }
00806 
00807     SqlVariant get_column(in char[] col_name)
00808     {
00809         int* found = find_column(col_name);
00810 
00811         if (found)
00812             return _columns[*found]._column;
00813         else {
00814             throw new MSqlException("column not found");
00815             return null;
00816         }
00817     }
00818   }
00819 
00820     ColumnType get_column_type(int idx)
00821     {
00822         return _columns[idx]._type;
00823     }
00824 
00825     ColumnType get_column_type(in char[] col_name)
00826     {
00827         int* found = find_column(col_name);
00828 
00829         if (found)
00830             return _columns[*found]._type;
00831         else {
00832             throw new MSqlException("column not found");
00833             return null;
00834         }
00835     }
00836 
00837     void print_columns(Stream o)
00838     {
00839         foreach(col; _columns) {
00840             ColumnType type = col._type;
00841 
00842             if (type._table_name.length)
00843                 o.writeString(type._table_name ~ '.');
00844 
00845             o.writeString(type._name ~ ": " ~ type.get_type_str() ~ '\n');
00846         }
00847 
00848         o.write('\n');
00849     }
00850 
00851     void print_values(Stream o)
00852     {
00853       version(XMLSTORAGE) {
00854         foreach(col; _columns) {
00855             ColumnType type = col._type;
00856 
00857     //      if (type._table_name.length)
00858     //          o.writeString(type._table_name ~ ".");
00859 
00860             o.writeString(type._name ~ "=" ~ col._column.str() ~ '\n');
00861         }
00862       } else {
00863         int i = 0;
00864 
00865         foreach(col; _columns) {
00866             ColumnType type = col._type;
00867 
00868     //      if (type._table_name)
00869     //          o.writeString(type._table_name ~ ".");
00870 
00871             o.writeString(type._name ~ "=" ~ _stmt().get_string(i++) ~ '\n');
00872         }
00873       }
00874     }
00875 
00876   version(XMLSTORAGE) {
00877     void dump_values(XMLStorage.XMLPos o);
00878   }
00879 
00880 protected:
00881     SqlStatement    _stmt;
00882     ColumnDataVector _columns;
00883 
00884     int[char[]]     _name_map;  // column index cache
00885 
00886     int* find_column(in char[] col_name)
00887     {
00888          // initialize column name map
00889         if (!_name_map) {
00890             int idx = 0;
00891 
00892             foreach(col; _columns)
00893                 _name_map[toupper(col._type._name)] = idx++;
00894         }
00895 
00896         return toupper(col_name) in _name_map;
00897     }
00898 
00899     int get_column_idx(in char[] col_name)
00900     {
00901         int* found = find_column(col_name);
00902 
00903         if (found)
00904             return *found;
00905         else {
00906             throw new MSqlException("column not found");
00907             //return -1;
00908         }
00909     }
00910 };
00911 
00912 
00913 version(MYSQLPL_PREP_STMT) {
00914 
00915 class SqlResult : public SqlRecord
00916 {
00917     this(SqlStatement stmt)
00918     {
00919         super(stmt);
00920 
00921       version(MYSQLPL_PREP_STMT) {
00922         stmt.bind_result(_columns);
00923       }
00924     }
00925 
00926     bool is_null(int idx)
00927     {
00928         return get_column(idx).is_null();
00929     }
00930     int is_null(in char[] col_name)
00931     {
00932         return get_column(col_name).is_null();
00933     }
00934 
00935     bool is_not_null(int idx)
00936     {
00937         return get_column(idx).is_not_null();
00938     }
00939     int is_not_null(in char[] col_name)
00940     {
00941         return get_column(col_name).is_not_null();
00942     }
00943 
00944     int get_int(int idx)
00945     {
00946         return get_column(idx).get_int();
00947     }
00948     int get_int(in char[] col_name)
00949     {
00950         return get_column(col_name).get_int();
00951     }
00952 
00953     long get_int64(int idx)
00954     {
00955         return get_column(idx).get_int64();
00956     }
00957     long get_int64(in char[] col_name)
00958     {
00959         return get_column(col_name).get_int64();
00960     }
00961 
00962     double get_double(int idx)
00963     {
00964         return get_column(idx).get_double();
00965     }
00966     double get_double(in char[] col_name)
00967     {
00968         return get_column(col_name).get_double();
00969     }
00970 
00971     char[] get_string(int idx)
00972     {
00973         return get_column(idx).str();
00974     }
00975     char[] get_string(in char[] col_name)
00976     {
00977         return get_column(col_name).str();
00978     }
00979 
00980   version(MYSQLPL_PREP_STMT) { // always used in this section
00981     SqlDate get_date(int idx, MYSQL_TIMESTAMP_TYPE type=MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATE)
00982     {
00983         return get_column(idx).date(type);
00984     }
00985 
00986     SqlDate get_date(in char[] col_name, MYSQL_TIMESTAMP_TYPE type=MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATE)
00987     {
00988         return get_column(col_name).date(type);
00989     }
00990   }
00991 };
00992 
00993 } else { // version(MYSQLPL_PREP_STMT)
00994 
00995  /// class to retrieve query result values
00996 
00997 class SqlResult : public SqlRecord
00998 {
00999     MYSQL_ROW   _row;
01000 
01001     this(SqlStatement stmt)
01002     {
01003         super(stmt);
01004         _row = null;
01005     }
01006 
01007     bool is_null(int idx)
01008     {
01009         return _row[idx] == null;
01010     }
01011     int is_null(in char[] col_name)
01012     {
01013         return is_null(get_column_idx(col_name));
01014     }
01015 
01016     bool is_not_null(int idx)
01017     {
01018         return _row[idx] != null;
01019     }
01020     int is_not_null(in char[] col_name)
01021     {
01022         return is_not_null(get_column_idx(col_name));
01023     }
01024 
01025     int get_int(int idx)
01026     {
01027         return std.c.stdlib.atoi(_row[idx]);
01028     }
01029     int get_int(in char[] col_name)
01030     {
01031         return get_int(get_column_idx(col_name));
01032     }
01033 
01034     long get_int64(int idx)
01035     {
01036         return std.c.stdlib.atoll(_row[idx]);
01037     }
01038     long get_int64(in char[] col_name)
01039     {
01040         return get_int64(get_column_idx(col_name));
01041     }
01042 
01043     double get_double(int idx)
01044     {
01045         return std.c.stdlib.atof(_row[idx]);
01046     }
01047     double get_double(in char[] col_name)
01048     {
01049         return get_double(get_column_idx(col_name));
01050     }
01051 
01052     char[] get_string(int idx)
01053     {
01054         char* str = _row[idx];
01055         return str? str[0..strlen(str)]: "";
01056     }
01057     char[] get_string(in char[] col_name)
01058     {
01059         return get_string(get_column_idx(col_name));
01060     }
01061 
01062   version(MYSQLPL_PREP_STMT) { // never used
01063     SqlDate get_date(int idx, MYSQL_TIMESTAMP_TYPE type=MYSQL_TIMESTAMP_DATE)
01064     {
01065         return get_column(idx).date(type);
01066     }
01067 
01068     SqlDate get_date(in char[] col_name, MYSQL_TIMESTAMP_TYPE type=MYSQL_TIMESTAMP_DATE)
01069     {
01070         return get_date(get_column_idx(col_name));
01071     }
01072   }
01073 };
01074 
01075 } // MYSQLPL_PREP_STMT
01076 
01077 
01078 class BindPar
01079 {
01080     void*       _ptr;
01081     int         _len;
01082     MYSQL_FIELD_TYPES _type;
01083     my_bool*    _pind;
01084     uint*       _plen;
01085 
01086     this()
01087     {
01088         _ptr    = null;
01089         _len    = 0;
01090         _type   = cast(MYSQL_FIELD_TYPES)-1;
01091         _pind   = null;
01092         _plen   = null;
01093     }
01094 
01095     this(in char[] str, my_bool* pind=null)
01096     {
01097         _ptr    = str.ptr;
01098         _len    = str.length;
01099         _type   = MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING;
01100         _pind   = pind;
01101         _plen   = null;
01102     }
01103 
01104     this(in int* var, my_bool* pind=null)
01105     {
01106         _ptr    = var;
01107         _len    = (*var).sizeof;
01108         _type   = MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG;
01109         _pind   = pind;
01110         _plen   = null;
01111     }
01112 
01113     this(in double* var, my_bool* pind=null)
01114     {
01115         _ptr    = var;
01116         _len    = (*var).sizeof;
01117         _type   = MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE;
01118         _pind   = pind;
01119         _plen   = null;
01120     }
01121 
01122   version(MYSQLPL_PREP_STMT) {
01123     this(SqlInt var)
01124     {
01125         _ptr    = var.get_ref();
01126         _len    = int.sizeof;
01127         _type   = MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG;
01128         _pind   = var.ind().get_ref();
01129         _plen   = null;
01130     }
01131 
01132     this(SqlInteger var)
01133     {
01134         _ptr    = var.get_ref();
01135         _len    = LONGLONG.sizeof;
01136         _type   = MYSQL_FIELD_TYPES.MYSQL_TYPE_LONGLONG;
01137         _pind   = var.ind().get_ref();
01138         _plen   = null;
01139     }
01140 
01141     this(in SqlString str)
01142     {
01143         _ptr    = str.c_str().ptr;
01144         _len    = str.len();
01145         _type   = MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING;
01146         _pind   = null;
01147         _plen   = null;
01148     }
01149 /*@@ SqlString as output buffer
01150     this(SqlString str)
01151     {
01152         _ptr    = str.str().ptr;
01153         _len    = str.blen();//alen();
01154         _type   = MYSQL_FIELD_TYPES.MYSQL_TYPE_VAR_STRING;
01155         _pind   = str.ind().get_ref();
01156         _plen   = str.get_len_ref();
01157     }
01158 */
01159     this(SqlDate date)
01160     {
01161         _ptr    = &date._value;
01162         _len    = MYSQL_TIME.sizeof;
01163         _type   = date.get_data_type();
01164         _pind   = date.ind().get_ref();
01165         _plen   = null;
01166     }
01167 
01168     this(SqlNumber num)
01169     {
01170         _ptr    = num.get_ref();
01171         _len    = double.sizeof;
01172         _type   = MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE;
01173         _pind   = num.ind().get_ref();
01174         _plen   = null;
01175     }
01176 
01177     this(MSqlBlob blob)
01178     {
01179         _ptr    = blob.get_ref();
01180         _len    = blob.get_len();
01181         _type   = MYSQL_FIELD_TYPES.MYSQL_TYPE_BLOB;
01182         _pind   = blob.ind().get_ref();
01183         _plen   = cast(uint*)blob.get_len_ref();
01184     }
01185   } // version(MYSQLPL_PREP_STMT)
01186 };
01187 
01188 
01189 class SqlQuery
01190 {
01191     this(in char[] sql)
01192     {
01193         _param_bind_vector = new BindVector;
01194 
01195         _sql = sql;
01196     }
01197 
01198     void where(in char[] cond)
01199     {
01200         if (!_cond.length)
01201             _cond ~= "\nwhere   ";
01202         else
01203             _cond ~= "\nand ";
01204 
01205         _cond ~= cond;
01206     }
01207 
01208     char[] get_sql()
01209     {
01210         return _sql ~ _cond;
01211     }
01212 
01213     void bind_param(BindPar par)
01214     {
01215         int idx = _param_bind_vector.length();
01216 
01217         _param_bind_vector.resize(idx+1);
01218 
01219         _param_bind_vector.bind(idx, par);
01220     }
01221 
01222     BindVector get_params()
01223     {
01224         return _param_bind_vector;
01225     }
01226 
01227 protected:
01228     char[]  _sql;
01229     char[]  _cond;
01230 
01231     BindVector  _param_bind_vector;
01232 };
01233 
01234 
01235  /// a MySQL SQL statement
01236 
01237 class SqlStatement
01238 {
01239     this(MSqlConnection conn)
01240     {
01241         _db = conn();
01242         _state = STATE.UNINITIALIZED;
01243     //  _res = null;
01244         _stmt_type = -1;
01245     //  _result = null;
01246         _param_bind_vector = new BindVector;
01247 
01248       version(MYSQLPL_PREP_STMT) {
01249         _stmt = mysqlpl_stmt_init(_db);
01250       }
01251     }
01252 
01253     this(MSqlConnection conn, in char[] sql)
01254     {
01255         _db = conn();
01256         _state = STATE.UNINITIALIZED;
01257     //  _res = null;
01258         _stmt_type = -1;
01259     //  _result = null;
01260         _param_bind_vector = new BindVector;
01261 
01262       version(MYSQLPL_PREP_STMT) {
01263         _stmt = mysqlpl_stmt_init(_db);
01264       }
01265 
01266         prepare(sql);
01267     }
01268 
01269     this(MSqlConnection conn, in SqlQuery query)
01270     {
01271         _db = conn();
01272         _state = STATE.UNINITIALIZED;
01273     //  _res = null;
01274         _stmt_type = -1;
01275     //  _result = null;
01276         _param_bind_vector = new BindVector;
01277 
01278       version(MYSQLPL_PREP_STMT) {
01279         _stmt = mysqlpl_stmt_init(_db);
01280       }
01281 
01282         execute(query);
01283     }
01284 
01285     ~this()
01286     {
01287       version(MYSQLPL_PREP_STMT) {
01288         if (_stmt)
01289             mysqlpl_stmt_close(_stmt);
01290 
01291         bindvector_free(_result_bind_vector);
01292         _result_bind_vector = null;
01293       } else {
01294         if (_result)
01295             mysqlpl_free_result(_result);
01296       }
01297     }
01298 
01299 
01300 protected:
01301 
01302     MYSQL*  _db;
01303 
01304   version(MYSQLPL_PREP_STMT) {
01305     MYSQL_STMT* _stmt;
01306 
01307     MYSQL_BIND* _result_bind_vector;
01308   } else {
01309     char[]  _sql;
01310 
01311      // create sql statement from prepared statement and integrate bind variables
01312     char[] create_bound_sql()
01313     {
01314         char[] str = _sql;
01315         char[] sql;
01316 
01317         foreach(BindPar value; _param_bind_vector) {
01318             int idx = next_bind_variable(str);
01319 
01320             if (idx == -1)
01321                 throw new MSqlException("too much bind values");
01322 
01323             sql ~= str[0 .. idx];
01324 
01325             switch(value._type) {
01326               case MYSQL_FIELD_TYPES.MYSQL_TYPE_VAR_STRING: {
01327                 sql ~= '\'';
01328 
01329                  // escape quote characters in bound string constants
01330                 char[] p = (cast(char*)value._ptr)[0 .. value._len];
01331 
01332                 foreach(c; p) {
01333                     if (c == '\'')
01334                         sql ~= "''";
01335                     else
01336                         sql ~= c;
01337                 }
01338 
01339                 sql ~= '\'';
01340                 break;}
01341 
01342               case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG:
01343                 sql ~= format("%d", *cast(int*)value._ptr);
01344                 break;
01345 
01346               case MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE:
01347                 sql ~= format("%f", *cast(double*)value._ptr);
01348                 break;
01349 
01350               default:
01351                 throw new MSqlException("unsupported datatype");
01352             }
01353 
01354             str = str[idx+1 .. length];
01355         }
01356 
01357         if (next_bind_variable(str) != -1)
01358             throw new MSqlException("too less bind values");
01359 
01360         sql ~= str;
01361 
01362         return sql;
01363     }
01364 
01365     static int next_bind_variable(in char[] p)
01366     {
01367         for(int i=0; i<p.length; ++i)
01368             if (p[i] == '?')
01369                 return i;
01370              // look for quotes and escape characters
01371             else if (p[i] == '\'') {
01372                 while(++i < p.length)
01373                     if (p[i]=='\'' && ++i<p.length-1 && p[i]!='\'')
01374                         break;
01375             }
01376 
01377         return -1;
01378     }
01379 
01380   }
01381 
01382     BindVector  _param_bind_vector;
01383 
01384     MYSQL_RES*  _result;
01385 
01386     enum STATE {
01387         UNINITIALIZED=0,
01388   //version(MYSQLPL_PREP_STMT) {
01389         PREPARED=1, RESULT_BOUND=2,
01390   //}
01391         EXECUTED=4, FETCHED=8,
01392         //EOF_DATA=16, STMT_ERROR=32
01393     };
01394     int _state;
01395 
01396     char[]  _last_sql;
01397 
01398     SqlResult _res;
01399 
01400     int _stmt_type;
01401 
01402 
01403 public:
01404 
01405     //bool eof() {return _state < EOF_DATA;}
01406 
01407 
01408      // Preparation of a SQL statements
01409 
01410     void prepare(in char[] sql)
01411     {
01412         delete _res;
01413         _res = null;
01414 
01415         _last_sql = sql;
01416 
01417       version(MYSQLPL_PREP_STMT) {
01418         int res = mysqlpl_stmt_prepare(_stmt, sql.ptr, sql.length);
01419         mysqlpl_check_error(_stmt, res);
01420 
01421         _state = STATE.PREPARED;
01422       } else {
01423         _sql = sql;
01424 
01425         if (_result)
01426             mysqlpl_free_result(_result);
01427       }
01428 
01429         _stmt_type = -1;
01430         _result = null;
01431     //  _result_bind_vector = null;
01432         _param_bind_vector.clear();
01433     }
01434 
01435 
01436     char[] get_last_sql()
01437     {
01438         return _last_sql;
01439     }
01440 
01441 
01442      // get number of processed rows
01443 
01444     my_ulonglong get_row_count()
01445     {
01446       version(MYSQLPL_PREP_STMT) {
01447         if (is_select()) {
01448             if (mysqlpl_stmt_store_result(_stmt))
01449                 throw new MSqlException(_stmt);
01450         }
01451 
01452         my_ulonglong res = mysqlpl_stmt_affected_rows(_stmt);   // for DML statements
01453     /*
01454         if (res == (my_ulonglong)-1)
01455             res = mysqlpl_stmt_num_rows(_stmt); // only for SELECT statements
01456     */
01457 
01458         if (res == cast(my_ulonglong)-1)
01459             throw new MSqlException(_stmt);
01460       } else {
01461         int res = mysqlpl_affected_rows(_db);
01462 
01463         if (res == -1)
01464             throw new MSqlException(_db);
01465       }
01466 
01467         return res;
01468     }
01469 
01470 
01471      // Binding of input and output variables
01472 
01473     void bind_param(int idx, BindPar par)
01474     {
01475         if (_param_bind_vector.length() <= idx)
01476             _param_bind_vector.resize(idx+1);
01477 
01478         _param_bind_vector.bind(idx, par);
01479     }
01480 
01481 
01482     void bind_param(int idx, in char[] str, my_bool* pind=null)
01483     {
01484         bind_param(idx, new BindPar(str, pind));
01485     }
01486 
01487     void bind_param(int idx, in int* var, my_bool* pind=null)
01488     {
01489         bind_param(idx, new BindPar(var, pind));
01490     }
01491 
01492     void bind_param(int idx, in double* var, my_bool* pind=null)
01493     {
01494         bind_param(idx, new BindPar(var, pind));
01495     }
01496 
01497   version(MYSQLPL_PREP_STMT) {
01498     void bind_param(int idx, SqlInt var)
01499     {
01500         bind_param(idx, new BindPar(var));
01501     }
01502 
01503     void bind_param(int idx, SqlInteger var)
01504     {
01505         bind_param(idx, new BindPar(var));
01506     }
01507 
01508     void bind_param(int idx, SqlString str)
01509     {
01510         bind_param(idx, new BindPar(str));
01511     }
01512 /*@@ SqlString as output buffer
01513     void bind_param(int idx, SqlString str)
01514     {
01515         bind_param(idx, new BindPar(str));
01516     }
01517 */
01518     void bind_param(int idx, SqlDate date)
01519     {
01520         bind_param(idx, new BindPar(date));
01521     }
01522 
01523     void bind_param(int idx, SqlNumber num)
01524     {
01525         bind_param(idx, new BindPar(num));
01526     }
01527 
01528     void bind_param(int idx, MSqlBlob blob)
01529     {
01530         bind_param(idx, new BindPar(blob));
01531     }
01532   } // version(MYSQLPL_PREP_STMT)
01533 
01534     void bind_params(in BindVector params)
01535     {
01536         _param_bind_vector = params;
01537     }
01538 
01539 
01540      // Definition of variables to receive query results
01541 
01542   version(MYSQLPL_PREP_STMT) {
01543 
01544     void bind_result_column(BindResultPar par, MYSQL_BIND* bind)
01545     {
01546         bindvector_bind(bind, par._ptr, par._type, par._len, par._pind, par._plen);
01547 
01548     /* ersetzt
01549         memset(&bind, 0, sizeof(bind));
01550 
01551         bind.buffer = par._ptr;
01552         bind.buffer_type = par._type;
01553         bind.buffer_length = par._len;
01554         bind.is_null = par._pind;
01555         bind.length = par._plen;
01556     */
01557     }
01558 
01559     void bind_result(MYSQL_BIND* bind_array)
01560     {
01561         my_bool res = mysqlpl_stmt_bind_result(_stmt, bind_array);
01562 
01563         mysqlpl_check_error(_stmt, res);
01564 
01565         if (_state & STATE.EXECUTED) {
01566             delete _res;
01567             _res = null;
01568 
01569             _state = (_state|STATE.RESULT_BOUND) & ~STATE.FETCHED;
01570         } else
01571             _state |= STATE.RESULT_BOUND;
01572     }
01573 
01574      // define all columns of a complete recordset
01575     void bind_result(ColumnDataVector columns)
01576     {
01577         MYSQL_BIND* p = _result_bind_vector;
01578 
01579         foreach(col; columns) {
01580             col._column.bind_result_column(this, p);
01581             p = bindvector_next(p);
01582         }
01583 
01584         bind_result(_result_bind_vector);
01585     }
01586 
01587   }
01588 
01589 
01590     void execute()
01591     {
01592       version(MYSQLPL_PREP_STMT) {
01593         if (!(_state & STATE.RESULT_BOUND)) {
01594              // a SELECT statement without ready define variables?
01595             if (is_select()) {  // a statement with result set? (=> SELECT)
01596                 _result_bind_vector = bindvector_resize(_result_bind_vector, get_column_count());
01597 
01598                  // define resultset variables
01599                 assert(!_res);
01600                 _res = new SqlResult(this);
01601             }
01602         }
01603 
01604         MYSQL_BIND* param_mbind_vector;
01605 
01606          // bind parameter values
01607         if (!_param_bind_vector.empty()) {
01608              // Umwandlung der Bindparamater von BindPar in MYSQL_BIND-Strukturelemente
01609             param_mbind_vector = bindvector_resize(param_mbind_vector, _param_bind_vector.length);
01610 
01611             MYSQL_BIND* o = param_mbind_vector;
01612             foreach(i; _param_bind_vector) {
01613                 mysqlpl_bind_param(i, o);
01614                 o = bindvector_next(o);
01615             }
01616 
01617             my_bool res = mysqlpl_stmt_bind_param(_stmt, param_mbind_vector);
01618 
01619             mysqlpl_check_error(_stmt, res);
01620         }
01621 
01622         int res = mysqlpl_stmt_execute(_stmt);
01623 
01624         mysqlpl_check_error(_stmt, res);
01625       } else {
01626         int res = mysqlpl_query(_db, toStringz(create_bound_sql()));
01627 
01628         mysqlpl_check_error(_db, res);
01629 
01630         if (_result)
01631             mysqlpl_free_result(_result);
01632 
01633         _result = mysqlpl_store_result(_db);
01634 
01635         if (_result) { // is_select()
01636              // define resultset variables
01637             if (_res)
01638                 delete _res;
01639 
01640             _res = new SqlResult(this);
01641         }
01642       }
01643 
01644         _state = (_state|STATE.EXECUTED) & ~STATE.FETCHED;
01645     }
01646 
01647     void execute(in char[] sql)
01648     {
01649         prepare(sql);
01650         execute();
01651     }
01652 
01653     void execute(in SqlQuery query)
01654     {
01655         prepare(query.get_sql());
01656         bind_params(query.get_params());
01657         execute();
01658     }
01659 
01660     bool execute_fetch()
01661     {
01662         execute();
01663 
01664         return fetch();
01665     }
01666 
01667     bool execute_fetch(in char[] sql)
01668     {
01669         prepare(sql);
01670 
01671         return execute_fetch();
01672     }
01673 
01674     bool fetch()
01675     {
01676         if (!(_state & STATE.EXECUTED))
01677             execute();
01678 
01679       version(MYSQLPL_PREP_STMT) {
01680         int res = mysqlpl_stmt_fetch(_stmt);
01681 
01682         if (res == MYSQL_NO_DATA)
01683             return false;
01684 
01685         mysqlpl_check_error(_stmt, res);
01686       } else {
01687         _res._row = mysqlpl_fetch_row(_result);
01688 
01689         if (!_res._row)
01690             return false;
01691       }
01692 
01693         _state |= STATE.FETCHED;
01694 
01695         return true;
01696     }
01697 
01698     MYSQL_RES* get_meta_res()
01699     {
01700       version(MYSQLPL_PREP_STMT) {
01701         if (!_result) {
01702             _result = mysqlpl_stmt_result_metadata(_stmt);
01703 
01704             if (!_result)
01705                 throw new MSqlException("no result set metadata");
01706         }
01707       }
01708 
01709         return _result;
01710     }
01711 
01712     bool is_select()
01713     {
01714   version(MYSQLPL_PREP_STMT) {
01715     if (!_result)
01716         _result = mysqlpl_stmt_result_metadata(_stmt);
01717 
01718     return _result!=null;
01719   } else {
01720     if (!(_state & STATE.EXECUTED))
01721         throw new MSqlException("statement not yet executed");
01722 
01723     return _result!=null;
01724   }
01725     }
01726 
01727     int get_column_count()
01728     {
01729       version(MYSQLPL_PREP_STMT) {
01730         uint count = mysqlpl_num_fields(get_meta_res());
01731 
01732         if (count == -1u)
01733             throw new MSqlException(_stmt);
01734 
01735         return count;
01736       } else {
01737         return mysqlpl_num_fields(_result);
01738       }
01739     }
01740 
01741     void get_column_type(int idx, out ColumnType info)
01742     {
01743         MYSQL_FIELD* field = mysqlpl_fetch_field_direct(get_meta_res(), idx);
01744 
01745         if (!field)
01746       version(MYSQLPL_PREP_STMT) {
01747             throw new MSqlException(_stmt);
01748       } else {
01749             throw new MSqlException(_db);
01750       }
01751 
01752         info.init(field);
01753     }
01754 
01755     void print_results(Stream o, bool header=true)
01756     {
01757         if (!(_state & STATE.EXECUTED))
01758             execute();
01759 
01760         if (header)
01761             _res.print_columns(o);
01762 
01763         int row_cnt = 0;
01764 
01765         while(fetch()) {
01766             ++row_cnt;
01767 
01768             o.writeString(format("row %d:\n", row_cnt));
01769 
01770             _res.print_values(o);
01771 
01772             o.write('\n');
01773         }
01774     }
01775 
01776     void print_results(in char[] sql, Stream o, bool header=true)
01777     {
01778         execute(sql);
01779 
01780         print_results(o, header);
01781     }
01782 
01783     SqlResult opCall()
01784     {
01785         if (!_res)
01786             fetch();
01787 
01788         return _res;
01789     }
01790 
01791   version(XMLSTORAGE) {//@@
01792     void dump_results(XMLStorage.XMLPos idx, in char[] element_name);
01793 
01794     void dump_results(in char[] sql, XMLStorage.XMLPos idx, in char[] element_name)
01795     {
01796         execute(sql);
01797 
01798         dump_results(idx, element_name);
01799     }
01800   }
01801 
01802 }; // SqlStatement
01803 
01804 
01805 version(MYSQLPL_PREP_STMT) {
01806 
01807  /// indicator variable
01808 
01809 class SqlInd
01810 {
01811     this(my_bool is_null=1)
01812     {
01813         _is_null = is_null;
01814     }
01815 
01816     this(SqlInd other)
01817     {
01818         _is_null = other._is_null;
01819     }
01820 
01821     my_bool opCast() {return _is_null;}
01822     my_bool* get_ref() {return &_is_null;}
01823 
01824     bool is_null() {return _is_null!=0;}
01825     bool is_not_null() {return _is_null==0;}
01826 
01827     void clear() {_is_null = 1;}
01828     void set() {_is_null = 0;}
01829 
01830 protected:
01831     my_bool _is_null;
01832 };
01833 
01834 
01835 class SqlValue
01836 {
01837     this()
01838     {
01839         _ind = new SqlInd();
01840     }
01841 
01842     this(in SqlValue other)
01843     {
01844         _ind = new SqlInd(other._ind);
01845     }
01846 
01847     bool is_null()
01848     {
01849         return _ind.is_null();
01850     }
01851 
01852     bool is_not_null()
01853     {
01854         return _ind.is_not_null();
01855     }
01856 
01857     SqlInd ind()
01858     {
01859         return _ind;
01860     }
01861 
01862 protected:
01863     SqlInd  _ind;
01864 };
01865 
01866 
01867  /// int with indicator variable
01868 
01869 class SqlInt : public SqlValue
01870 {
01871     this()  // null constructor
01872     {
01873     }
01874 
01875     this(int value)
01876     {
01877         _value = value;
01878         _ind.set();
01879     }
01880 
01881     this(in SqlInt other)
01882     {
01883         super(other);
01884         _value = other._value;
01885     }
01886 
01887     const int INT_NULL = -1;
01888 
01889     int opCast() {return _ind.is_null()? INT_NULL: _value;}
01890     int* get_ref() {return &_value;}
01891 
01892     char[] str()
01893     {
01894         if (_ind.is_null())
01895             return "";
01896 
01897         return format("%d", _value);
01898     }
01899 
01900 protected:
01901     int     _value;
01902 };
01903 
01904 
01905  /// 64 bit integer with indicator variable
01906 
01907 class SqlInteger : public SqlValue
01908 {
01909     this()  // null constructor
01910     {
01911     }
01912 
01913     this(int value)
01914     {
01915         _value = value;
01916 
01917         _ind.set();
01918     }
01919 
01920     this(in SqlInteger other)
01921     {
01922         super(other);
01923         _value = other._value;
01924     }
01925 
01926     const int INT_NULL = -1;
01927 
01928     LONGLONG opCast() {return _ind.is_null()? INT_NULL: _value;}
01929     LONGLONG* get_ref() {return &_value;}
01930 
01931     char[] str()
01932     {
01933         if (_ind.is_null())
01934             return "";
01935 
01936         return format("%d", _value);
01937     }
01938 
01939 protected:
01940     LONGLONG _value;
01941 };
01942 
01943 
01944 class SqlString : public SqlValue
01945 {
01946     this(int blen=2000)
01947     {
01948         _str.length = blen;
01949         _len = 0;
01950     }
01951 
01952     this(in char[] s, int blen=2000)
01953     {
01954         _str.length = blen;
01955 
01956         opAssign(s);
01957 
01958         _ind.set();
01959     }
01960 
01961     this(in SqlString other)
01962     {
01963         super(other);
01964 
01965         _str = other._str.dup;
01966         _len = other._len;
01967     }
01968 
01969     int len() {return is_null()? 0: _len;}
01970     int blen() {return _str.length;}
01971 //  int alen() {return _str.length + 1;}
01972 
01973     void resize(int l) {_str.length = l;}
01974     void clear() {_str.length = 0; _ind.clear();}
01975 
01976     char[] str() {return _str[0.._len];}    // Note: _ind is not checked by this function.
01977     char[] str(int l) {resize(l); return _str[0.._len];}    // Note: _ind is not changed by this function.
01978 
01979     char[] c_str() {return is_null()? "": _str[0.._len];}
01980 
01981     SqlString opAssign(in char[] s)
01982     {
01983         if (s) {
01984             _str[0 .. s.length] = s[];
01985             _len = s.length;
01986             _ind.set();
01987         } else {
01988             _len = 0;
01989             _ind.clear();
01990         }
01991 
01992         return this;
01993     }
01994 
01995     Stream writeString(Stream os)
01996     {
01997         if (is_not_null())
01998             os.writeString(_str);
01999             return os;
02000     }
02001 
02002 protected:
02003     char[]  _str;
02004     size_t  _len;
02005 };
02006 
02007 
02008 struct MYSQL_TIME
02009 {
02010   uint  year, month, day, hour, minute, second;
02011   uint  second_part;
02012   my_bool neg;
02013   MYSQL_TIMESTAMP_TYPE time_type;
02014 };
02015 
02016 
02017  /// wrapper for MYSQL_TIME
02018 
02019 class SqlDate : public SqlValue
02020 {
02021     this(MYSQL_TIMESTAMP_TYPE type=MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATETIME)
02022     {
02023         _value.time_type = type;
02024     }
02025 
02026     this(MYSQL_TIME time, MYSQL_TIMESTAMP_TYPE type=MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATETIME)
02027     {
02028         _value = time;
02029         _value.time_type = MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATETIME;
02030     }
02031 
02032     this(in char[] str, MYSQL_TIMESTAMP_TYPE type=MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATETIME)
02033     {
02034         while(str.length>0 && std.ctype.isspace(str[0]))
02035             str = str[1 .. length];
02036 
02037         char* s = toStringz(str);
02038 
02039         if (s && *s) {
02040             switch(_value.time_type) {
02041               case MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATE:
02042                 if (sscanf(s, "%04d-%02d-%02d",
02043                                 &_value.year, &_value.month, &_value.day) != 3)
02044                 if (sscanf(s, "%02d.%02d.%04d",
02045                                 &_value.day, &_value.month, &_value.year) != 3)
02046                     throw new MSqlException("date conversion error");
02047                 break;
02048 
02049               case MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_TIME:
02050                 _value.second_part = 0;
02051                 if (sscanf(s, "%02d:%02d:%02d.%06d",
02052                                 &_value.hour, &_value.minute, &_value.second, &_value.second_part) < 3)
02053                     throw new MSqlException("time conversion error");
02054                 break;
02055 
02056               //case MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATETIME:
02057               default:
02058                 _value.hour = 0;
02059                 _value.minute = 0;
02060                 _value.second = 0;
02061                 _value.second_part = 0;
02062                 if (sscanf(s, "%04d-%02d-%02d %02d:%02d:%02d.%06d",
02063                                 &_value.year, &_value.month, &_value.day, &_value.hour, &_value.minute, &_value.second, &_value.second_part) < 6)
02064                 if (sscanf(s, "%02d.%02d.%04d %02d:%02d:%02d.%06d",
02065                                 &_value.day, &_value.month, &_value.year, &_value.hour, &_value.minute, &_value.second, &_value.second_part) < 3)
02066                     throw new MSqlException("datetime conversion error");
02067             }
02068 
02069             _value.time_type = type;
02070 
02071             _ind.set();
02072         } else
02073             _ind.clear();
02074     }
02075 
02076     this(in SqlDate other, MYSQL_TIMESTAMP_TYPE type)
02077     {
02078         _value = other._value;
02079 
02080         if (other._value.time_type != type) {
02081             if (type==MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_NONE || type==MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_ERROR)
02082                 _value.time_type = type;
02083             else {
02084                 if (other._value.time_type == MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATE) {
02085                     if (type == MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_TIME)
02086                         throw new MSqlException("no conversion from time to date");
02087 
02088                     _value.hour = 0;
02089                     _value.minute = 0;
02090                     _value.second = 0;
02091                 } else if (other._value.time_type == MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_TIME) {
02092                     if (type == MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATE)
02093                         throw new MSqlException("no conversion from date to time");
02094 
02095                     _value.year = 0;
02096                     _value.month = 0;
02097                     _value.day = 0;
02098                 }
02099 
02100                 _value.time_type = type;
02101             }
02102         }
02103     }
02104 
02105     MYSQL_FIELD_TYPES get_data_type()
02106     {
02107         switch(_value.time_type) {
02108           case MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATE:
02109             return MYSQL_FIELD_TYPES.MYSQL_TYPE_DATE;
02110 
02111           case MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_TIME:
02112             return MYSQL_FIELD_TYPES.MYSQL_TYPE_TIME;
02113 
02114           case MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATETIME:
02115             return MYSQL_FIELD_TYPES.MYSQL_TYPE_DATETIME;
02116 
02117           default:
02118             return cast(MYSQL_FIELD_TYPES)-1;
02119         }
02120     }
02121 
02122     char[] str()
02123     {
02124         if (_ind.is_not_null()) {
02125             switch(_value.time_type) {
02126               case MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATE:
02127                 return format("%04d-%02d-%02d",
02128                                 _value.year, _value.month, _value.day);
02129                 break;
02130 
02131               case MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_TIME:
02132                 return format("%02d:%02d:%02d.%06d",
02133                                 _value.hour, _value.minute, _value.second, _value.second_part);
02134                 break;
02135 
02136               //case MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATETIME:
02137               default:
02138                 return format("%04d-%02d-%02d %02d:%02d:%02d.%06d",
02139                                 _value.year, _value.month, _value.day,
02140                                 _value.hour, _value.minute, _value.second, _value.second_part);
02141             }
02142         } else
02143             return "";
02144     }
02145 
02146     MYSQL_TIME opCast() {return _value;}
02147 
02148     MYSQL_TIME  _value;
02149 };
02150 
02151 
02152 class SqlNumber : public SqlValue
02153 {
02154     this()
02155     {
02156     }
02157 
02158     this(int i)
02159     {
02160         _value = i;
02161         _ind.set();
02162     }
02163 
02164     this(LONGLONG l)
02165     {
02166         _value = l;
02167         _ind.set();
02168     }
02169 
02170     this(double d)
02171     {
02172         _value = d;
02173         _ind.set();
02174     }
02175 
02176     this(in char[] s)
02177     {
02178         if (sscanf(toStringz(s), "%lf", &_value) == 1)  // %lf -> double
02179             _ind.set();
02180     }
02181 
02182 //@@    void* get_ref() {return &_value;}
02183 
02184     char[] str()
02185     {
02186         if (_ind.is_null())
02187             return "";
02188 
02189         return format("%f", _value);    // %f -> double
02190     }
02191 
02192     double opCast() {return _value;}
02193     double* get_ref() {return &_value;}
02194 
02195     int get_int()
02196     {
02197         return _ind.is_not_null()? cast(int)(_value+.5): 0;
02198     }
02199 
02200     long get_int64()
02201     {
02202         return _ind.is_not_null()? cast(long)(_value+.5): 0;
02203     }
02204 
02205     double get_double()
02206     {
02207         return _ind.is_not_null()? _value: 0.;
02208     }
02209 
02210 protected:
02211     double  _value;
02212 };
02213 
02214 
02215 class MSqlBlob : public SqlValue
02216 {
02217     this(int len=0x10000)
02218     {
02219         _len = len;
02220         _ptr = null;
02221         _own = true;
02222     }
02223 
02224     this(void* ptr, int len)
02225     {
02226         _len = len;
02227         _ptr = ptr;
02228         _own = false;
02229     }
02230 
02231     this(in MSqlBlob other)
02232     {
02233         super(other);
02234 
02235         _len = other._len;
02236         _own = true;
02237 
02238         if (other._ptr)
02239             memcpy(_ptr=std.c.stdlib.malloc(other._len), other._ptr, other._len);
02240         else
02241             _ptr = null;
02242     }
02243 
02244     ~this()
02245     {
02246         if (_own)
02247             std.c.stdlib.free(_ptr);
02248     }
02249 
02250     void* get_ref()
02251     {
02252         if (_own && !_ptr)  // delayed buffer allocation
02253             _ptr = std.c.stdlib.malloc(_len);
02254 
02255         return _ptr;
02256     }
02257 
02258     int     get_len() {return _len;}
02259     ulong*  get_len_ref() {return &_len;}
02260 
02261     char[]  str()
02262     {
02263         if (_ind.is_not_null()) {
02264             return (cast(char*)_ptr)[0 .. _len];
02265         } else
02266             return "";
02267     }
02268 
02269 protected:
02270     ulong   _len;
02271     void*   _ptr;
02272     bool    _own;
02273 };
02274 
02275 
02276  /// factory for call parameters for MySQL define functions
02277 
02278 class BindResultPar
02279 {
02280     void*       _ptr;
02281     int         _len;
02282     MYSQL_FIELD_TYPES _type;
02283     my_bool*    _pind;
02284     uint*       _plen;
02285 
02286     this(SqlInt var)
02287     {
02288         _ptr    = var.get_ref();
02289         _len    = int.sizeof;
02290         _type   = MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG;
02291         _pind   = var.ind().get_ref();
02292         _plen   = null;
02293     }
02294 
02295     this(SqlInteger var)
02296     {
02297         _ptr    = var.get_ref();
02298         _len    = LONGLONG.sizeof;
02299         _type   = MYSQL_FIELD_TYPES.MYSQL_TYPE_LONGLONG;
02300         _pind   = var.ind().get_ref();
02301         _plen   = null;
02302     }
02303 
02304     this(int* var, my_bool* pind=null)
02305     {
02306         _ptr    = var;
02307         _len    = int.sizeof;
02308         _type   = MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG;
02309         _pind   = pind;
02310         _plen   = null;
02311     }
02312 
02313     this(in char[] buffer, int len, MYSQL_FIELD_TYPES type=MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING/*MYSQL_TYPE_VAR_STRING*/, my_bool* pind=null)
02314     {
02315         _ptr    = buffer.ptr;
02316         _len    = len;
02317         _type   = type;
02318         _pind   = pind;
02319         _plen   = null;
02320     }
02321 
02322     this(SqlString str)
02323     {
02324         _ptr    = str.str().ptr;
02325         _len    = str.blen();//alen();
02326         _type   = MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING;
02327         _pind   = str.ind().get_ref();
02328         _plen   = &str._len;
02329     }
02330 
02331     this(SqlNumber num)
02332     {
02333         _ptr    = num.get_ref();
02334         _len    = double.sizeof;
02335         _type   = MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE;
02336         _pind   = num.ind().get_ref();
02337         _plen   = null;
02338     }
02339 
02340   version(MYSQLPL_PREP_STMT) {
02341     this(SqlDate date)
02342     {
02343         _ptr    = &date._value;
02344         _len    = date._value.sizeof;
02345         _type   = date.get_data_type();
02346         _pind   = date.ind().get_ref();
02347         _plen   = null;
02348     }
02349   }
02350 
02351     this(MSqlBlob blob)
02352     {
02353         _ptr    = blob.get_ref();
02354         _len    = blob.get_len();
02355         _type   = MYSQL_FIELD_TYPES.MYSQL_TYPE_BLOB;
02356         _pind   = blob.ind().get_ref();
02357         _plen   = cast(uint*)blob.get_len_ref();
02358     }
02359 };
02360 
02361 
02362 class SqlVariant
02363 {
02364     this()
02365     {
02366         _data_type = cast(MYSQL_FIELD_TYPES)-1;
02367     }
02368 
02369     this(MYSQL_FIELD_TYPES data_type)
02370     {
02371         _data_type = data_type;
02372 
02373         switch(data_type) {
02374           case MYSQL_FIELD_TYPES.MYSQL_TYPE_VAR_STRING:
02375             _data_type = MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING;
02376             // fall through
02377 
02378           case MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING:
02379             _string = new SqlString;
02380             break;
02381 
02382           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TINY:
02383           case MYSQL_FIELD_TYPES.MYSQL_TYPE_SHORT:
02384           case MYSQL_FIELD_TYPES.MYSQL_TYPE_INT24:
02385           case MYSQL_FIELD_TYPES.MYSQL_TYPE_YEAR:
02386           case MYSQL_FIELD_TYPES.MYSQL_TYPE_ENUM:
02387             _data_type = MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG;
02388             // fall through
02389           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG:
02390             _int = new SqlInt;
02391             break;
02392 
02393           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONGLONG:
02394             _integer = new SqlInteger;
02395             break;
02396 
02397           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DECIMAL:
02398           case MYSQL_FIELD_TYPES.MYSQL_TYPE_NEWDECIMAL: // MYSQL_VERSION_ID>=50000
02399           case MYSQL_FIELD_TYPES.MYSQL_TYPE_FLOAT:
02400             _data_type = MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE;
02401             // fall through
02402 
02403           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE:
02404             _number = new SqlNumber;
02405             break;
02406 
02407           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATE:
02408             _date = new SqlDate(MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATE);
02409             break;
02410 
02411           case MYSQL_FIELD_TYPES.MYSQL_TYPE_NEWDATE:    // MYSQL_VERSION_ID>=50000
02412             _date = new SqlDate(MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATE);
02413             break;
02414 
02415           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATETIME:
02416             _date = new SqlDate(MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATETIME);
02417             break;
02418 
02419           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TIMESTAMP:
02420             _date = new SqlDate(MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_TIME);
02421             break;
02422 
02423           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TINY_BLOB:
02424           case MYSQL_FIELD_TYPES.MYSQL_TYPE_MEDIUM_BLOB:
02425           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG_BLOB:
02426             _data_type = MYSQL_FIELD_TYPES.MYSQL_TYPE_BLOB;
02427 
02428             // fall through
02429           case MYSQL_FIELD_TYPES.MYSQL_TYPE_BLOB:
02430             _blob = new MSqlBlob;
02431             break;
02432 
02433           default:
02434             throw new MSqlException("unsupported datatype");
02435         }
02436     }
02437 
02438     this(in SqlVariant other)
02439     {
02440         _data_type = cast(MYSQL_FIELD_TYPES)-1;
02441 
02442         assign(other);
02443     }
02444 
02445     ~this()
02446     {
02447         clear();
02448     }
02449 
02450     this(in SqlString x)
02451     {
02452         _string = new SqlString(x);
02453         _data_type = MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING;
02454     }
02455 
02456     this(in char[] x)
02457     {
02458         _string = new SqlString(x);
02459         _data_type = MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING;
02460     }
02461 
02462     this(in SqlInt x)
02463     {
02464         _int = new SqlInt(x);
02465         _data_type = MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG;
02466     }
02467 
02468     this(in SqlInteger x)
02469     {
02470         _integer = new SqlInteger(x);
02471         _data_type = MYSQL_FIELD_TYPES.MYSQL_TYPE_LONGLONG;
02472     }
02473 
02474     this(in SqlNumber x)
02475     {
02476         _number = new SqlNumber(cast(double)x);
02477         _data_type = MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE;
02478     }
02479 
02480   version(MYSQLPL_PREP_STMT) {
02481     this(in SqlDate x)
02482     {
02483         _date = new SqlDate(cast(MYSQL_TIME)x);
02484         _data_type = x.get_data_type();
02485     }
02486   }
02487 
02488     void clear()
02489     {
02490         switch(_data_type) {
02491           case cast(MYSQL_FIELD_TYPES)-1:
02492             break;
02493 
02494           case MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING:
02495             delete _string;
02496             break;
02497 
02498           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG:
02499             delete _int;
02500             break;
02501 
02502           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONGLONG:
02503             delete _integer;
02504             break;
02505 
02506           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE:
02507             delete _number;
02508             break;
02509 
02510           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATE:
02511           case MYSQL_FIELD_TYPES.MYSQL_TYPE_NEWDATE:    // MYSQL_VERSION_ID>=50000
02512           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATETIME:
02513           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TIME:
02514           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TIMESTAMP:
02515             delete _date;
02516             break;
02517 
02518           case MYSQL_FIELD_TYPES.MYSQL_TYPE_BLOB:
02519             delete _blob;
02520             break;
02521 
02522           default:
02523             assert(0);
02524         }
02525 
02526         _data_type = cast(MYSQL_FIELD_TYPES)-1;
02527     }
02528 
02529     void assign(in SqlVariant other)
02530     {
02531         clear();
02532 
02533         _data_type = other._data_type;
02534 
02535         switch(other._data_type) {
02536           case cast(MYSQL_FIELD_TYPES)-1:
02537             break;
02538 
02539           case MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING:
02540             _string = new SqlString(other._string);
02541             break;
02542 
02543           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG:
02544             _int = new SqlInt(other._int);
02545             break;
02546 
02547           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONGLONG:
02548             _integer = new SqlInteger(other._integer);
02549             break;
02550 
02551           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE:
02552             _number = new SqlNumber(cast(double)other._number);
02553             break;
02554 
02555           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATE:
02556           case MYSQL_FIELD_TYPES.MYSQL_TYPE_NEWDATE:    // MYSQL_VERSION_ID>=50000
02557           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATETIME:
02558           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TIME:
02559           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TIMESTAMP:
02560             _date = new SqlDate(other._date._value);
02561             break;
02562 
02563           case MYSQL_FIELD_TYPES.MYSQL_TYPE_BLOB:
02564             _blob = new MSqlBlob(other._blob);
02565             break;
02566 
02567           default:
02568             assert(0);
02569         }
02570     }
02571 
02572     int get_data_type()
02573     {
02574         return _data_type;
02575     }
02576 
02577     char[] str()
02578     {
02579         switch(_data_type) {
02580           case cast(MYSQL_FIELD_TYPES)-1:
02581             return "";
02582 
02583           case MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING:
02584             return _string.c_str();
02585     //      return *_string;
02586 
02587           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG:
02588             return _int.str();
02589 
02590           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONGLONG:
02591             return _integer.str();
02592 
02593           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE:
02594             return _number.str();
02595 
02596           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATE:
02597           case MYSQL_FIELD_TYPES.MYSQL_TYPE_NEWDATE:    // MYSQL_VERSION_ID>=50000
02598           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATETIME:
02599           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TIME:
02600           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TIMESTAMP:
02601             return _date.str();
02602 
02603           case MYSQL_FIELD_TYPES.MYSQL_TYPE_BLOB:
02604             return _blob.str();
02605             break;
02606 
02607           default:
02608             assert(0);
02609             return "";
02610         }
02611     }
02612 
02613     int get_int()
02614     {
02615         switch(_data_type) {
02616           case cast(MYSQL_FIELD_TYPES)-1:
02617             return 0;
02618 
02619           case MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING:
02620             return std.c.stdlib.atoi(toStringz(_string.str()));
02621 
02622           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG:
02623             return cast(int)_int;
02624 
02625           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONGLONG:
02626             return cast(LONGLONG)_integer;
02627 
02628           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE:
02629             return _number.get_int();
02630 
02631         //case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATETIME:
02632         //  return ...
02633 
02634           default:
02635             throw new MSqlException("no conversion to int");
02636         }
02637     }
02638 
02639     long get_int64()
02640     {
02641         switch(_data_type) {
02642           case cast(MYSQL_FIELD_TYPES)-1:
02643             return 0;
02644 
02645           case MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING:
02646             return std.c.stdlib.atoll(toStringz(_string.str()));
02647 
02648           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG:
02649             return cast(int)_int;
02650 
02651           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONGLONG:
02652             return cast(LONGLONG)_integer;
02653 
02654           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE:
02655             return _number.get_int64();
02656 
02657         //case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATETIME:
02658         //  return ...
02659 
02660           default:
02661             throw new MSqlException("no conversion to int64");
02662         }
02663     }
02664 
02665     double get_double()
02666     {
02667         switch(_data_type) {
02668           case cast(MYSQL_FIELD_TYPES)-1:
02669             return 0;
02670 
02671           case MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING:
02672             return std.c.stdlib.atof(toStringz(_string.str()));
02673 
02674           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG:
02675             return cast(int)_int;
02676 
02677           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONGLONG:
02678             return cast(LONGLONG)_integer;
02679 
02680           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE:
02681             return _number.get_double();
02682 
02683         //case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATETIME:
02684         //  return ...
02685 
02686           default:
02687             throw new MSqlException("no conversion to double");
02688         }
02689     }
02690 
02691     SqlNumber number()
02692     {
02693         switch(_data_type) {
02694           case cast(MYSQL_FIELD_TYPES)-1:
02695             return new SqlNumber();
02696 
02697           case MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING:
02698             return new SqlNumber(_string.str());
02699 
02700           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG:
02701             return new SqlNumber(cast(int)_int);
02702 
02703           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONGLONG:
02704             return new SqlNumber(cast(LONGLONG)_integer);
02705 
02706           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE:
02707             return _number;
02708 
02709         //case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATETIME:
02710         //  return ...
02711 
02712           default:
02713             throw new MSqlException("no conversion to number");
02714         }
02715     }
02716 
02717     bool is_null()
02718     {
02719         switch(_data_type) {
02720           case cast(MYSQL_FIELD_TYPES)-1:
02721             return true;
02722 
02723           case MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING:
02724             return _string.is_null();
02725 
02726           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG:
02727             return _int.is_null();
02728 
02729           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONGLONG:
02730             return _integer.is_null();
02731 
02732           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE:
02733             return _number.is_null();
02734 
02735           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATE:
02736           case MYSQL_FIELD_TYPES.MYSQL_TYPE_NEWDATE:    // MYSQL_VERSION_ID>=50000
02737           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATETIME:
02738           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TIME:
02739           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TIMESTAMP:
02740             return _date.is_null();
02741 
02742           case MYSQL_FIELD_TYPES.MYSQL_TYPE_BLOB:
02743             return _blob.is_null();
02744 
02745           default:
02746             assert(0);
02747             return true;
02748         }
02749     }
02750 
02751     bool is_not_null()
02752     {
02753         return !is_null();
02754     }
02755 
02756   version(MYSQLPL_PREP_STMT) {
02757     void bind_result_column(SqlStatement stmt, MYSQL_BIND* bind)
02758     {
02759         switch(_data_type) {
02760           case MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING:
02761             stmt.bind_result_column(new BindResultPar(_string), bind);
02762             break;
02763 
02764           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONG:
02765             stmt.bind_result_column(new BindResultPar(_int), bind);
02766             break;
02767 
02768           case MYSQL_FIELD_TYPES.MYSQL_TYPE_LONGLONG:
02769             stmt.bind_result_column(new BindResultPar(_integer), bind);
02770             break;
02771 
02772           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE:
02773             stmt.bind_result_column(new BindResultPar(_number), bind);
02774             break;
02775 
02776           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATE:
02777           case MYSQL_FIELD_TYPES.MYSQL_TYPE_NEWDATE:    // MYSQL_VERSION_ID>=50000
02778           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATETIME:
02779           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TIME:
02780           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TIMESTAMP:
02781             stmt.bind_result_column(new BindResultPar(_date), bind);
02782             break;
02783 
02784           case MYSQL_FIELD_TYPES.MYSQL_TYPE_BLOB:
02785             stmt.bind_result_column(new BindResultPar(_blob), bind);
02786             break;
02787 
02788           default:
02789             assert(0);
02790         }
02791     }
02792   }
02793 
02794   version(MYSQLPL_PREP_STMT) {
02795     SqlDate date(MYSQL_TIMESTAMP_TYPE type=MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATE)
02796     {
02797         switch(_data_type) {
02798           case cast(MYSQL_FIELD_TYPES)-1:
02799             return new SqlDate();
02800 
02801           case MYSQL_FIELD_TYPES.MYSQL_TYPE_STRING:
02802             return new SqlDate(_string.str(), MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATE);
02803 
02804           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATE:
02805           case MYSQL_FIELD_TYPES.MYSQL_TYPE_NEWDATE:    // MYSQL_VERSION_ID>=50000
02806           case MYSQL_FIELD_TYPES.MYSQL_TYPE_DATETIME:
02807           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TIME:
02808           case MYSQL_FIELD_TYPES.MYSQL_TYPE_TIMESTAMP:
02809             return new SqlDate(_date, type);
02810 
02811           default:
02812             throw new MSqlException("no conversion to date type");
02813         }
02814     }
02815 
02816     SqlDate datetime()
02817     {
02818         return date(MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_DATETIME);
02819     }
02820 
02821     SqlDate time()
02822     {
02823         return date(MYSQL_TIMESTAMP_TYPE.MYSQL_TIMESTAMP_TIME);
02824     }
02825   }
02826 
02827 protected:
02828     union {
02829         SqlString   _string;
02830         SqlInt      _int;
02831         SqlInteger  _integer;
02832         SqlNumber   _number;
02833       version(MYSQLPL_PREP_STMT) {
02834         SqlDate     _date;
02835       }
02836         MSqlBlob    _blob;
02837     };
02838 
02839     MYSQL_FIELD_TYPES _data_type;
02840 };
02841 
02842 }

Generated on Fri Jan 31 2014 00:12:25 for MySQLPL/D by  doxygen 1.7.2