00001
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 #include "dbmysql/mysqlsrv.h"
00029 #include "base/vector.hpp"
00030 #include "base/list.hpp"
00031 #include "base/string.hpp"
00032 #include "base/memory.hpp"
00033 #include "base/common.hpp"
00034 #include "base/numeric.h"
00035
00036 BEGIN_TERIMBER_NAMESPACE
00037 #pragma pack(4)
00038
00039 #define check_retcode_db(x) \
00040 if (!(x)) \
00041 { \
00042 throw exception(mysql_errno(_desc), mysql_error(_desc)); \
00043 }
00044
00045 #define check_retcode(x) \
00046 if (!(x)) \
00047 { \
00048 throw exception(mysql_stmt_errno(_stmt), mysql_stmt_error(_stmt)); \
00049 }
00050
00051 static const char* valid_delimeters = " ,)}";
00052
00053 mysql_dbserver::mysql_dbserver(size_t ident) : dbserver_impl(ident),
00054 _desc(0), _stmt(0)
00055 {
00056 }
00057
00058 mysql_dbserver::~mysql_dbserver()
00059 {
00060 if (_is_open_sql())
00061 close_sql();
00062
00063 if (_is_connect())
00064 disconnect();
00065 }
00066
00067
00068 void
00069 mysql_dbserver::v_connect(bool trusted_connection, const char* connection_string)
00070 {
00071
00072
00073
00074 string_t user, password, host, database;
00075 unsigned short port = 0;
00076 parse_connection_string(connection_string, user, password, host, port, database);
00077
00078
00079
00080
00081
00082
00083 if (!(_desc = mysql_init(0)))
00084 throw exception(0, "can't init mysql");
00085
00086
00087 MYSQL* dummy = 0;
00088 check_retcode_db((dummy = mysql_real_connect(_desc, host,
00089 user,
00090 password,
00091 0,
00092 port,
00093 0,
00094 CLIENT_MULTI_RESULTS)) != 0)
00095
00096
00097 if (database.length())
00098 check_retcode_db(mysql_select_db(_desc, database) == 0)
00099
00100 }
00101
00102 void
00103 mysql_dbserver::v_disconnect()
00104 {
00105 _temp_allocator->clear_extra();
00106
00107 v_close();
00108
00109 if (_desc)
00110 {
00111 mysql_close(_desc);
00112 _desc = 0;
00113
00114 }
00115 }
00116
00117 void
00118 mysql_dbserver::v_start_transaction()
00119 {
00120
00121 check_retcode_db(mysql_autocommit(_desc, false) == 0)
00122 }
00123
00124 void
00125 mysql_dbserver::v_commit()
00126 {
00127
00128 check_retcode_db(mysql_commit(_desc) == 0)
00129 }
00130
00131 void
00132 mysql_dbserver::v_rollback()
00133 {
00134
00135 check_retcode_db(mysql_rollback(_desc) == 0)
00136 }
00137
00138 bool
00139 mysql_dbserver::v_is_connect_alive()
00140 {
00141
00142 if (!_is_connect())
00143 return false;
00144
00145 return true;
00146 }
00147
00149 void
00150 mysql_dbserver::v_before_execute()
00151 {
00152 check_retcode_db((_stmt = mysql_stmt_init(_desc)) != 0)
00153
00154 switch (get_action())
00155 {
00156 case ACTION_EXEC_SQL:
00157 case ACTION_EXEC_SQL_ASYNC:
00158 case ACTION_EXEC_PROC:
00159 case ACTION_EXEC_PROC_ASYNC:
00160 break;
00161 case ACTION_OPEN_SQL:
00162 case ACTION_OPEN_SQL_ASYNC:
00163 case ACTION_OPEN_PROC:
00164 case ACTION_OPEN_PROC_ASYNC:
00165 {
00166 const unsigned long type = CURSOR_TYPE_READ_ONLY;
00167 check_retcode(mysql_stmt_attr_set(_stmt, STMT_ATTR_CURSOR_TYPE, &type) == 0);
00168 }
00169 break;
00170 default:
00171 break;
00172 }
00173
00174 check_retcode(mysql_stmt_prepare(_stmt, (const char*)_sql, (unsigned long)_sql.length()) == 0)
00175 }
00176
00177 void
00178 mysql_dbserver::v_after_execute()
00179 {
00180 switch (get_action())
00181 {
00182 case ACTION_EXEC_SQL:
00183 case ACTION_EXEC_SQL_ASYNC:
00184 case ACTION_EXEC_PROC:
00185 case ACTION_EXEC_PROC_ASYNC:
00186 {
00187 size_t maxRes = 1024;
00188 while (mysql_more_results(_desc) && maxRes-- > 0);
00189 }
00190 break;
00191 case ACTION_OPEN_SQL:
00192 case ACTION_OPEN_SQL_ASYNC:
00193 case ACTION_OPEN_PROC:
00194 case ACTION_OPEN_PROC_ASYNC:
00195 mysql_next_result(_desc);
00196 break;
00197 default:
00198 break;
00199 }
00200 }
00201
00202
00203 void
00204 mysql_dbserver::v_execute()
00205 {
00206 switch (get_action())
00207 {
00208 case ACTION_EXEC_PROC:
00209 case ACTION_EXEC_PROC_ASYNC:
00210 case ACTION_EXEC_SQL:
00211 case ACTION_EXEC_SQL_ASYNC:
00212 break;
00213 default:
00214 break;
00215 }
00216
00217 check_retcode(mysql_stmt_execute(_stmt) == 0)
00218 }
00219
00220
00221 void
00222 mysql_dbserver::v_close()
00223 {
00224 if (_stmt)
00225 {
00226 mysql_stmt_free_result(_stmt);
00227 mysql_stmt_close(_stmt);
00228 _stmt = 0;
00229 }
00230
00231
00232
00233 _param_binders.clear();
00234 _column_binders.clear();
00235 }
00236
00237
00238 void
00239 mysql_dbserver::v_fetch()
00240 {
00241
00242 if (_start_row != 0)
00243 {
00244 v_execute();
00245 size_t skip_rows = 0;
00246 while (skip_rows++ < _start_row && mysql_stmt_fetch(_stmt));
00247 }
00248
00249
00250 size_t col_count = _cols.size();
00251 size_t select_row = 0;
00252
00253 int x = 0;
00254
00255 while (_requested_rows
00256 && (x = mysql_stmt_fetch(_stmt)) == 0
00257 )
00258 {
00259 if (STATE_INTERRUPTED == get_state())
00260 exception::_throw("Fetching process is interrupted");
00261
00262
00263 _vector< terimber_db_value > val;
00264 recordset_list_t::iterator iter_val = _data.push_back(*_data_allocator, val);
00265 if (iter_val == _data.end())
00266 exception::_throw("Not enough memory");
00267
00268
00269 if (!iter_val->resize(*_data_allocator, col_count))
00270 exception::_throw("Not enough memory");
00271
00272 for (size_t index = 0; index < col_count; ++index)
00273 v_convert_one_value(0, index, (*iter_val)[index]);
00274
00275 ++select_row;
00276
00277 --_requested_rows;
00278 }
00279
00280 check_retcode(_requested_rows == 0 || x == MYSQL_NO_DATA)
00281
00282
00283 _fetched_rows = select_row;
00284 }
00285
00286
00287 void
00288 mysql_dbserver::v_replace_quote()
00289 {
00290 if (0 == _quote)
00291 return;
00292
00293
00294 if (!_sql.length())
00295 return;
00296
00297
00298 char* buf = (char*)check_pointer(_temp_allocator->allocate(_sql.length() + 1));
00299
00300 *buf = 0;
00301
00302 size_t count_params = 0;
00303
00304 char* new_sql = buf;
00305 const char* begin = _sql;
00306 const char* end = 0;
00307
00308
00309 while (0 != (end = strchr(begin, _quote)))
00310 {
00311 ++count_params;
00312 size_t len = end - begin;
00313
00314 str_template::strcpy(new_sql, begin, len);
00315 begin += len + 1;
00316 new_sql += len;
00317
00318 *new_sql++ = '?';
00319
00320
00321 begin += strcspn(begin, valid_delimeters);
00322 }
00323
00324
00325 if (count_params != _params.size())
00326 exception::_throw("Number of parameters doesn't match the sql statement syntax");
00327
00328
00329 if (_params.size())
00330 {
00331 _param_binders.resize(*_columns_allocator, _params.size());
00332 }
00333
00334
00335 str_template::strcpy(new_sql, begin, os_minus_one);
00336
00337 _sql = buf;
00338 }
00339
00340
00341 void
00342 mysql_dbserver::v_bind_one_param(size_t index)
00343 {
00344 binder& cur = _params[index];
00345
00346 MYSQL_BIND& mysql_binder = _param_binders[index];
00347 mysql_binder.is_unsigned = 1;
00348
00349 mysql_binder.is_null = (char*)&cur._value.nullVal;
00350 mysql_binder.length = (unsigned long*)&cur._real_length;
00351
00352 switch (cur._type)
00353 {
00354 case db_bool:
00355 cur._max_length = sizeof(bool);
00356 mysql_binder.buffer_length = (unsigned long)(cur._real_length = cur._value.nullVal ? 0 : cur._max_length);
00357 mysql_binder.buffer = cur._bind_buffer = &(cur._value.val.boolVal);
00358 cur._native_type = mysql_binder.buffer_type = MYSQL_TYPE_TINY;
00359 break;
00360 case db_sb1:
00361 mysql_binder.is_unsigned = 0;
00362 case db_ub1:
00363 cur._max_length = sizeof(ub1_t);
00364 mysql_binder.buffer_length = (unsigned long)(cur._real_length = cur._value.nullVal ? 0 : cur._max_length);
00365 mysql_binder.buffer = cur._bind_buffer = cur._type == db_sb1 ? (void*)&(cur._value.val.cVal) : (void*)&(cur._value.val.bVal);
00366 cur._native_type = mysql_binder.buffer_type = MYSQL_TYPE_TINY;
00367 break;
00368 case db_sb2:
00369 mysql_binder.is_unsigned = 0;
00370 case db_ub2:
00371 cur._max_length = sizeof(ub2_t);
00372 mysql_binder.buffer_length = (unsigned long)(cur._real_length = cur._value.nullVal ? 0 : cur._max_length);
00373 cur._bind_buffer = cur._type == db_sb2 ? (void*)&(cur._value.val.iVal) : (void*)&(cur._value.val.uiVal);
00374 cur._native_type = mysql_binder.buffer_type = MYSQL_TYPE_SHORT;
00375 break;
00376 case db_sb4:
00377 mysql_binder.is_unsigned = 0;
00378 case db_ub4:
00379 cur._max_length = sizeof(ub4_t);
00380 mysql_binder.buffer_length = (unsigned long)(cur._real_length = cur._value.nullVal ? 0 : cur._max_length);
00381 mysql_binder.buffer = cur._bind_buffer = cur._type == db_ub4 ? (void*)&(cur._value.val.lVal) : (void*)&(cur._value.val.ulVal);
00382 cur._native_type = mysql_binder.buffer_type = MYSQL_TYPE_LONG;
00383 break;
00384 case db_float:
00385 cur._max_length = sizeof(float);
00386 mysql_binder.buffer_length = (unsigned long)(cur._real_length = cur._value.nullVal ? 0 : cur._max_length);
00387 mysql_binder.buffer = cur._bind_buffer = &(cur._value.val.fltVal);
00388 cur._native_type = mysql_binder.buffer_type = MYSQL_TYPE_FLOAT;
00389 break;
00390 case db_double:
00391 cur._max_length = sizeof(double);
00392 #ifdef OS_64BIT
00393 mysql_binder.buffer_length = (unsigned long)(cur._real_length = cur._value.nullVal ? 0 : cur._max_length);
00394 mysql_binder.buffer = cur._bind_buffer = &(cur._value.val.dblVal);
00395 #else
00396 mysql_binder.buffer_length = cur._real_length = cur._value.nullVal || !cur._value.val.dblVal ? 0 : cur._max_length;
00397
00398 if (is_param_out(cur._in_out))
00399 {
00400 double* buf = (double*)check_pointer(_temp_allocator->allocate(sizeof(double)));
00401 *buf = cur._value.val.dblVal ? *cur._value.val.dblVal : 0.0;
00402 mysql_binder.buffer = cur._bind_buffer = buf;
00403 }
00404 else
00405 mysql_binder.buffer = cur._bind_buffer = (void*)cur._value.val.dblVal;
00406 #endif
00407 cur._native_type = mysql_binder.buffer_type = MYSQL_TYPE_DOUBLE;
00408 break;
00409 case db_sb8:
00410 mysql_binder.is_unsigned = 0;
00411 case db_ub8:
00412
00413 cur._max_length = sizeof(ub8_t);
00414 #ifdef OS_64BIT
00415 mysql_binder.buffer_length = (unsigned long)(cur._real_length = cur._value.nullVal ? 0 : cur._max_length);
00416 mysql_binder.buffer = cur._bind_buffer = &(cur._value.val.uintVal);
00417 #else
00418 mysql_binder.buffer_length = cur._real_length = cur._value.nullVal || !cur._value.val.uintVal ? 0 : cur._max_length;
00419
00420 if (is_param_out(cur._in_out))
00421 {
00422 ub8_t* buf = (ub8_t*)check_pointer(_temp_allocator->allocate(sizeof(ub8_t)));
00423 *buf = cur._value.val.uintVal ? *cur._value.val.uintVal : 0;
00424 mysql_binder.buffer = cur._bind_buffer = buf;
00425 }
00426 else
00427 mysql_binder.buffer = cur._bind_buffer = (void*)cur._value.val.intVal;
00428 #endif
00429
00430 cur._native_type = mysql_binder.buffer_type = MYSQL_TYPE_LONGLONG;
00431 break;
00432 case db_date:
00433 #ifdef OS_64BIT
00434 mysql_binder.buffer_length = (unsigned long)(cur._real_length = cur._value.nullVal ? 0 : sizeof(MYSQL_TIME));
00435 #else
00436 mysql_binder.buffer_length = cur._real_length = cur._value.nullVal || !cur._value.val.intVal ? 0 : sizeof(MYSQL_TIME);
00437 #endif
00438 {
00439 MYSQL_TIME* ptds = (MYSQL_TIME*)check_pointer(_temp_allocator->allocate(sizeof(MYSQL_TIME)));
00440 mysql_binder.buffer = cur._bind_buffer = ptds;
00441
00442 if (cur._value.val.intVal)
00443 {
00444 ub4_t year32;
00445 ub1_t month8, day8, hour8, minute8, second8, wday8;
00446 ub2_t millisec16, yday16;
00447 date::convert_from(
00448 #ifdef OS_64BIT
00449 cur._value.val.intVal,
00450 #else
00451 *cur._value.val.intVal,
00452 #endif
00453 year32,
00454 month8,
00455 day8,
00456 hour8,
00457 minute8,
00458 second8,
00459 millisec16,
00460 wday8,
00461 yday16);
00462
00463 ptds->year = year32;
00464 ptds->month = month8;
00465 ptds->day = day8;
00466 ptds->hour = hour8;
00467 ptds->minute = minute8;
00468 ptds->second = second8;
00469 ptds->second_part = millisec16;
00470 ptds->neg = false;
00471 ptds->time_type = MYSQL_TIMESTAMP_DATETIME;
00472 }
00473 }
00474
00475 cur._native_type = mysql_binder.buffer_type = MYSQL_TYPE_TIMESTAMP;
00476 break;
00477 case db_string:
00478 cur._real_length = cur._value.val.strVal ? strlen(cur._value.val.strVal) : 0;
00479 cur._max_length = __max(cur._max_length, cur._real_length);
00480 mysql_binder.buffer_length = (unsigned long)cur._max_length;
00481
00482 if (is_param_out(cur._in_out))
00483 {
00484 mysql_binder.buffer = cur._bind_buffer = check_pointer(_temp_allocator->allocate(cur._max_length));
00485 if (cur._value.val.strVal)
00486 str_template::strcpy((char*)cur._bind_buffer, cur._value.val.strVal, os_minus_one);
00487 else
00488 memset(cur._bind_buffer, 0, cur._max_length);
00489 }
00490 else
00491 mysql_binder.buffer = cur._bind_buffer = (void*)cur._value.val.strVal;
00492
00493
00494 cur._native_type = mysql_binder.buffer_type = MYSQL_TYPE_VAR_STRING;
00495 break;
00496 case db_wstring:
00497 cur._real_length = cur._value.val.wstrVal ? wcslen(cur._value.val.wstrVal) : 0;
00498 cur._max_length = 6 * __max(cur._max_length, cur._real_length);
00499 mysql_binder.buffer_length = (unsigned long)cur._max_length;
00500
00501 mysql_binder.buffer = cur._bind_buffer = check_pointer(_temp_allocator->allocate(cur._max_length));
00502 if (cur._value.val.wstrVal)
00503 {
00504 string_t conv(_temp_allocator);
00505 str_template::unicode_to_multibyte(conv, cur._value.val.wstrVal, os_minus_one);
00506
00507 memcpy(cur._bind_buffer, (const char*)conv, conv.length() + 1);
00508
00509 cur._real_length = conv.length();
00510 }
00511 else
00512 memset(cur._bind_buffer, 0, cur._max_length);
00513
00514
00515 cur._native_type = mysql_binder.buffer_type = MYSQL_TYPE_VAR_STRING;
00516 break;
00517 case db_decimal:
00518 case db_numeric:
00519 cur._max_length = 40;
00520 mysql_binder.buffer_length = (unsigned long)(cur._real_length = cur._value.nullVal || !cur._value.val.bufVal ? 0 : cur._max_length);
00521
00522 {
00523 char* buf = (char*)check_pointer(_temp_allocator->allocate(cur._max_length));
00524 mysql_binder.buffer = cur._bind_buffer = buf;
00525
00526 if (cur._value.val.bufVal)
00527 {
00528 numeric num(_temp_allocator);
00529 if (!num.parse_orcl(cur._value.val.bufVal))
00530 exception::_throw("Out of range");
00531
00532
00533 if (!num.format(buf, '.'))
00534 exception::_throw("Out of range");
00535
00536 mysql_binder.buffer_length = (unsigned long)(cur._real_length = strlen(buf));
00537 cur._precision = num.precision();
00538 cur._scale = num.scale();
00539 }
00540 }
00541
00542 cur._native_type = mysql_binder.buffer_type = MYSQL_TYPE_DECIMAL;
00543 break;
00544 case db_binary:
00545 cur._max_length = __max(cur._max_length, cur._value.val.bufVal ? *(size_t*)cur._value.val.bufVal : 0);
00546 mysql_binder.buffer_length = (unsigned long)(cur._real_length = cur._value.nullVal || !cur._value.val.bufVal ? 0 : cur._max_length);
00547
00548 mysql_binder.buffer = cur._bind_buffer = cur._value.val.bufVal ? (ub1_t*)cur._value.val.bufVal + sizeof(size_t) : 0;
00549
00550 cur._native_type = mysql_binder.buffer_type = MYSQL_TYPE_LONG_BLOB;
00551
00552
00553 break;
00554 default:
00555 exception::_throw("Unsupported parameter type");
00556 assert(false);
00557 }
00558
00559
00560 if (_params.size() == index + 1)
00561 {
00562 check_retcode(mysql_stmt_bind_param(_stmt, &_param_binders[0]) == 0)
00563 }
00564 }
00565
00566 void
00567 mysql_dbserver::v_before_bind_columns()
00568 {
00569 if (_cols.size())
00570 _column_binders.resize(*_columns_allocator, _cols.size());
00571 }
00572
00573
00574 void
00575 mysql_dbserver::v_bind_one_column(size_t index)
00576 {
00577 binder& cur = _cols[index];
00578
00579 MYSQL_BIND& mysql_binder = _column_binders[index];
00580 cur._value.nullVal = false;
00581 mysql_binder.is_null = (char*)&cur._value.nullVal;
00582 mysql_binder.buffer_type = (enum_field_types)cur._native_type;
00583 mysql_binder.length = (unsigned long*)&cur._real_length;
00584 mysql_binder.is_unsigned = (cur._bind_type == UNSIGNED_FLAG);
00585
00586 switch (cur._native_type)
00587 {
00588 case MYSQL_TYPE_TINY:
00589 mysql_binder.buffer_length = (unsigned long)(cur._max_length = sizeof(sb1_t));
00590 mysql_binder.buffer = cur._bind_buffer = &(cur._value.val.cVal);
00591 break;
00592 case MYSQL_TYPE_SHORT:
00593 mysql_binder.buffer_length = (unsigned long)(cur._max_length = sizeof(sb2_t));
00594 mysql_binder.buffer = cur._bind_buffer = &(cur._value.val.iVal);
00595 break;
00596 case MYSQL_TYPE_INT24:
00597 case MYSQL_TYPE_LONG:
00598 mysql_binder.buffer_length = (unsigned long)(cur._max_length = sizeof(sb4_t));
00599 mysql_binder.buffer = cur._bind_buffer = &(cur._value.val.lVal);
00600 break;
00601 case MYSQL_TYPE_FLOAT:
00602 mysql_binder.buffer_length = (unsigned long)(cur._max_length = sizeof(float));
00603 mysql_binder.buffer = cur._bind_buffer = &(cur._value.val.fltVal);
00604 break;
00605 case MYSQL_TYPE_DOUBLE:
00606 mysql_binder.buffer_length = (unsigned long)(cur._max_length = sizeof(double));
00607 #ifdef OS_64BIT
00608 mysql_binder.buffer = cur._bind_buffer = &(cur._value.val.dblVal);
00609 #else
00610 mysql_binder.buffer = cur._bind_buffer = check_pointer(_temp_allocator->allocate(cur._max_length));
00611 #endif
00612 break;
00613 case MYSQL_TYPE_TIMESTAMP:
00614 case MYSQL_TYPE_DATE:
00615 case MYSQL_TYPE_DATETIME:
00616 case MYSQL_TYPE_TIME:
00617 case MYSQL_TYPE_YEAR:
00618 case MYSQL_TYPE_NEWDATE:
00619 mysql_binder.buffer_length = (unsigned long)(cur._max_length = sizeof(MYSQL_TIME));
00620 mysql_binder.buffer = cur._bind_buffer = check_pointer(_temp_allocator->allocate(cur._max_length));
00621 break;
00622 case MYSQL_TYPE_DECIMAL:
00623 mysql_binder.buffer_length = (unsigned long)(cur._max_length = 40);
00624 mysql_binder.buffer = cur._bind_buffer = check_pointer(_temp_allocator->allocate(cur._max_length));
00625 break;
00626 case MYSQL_TYPE_LONGLONG:
00627 mysql_binder.buffer_length = (unsigned long)(cur._max_length = sizeof(sb8_t));
00628 #ifdef OS_64BIT
00629 mysql_binder.buffer = cur._bind_buffer = &(cur._value.val.uintVal);
00630 #else
00631 mysql_binder.buffer = cur._bind_buffer = check_pointer(_temp_allocator->allocate(cur._max_length));
00632 #endif
00633 break;
00634 case MYSQL_TYPE_ENUM:
00635 case MYSQL_TYPE_SET:
00636 case MYSQL_TYPE_VAR_STRING:
00637 case MYSQL_TYPE_STRING:
00638 case MYSQL_TYPE_GEOMETRY:
00639 mysql_binder.buffer_length = (unsigned long)(cur._max_length = 4000);
00640 mysql_binder.buffer = cur._bind_buffer = check_pointer(_temp_allocator->allocate(cur._max_length));
00641 break;
00642 case MYSQL_TYPE_TINY_BLOB:
00643 case MYSQL_TYPE_MEDIUM_BLOB:
00644 case MYSQL_TYPE_LONG_BLOB:
00645 case MYSQL_TYPE_BLOB:
00646
00647 mysql_binder.buffer_length = (unsigned long)(cur._max_length = cur._real_length = 64*1024);
00648 mysql_binder.buffer = cur._bind_buffer = check_pointer(_temp_allocator->allocate(cur._real_length));
00649 break;
00650 default:
00651 exception::_throw("Unsupported native sql type");
00652 assert(false);
00653 }
00654
00655
00656 if (_cols.size() == index + 1)
00657 {
00658 check_retcode(mysql_stmt_bind_result(_stmt, &_column_binders[0]) == 0)
00659 }
00660 }
00661
00662
00663 size_t
00664 mysql_dbserver::v_get_number_columns()
00665 {
00666 return mysql_stmt_field_count(_stmt);
00667 }
00668
00669
00670 void
00671 mysql_dbserver::v_convert_one_value(size_t row, size_t index, terimber_db_value& val)
00672 {
00673 binder& cur = _cols[index];
00674 MYSQL_BIND& mysql_binder = _column_binders[index];
00675
00676 if (cur._value.nullVal || !cur._real_length)
00677 {
00678 memset(&val, 0, sizeof(terimber_db_value));
00679 val.nullVal = true;
00680 cur._value.nullVal = false;
00681 return;
00682 }
00683 else
00684 val.nullVal = false;
00685
00686
00687 switch (cur._native_type)
00688 {
00689 case MYSQL_TYPE_TINY:
00690 val.val.cVal = cur._value.val.cVal;
00691 break;
00692 case MYSQL_TYPE_SHORT:
00693 val.val.iVal = cur._value.val.iVal;
00694 break;
00695 case MYSQL_TYPE_INT24:
00696 case MYSQL_TYPE_LONG:
00697 val.val.lVal = cur._value.val.lVal;
00698 break;
00699 case MYSQL_TYPE_FLOAT:
00700 val.val.fltVal = cur._value.val.fltVal;
00701 break;
00702 case MYSQL_TYPE_DOUBLE:
00703 #ifdef OS_64BIT
00704 val.val.dblVal = cur._value.val.dblVal;
00705 #else
00706 val.val.dblVal = (double*)check_pointer(_data_allocator->allocate(cur._max_length));
00707 memcpy((void*)val.val.dblVal, cur._bind_buffer, cur._max_length);
00708 #endif
00709 break;
00710 case MYSQL_TYPE_TIMESTAMP:
00711 case MYSQL_TYPE_DATE:
00712 case MYSQL_TYPE_DATETIME:
00713 case MYSQL_TYPE_TIME:
00714 case MYSQL_TYPE_YEAR:
00715 case MYSQL_TYPE_NEWDATE:
00716 {
00717 MYSQL_TIME* ptds = (MYSQL_TIME*)cur._bind_buffer;
00718 sb8_t dummy64;
00719 date::convert_to(ptds->year, (ub1_t)ptds->month, (ub1_t)ptds->day, (ub1_t)ptds->hour, (ub1_t)ptds->minute, (ub1_t)ptds->second, (ub2_t)ptds->second_part, dummy64);
00720 #ifdef OS_64BIT
00721 val.val.intVal = dummy64;
00722 #else
00723 sb8_t* dummy = (sb8_t*)check_pointer(_data_allocator->allocate(sizeof(sb8_t)));
00724 *dummy = dummy64;
00725 val.val.intVal = dummy;
00726 #endif
00727 }
00728 break;
00729 case MYSQL_TYPE_DECIMAL:
00730 {
00731 const char* buf = (const char*)cur._bind_buffer;
00732 size_t len = (buf) ? strlen(buf) : 0;
00733 numeric num(buf, len, '.', _temp_allocator);
00734 ub1_t* bval = (ub1_t*)check_pointer(_data_allocator->allocate(num.orcl_len()));
00735 if (!num.persist_orcl(bval))
00736 exception::_throw("Out of range");
00737 val.val.bufVal = bval;
00738 }
00739 break;
00740 case MYSQL_TYPE_LONGLONG:
00741 #ifdef OS_64BIT
00742 val.val.intVal = cur._value.val.intVal;
00743 #else
00744 val.val.intVal = (sb8_t*)check_pointer(_data_allocator->allocate(cur._max_length));
00745 memcpy((void*)val.val.intVal, cur._bind_buffer, cur._max_length);
00746 #endif
00747 break;
00748 case MYSQL_TYPE_ENUM:
00749 case MYSQL_TYPE_SET:
00750 case MYSQL_TYPE_VAR_STRING:
00751 case MYSQL_TYPE_STRING:
00752 case MYSQL_TYPE_GEOMETRY:
00753 {
00754 char* sz = (char*)check_pointer(_data_allocator->allocate(cur._real_length + 1));
00755 sz[cur._real_length] = 0;
00756 memcpy(sz, cur._bind_buffer, cur._real_length);
00757 val.val.strVal = sz;
00758 }
00759 break;
00760 case MYSQL_TYPE_TINY_BLOB:
00761 case MYSQL_TYPE_MEDIUM_BLOB:
00762 case MYSQL_TYPE_LONG_BLOB:
00763 case MYSQL_TYPE_BLOB:
00764 {
00765 ub1_t* bval = (ub1_t*)check_pointer(_data_allocator->allocate(cur._real_length + sizeof(size_t)));
00766 *(ub4_t*)bval = (ub4_t)cur._real_length;
00767 memcpy((ub1_t*)bval + sizeof(size_t), cur._bind_buffer, cur._real_length);
00768 val.val.bufVal = bval;
00769 }
00770 break;
00771 default:
00772 exception::_throw("Unsupported native sql type");
00773 assert(false);
00774 }
00775 }
00776
00777
00778 void
00779 mysql_dbserver::v_get_one_column_info(size_t index)
00780 {
00781 binder& cur = _cols[index];
00782
00783 cur._real_length = _stmt->fields[index].length;
00784 cur.set_name(_columns_allocator, _stmt->fields[index].name);
00785 cur._native_type = _stmt->fields[index].type;
00786 cur._scale = _stmt->fields[index].decimals;
00787 cur._precision = cur._real_length - cur._scale;
00788 cur._value.nullVal = IS_NOT_NULL(_stmt->fields[index].flags);
00789 cur._max_length = __max(_stmt->fields[index].max_length, _stmt->fields[index].length);
00790
00791 cur._bind_type = (_stmt->fields[index].flags & UNSIGNED_FLAG);
00792 }
00793
00794
00795 void
00796 mysql_dbserver::v_form_sql_string()
00797 {
00798 size_t count_params = _params.size();
00799 switch (get_action())
00800 {
00801 case ACTION_NONE:
00802 case ACTION_EXEC_SQL:
00803 case ACTION_OPEN_SQL:
00804 case ACTION_EXEC_SQL_ASYNC:
00805 case ACTION_OPEN_SQL_ASYNC:
00806 case ACTION_FETCH:
00807 case ACTION_FETCH_ASYNC:
00808 break;
00809 case ACTION_OPEN_PROC:
00810 case ACTION_EXEC_PROC:
00811 case ACTION_OPEN_PROC_ASYNC:
00812 case ACTION_EXEC_PROC_ASYNC:
00813 {
00814 string_t val(_temp_allocator);
00815 char q[2] = {_quote, 0};
00816 val = "call ";
00817 val += _sql;
00818 val += "(";
00819
00820 for (size_t index = 0; index < count_params; index++)
00821 {
00822 if (0 != index)
00823 val += ", ";
00824
00825 val += q;
00826 }
00827
00828 val += ")";
00829
00830 _sql = val;
00831 }
00832 break;
00833 default:
00834 assert(false);
00835 }
00836 }
00837
00838
00839 void
00840 mysql_dbserver::v_rebind_one_param(size_t index)
00841 {
00842 binder& cur = _params[index];
00843 if (!is_param_out(cur._in_out))
00844 return;
00845
00846 cur._value.nullVal = false;
00847
00848 if (cur._real_length == os_minus_one)
00849 {
00850 cur._value.nullVal = true;
00851 memset(&cur._value.val, 0, sizeof(terimber_db_value));
00852 return;
00853 }
00854
00855 switch (cur._native_type)
00856 {
00857 case MYSQL_TYPE_TINY:
00858 case MYSQL_TYPE_SHORT:
00859 case MYSQL_TYPE_INT24:
00860 case MYSQL_TYPE_LONG:
00861 case MYSQL_TYPE_FLOAT:
00862 break;
00863 case MYSQL_TYPE_DOUBLE:
00864 #ifdef OS_64BIT
00865 cur._value.val.dblVal = cur._value.val.dblVal;
00866 #else
00867 cur._value.val.dblVal = (double*)check_pointer(cur.allocate_value(0));
00868 memcpy((void*)cur._value.val.dblVal, cur._bind_buffer, cur._max_length);
00869 #endif
00870 break;
00871 case MYSQL_TYPE_TIMESTAMP:
00872 case MYSQL_TYPE_DATE:
00873 case MYSQL_TYPE_DATETIME:
00874 case MYSQL_TYPE_TIME:
00875 case MYSQL_TYPE_YEAR:
00876 case MYSQL_TYPE_NEWDATE:
00877 {
00878 MYSQL_TIME* ptds = (MYSQL_TIME*)cur._bind_buffer;
00879 sb8_t dummy64;
00880 date::convert_to(ptds->year, (ub1_t)ptds->month, (ub1_t)ptds->day, (ub1_t)ptds->hour, (ub1_t)ptds->minute, (ub1_t)ptds->second, (ub2_t)ptds->second_part, dummy64);
00881 #ifdef OS_64BIT
00882 cur._value.val.intVal = dummy64;
00883 #else
00884 sb8_t* dummy = (sb8_t*)check_pointer(cur.allocate_value(0));
00885 *dummy = dummy64;
00886 cur._value.val.intVal = dummy;
00887 #endif
00888 }
00889 break;
00890 case MYSQL_TYPE_LONGLONG:
00891 #ifdef OS_64BIT
00892 cur._value.val.intVal = cur._value.val.intVal;
00893 #else
00894 cur._value.val.intVal = (sb8_t*)check_pointer(cur.allocate_value(0));
00895 memcpy((void*)cur._value.val.intVal, cur._bind_buffer, cur._max_length);
00896 #endif
00897 break;
00898 case MYSQL_TYPE_DECIMAL:
00899 {
00900 const char* buf = (const char*)cur._bind_buffer;
00901 size_t len = (buf) ? strlen(buf) : 0;
00902 numeric num(buf, len, '.', _temp_allocator);
00903 ub1_t* bval = (ub1_t*)check_pointer(cur.allocate_value(num.orcl_len()));
00904 if (!num.persist_orcl(bval))
00905 exception::_throw("Out of range");
00906 cur._value.val.bufVal = bval;
00907 }
00908 break;
00909 case MYSQL_TYPE_ENUM:
00910 case MYSQL_TYPE_SET:
00911 case MYSQL_TYPE_VAR_STRING:
00912 case MYSQL_TYPE_STRING:
00913 case MYSQL_TYPE_GEOMETRY:
00914 {
00915 char* sz = (char*)check_pointer(cur.allocate_value(cur._real_length));
00916 sz[cur._real_length] = 0;
00917 memcpy(sz, cur._bind_buffer, cur._real_length);
00918 }
00919 break;
00920 case MYSQL_TYPE_TINY_BLOB:
00921 case MYSQL_TYPE_MEDIUM_BLOB:
00922 case MYSQL_TYPE_LONG_BLOB:
00923 case MYSQL_TYPE_BLOB:
00924 {
00925 ub1_t* bval = (ub1_t*)check_pointer(cur.allocate_value(cur._real_length));
00926 memcpy(bval, cur._bind_buffer, cur._real_length);
00927 }
00928 break;
00929 default:
00930 exception::_throw("Unsupported native sql type");
00931 assert(false);
00932 }
00933 }
00934
00935
00936 void
00937 mysql_dbserver::v_interrupt_async()
00938 {
00939
00940 v_close();
00941 }
00942
00943
00944 dbtypes
00945 mysql_dbserver::v_native_type_to_client_type(size_t native_type)
00946 {
00947 switch (native_type)
00948 {
00949 case MYSQL_TYPE_NULL:
00950 return db_unknown;
00951 case MYSQL_TYPE_TINY:
00952 return db_sb1;
00953 case MYSQL_TYPE_SHORT:
00954 return db_sb2;
00955 case MYSQL_TYPE_INT24:
00956 case MYSQL_TYPE_LONG:
00957 return db_sb4;
00958 case MYSQL_TYPE_FLOAT:
00959 return db_float;
00960 case MYSQL_TYPE_DOUBLE:
00961 return db_double;
00962 case MYSQL_TYPE_TIMESTAMP:
00963 case MYSQL_TYPE_DATE:
00964 case MYSQL_TYPE_DATETIME:
00965 case MYSQL_TYPE_TIME:
00966 case MYSQL_TYPE_YEAR:
00967 case MYSQL_TYPE_NEWDATE:
00968 return db_date;
00969 case MYSQL_TYPE_DECIMAL:
00970 return db_decimal;
00971 case MYSQL_TYPE_LONGLONG:
00972 return db_sb8;
00973 case MYSQL_TYPE_ENUM:
00974 case MYSQL_TYPE_SET:
00975 case MYSQL_TYPE_VAR_STRING:
00976 case MYSQL_TYPE_STRING:
00977 case MYSQL_TYPE_GEOMETRY:
00978 return db_string;
00979 case MYSQL_TYPE_TINY_BLOB:
00980 case MYSQL_TYPE_MEDIUM_BLOB:
00981 case MYSQL_TYPE_LONG_BLOB:
00982 case MYSQL_TYPE_BLOB:
00983 return db_binary;
00984 default:
00985 assert(false);
00986 return db_unknown;
00987 }
00988 }
00989
00990 void
00991 mysql_dbserver::parse_connection_string(const char* connection_string, string_t& user, string_t& password, string_t& host, unsigned short& port, string_t& database)
00992 {
00993
00994
00995 if (!connection_string)
00996 return;
00997
00998 const char* semicolumn = 0;
00999
01000 const char* find = strstr(connection_string, "UID=");
01001 size_t len = strlen("UID=");
01002 if (find)
01003 {
01004 semicolumn = strchr(find + len, ';');
01005 user.assign(find + len, semicolumn ? semicolumn - find -len : os_minus_one);
01006 }
01007
01008
01009 find = strstr(connection_string, "PWD=");
01010 len = strlen("PWD=");
01011 if (find)
01012 {
01013 semicolumn = strchr(find + len, ';');
01014 password.assign(find + len, semicolumn ? semicolumn - find -len : os_minus_one);
01015 }
01016
01017 find = strstr(connection_string, "HOST=");
01018 len = strlen("HOST=");
01019 if (find)
01020 {
01021 semicolumn = strchr(find + len, ';');
01022 host.assign(find + len, semicolumn ? semicolumn - find -len : os_minus_one);
01023 }
01024
01025 find = strstr(connection_string, "DB=");
01026 len = strlen("DB=");
01027 if (find)
01028 {
01029 semicolumn = strchr(find + len, ';');
01030 database.assign(find + len, semicolumn ? semicolumn - find -len : os_minus_one);
01031 }
01032
01033 find = strstr(connection_string, "PORT=");
01034 len = strlen("PORT=");
01035 if (find)
01036 {
01037 semicolumn = strchr(find + len, ';');
01038 string_t strport;
01039 strport.assign(find + len, semicolumn ? semicolumn - find -len : os_minus_one);
01040 if (strport.length())
01041 str_template::strscan((const char*)strport, 32, "%hu", &port);
01042 }
01043 }
01044
01046
01048
01049 db_entry*
01050 mysql_db_creator::create( const db_arg& arg
01051 )
01052 {
01053 db_entry* obj = 0;
01054 if (0 != (obj = new db_entry(arg._ident, arg._trusted, arg._login_string)))
01055 {
01056 if (!(obj->_obj = new mysql_dbserver(arg._ident)))
01057 delete obj, obj = 0;
01058 }
01059
01060 return obj;
01061 }
01062
01063 #pragma pack()
01064 END_TERIMBER_NAMESPACE