@@ -31,6 +31,10 @@ DBConnection_SQLITE::DBConnection_SQLITE() :
3131 mIsError(false )
3232{
3333 connectionType = CT_SQLITE;
34+
35+ // MW-2014-01-29: [[ Sqlite382 ]] Make sure options are set to defaults (false).
36+ m_enable_binary = false ;
37+ m_enable_extensions = false ;
3438}
3539
3640DBConnection_SQLITE::~DBConnection_SQLITE ()
@@ -39,6 +43,11 @@ DBConnection_SQLITE::~DBConnection_SQLITE()
3943 disconnect ();
4044}
4145
46+ bool DBConnection_SQLITE::IsBinaryEnabled (void )
47+ {
48+ return m_enable_binary;
49+ }
50+
4251// Only 1 arguments are expected.
4352// args[0]: --unused--
4453// args[1]: filename of database
@@ -50,7 +59,8 @@ Bool DBConnection_SQLITE::connect(char **args, int numargs)
5059 Bool ret = False;
5160
5261
53- if (!isConnected && numargs > 1 ) {
62+ // MW-2014-01-29: [[ Sqlite382 ]] We only need a minimum of one argument.
63+ if (!isConnected && numargs >= 1 ) {
5464 char *fname;
5565 string bhash;
5666 string mash;
@@ -61,6 +71,36 @@ Bool DBConnection_SQLITE::connect(char **args, int numargs)
6171 // path encoded as UTF-8.
6272 fname = os_path_to_native_utf8 (args[0 ]);
6373
74+ // MW-2014-01-29: [[ Sqlite382 ]] If there's a second argument, then interpret
75+ // it as an options string.
76+ if (numargs >= 2 )
77+ {
78+ const char *t_start;
79+ t_start = args[1 ];
80+ for (;;)
81+ {
82+ // Find the end of the item (delimited by ',').
83+ const char *t_end;
84+ t_end = strchr (t_start, ' ,' );
85+ if (t_end == NULL )
86+ t_end = t_start + strlen (t_start);
87+
88+ // Check to see if we recognise the option (ignoring ones we don't know
89+ // anything about).
90+ if ((t_end - t_start) == 6 && strncasecmp (t_start, " binary" , 6 ) == 0 )
91+ m_enable_binary = true ;
92+ if ((t_end - t_start) == 10 && strncasecmp (t_start, " extensions" , 10 ) == 0 )
93+ m_enable_extensions = true ;
94+
95+ // If the end points to NUL we are done.
96+ if (*t_end == ' \0 ' )
97+ break ;
98+
99+ // Start is the char after the separating ','.
100+ t_start = t_end + 1 ;
101+ }
102+ }
103+
64104 try
65105 {
66106 mDB .setDatabase (fname);
@@ -72,13 +112,18 @@ Bool DBConnection_SQLITE::connect(char **args, int numargs)
72112 {
73113 ret = True;
74114 isConnected = True;
115+
116+ // MW-2014-01-29: [[ Sqlite382 ]] Now we have a handle, configure extension
117+ // loading.
118+ sqlite3_enable_load_extension (mDB . getHandle (), m_enable_extensions ? 1 : 0 );
75119 }
76120 }
77121 catch (DbErrors &e)
78122 {
79123 mIsError = true ;
80124 setErrorStr (e.getMsg ());
81125 }
126+
82127 free (fname);
83128 }
84129 return ret;
@@ -193,7 +238,7 @@ DBCursor *DBConnection_SQLITE::sqlQuery(char *query, DBString *args, int numargs
193238 }
194239
195240 try {
196- ret = new DBCursor_SQLITE (mDB );
241+ ret = new DBCursor_SQLITE (mDB , m_enable_binary );
197242 Dataset *ds = ret->getDataset ();
198243
199244 ds->query (newquery);
@@ -325,6 +370,13 @@ char *replaceString(char *p_string, char *p_find, char *p_replace)
325370 return t_output_buffer_copy;
326371}
327372
373+ static char num2nibble (int p_nibble)
374+ {
375+ if (p_nibble < 10 )
376+ return ' 0' + p_nibble;
377+ return ' A' + (p_nibble - 10 );
378+ }
379+
328380bool queryCallback (void *p_context, int p_placeholder, DBBuffer& p_output)
329381{
330382 QueryMetadata *t_query_metadata;
@@ -339,11 +391,45 @@ bool queryCallback(void *p_context, int p_placeholder, DBBuffer& p_output)
339391 size_t t_escaped_string_length;
340392 t_escaped_string_length = 0 ;
341393
394+ // MW-2014-01-29: [[ Sqlite382 ]] If true the value needs quoting, otherwise it is
395+ // already quoted appropriately.
396+ bool t_needs_quotes;
397+ t_needs_quotes = true ;
342398 if (t_parameter_value . isbinary)
343399 {
344- // According to documentation in sqlitedecode.cpp, this is the required size of output buffer
345- t_escaped_string = malloc (2 + (257 * t_parameter_value . length) / 254 );
346- t_escaped_string_length = sqlite_encode_binary ((const unsigned char *)t_parameter_value . sptr, t_parameter_value . length, (unsigned char *)t_escaped_string);
400+ DBConnection_SQLITE *t_conn;
401+ t_conn = (DBConnection_SQLITE *)t_query_metadata -> connection;
402+
403+ if (t_conn -> IsBinaryEnabled ())
404+ {
405+ // MW-2014-01-29: [[ Sqlite382 ]] Encode the binary as BLOB literal - X'<hex>'. Thus
406+ // the length of the escaped string is 3 + 2 * size.;
407+ t_escaped_string_length = 3 + 2 * t_parameter_value . length;
408+ t_escaped_string = malloc (t_escaped_string_length);
409+ t_needs_quotes = false ;
410+
411+ // Quote the binary!
412+ char *t_buffer;
413+ t_buffer = (char *)t_escaped_string;
414+
415+ *t_buffer++ = ' X' ;
416+ *t_buffer++ = ' \' ' ;
417+ for (size_t i = 0 ; i < t_parameter_value . length; i++)
418+ {
419+ char t_high_nibble, t_low_nibble;
420+ t_high_nibble = num2nibble (((unsigned )t_parameter_value . sptr[i] & 0xff ) >> 4 );
421+ t_low_nibble = num2nibble (((unsigned )t_parameter_value . sptr[i]) & 0xf );
422+ *t_buffer++ = t_high_nibble;
423+ *t_buffer++ = t_low_nibble;
424+ }
425+ *t_buffer++ = ' \' ' ;
426+ }
427+ else
428+ {
429+ // According to documentation in sqlitedecode.cpp, this is the required size of output buffer
430+ t_escaped_string = malloc (2 + (257 * t_parameter_value . length) / 254 );
431+ t_escaped_string_length = sqlite_encode_binary ((const unsigned char *)t_parameter_value . sptr, t_parameter_value . length, (unsigned char *)t_escaped_string);
432+ }
347433 }
348434 else
349435 {
@@ -363,18 +449,26 @@ bool queryCallback(void *p_context, int p_placeholder, DBBuffer& p_output)
363449 }
364450 }
365451
366- p_output . ensure (t_escaped_string_length + 2 );
367- memcpy (p_output . getFrontier (), " '" , 1 );
368- p_output . advance (1 );
452+ if (t_needs_quotes)
453+ {
454+ p_output . ensure (t_escaped_string_length + 2 );
455+ memcpy (p_output . getFrontier (), " '" , 1 );
456+ p_output . advance (1 );
457+ }
458+ else
459+ p_output . ensure (t_escaped_string_length);
369460
370461 if (t_escaped_string != NULL )
371462 {
372463 memcpy (p_output . getFrontier (), t_escaped_string, t_escaped_string_length);
373464 p_output . advance (t_escaped_string_length);
374465 }
375466
376- memcpy (p_output . getFrontier (), " '" , 1 );
377- p_output . advance (1 );
467+ if (t_needs_quotes)
468+ {
469+ memcpy (p_output . getFrontier (), " '" , 1 );
470+ p_output . advance (1 );
471+ }
378472
379473 free (t_escaped_string);
380474 return true ;
@@ -398,6 +492,7 @@ char *DBConnection_SQLITE::BindVariables(char *p_query, int p_query_length, DBSt
398492 QueryMetadata t_query_metadata;
399493 t_query_metadata . argument_count = p_argument_count;
400494 t_query_metadata . arguments = p_arguments;
495+ t_query_metadata . connection = this ;
401496
402497 DBBuffer t_query_buffer (t_parsed_query_length + 1 );
403498
0 commit comments