Version: 1.0.0
postgresql_database.cpp
Go to the documentation of this file.
1 #include "wx/database/wxprec.h"
2 
3 #if wxUSE_DATABASE_POSTGRESQL
4 
5 // ctor
7  : wxDatabase()
8 {
9 #ifndef DONT_USE_DYNAMIC_DATABASE_LINKING
11  if (!m_pInterface->Init())
12  {
14  SetErrorMessage(wxT("Error loading PostgreSQL library"));
15  ThrowDatabaseException();
16  return;
17  }
18 #endif
19  m_strServer = _("localhost");
20  m_strUser = wxT("");
21  m_strPassword = wxT("");
22  m_strDatabase = wxT("");
23  m_strPort = wxT("");
24 }
25 
26 wxPostgresDatabase::wxPostgresDatabase(const wxString& strDatabase)
27  : wxDatabase()
28 {
29 #ifndef DONT_USE_DYNAMIC_DATABASE_LINKING
31  if (!m_pInterface->Init())
32  {
34  SetErrorMessage(wxT("Error loading PostgreSQL library"));
35  ThrowDatabaseException();
36  return;
37  }
38 #endif
39  m_strServer = _("localhost");
40  m_strUser = wxT("");
41  m_strPassword = wxT("");
42  m_strPort = wxT("");
43 
44  Open(strDatabase);
45 }
46 
47 wxPostgresDatabase::wxPostgresDatabase(const wxString& strServer, const wxString& strDatabase)
48  : wxDatabase()
49 {
50 #ifndef DONT_USE_DYNAMIC_DATABASE_LINKING
52  if (!m_pInterface->Init())
53  {
55  SetErrorMessage(wxT("Error loading PostgreSQL library"));
56  ThrowDatabaseException();
57  return;
58  }
59 #endif
60  m_strServer = strServer;
61  m_strUser = wxT("");
62  m_strPassword = wxT("");
63  m_strPort = wxT("");
64 
65  Open(strDatabase);
66 }
67 
68 wxPostgresDatabase::wxPostgresDatabase(const wxString& strDatabase, const wxString& strUser, const wxString& strPassword)
69  : wxDatabase()
70 {
71 #ifndef DONT_USE_DYNAMIC_DATABASE_LINKING
73  if (!m_pInterface->Init())
74  {
76  SetErrorMessage(wxT("Error loading PostgreSQL library"));
77  ThrowDatabaseException();
78  return;
79  }
80 #endif
81  m_strServer = _("localhost");
82  m_strUser = strUser;
83  m_strPassword = strPassword;
84  m_strPort = wxT("");
85 
86  Open(strDatabase);
87 }
88 
89 wxPostgresDatabase::wxPostgresDatabase(const wxString& strServer, const wxString& strDatabase, const wxString& strUser, const wxString& strPassword)
90  : wxDatabase()
91 {
92 #ifndef DONT_USE_DYNAMIC_DATABASE_LINKING
94  if (!m_pInterface->Init())
95  {
97  SetErrorMessage(wxT("Error loading PostgreSQL library"));
98  ThrowDatabaseException();
99  return;
100  }
101 #endif
102  m_strServer = strServer;
103  m_strUser = strUser;
104  m_strPassword = strPassword;
105  m_strPort = wxT("");
106 
107  Open(strDatabase);
108 }
109 
110 wxPostgresDatabase::wxPostgresDatabase(const wxString& strServer, int nPort, const wxString& strDatabase, const wxString& strUser, const wxString& strPassword)
111  : wxDatabase()
112 {
113 #ifndef DONT_USE_DYNAMIC_DATABASE_LINKING
115  if (!m_pInterface->Init())
116  {
117  SetErrorCode(wxDATABASE_ERROR_LOADING_LIBRARY);
118  SetErrorMessage(wxT("Error loading PostgreSQL library"));
119  ThrowDatabaseException();
120  return;
121  }
122 #endif
123  m_strServer = strServer;
124  m_strUser = strUser;
125  m_strPassword = strPassword;
126  m_strPort = wxString::Format(_("%d"), nPort);
127 
128  Open(strDatabase);
129 }
130 
131 // dtor
133 {
134  Close();
135  wxDELETE(m_pInterface);
136 }
137 
138 // open database
140 {
141  ResetErrorCodes();
142 
143  wxCharBuffer serverCharBuffer;
144  const char* pHost = NULL;
145  wxCharBuffer pDatabaseBuffer = ConvertToUnicodeStream(m_strDatabase);
146  const char* pDatabase = pDatabaseBuffer;
147  wxCharBuffer userCharBuffer;
148  const char* pUser = NULL;
149  wxCharBuffer passwordCharBuffer;
150  const char* pPassword = NULL;
151  const char* pTty = NULL;
152  const char* pOptions = NULL;
153  wxCharBuffer portCharBuffer;
154  const char* pPort = NULL;
155 
156  if (m_strServer != _("localhost") && m_strServer != wxT(""))
157  {
158  serverCharBuffer = ConvertToUnicodeStream(m_strServer);
159  pHost = serverCharBuffer;
160  }
161 
162  if (m_strUser != wxT(""))
163  {
164  userCharBuffer = ConvertToUnicodeStream(m_strUser);
165  pUser = userCharBuffer;
166  }
167 
168  if (m_strPassword != wxT(""))
169  {
170  passwordCharBuffer = ConvertToUnicodeStream(m_strPassword);
171  pPassword = passwordCharBuffer;
172  }
173 
174  if (m_strPort != wxT(""))
175  {
176  portCharBuffer = ConvertToUnicodeStream(m_strPort);
177  pPort = portCharBuffer;
178  }
179 
180  m_pDatabase = m_pInterface->GetPQsetdbLogin()(pHost, pPort, pOptions, pTty, pDatabase, pUser, pPassword);
181  if (m_pInterface->GetPQstatus()((PGconn*)m_pDatabase) == CONNECTION_BAD)
182  {
186  return false;
187  }
188 
189  m_pInterface->GetPQsetClientEncoding()((PGconn*)m_pDatabase, "UTF-8");
190  wxCSConv conv((const wxChar*)(m_pInterface->GetPQencodingToChar()(m_pInterface->GetPQclientEncoding()((PGconn*)m_pDatabase))));
191  SetEncoding(&conv);
192 
193  return true;
194 }
195 
196 bool wxPostgresDatabase::Open(const wxString& strDatabase)
197 {
198  m_strDatabase = strDatabase;
199  return Open();
200 }
201 
202 bool wxPostgresDatabase::Open(const wxString& strServer, const wxString& strDatabase)
203 {
204  m_strServer = strServer;
205  m_strUser = wxT("");
206  m_strPassword = wxT("");
207  m_strDatabase = strDatabase;
208  m_strPort = wxT("");
209  return Open();
210 }
211 
212 bool wxPostgresDatabase::Open(const wxString& strDatabase, const wxString& strUser, const wxString& strPassword)
213 {
214  m_strServer = _("localhost");
215  m_strUser = strUser;
216  m_strPassword = strPassword;
217  m_strDatabase = strDatabase;
218  m_strPort = wxT("");
219  return Open();
220 }
221 
222 bool wxPostgresDatabase::Open(const wxString& strServer, const wxString& strDatabase, const wxString& strUser, const wxString& strPassword)
223 {
224  m_strServer = strServer;
225  m_strUser = strUser;
226  m_strPassword = strPassword;
227  m_strDatabase = strDatabase;
228  m_strPort = wxT("");
229  return Open();
230 }
231 
232 bool wxPostgresDatabase::Open(const wxString& strServer, int nPort, const wxString& strDatabase, const wxString& strUser, const wxString& strPassword)
233 {
234  m_strServer = strServer;
235  m_strUser = strUser;
236  m_strPassword = strPassword;
237  m_strDatabase = strDatabase;
238  SetPort(nPort);
239  return Open();
240 }
241 
242 // close database
244 {
245  CloseResultSets();
246  CloseStatements();
247 
248  if (m_pDatabase)
249  {
250  m_pInterface->GetPQfinish()((PGconn*)m_pDatabase);
251  m_pDatabase = NULL;
252  }
253 
254  return true;
255 }
256 
257 void wxPostgresDatabase::SetPort(int nPort)
258 {
259  m_strPort = wxString::Format(_("%d"), nPort);
260 }
261 
263 {
264  if (m_pDatabase)
265  return (m_pInterface->GetPQstatus()((PGconn*)m_pDatabase) != CONNECTION_BAD);
266  else
267  return false;
268 }
269 
270 // transaction support
272 {
273  RunQuery(_("BEGIN"), false);
274 }
275 
277 {
278  RunQuery(_("COMMIT"), false);
279 }
280 
282 {
283  RunQuery(_("ROLLBACK"), false);
284 }
285 
286 
287 // query database
288 int wxPostgresDatabase::RunQuery(const wxString& strQuery, bool WXUNUSED(bParseQuery))
289 {
290  // PostgreSQL takes care of parsing the queries itself so bParseQuery is ignored
291 
292  ResetErrorCodes();
293 
294  wxCharBuffer sqlBuffer = ConvertToUnicodeStream(strQuery);
295  PGresult* pResultCode = m_pInterface->GetPQexec()((PGconn*)m_pDatabase, sqlBuffer);
296  if ((pResultCode == NULL) || (m_pInterface->GetPQresultStatus()(pResultCode) != PGRES_COMMAND_OK))
297  {
300  m_pInterface->GetPQclear()(pResultCode);
303  }
304  else
305  {
306  wxString rowsAffected = ConvertFromUnicodeStream(m_pInterface->GetPQcmdTuples()(pResultCode));
307  long rows = -1;
308  rowsAffected.ToLong(&rows);
309  m_pInterface->GetPQclear()(pResultCode);
310  return (int)rows;
311  }
312 }
313 
315 {
316  ResetErrorCodes();
317 
318  wxCharBuffer sqlBuffer = ConvertToUnicodeStream(strQuery);
319  PGresult* pResultCode = m_pInterface->GetPQexec()((PGconn*)m_pDatabase, sqlBuffer);
320  if ((pResultCode == NULL) || (m_pInterface->GetPQresultStatus()(pResultCode) != PGRES_TUPLES_OK))
321  {
324  m_pInterface->GetPQclear()(pResultCode);
326  return NULL;
327  }
328  else
329  {
330  wxPostgresResultSet* pResultSet = new wxPostgresResultSet(m_pInterface, pResultCode);
331  pResultSet->SetEncoding(GetEncoding());
332  LogResultSetForCleanup(pResultSet);
333  return pResultSet;
334  }
335 }
336 
337 // wxPreparedStatement support
339 {
340  ResetErrorCodes();
341 
343  LogStatementForCleanup(pStatement);
344  return pStatement;
345 }
346 
347 bool wxPostgresDatabase::TableExists(const wxString& table)
348 {
349  // Initialize variables
350  bool bReturn = false;
351  // Keep these variables outside of scope so that we can clean them up
352  // in case of an error
353  wxPreparedStatement* pStatement = NULL;
354  wxDatabaseResultSet* pResult = NULL;
355 
356 #if wxUSE_DATABASE_EXCEPTIONS
357  try
358  {
359 #endif
360  wxString query = _("SELECT COUNT(*) FROM information_schema.tables WHERE table_type='BASE TABLE' AND table_name=?;");
361  pStatement = PrepareStatement(query);
362  if (pStatement)
363  {
364  pStatement->SetParamString(1, table);
365  pResult = pStatement->ExecuteQuery();
366  if (pResult)
367  {
368  if (pResult->Next())
369  {
370  if(pResult->GetResultInt(1) != 0)
371  {
372  bReturn = true;
373  }
374  }
375  }
376  }
377 #if wxUSE_DATABASE_EXCEPTIONS
378  }
379  catch (wxDatabaseException& e)
380  {
381  if (pResult != NULL)
382  {
383  CloseResultSet(pResult);
384  pResult = NULL;
385  }
386 
387  if (pStatement != NULL)
388  {
389  CloseStatement(pStatement);
390  pStatement = NULL;
391  }
392 
393  throw e;
394  }
395 #endif
396 
397  if (pResult != NULL)
398  {
399  CloseResultSet(pResult);
400  pResult = NULL;
401  }
402 
403  if (pStatement != NULL)
404  {
405  CloseStatement(pStatement);
406  pStatement = NULL;
407  }
408 
409  return bReturn;
410 }
411 
412 bool wxPostgresDatabase::ViewExists(const wxString& view)
413 {
414  // Initialize variables
415  bool bReturn = false;
416  // Keep these variables outside of scope so that we can clean them up
417  // in case of an error
418  wxPreparedStatement* pStatement = NULL;
419  wxDatabaseResultSet* pResult = NULL;
420 
421 #if wxUSE_DATABASE_EXCEPTIONS
422  try
423  {
424 #endif
425  wxString query = _("SELECT COUNT(*) FROM information_schema.tables WHERE table_type='VIEW' AND table_name=?;");
426  pStatement = PrepareStatement(query);
427  if (pStatement)
428  {
429  pStatement->SetParamString(1, view);
430  pResult = pStatement->ExecuteQuery();
431  if (pResult)
432  {
433  if (pResult->Next())
434  {
435  if(pResult->GetResultInt(1) != 0)
436  {
437  bReturn = true;
438  }
439  }
440  }
441  }
442 #if wxUSE_DATABASE_EXCEPTIONS
443  }
444  catch (wxDatabaseException& e)
445  {
446  if (pResult != NULL)
447  {
448  CloseResultSet(pResult);
449  pResult = NULL;
450  }
451 
452  if (pStatement != NULL)
453  {
454  CloseStatement(pStatement);
455  pStatement = NULL;
456  }
457 
458  throw e;
459  }
460 #endif
461 
462  if (pResult != NULL)
463  {
464  CloseResultSet(pResult);
465  pResult = NULL;
466  }
467 
468  if (pStatement != NULL)
469  {
470  CloseStatement(pStatement);
471  pStatement = NULL;
472  }
473 
474  return bReturn;
475 }
476 
477 wxArrayString wxPostgresDatabase::GetTables()
478 {
479  wxArrayString returnArray;
480 
481  wxDatabaseResultSet* pResult = NULL;
482 #if wxUSE_DATABASE_EXCEPTIONS
483  try
484  {
485 #endif
486  wxString query = _("SELECT table_name FROM information_schema.tables WHERE table_type='BASE TABLE' AND table_schema='public';");
487  pResult = ExecuteQuery(query);
488 
489  while (pResult->Next())
490  {
491  returnArray.Add(pResult->GetResultString(1));
492  }
493 #if wxUSE_DATABASE_EXCEPTIONS
494  }
495  catch (wxDatabaseException& e)
496  {
497  if (pResult != NULL)
498  {
499  CloseResultSet(pResult);
500  pResult = NULL;
501  }
502 
503  throw e;
504  }
505 #endif
506 
507  if (pResult != NULL)
508  {
509  CloseResultSet(pResult);
510  pResult = NULL;
511  }
512 
513  return returnArray;
514 }
515 
516 wxArrayString wxPostgresDatabase::GetViews()
517 {
518  wxArrayString returnArray;
519 
520  wxDatabaseResultSet* pResult = NULL;
521 #if wxUSE_DATABASE_EXCEPTIONS
522  try
523  {
524 #endif
525  wxString query = _("SELECT table_name FROM information_schema.tables WHERE table_type='VIEW' AND table_schema='public';");
526  pResult = ExecuteQuery(query);
527 
528  while (pResult->Next())
529  {
530  returnArray.Add(pResult->GetResultString(1));
531  }
532 #if wxUSE_DATABASE_EXCEPTIONS
533  }
534  catch (wxDatabaseException& e)
535  {
536  if (pResult != NULL)
537  {
538  CloseResultSet(pResult);
539  pResult = NULL;
540  }
541 
542  throw e;
543  }
544 #endif
545 
546  if (pResult != NULL)
547  {
548  CloseResultSet(pResult);
549  pResult = NULL;
550  }
551 
552  return returnArray;
553 }
554 
555 wxArrayString wxPostgresDatabase::GetColumns(const wxString& table)
556 {
557  // Initialize variables
558  wxArrayString returnArray;
559 
560  // Keep these variables outside of scope so that we can clean them up
561  // in case of an error
562  wxPreparedStatement* pStatement = NULL;
563  wxDatabaseResultSet* pResult = NULL;
564 
565 #if wxUSE_DATABASE_EXCEPTIONS
566  try
567  {
568 #endif
569  wxString query = _("SELECT column_name FROM information_schema.columns WHERE table_name=? ORDER BY ordinal_position;");
570  pStatement = PrepareStatement(query);
571  if (pStatement)
572  {
573  pStatement->SetParamString(1, table);
574  pResult = pStatement->ExecuteQuery();
575  if (pResult)
576  {
577  while (pResult->Next())
578  {
579  returnArray.Add(pResult->GetResultString(1));
580  }
581  }
582  }
583 #if wxUSE_DATABASE_EXCEPTIONS
584  }
585  catch (wxDatabaseException& e)
586  {
587  if (pResult != NULL)
588  {
589  CloseResultSet(pResult);
590  pResult = NULL;
591  }
592 
593  if (pStatement != NULL)
594  {
595  CloseStatement(pStatement);
596  pStatement = NULL;
597  }
598 
599  throw e;
600  }
601 #endif
602 
603  if (pResult != NULL)
604  {
605  CloseResultSet(pResult);
606  pResult = NULL;
607  }
608 
609  if (pStatement != NULL)
610  {
611  CloseStatement(pStatement);
612  pStatement = NULL;
613  }
614 
615  return returnArray;
616 }
617 
618 
619 wxArrayString wxPostgresDatabase::GetPKColumns(const wxString& table)
620 {
621  // Initialize variables
622  wxArrayString returnArray;
623 
624  // Keep these variables outside of scope so that we can clean them up
625  // in case of an error
626  wxPreparedStatement* pStatement = NULL;
627  wxDatabaseResultSet* pResult = NULL;
628 
629 #if wxUSE_DATABASE_EXCEPTIONS
630  try
631  {
632 #endif
633  wxString query = _("SELECT pg_attribute.attname,format_type(pg_attribute.atttypid, pg_attribute.atttypmod) FROM pg_index, pg_class, pg_attribute WHERE pg_class.oid = ? ::regclass AND indrelid = pg_class.oid AND pg_attribute.attrelid = pg_class.oid AND pg_attribute.attnum = any(pg_index.indkey) AND indisprimary;");
634  pStatement = PrepareStatement(query);
635  if (pStatement)
636  {
637  pStatement->SetParamString(1, table);
638  pResult = pStatement->ExecuteQuery();
639  if (pResult)
640  {
641  while (pResult->Next())
642  {
643  returnArray.Add(pResult->GetResultString(wxT("attname")));
644  }
645  }
646  }
647 #if wxUSE_DATABASE_EXCEPTIONS
648  }
649  catch (wxDatabaseException& e)
650  {
651  if (pResult != NULL)
652  {
653  CloseResultSet(pResult);
654  pResult = NULL;
655  }
656 
657  if (pStatement != NULL)
658  {
659  CloseStatement(pStatement);
660  pStatement = NULL;
661  }
662 
663  throw e;
664  }
665 #endif
666 
667  if (pResult != NULL)
668  {
669  CloseResultSet(pResult);
670  pResult = NULL;
671  }
672 
673  if (pStatement != NULL)
674  {
675  CloseStatement(pStatement);
676  pStatement = NULL;
677  }
678 
679  return returnArray;
680 }
681 
682 
684 {
685  // Ultimately, this will probably be a map of Postgresql database error code values to wxDatabase values
686  // For now though, we'll just return error
687  return nCode;
688  //return wxDATABASE_ERROR;
689 }
690 
692 {
693  bool bAvailable = false;
695  bAvailable = pInterface && pInterface->Init();
696  wxDELETE(pInterface);
697  return bAvailable;
698 }
699 
700 #endif//wxUSE_DATABASE_POSTGRESQL
virtual wxPreparedStatement * PrepareStatement(const wxString &strQuery)
Prepare a SQL statement which can be reused with different parameters.
virtual bool IsOpen()
Is the connection to the database open?
virtual wxArrayString GetColumns(const wxString &table)
Retrieve all column names for a table.
static wxPostgresPreparedStatement * CreateStatement(wxDynamicPostgresInterface *pInterface, PGconn *pDatabase, const wxString &strSQL)
PQclientEncodingType GetPQclientEncoding()
virtual wxArrayString GetPKColumns(const wxString &table)
get Primary keys column names
PQsetClientEncodingType GetPQsetClientEncoding()
virtual void RollBack()
Rollback the current transaction.
virtual wxString GetResultString(int nField)=0
Retrieve a wxString from the result set by the 1-based field index.
virtual void Commit()
Commit the current transaction.
wxDatabaseResultSet * ExecuteQuery(const wxString &strQuery)
See RunQueryWithResults.
Definition: database.h:64
static int TranslateErrorCode(int nCode)
virtual int RunQuery(const wxString &strQuery, bool bParseQuery)
Run an insert, update, or delete query on the database.
PQsetdbLoginType GetPQsetdbLogin()
void SetPort(int nPort)
PQencodingToCharType GetPQencodingToChar()
virtual int GetResultInt(int nField)=0
Retrieve an integer from the result set by the 1-based field index.
virtual wxDatabaseResultSet * RunQueryWithResults(const wxString &strQuery)
Run a select query on the database.
virtual bool CloseStatement(wxPreparedStatement *pStatement)
Close a prepared statement previously prepared by the database.
Definition: database.cpp:95
virtual bool ViewExists(const wxString &view)
Check for the existence of a view by name.
virtual bool Close()
close database
virtual wxArrayString GetTables()
Retrieve all table names.
void SetErrorMessage(const wxString &strErrorMessage)
wxDatabaseResultSet * ExecuteQuery()
See RunQueryWithResults.
virtual ~wxPostgresDatabase()
virtual bool Next()=0
Move to the next record in the result set.
void LogStatementForCleanup(wxPreparedStatement *pStatement)
Add prepared statement object pointer to the list for "garbage collection".
Definition: database.h:183
void SetEncoding(wxFontEncoding encoding)
void LogResultSetForCleanup(wxDatabaseResultSet *pResultSet)
Add result set object pointer to the list for "garbage collection".
Definition: database.h:181
#define wxDATABASE_QUERY_RESULT_ERROR
Definition: errorcodes.h:21
wxDynamicPostgresInterface * m_pInterface
static bool IsAvailable()
virtual void BeginTransaction()
Begin a transaction.
void SetErrorCode(int nErrorCode)
#define wxDATABASE_ERROR_LOADING_LIBRARY
Definition: errorcodes.h:16
void CloseStatements()
Close all prepared statement objects that have been generated but not yet closed.
Definition: database.cpp:38
virtual wxString ConvertFromUnicodeStream(const char *inputBuffer)
PQresultStatusType GetPQresultStatus()
const wxCSConv * GetEncoding()
virtual bool Open()
virtual const wxCharBuffer ConvertToUnicodeStream(const wxString &inputString)
PQerrorMessageType GetPQerrorMessage()
virtual bool TableExists(const wxString &table)
Check for the existence of a table by name.
void CloseResultSets()
Close all result set objects that have been generated but not yet closed.
Definition: database.cpp:24
virtual bool CloseResultSet(wxDatabaseResultSet *pResultSet)
Close a result set returned by the database or a prepared statement previously.
Definition: database.cpp:52
virtual wxArrayString GetViews()
Retrieve all view names.
virtual void SetParamString(int nPosition, const wxString &strValue)=0
Set the parameter at the 1-based position to a wxString value.