DCL 3.7.4
Loading...
Searching...
No Matches
PqQuery Class Reference

#include <PqQuery.h>

Inheritance diagram for PqQuery:
SQL::Query Object

Public Member Functions

 PqQuery (PqConnection *pConnection)
virtual ~PqQuery ()
virtual void __destroy ()
virtual bool __prepare (const char *_sql, size_t _sqllen, size_t _paramCount)
virtual bool __execute ()
virtual bool __fetch ()
virtual bool __getField (size_t _index, SQL::Field **_fieldHandleOut)
virtual bool __getParam (size_t _index, SQL::Param **_paramHandleOut)
Public Member Functions inherited from Object
virtual String toString () const
virtual void destroy ()
String className () const
bool isInstanceOf (const std::type_info &typeinfo) const
virtual const std::type_info & typeInfo () const

Protected Member Functions

bool reset ()
Protected Member Functions inherited from SQL::Query
 Query (Connection *_connHandle)
virtual ~Query ()
virtual bool __moreResults (bool *_moreResults)
Protected Member Functions inherited from Object
virtual ~Object ()
 Object ()

Protected Attributes

int __stmtNo
ByteString __stmtID
ByteString __cursorID
ByteString __query
int __nfields
void * __inBINDs
PqField__fields
PqParam__params
PGresult * __res
int __row
Protected Attributes inherited from SQL::Query
Connection__connHandle
bool __eof
int64_t __affectedRows
size_t __fieldCount
size_t __paramCount
wchar_t __placeholder
unsigned int __states

Additional Inherited Members

Public Types inherited from SQL::Query
enum  State { stStandBy = (unsigned int) 0x0001 , stPrepared = 0x0002 , stExecuted = 0x0004 , stFetched = 0x0008 }

Detailed Description

Definition at line 15 of file PqQuery.h.

Constructor & Destructor Documentation

◆ PqQuery()

PqQuery::PqQuery ( PqConnection * pConnection)

◆ ~PqQuery()

PqQuery::~PqQuery ( )
virtual

Definition at line 71 of file PqQuery.cpp.

72{
73#ifdef __DCL_DEBUG
74 if (!reset()) {
75 char buf[256];
76 size_t buflen = sizeof(buf) - 1;
77 bool b = conn()->__getErrorMessage(buf, &buflen);
78 buf[b ? buflen : 0] = '\0';
79 __DCL_TRACE1(L"Warning! Query reset error! %hs\n", buf);
80 }
81#else
82 (void)reset();
83#endif
84}
#define __DCL_TRACE1(fmt, arg1)
Definition Object.h:399
bool reset()
Definition PqQuery.cpp:91

Member Function Documentation

◆ __destroy()

void PqQuery::__destroy ( )
virtual

Implements SQL::Query.

Definition at line 86 of file PqQuery.cpp.

87{
88 delete this;
89}

◆ __execute()

bool PqQuery::__execute ( )
virtual

Implements SQL::Query.

Definition at line 256 of file PqQuery.cpp.

