ODBCConnection.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. //
  2. // Copyright (c) 2008-2015 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "../../Precompiled.h"
  23. #include "../../Database/DatabaseEvents.h"
  24. #include "../../IO/Log.h"
  25. #include <sqlext.h>
  26. namespace Urho3D
  27. {
  28. DbConnection::DbConnection(Context* context, const String& connectionString) :
  29. Object(context),
  30. connectionString_(connectionString)
  31. {
  32. try
  33. {
  34. connectionImpl_ = nanodbc::connection(connectionString.CString());
  35. }
  36. catch (std::runtime_error& e)
  37. {
  38. HandleRuntimeError("Could not connect", e.what());
  39. }
  40. }
  41. DbConnection::~DbConnection()
  42. {
  43. try
  44. {
  45. Finalize();
  46. connectionImpl_.disconnect();
  47. }
  48. catch (std::runtime_error& e)
  49. {
  50. // This should not happen after finalizing the connection, log error in Release but assert in Debug
  51. HandleRuntimeError("Could not disconnect", e.what());
  52. assert(false);
  53. }
  54. }
  55. void DbConnection::Finalize()
  56. {
  57. // TODO
  58. }
  59. DbResult DbConnection::Execute(const String& sql, bool useCursorEvent)
  60. {
  61. DbResult result;
  62. try
  63. {
  64. result.resultImpl_ = nanodbc::execute(connectionImpl_, sql.Trimmed().CString());
  65. unsigned numCols = (unsigned)result.resultImpl_.columns();
  66. if (numCols)
  67. {
  68. result.columns_.Resize(numCols);
  69. for (unsigned i = 0; i < numCols; ++i)
  70. result.columns_[i] = result.resultImpl_.column_name((short)i).c_str();
  71. bool filtered = false;
  72. bool aborted = false;
  73. while (result.resultImpl_.next())
  74. {
  75. VariantVector colValues(numCols);
  76. for (unsigned i = 0; i < numCols; ++i)
  77. {
  78. if (!result.resultImpl_.is_null((short)i))
  79. {
  80. // We can only bind primitive data type that our Variant class supports
  81. switch (result.resultImpl_.column_c_datatype((short)i))
  82. {
  83. case SQL_C_LONG:
  84. colValues[i] = result.resultImpl_.get<int>((short)i);
  85. if (result.resultImpl_.column_datatype((short)i) == SQL_BIT)
  86. colValues[i] = colValues[i] != 0;
  87. break;
  88. case SQL_C_FLOAT:
  89. colValues[i] = result.resultImpl_.get<float>((short)i);
  90. break;
  91. case SQL_C_DOUBLE:
  92. colValues[i] = result.resultImpl_.get<double>((short)i);
  93. break;
  94. default:
  95. // All other types are stored using their string representation in the Variant
  96. colValues[i] = result.resultImpl_.get<nanodbc::string_type>((short)i).c_str();
  97. break;
  98. }
  99. }
  100. }
  101. if (useCursorEvent)
  102. {
  103. using namespace DbCursor;
  104. VariantMap& eventData = GetEventDataMap();
  105. eventData[P_DBCONNECTION] = this;
  106. eventData[P_RESULTIMPL] = &result.resultImpl_;
  107. eventData[P_SQL] = sql;
  108. eventData[P_NUMCOLS] = numCols;
  109. eventData[P_COLVALUES] = colValues;
  110. eventData[P_COLHEADERS] = result.columns_;
  111. eventData[P_FILTER] = false;
  112. eventData[P_ABORT] = false;
  113. SendEvent(E_DBCURSOR, eventData);
  114. filtered = eventData[P_FILTER].GetBool();
  115. aborted = eventData[P_ABORT].GetBool();
  116. }
  117. if (!filtered)
  118. result.rows_.Push(colValues);
  119. if (aborted)
  120. break;
  121. }
  122. }
  123. result.numAffectedRows_ = numCols ? -1 : result.resultImpl_.affected_rows();
  124. }
  125. catch (std::runtime_error& e)
  126. {
  127. HandleRuntimeError("Could not execute", e.what());
  128. }
  129. return result;
  130. }
  131. void DbConnection::HandleRuntimeError(const char* message, const char* cause)
  132. {
  133. StringVector tokens = (String(cause) + "::").Split(':'); // Added "::" as sentinels against unexpected cause format
  134. LOGERRORF("%s: nanodbc:%s:%s", message, tokens[1].CString(), tokens[2].CString());
  135. }
  136. }