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