Version: 1.0.0
tds_preparedstatement.cpp
Go to the documentation of this file.
1 #include "wx/database/wxprec.h"
2 
3 #if wxUSE_DATABASE_TDS
4 
5 // ctor
6 wxTdsPreparedStatement::wxTdsPreparedStatement(TDSSOCKET* pDatabase, TDSDYNAMIC* pStatement, const wxString& strQuery)
8 {
9  m_pDatabase = pDatabase;
10  m_pStatement = pStatement;
11  m_strOriginalQuery = strQuery;
12 }
13 
14 // dtor
16 {
17  Close();
18 }
19 
21 {
23 
25 
26  tds_submit_unprepare(m_pDatabase, m_pStatement);
27 
28  if (m_pStatement != NULL)
29  tds_release_dynamic(&m_pStatement);
30 
31  // Double check that result sets are de-allocated
33 }
34 
36 {
37  int rc;
38  int result_type;
39  TDS_INT8 saved_rows_affected = 0; //AML
40  while ((rc = tds_process_tokens(m_pDatabase, &result_type, NULL, TDS_TOKEN_RESULTS)) == TDS_SUCCESS)
41  {
42  switch (result_type)
43  {
44  case TDS_DONE_RESULT:
45  case TDS_DONEPROC_RESULT:
46  /* ignore possible spurious result (TDS7+ send it) */
47  case TDS_STATUS_RESULT:
48  break;
49  case TDS_DONEINPROC_RESULT:
50  saved_rows_affected = m_pDatabase->rows_affected;
51  break;
52  case TDS_ROWFMT_RESULT:
53  case TDS_COMPUTEFMT_RESULT:
54  case TDS_DESCRIBE_RESULT:
55  break;
56  case TDS_ROW_RESULT:
57  //fprintf(stderr, "Warning: wxTdsPreparedStatement query should not return results. Type: %d\n", result_type);
58  if (m_pDatabase->current_results && m_pDatabase->current_results->num_cols > 0)
59  {
60  while (tds_process_tokens(m_pDatabase, &result_type, NULL, TDS_STOPAT_ROWFMT|TDS_RETURN_DONE|TDS_RETURN_ROW) == TDS_SUCCESS)
61  {
62  //fprintf(stderr, "Warning: wxTdsPreparedStatement TDS_ROW_RESULT query should not return results. Type: %d\n", result_type);
63  if (result_type != TDS_ROW_RESULT)
64  break;
65  if (!m_pDatabase->current_results)
66  continue;
67  }
68  }
69  return;
70  default:
71  //fprintf(stderr, "Error: wxTdsPreparedStatement query should not return results. Type: %d\n", result_type);
72  return;
73  }
74  }
75 
76  if (m_pDatabase != NULL)
77  m_pDatabase->rows_affected = saved_rows_affected;
78 
79  // Clean up after ourselves
80  if (m_pDatabase != NULL)
81  tds_free_all_results(m_pDatabase);
82 
83  if (rc == TDS_FAIL)
84  {
85  //fprintf(stderr, "tds_process_tokens() returned TDS_FAIL\n");
88  return;
89  }
90  else if (rc != TDS_NO_MORE_RESULTS)
91  {
92  //fprintf(stderr, "tds_process_tokens() unexpected return\n");
95  return;
96  }
97 }
98 
100 {
101  TDSPARAMINFO* pParameters = m_pStatement->params;
102  while ((pParameters == NULL) || (nPosition > (pParameters->num_cols)))
103  {
104  pParameters = tds_alloc_param_result(pParameters);
105  if (pParameters == NULL)
106  {
107  //fprintf(stderr, "out of memory!\n");
109  SetErrorMessage(wxT("out of memory"));
111  return;
112  }
113  }
114  m_pStatement->params = pParameters;
115 }
116 
117 // set parameter
118 void wxTdsPreparedStatement::SetParamInt(int nPosition, int nValue)
119 {
120  //fprintf(stderr, "Setting param %d to int %d\n", nPosition, nValue);
121  ResetErrorCodes();
122 
123  AllocateParameter(nPosition);
124  TDSCOLUMN* curcol = m_pStatement->params->columns[nPosition-1];
125  tds_set_param_type(m_pDatabase->conn, curcol, SYBINTN);
126  curcol->column_size = sizeof(TDS_INT);
127  curcol->on_server.column_size = sizeof(TDS_INT);
128  curcol->column_cur_size = sizeof(TDS_INT);
129 
130  tds_alloc_param_data(curcol);
131  memcpy(curcol->column_data, &nValue, sizeof(nValue));
132 }
133 
134 void wxTdsPreparedStatement::SetParamDouble(int nPosition, double dblValue)
135 {
136  //fprintf(stderr, "Setting param %d to double %f\n", nPosition, dblValue);
137  ResetErrorCodes();
138 
139  AllocateParameter(nPosition);
140  TDSCOLUMN* curcol = m_pStatement->params->columns[nPosition-1];
141  tds_set_param_type(m_pDatabase->conn, curcol, SYBFLTN);
142  curcol->column_size = sizeof(TDS_FLOAT);
143  curcol->on_server.column_size = sizeof(TDS_FLOAT);
144  curcol->column_cur_size = sizeof(TDS_FLOAT);
145 
146  tds_alloc_param_data(curcol);
147  memcpy(curcol->column_data, &dblValue, sizeof(dblValue));
148 }
149 
150 void wxTdsPreparedStatement::SetParamString(int nPosition, const wxString& strValue)
151 {
152  //fprintf(stderr, "Setting param %d to string '%s'\n", nPosition, strValue.c_str());
153  ResetErrorCodes();
154 
155  // AML
156  // it will not be possible to set a UNICODE parameter string unless
157  // we set up curcol
158 
159  AllocateParameter(nPosition);
160 
161  wxCharBuffer valueBuffer = ConvertToUnicodeStream(strValue);
162  int nLength = GetEncodedStreamLength(strValue);
163 
164  //const wchar_t* valueBuffer = strValue.wc_str();
165 
166  //const char* valueBuffer = strValue.mb_str();
167  //int nLength = strValue.Len();
168  TDSCOLUMN* curcol = m_pStatement->params->columns[nPosition-1];
169  tds_set_param_type(m_pDatabase->conn, curcol, XSYBNVARCHAR);
170  curcol->column_size = nLength+1;
171  curcol->column_cur_size = nLength;
172 
173  tds_alloc_param_data(curcol);
174  memcpy(curcol->column_data, valueBuffer, nLength+1);
175 }
176 
177 void wxTdsPreparedStatement::SetParamNull(int nPosition)
178 {
179  //fprintf(stderr, "Setting param %d to NULL\n", nPosition);
180  ResetErrorCodes();
181 
182  AllocateParameter(nPosition);
183  TDSCOLUMN* curcol = m_pStatement->params->columns[nPosition-1];
184  tds_set_param_type(m_pDatabase->conn, curcol, SYBVARCHAR);
185 
186  tds_alloc_param_data(curcol);
187 
188  //tds_alloc_param_data(m_pParameters, curcol);
189  //memcpy(curcol->column_data, valueBuffer, nLength);
190 }
191 
192 void wxTdsPreparedStatement::SetParamBlob(int nPosition, const void* pData, long nDataLength)
193 {
194  //fprintf(stderr, "Setting param %d to blob\n", nPosition);
195  ResetErrorCodes();
196 
197  AllocateParameter(nPosition);
198  CONV_RESULT cr;
199  //fprintf(stderr, "data length = %ld\n", nDataLength);
200  int ret = tds_convert(tds_get_ctx(this->m_pDatabase), SYBBINARY, (TDS_CHAR*)pData, nDataLength, SYBVARBINARY, &cr);
201  //fprintf(stderr, "tds_convert returned %d, data length = %ld\n", ret, nDataLength);
202  TDSCOLUMN* curcol = m_pStatement->params->columns[nPosition-1];
203  tds_set_param_type(m_pDatabase->conn, curcol, SYBVARBINARY);
204  curcol->column_size = ret;
205  curcol->on_server.column_size = ret;
206  curcol->column_cur_size = ret;
207 
208  tds_alloc_param_data(curcol);
209  //fprintf(stderr, "Ready for memcpy of %d bytes\n", ret);
210  memcpy(curcol->column_data, cr.ib, ret);
211  int x = sizeof(cr.ib);
212  //fprintf(stderr, "Memcpy completed\n");
213  free(cr.ib);
214 }
215 
216 void wxTdsPreparedStatement::SetParamDate(int nPosition, const wxDateTime& dateValue)
217 {
218  //fprintf(stderr, "Setting param %d to date %s\n", nPosition, dateValue.Format().c_str());
219  ResetErrorCodes();
220 
221  AllocateParameter(nPosition);
222 
223  wxString dateAsString = dateValue.Format(_("%Y-%m-%d %H:%M:%S"));
224  //fprintf(stderr, "Setting param %d to date %s\n", nPosition, dateAsString.c_str());
225 
226  // for some unknown reason when sending as a SYBDATETIME
227  // sub-minute information is being lost (as if it is a SMALLDATETIME)
228  // so send as a SYBVARCHAR instead
229 
230 #if 0
231  CONV_RESULT cr;
232  wxCharBuffer dateCharBuffer = ConvertToUnicodeStream(dateAsString);
233  int bufferLength = GetEncodedStreamLength(dateAsString);
234  int ret = tds_convert(tds_get_ctx(this->m_pDatabase), SYBVARCHAR, (TDS_CHAR*)(const char*)dateCharBuffer, bufferLength, SYBDATETIME, &cr);
235  //fprintf(stderr, "tds_convert returned %d, sizeof TDS_DATETIME = %d\n", ret, sizeof(TDS_DATETIME));
236 
237  int valueSize = (ret < 0) ? sizeof(TDS_DATETIME) : ret;
238 
239  TDSCOLUMN* curcol = m_pStatement->params->columns[nPosition-1];
240  tds_set_param_type(m_pDatabase->conn, curcol, SYBDATETIMN);
241  curcol->column_size = valueSize;
242  curcol->on_server.column_size = valueSize;
243  curcol->column_cur_size = valueSize;
244 
245  tds_alloc_param_data(curcol);
246  memcpy(curcol->column_data, &cr.dt, valueSize);
247 #else
248  SetParamString(nPosition, dateAsString);
249 #endif
250 }
251 
252 void wxTdsPreparedStatement::SetParamBool(int nPosition, bool bValue)
253 {
254  //fprintf(stderr, "Setting param %d to boolean %d\n", nPosition, bValue);
255  ResetErrorCodes();
256 
257  AllocateParameter(nPosition);
258  TDSCOLUMN* curcol = m_pStatement->params->columns[nPosition-1];
259  tds_set_param_type(m_pDatabase->conn, curcol, SYBBITN);
260  curcol->column_size = sizeof(bool);
261  curcol->on_server.column_size = sizeof(bool);
262  curcol->column_cur_size = sizeof(bool); // TDS_DATETIME
263 
264  tds_alloc_param_data(curcol);
265  memcpy(curcol->column_data, &bValue , sizeof(bool));
266 }
267 
269 {
270  ResetErrorCodes();
271 
272  int nReturn = 0;
273  // It would probably be better to iterate through the query string to make sure that
274  // none of the '?' are in string literals
275  //fprintf(stderr, "Freq of '%s' = %d\n", m_strOriginalQuery, m_strOriginalQuery.Freq('?'));
276  //AML start
277  //nReturn = m_strOriginalQuery.Freq('?');
278  bool bInStringLiteral = false;
279  for (size_t i = 0; i < m_strOriginalQuery.length(); i++)
280  {
281  wxChar character = m_strOriginalQuery[i];
282  if ('\'' == character)
283  {
284  // Signify that we are inside a string literal inside the SQL
285  bInStringLiteral = !bInStringLiteral;
286  }
287  else if (('?' == character) && !bInStringLiteral)
288  {
289  nReturn++;
290  }
291  }
292  //AML end
293 
294  return nReturn;
295 }
296 
298 {
299  //fprintf(stderr, "Running statement without results\n");
300  ResetErrorCodes();
301 
303 
304  // Execute the query
305  int nReturn = tds_submit_execute(m_pDatabase, m_pStatement);
306  if (nReturn != TDS_SUCCESS)
307  {
308  //fprintf(stderr, "tds_submit_execute() failed for statement '%s'\n", m_pStatement->query);
312  }
313 
314  //fprintf(stderr, "Statement executed. Freeing results\n");
316 
317  return /*AML wxDATABASE_QUERY_RESULT_ERROR*/m_pDatabase->rows_affected;
318 }
319 
321 {
322  ResetErrorCodes();
323 
324  //fprintf(stderr, "Running statement with results\n");
326 
327  // Execute the query
328  int nReturn = tds_submit_execute(m_pDatabase, m_pStatement);
329  if (nReturn != TDS_SUCCESS)
330  {
331  //fprintf(stderr, "tds_submit_execute() failed for query '%s'\n", m_pStatement->query);
332  //fprintf(stderr, "tds_submit_execute() return code: %d\n", nReturn);
336  return NULL;
337  }
338  wxTdsResultSet* pResultSet = new wxTdsResultSet(m_pDatabase);
339  if (pResultSet)
340  pResultSet->SetEncoding(GetEncoding());
341 
342  LogResultSetForCleanup(pResultSet);
343  //fprintf(stderr, "Returning prepared statement result set\n");
344  return pResultSet;
345 }
346 
348 {
349  return 0;
350 }
351 
353 {
354  wxTdsDatabase* pDatabase = wxTdsDatabase::LookupTdsLayer(/*AML this->m_pDatabase->tds_ctx*/tds_get_ctx(this->m_pDatabase));
355  if (pDatabase != NULL)
356  {
357  SetErrorCode(pDatabase->GetErrorCode());
358  SetErrorMessage(pDatabase->GetErrorMessage());
359  }
360 }
361 
362 #endif//wxUSE_DATABASE_TDS
virtual void SetParamDate(int nPosition, const wxDateTime &dateValue)
Set the parameter at the 1-based position to a wxDateTime value.
virtual void Close()
Close the result set (call wxDatabase::ClosePreparedStatement() instead on the statement)
virtual void SetParamBlob(int nPosition, const void *pData, long nDataLength)
Set the parameter at the 1-based position to a Blob value.
virtual void SetParamString(int nPosition, const wxString &strValue)
Set the parameter at the 1-based position to a wxString value.
virtual int GetParameterCount()
int FindStatementAndAdjustPositionIndex(int *pPosition)
wxTdsPreparedStatement(TDSSOCKET *pDatabase, TDSDYNAMIC *pStatement, const wxString &strQuery)
static wxTdsDatabase * LookupTdsLayer(const TDSCONTEXT *pContext)
void SetErrorInformationFromDatabaseLayer()
virtual wxDatabaseResultSet * RunQueryWithResults()
Run an insert, update, or delete query on the database.
TDSSOCKET * m_pDatabase
Definition: tds_database.h:102
virtual void SetParamBool(int nPosition, bool bValue)
Set the parameter at the 1-based position to a boolean value.
const wxString & GetErrorMessage()
virtual ~wxTdsPreparedStatement()
#define wxDATABASE_ALLOCATION_ERROR
Definition: errorcodes.h:10
virtual void SetParamNull(int nPosition)
Set the parameter at the 1-based position to a NULL value.
void SetErrorMessage(const wxString &strErrorMessage)
void LogResultSetForCleanup(wxDatabaseResultSet *pResultSet)
Add result set object pointer to the list for "garbage collection".
void SetEncoding(wxFontEncoding encoding)
void AllocateParameter(int nPosition)
virtual size_t GetEncodedStreamLength(const wxString &inputString)
void CloseResultSets()
Close all result set objects that have been generated but not yet closed.
void SetErrorCode(int nErrorCode)
const wxCSConv * GetEncoding()
virtual void SetParamInt(int nPosition, int nValue)
Set the parameter at the 1-based position to an int value.
virtual int RunQuery()
Run an insert, update, or delete query on the database.
virtual const wxCharBuffer ConvertToUnicodeStream(const wxString &inputString)
virtual void SetParamDouble(int nPosition, double dblValue)
Set the parameter at the 1-based position to a double value.