00001 module mysqlpl;
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
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;
00050
00051
00052
00053
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 {
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,
00085 MYSQL_TYPE_VARCHAR,
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;
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;
00121
00122
00123
00124
00125 MYSQL* mysqlpl_init(MYSQL*);
00126 MYSQL_FIELD* mysqlpl_next_field(MYSQL_FIELD*);
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 }
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 }
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
00274
00275 class MSqlException : public Exception
00276 {
00277 this(MYSQL* db)
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
00294
00295 }
00296
00297 version(MYSQLPL_PREP_STMT) {
00298 this(MYSQL_STMT* s)
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
00315
00316 }
00317
00318 this(MYSQL_STMT* s, SqlStatement stmt)
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
00337
00338 }
00339
00340 }
00341
00342 this(in char[] msg)
00343 {
00344 super(msg);
00345
00346
00347
00348 }
00349
00350 uint _sql_error_code;
00351
00352 version(MYSQLPL_PREP_STMT) {
00353 char[] _sqlstate;
00354 }
00355
00356 char[] _last_sql;
00357
00358
00359 };
00360
00361
00362
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 }
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
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
00471 my_bool res = mysqlpl_autocommit(_db, 0);
00472 mysqlpl_check_error(_env(), res);
00473 } else {
00474 (new SqlStatement(this)).execute("set autocommit=0");
00475 }
00476 }
00477
00478 ~this()
00479 {
00480
00481
00482
00483
00484 }
00485
00486
00487 version(MYSQLPL_PREP_STMT) {
00488
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 {
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
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
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:
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:
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
00708 _table_name = table[0 .. strlen(table)];
00709 _name = name[0 .. strlen(name)];
00710
00711
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
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
00753
00754
00755
00756
00757
00758
00759
00760
00761 }
00762
00763 }
00764
00765
00766 alias vector!(ColumnData) ColumnDataVector;
00767
00768
00769
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
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
00858
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
00869
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;
00885
00886 int* find_column(in char[] col_name)
00887 {
00888
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
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) {
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 {
00994
00995
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) {
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 }
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
01150
01151
01152
01153
01154
01155
01156
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 }
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
01236
01237 class SqlStatement
01238 {
01239 this(MSqlConnection conn)
01240 {
01241 _db = conn();
01242 _state = STATE.UNINITIALIZED;
01243
01244 _stmt_type = -1;
01245
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
01258 _stmt_type = -1;
01259
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
01274 _stmt_type = -1;
01275
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
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
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
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
01389 PREPARED=1, RESULT_BOUND=2,
01390
01391 EXECUTED=4, FETCHED=8,
01392
01393 };
01394 int _state;
01395
01396 char[] _last_sql;
01397
01398 SqlResult _res;
01399
01400 int _stmt_type;
01401
01402
01403 public:
01404
01405
01406
01407
01408
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
01432 _param_bind_vector.clear();
01433 }
01434
01435
01436 char[] get_last_sql()
01437 {
01438 return _last_sql;
01439 }
01440
01441
01442
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);
01453
01454
01455
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
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
01513
01514
01515
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 }
01533
01534 void bind_params(in BindVector params)
01535 {
01536 _param_bind_vector = params;
01537 }
01538
01539
01540
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
01549
01550
01551
01552
01553
01554
01555
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
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
01595 if (is_select()) {
01596 _result_bind_vector = bindvector_resize(_result_bind_vector, get_column_count());
01597
01598
01599 assert(!_res);
01600 _res = new SqlResult(this);
01601 }
01602 }
01603
01604 MYSQL_BIND* param_mbind_vector;
01605
01606
01607 if (!_param_bind_vector.empty()) {
01608
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) {
01636
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 };
01803
01804
01805 version(MYSQLPL_PREP_STMT) {
01806
01807
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
01868
01869 class SqlInt : public SqlValue
01870 {
01871 this()
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
01906
01907 class SqlInteger : public SqlValue
01908 {
01909 this()
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
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];}
01977 char[] str(int l) {resize(l); return _str[0.._len];}
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
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
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
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)
02179 _ind.set();
02180 }
02181
02182
02183
02184 char[] str()
02185 {
02186 if (_ind.is_null())
02187 return "";
02188
02189 return format("%f", _value);
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)
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
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, 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();
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
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
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:
02399 case MYSQL_FIELD_TYPES.MYSQL_TYPE_FLOAT:
02400 _data_type = MYSQL_FIELD_TYPES.MYSQL_TYPE_DOUBLE;
02401
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:
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
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:
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:
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
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:
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
02632
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
02658
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
02684
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
02710
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:
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:
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:
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 }