257{
258 if (__nfields && __CURSOR_ENABLED(conn())) {
259 // SELECT, EXECUTE
260 ByteString cursorID = ByteString::format("curs_%d", __stmtNo);
261 ByteStringBuilder cmd(__query.length() + 20);
262 cmd.assign("DECLARE ").append(cursorID).append(" CURSOR FOR ").append(__query);
263 PGresult* res = PQexecParams(conn()->connHandle(), cmd,
264 (int)Query::__paramCount, __BIND_TYPES,
267 );
268 if (PQresultStatus(res) != PGRES_COMMAND_OK) {
269 __SET_ERROR_MSG(PQerrorMessage(conn()->connHandle()));
270 PQclear(res);
271 return false;
272 }
273 PQclear(res);
274 __cursorID = cursorID;
275 Query::__eof = false;
276
277 res = PQdescribePortal(conn()->connHandle(), cursorID);
278 if (PQresultStatus(res) != PGRES_COMMAND_OK) {
279 __SET_ERROR_MSG(PQerrorMessage(conn()->connHandle()));
280 PQclear(res);
281 return false;
282 }
283#if defined(__DCL_DEBUG) && __TRACE_THIS && 0
284 for (int i = 0; i < PQnfields(res); i++) {
285 Oid oid = PQftype(res, i);
286 __DCL_TRACE6_N(L"[%2d] size [%6d %7d %4d] [%4d %-16hs]\n", i,
287 PQfsize(res, i), PQfmod(res, i), PQfformat(res, i),
288 oid, PQfname(res, i)
289 );
290 }
291#endif
293 (__fields == NULL)
294 && (Query::__fieldCount == 0)
295 );
296 Query::__fieldCount = __nfields;
297 __fields = new PqField[Query::__fieldCount];
298 if (__fields == NULL) {
300 return false;
301 }
302
303 for (size_t i = 0; i < Query::__fieldCount; i++) {
304 if (!__fields[i].init(this, (int)i, res))
305 return false;
306 }
307 PQclear(res);
308 }
309 else {
310 // SELECT, EXECUTE, INSERT, UPDATE, DELETE, ...
311#if defined(__DCL_DEBUG) && __TRACE_THIS && 0
312 for (size_t i = 0; i < Query::__paramCount; i++) {
313 __DCL_TRACE4_N(L"length [%8d] value[%p] type [%4d %ls] \n",
315 __BIND_TYPES[i],
317 );
318 }
319#endif
320 PGresult* res = PQexecPrepared(conn()->connHandle(), __stmtID,
321 (int)Query::__paramCount,
324 );
325 switch (PQresultStatus(res)) {
326 case PGRES_COMMAND_OK: {
327 // INSERT, UPDATE, DELETE, MERGE, MOVE, FETCH, COPY
328 char* psz = PQcmdTuples(res);
329 if (psz) {
330 Query::__affectedRows = strtoll(psz, NULL, 10);
331 }
332 PQclear(res);
333 break;
334 }
335 case PGRES_TUPLES_OK: {
336 if (__nfields != (int)Query::__fieldCount) {
338 (__fields == NULL)
339 && (Query::__fieldCount == 0)
340 );
341 Query::__fieldCount = __nfields;
342 __fields = new PqField[Query::__fieldCount];
343 if (__fields == NULL) {
345 return false;
346 }
347
348 for (size_t i = 0; i < Query::__fieldCount; i++) {
349 if (!__fields[i].init(this, (int)i, res))
350 return false;
351 }
352 }
353 __DCL_ASSERT(PQnfields(res) > 0);
354 __DCL_ASSERT(__row == -1);
355 __res = res;
356 Query::__eof = false;
357 break;
358 }
359 default: {
360 __SET_ERROR_MSG(PQerrorMessage(conn()->connHandle()));
361 PQclear(res);
362 return false;
363 }
364 }
365 }
366
367 for(size_t i = 0; i < Query::__paramCount; i++) {
368 __SET_BIND_TYPE(i, 0);
370 __SET_BIND_LENGTH(i, 0);
372
373 if (!(__params[i].onAfterExecute()))
374 return false;
375 }
376
377 return true;
378}
#define NULL
Definition Config.h:312
#define __DCL_TRACE4_N(fmt, arg1, arg2, arg3, arg4)
#define __SET_ERROR_MSG(_message)
const wchar_t * __dataTypeName(const ifx_sqlvar_t *_sqlvar)
Definition IFXField.cpp:304
#define __DCL_TRACE6_N(fmt, arg1, arg2, arg3, arg4, arg5, arg6)
Definition ODBCQuery.cpp:45
#define __DCL_ASSERT(expr)
Definition Object.h:394
#define __SET_BIND_LENGTH(_index, _length)
#define __BIND_VALUES
#define __SET_BIND_VALUE(_index, _value)
#define __BIND_TYPES
#define __SET_BIND_FORMAT(_index, _format)
#define __BIND_FORMATS
#define __SET_BIND_TYPE(_index, _type)
#define __BIND_LENGTHS
#define __CURSOR_ENABLED(_conn)
Definition PqQuery.h:10
#define __FORMAT_DEFAULT
Definition PqQuery.h:8
#define __FORMAT_TEXT
Definition PqQuery.h:6
#define __SET_ERROR(_errorCode)
Definition SQLCore.cpp:149
int __stmtNo
Definition PqQuery.h:25
int __row
Definition PqQuery.h:40
PqField * __fields
Definition PqQuery.h:36
ByteString __stmtID
Definition PqQuery.h:26
int __nfields
Definition PqQuery.h:29
PqParam * __params
Definition PqQuery.h:37
PGresult * __res
Definition PqQuery.h:39
ByteString __cursorID
Definition PqQuery.h:27
ByteString __query
Definition PqQuery.h:28
@ eOutOfMemory
Definition SQLCore.h:24

