]> Creatis software - creaImageIO.git/blob - src/CppSQLite3.cpp
start!
[creaImageIO.git] / src / CppSQLite3.cpp
1 ////////////////////////////////////////////////////////////////////////////////\r
2 // CppSQLite3 - A C++ wrapper around the SQLite3 embedded database library.\r
3 //\r
4 // Copyright (c) 2004 Rob Groves. All Rights Reserved. rob.groves@btinternet.com\r
5 // \r
6 // Permission to use, copy, modify, and distribute this software and its\r
7 // documentation for any purpose, without fee, and without a written\r
8 // agreement, is hereby granted, provided that the above copyright notice, \r
9 // this paragraph and the following two paragraphs appear in all copies, \r
10 // modifications, and distributions.\r
11 //\r
12 // IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT,\r
13 // INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST\r
14 // PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,\r
15 // EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
16 //\r
17 // THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT\r
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A\r
19 // PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF\r
20 // ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". THE AUTHOR HAS NO OBLIGATION\r
21 // TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.\r
22 //\r
23 // V3.0         03/08/2004      -Initial Version for sqlite3\r
24 //\r
25 // V3.1         16/09/2004      -Implemented getXXXXField using sqlite3 functions\r
26 //                                              -Added CppSQLiteDB3::tableExists()\r
27 ////////////////////////////////////////////////////////////////////////////////\r
28 #include "CppSQLite3.h"\r
29 #include <cstdlib>\r
30 \r
31 \r
32 // Named constant for passing to CppSQLite3Exception when passing it a string\r
33 // that cannot be deleted.\r
34 static const bool DONT_DELETE_MSG=false;\r
35 \r
36 ////////////////////////////////////////////////////////////////////////////////\r
37 // Prototypes for SQLite functions not included in SQLite DLL, but copied below\r
38 // from SQLite encode.c\r
39 ////////////////////////////////////////////////////////////////////////////////\r
40 int sqlite3_encode_binary(const unsigned char *in, int n, unsigned char *out);\r
41 int sqlite3_decode_binary(const unsigned char *in, unsigned char *out);\r
42 \r
43 ////////////////////////////////////////////////////////////////////////////////\r
44 \r
45 ////////////////////////////////////////////////////////////////////////////////\r
46 \r
47 CppSQLite3Exception::CppSQLite3Exception(const int nErrCode,\r
48                                                                         char* szErrMess,\r
49                                                                         bool bDeleteMsg/*=true*/) :\r
50                                                                         mnErrCode(nErrCode)\r
51 {\r
52         mpszErrMess = sqlite3_mprintf("%s[%d]: %s",\r
53                                                                 errorCodeAsString(nErrCode),\r
54                                                                 nErrCode,\r
55                                                                 szErrMess ? szErrMess : "");\r
56 \r
57         if (bDeleteMsg && szErrMess)\r
58         {\r
59                 sqlite3_free(szErrMess);\r
60         }\r
61 }\r
62 \r
63                                                                         \r
64 CppSQLite3Exception::CppSQLite3Exception(const CppSQLite3Exception&  e) :\r
65                                                                         mnErrCode(e.mnErrCode)\r
66 {\r
67         mpszErrMess = 0;\r
68         if (e.mpszErrMess)\r
69         {\r
70                 mpszErrMess = sqlite3_mprintf("%s", e.mpszErrMess);\r
71         }\r
72 }\r
73 \r
74 \r
75 const char* CppSQLite3Exception::errorCodeAsString(int nErrCode)\r
76 {\r
77         switch (nErrCode)\r
78         {\r
79                 case SQLITE_OK          : return "SQLITE_OK";\r
80                 case SQLITE_ERROR       : return "SQLITE_ERROR";\r
81                 case SQLITE_INTERNAL    : return "SQLITE_INTERNAL";\r
82                 case SQLITE_PERM        : return "SQLITE_PERM";\r
83                 case SQLITE_ABORT       : return "SQLITE_ABORT";\r
84                 case SQLITE_BUSY        : return "SQLITE_BUSY";\r
85                 case SQLITE_LOCKED      : return "SQLITE_LOCKED";\r
86                 case SQLITE_NOMEM       : return "SQLITE_NOMEM";\r
87                 case SQLITE_READONLY    : return "SQLITE_READONLY";\r
88                 case SQLITE_INTERRUPT   : return "SQLITE_INTERRUPT";\r
89                 case SQLITE_IOERR       : return "SQLITE_IOERR";\r
90                 case SQLITE_CORRUPT     : return "SQLITE_CORRUPT";\r
91                 case SQLITE_NOTFOUND    : return "SQLITE_NOTFOUND";\r
92                 case SQLITE_FULL        : return "SQLITE_FULL";\r
93                 case SQLITE_CANTOPEN    : return "SQLITE_CANTOPEN";\r
94                 case SQLITE_PROTOCOL    : return "SQLITE_PROTOCOL";\r
95                 case SQLITE_EMPTY       : return "SQLITE_EMPTY";\r
96                 case SQLITE_SCHEMA      : return "SQLITE_SCHEMA";\r
97                 case SQLITE_TOOBIG      : return "SQLITE_TOOBIG";\r
98                 case SQLITE_CONSTRAINT  : return "SQLITE_CONSTRAINT";\r
99                 case SQLITE_MISMATCH    : return "SQLITE_MISMATCH";\r
100                 case SQLITE_MISUSE      : return "SQLITE_MISUSE";\r
101                 case SQLITE_NOLFS       : return "SQLITE_NOLFS";\r
102                 case SQLITE_AUTH        : return "SQLITE_AUTH";\r
103                 case SQLITE_FORMAT      : return "SQLITE_FORMAT";\r
104                 case SQLITE_RANGE       : return "SQLITE_RANGE";\r
105                 case SQLITE_ROW         : return "SQLITE_ROW";\r
106                 case SQLITE_DONE        : return "SQLITE_DONE";\r
107                 case CPPSQLITE_ERROR    : return "CPPSQLITE_ERROR";\r
108                 default: return "UNKNOWN_ERROR";\r
109         }\r
110 }\r
111 \r
112 \r
113 CppSQLite3Exception::~CppSQLite3Exception()\r
114 {\r
115         if (mpszErrMess)\r
116         {\r
117                 sqlite3_free(mpszErrMess);\r
118                 mpszErrMess = 0;\r
119         }\r
120 }\r
121 \r
122 \r
123 ////////////////////////////////////////////////////////////////////////////////\r
124 \r
125 CppSQLite3Buffer::CppSQLite3Buffer()\r
126 {\r
127         mpBuf = 0;\r
128 }\r
129 \r
130 \r
131 CppSQLite3Buffer::~CppSQLite3Buffer()\r
132 {\r
133         clear();\r
134 }\r
135 \r
136 \r
137 void CppSQLite3Buffer::clear()\r
138 {\r
139         if (mpBuf)\r
140         {\r
141                 sqlite3_free(mpBuf);\r
142                 mpBuf = 0;\r
143         }\r
144 \r
145 }\r
146 \r
147 \r
148 const char* CppSQLite3Buffer::format(const char* szFormat, ...)\r
149 {\r
150         clear();\r
151         va_list va;\r
152         va_start(va, szFormat);\r
153         mpBuf = sqlite3_vmprintf(szFormat, va);\r
154         va_end(va);\r
155         return mpBuf;\r
156 }\r
157 \r
158 \r
159 ////////////////////////////////////////////////////////////////////////////////\r
160 \r
161 CppSQLite3Binary::CppSQLite3Binary() :\r
162                                                 mpBuf(0),\r
163                                                 mnBinaryLen(0),\r
164                                                 mnBufferLen(0),\r
165                                                 mnEncodedLen(0),\r
166                                                 mbEncoded(false)\r
167 {\r
168 }\r
169 \r
170 \r
171 CppSQLite3Binary::~CppSQLite3Binary()\r
172 {\r
173         clear();\r
174 }\r
175 \r
176 \r
177 void CppSQLite3Binary::setBinary(const unsigned char* pBuf, int nLen)\r
178 {\r
179         mpBuf = allocBuffer(nLen);\r
180         memcpy(mpBuf, pBuf, nLen);\r
181 }\r
182 \r
183 \r
184 void CppSQLite3Binary::setEncoded(const unsigned char* pBuf)\r
185 {\r
186         clear();\r
187 \r
188         mnEncodedLen = strlen((const char*)pBuf);\r
189         mnBufferLen = mnEncodedLen + 1; // Allow for NULL terminator\r
190 \r
191         mpBuf = (unsigned char*)malloc(mnBufferLen);\r
192 \r
193         if (!mpBuf)\r
194         {\r
195                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
196                                                                 "Cannot allocate memory",\r
197                                                                 DONT_DELETE_MSG);\r
198         }\r
199 \r
200         memcpy(mpBuf, pBuf, mnBufferLen);\r
201         mbEncoded = true;\r
202 }\r
203 \r
204 \r
205 const unsigned char* CppSQLite3Binary::getEncoded()\r
206 {\r
207         if (!mbEncoded)\r
208         {\r
209                 unsigned char* ptmp = (unsigned char*)malloc(mnBinaryLen);\r
210                 memcpy(ptmp, mpBuf, mnBinaryLen);\r
211                 mnEncodedLen = sqlite3_encode_binary(ptmp, mnBinaryLen, mpBuf);\r
212                 free(ptmp);\r
213                 mbEncoded = true;\r
214         }\r
215 \r
216         return mpBuf;\r
217 }\r
218 \r
219 \r
220 const unsigned char* CppSQLite3Binary::getBinary()\r
221 {\r
222         if (mbEncoded)\r
223         {\r
224                 // in/out buffers can be the same\r
225                 mnBinaryLen = sqlite3_decode_binary(mpBuf, mpBuf);\r
226 \r
227                 if (mnBinaryLen == -1)\r
228                 {\r
229                         throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
230                                                                         "Cannot decode binary",\r
231                                                                         DONT_DELETE_MSG);\r
232                 }\r
233 \r
234                 mbEncoded = false;\r
235         }\r
236 \r
237         return mpBuf;\r
238 }\r
239 \r
240 \r
241 int CppSQLite3Binary::getBinaryLength()\r
242 {\r
243         getBinary();\r
244         return mnBinaryLen;\r
245 }\r
246 \r
247 \r
248 unsigned char* CppSQLite3Binary::allocBuffer(int nLen)\r
249 {\r
250         clear();\r
251 \r
252         // Allow extra space for encoded binary as per comments in\r
253         // SQLite encode.c See bottom of this file for implementation\r
254         // of SQLite functions use 3 instead of 2 just to be sure ;-)\r
255         mnBinaryLen = nLen;\r
256         mnBufferLen = 3 + (257*nLen)/254;\r
257 \r
258         mpBuf = (unsigned char*)malloc(mnBufferLen);\r
259 \r
260         if (!mpBuf)\r
261         {\r
262                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
263                                                                 "Cannot allocate memory",\r
264                                                                 DONT_DELETE_MSG);\r
265         }\r
266 \r
267         mbEncoded = false;\r
268 \r
269         return mpBuf;\r
270 }\r
271 \r
272 \r
273 void CppSQLite3Binary::clear()\r
274 {\r
275         if (mpBuf)\r
276         {\r
277                 mnBinaryLen = 0;\r
278                 mnBufferLen = 0;\r
279                 free(mpBuf);\r
280                 mpBuf = 0;\r
281         }\r
282 }\r
283 \r
284 \r
285 ////////////////////////////////////////////////////////////////////////////////\r
286 \r
287 CppSQLite3Query::CppSQLite3Query()\r
288 {\r
289         mpVM = 0;\r
290         mbEof = true;\r
291         mnCols = 0;\r
292         mbOwnVM = false;\r
293 }\r
294 \r
295 \r
296 CppSQLite3Query::CppSQLite3Query(const CppSQLite3Query& rQuery)\r
297 {\r
298         mpVM = rQuery.mpVM;\r
299         // Only one object can own the VM\r
300         const_cast<CppSQLite3Query&>(rQuery).mpVM = 0;\r
301         mbEof = rQuery.mbEof;\r
302         mnCols = rQuery.mnCols;\r
303         mbOwnVM = rQuery.mbOwnVM;\r
304 }\r
305 \r
306 \r
307 CppSQLite3Query::CppSQLite3Query(sqlite3* pDB,\r
308                                                         sqlite3_stmt* pVM,\r
309                                                         bool bEof,\r
310                                                         bool bOwnVM/*=true*/)\r
311 {\r
312         mpDB = pDB;\r
313         mpVM = pVM;\r
314         mbEof = bEof;\r
315         mnCols = sqlite3_column_count(mpVM);\r
316         mbOwnVM = bOwnVM;\r
317 }\r
318 \r
319 \r
320 CppSQLite3Query::~CppSQLite3Query()\r
321 {\r
322         try\r
323         {\r
324                 finalize();\r
325         }\r
326         catch (...)\r
327         {\r
328         }\r
329 }\r
330 \r
331 \r
332 CppSQLite3Query& CppSQLite3Query::operator=(const CppSQLite3Query& rQuery)\r
333 {\r
334         try\r
335         {\r
336                 finalize();\r
337         }\r
338         catch (...)\r
339         {\r
340         }\r
341         mpVM = rQuery.mpVM;\r
342         // Only one object can own the VM\r
343         const_cast<CppSQLite3Query&>(rQuery).mpVM = 0;\r
344         mbEof = rQuery.mbEof;\r
345         mnCols = rQuery.mnCols;\r
346         mbOwnVM = rQuery.mbOwnVM;\r
347         return *this;\r
348 }\r
349 \r
350 \r
351 int CppSQLite3Query::numFields()\r
352 {\r
353         checkVM();\r
354         return mnCols;\r
355 }\r
356 \r
357 \r
358 const char* CppSQLite3Query::fieldValue(int nField)\r
359 {\r
360         checkVM();\r
361 \r
362         if (nField < 0 || nField > mnCols-1)\r
363         {\r
364                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
365                                                                 "Invalid field index requested",\r
366                                                                 DONT_DELETE_MSG);\r
367         }\r
368 \r
369         return (const char*)sqlite3_column_text(mpVM, nField);\r
370 }\r
371 \r
372 \r
373 const char* CppSQLite3Query::fieldValue(const char* szField)\r
374 {\r
375         int nField = fieldIndex(szField);\r
376         return (const char*)sqlite3_column_text(mpVM, nField);\r
377 }\r
378 \r
379 \r
380 int CppSQLite3Query::getIntField(int nField, int nNullValue/*=0*/)\r
381 {\r
382         if (fieldDataType(nField) == SQLITE_NULL)\r
383         {\r
384                 return nNullValue;\r
385         }\r
386         else\r
387         {\r
388                 return sqlite3_column_int(mpVM, nField);\r
389         }\r
390 }\r
391 \r
392 \r
393 int CppSQLite3Query::getIntField(const char* szField, int nNullValue/*=0*/)\r
394 {\r
395         int nField = fieldIndex(szField);\r
396         return getIntField(nField, nNullValue);\r
397 }\r
398 \r
399 \r
400 double CppSQLite3Query::getFloatField(int nField, double fNullValue/*=0.0*/)\r
401 {\r
402         if (fieldDataType(nField) == SQLITE_NULL)\r
403         {\r
404                 return fNullValue;\r
405         }\r
406         else\r
407         {\r
408                 return sqlite3_column_double(mpVM, nField);\r
409         }\r
410 }\r
411 \r
412 \r
413 double CppSQLite3Query::getFloatField(const char* szField, double fNullValue/*=0.0*/)\r
414 {\r
415         int nField = fieldIndex(szField);\r
416         return getFloatField(nField, fNullValue);\r
417 }\r
418 \r
419 \r
420 const char* CppSQLite3Query::getStringField(int nField, const char* szNullValue/*=""*/)\r
421 {\r
422         if (fieldDataType(nField) == SQLITE_NULL)\r
423         {\r
424                 return szNullValue;\r
425         }\r
426         else\r
427         {\r
428                 return (const char*)sqlite3_column_text(mpVM, nField);\r
429         }\r
430 }\r
431 \r
432 \r
433 const char* CppSQLite3Query::getStringField(const char* szField, const char* szNullValue/*=""*/)\r
434 {\r
435         int nField = fieldIndex(szField);\r
436         return getStringField(nField, szNullValue);\r
437 }\r
438 \r
439 \r
440 const unsigned char* CppSQLite3Query::getBlobField(int nField, int& nLen)\r
441 {\r
442         checkVM();\r
443 \r
444         if (nField < 0 || nField > mnCols-1)\r
445         {\r
446                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
447                                                                 "Invalid field index requested",\r
448                                                                 DONT_DELETE_MSG);\r
449         }\r
450 \r
451         nLen = sqlite3_column_bytes(mpVM, nField);\r
452         return (const unsigned char*)sqlite3_column_blob(mpVM, nField);\r
453 }\r
454 \r
455 \r
456 const unsigned char* CppSQLite3Query::getBlobField(const char* szField, int& nLen)\r
457 {\r
458         int nField = fieldIndex(szField);\r
459         return getBlobField(nField, nLen);\r
460 }\r
461 \r
462 \r
463 bool CppSQLite3Query::fieldIsNull(int nField)\r
464 {\r
465         return (fieldDataType(nField) == SQLITE_NULL);\r
466 }\r
467 \r
468 \r
469 bool CppSQLite3Query::fieldIsNull(const char* szField)\r
470 {\r
471         int nField = fieldIndex(szField);\r
472         return (fieldDataType(nField) == SQLITE_NULL);\r
473 }\r
474 \r
475 \r
476 int CppSQLite3Query::fieldIndex(const char* szField)\r
477 {\r
478         checkVM();\r
479 \r
480         if (szField)\r
481         {\r
482                 for (int nField = 0; nField < mnCols; nField++)\r
483                 {\r
484                         const char* szTemp = sqlite3_column_name(mpVM, nField);\r
485 \r
486                         if (strcmp(szField, szTemp) == 0)\r
487                         {\r
488                                 return nField;\r
489                         }\r
490                 }\r
491         }\r
492 \r
493         throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
494                                                         "Invalid field name requested",\r
495                                                         DONT_DELETE_MSG);\r
496 }\r
497 \r
498 \r
499 const char* CppSQLite3Query::fieldName(int nCol)\r
500 {\r
501         checkVM();\r
502 \r
503         if (nCol < 0 || nCol > mnCols-1)\r
504         {\r
505                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
506                                                                 "Invalid field index requested",\r
507                                                                 DONT_DELETE_MSG);\r
508         }\r
509 \r
510         return sqlite3_column_name(mpVM, nCol);\r
511 }\r
512 \r
513 \r
514 const char* CppSQLite3Query::fieldDeclType(int nCol)\r
515 {\r
516         checkVM();\r
517 \r
518         if (nCol < 0 || nCol > mnCols-1)\r
519         {\r
520                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
521                                                                 "Invalid field index requested",\r
522                                                                 DONT_DELETE_MSG);\r
523         }\r
524 \r
525         return sqlite3_column_decltype(mpVM, nCol);\r
526 }\r
527 \r
528 \r
529 int CppSQLite3Query::fieldDataType(int nCol)\r
530 {\r
531         checkVM();\r
532 \r
533         if (nCol < 0 || nCol > mnCols-1)\r
534         {\r
535                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
536                                                                 "Invalid field index requested",\r
537                                                                 DONT_DELETE_MSG);\r
538         }\r
539 \r
540         return sqlite3_column_type(mpVM, nCol);\r
541 }\r
542 \r
543 \r
544 bool CppSQLite3Query::eof()\r
545 {\r
546         checkVM();\r
547         return mbEof;\r
548 }\r
549 \r
550 \r
551 void CppSQLite3Query::nextRow()\r
552 {\r
553         checkVM();\r
554 \r
555         int nRet = sqlite3_step(mpVM);\r
556 \r
557         if (nRet == SQLITE_DONE)\r
558         {\r
559                 // no rows\r
560                 mbEof = true;\r
561         }\r
562         else if (nRet == SQLITE_ROW)\r
563         {\r
564                 // more rows, nothing to do\r
565         }\r
566         else\r
567         {\r
568                 nRet = sqlite3_finalize(mpVM);\r
569                 mpVM = 0;\r
570                 const char* szError = sqlite3_errmsg(mpDB);\r
571                 throw CppSQLite3Exception(nRet,\r
572                                                                 (char*)szError,\r
573                                                                 DONT_DELETE_MSG);\r
574         }\r
575 }\r
576 \r
577 \r
578 void CppSQLite3Query::finalize()\r
579 {\r
580         if (mpVM && mbOwnVM)\r
581         {\r
582                 int nRet = sqlite3_finalize(mpVM);\r
583                 mpVM = 0;\r
584                 if (nRet != SQLITE_OK)\r
585                 {\r
586                         const char* szError = sqlite3_errmsg(mpDB);\r
587                         throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
588                 }\r
589         }\r
590 }\r
591 \r
592 \r
593 void CppSQLite3Query::checkVM()\r
594 {\r
595         if (mpVM == 0)\r
596         {\r
597                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
598                                                                 "Null Virtual Machine pointer",\r
599                                                                 DONT_DELETE_MSG);\r
600         }\r
601 }\r
602 \r
603 \r
604 ////////////////////////////////////////////////////////////////////////////////\r
605 \r
606 CppSQLite3Table::CppSQLite3Table()\r
607 {\r
608         mpaszResults = 0;\r
609         mnRows = 0;\r
610         mnCols = 0;\r
611         mnCurrentRow = 0;\r
612 }\r
613 \r
614 \r
615 CppSQLite3Table::CppSQLite3Table(const CppSQLite3Table& rTable)\r
616 {\r
617         mpaszResults = rTable.mpaszResults;\r
618         // Only one object can own the results\r
619         const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0;\r
620         mnRows = rTable.mnRows;\r
621         mnCols = rTable.mnCols;\r
622         mnCurrentRow = rTable.mnCurrentRow;\r
623 }\r
624 \r
625 \r
626 CppSQLite3Table::CppSQLite3Table(char** paszResults, int nRows, int nCols)\r
627 {\r
628         mpaszResults = paszResults;\r
629         mnRows = nRows;\r
630         mnCols = nCols;\r
631         mnCurrentRow = 0;\r
632 }\r
633 \r
634 \r
635 CppSQLite3Table::~CppSQLite3Table()\r
636 {\r
637         try\r
638         {\r
639                 finalize();\r
640         }\r
641         catch (...)\r
642         {\r
643         }\r
644 }\r
645 \r
646 \r
647 CppSQLite3Table& CppSQLite3Table::operator=(const CppSQLite3Table& rTable)\r
648 {\r
649         try\r
650         {\r
651                 finalize();\r
652         }\r
653         catch (...)\r
654         {\r
655         }\r
656         mpaszResults = rTable.mpaszResults;\r
657         // Only one object can own the results\r
658         const_cast<CppSQLite3Table&>(rTable).mpaszResults = 0;\r
659         mnRows = rTable.mnRows;\r
660         mnCols = rTable.mnCols;\r
661         mnCurrentRow = rTable.mnCurrentRow;\r
662         return *this;\r
663 }\r
664 \r
665 \r
666 void CppSQLite3Table::finalize()\r
667 {\r
668         if (mpaszResults)\r
669         {\r
670                 sqlite3_free_table(mpaszResults);\r
671                 mpaszResults = 0;\r
672         }\r
673 }\r
674 \r
675 \r
676 int CppSQLite3Table::numFields()\r
677 {\r
678         checkResults();\r
679         return mnCols;\r
680 }\r
681 \r
682 \r
683 int CppSQLite3Table::numRows()\r
684 {\r
685         checkResults();\r
686         return mnRows;\r
687 }\r
688 \r
689 \r
690 const char* CppSQLite3Table::fieldValue(int nField)\r
691 {\r
692         checkResults();\r
693 \r
694         if (nField < 0 || nField > mnCols-1)\r
695         {\r
696                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
697                                                                 "Invalid field index requested",\r
698                                                                 DONT_DELETE_MSG);\r
699         }\r
700 \r
701         int nIndex = (mnCurrentRow*mnCols) + mnCols + nField;\r
702         return mpaszResults[nIndex];\r
703 }\r
704 \r
705 \r
706 const char* CppSQLite3Table::fieldValue(const char* szField)\r
707 {\r
708         checkResults();\r
709 \r
710         if (szField)\r
711         {\r
712                 for (int nField = 0; nField < mnCols; nField++)\r
713                 {\r
714                         if (strcmp(szField, mpaszResults[nField]) == 0)\r
715                         {\r
716                                 int nIndex = (mnCurrentRow*mnCols) + mnCols + nField;\r
717                                 return mpaszResults[nIndex];\r
718                         }\r
719                 }\r
720         }\r
721 \r
722         throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
723                                                         "Invalid field name requested",\r
724                                                         DONT_DELETE_MSG);\r
725 }\r
726 \r
727 \r
728 int CppSQLite3Table::getIntField(int nField, int nNullValue/*=0*/)\r
729 {\r
730         if (fieldIsNull(nField))\r
731         {\r
732                 return nNullValue;\r
733         }\r
734         else\r
735         {\r
736                 return atoi(fieldValue(nField));\r
737         }\r
738 }\r
739 \r
740 \r
741 int CppSQLite3Table::getIntField(const char* szField, int nNullValue/*=0*/)\r
742 {\r
743         if (fieldIsNull(szField))\r
744         {\r
745                 return nNullValue;\r
746         }\r
747         else\r
748         {\r
749                 return atoi(fieldValue(szField));\r
750         }\r
751 }\r
752 \r
753 \r
754 double CppSQLite3Table::getFloatField(int nField, double fNullValue/*=0.0*/)\r
755 {\r
756         if (fieldIsNull(nField))\r
757         {\r
758                 return fNullValue;\r
759         }\r
760         else\r
761         {\r
762                 return atof(fieldValue(nField));\r
763         }\r
764 }\r
765 \r
766 \r
767 double CppSQLite3Table::getFloatField(const char* szField, double fNullValue/*=0.0*/)\r
768 {\r
769         if (fieldIsNull(szField))\r
770         {\r
771                 return fNullValue;\r
772         }\r
773         else\r
774         {\r
775                 return atof(fieldValue(szField));\r
776         }\r
777 }\r
778 \r
779 \r
780 const char* CppSQLite3Table::getStringField(int nField, const char* szNullValue/*=""*/)\r
781 {\r
782         if (fieldIsNull(nField))\r
783         {\r
784                 return szNullValue;\r
785         }\r
786         else\r
787         {\r
788                 return fieldValue(nField);\r
789         }\r
790 }\r
791 \r
792 \r
793 const char* CppSQLite3Table::getStringField(const char* szField, const char* szNullValue/*=""*/)\r
794 {\r
795         if (fieldIsNull(szField))\r
796         {\r
797                 return szNullValue;\r
798         }\r
799         else\r
800         {\r
801                 return fieldValue(szField);\r
802         }\r
803 }\r
804 \r
805 \r
806 bool CppSQLite3Table::fieldIsNull(int nField)\r
807 {\r
808         checkResults();\r
809         return (fieldValue(nField) == 0);\r
810 }\r
811 \r
812 \r
813 bool CppSQLite3Table::fieldIsNull(const char* szField)\r
814 {\r
815         checkResults();\r
816         return (fieldValue(szField) == 0);\r
817 }\r
818 \r
819 \r
820 const char* CppSQLite3Table::fieldName(int nCol)\r
821 {\r
822         checkResults();\r
823 \r
824         if (nCol < 0 || nCol > mnCols-1)\r
825         {\r
826                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
827                                                                 "Invalid field index requested",\r
828                                                                 DONT_DELETE_MSG);\r
829         }\r
830 \r
831         return mpaszResults[nCol];\r
832 }\r
833 \r
834 \r
835 void CppSQLite3Table::setRow(int nRow)\r
836 {\r
837         checkResults();\r
838 \r
839         if (nRow < 0 || nRow > mnRows-1)\r
840         {\r
841                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
842                                                                 "Invalid row index requested",\r
843                                                                 DONT_DELETE_MSG);\r
844         }\r
845 \r
846         mnCurrentRow = nRow;\r
847 }\r
848 \r
849 \r
850 void CppSQLite3Table::checkResults()\r
851 {\r
852         if (mpaszResults == 0)\r
853         {\r
854                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
855                                                                 "Null Results pointer",\r
856                                                                 DONT_DELETE_MSG);\r
857         }\r
858 }\r
859 \r
860 \r
861 ////////////////////////////////////////////////////////////////////////////////\r
862 \r
863 CppSQLite3Statement::CppSQLite3Statement()\r
864 {\r
865         mpDB = 0;\r
866         mpVM = 0;\r
867 }\r
868 \r
869 \r
870 CppSQLite3Statement::CppSQLite3Statement(const CppSQLite3Statement& rStatement)\r
871 {\r
872         mpDB = rStatement.mpDB;\r
873         mpVM = rStatement.mpVM;\r
874         // Only one object can own VM\r
875         const_cast<CppSQLite3Statement&>(rStatement).mpVM = 0;\r
876 }\r
877 \r
878 \r
879 CppSQLite3Statement::CppSQLite3Statement(sqlite3* pDB, sqlite3_stmt* pVM)\r
880 {\r
881         mpDB = pDB;\r
882         mpVM = pVM;\r
883 }\r
884 \r
885 \r
886 CppSQLite3Statement::~CppSQLite3Statement()\r
887 {\r
888         try\r
889         {\r
890                 finalize();\r
891         }\r
892         catch (...)\r
893         {\r
894         }\r
895 }\r
896 \r
897 \r
898 CppSQLite3Statement& CppSQLite3Statement::operator=(const CppSQLite3Statement& rStatement)\r
899 {\r
900         mpDB = rStatement.mpDB;\r
901         mpVM = rStatement.mpVM;\r
902         // Only one object can own VM\r
903         const_cast<CppSQLite3Statement&>(rStatement).mpVM = 0;\r
904         return *this;\r
905 }\r
906 \r
907 \r
908 int CppSQLite3Statement::execDML()\r
909 {\r
910         checkDB();\r
911         checkVM();\r
912 \r
913         const char* szError=0;\r
914 \r
915         int nRet = sqlite3_step(mpVM);\r
916 \r
917         if (nRet == SQLITE_DONE)\r
918         {\r
919                 int nRowsChanged = sqlite3_changes(mpDB);\r
920 \r
921                 nRet = sqlite3_reset(mpVM);\r
922 \r
923                 if (nRet != SQLITE_OK)\r
924                 {\r
925                         szError = sqlite3_errmsg(mpDB);\r
926                         throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
927                 }\r
928 \r
929                 return nRowsChanged;\r
930         }\r
931         else\r
932         {\r
933                 nRet = sqlite3_reset(mpVM);\r
934                 szError = sqlite3_errmsg(mpDB);\r
935                 throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
936         }\r
937 }\r
938 \r
939 \r
940 CppSQLite3Query CppSQLite3Statement::execQuery()\r
941 {\r
942         checkDB();\r
943         checkVM();\r
944 \r
945         int nRet = sqlite3_step(mpVM);\r
946 \r
947         if (nRet == SQLITE_DONE)\r
948         {\r
949                 // no rows\r
950                 return CppSQLite3Query(mpDB, mpVM, true/*eof*/, false);\r
951         }\r
952         else if (nRet == SQLITE_ROW)\r
953         {\r
954                 // at least 1 row\r
955                 return CppSQLite3Query(mpDB, mpVM, false/*eof*/, false);\r
956         }\r
957         else\r
958         {\r
959                 nRet = sqlite3_reset(mpVM);\r
960                 const char* szError = sqlite3_errmsg(mpDB);\r
961                 throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
962         }\r
963 }\r
964 \r
965 \r
966 void CppSQLite3Statement::bind(int nParam, const char* szValue)\r
967 {\r
968         checkVM();\r
969         int nRes = sqlite3_bind_text(mpVM, nParam, szValue, -1, SQLITE_TRANSIENT);\r
970 \r
971         if (nRes != SQLITE_OK)\r
972         {\r
973                 throw CppSQLite3Exception(nRes,\r
974                                                                 "Error binding string param",\r
975                                                                 DONT_DELETE_MSG);\r
976         }\r
977 }\r
978 \r
979 \r
980 void CppSQLite3Statement::bind(int nParam, const int nValue)\r
981 {\r
982         checkVM();\r
983         int nRes = sqlite3_bind_int(mpVM, nParam, nValue);\r
984 \r
985         if (nRes != SQLITE_OK)\r
986         {\r
987                 throw CppSQLite3Exception(nRes,\r
988                                                                 "Error binding int param",\r
989                                                                 DONT_DELETE_MSG);\r
990         }\r
991 }\r
992 \r
993 \r
994 void CppSQLite3Statement::bind(int nParam, const double dValue)\r
995 {\r
996         checkVM();\r
997         int nRes = sqlite3_bind_double(mpVM, nParam, dValue);\r
998 \r
999         if (nRes != SQLITE_OK)\r
1000         {\r
1001                 throw CppSQLite3Exception(nRes,\r
1002                                                                 "Error binding double param",\r
1003                                                                 DONT_DELETE_MSG);\r
1004         }\r
1005 }\r
1006 \r
1007 \r
1008 void CppSQLite3Statement::bind(int nParam, const unsigned char* blobValue, int nLen)\r
1009 {\r
1010         checkVM();\r
1011         int nRes = sqlite3_bind_blob(mpVM, nParam,\r
1012                                                                 (const void*)blobValue, nLen, SQLITE_TRANSIENT);\r
1013 \r
1014         if (nRes != SQLITE_OK)\r
1015         {\r
1016                 throw CppSQLite3Exception(nRes,\r
1017                                                                 "Error binding blob param",\r
1018                                                                 DONT_DELETE_MSG);\r
1019         }\r
1020 }\r
1021 \r
1022         \r
1023 void CppSQLite3Statement::bindNull(int nParam)\r
1024 {\r
1025         checkVM();\r
1026         int nRes = sqlite3_bind_null(mpVM, nParam);\r
1027 \r
1028         if (nRes != SQLITE_OK)\r
1029         {\r
1030                 throw CppSQLite3Exception(nRes,\r
1031                                                                 "Error binding NULL param",\r
1032                                                                 DONT_DELETE_MSG);\r
1033         }\r
1034 }\r
1035 \r
1036 \r
1037 void CppSQLite3Statement::reset()\r
1038 {\r
1039         if (mpVM)\r
1040         {\r
1041                 int nRet = sqlite3_reset(mpVM);\r
1042 \r
1043                 if (nRet != SQLITE_OK)\r
1044                 {\r
1045                         const char* szError = sqlite3_errmsg(mpDB);\r
1046                         throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
1047                 }\r
1048         }\r
1049 }\r
1050 \r
1051 \r
1052 void CppSQLite3Statement::finalize()\r
1053 {\r
1054         if (mpVM)\r
1055         {\r
1056                 int nRet = sqlite3_finalize(mpVM);\r
1057                 mpVM = 0;\r
1058 \r
1059                 if (nRet != SQLITE_OK)\r
1060                 {\r
1061                         const char* szError = sqlite3_errmsg(mpDB);\r
1062                         throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
1063                 }\r
1064         }\r
1065 }\r
1066 \r
1067 \r
1068 void CppSQLite3Statement::checkDB()\r
1069 {\r
1070         if (mpDB == 0)\r
1071         {\r
1072                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
1073                                                                 "Database not open",\r
1074                                                                 DONT_DELETE_MSG);\r
1075         }\r
1076 }\r
1077 \r
1078 \r
1079 void CppSQLite3Statement::checkVM()\r
1080 {\r
1081         if (mpVM == 0)\r
1082         {\r
1083                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
1084                                                                 "Null Virtual Machine pointer",\r
1085                                                                 DONT_DELETE_MSG);\r
1086         }\r
1087 }\r
1088 \r
1089 \r
1090 ////////////////////////////////////////////////////////////////////////////////\r
1091 \r
1092 CppSQLite3DB::CppSQLite3DB()\r
1093 {\r
1094         mpDB = 0;\r
1095         mnBusyTimeoutMs = 60000; // 60 seconds\r
1096 }\r
1097 \r
1098 \r
1099 CppSQLite3DB::CppSQLite3DB(const CppSQLite3DB& db)\r
1100 {\r
1101         mpDB = db.mpDB;\r
1102         mnBusyTimeoutMs = 60000; // 60 seconds\r
1103 }\r
1104 \r
1105 \r
1106 CppSQLite3DB::~CppSQLite3DB()\r
1107 {\r
1108         close();\r
1109 }\r
1110 \r
1111 \r
1112 CppSQLite3DB& CppSQLite3DB::operator=(const CppSQLite3DB& db)\r
1113 {\r
1114         mpDB = db.mpDB;\r
1115         mnBusyTimeoutMs = 60000; // 60 seconds\r
1116         return *this;\r
1117 }\r
1118 \r
1119 \r
1120 void CppSQLite3DB::open(const char* szFile)\r
1121 {\r
1122         int nRet = sqlite3_open(szFile, &mpDB);\r
1123 \r
1124         if (nRet != SQLITE_OK)\r
1125         {\r
1126                 const char* szError = sqlite3_errmsg(mpDB);\r
1127                 throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
1128         }\r
1129 \r
1130         setBusyTimeout(mnBusyTimeoutMs);\r
1131 }\r
1132 \r
1133 \r
1134 void CppSQLite3DB::close()\r
1135 {\r
1136         if (mpDB)\r
1137         {\r
1138                 sqlite3_close(mpDB);\r
1139                 mpDB = 0;\r
1140         }\r
1141 }\r
1142 \r
1143 \r
1144 CppSQLite3Statement CppSQLite3DB::compileStatement(const char* szSQL)\r
1145 {\r
1146         checkDB();\r
1147 \r
1148         sqlite3_stmt* pVM = compile(szSQL);\r
1149         return CppSQLite3Statement(mpDB, pVM);\r
1150 }\r
1151 \r
1152 \r
1153 bool CppSQLite3DB::tableExists(const char* szTable)\r
1154 {\r
1155         char szSQL[128];\r
1156         sprintf(szSQL,\r
1157                         "select count(*) from sqlite_master where type='table' and name='%s'",\r
1158                         szTable);\r
1159         int nRet = execScalar(szSQL);\r
1160         return (nRet > 0);\r
1161 }\r
1162 \r
1163 \r
1164 int CppSQLite3DB::execDML(const char* szSQL)\r
1165 {\r
1166         checkDB();\r
1167 \r
1168         char* szError=0;\r
1169 \r
1170         int nRet = sqlite3_exec(mpDB, szSQL, 0, 0, &szError);\r
1171 \r
1172         if (nRet == SQLITE_OK)\r
1173         {\r
1174                 return sqlite3_changes(mpDB);\r
1175         }\r
1176         else\r
1177         {\r
1178                 throw CppSQLite3Exception(nRet, szError);\r
1179         }\r
1180 }\r
1181 \r
1182 \r
1183 CppSQLite3Query CppSQLite3DB::execQuery(const char* szSQL)\r
1184 {\r
1185         checkDB();\r
1186 \r
1187         sqlite3_stmt* pVM = compile(szSQL);\r
1188 \r
1189         int nRet = sqlite3_step(pVM);\r
1190 \r
1191         if (nRet == SQLITE_DONE)\r
1192         {\r
1193                 // no rows\r
1194                 return CppSQLite3Query(mpDB, pVM, true/*eof*/);\r
1195         }\r
1196         else if (nRet == SQLITE_ROW)\r
1197         {\r
1198                 // at least 1 row\r
1199                 return CppSQLite3Query(mpDB, pVM, false/*eof*/);\r
1200         }\r
1201         else\r
1202         {\r
1203                 nRet = sqlite3_finalize(pVM);\r
1204                 const char* szError= sqlite3_errmsg(mpDB);\r
1205                 throw CppSQLite3Exception(nRet, (char*)szError, DONT_DELETE_MSG);\r
1206         }\r
1207 }\r
1208 \r
1209 \r
1210 int CppSQLite3DB::execScalar(const char* szSQL)\r
1211 {\r
1212         CppSQLite3Query q = execQuery(szSQL);\r
1213 \r
1214         if (q.eof() || q.numFields() < 1)\r
1215         {\r
1216                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
1217                                                                 "Invalid scalar query",\r
1218                                                                 DONT_DELETE_MSG);\r
1219         }\r
1220 \r
1221         return atoi(q.fieldValue(0));\r
1222 }\r
1223 \r
1224 \r
1225 CppSQLite3Table CppSQLite3DB::getTable(const char* szSQL)\r
1226 {\r
1227         checkDB();\r
1228 \r
1229         char* szError=0;\r
1230         char** paszResults=0;\r
1231         int nRet;\r
1232         int nRows(0);\r
1233         int nCols(0);\r
1234 \r
1235         nRet = sqlite3_get_table(mpDB, szSQL, &paszResults, &nRows, &nCols, &szError);\r
1236 \r
1237         if (nRet == SQLITE_OK)\r
1238         {\r
1239                 return CppSQLite3Table(paszResults, nRows, nCols);\r
1240         }\r
1241         else\r
1242         {\r
1243                 throw CppSQLite3Exception(nRet, szError);\r
1244         }\r
1245 }\r
1246 \r
1247 \r
1248 sqlite_int64 CppSQLite3DB::lastRowId()\r
1249 {\r
1250         return sqlite3_last_insert_rowid(mpDB);\r
1251 }\r
1252 \r
1253 \r
1254 void CppSQLite3DB::setBusyTimeout(int nMillisecs)\r
1255 {\r
1256         mnBusyTimeoutMs = nMillisecs;\r
1257         sqlite3_busy_timeout(mpDB, mnBusyTimeoutMs);\r
1258 }\r
1259 \r
1260 \r
1261 void CppSQLite3DB::checkDB()\r
1262 {\r
1263         if (!mpDB)\r
1264         {\r
1265                 throw CppSQLite3Exception(CPPSQLITE_ERROR,\r
1266                                                                 "Database not open",\r
1267                                                                 DONT_DELETE_MSG);\r
1268         }\r
1269 }\r
1270 \r
1271 \r
1272 sqlite3_stmt* CppSQLite3DB::compile(const char* szSQL)\r
1273 {\r
1274         checkDB();\r
1275 \r
1276         char* szError=0;\r
1277         const char* szTail=0;\r
1278         sqlite3_stmt* pVM;\r
1279 \r
1280         int nRet = sqlite3_prepare(mpDB, szSQL, -1, &pVM, &szTail);\r
1281 \r
1282         if (nRet != SQLITE_OK)\r
1283         {\r
1284                 throw CppSQLite3Exception(nRet, szError);\r
1285         }\r
1286 \r
1287         return pVM;\r
1288 }\r
1289 \r
1290 \r
1291 ////////////////////////////////////////////////////////////////////////////////\r
1292 // SQLite encode.c reproduced here, containing implementation notes and source\r
1293 // for sqlite3_encode_binary() and sqlite3_decode_binary() \r
1294 ////////////////////////////////////////////////////////////////////////////////\r
1295 \r
1296 /*\r
1297 ** 2002 April 25\r
1298 **\r
1299 ** The author disclaims copyright to this source code.  In place of\r
1300 ** a legal notice, here is a blessing:\r
1301 **\r
1302 **    May you do good and not evil.\r
1303 **    May you find forgiveness for yourself and forgive others.\r
1304 **    May you share freely, never taking more than you give.\r
1305 **\r
1306 *************************************************************************\r
1307 ** This file contains helper routines used to translate binary data into\r
1308 ** a null-terminated string (suitable for use in SQLite) and back again.\r
1309 ** These are convenience routines for use by people who want to store binary\r
1310 ** data in an SQLite database.  The code in this file is not used by any other\r
1311 ** part of the SQLite library.\r
1312 **\r
1313 ** $Id: CppSQLite3.cpp,v 1.1.1.1 2008/09/26 14:15:48 guigues Exp $\r
1314 */\r
1315 \r
1316 /*\r
1317 ** How This Encoder Works\r
1318 **\r
1319 ** The output is allowed to contain any character except 0x27 (') and\r
1320 ** 0x00.  This is accomplished by using an escape character to encode\r
1321 ** 0x27 and 0x00 as a two-byte sequence.  The escape character is always\r
1322 ** 0x01.  An 0x00 is encoded as the two byte sequence 0x01 0x01.  The\r
1323 ** 0x27 character is encoded as the two byte sequence 0x01 0x03.  Finally,\r
1324 ** the escape character itself is encoded as the two-character sequence\r
1325 ** 0x01 0x02.\r
1326 **\r
1327 ** To summarize, the encoder works by using an escape sequences as follows:\r
1328 **\r
1329 **       0x00  ->  0x01 0x01\r
1330 **       0x01  ->  0x01 0x02\r
1331 **       0x27  ->  0x01 0x03\r
1332 **\r
1333 ** If that were all the encoder did, it would work, but in certain cases\r
1334 ** it could double the size of the encoded string.  For example, to\r
1335 ** encode a string of 100 0x27 characters would require 100 instances of\r
1336 ** the 0x01 0x03 escape sequence resulting in a 200-character output.\r
1337 ** We would prefer to keep the size of the encoded string smaller than\r
1338 ** this.\r
1339 **\r
1340 ** To minimize the encoding size, we first add a fixed offset value to each \r
1341 ** byte in the sequence.  The addition is modulo 256.  (That is to say, if\r
1342 ** the sum of the original character value and the offset exceeds 256, then\r
1343 ** the higher order bits are truncated.)  The offset is chosen to minimize\r
1344 ** the number of characters in the string that need to be escaped.  For\r
1345 ** example, in the case above where the string was composed of 100 0x27\r
1346 ** characters, the offset might be 0x01.  Each of the 0x27 characters would\r
1347 ** then be converted into an 0x28 character which would not need to be\r
1348 ** escaped at all and so the 100 character input string would be converted\r
1349 ** into just 100 characters of output.  Actually 101 characters of output - \r
1350 ** we have to record the offset used as the first byte in the sequence so\r
1351 ** that the string can be decoded.  Since the offset value is stored as\r
1352 ** part of the output string and the output string is not allowed to contain\r
1353 ** characters 0x00 or 0x27, the offset cannot be 0x00 or 0x27.\r
1354 **\r
1355 ** Here, then, are the encoding steps:\r
1356 **\r
1357 **     (1)   Choose an offset value and make it the first character of\r
1358 **           output.\r
1359 **\r
1360 **     (2)   Copy each input character into the output buffer, one by\r
1361 **           one, adding the offset value as you copy.\r
1362 **\r
1363 **     (3)   If the value of an input character plus offset is 0x00, replace\r
1364 **           that one character by the two-character sequence 0x01 0x01.\r
1365 **           If the sum is 0x01, replace it with 0x01 0x02.  If the sum\r
1366 **           is 0x27, replace it with 0x01 0x03.\r
1367 **\r
1368 **     (4)   Put a 0x00 terminator at the end of the output.\r
1369 **\r
1370 ** Decoding is obvious:\r
1371 **\r
1372 **     (5)   Copy encoded characters except the first into the decode \r
1373 **           buffer.  Set the first encoded character aside for use as\r
1374 **           the offset in step 7 below.\r
1375 **\r
1376 **     (6)   Convert each 0x01 0x01 sequence into a single character 0x00.\r
1377 **           Convert 0x01 0x02 into 0x01.  Convert 0x01 0x03 into 0x27.\r
1378 **\r
1379 **     (7)   Subtract the offset value that was the first character of\r
1380 **           the encoded buffer from all characters in the output buffer.\r
1381 **\r
1382 ** The only tricky part is step (1) - how to compute an offset value to\r
1383 ** minimize the size of the output buffer.  This is accomplished by testing\r
1384 ** all offset values and picking the one that results in the fewest number\r
1385 ** of escapes.  To do that, we first scan the entire input and count the\r
1386 ** number of occurances of each character value in the input.  Suppose\r
1387 ** the number of 0x00 characters is N(0), the number of occurances of 0x01\r
1388 ** is N(1), and so forth up to the number of occurances of 0xff is N(255).\r
1389 ** An offset of 0 is not allowed so we don't have to test it.  The number\r
1390 ** of escapes required for an offset of 1 is N(1)+N(2)+N(40).  The number\r
1391 ** of escapes required for an offset of 2 is N(2)+N(3)+N(41).  And so forth.\r
1392 ** In this way we find the offset that gives the minimum number of escapes,\r
1393 ** and thus minimizes the length of the output string.\r
1394 */\r
1395 \r
1396 /*\r
1397 ** Encode a binary buffer "in" of size n bytes so that it contains\r
1398 ** no instances of characters '\'' or '\000'.  The output is \r
1399 ** null-terminated and can be used as a string value in an INSERT\r
1400 ** or UPDATE statement.  Use sqlite3_decode_binary() to convert the\r
1401 ** string back into its original binary.\r
1402 **\r
1403 ** The result is written into a preallocated output buffer "out".\r
1404 ** "out" must be able to hold at least 2 +(257*n)/254 bytes.\r
1405 ** In other words, the output will be expanded by as much as 3\r
1406 ** bytes for every 254 bytes of input plus 2 bytes of fixed overhead.\r
1407 ** (This is approximately 2 + 1.0118*n or about a 1.2% size increase.)\r
1408 **\r
1409 ** The return value is the number of characters in the encoded\r
1410 ** string, excluding the "\000" terminator.\r
1411 */\r
1412 int sqlite3_encode_binary(const unsigned char *in, int n, unsigned char *out){\r
1413   int i, j, e, m;\r
1414   int cnt[256];\r
1415   if( n<=0 ){\r
1416     out[0] = 'x';\r
1417     out[1] = 0;\r
1418     return 1;\r
1419   }\r
1420   memset(cnt, 0, sizeof(cnt));\r
1421   for(i=n-1; i>=0; i--){ cnt[in[i]]++; }\r
1422   m = n;\r
1423   for(i=1; i<256; i++){\r
1424     int sum;\r
1425     if( i=='\'' ) continue;\r
1426     sum = cnt[i] + cnt[(i+1)&0xff] + cnt[(i+'\'')&0xff];\r
1427     if( sum<m ){\r
1428       m = sum;\r
1429       e = i;\r
1430       if( m==0 ) break;\r
1431     }\r
1432   }\r
1433   out[0] = e;\r
1434   j = 1;\r
1435   for(i=0; i<n; i++){\r
1436     int c = (in[i] - e)&0xff;\r
1437     if( c==0 ){\r
1438       out[j++] = 1;\r
1439       out[j++] = 1;\r
1440     }else if( c==1 ){\r
1441       out[j++] = 1;\r
1442       out[j++] = 2;\r
1443     }else if( c=='\'' ){\r
1444       out[j++] = 1;\r
1445       out[j++] = 3;\r
1446     }else{\r
1447       out[j++] = c;\r
1448     }\r
1449   }\r
1450   out[j] = 0;\r
1451   return j;\r
1452 }\r
1453 \r
1454 /*\r
1455 ** Decode the string "in" into binary data and write it into "out".\r
1456 ** This routine reverses the encoding created by sqlite3_encode_binary().\r
1457 ** The output will always be a few bytes less than the input.  The number\r
1458 ** of bytes of output is returned.  If the input is not a well-formed\r
1459 ** encoding, -1 is returned.\r
1460 **\r
1461 ** The "in" and "out" parameters may point to the same buffer in order\r
1462 ** to decode a string in place.\r
1463 */\r
1464 int sqlite3_decode_binary(const unsigned char *in, unsigned char *out){\r
1465   int i, c, e;\r
1466   e = *(in++);\r
1467   i = 0;\r
1468   while( (c = *(in++))!=0 ){\r
1469     if( c==1 ){\r
1470       c = *(in++);\r
1471       if( c==1 ){\r
1472         c = 0;\r
1473       }else if( c==2 ){\r
1474         c = 1;\r
1475       }else if( c==3 ){\r
1476         c = '\'';\r
1477       }else{\r
1478         return -1;\r
1479       }\r
1480     }\r
1481     out[i++] = (c + e)&0xff;\r
1482   }\r
1483   return i;\r
1484 }\r