Version: 1.0.0
postgresql_preparedstatement.cpp
Go to the documentation of this file.
1 #include "wx/database/wxprec.h"
2 
3 #if wxUSE_DATABASE_POSTGRESQL
4 
5 #include "wx/tokenzr.h"
6 
7 #include "wx/arrimpl.cpp"
8 WX_DEFINE_OBJARRAY(ArrayOfPostgresPreparedStatementWrappers);
9 
12 {
13  m_pInterface = pInterface;
14 }
15 
16 wxPostgresPreparedStatement::wxPostgresPreparedStatement(wxDynamicPostgresInterface* pInterface, PGconn* pDatabase, const wxString& strSQL, const wxString& strStatementName)
18 {
19  m_pInterface = pInterface;
20  AddStatement(pDatabase, strSQL, strStatementName);
21 }
22 
23 
25 {
26  Close();
27 }
28 
29 
31 {
33  m_Statements.Clear();
34 }
35 
36 void wxPostgresPreparedStatement::AddStatement(PGconn* pDatabase, const wxString& strSQL, const wxString& strStatementName)
37 {
38  wxPostgresPreparedStatementWrapper Statement(m_pInterface, pDatabase, strSQL, strStatementName);
39  Statement.SetEncoding(GetEncoding());
40  m_Statements.push_back(Statement);
41 }
42 
44 {
45  wxArrayString Queries = ParseQueries(strSQL);
46 
47  wxArrayString::iterator start = Queries.begin();
48  wxArrayString::iterator stop = Queries.end();
49 
50  wxPostgresPreparedStatement* pStatement = new wxPostgresPreparedStatement(pInterface);
51  const char* strEncoding = pInterface->GetPQencodingToChar()(pInterface->GetPQclientEncoding()(pDatabase));
52  wxCSConv conv((const wxChar*)strEncoding);
53  pStatement->SetEncoding(&conv);
54  while (start != stop)
55  {
57  pStatement->AddStatement(pDatabase, (*start), strName);
58  wxCharBuffer nameBuffer = wxDatabaseStringConverter::ConvertToUnicodeStream(strName, strEncoding);
59  wxCharBuffer sqlBuffer = wxDatabaseStringConverter::ConvertToUnicodeStream(TranslateSQL((*start)), strEncoding);
60  PGresult* pResult = pInterface->GetPQprepare()(pDatabase, nameBuffer, sqlBuffer, 0, NULL);
61  if (pResult == NULL)
62  {
63  delete pStatement;
64  return NULL;
65  }
66 
67  if (pInterface->GetPQresultStatus()(pResult) != PGRES_COMMAND_OK)
68  {
69  pStatement->SetErrorCode(wxPostgresDatabase::TranslateErrorCode(pInterface->GetPQresultStatus()(pResult)));
71  pInterface->GetPQresultErrorMessage()(pResult), strEncoding));
72  pInterface->GetPQclear()(pResult);
73  pStatement->ThrowDatabaseException();
74  return pStatement;
75  }
76  pInterface->GetPQclear()(pResult);
77 
78  start++;
79  }
80 
81  // Success? Return the statement
82  return pStatement;
83 }
84 
85 // set field
86 void wxPostgresPreparedStatement::SetParamInt(int nPosition, int nValue)
87 {
88  int nIndex = FindStatementAndAdjustPositionIndex(&nPosition);
89  if (nIndex > -1)
90  {
91  m_Statements[nIndex].SetParam(nPosition, nValue);
92  }
93 }
94 
95 void wxPostgresPreparedStatement::SetParamDouble(int nPosition, double dblValue)
96 {
97  int nIndex = FindStatementAndAdjustPositionIndex(&nPosition);
98  if (nIndex > -1)
99  {
100  m_Statements[nIndex].SetParam(nPosition, dblValue);
101  }
102 }
103 
104 void wxPostgresPreparedStatement::SetParamString(int nPosition, const wxString& strValue)
105 {
106  int nIndex = FindStatementAndAdjustPositionIndex(&nPosition);
107  if (nIndex > -1)
108  {
109  m_Statements[nIndex].SetParam(nPosition, strValue);
110  }
111 }
112 
114 {
115  int nIndex = FindStatementAndAdjustPositionIndex(&nPosition);
116  if (nIndex > -1)
117  {
118  m_Statements[nIndex].SetParam(nPosition);
119  }
120 }
121 
122 void wxPostgresPreparedStatement::SetParamBlob(int nPosition, const void* pData, long nDataLength)
123 {
124  int nIndex = FindStatementAndAdjustPositionIndex(&nPosition);
125  if (nIndex > -1)
126  {
127  m_Statements[nIndex].SetParam(nPosition, pData, nDataLength);
128  }
129 }
130 
131 void wxPostgresPreparedStatement::SetParamDate(int nPosition, const wxDateTime& dateValue)
132 {
133  int nIndex = FindStatementAndAdjustPositionIndex(&nPosition);
134  if (nIndex > -1)
135  {
136  m_Statements[nIndex].SetParam(nPosition, dateValue);
137  }
138 }
139 
140 void wxPostgresPreparedStatement::SetParamBool(int nPosition, bool bValue)
141 {
142  int nIndex = FindStatementAndAdjustPositionIndex(&nPosition);
143  if (nIndex > -1)
144  {
145  m_Statements[nIndex].SetParam(nPosition, bValue);
146  }
147 }
148 
150 {
151  int nParameters = 0;
152 
153  for (unsigned int i=0; i<(m_Statements.size()); i++)
154  {
155  nParameters += m_Statements[i].GetParameterCount();
156  }
157  return nParameters;
158 }
159 
160 
162 {
163  // Iterate through the statements and have them run their queries
164  int nRows = wxDATABASE_QUERY_RESULT_ERROR;
165  for (unsigned int i=0; i<(m_Statements.size()); i++)
166  {
167  nRows = m_Statements[i].RunQuery();
169  {
174  }
175  }
176  return nRows;
177 }
178 
180 {
181  for (unsigned int i=0; i<(m_Statements.size()-1); i++)
182  {
183  m_Statements[i].RunQuery();
185  {
189  return NULL;
190  }
191  }
192  wxPostgresPreparedStatementWrapper* pLastStatement = &(m_Statements[m_Statements.size()-1]);
193  wxDatabaseResultSet* pResultSet = pLastStatement->RunQueryWithResults();
194  if (pLastStatement->GetErrorCode() != wxDATABASE_OK)
195  {
196  SetErrorCode(pLastStatement->GetErrorCode());
197  SetErrorMessage(pLastStatement->GetErrorMessage());
199  }
200 
201  LogResultSetForCleanup(pResultSet);
202  return pResultSet;
203 }
204 
206 {
207  // Just come up with a string prefixed with "databaselayer_" and 10 random characters
208  wxString strReturn = _("databaselayer_");
209  for (int i=0; i<10; i++)
210  {
211  strReturn << (int) (10.0*rand()/(RAND_MAX+1.0));
212  }
213  return strReturn;
214 }
215 
217 {
218  if (m_Statements.size() == 0)
219  return 0;
220 
221  // Go through all the elements in the vector
222  // Get the number of parameters in each statement
223  // Adjust the nPosition for the the broken up statements
224  for (unsigned int i=0; i<m_Statements.size(); i++)
225  {
226  int nParametersInThisStatement = m_Statements[i].GetParameterCount();
227 
228  if (*pPosition > nParametersInThisStatement)
229  {
230  *pPosition -= nParametersInThisStatement; // Decrement the position indicator by the number of parameters in this statement
231  }
232  else
233  {
234  // We're in the correct statement, return the index
235  return i;
236  }
237  }
238  return -1;
239 }
240 
241 wxString wxPostgresPreparedStatement::TranslateSQL(const wxString& strOriginalSQL)
242 {
243  int nParameterIndex = 1;
244  wxString strReturn = wxEmptyString;//strOriginalSQL;
245  /*
246  int nFound = strReturn.Replace(_("?"), wxString::Format(_("$%d"), nParameterIndex), false);
247  while (nFound != 0)
248  {
249  nParameterIndex++;
250  nFound = strReturn.Replace(_("?"), wxString::Format(_("$%d"), nParameterIndex), false);
251  }
252  */
253  bool bInStringLiteral = false;
254  size_t len = strOriginalSQL.length();
255  for (size_t i = 0; i < len; i++)
256  {
257  wxChar character = strOriginalSQL[i];
258  if ('\'' == character)
259  {
260  // Signify that we are inside a string literal inside the SQL
261  bInStringLiteral = !bInStringLiteral;
262  // Pass the character on to the return string
263  strReturn += character;
264  }
265  else
266  {
267  if ('?' == character)
268  {
269  if (bInStringLiteral)
270  {
271  // Pass the character on to the return string
272  strReturn += character;
273  }
274  else
275  {
276  // Replace the question mark with a prepared statement placeholder
277  strReturn += wxString::Format(_("$%d"), nParameterIndex);
278  nParameterIndex++;
279  }
280  }
281  else
282  {
283  // Pass the character on to the return string
284  strReturn += character;
285  }
286  }
287  }
288 
289  return strReturn;
290 }
291 
292 #endif//wxUSE_DATABASE_POSTGRESQL
wxPostgresPreparedStatement(wxDynamicPostgresInterface *pInterface)
virtual void SetParamBool(int nPosition, bool bValue)
Set the parameter at the 1-based position to a boolean value.
static wxPostgresPreparedStatement * CreateStatement(wxDynamicPostgresInterface *pInterface, PGconn *pDatabase, const wxString &strSQL)
PQclientEncodingType GetPQclientEncoding()
virtual int GetParameterCount()
wxDatabaseResultSet * RunQueryWithResults()
ArrayOfPostgresPreparedStatementWrappers m_Statements
void AddStatement(PGconn *pDatabase, const wxString &strSQL, const wxString &strStatementName)
static int TranslateErrorCode(int nCode)
PQencodingToCharType GetPQencodingToChar()
const wxString & GetErrorMessage()
#define wxDATABASE_OK
Definition: errorcodes.h:4
static wxString TranslateSQL(const wxString &strOriginalSQL)
virtual wxDatabaseResultSet * RunQueryWithResults()
Run an insert, update, or delete query on the database.
void SetErrorMessage(const wxString &strErrorMessage)
void LogResultSetForCleanup(wxDatabaseResultSet *pResultSet)
Add result set object pointer to the list for "garbage collection".
wxArrayString ParseQueries(const wxString &strQuery)
PQresultErrorMessageType GetPQresultErrorMessage()
void SetEncoding(wxFontEncoding encoding)
#define wxDATABASE_QUERY_RESULT_ERROR
Definition: errorcodes.h:21
virtual void Close()
Close the result set (call wxDatabase::ClosePreparedStatement() instead on the statement)
virtual void SetParamString(int nPosition, const wxString &strValue)
Set the parameter at the 1-based position to a wxString value.
virtual void SetParamDouble(int nPosition, double dblValue)
Set the parameter at the 1-based position to a double value.
virtual ~wxPostgresPreparedStatement()
static wxString GenerateRandomStatementName()
wxDynamicPostgresInterface * m_pInterface
void CloseResultSets()
Close all result set objects that have been generated but not yet closed.
void SetErrorCode(int nErrorCode)
int FindStatementAndAdjustPositionIndex(int *pPosition)
virtual void SetParamDate(int nPosition, const wxDateTime &dateValue)
Set the parameter at the 1-based position to a wxDateTime value.
virtual wxString ConvertFromUnicodeStream(const char *inputBuffer)
PQresultStatusType GetPQresultStatus()
const wxCSConv * GetEncoding()
virtual int RunQuery()
Run an insert, update, or delete query on the database.
virtual void SetParamNull(int nPosition)
Set the parameter at the 1-based position to a NULL value.
virtual void SetParamBlob(int nPosition, const void *pData, long nDataLength)
Set the parameter at the 1-based position to a Blob value.
virtual const wxCharBuffer ConvertToUnicodeStream(const wxString &inputString)
virtual void SetParamInt(int nPosition, int nValue)
Set the parameter at the 1-based position to an int value.