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 &paramTypeStr, 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 &paramTypeStr, 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 &paramTypeStr, 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 &paramTypeStr, 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 &paramTypeStr, 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 &paramTypeStr, 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 &paramTypeStr, 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, &paramData, &paramLength);
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 }