◆ __fetch()

bool PqQuery::__fetch ( )
virtual

Implements SQL::Query.

Definition at line 380 of file PqQuery.cpp.

381{
382 if (__res) {
383 __row++;
384 }
385
386 if (!__cursorID.isEmpty() && (__res == NULL || PQntuples(__res) == __row)) {
387 // cursor를 사용하도록 되어 있는데,
388 // 처음 FETCH이거나, 이전에 FETCH한 행들의 마지막에 도달했다.
389 ByteStringBuilder cmd;
390 cmd.assign("FETCH ").append(conn()->cursor() == 0 ?
391 "NEXT" : ByteString::valueOf(conn()->cursor()))
392 .append(" IN ").append(__cursorID);
393 __DCL_TRACE1_N(L"__execute [%hs]\n", cmd.data());
394 PGresult* res = PQexecParams(conn()->connHandle(), cmd,
396 );
397 if (PQresultStatus(res) != PGRES_TUPLES_OK) {
398 __SET_ERROR_MSG(PQerrorMessage(conn()->connHandle()));
399 PQclear(res);
400 return false;
401 }
402
403 if (__res) {
404 PQclear(__res);
405 }
406 __res = res;
407 __row = 0;
408 }
409
410 bool r = true;
411 if (__row == PQntuples(__res)) {
412 Query::__eof = true;
413 if (!__cursorID.isEmpty()) {
414 // FETCH한 행이 없으므로, cursor를 닫는다.
415 __DCL_ASSERT(!__query.isEmpty());
416 __query.clear();
417
418 ByteString cmd = "CLOSE " + __cursorID;
419 PGresult* res = PQexec(conn()->connHandle(), cmd);
420 if (PQresultStatus(res) != PGRES_COMMAND_OK) {
421 __SET_ERROR_MSG(PQerrorMessage(conn()->connHandle()));
422 r = false;
423 }
424 PQclear(res);
425#ifdef LIBPQ_HAS_CLOSE_PREPARED
426 res = PQclosePortal(conn()->connHandle(), __cursorID);
427 if (r && PQresultStatus(res) != PGRES_COMMAND_OK) {
428 __SET_ERROR_MSG(PQerrorMessage(conn()->connHandle()));
429 r = false;
430 }
431 PQclear(res);
432#endif
433 __cursorID.clear();
434 }
435 }
436
437 return r;
438}
#define __DCL_TRACE1_N(fmt, arg)
IOException *size_t r
Definition MediaInfo.cpp:82

◆ __getField()

bool PqQuery::__getField ( size_t _index,
SQL::Field ** _fieldHandleOut )
virtual

Implements SQL::Query.

Definition at line 461 of file PqQuery.cpp.

462{
463 __DCL_ASSERT(Query::__fieldCount > 0);
464 __DCL_ASSERT((0 <= _index) && (_index < Query::__fieldCount));
465 *_fieldHandleOut = &__fields[_index];
466 return true;
467}

◆ __getParam()

bool PqQuery::__getParam ( size_t _index,
SQL::Param ** _paramHandleOut )
virtual

Implements SQL::Query.

Definition at line 469 of file PqQuery.cpp.

