00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "common.h"
00016 #include "query_handler.h"
00017 #include "login_info.h"
00018
00019 #include <basis/function.h>
00020 #include <basis/log_base.h>
00021 #include <basis/portable.h>
00022 #include <basis/set.cpp>
00023 #include <basis/string_array.h>
00024 #include <data_struct/deep_array.cpp>
00025 #include <opsystem/byte_filer.h>
00026 #include <opsystem/directory.h>
00027 #include <opsystem/filename.h>
00028 #include <opsystem/ini_config.h>
00029 #include <textual/list_parsing.h>
00030
00031 #include <malloc.h>
00032
00033 #define BASE_LOG(s) EMERGENCY_LOG(program_wide_logger(), s)
00034 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), filename(portable::application_name()).basename().raw() + " " + s)
00035
00037
00038 class deep_string_array : public deep_array<istring> {};
00039
00041
00043
00044 query_handler::query_handler()
00045 : _global_current_db(NIL),
00046 _bind_strings(new deep_string_array),
00047 _bind_ints(new int_array)
00048 {
00049 common_database_support::_error_was_seen = false;
00050 }
00051
00052 query_handler::~query_handler()
00053 {
00054 FUNCDEF("destructor");
00055 if (_global_current_db) {
00056 LOG(isprintf("closing database connection."));
00057 dbclose(_global_current_db);
00058 _global_current_db = NIL;
00059 }
00060 dbexit();
00061 WHACK(_bind_strings);
00062 WHACK(_bind_ints);
00063 }
00064
00065 istring query_handler::get_bound_string(int index)
00066 { return _bind_strings->get(index); }
00067
00068 int query_handler::get_bound_int(int index)
00069 { return _bind_ints->get(index); }
00070
00071 bool query_handler::prepare_for_query(const istring &config_file,
00072 database_login_info &persistent_login_info)
00073 {
00074 FUNCDEF("prepare_for_query");
00075 ini_configurator ini(config_file);
00076
00077 database_login_info temp_info(persistent_login_info.db_section);
00078 bool worked = database_login_info::read_login_info(ini, temp_info);
00079 if (!worked) {
00080 LOG(istring("ERROR: failed to read db login info from ") + config_file);
00081 return false;
00082 }
00083
00084
00085
00086 bool retried_connection = false;
00087 if (!_global_current_db || !temp_info.identical(persistent_login_info)
00088 || common_database_support::_error_was_seen) {
00089 persistent_login_info = temp_info;
00090 retried_connection = true;
00091
00092 if (common_database_support::_error_was_seen) {
00093
00094 LOG("handling previous db issue by re-opening database...");
00095 common_database_support::_error_was_seen = false;
00096 }
00097
00098 persistent_login_info.update_freetds_configuration();
00099
00100
00101 bool worked = login_to_database(persistent_login_info);
00102 if (!worked) {
00103 LOG(istring("ERROR: failed to login to database ")
00104 + persistent_login_info.database
00105 + " using authentication info.");
00106 return false;
00107 }
00108
00109 bool using_okay = use_database(persistent_login_info);
00110 if (!using_okay) {
00111 LOG(istring("ERROR: failed to USE database ")
00112 + persistent_login_info.database + " on server.");
00113 return false;
00114 }
00115 }
00116
00117 if (!_global_current_db) {
00118
00119 LOG("ERROR: failed to end up with a working database object");
00120 return false;
00121 } else {
00122 if (retried_connection) {
00123 LOG(istring("Now connected to database ")
00124 + persistent_login_info.database);
00125 }
00126 }
00127
00128 return true;
00129 }
00130
00131 bool query_handler::bind_columns()
00132 {
00133 FUNCDEF("bind_columns");
00134 if (!_global_current_db) { LOG("ERROR: null database object"); return false; }
00135
00136 bool to_return = true;
00137
00138 int db_cols = dbnumcols(_global_current_db);
00140 for (int i = 1; i <= db_cols; i++) {
00141 int type = dbcoltype(_global_current_db, i);
00142 switch (type) {
00143 case SYBINT1:
00144 case SYBINT2:
00145 case SYBINT4: {
00146 if (_bind_ints->length() < db_cols + 1) {
00147 _bind_ints->insert(_bind_ints->length(),
00148 db_cols + 2 - _bind_ints->length());
00149 }
00150 if (dbbind(_global_current_db, i, INTBIND, sizeof(int),
00151 (BYTE *) &_bind_ints->use(i)) != SUCCEED) {
00152 to_return = false;
00153 LOG(isprintf("ERROR: had problem with binding to int on column %d", i));
00154 }
00155 break;
00156 }
00157 case SYBCHAR:
00158 case SYBVARCHAR:
00159 case SYBTEXT: {
00160 if (_bind_strings->length() < db_cols + 1) {
00161 _bind_strings->insert(_bind_strings->length(),
00162 db_cols + 2 - _bind_strings->length());
00163 }
00164 if (_bind_strings->get(i).length() < MAX_DB_STRING + 1) {
00165 _bind_strings->put(i, istring('\0', MAX_DB_STRING + 1));
00166 }
00167 char *field = _bind_strings->use(i).access();
00168 if (SUCCEED != dbbind(_global_current_db, i, STRINGBIND, -1, (BYTE *)field)) {
00169
00170
00171 to_return = false;
00172 LOG(isprintf("ERROR: had problem with binding to string on column %d", i));
00173 }
00174 break;
00175 }
00176 default: {
00177
00178
00179 LOG(isprintf("unhandled type for column %d, type is %d", i, type));
00180 break;
00181 }
00182 }
00183 }
00184 return to_return;
00185 }
00186
00187 bool query_handler::print_row(log_base &output)
00188 {
00189 FUNCDEF("print_row");
00190 if (!_global_current_db) { LOG("ERROR: null database object"); return false; }
00191 bool to_return = true;
00192 istring to_show;
00193 for (int i = 1; i <= dbnumcols(_global_current_db); i++) {
00194 if (i != 1) to_show += " ";
00195 int type = dbcoltype(_global_current_db, i);
00196 switch (type) {
00197 case SYBINT1:
00198 case SYBINT2:
00199 case SYBINT4: {
00200 to_show += isprintf("%d", _bind_ints->get(i));
00201 break;
00202 }
00203 case SYBCHAR:
00204 case SYBVARCHAR:
00205 case SYBTEXT: {
00206
00207
00208 istring found = (*_bind_strings)[i];
00209 found.shrink();
00210 to_show += found;
00211 break;
00212 }
00213 default: {
00214 to_show += "UNHANDLED";
00215 break;
00216 }
00217 }
00218 }
00219 output.log(to_show);
00220 if (&output != &program_wide_logger()) {
00221 BASE_LOG(to_show);
00222 }
00223 }
00224
00225 bool query_handler::show_this_row(int row_num, log_base &output)
00226 {
00227 FUNCDEF("show_this_row");
00228 if (!_global_current_db) { LOG("ERROR: null database object"); return false; }
00229 bool to_return = true;
00230 istring to_show;
00231 for (int i = 1; i <= dbnumcols(_global_current_db); i++) {
00232 if (i != 1) to_show += "\t";
00233 int type = dbcoltype(_global_current_db, i);
00234 switch (type) {
00235 case SYBINT1:
00236 case SYBINT2:
00237 case SYBINT4: {
00238 to_show += isprintf("I=%d", _bind_ints->get(i));
00239 break;
00240 }
00241 case SYBCHAR:
00242 case SYBVARCHAR:
00243 case SYBTEXT: {
00244
00245
00246 to_show += "S=";
00247 istring found = (*_bind_strings)[i];
00248 found.shrink();
00249 to_show += found;
00250 break;
00251 }
00252 default: {
00253 to_show += "UNHANDLED";
00254 break;
00255 }
00256 }
00257 }
00258 output.log(isprintf("#%d: ", row_num) + to_show);
00259 if (&output != &program_wide_logger()) {
00260 LOG(isprintf("#%d: ", row_num) + to_show);
00261 }
00262 }
00263
00264 void query_handler::show_column_structure()
00265 {
00266 FUNCDEF("show_column_structure");
00267 if (!_global_current_db) { LOG("ERROR: null database object"); return; }
00268 for (int i = 1; i <= dbnumcols(_global_current_db); i++) {
00269 LOG(isprintf(" col %d: type=%d name=%s", i, dbcoltype(_global_current_db, i),
00270 dbcolname(_global_current_db, i)));
00271 }
00272 }
00273
00274 void query_handler::show_results(bool verbose, log_base &output)
00275 {
00276 FUNCDEF("show_results");
00277 if (!_global_current_db) { LOG("ERROR: null database object"); return; }
00278 int db_result = REG_ROW;
00279
00280 int row_num = 1;
00281 BASE_LOG(istring('-', 42));
00282 bind_columns();
00283 while (db_result == REG_ROW) {
00284
00285 db_result = dbnextrow(_global_current_db);
00286 if (db_result == REG_ROW) {
00287 if (verbose)
00288 show_this_row(row_num++, output);
00289 else
00290 print_row(output);
00291 } else if (db_result != NO_MORE_ROWS) {
00292
00293 LOG(isprintf("ERROR: failure to get next row=%d", db_result));
00294 }
00295 }
00296 BASE_LOG(istring('-', 42));
00297 }
00298
00299 bool query_handler::login_to_database(const database_login_info &cred)
00300 {
00301 FUNCDEF("login_to_database");
00302 LOG(isprintf("about to logon as \"%s\"", cred.user_name.s()));
00303
00304
00305 if (_global_current_db) {
00306
00307 dbclose(_global_current_db);
00308 _global_current_db = NIL;
00309 dbexit();
00310 }
00311
00312 dbinit();
00313 dberrhandle(common_database_support::syb_err_handler);
00314 dbmsghandle(common_database_support::syb_msg_handler);
00315
00316 LOGINREC *database_login = dblogin();
00317 DBSETLPWD(database_login, cred.password.s());
00318 DBSETLUSER(database_login, cred.user_name.s());
00319 DBSETLAPP(database_login, portable::application_name().s());
00320
00321
00322 LOG(isprintf("about to connect to \"%s\" on instance %s",
00323 cred.db_host.s(), cred.db_instance.s()));
00324
00325
00326 _global_current_db = dbopen(database_login, cred.db_section.s());
00327 if (!_global_current_db) {
00328 LOG(isprintf("ERROR: unable to connect to \"%s\" on instance %s",
00329 cred.db_host.s(), cred.db_instance.s()));
00330 dbloginfree(database_login);
00331 return NIL;
00332 }
00333 dbloginfree(database_login);
00334 return !!_global_current_db;
00335 }
00336
00337 bool query_handler::use_database(const database_login_info &cred)
00338 {
00339 FUNCDEF("use_database");
00340 if (!_global_current_db) { LOG("ERROR: null database object"); return false; }
00341 LOG(isprintf("using database \"%s\"", cred.database.s()));
00342 if (cred.database.length()) {
00343 DBINT erc = dbuse(_global_current_db, cred.database.s());
00344 if (erc != SUCCEED) {
00345 LOG(isprintf("ERROR: unable to use database %s", cred.database.s()));
00346 return false;
00347 }
00348 }
00349 return true;
00350 }
00351
00352 bool query_handler::process_query(const istring &query, log_base &output)
00353 {
00354 FUNCDEF("process_query");
00355 if (!_global_current_db) { LOG("ERROR: null database object"); return false; }
00356 LOG(istring("process_query on: ") + query);
00357 dbfreebuf(_global_current_db);
00358 dbcmd(_global_current_db, query.s());
00359 dbsqlexec(_global_current_db);
00360
00361 if (dbresults(_global_current_db) != SUCCEED) {
00362 LOG(isprintf("ERROR: was expecting a result set and got none."));
00364 return false;
00365 }
00366 show_results(false, output);
00367 dbcanquery(_global_current_db);
00368 return true;
00369 }
00370
00372
00373
00374
00375
00376
00377
00378
00379
00380
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440