1 //////////////////////////////////////////////////////////////////////////
2 //
3 // pgAdmin III - PostgreSQL Tools
4 //
5 // Copyright (C) 2002 - 2016, The pgAdmin Development Team
6 // This software is released under the PostgreSQL Licence
7 //
8 // pgSet.cpp - PostgreSQL ResultSet class
9 //
10 //////////////////////////////////////////////////////////////////////////
11
12 #include "pgAdmin3.h"
13
14 // wxWindows headers
15 #include <wx/wx.h>
16
17 // PostgreSQL headers
18 #include <libpq-fe.h>
19
20 // App headers
21 #include "db/pgSet.h"
22 #include "db/pgConn.h"
23 #include "utils/sysLogger.h"
24 #include "utils/pgDefs.h"
25
pgSet()26 pgSet::pgSet()
27 : conv(wxConvLibc)
28 {
29 conn = 0;
30 res = 0;
31 nCols = 0;
32 nRows = 0;
33 pos = 0;
34 }
35
pgSet(PGresult * newRes,pgConn * newConn,wxMBConv & cnv,bool needColQt)36 pgSet::pgSet(PGresult *newRes, pgConn *newConn, wxMBConv &cnv, bool needColQt)
37 : conv(cnv)
38 {
39 needColQuoting = needColQt;
40
41 conn = newConn;
42 res = newRes;
43
44 // Make sure we have tuples
45 if (PQresultStatus(res) != PGRES_TUPLES_OK)
46 {
47 nCols = 0;
48 nRows = 0;
49 pos = 0;
50 }
51 else
52 {
53 nCols = PQnfields(res);
54 for (int x = 0; x < nCols + 1; x++)
55 {
56 colTypes.Add(wxT(""));
57 colFullTypes.Add(wxT(""));
58 colClasses.Add(0);
59 }
60
61 nRows = PQntuples(res);
62 MoveFirst();
63 }
64 }
65
66
~pgSet()67 pgSet::~pgSet()
68 {
69 PQclear(res);
70 }
71
72
73
ColTypeOid(const int col) const74 OID pgSet::ColTypeOid(const int col) const
75 {
76 wxASSERT(col < nCols && col >= 0);
77
78 return PQftype(res, col);
79 }
80
ColTypeMod(const int col) const81 long pgSet::ColTypeMod(const int col) const
82 {
83 wxASSERT(col < nCols && col >= 0);
84
85 return PQfmod(res, col);
86 }
87
88
GetInsertedCount() const89 long pgSet::GetInsertedCount() const
90 {
91 char *cnt = PQcmdTuples(res);
92 if (!*cnt)
93 return -1;
94 else
95 return atol(cnt);
96 }
97
98
ColTypClass(const int col) const99 pgTypClass pgSet::ColTypClass(const int col) const
100 {
101 wxASSERT(col < nCols && col >= 0);
102
103 if (colClasses[col] != 0)
104 return (pgTypClass)colClasses[col];
105
106 wxString typoid = ExecuteScalar(
107 wxT("SELECT CASE WHEN typbasetype=0 THEN oid else typbasetype END AS basetype\n")
108 wxT(" FROM pg_type WHERE oid=") + NumToStr(ColTypeOid(col)));
109
110 switch (StrToLong(typoid))
111 {
112 case PGOID_TYPE_BOOL:
113 colClasses[col] = PGTYPCLASS_BOOL;
114 break;
115 case PGOID_TYPE_INT8:
116 case PGOID_TYPE_INT2:
117 case PGOID_TYPE_INT4:
118 case PGOID_TYPE_OID:
119 case PGOID_TYPE_XID:
120 case PGOID_TYPE_TID:
121 case PGOID_TYPE_CID:
122 case PGOID_TYPE_FLOAT4:
123 case PGOID_TYPE_FLOAT8:
124 case PGOID_TYPE_MONEY:
125 case PGOID_TYPE_BIT:
126 case PGOID_TYPE_NUMERIC:
127 colClasses[col] = PGTYPCLASS_NUMERIC;
128 break;
129 case PGOID_TYPE_BYTEA:
130 case PGOID_TYPE_CHAR:
131 case PGOID_TYPE_NAME:
132 case PGOID_TYPE_TEXT:
133 case PGOID_TYPE_VARCHAR:
134 colClasses[col] = PGTYPCLASS_STRING;
135 break;
136 case PGOID_TYPE_TIMESTAMP:
137 case PGOID_TYPE_TIMESTAMPTZ:
138 case PGOID_TYPE_TIME:
139 case PGOID_TYPE_TIMETZ:
140 case PGOID_TYPE_INTERVAL:
141 colClasses[col] = PGTYPCLASS_DATE;
142 break;
143 default:
144 colClasses[col] = PGTYPCLASS_OTHER;
145 break;
146 }
147
148 return (pgTypClass)colClasses[col];
149 }
150
151
ColType(const int col) const152 wxString pgSet::ColType(const int col) const
153 {
154 wxASSERT(col < nCols && col >= 0);
155
156 if (!colTypes[col].IsEmpty())
157 return colTypes[col];
158
159 wxString szSQL, szResult;
160 szSQL.Printf(wxT("SELECT format_type(oid,NULL) as typname FROM pg_type WHERE oid = %d"), (int)ColTypeOid(col));
161 szResult = ExecuteScalar(szSQL);
162 colTypes[col] = szResult;
163
164 return szResult;
165 }
166
ColFullType(const int col) const167 wxString pgSet::ColFullType(const int col) const
168 {
169 wxASSERT(col < nCols && col >= 0);
170
171 if (!colFullTypes[col].IsEmpty())
172 return colFullTypes[col];
173
174 wxString szSQL, szResult;
175 szSQL.Printf(wxT("SELECT format_type(oid,%d) as typname FROM pg_type WHERE oid = %d"), (int)ColTypeMod(col), (int)ColTypeOid(col));
176 szResult = ExecuteScalar(szSQL);
177 colFullTypes[col] = szResult;
178
179 return szResult;
180 }
181
ColScale(const int col) const182 int pgSet::ColScale(const int col) const
183 {
184 wxASSERT(col < nCols && col >= 0);
185
186 // TODO
187 return 0;
188 }
ColName(const int col) const189 wxString pgSet::ColName(const int col) const
190 {
191 wxASSERT(col < nCols && col >= 0);
192
193 return wxString(PQfname(res, col), conv);
194 }
195
196
ColNumber(const wxString & colname) const197 int pgSet::ColNumber(const wxString &colname) const
198 {
199 int col;
200
201 if (needColQuoting)
202 {
203 wxString quotedColName = colname;
204 quotedColName.Replace(wxT("\""), wxT("\"\""));
205 col = PQfnumber(res, (wxT("\"") + quotedColName + wxT("\"")).mb_str(conv));
206 }
207 else
208 col = PQfnumber(res, colname.mb_str(conv));
209
210 if (col < 0)
211 {
212 wxLogError(__("Column not found in pgSet: %s"), colname.c_str());
213 }
214 return col;
215 }
216
HasColumn(const wxString & colname) const217 bool pgSet::HasColumn(const wxString &colname) const
218 {
219 if (needColQuoting)
220 {
221 wxString quotedColName = colname;
222 quotedColName.Replace(wxT("\""), wxT("\"\""));
223 return (PQfnumber(res, (wxT("\"") + quotedColName + wxT("\"")).mb_str(conv)) < 0 ? false : true);
224 }
225 else
226 return (PQfnumber(res, colname.mb_str(conv)) < 0 ? false : true);
227
228 }
229
230
231
GetCharPtr(const int col) const232 char *pgSet::GetCharPtr(const int col) const
233 {
234 wxASSERT(col < nCols && col >= 0);
235
236 return PQgetvalue(res, pos - 1, col);
237 }
238
239
GetCharPtr(const wxString & col) const240 char *pgSet::GetCharPtr(const wxString &col) const
241 {
242 return PQgetvalue(res, pos - 1, ColNumber(col));
243 }
244
245
GetVal(const int col) const246 wxString pgSet::GetVal(const int col) const
247 {
248 wxASSERT(col < nCols && col >= 0);
249
250 return wxString(GetCharPtr(col), conv);
251 }
252
253
GetVal(const wxString & colname) const254 wxString pgSet::GetVal(const wxString &colname) const
255 {
256 return GetVal(ColNumber(colname));
257 }
258
259
GetLong(const int col) const260 long pgSet::GetLong(const int col) const
261 {
262 wxASSERT(col < nCols && col >= 0);
263
264 char *c = PQgetvalue(res, pos - 1, col);
265 if (c)
266 return atol(c);
267 else
268 return 0;
269 }
270
271
GetLong(const wxString & col) const272 long pgSet::GetLong(const wxString &col) const
273 {
274 char *c = PQgetvalue(res, pos - 1, ColNumber(col));
275 if (c)
276 return atol(c);
277 else
278 return 0;
279 }
280
281
GetBool(const int col) const282 bool pgSet::GetBool(const int col) const
283 {
284 wxASSERT(col < nCols && col >= 0);
285
286 char *c = PQgetvalue(res, pos - 1, col);
287 if (c)
288 {
289 if (*c == 't' || *c == '1' || !strcmp(c, "on"))
290 return true;
291 }
292 return false;
293 }
294
295
GetBool(const wxString & col) const296 bool pgSet::GetBool(const wxString &col) const
297 {
298 return GetBool(ColNumber(col));
299 }
300
301
GetDateTime(const int col) const302 wxDateTime pgSet::GetDateTime(const int col) const
303 {
304 wxASSERT(col < nCols && col >= 0);
305
306 wxDateTime dt;
307 wxString str = GetVal(col);
308 /* This hasn't just been used. ( Is not infinity ) */
309 if (!str.IsEmpty())
310 dt.ParseDateTime(str);
311 return dt;
312 }
313
314
GetDateTime(const wxString & col) const315 wxDateTime pgSet::GetDateTime(const wxString &col) const
316 {
317 return GetDateTime(ColNumber(col));
318 }
319
320
GetDate(const int col) const321 wxDateTime pgSet::GetDate(const int col) const
322 {
323 wxASSERT(col < nCols && col >= 0);
324
325 wxDateTime dt;
326 wxString str = GetVal(col);
327 /* This hasn't just been used. ( Is not infinity ) */
328 if (!str.IsEmpty())
329 dt.ParseDate(str);
330 return dt;
331 }
332
333
GetDate(const wxString & col) const334 wxDateTime pgSet::GetDate(const wxString &col) const
335 {
336 return GetDate(ColNumber(col));
337 }
338
339
GetDouble(const int col) const340 double pgSet::GetDouble(const int col) const
341 {
342 wxASSERT(col < nCols && col >= 0);
343
344 return StrToDouble(GetVal(col));
345 }
346
347
GetDouble(const wxString & col) const348 double pgSet::GetDouble(const wxString &col) const
349 {
350 return GetDouble(ColNumber(col));
351 }
352
353
GetLongLong(const int col) const354 wxULongLong pgSet::GetLongLong(const int col) const
355 {
356 wxASSERT(col < nCols && col >= 0);
357
358 char *c = PQgetvalue(res, pos - 1, col);
359 if (c)
360 return atolonglong(c);
361 else
362 return 0;
363 }
364
GetLongLong(const wxString & col) const365 wxULongLong pgSet::GetLongLong(const wxString &col) const
366 {
367 return GetLongLong(ColNumber(col));
368 }
369
370
GetOid(const int col) const371 OID pgSet::GetOid(const int col) const
372 {
373 wxASSERT(col < nCols && col >= 0);
374
375 char *c = PQgetvalue(res, pos - 1, col);
376 if (c)
377 return (OID)strtoul(c, 0, 10);
378 else
379 return 0;
380 }
381
382
GetOid(const wxString & col) const383 OID pgSet::GetOid(const wxString &col) const
384 {
385 return GetOid(ColNumber(col));
386 }
387
388
ExecuteScalar(const wxString & sql) const389 wxString pgSet::ExecuteScalar(const wxString &sql) const
390 {
391 return conn->ExecuteScalar(sql);
392 }
393
394
395 //////////////////////////////////////////////////////////////////
396
pgSetIterator(pgConn * conn,const wxString & qry)397 pgSetIterator::pgSetIterator(pgConn *conn, const wxString &qry)
398 {
399 set = conn->ExecuteSet(qry);
400 first = true;
401 }
402
403
pgSetIterator(pgSet * s)404 pgSetIterator::pgSetIterator(pgSet *s)
405 {
406 set = s;
407 first = true;
408 }
409
410
~pgSetIterator()411 pgSetIterator::~pgSetIterator()
412 {
413 if (set)
414 delete set;
415 }
416
417
RowsLeft()418 bool pgSetIterator::RowsLeft()
419 {
420 if (!set)
421 return false;
422
423 if (first)
424 {
425 if (!set->NumRows())
426 return false;
427 first = false;
428 }
429 else
430 set->MoveNext();
431
432 return !set->Eof();
433 }
434
435
MovePrev()436 bool pgSetIterator::MovePrev()
437 {
438 if (!set)
439 return false;
440
441 set->MovePrevious();
442 return true;
443 }
444