470{
471 __DCL_ASSERT(Query::__paramCount > 0);
472 __DCL_ASSERT((0 <= _index) && (_index < Query::__paramCount));
473 *_paramHandleOut = &__params[_index];
474 return true;
475}

◆ __prepare()

bool PqQuery::__prepare ( const char * _sql,
size_t _sqllen,
size_t _paramCount )
virtual

Implements SQL::Query.

Definition at line 162 of file PqQuery.cpp.

165{
166 if(!reset())
167 return false;
168
169 // PostgreSQL 17 이전의 libpq 에는 PQclosePrepared, PQclosePortal 이 없다.
170 // stmtID가 동일하면 prepared statement "stmt_0" already exists
171 // 연결이 지속되는 동안 이 값을 계속 증가시킨다.
172 __stmtNo = conn()->stmtNo();
173 ByteString stmtID = ByteString::format("stmt_%d", __stmtNo);
174 PGresult* res = PQprepare(conn()->connHandle(), stmtID, _sql, 0, NULL);
175 if (PQresultStatus(res) != PGRES_COMMAND_OK) {
176 __SET_ERROR_MSG(PQerrorMessage(conn()->connHandle()));
177 PQclear(res);
178 return false;
179 }
180 PQclear(res);
181
182 res = PQdescribePrepared(conn()->connHandle(), stmtID);
183 if (PQresultStatus(res) != PGRES_COMMAND_OK) {
184 __SET_ERROR_MSG(PQerrorMessage(conn()->connHandle()));
185 PQclear(res);
186 return false;
187 }
188
190 && (Query::__paramCount == 0)
191 && (__inBINDs == NULL)
192 );
193
194 int nparams = PQnparams(res);
195 if (nparams) {
196 __DCL_ASSERT((size_t)nparams == _paramCount);;
197
198#if defined(__DCL_DEBUG) && __TRACE_THIS && 0
199 for (int i = 0; i < nparams; i++) {
200 Oid oid = PQparamtype(res, i);
201 __DCL_TRACE3_N(L"[%2d] [%4d %-10ls]\n", i,
202 oid, __dataTypeName(oid)
203 );
204 }
205#endif
206 size_t alloc = nparams * (sizeof(char*) + sizeof(int) * 3);
207 __DCL_TRACE2_N(L"__inBINDs nparams[%2d] * (8+4+4+4=20) alloc[%zd]\n",
208 nparams, alloc);
209 __inBINDs = malloc(alloc);
210 if (__inBINDs == NULL) {
212 return false;
213 }
214 memset(__inBINDs, 0, alloc);
215
216#define __BIND_VALUES ((const char**)((char*)__inBINDs))
217#define __BIND_TYPES ((Oid*)((char*)__inBINDs \
218 + (Query::__paramCount * (sizeof(char*) + sizeof(int) * 0))))
219#define __BIND_LENGTHS ((int*)((char*)__inBINDs \
220 + (Query::__paramCount * (sizeof(char*) + sizeof(int) * 1))))
221#define __BIND_FORMATS ((int*)((char*)__inBINDs \
222 + (Query::__paramCount * (sizeof(char*) + sizeof(int) * 2))))
223
224#define __SET_BIND_TYPE(_index, _type) __BIND_TYPES[_index] = _type
225#define __SET_BIND_VALUE(_index, _value) __BIND_VALUES[_index] = _value
226#define __SET_BIND_LENGTH(_index, _length) __BIND_LENGTHS[_index] = _length
227#define __SET_BIND_FORMAT(_index, _format) __BIND_FORMATS[_index] = _format
228
229 Query::__paramCount = nparams;
230 __params = new PqParam[Query::__paramCount];
231 if (__params == NULL) {
233 return false;
234 }
235
236 for (size_t i = 0; i < Query::__paramCount; i++) {
237 if (!__params[i].init(this, (int)i, res))
238 return false;
239 }
240 }
241
242 __stmtID = stmtID;
243 __nfields = PQnfields(res);
244 if (__nfields) {
245 // SELECT, EXECUTE ...
246 // execute에서 CURSOR를 만든다.
247 if (__CURSOR_ENABLED(conn())) {
248 __query.assign(_sql, _sqllen);
249 }
250 }
251
252 PQclear(res);
253 return true;
254}
#define __DCL_TRACE2_N(fmt, arg1, arg2)
#define __DCL_TRACE3_N(fmt, arg1, arg2, arg3)
void * __inBINDs
Definition PqQuery.h:35

