xref: /sqlite-3.40.0/ext/misc/sqlar.c (revision d1b51d49)
1 /*
2 ** 2017-12-17
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
7 **    May you do good and not evil.
8 **    May you find forgiveness for yourself and forgive others.
9 **    May you share freely, never taking more than you give.
10 **
11 ******************************************************************************
12 **
13 ** Utility functions sqlar_compress() and sqlar_uncompress(). Useful
14 ** for working with sqlar archives and used by the shell tool's built-in
15 ** sqlar support.
16 */
17 #include "sqlite3ext.h"
18 SQLITE_EXTENSION_INIT1
19 #include <zlib.h>
20 
21 /*
22 ** Implementation of the "sqlar_compress(X)" SQL function.
23 **
24 ** If the type of X is SQLITE_BLOB, and compressing that blob using
25 ** zlib utility function compress() yields a smaller blob, return the
26 ** compressed blob. Otherwise, return a copy of X.
27 */
28 static void sqlarCompressFunc(
29   sqlite3_context *context,
30   int argc,
31   sqlite3_value **argv
32 ){
33   assert( argc==1 );
34   if( sqlite3_value_type(argv[0])==SQLITE_BLOB ){
35     const Bytef *pData = sqlite3_value_blob(argv[0]);
36     uLong nData = sqlite3_value_bytes(argv[0]);
37     uLongf nOut = compressBound(nData);
38     Bytef *pOut;
39 
40     pOut = (Bytef*)sqlite3_malloc(nOut);
41     if( pOut==0 ){
42       sqlite3_result_error_nomem(context);
43       return;
44     }else{
45       if( Z_OK!=compress(pOut, &nOut, pData, nData) ){
46         sqlite3_result_error(context, "error in compress()", -1);
47       }else if( nOut<nData ){
48         sqlite3_result_blob(context, pOut, nOut, SQLITE_TRANSIENT);
49       }else{
50         sqlite3_result_value(context, argv[0]);
51       }
52       sqlite3_free(pOut);
53     }
54   }else{
55     sqlite3_result_value(context, argv[0]);
56   }
57 }
58 
59 /*
60 ** Implementation of the "sqlar_uncompress(X,SZ)" SQL function
61 **
62 ** Parameter SZ is interpreted as an integer. If it is less than or
63 ** equal to zero, then this function returns a copy of X. Or, if
64 ** SZ is equal to the size of X when interpreted as a blob, also
65 ** return a copy of X. Otherwise, decompress blob X using zlib
66 ** utility function uncompress() and return the results (another
67 ** blob).
68 */
69 static void sqlarUncompressFunc(
70   sqlite3_context *context,
71   int argc,
72   sqlite3_value **argv
73 ){
74   uLong nData;
75   uLongf sz;
76 
77   assert( argc==2 );
78   sz = sqlite3_value_int(argv[1]);
79 
80   if( sz<=0 || sz==(nData = sqlite3_value_bytes(argv[0])) ){
81     sqlite3_result_value(context, argv[0]);
82   }else{
83     const Bytef *pData= sqlite3_value_blob(argv[0]);
84     Bytef *pOut = sqlite3_malloc(sz);
85     if( Z_OK!=uncompress(pOut, &sz, pData, nData) ){
86       sqlite3_result_error(context, "error in uncompress()", -1);
87     }else{
88       sqlite3_result_blob(context, pOut, sz, SQLITE_TRANSIENT);
89     }
90     sqlite3_free(pOut);
91   }
92 }
93 
94 
95 #ifdef _WIN32
96 __declspec(dllexport)
97 #endif
98 int sqlite3_sqlar_init(
99   sqlite3 *db,
100   char **pzErrMsg,
101   const sqlite3_api_routines *pApi
102 ){
103   int rc = SQLITE_OK;
104   SQLITE_EXTENSION_INIT2(pApi);
105   (void)pzErrMsg;  /* Unused parameter */
106   rc = sqlite3_create_function(db, "sqlar_compress", 1, SQLITE_UTF8, 0,
107                                sqlarCompressFunc, 0, 0);
108   if( rc==SQLITE_OK ){
109     rc = sqlite3_create_function(db, "sqlar_uncompress", 2, SQLITE_UTF8, 0,
110                                  sqlarUncompressFunc, 0, 0);
111   }
112   return rc;
113 }
114