1 #include "PostgreSQLInterface.h"
2 #include "VariadicSQLParser.h"
3
4 // libpq-fe.h is part of PostgreSQL which must be installed on this computer to use the PostgreRepository
5 #include "libpq-fe.h"
6
7 #ifdef _CONSOLE_1
8 #include "Console1Includes.h"
9 #elif defined(_WIN32)
10 #include <winsock2.h> // htonl
11 #elif defined(_CONSOLE_2)
12 #include "Console2Includes.h"
13 #else
14 #include <arpa/inet.h>
15 #endif
16
17 // alloca
18 #ifdef _COMPATIBILITY_1
19 #elif defined(_WIN32)
20 #include <malloc.h>
21 #else
22 //#include <stdlib.h>
23 #endif
24
25 #include "RakString.h"
26 #include "RakAssert.h"
27 #include "BitStream.h"
28 #include "FormatString.h"
29 #include "LinuxStrings.h"
30
31 #define PQEXECPARAM_FORMAT_TEXT 0
32 #define PQEXECPARAM_FORMAT_BINARY 1
33
PostgreSQLInterface()34 PostgreSQLInterface::PostgreSQLInterface()
35 {
36 pgConn=0;
37 isConnected=false;
38 lastError[0]=0;
39 pgConnAllocatedHere=false;
40 }
~PostgreSQLInterface()41 PostgreSQLInterface::~PostgreSQLInterface()
42 {
43 if (isConnected && pgConnAllocatedHere)
44 PQfinish(pgConn);
45 }
Connect(const char * conninfo)46 bool PostgreSQLInterface::Connect(const char *conninfo)
47 {
48 if (isConnected==false)
49 {
50 pgConn=PQconnectdb(conninfo);
51 ConnStatusType status = PQstatus(pgConn);
52 isConnected=status==CONNECTION_OK;
53 if (isConnected==false)
54 {
55 PQfinish(pgConn);
56 return false;
57 }
58 pgConnAllocatedHere=true;
59 }
60
61 return isConnected;
62 }
AssignConnection(PGconn * _pgConn)63 void PostgreSQLInterface::AssignConnection(PGconn *_pgConn)
64 {
65 pgConnAllocatedHere=false;
66 pgConn=_pgConn;
67 ConnStatusType status = PQstatus(pgConn);
68 isConnected=status==CONNECTION_OK;
69 }
GetPGConn(void) const70 PGconn *PostgreSQLInterface::GetPGConn(void) const
71 {
72 return pgConn;
73 }
Disconnect(void)74 void PostgreSQLInterface::Disconnect(void)
75 {
76 if (isConnected)
77 {
78 PQfinish(pgConn);
79 isConnected=false;
80 }
81 }
Rollback(void)82 void PostgreSQLInterface::Rollback(void)
83 {
84 PGresult *result = PQexec(pgConn, "ROLLBACK;");
85 PQclear(result);
86 }
IsResultSuccessful(PGresult * result,bool rollbackOnFailure)87 bool PostgreSQLInterface::IsResultSuccessful(PGresult *result, bool rollbackOnFailure)
88 {
89 if (result==0)
90 return false;
91
92 bool success=false;
93 ExecStatusType execStatus = PQresultStatus(result);
94 strcpy(lastError,PQresultErrorMessage(result));
95 switch (execStatus)
96 {
97 case PGRES_COMMAND_OK:
98 success=true;
99 break;
100 case PGRES_EMPTY_QUERY:
101 break;
102 case PGRES_TUPLES_OK:
103 success=true;
104 break;
105 case PGRES_COPY_OUT:
106 break;
107 case PGRES_COPY_IN:
108 break;
109 case PGRES_BAD_RESPONSE:
110 break;
111 case PGRES_NONFATAL_ERROR:
112 break;
113 case PGRES_FATAL_ERROR:
114 if (rollbackOnFailure)
115 Rollback();
116 break;
117 }
118 return success;
119 }
ExecuteBlockingCommand(const char * command,PGresult ** result,bool rollbackOnFailure)120 bool PostgreSQLInterface::ExecuteBlockingCommand(const char *command, PGresult **result, bool rollbackOnFailure)
121 {
122 *result = PQexec(pgConn, command);
123 return IsResultSuccessful(*result, rollbackOnFailure);
124 }
PQGetValueFromBinary(int * output,PGresult * result,unsigned int rowIndex,const char * columnName)125 bool PostgreSQLInterface::PQGetValueFromBinary(int *output, PGresult *result, unsigned int rowIndex, const char *columnName)
126 {
127 return PQGetValueFromBinary(output,result,(int) rowIndex,columnName);
128 }
PQGetValueFromBinary(int * output,PGresult * result,int rowIndex,const char * columnName)129 bool PostgreSQLInterface::PQGetValueFromBinary(int *output, PGresult *result, int rowIndex, const char *columnName)
130 {
131 int columnIndex = PQfnumber(result, columnName); if (columnIndex==-1) return false;
132 char *binaryData = PQgetvalue(result, rowIndex, columnIndex);
133 if (binaryData==0)
134 return false;
135 if (binaryData)
136 {
137 RakAssert(PQgetlength(result, rowIndex, columnIndex)==sizeof(int));
138 memcpy(output, binaryData, sizeof(int));
139 EndianSwapInPlace((char*)output, sizeof(int));
140 return true;
141 }
142 return false;
143 }
PQGetValueFromBinary(unsigned int * output,PGresult * result,int rowIndex,const char * columnName)144 bool PostgreSQLInterface::PQGetValueFromBinary(unsigned int *output, PGresult *result, int rowIndex, const char *columnName)
145 {
146 int columnIndex = PQfnumber(result, columnName); if (columnIndex==-1) return false;
147 char *binaryData = PQgetvalue(result, rowIndex, columnIndex);
148 if (binaryData==0 || PQgetlength(result, rowIndex, columnIndex)==0)
149 return false;
150 if (binaryData)
151 {
152 RakAssert(PQgetlength(result, rowIndex, columnIndex)==sizeof(unsigned int));
153 memcpy(output, binaryData, sizeof(unsigned int));
154 EndianSwapInPlace((char*)output, sizeof(unsigned int));
155 return true;
156 }
157 return false;
158 }
PQGetValueFromBinary(long long * output,PGresult * result,int rowIndex,const char * columnName)159 bool PostgreSQLInterface::PQGetValueFromBinary(long long *output, PGresult *result, int rowIndex, const char *columnName)
160 {
161 int columnIndex = PQfnumber(result, columnName); if (columnIndex==-1) return false;
162 char *binaryData = PQgetvalue(result, rowIndex, columnIndex);
163 if (binaryData==0)
164 return false;
165 if (binaryData)
166 {
167 RakAssert(PQgetlength(result, rowIndex, columnIndex)==sizeof(long long));
168 memcpy(output, binaryData, sizeof(long long));
169 EndianSwapInPlace((char*)output, sizeof(long long));
170 return true;
171 }
172 return false;
173 }
PQGetValueFromBinary(float * output,PGresult * result,int rowIndex,const char * columnName)174 bool PostgreSQLInterface::PQGetValueFromBinary(float *output, PGresult *result, int rowIndex, const char *columnName)
175 {
176 int columnIndex = PQfnumber(result, columnName); if (columnIndex==-1) return false;
177 char *binaryData = PQgetvalue(result, rowIndex, columnIndex);
178 if (binaryData==0)
179 return false;
180 int len = PQgetlength(result, rowIndex, columnIndex);
181 RakAssert(len==sizeof(float));
182 RakAssert(binaryData);
183 if (binaryData)
184 {
185 memcpy(output, binaryData, sizeof(float));
186 EndianSwapInPlace((char*)output, sizeof(float));
187 return true;
188 }
189 return false;
190 }
PQGetValueFromBinary(double * output,PGresult * result,int rowIndex,const char * columnName)191 bool PostgreSQLInterface::PQGetValueFromBinary(double *output, PGresult *result, int rowIndex, const char *columnName)
192 {
193 int columnIndex = PQfnumber(result, columnName); if (columnIndex==-1) return false;
194 char *binaryData = PQgetvalue(result, rowIndex, columnIndex);
195 if (binaryData==0)
196 return false;
197 int len = PQgetlength(result, rowIndex, columnIndex);
198 RakAssert(len==sizeof(double));
199 RakAssert(binaryData);
200 if (binaryData)
201 {
202 memcpy(output, binaryData, sizeof(double));
203 EndianSwapInPlace((char*)output, sizeof(double));
204 return true;
205 }
206 return false;
207 }
PQGetValueFromBinary(bool * output,PGresult * result,int rowIndex,const char * columnName)208 bool PostgreSQLInterface::PQGetValueFromBinary(bool *output, PGresult *result, int rowIndex, const char *columnName)
209 {
210 int columnIndex = PQfnumber(result, columnName); if (columnIndex==-1) return false;
211 char *binaryData = PQgetvalue(result, rowIndex, columnIndex);
212 if (binaryData==0)
213 return false;
214 *output = binaryData[0]!=0;
215
216 // Seems to return 1 byte only
217 /*
218 int tempResult=0;
219 // int len = PQgetlength(result, rowIndex, columnIndex);
220 // RakAssert(len==sizeof(int)); // bug here, returns 0, but is an int
221 RakAssert(binaryData);
222 if (binaryData)
223 {
224 memcpy(&tempResult, binaryData, sizeof(int));
225 EndianSwapInPlace((char*)&tempResult, sizeof(int));
226 *output = tempResult!=0;
227 return true;
228 }
229 */
230
231 return true;
232 }
PQGetValueFromBinary(RakNet::RakString * output,PGresult * result,int rowIndex,const char * columnName)233 bool PostgreSQLInterface::PQGetValueFromBinary(RakNet::RakString *output, PGresult *result, int rowIndex, const char *columnName)
234 {
235 int columnIndex = PQfnumber(result, columnName); if (columnIndex==-1) return false;
236 char *gv;
237 gv = PQgetvalue(result, rowIndex, columnIndex);
238 if (gv && gv[0])
239 *output=gv;
240 else
241 output->Clear();
242 return output->IsEmpty()==false;
243 }
PQGetValueFromBinary(char ** output,unsigned int * outputLength,PGresult * result,int rowIndex,const char * columnName)244 bool PostgreSQLInterface::PQGetValueFromBinary(char **output, unsigned int *outputLength, PGresult *result, int rowIndex, const char *columnName)
245 {
246 return PQGetValueFromBinary(output, (int*) outputLength,result, rowIndex,columnName);
247 }
PQGetValueFromBinary(char ** output,int * outputLength,PGresult * result,int rowIndex,const char * columnName)248 bool PostgreSQLInterface::PQGetValueFromBinary(char **output, int *outputLength, PGresult *result, int rowIndex, const char *columnName)
249 {
250 int columnIndex = PQfnumber(result, columnName);
251 if (columnIndex!=-1)
252 {
253 *outputLength=PQgetlength(result, rowIndex, columnIndex);
254 if (*outputLength==0)
255 {
256 *output=0;
257 return false;
258 }
259 else
260 {
261 *output = (char*) rakMalloc_Ex(*outputLength,__FILE__,__LINE__);
262 memcpy(*output, PQgetvalue(result, rowIndex, columnIndex), *outputLength);
263 return true;
264 }
265 }
266 else
267 return false;
268
269 }
EndianSwapInPlace(char * data,int dataLength)270 void PostgreSQLInterface::EndianSwapInPlace(char* data, int dataLength)
271 {
272 static bool alreadyNetworkOrder=(htonl(12345) == 12345);
273 if (alreadyNetworkOrder)
274 return;
275 int i;
276 char tmp;
277 for (i=0; i < dataLength/2; i++)
278 {
279 tmp=data[i];
280 data[i]=data[dataLength-1-i];
281 data[dataLength-1-i]=tmp;
282 }
283 }
284
GetLocalTimestamp(void)285 char *PostgreSQLInterface::GetLocalTimestamp(void)
286 {
287 static char strRes[512];
288
289 PGresult *result;
290 if (ExecuteBlockingCommand("SELECT LOCALTIMESTAMP", &result, false))
291 {
292 char *ts=PQgetvalue(result, 0, 0);
293 if (ts)
294 {
295 sprintf(strRes,"Local timestamp is: %s\n", ts);
296 }
297 else
298 {
299 sprintf(strRes,"Can't read current time\n");
300 }
301 PQclear(result);
302 }
303 else
304 sprintf(strRes,"Failed to read LOCALTIMESTAMP\n");
305
306 return (char*)strRes;
307 }
GetEpoch(void)308 long long PostgreSQLInterface::GetEpoch(void)
309 {
310 PGresult *result;
311 long long out;
312 result = QueryVariadic("EXTRACT(EPOCH FROM current_timestamp) as out);");
313 PostgreSQLInterface::PQGetValueFromBinary(&out, result, 0, "out");
314 PQclear(result);
315 return out;
316 }
317
GetLastError(void) const318 const char* PostgreSQLInterface::GetLastError(void) const
319 {
320 return (char*)lastError;
321 }
EncodeQueryInput(const char * colName,unsigned int value,RakNet::RakString & paramTypeStr,RakNet::RakString & valueStr,int & numParams,char ** paramData,int * paramLength,int * paramFormat)322 void PostgreSQLInterface::EncodeQueryInput(const char *colName, unsigned int value, RakNet::RakString ¶mTypeStr, RakNet::RakString &valueStr, int &numParams, char **paramData, int *paramLength, int *paramFormat)
323 {
324 (void)numParams;
325 (void)paramData;
326 (void)paramLength;
327 (void)paramFormat;
328
329 if (paramTypeStr.IsEmpty()==false)
330 {
331 paramTypeStr += ", ";
332 valueStr += ", ";
333 }
334 paramTypeStr += colName;
335 valueStr += FormatString("%i", value);
336 }
EncodeQueryUpdate(const char * colName,unsigned int value,RakNet::RakString & valueStr,int & numParams,char ** paramData,int * paramLength,int * paramFormat)337 void PostgreSQLInterface::EncodeQueryUpdate(const char *colName, unsigned int value, RakNet::RakString &valueStr, int &numParams, char **paramData, int *paramLength, int *paramFormat)
338 {
339 (void)numParams;
340 (void)paramData;
341 (void)paramLength;
342 (void)paramFormat;
343
344 if (valueStr.IsEmpty()==false)
345 {
346 valueStr += ", ";
347 }
348 valueStr += colName;
349 valueStr += " = ";
350 valueStr += FormatString("%i", value);
351 }
EncodeQueryInput(const char * colName,int value,RakNet::RakString & paramTypeStr,RakNet::RakString & valueStr,int & numParams,char ** paramData,int * paramLength,int * paramFormat)352 void PostgreSQLInterface::EncodeQueryInput(const char *colName, int value, RakNet::RakString ¶mTypeStr, RakNet::RakString &valueStr, int &numParams, char **paramData, int *paramLength, int *paramFormat)
353 {
354 (void)numParams;
355 (void)paramData;
356 (void)paramLength;
357 (void)paramFormat;
358
359 if (paramTypeStr.IsEmpty()==false)
360 {
361 paramTypeStr += ", ";
362 valueStr += ", ";
363 }
364 paramTypeStr += colName;
365 valueStr += FormatString("%i", value);
366 }
EncodeQueryInput(const char * colName,bool value,RakNet::RakString & paramTypeStr,RakNet::RakString & valueStr,int & numParams,char ** paramData,int * paramLength,int * paramFormat)367 void PostgreSQLInterface::EncodeQueryInput(const char *colName, bool value, RakNet::RakString ¶mTypeStr, RakNet::RakString &valueStr, int &numParams, char **paramData, int *paramLength, int *paramFormat)
368 {
369 (void)numParams;
370 (void)paramData;
371 (void)paramLength;
372 (void)paramFormat;
373
374 if (paramTypeStr.IsEmpty()==false)
375 {
376 paramTypeStr += ", ";
377 valueStr += ", ";
378 }
379 paramTypeStr += colName;
380 if (value)
381 valueStr += "true";
382 else
383 valueStr += "false";
384 }
EncodeQueryUpdate(const char * colName,int value,RakNet::RakString & valueStr,int & numParams,char ** paramData,int * paramLength,int * paramFormat)385 void PostgreSQLInterface::EncodeQueryUpdate(const char *colName, int value, RakNet::RakString &valueStr, int &numParams, char **paramData, int *paramLength, int *paramFormat)
386 {
387 (void)numParams;
388 (void)paramData;
389 (void)paramLength;
390 (void)paramFormat;
391
392 if (valueStr.IsEmpty()==false)
393 {
394 valueStr += ", ";
395 }
396 valueStr += colName;
397 valueStr += " = ";
398 valueStr += FormatString("%i", value);
399 }
EncodeQueryInput(const char * colName,float value,RakNet::RakString & paramTypeStr,RakNet::RakString & valueStr,int & numParams,char ** paramData,int * paramLength,int * paramFormat)400 void PostgreSQLInterface::EncodeQueryInput(const char *colName, float value, RakNet::RakString ¶mTypeStr, RakNet::RakString &valueStr, int &numParams, char **paramData, int *paramLength, int *paramFormat)
401 {
402 (void)numParams;
403 (void)paramData;
404 (void)paramLength;
405 (void)paramFormat;
406
407 if (paramTypeStr.IsEmpty()==false)
408 {
409 paramTypeStr += ", ";
410 valueStr += ", ";
411 }
412 paramTypeStr += colName;
413 valueStr += FormatString("%f", value);
414 }
EncodeQueryUpdate(const char * colName,float value,RakNet::RakString & valueStr,int & numParams,char ** paramData,int * paramLength,int * paramFormat)415 void PostgreSQLInterface::EncodeQueryUpdate(const char *colName, float value, RakNet::RakString &valueStr, int &numParams, char **paramData, int *paramLength, int *paramFormat)
416 {
417 (void)numParams;
418 (void)paramData;
419 (void)paramLength;
420 (void)paramFormat;
421
422 if (valueStr.IsEmpty()==false)
423 {
424 valueStr += ", ";
425 }
426 valueStr += colName;
427 valueStr += " = ";
428 valueStr += FormatString("%f", value);
429 }
EncodeQueryInput(const char * colName,char * binaryData,int binaryDataLength,RakNet::RakString & paramTypeStr,RakNet::RakString & valueStr,int & numParams,char ** paramData,int * paramLength,int * paramFormat,bool writeEmpty)430 void PostgreSQLInterface::EncodeQueryInput(const char *colName, char *binaryData, int binaryDataLength, RakNet::RakString ¶mTypeStr, RakNet::RakString &valueStr, int &numParams, char **paramData, int *paramLength, int *paramFormat, bool writeEmpty)
431 {
432 if (writeEmpty==false && (binaryData==0 || binaryDataLength==0))
433 return;
434
435 if (binaryData==0)
436 binaryDataLength=0;
437
438 if (paramTypeStr.IsEmpty()==false)
439 {
440 paramTypeStr += ", ";
441 valueStr += ", ";
442 }
443 paramTypeStr += colName;
444 valueStr+=FormatString("$%i::bytea", numParams+1);
445
446 paramData[numParams]=binaryData;
447 paramLength[numParams]=binaryDataLength;
448 paramFormat[numParams]=PQEXECPARAM_FORMAT_BINARY;
449 numParams++;
450 }
EncodeQueryUpdate(const char * colName,char * binaryData,int binaryDataLength,RakNet::RakString & valueStr,int & numParams,char ** paramData,int * paramLength,int * paramFormat)451 void PostgreSQLInterface::EncodeQueryUpdate(const char *colName, char *binaryData, int binaryDataLength, RakNet::RakString &valueStr, int &numParams, char **paramData, int *paramLength, int *paramFormat)
452 {
453 if (binaryData==0 || binaryDataLength==0)
454 return;
455
456 if (binaryData==0)
457 binaryDataLength=0;
458
459 if (valueStr.IsEmpty()==false)
460 {
461 valueStr += ", ";
462 }
463 valueStr += colName;
464 valueStr += " = ";
465 valueStr+=FormatString("$%i::bytea", numParams+1);
466
467 paramData[numParams]=binaryData;
468 paramLength[numParams]=binaryDataLength;
469 paramFormat[numParams]=PQEXECPARAM_FORMAT_BINARY;
470 numParams++;
471 }
EncodeQueryInput(const char * colName,const char * str,RakNet::RakString & paramTypeStr,RakNet::RakString & valueStr,int & numParams,char ** paramData,int * paramLength,int * paramFormat,bool writeEmpty,const char * type)472 void PostgreSQLInterface::EncodeQueryInput(const char *colName, const char *str, RakNet::RakString ¶mTypeStr, RakNet::RakString &valueStr, int &numParams, char **paramData, int *paramLength, int *paramFormat, bool writeEmpty, const char *type)
473 {
474 if (writeEmpty==false && (str==0 || str[0]==0))
475 return;
476
477 static char *emptyStr="";
478 static char *emptyDate="01/01/01";
479
480 if (paramTypeStr.IsEmpty()==false)
481 {
482 paramTypeStr += ", ";
483 valueStr += ", ";
484 }
485 paramTypeStr += colName;
486 valueStr+=FormatString("$%i::%s", numParams+1, type);
487
488 if (writeEmpty && (str==0 || str[0]==0))
489 {
490 if (strcmp(type,"date")==0)
491 {
492 paramData[numParams]=emptyDate;
493 paramLength[numParams]=(int)strlen(emptyDate);
494 }
495 else
496 {
497 paramData[numParams]=emptyStr;
498 paramLength[numParams]=0;
499 }
500 }
501 else
502 {
503 paramData[numParams]=(char*) str;
504 paramLength[numParams]=(int) strlen(str);
505 }
506 paramFormat[numParams]=PQEXECPARAM_FORMAT_TEXT;
507 numParams++;
508 }
EncodeQueryUpdate(const char * colName,const char * str,RakNet::RakString & valueStr,int & numParams,char ** paramData,int * paramLength,int * paramFormat,const char * type)509 void PostgreSQLInterface::EncodeQueryUpdate(const char *colName, const char *str, RakNet::RakString &valueStr, int &numParams, char **paramData, int *paramLength, int *paramFormat, const char *type)
510 {
511 if (str==0 || str[0]==0)
512 return;
513
514 if (valueStr.IsEmpty()==false)
515 {
516 valueStr += ", ";
517 }
518 valueStr += colName;
519 valueStr+=" = ";
520 valueStr+=FormatString("$%i::%s", numParams+1, type);
521
522 paramData[numParams]=(char*) str;
523 paramLength[numParams]=(int) strlen(str);
524
525 paramFormat[numParams]=PQEXECPARAM_FORMAT_TEXT;
526 numParams++;
527 }
EncodeQueryInput(const char * colName,const RakNet::RakString & str,RakNet::RakString & paramTypeStr,RakNet::RakString & valueStr,int & numParams,char ** paramData,int * paramLength,int * paramFormat,bool writeEmpty,const char * type)528 void PostgreSQLInterface::EncodeQueryInput(const char *colName, const RakNet::RakString &str, RakNet::RakString ¶mTypeStr, RakNet::RakString &valueStr, int &numParams, char **paramData, int *paramLength, int *paramFormat, bool writeEmpty, const char *type)
529 {
530 EncodeQueryInput(colName, str.C_String(), paramTypeStr, valueStr, numParams, paramData, paramLength, paramFormat, writeEmpty, type);
531 }
EncodeQueryUpdate(const char * colName,const RakNet::RakString & str,RakNet::RakString & valueStr,int & numParams,char ** paramData,int * paramLength,int * paramFormat,const char * type)532 void PostgreSQLInterface::EncodeQueryUpdate(const char *colName, const RakNet::RakString &str, RakNet::RakString &valueStr, int &numParams, char **paramData, int *paramLength, int *paramFormat, const char *type)
533 {
534 EncodeQueryUpdate(colName, str.C_String(), valueStr, numParams, paramData, paramLength, paramFormat, type);
535 }
GetEscapedString(const char * input) const536 RakNet::RakString PostgreSQLInterface::GetEscapedString(const char *input) const
537 {
538 unsigned long len = (unsigned long) strlen(input);
539 char *fn = (char*) rakMalloc_Ex(len*2+1,__FILE__,__LINE__);
540 int error;
541 PQescapeStringConn(pgConn, fn, input, len, &error);
542 RakNet::RakString output;
543 // Use assignment so it doesn't parse printf escape strings
544 output = fn;
545 rakFree_Ex(fn,__FILE__,__LINE__);
546 return output;
547 }
548
QueryVariadic(const char * input,...)549 PGresult * PostgreSQLInterface::QueryVariadic( const char * input, ... )
550 {
551 RakNet::RakString query;
552 PGresult *result;
553 DataStructures::List<VariadicSQLParser::IndexAndType> indices;
554 if ( input==0 || input[0]==0 )
555 return 0;
556
557 // Lookup this query in the stored query table. If it doesn't exist, prepare it.
558 RakNet::RakString inputStr;
559 inputStr=input;
560 unsigned int preparedQueryIndex;
561 for (preparedQueryIndex=0; preparedQueryIndex < preparedQueries.Size(); preparedQueryIndex++)
562 {
563 if (preparedQueries[preparedQueryIndex].StrICmp(inputStr)==0)
564 break;
565 }
566
567 // Find out how many params there are
568 // Find out the type of each param (%f, %s)
569 indices.Clear(false, __FILE__, __LINE__);
570 GetTypeMappingIndices( input, indices );
571
572 if (preparedQueryIndex==preparedQueries.Size())
573 {
574 // if (indices.Size()>0)
575 // query += " (";
576 RakNet::RakString formatCopy;
577 RakNet::RakString insertion;
578 formatCopy=input;
579 unsigned int i;
580 unsigned int indexOffset=0;
581 for (i=0; i < indices.Size(); i++)
582 {
583 // if (i!=0)
584 // query += ",";
585 // query+=typeMappings[indices[i].typeMappingIndex].type;
586 formatCopy.SetChar(indices[i].strIndex+indexOffset, '$');
587 // if (i < 9)
588 // formatCopy.SetChar(indices[i].strIndex+1, i+1+'0');
589 // else
590 insertion=RakNet::RakString("%i::%s", i+1, VariadicSQLParser::GetTypeMappingAtIndex(indices[i].typeMappingIndex));
591 formatCopy.SetChar(indices[i].strIndex+1+indexOffset, insertion);
592 indexOffset+=(unsigned int) insertion.GetLength()-1;
593 }
594 // if (indices.Size()>0)
595 // query += ")";
596 // query += " AS ";
597 query += formatCopy;
598 // query += ";\n";
599 formatCopy+= ";\n";
600 result = PQprepare(pgConn, RakNet::RakString("PGSQL_ExecuteVariadic_%i", preparedQueries.Size()), formatCopy.C_String(), indices.Size(), NULL);
601 if (IsResultSuccessful(result, false))
602 {
603 PQclear(result);
604 preparedQueries.Insert(inputStr, __FILE__, __LINE__);
605 }
606 else
607 {
608 printf(formatCopy.C_String());
609 printf("\n");
610 printf(lastError);
611 RakAssert(0);
612 PQclear(result);
613 return 0;
614 }
615 }
616
617 // char *paramData[512];
618 // int paramLength[512];
619 // int paramFormat[512];
620
621 va_list argptr;
622 va_start(argptr, input);
623 char **paramData;
624 int *paramLength;
625 int *paramFormat;
626 ExtractArguments(argptr, indices, ¶mData, ¶mLength);
627 paramFormat=RakNet::OP_NEW_ARRAY<int>(indices.Size(),__FILE__,__LINE__);
628 for (unsigned int i=0; i < indices.Size(); i++)
629 paramFormat[i]=PQEXECPARAM_FORMAT_BINARY;
630 result = PQexecPrepared(pgConn, RakNet::RakString("PGSQL_ExecuteVariadic_%i", preparedQueryIndex), indices.Size(), paramData, paramLength, paramFormat, PQEXECPARAM_FORMAT_BINARY );
631 VariadicSQLParser::FreeArguments(indices, paramData, paramLength);
632 RakNet::OP_DELETE_ARRAY(paramFormat,__FILE__,__LINE__);
633 va_end(argptr);
634
635 if (IsResultSuccessful(result, false)==false)
636 {
637 printf(lastError);
638 PQclear(result);
639 return 0;
640 }
641 return result;
642 }
643 /*
644 PGresult * PostgreSQLInterface::QueryVariadic( const char * input, ... )
645 {
646 RakNet::RakString query;
647 PGresult *result;
648 unsigned int i;
649 DataStructures::List<IndexAndType> indices;
650 if ( input==0 || input[0]==0 )
651 return 0;
652
653 // Find out how many params there are
654 // Find out the type of each param (%f, %s)
655 GetTypeMappingIndices( input, indices );
656
657 char *paramData[512];
658 int paramLength[512];
659 int paramFormat[512];
660
661 va_list argptr;
662 int variadicArgIndex;
663 va_start(argptr, input);
664 for (variadicArgIndex=0, i=0; i < indices.Size(); i++, variadicArgIndex++)
665 {
666 if (typeMappings[indices[i].typeMappingIndex].inputType=='i' ||
667 typeMappings[indices[i].typeMappingIndex].inputType=='d')
668 {
669 int val = va_arg( argptr, int );
670 paramData[i]=(char*) &val;
671 paramLength[i]=sizeof(val);
672 if (RakNet::BitStream::IsNetworkOrder()==false) RakNet::BitStream::ReverseBytesInPlace((unsigned char*) paramData[i], paramLength[i]);
673 }
674 else if (typeMappings[indices[i].typeMappingIndex].inputType=='s')
675 {
676 char* val = va_arg( argptr, char* );
677 paramData[i]=val;
678 paramLength[i]=(int) strlen(val);
679 }
680 else if (typeMappings[indices[i].typeMappingIndex].inputType=='b')
681 {
682 bool val = va_arg( argptr, bool );
683 paramData[i]=(char*) &val;
684 paramLength[i]=sizeof(bool);
685 if (RakNet::BitStream::IsNetworkOrder()==false) RakNet::BitStream::ReverseBytesInPlace((unsigned char*) paramData[i], paramLength[i]);
686 }
687 else if (typeMappings[indices[i].typeMappingIndex].inputType=='f')
688 {
689 float val = va_arg( argptr, float );
690 paramData[i]=(char*) &val;
691 paramLength[i]=sizeof(float);
692 if (RakNet::BitStream::IsNetworkOrder()==false) RakNet::BitStream::ReverseBytesInPlace((unsigned char*) paramData[i], paramLength[i]);
693 }
694 else if (typeMappings[indices[i].typeMappingIndex].inputType=='g')
695 {
696 double val = va_arg( argptr, double );
697 paramData[i]=(char*) &val;
698 paramLength[i]=sizeof(double);
699 if (RakNet::BitStream::IsNetworkOrder()==false) RakNet::BitStream::ReverseBytesInPlace((unsigned char*) paramData[i], paramLength[i]);
700 }
701 else if (typeMappings[indices[i].typeMappingIndex].inputType=='a')
702 {
703 char* val = va_arg( argptr, char* );
704 paramData[i]=val;
705 variadicArgIndex++;
706 paramLength[i]=va_arg( argptr, unsigned int );
707 }
708 paramFormat[i]=PQEXECPARAM_FORMAT_BINARY;
709 }
710
711 // Replace each %whatever with $index::type
712 RakNet::RakString inputCopy;
713 inputCopy=input;
714 unsigned int lastIndex=0;
715 for (i=0; i < indices.Size(); i++)
716 {
717 query+=inputCopy.SubStr(lastIndex, indices[i].strIndex-lastIndex);
718 query+=RakNet::RakString("$%i::", i+1);
719 query+=typeMappings[indices[i].typeMappingIndex].type;
720 lastIndex=indices[i].strIndex+2; // +2 is to skip the %whateverCharacter
721 }
722 query+=inputCopy.SubStr(lastIndex, (unsigned int)-1);
723
724 result = PQexecParams(pgConn, query.C_String(),indices.Size(),0,paramData,paramLength,paramFormat,PQEXECPARAM_FORMAT_BINARY);
725 if (IsResultSuccessful(result, false)==false)
726 {
727 PQclear(result);
728 return 0;
729 }
730 return result;
731 }
732 */
ClearResult(PGresult * result)733 void PostgreSQLInterface::ClearResult(PGresult *result)
734 {
735 PQclear(result);
736 }