◆ reset()

bool PqQuery::reset ( )
protected

Definition at line 91 of file PqQuery.cpp.

92{
93 Query::__eof = true;
94 Query::__affectedRows = -1;
95
96 // clear fields
97 if (__fields) {
98 __DCL_ASSERT(Query::__fieldCount > 0);
99 delete[] __fields;
100 __fields = NULL;
101 Query::__fieldCount = 0;
102 __nfields = 0;
103 }
104
105 // clear binds
106 if (__params) {
107 __DCL_ASSERT(Query::__paramCount > 0);
108 delete[] __params;
109 __params = NULL;
110 Query::__paramCount = 0;
111 }
112
113 if (__inBINDs) {
114 free(__inBINDs);
115 __inBINDs = NULL;
116 }
117
118 if (__res) {
119 PQclear(__res);
120 __res = NULL;
121 __row = -1;
122 }
123
124 bool r = true;
125 if (!__cursorID.isEmpty()) {
126 __DCL_ASSERT(!__query.isEmpty());
127 __query.clear();
128
129 ByteString cmd = "CLOSE " + __cursorID;
130 PGresult* res = PQexec(conn()->connHandle(), cmd);
131 if (PQresultStatus(res) != PGRES_COMMAND_OK) {
132 __SET_ERROR_MSG(PQerrorMessage(conn()->connHandle()));
133 r = false;
134 }
135 PQclear(res);
136#ifdef LIBPQ_HAS_CLOSE_PREPARED
137 res = PQclosePortal(conn()->connHandle(), __cursorID);
138 if (r && PQresultStatus(res) != PGRES_COMMAND_OK) {
139 __SET_ERROR_MSG(PQerrorMessage(conn()->connHandle()));
140 r = false;
141 }
142 PQclear(res);
143#endif
144 __cursorID.clear();
145 }
146
147 if (!__stmtID.isEmpty()) {
148#ifdef LIBPQ_HAS_CLOSE_PREPARED
149 PGresult* res = PQclosePrepared(conn()->connHandle(), __stmtID);
150 if (r && PQresultStatus(res) != PGRES_COMMAND_OK) {
151 __SET_ERROR_MSG(PQerrorMessage(conn()->connHandle()));
152 r = false;
153 }
154 PQclear(res);
155#endif
156 __stmtID.clear();
157 }
158
159 return r;
160}

Member Data Documentation

◆ __cursorID

ByteString PqQuery::__cursorID
protected

Definition at line 27 of file PqQuery.h.

◆ __fields

PqField* PqQuery::__fields
protected

Definition at line 36 of file PqQuery.h.

◆ __inBINDs

void* PqQuery::__inBINDs
protected

Definition at line 35 of file PqQuery.h.

◆ __nfields

int PqQuery::__nfields
protected

Definition at line 29 of file PqQuery.h.

◆ __params

PqParam* PqQuery::__params
protected

Definition at line 37 of file PqQuery.h.

◆ __query

ByteString PqQuery::__query
protected

Definition at line 28 of file PqQuery.h.

◆ __res

PGresult* PqQuery::__res
protected

Definition at line 39 of file PqQuery.h.

◆ __row

int PqQuery::__row
protected

Definition at line 40 of file PqQuery.h.

◆ __stmtID

ByteString PqQuery::__stmtID
protected

Definition at line 26 of file PqQuery.h.

◆ __stmtNo

int PqQuery::__stmtNo
protected

Definition at line 25 of file PqQuery.h.


The documentation for this class was generated from the following files: