00001 #include "../include/FirebirdDatabaseLayer.h"
00002 #include "../include/FirebirdResultSet.h"
00003 #include "../include/DatabaseErrorCodes.h"
00004 #include "../include/DatabaseLayerException.h"
00005
00006 #include "wx/tokenzr.h"
00007 #include "wx/regex.h"
00008
00009
00010 FirebirdDatabaseLayer::FirebirdDatabaseLayer()
00011 : DatabaseLayer()
00012 {
00013 m_pDatabase = NULL;
00014 m_pTransaction = NULL;
00015
00016 m_strServer = _("localhost");
00017 m_strDatabase = _("");
00018 m_strRole = wxEmptyString;
00019 }
00020
00021 FirebirdDatabaseLayer::FirebirdDatabaseLayer(const wxString& strDatabase)
00022 : DatabaseLayer()
00023 {
00024 m_pDatabase = NULL;
00025 m_pTransaction = NULL;
00026
00027 m_strServer = _("localhost");
00028 m_strUser = _("");
00029 m_strPassword = _("");
00030 m_strRole = wxEmptyString;
00031
00032 Open(strDatabase);
00033 }
00034
00035 FirebirdDatabaseLayer::FirebirdDatabaseLayer(const wxString& strDatabase, const wxString& strUser, const wxString& strPassword)
00036 : DatabaseLayer()
00037 {
00038 m_pDatabase = NULL;
00039 m_pTransaction = NULL;
00040
00041 m_strServer = _("");
00042 m_strUser = strUser;
00043 m_strPassword = strPassword;
00044 m_strRole = wxEmptyString;
00045
00046 Open(strDatabase);
00047 }
00048
00049 FirebirdDatabaseLayer::FirebirdDatabaseLayer(const wxString& strServer, const wxString& strDatabase, const wxString& strUser, const wxString& strPassword)
00050 : DatabaseLayer()
00051 {
00052 m_pDatabase = NULL;
00053 m_pTransaction = NULL;
00054
00055 m_strServer = strServer;
00056 m_strUser = strUser;
00057 m_strPassword = strPassword;
00058 m_strRole = wxEmptyString;
00059
00060 Open(strDatabase);
00061 }
00062
00063 FirebirdDatabaseLayer::FirebirdDatabaseLayer(const wxString& strServer, const wxString& strDatabase, const wxString& strUser, const wxString& strPassword, const wxString& strRole)
00064 : DatabaseLayer()
00065 {
00066 m_pDatabase = NULL;
00067 m_pTransaction = NULL;
00068
00069 m_strServer = strServer;
00070 m_strUser = strUser;
00071 m_strPassword = strPassword;
00072 m_strRole = strRole;
00073
00074 Open(strDatabase);
00075 }
00076
00077
00078 FirebirdDatabaseLayer::~FirebirdDatabaseLayer()
00079 {
00080 Close();
00081 }
00082
00083
00084 bool FirebirdDatabaseLayer::Open(const wxString& strDatabase)
00085 {
00086 m_strDatabase = strDatabase;
00087 return Open();
00088 }
00089
00090 bool FirebirdDatabaseLayer::Open(const wxString& strDatabase, const wxString& strUser, const wxString& strPassword)
00091 {
00092 m_strUser = strUser;
00093 m_strPassword = strPassword;
00094
00095 return Open(strDatabase);
00096 }
00097
00098 bool FirebirdDatabaseLayer::Open(const wxString& strServer, const wxString& strDatabase, const wxString& strUser, const wxString& strPassword)
00099 {
00100 m_strServer = strServer;
00101 m_strUser = strUser;
00102 m_strPassword = strPassword;
00103
00104 return Open(strDatabase);
00105 }
00106
00107 bool FirebirdDatabaseLayer::Open()
00108 {
00109 ResetErrorCodes();
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 wxCharBuffer systemEncoding = "UTF-8";
00125
00126 wxCSConv conv(_("UTF-8"));
00127 SetEncoding(&conv);
00128
00129
00130 char* pDpb;
00131 short nDpbLength = 0;
00132 wxCharBuffer userCharBuffer = ConvertToUnicodeStream(m_strUser);
00133 wxCharBuffer passwordCharBuffer = ConvertToUnicodeStream(m_strPassword);
00134 wxCharBuffer roleCharBuffer = ConvertToUnicodeStream(m_strRole);
00135
00136 pDpb = (char*)0;
00137
00138 if (m_strRole == wxEmptyString)
00139 {
00140 isc_expand_dpb(&pDpb, &nDpbLength, isc_dpb_user_name, (const char*)userCharBuffer,
00141 isc_dpb_password, (const char*)passwordCharBuffer, isc_dpb_lc_ctype, (const char*)systemEncoding, NULL);
00142 }
00143 else
00144 {
00145 isc_expand_dpb(&pDpb, &nDpbLength, isc_dpb_user_name, (const char*)userCharBuffer,
00146 isc_dpb_password, (const char*)passwordCharBuffer, isc_dpb_lc_ctype, (const char*)systemEncoding,
00147 isc_dpb_sql_role_name, (const char*)roleCharBuffer, NULL);
00148 }
00149
00150
00151 wxString strDatabaseUrl;
00152 if (m_strServer.IsEmpty())
00153 strDatabaseUrl = m_strDatabase;
00154 else
00155 strDatabaseUrl = m_strServer + _(":") + m_strDatabase;
00156
00157 m_pDatabase = NULL;
00158 m_pTransaction = NULL;
00159
00160 wxCharBuffer urlBuffer = ConvertToUnicodeStream(strDatabaseUrl);
00161
00162 int nReturn = isc_attach_database(m_Status, 0, (char*)(const char*)urlBuffer, &m_pDatabase, nDpbLength, pDpb);
00163 if (nReturn != 0)
00164 {
00165 InterpretErrorCodes();
00166 ThrowDatabaseException();
00167
00168 return false;
00169 }
00170 return true;
00171 }
00172
00173
00174 bool FirebirdDatabaseLayer::Close()
00175 {
00176 CloseResultSets();
00177 CloseStatements();
00178
00179 if (m_pDatabase)
00180 {
00181 int nReturn = isc_detach_database(m_Status, &m_pDatabase);
00182 m_pDatabase = 0L;
00183 if (nReturn != 0)
00184 {
00185 InterpretErrorCodes();
00186 ThrowDatabaseException();
00187 return false;
00188 }
00189 }
00190
00191 return true;
00192 }
00193
00194
00195 void FirebirdDatabaseLayer::BeginTransaction()
00196 {
00197 ResetErrorCodes();
00198
00199 wxLogDebug(_("Beginning transaction\n"));
00200 if (m_pDatabase)
00201 {
00202 m_pTransaction = 0L;
00203 int nReturn = isc_start_transaction(m_Status, &m_pTransaction, 1, &m_pDatabase, 0 , NULL);
00204 if (nReturn != 0)
00205 {
00206 InterpretErrorCodes();
00207 ThrowDatabaseException();
00208 }
00209 }
00210 }
00211
00212 void FirebirdDatabaseLayer::Commit()
00213 {
00214 ResetErrorCodes();
00215
00216 wxLogDebug(_("Committing transaction\n"));
00217 if (m_pDatabase && m_pTransaction)
00218 {
00219 int nReturn = isc_commit_transaction(m_Status, &m_pTransaction);
00220
00221 m_pTransaction = NULL;
00222 if (nReturn != 0)
00223 {
00224 InterpretErrorCodes();
00225 ThrowDatabaseException();
00226 }
00227 }
00228 }
00229
00230 void FirebirdDatabaseLayer::RollBack()
00231 {
00232 ResetErrorCodes();
00233
00234 wxLogDebug(_("Rolling back transaction\n"));
00235 if (m_pDatabase && m_pTransaction)
00236 {
00237 int nReturn = isc_rollback_transaction(m_Status, &m_pTransaction);
00238
00239 m_pTransaction = NULL;
00240 if (nReturn != 0)
00241 {
00242 InterpretErrorCodes();
00243 ThrowDatabaseException();
00244 }
00245 }
00246 }
00247
00248
00249 bool FirebirdDatabaseLayer::RunQuery(const wxString& strQuery, bool bParseQuery)
00250 {
00251 ResetErrorCodes();
00252 if (m_pDatabase != NULL)
00253 {
00254 wxCharBuffer sqlDebugBuffer = ConvertToUnicodeStream(strQuery);
00255 wxLogDebug(_("Running query: \"%s\"\n"), (const char*)sqlDebugBuffer);
00256
00257 wxArrayString QueryArray;
00258 if (bParseQuery)
00259 QueryArray = ParseQueries(strQuery);
00260 else
00261 QueryArray.push_back(strQuery);
00262
00263 wxArrayString::iterator start = QueryArray.begin();
00264 wxArrayString::iterator stop = QueryArray.end();
00265
00266 if (QueryArray.size() > 0)
00267 {
00268 bool bQuickieTransaction = false;
00269
00270 if (m_pTransaction == NULL)
00271 {
00272
00273 bQuickieTransaction = true;
00274 }
00275
00276 if (bQuickieTransaction)
00277 {
00278 BeginTransaction();
00279 if (GetErrorCode() != DATABASE_LAYER_OK)
00280 {
00281 wxLogError(_("Unable to start transaction"));
00282 ThrowDatabaseException();
00283 return false;
00284 }
00285 }
00286
00287 while (start != stop)
00288 {
00289 wxCharBuffer sqlBuffer = ConvertToUnicodeStream(*start);
00290
00291 int nReturn = isc_dsql_execute_immediate(m_Status, &m_pDatabase, &m_pTransaction, GetEncodedStreamLength(*start), (char*)(const char*)sqlBuffer, 1, NULL);
00292 if (nReturn != 0)
00293 {
00294 InterpretErrorCodes();
00295
00296
00297 isc_rollback_transaction(m_Status, &m_pTransaction);
00298 m_pTransaction = NULL;
00299
00300 ThrowDatabaseException();
00301 return false;
00302 }
00303 start++;
00304 }
00305
00306 if (bQuickieTransaction)
00307 {
00308 Commit();
00309 if (GetErrorCode() != DATABASE_LAYER_OK)
00310 {
00311 ThrowDatabaseException();
00312 return false;
00313 }
00314 }
00315 }
00316
00317 return true;
00318 }
00319 else
00320 {
00321 wxLogError(_("Database handle is NULL"));
00322 return false;
00323 }
00324 }
00325
00326 DatabaseResultSet* FirebirdDatabaseLayer::RunQueryWithResults(const wxString& strQuery)
00327 {
00328 ResetErrorCodes();
00329 if (m_pDatabase != NULL)
00330 {
00331 wxCharBuffer sqlDebugBuffer = ConvertToUnicodeStream(strQuery);
00332 wxLogDebug(_("Running query: \"%s\"\n"), (const char*)sqlDebugBuffer);
00333
00334 wxArrayString QueryArray = ParseQueries(strQuery);
00335
00336 if (QueryArray.size() > 0)
00337 {
00338 bool bQuickieTransaction = false;
00339
00340 if (m_pTransaction == NULL)
00341 {
00342
00343 bQuickieTransaction = true;
00344 }
00345
00346 if (QueryArray.size() > 1)
00347 {
00348 if (bQuickieTransaction)
00349 {
00350 BeginTransaction();
00351 if (GetErrorCode() != DATABASE_LAYER_OK)
00352 {
00353 wxLogError(_("Unable to start transaction"));
00354 ThrowDatabaseException();
00355 return NULL;
00356 }
00357 }
00358
00359
00360 for (unsigned int i=0; i<QueryArray.size()-1; i++)
00361 {
00362 RunQuery(QueryArray[i], false);
00363 if (GetErrorCode() != DATABASE_LAYER_OK)
00364 {
00365 ThrowDatabaseException();
00366 return NULL;
00367 }
00368 }
00369
00370
00371 if (bQuickieTransaction)
00372 {
00373 Commit();
00374 if (GetErrorCode() != DATABASE_LAYER_OK)
00375 {
00376 ThrowDatabaseException();
00377 return NULL;
00378 }
00379 }
00380 }
00381
00382 isc_tr_handle pQueryTransaction = NULL;
00383 bool bManageTransaction = false;
00384 if (bQuickieTransaction)
00385 {
00386 bManageTransaction = true;
00387 int nReturn = isc_start_transaction(m_Status, &pQueryTransaction, 1, &m_pDatabase, 0 , NULL);
00388 if (nReturn != 0)
00389 {
00390 InterpretErrorCodes();
00391 ThrowDatabaseException();
00392 }
00393 }
00394 else
00395 {
00396 pQueryTransaction = m_pTransaction;
00397 }
00398
00399 isc_stmt_handle pStatement = NULL;
00400 int nReturn = isc_dsql_allocate_statement(m_Status, &m_pDatabase, &pStatement);
00401 if (nReturn != 0)
00402 {
00403 InterpretErrorCodes();
00404
00405
00406
00407 isc_rollback_transaction(m_Status, &pQueryTransaction);
00408
00409 ThrowDatabaseException();
00410 return NULL;
00411 }
00412
00413 wxCharBuffer sqlBuffer = ConvertToUnicodeStream(QueryArray[QueryArray.size()-1]);
00414 nReturn = isc_dsql_prepare(m_Status, &pQueryTransaction, &pStatement, 0, (char*)(const char*)sqlBuffer, 1, NULL);
00415 if (nReturn != 0)
00416 {
00417 InterpretErrorCodes();
00418
00419
00420
00421 isc_rollback_transaction(m_Status, &pQueryTransaction);
00422
00423 ThrowDatabaseException();
00424 return NULL;
00425 }
00426
00427
00428
00429 XSQLDA* pOutputSqlda = (XSQLDA*)malloc(XSQLDA_LENGTH(1));
00430 pOutputSqlda->sqln = 1;
00431 pOutputSqlda->version = SQLDA_VERSION1;
00432
00433
00434 nReturn = isc_dsql_describe(m_Status, &pStatement, 1, pOutputSqlda);
00435 if (nReturn != 0)
00436 {
00437 free(pOutputSqlda);
00438 InterpretErrorCodes();
00439
00440
00441
00442 isc_rollback_transaction(m_Status, &pQueryTransaction);
00443
00444 ThrowDatabaseException();
00445 return NULL;
00446 }
00447
00448 if (pOutputSqlda->sqld > pOutputSqlda->sqln)
00449 {
00450 int nColumns = pOutputSqlda->sqld;
00451 free(pOutputSqlda);
00452 pOutputSqlda = (XSQLDA*)malloc(XSQLDA_LENGTH(nColumns));
00453 pOutputSqlda->sqln = nColumns;
00454 pOutputSqlda->version = SQLDA_VERSION1;
00455 nReturn = isc_dsql_describe(m_Status, &pStatement, 1, pOutputSqlda);
00456 if (nReturn != 0)
00457 {
00458 free(pOutputSqlda);
00459 InterpretErrorCodes();
00460
00461
00462
00463 isc_rollback_transaction(m_Status, &pQueryTransaction);
00464
00465 ThrowDatabaseException();
00466 return NULL;
00467 }
00468 }
00469
00470
00471 FirebirdResultSet* pResultSet = new FirebirdResultSet(m_pDatabase, pQueryTransaction, pStatement, pOutputSqlda, true, bManageTransaction);
00472 pResultSet->SetEncoding(GetEncoding());
00473 if (pResultSet->GetErrorCode() != DATABASE_LAYER_OK)
00474 {
00475 SetErrorCode(pResultSet->GetErrorCode());
00476 SetErrorMessage(pResultSet->GetErrorMessage());
00477
00478
00479
00480 isc_rollback_transaction(m_Status, &pQueryTransaction);
00481
00482
00483
00484 #ifndef DONT_USE_DATABASE_LAYER_EXCEPTIONS
00485 try
00486 {
00487 #endif
00488 delete pResultSet;
00489 #ifndef DONT_USE_DATABASE_LAYER_EXCEPTIONS
00490 }
00491 catch (DatabaseLayerException& e)
00492 {
00493 }
00494 #endif
00495
00496 ThrowDatabaseException();
00497 }
00498
00499
00500 nReturn = isc_dsql_execute(m_Status, &pQueryTransaction, &pStatement, 1, NULL);
00501 if (nReturn != 0)
00502 {
00503 InterpretErrorCodes();
00504
00505
00506
00507 isc_rollback_transaction(m_Status, &pQueryTransaction);
00508
00509
00510
00511 #ifndef DONT_USE_DATABASE_LAYER_EXCEPTIONS
00512 try
00513 {
00514 #endif
00515 delete pResultSet;
00516 #ifndef DONT_USE_DATABASE_LAYER_EXCEPTIONS
00517 }
00518 catch (DatabaseLayerException& e)
00519 {
00520 }
00521 #endif
00522
00523 ThrowDatabaseException();
00524 return NULL;
00525 }
00526
00527
00528
00529 LogResultSetForCleanup(pResultSet);
00530 return pResultSet;
00531 }
00532 else
00533 return NULL;
00534 }
00535 else
00536 {
00537 wxLogError(_("Database handle is NULL"));
00538 return NULL;
00539 }
00540 }
00541
00542 PreparedStatement* FirebirdDatabaseLayer::PrepareStatement(const wxString& strQuery)
00543 {
00544 ResetErrorCodes();
00545
00546 FirebirdPreparedStatement* pStatement = FirebirdPreparedStatement::CreateStatement(m_pDatabase, m_pTransaction, strQuery, GetEncoding());
00547 if (pStatement && (pStatement->GetErrorCode() != DATABASE_LAYER_OK))
00548 {
00549 SetErrorCode(pStatement->GetErrorCode());
00550 SetErrorMessage(pStatement->GetErrorMessage());
00551 wxDELETE(pStatement);
00552
00553 ThrowDatabaseException();
00554 }
00555
00556 LogStatementForCleanup(pStatement);
00557 return pStatement;
00558 }
00559
00560 int FirebirdDatabaseLayer::TranslateErrorCode(int nCode)
00561 {
00562
00563
00564 return nCode;
00565 }
00566
00567 wxString FirebirdDatabaseLayer::TranslateErrorCodeToString(int nCode, ISC_STATUS_ARRAY status)
00568 {
00569 char szError[512];
00570 wxString strReturn;
00571 if (nCode < -900)
00572 {
00573 long *pVector = status;
00574 isc_interprete(szError, &pVector);
00575
00576 strReturn = wxString::Format(_("%s\n"), szError);
00577 while (isc_interprete(szError, &pVector))
00578 {
00579
00580 strReturn += wxString::Format(_("%s\n"), szError);
00581 }
00582 }
00583 else
00584 {
00585 isc_sql_interprete(nCode, szError, sizeof(szError));
00586 wxCharBuffer systemEncoding = wxLocale::GetSystemEncodingName().mb_str(*wxConvCurrent);
00587 strReturn = DatabaseStringConverter::ConvertFromUnicodeStream(szError, (const char*)systemEncoding);
00588 }
00589
00590 return strReturn;
00591 }
00592
00593 void FirebirdDatabaseLayer::InterpretErrorCodes()
00594 {
00595 wxLogDebug(_("FirebirdDatabaseLayer::InterpretErrorCodes()\n"));
00596
00597 long nSqlCode = isc_sqlcode(m_Status);
00598 SetErrorMessage(FirebirdDatabaseLayer::TranslateErrorCodeToString(nSqlCode, m_Status));
00599 if (nSqlCode < -900)
00600 {
00601 SetErrorCode(FirebirdDatabaseLayer::TranslateErrorCode(m_Status[1]));
00602 }
00603 else
00604 {
00605 SetErrorCode(FirebirdDatabaseLayer::TranslateErrorCode(nSqlCode));
00606 }
00607 }
00608