mksqlite  2.5
A MATLAB interface to SQLite
sql_builtin_functions.hpp
Go to the documentation of this file.
1 
18 #pragma once
19 
20 /* Extending SQLite with additional builtin functions */
21 
22 //#include "config.h"
23 //#include "global.hpp"
24 //#include "sqlite/sqlite3.h"
25 #include "typed_blobs.hpp"
26 #include "number_compressor.hpp"
27 #include "serialize.hpp"
28 #include "deelx/deelx.h"
29 //#include "utils.hpp"
30 
31 extern "C"
32 {
33  #include "md5/md5.h" /* little endian only! */
34 }
35 
36 /* SQLite function extensions by mksqlite */
37 void pow_func( sqlite3_context *ctx, int argc, sqlite3_value **argv );
38 void lg_func( sqlite3_context *ctx, int argc, sqlite3_value **argv );
39 void ln_func( sqlite3_context *ctx, int argc, sqlite3_value **argv );
40 void exp_func( sqlite3_context *ctx, int argc, sqlite3_value **argv );
41 void regex_func( sqlite3_context *ctx, int argc, sqlite3_value **argv );
42 void BDC_ratio_func( sqlite3_context *ctx, int argc, sqlite3_value **argv );
43 void BDC_pack_time_func( sqlite3_context *ctx, int argc, sqlite3_value **argv );
44 void BDC_unpack_time_func( sqlite3_context *ctx, int argc, sqlite3_value **argv );
45 void MD5_func( sqlite3_context *ctx, int argc, sqlite3_value **argv );
46 
47 
48 // Forward declarations
49 int blob_pack ( const mxArray* pcItem, bool bStreamable,
50  void** ppBlob, size_t* pBlob_size,
51  double *pdProcess_time, double* pdRatio,
52  const char* compressor = g_compression_type,
53  int level = g_compression_level );
54 int blob_unpack ( const void* pBlob, size_t blob_size,
55  bool bStreamable, mxArray** ppItem,
56  double* pProcess_time, double* pdRatio );
57 void blob_free ( void** pBlob );
58 
59 
60 #ifdef MAIN_MODULE
61 
62 /* sqlite builtin functions, implementations */
63 
74 void pow_func( sqlite3_context *ctx, int argc, sqlite3_value **argv ){
75  assert( argc == 2 ) ;
76  double base, exponent, result;
77 
78  // Check "base" parameter (handles NULL and double types)
79  switch( sqlite3_value_type( argv[0] ) )
80  {
81  case SQLITE_NULL:
82  sqlite3_result_null( ctx );
83  return;
84  default:
85  base = sqlite3_value_double( argv[0] );
86  }
87 
88  // Check "exponent" parameter (handles NULL and double types)
89  switch( sqlite3_value_type( argv[1] ) )
90  {
91  case SQLITE_NULL:
92  sqlite3_result_null( ctx );
93  return;
94  default:
95  exponent = sqlite3_value_double( argv[1] );
96  }
97 
98  try
99  {
100  result = pow( base, exponent );
101  }
102  catch( ... )
103  {
104  sqlite3_result_error( ctx, "pow(): evaluation error", -1 );
105  return;
106  }
107 
108  sqlite3_result_double( ctx, result );
109 }
110 
111 
112 /* sqlite builtin functions, implementations */
113 
124 void lg_func( sqlite3_context *ctx, int argc, sqlite3_value **argv ){
125  assert( argc == 1 );
126  double value, result;
127 
128  // Check "value" parameter (handles NULL and double types)
129  switch( sqlite3_value_type( argv[0] ) )
130  {
131  case SQLITE_NULL:
132  sqlite3_result_null( ctx );
133  return;
134  default:
135  value = sqlite3_value_double( argv[0] );
136  }
137 
138  try
139  {
140  result = log10( value );
141  }
142  catch( ... )
143  {
144  sqlite3_result_error( ctx, "lg(): evaluation error", -1 );
145  return;
146  }
147 
148  sqlite3_result_double( ctx, result );
149 }
150 
151 
162 void ln_func( sqlite3_context *ctx, int argc, sqlite3_value **argv ){
163  assert( argc == 1 );
164  double value, result;
165 
166  // Check "value" parameter (handles NULL and double types)
167  switch( sqlite3_value_type( argv[0] ) )
168  {
169  case SQLITE_NULL:
170  sqlite3_result_null( ctx );
171  return;
172  default:
173  value = sqlite3_value_double( argv[0] );
174  }
175 
176  try
177  {
178  result = log( value );
179  }
180  catch( ... )
181  {
182  sqlite3_result_error( ctx, "ln(): evaluation error", -1 );
183  return;
184  }
185 
186  sqlite3_result_double( ctx, result );
187 }
188 
189 
200 void exp_func( sqlite3_context *ctx, int argc, sqlite3_value **argv ){
201  assert( argc == 1 );
202  double value, result;
203 
204  // Check "value" parameter (handles NULL and double types)
205  switch( sqlite3_value_type( argv[0] ) )
206  {
207  case SQLITE_NULL:
208  sqlite3_result_null( ctx );
209  return;
210  default:
211  value = sqlite3_value_double( argv[0] );
212  }
213 
214  try
215  {
216  result = exp( value );
217  }
218  catch( ... )
219  {
220  sqlite3_result_error( ctx, "exp(): evaluation error", -1 );
221  return;
222  }
223 
224  sqlite3_result_double( ctx, result );
225 }
226 
227 
242 void regex_func( sqlite3_context *ctx, int argc, sqlite3_value **argv ){
243  assert( argc >= 2 ); // at least 2 arguments needed
244  char *str = NULL, *pattern = NULL, *replace = NULL;
245 
246  sqlite3_result_null( ctx );
247 
248  // Get input arguments
249  str = utils_strnewdup( (const char*)sqlite3_value_text( argv[0] ), g_convertUTF8 );
250  pattern = utils_strnewdup( (const char*)sqlite3_value_text( argv[1] ), g_convertUTF8 );
251 
252  HC_NOTES( str, "regex_func" );
253  HC_NOTES( pattern, "regex_func" );
254 
255  // Optional 3rd parameter is the replacement pattern
256  if( argc > 2 )
257  {
258  replace = utils_strnewdup( (const char*)sqlite3_value_text( argv[2] ), g_convertUTF8 );
259  HC_NOTES( replace, "regex_func" );
260  }
261 
262  CRegexpT <char> regexp( pattern );
263 
264  // find and match
265  MatchResult result = regexp.Match( str );
266 
267  // result
268  if( result.IsMatched() )
269  {
270  char *str_value = NULL;
271 
272  if( argc == 2 )
273  {
274  // Match mode
275  int start = result.GetStart(); // first match position (0 based)
276  int end = result.GetEnd(); // position afterwards matching substring (0 based)
277  int len = end - start;
278 
279  str_value = (char*)MEM_ALLOC( len + 1, sizeof(char) );
280 
281  // make a substring copy
282  if( str_value && len > 0 )
283  {
284  memset( str_value, 0, len + 1 );
285  strncpy( str_value, &str[start], len );
286  }
287  }
288  else
289  {
290  // Replace mode (allocates space)
291  char* result = regexp.Replace( str, replace );
292 
293  // make a copy with own memory management
294  if( result )
295  {
296  int len = (int)strlen( result );
297  str_value = (char*)MEM_ALLOC( len + 1, sizeof(char) );
298 
299  if( str_value && len )
300  {
301  strcpy( str_value, result );
302  }
303 
304  CRegexpT<char>::ReleaseString( result );
305  }
306  }
307 
308  // str_value holds substring now, if any (otherwise NULL)
309 
310  // Optionally convert result string to UTF
311  if( str_value && g_convertUTF8 )
312  {
313  int len = utils_latin2utf( (unsigned char*)str_value, NULL ); // get the size only
314  char *temp = (char*)MEM_ALLOC( len, sizeof(char) ); // allocate memory
315  if( temp )
316  {
317  ::utils_latin2utf( (unsigned char*)str_value, (unsigned char*)temp );
318  ::utils_free_ptr( str_value );
319  str_value = temp;
320  }
321  }
322 
323  // Return a string copy and delete the original
324  if( str_value )
325  {
326  sqlite3_result_text( ctx, str_value, -1, SQLITE_TRANSIENT );
327  ::utils_free_ptr( str_value );
328  }
329  }
330 
331  if( str )
332  {
333  ::utils_free_ptr( str );
334  }
335 
336  if( pattern )
337  {
338  ::utils_free_ptr( pattern );
339  }
340 
341  if( replace )
342  {
343  ::utils_free_ptr( replace );
344  }
345 }
346 
347 
357 void MD5_func( sqlite3_context *ctx, int argc, sqlite3_value **argv ){
358  assert( argc == 1 );
359 
360  // two versions of typed header will be tested
361  typedef TypedBLOBHeaderV1 tbhv1_t;
362  typedef TypedBLOBHeaderV2 tbhv2_t;
363 
364  tbhv1_t* tbh1 = NULL;
365  tbhv2_t* tbh2 = NULL;
366 
367  MD5_CTX md5_ctx; // md5 context
368  unsigned char digest[16];
369  char* str_result = NULL;
370  const char hex_chars[] = "0123456789ABCDEF";
371 
372  sqlite3_result_null( ctx );
373 
374  if( TBH_endian[0] != 'L' )
375  {
376  sqlite3_result_error( ctx, "MD5(): implementation for litte endian only!", -1 );
377  return;
378  }
379 
380  // get and handle argument "value"
381  switch( sqlite3_value_type( argv[0] ) )
382  {
383  case SQLITE_INTEGER:
384  {
385  int bytes = sqlite3_value_bytes( argv[0] );
386  sqlite3_int64 value = (long)sqlite3_value_int64( argv[0] );
387 
388  MD5_Init( &md5_ctx );
389  MD5_Update( &md5_ctx, &value, bytes );
390  MD5_Final( digest, &md5_ctx );
391 
392  break;
393  }
394  case SQLITE_FLOAT:
395  {
396  int bytes = sqlite3_value_bytes( argv[0] );
397  double value = (double)sqlite3_value_double( argv[0] );
398 
399  MD5_Init( &md5_ctx );
400  MD5_Update( &md5_ctx, &value, sizeof( double ) );
401  MD5_Final( digest, &md5_ctx );
402 
403  break;
404  }
405  case SQLITE_TEXT:
406  {
407  int bytes = sqlite3_value_bytes( argv[0] );
408  char* value = utils_strnewdup( (const char*)sqlite3_value_text( argv[0] ), g_convertUTF8 );
409  assert( NULL != value );
410 
411  HC_NOTES( value, "MD5_func" );
412 
413  MD5_Init( &md5_ctx );
414  MD5_Update( &md5_ctx, value, (int)strlen( value ) );
415  MD5_Final( digest, &md5_ctx );
416 
417  ::utils_free_ptr( value );
418  break;
419  }
420  case SQLITE_BLOB:
421  {
422  int bytes = sqlite3_value_bytes( argv[0] );
423  tbhv1_t* tbh1 = (tbhv1_t*)sqlite3_value_blob( argv[0] );
424  tbhv2_t* tbh2 = (tbhv2_t*)sqlite3_value_blob( argv[0] );
425 
426  /* No typed header? Use raw blob data then */
427  if( !tbh1->validMagic() )
428  {
429  MD5_Init( &md5_ctx );
430  MD5_Update( &md5_ctx, (void*)tbh1, bytes );
431  MD5_Final( digest, &md5_ctx );
432  break;
433  }
434 
435  /* uncompressed typed header? */
436  if( tbh1->validVer() )
437  {
438  MD5_Init( &md5_ctx );
439  MD5_Update( &md5_ctx, tbh1->getData(), (int)(bytes - tbh1->dataOffset()) );
440  MD5_Final( digest, &md5_ctx );
441  break;
442  }
443 
444  /* compressed typed header? Decompress first */
445  if( tbh2->validVer() && tbh2->validCompression() )
446  {
447  mxArray* pItem = NULL;
448  double process_time = 0.0, ratio = 0.0;
449 
450  if( blob_unpack( tbh2, (int)bytes, can_serialize(), &pItem, &process_time, &ratio ) && pItem )
451  {
452  size_t data_size = TypedBLOBHeaderBase::getDataSize( pItem );
453 
454  MD5_Init( &md5_ctx );
455  MD5_Update( &md5_ctx, mxGetData( pItem ), (int)data_size );
456  MD5_Final( digest, &md5_ctx );
457 
458  ::utils_destroy_array( pItem );
459  }
460  break;
461  }
462  }
463  case SQLITE_NULL:
464  default:
465  return;
466  }
467 
468  // build result string
469  str_result = (char*)MEM_ALLOC( 16*2+1, 1 );
470 
471  if( str_result )
472  {
473  memset( str_result, 0, 16*2+1 );
474 
475  for( int i = 0; i < 16; i++ )
476  {
477  str_result[2*i+0] = hex_chars[digest[i] >> 4];
478  str_result[2*i+1] = hex_chars[digest[i] & 0x0f];
479  }
480 
481  sqlite3_result_text( ctx, str_result, -1, SQLITE_TRANSIENT );
482  ::utils_free_ptr( str_result );
483  }
484 }
485 
486 
497 void BDC_ratio_func( sqlite3_context *ctx, int argc, sqlite3_value **argv ){
498  assert( argc == 1 );
499 
500  // two versions of typed header will be tested
501  typedef TypedBLOBHeaderV1 tbhv1_t;
502  typedef TypedBLOBHeaderV2 tbhv2_t;
503 
504  sqlite3_result_null( ctx );
505 
506  // get and handle "value"
507  if( SQLITE_BLOB == sqlite3_value_type( argv[0] ) )
508  {
509  tbhv1_t* tbh1 = (tbhv1_t*)sqlite3_value_blob( argv[0] );
510  tbhv2_t* tbh2 = (tbhv2_t*)sqlite3_value_blob( argv[0] );
511  size_t blob_size = (size_t)sqlite3_value_bytes( argv[0] );
512  double ratio = 0.0;
513 
514  // omit ratio of 1, if blob is type V1 (uncompressed)
515  if( tbh1 && tbh1->validMagic() && tbh1->validVer() )
516  {
517  sqlite3_result_double( ctx, 1.0 );
518  }
519  else if( tbh2 && tbh2->validMagic() && tbh2->validVer() && tbh2->validCompression() )
520  {
521  mxArray* pItem = NULL;
522  double process_time = 0.0;
523 
524  if( !blob_unpack( (void*)tbh2, blob_size, can_serialize(), &pItem, &process_time, &ratio ) )
525  {
526  sqlite3_result_error( ctx, "BDCRatio(): an error while unpacking occured!", -1 );
527  }
528  else
529  {
530  sqlite3_result_double( ctx, ratio );
531  }
532 
533  ::utils_destroy_array( pItem );
534  }
535  }
536  else
537  {
538  sqlite3_result_error( ctx, "BDCRatio(): only BLOB type supported!", -1 );
539  }
540 }
541 
542 
553 void BDC_pack_time_func( sqlite3_context *ctx, int argc, sqlite3_value **argv ){
554  assert( argc == 1 );
555 
556  // two versions of typed header will be tested
557  typedef TypedBLOBHeaderV1 tbhv1_t;
558  typedef TypedBLOBHeaderV2 tbhv2_t;
559 
560  sqlite3_result_null( ctx );
561 
562  // get and handle "value" argument
563  if( SQLITE_BLOB == sqlite3_value_type( argv[0] ) )
564  {
565  tbhv1_t* tbh1 = (tbhv1_t*)sqlite3_value_blob( argv[0] );
566  tbhv2_t* tbh2 = (tbhv2_t*)sqlite3_value_blob( argv[0] );
567  size_t blob_size = (size_t)sqlite3_value_bytes( argv[0] );
568  double process_time = 0.0;
569  double ratio = 0.0;
570 
571  sqlite3_result_null( ctx );
572 
573  // omit process time of zero, if blob is type V1 (uncompressed)
574  if( tbh1 && tbh1->validMagic() && tbh1->validVer() )
575  {
576  sqlite3_result_double( ctx, 0.0 );
577  }
578  else if( tbh2 && tbh2->validMagic() && tbh2->validVer() && tbh2->validCompression() )
579  {
580  mxArray* pItem = NULL;
581  void* dummy_blob = NULL;
582  size_t dummy_blob_size = 0;
583  double process_time = 0.0;
584 
585  if( !blob_unpack( (void*)tbh2, blob_size, can_serialize(), &pItem, &process_time, &ratio ) )
586  {
587  sqlite3_result_error( ctx, "BDCRatio(): an error while unpacking occured!", -1 );
588  }
589  else if( !blob_pack( pItem, can_serialize(), &dummy_blob, &dummy_blob_size, &process_time, &ratio ) )
590  {
591  sqlite3_result_error( ctx, "BDCRatio(): an error while packing occured!", -1 );
592  }
593  else
594  {
595  sqlite3_result_double( ctx, process_time );
596  }
597 
598  sqlite3_free( dummy_blob );
599  ::utils_destroy_array( pItem );
600  }
601  }
602  else
603  {
604  sqlite3_result_error( ctx, "BDCPackTime(): only BLOB type supported!", -1 );
605  }
606 }
607 
608 
619 void BDC_unpack_time_func( sqlite3_context *ctx, int argc, sqlite3_value **argv ){
620  assert( argc == 1 );
621 
622  // two versions of typed header will be tested
623  typedef TypedBLOBHeaderV1 tbhv1_t;
624  typedef TypedBLOBHeaderV2 tbhv2_t;
625 
626  sqlite3_result_null( ctx );
627 
628  // get and handle "value" argument
629  if( SQLITE_BLOB == sqlite3_value_type( argv[0] ) )
630  {
631  tbhv1_t* tbh1 = (tbhv1_t*)sqlite3_value_blob( argv[0] );
632  tbhv2_t* tbh2 = (tbhv2_t*)sqlite3_value_blob( argv[0] );
633  size_t blob_size = (size_t)sqlite3_value_bytes( argv[0] );
634  double process_time = 0.0;
635  double ratio = 0.0;
636 
637  // omit process time of zero, if blob is type V1 (uncompressed)
638  if( tbh1 && tbh1->validMagic() && tbh1->validVer() )
639  {
640  sqlite3_result_double( ctx, 0.0 );
641  }
642  else if( tbh2 && tbh2->validMagic() && tbh2->validVer() && tbh2->validCompression() )
643  {
644  mxArray *pItem = NULL;;
645 
646  if( !blob_unpack( (void*)tbh2, blob_size, can_serialize(), &pItem, &process_time, &ratio ) )
647  {
648  sqlite3_result_error( ctx, "BDCUnpackTime(): an error while unpacking occured!", -1 );
649  }
650  else
651  {
652  sqlite3_result_double( ctx, process_time );
653  }
654 
655  ::utils_destroy_array( pItem );
656  }
657  }
658  else
659  {
660  sqlite3_result_error( ctx, "BDCUnpackTime(): only BLOB type supported!", -1 );
661  }
662 }
663 
664 
665 
666 
667 
668 /*
669  * Functions for BLOB handling (compression and typing)
670  */
671 
675 void blob_free( void** ppBlob )
676 {
677  if( ppBlob )
678  {
679  sqlite3_free( *ppBlob );
680  *ppBlob = NULL;
681  }
682 }
683 
684 
699 int blob_pack( const mxArray* pcItem, bool bStreamable,
700  void** ppBlob, size_t* pBlob_size,
701  double *pdProcess_time, double* pdRatio,
702  const char* compressor, int level )
703 {
704  Err err;
705 
706  assert( pcItem && ppBlob && pBlob_size && pdProcess_time && pdRatio );
707 
708  ValueMex value( pcItem ); // object wrapper
709  mxArray* byteStream = NULL; // for stream preprocessing
710  NumberCompressor numericSequence; // compressor
711 
712  // BLOB packaging in 3 steps:
713  // 1. Serialize
714  // 2. Compress
715  // 3. Encapsulate (typed BLOBs)
716 
717  if( value.Complexity() == ValueMex::TC_COMPLEX )
718  {
719  if( !bStreamable || !serialize( pcItem, byteStream ) )
720  {
721  err.set( MSG_ERRMEMORY );
722  goto finalize;
723  }
724 
725  // inherit new byte stream instead original array
726  value = ValueMex( byteStream );
727  }
728 
729 
730  *ppBlob = NULL;
731  *pBlob_size = 0;
732  *pdProcess_time = 0.0;
733  *pdRatio = 1.0;
734 
735  /*
736  * create a typed blob. Header information is generated
737  * according to value and type of the matrix and the machine
738  */
739  // setCompressor() always returns true, since parameters had been checked already
740  (void)numericSequence.setCompressor( compressor, level );
741 
742  // only if compression is desired
743  if( g_compression_level )
744  {
745  double start_time = utils_get_wall_time();
746 
747  numericSequence.pack( value.Data(), value.ByData(), value.ByElement(),
748  value.IsDoubleClass() ); // allocates m_rdata
749 
750  *pdProcess_time = utils_get_wall_time() - start_time;
751 
752  // any compressed data omitted?
753  if( numericSequence.m_result_size > 0 )
754  {
755  size_t blob_size_uncompressed;
756 
757  *pBlob_size =
759  numericSequence.m_result_size;
760 
761  blob_size_uncompressed =
763  value.ByData();
764 
765  assert( blob_size_uncompressed != 0 );
766 
767  // calculate the compression ratio
768  *pdRatio = (double)*pBlob_size / blob_size_uncompressed;
769 
770  if( *pBlob_size >= blob_size_uncompressed )
771  {
772  // Switch zu uncompressed blob, it's not worth the efford.
773  numericSequence.free_result();
774  }
775  }
776 
777  // still use compressed data to store in the blob?
778  if( numericSequence.m_result_size > 0 )
779  {
780  TypedBLOBHeaderV2* tbh2 = NULL;
781 
782  // discard data if it exeeds max allowd size by sqlite
783  if( *pBlob_size > CONFIG_MKSQLITE_MAX_BLOB_SIZE )
784  {
785  err.set( MSG_BLOBTOOBIG );
786  goto finalize;
787  }
788 
789  // allocate space for a typed blob containing compressed data
790  tbh2 = (TypedBLOBHeaderV2*)sqlite3_malloc( (int)*pBlob_size );
791  if( NULL == tbh2 )
792  {
793  err.set( MSG_ERRMEMORY );
794  goto finalize;
795  }
796 
797  // blob typing...
798  tbh2->init( value.Item() );
799  tbh2->setCompressor( numericSequence.getCompressorName() );
800 
801  // ...and copy compressed data
803  // (Most platforms use little endian)
804  memcpy( (char*)tbh2->getData(), numericSequence.m_result, numericSequence.m_result_size );
805 
806  // optionally check if compressed data equals to original?
807  if( g_compression_check && !numericSequence.isLossy() )
808  {
809  mxArray* unpacked = NULL;
810  bool is_equal = false;
811  double dummy;
812 
813  // inflate compressed data again
814  if( !blob_unpack( (void*)tbh2, (int)*pBlob_size, bStreamable, &unpacked, &dummy, &dummy ) )
815  {
816  sqlite3_free( tbh2 );
817 
818  err.set( MSG_ERRCOMPRESSION );
819  goto finalize;
820  }
821 
822  is_equal = ( memcmp( value.Data(), ValueMex(unpacked).Data(), value.ByData() ) == 0 );
823  ::utils_destroy_array( unpacked );
824 
825  // check if uncompressed data equals original
826  if( !is_equal )
827  {
828  sqlite3_free( tbh2 );
829 
830  err.set( MSG_ERRCOMPRESSION );
831  goto finalize;
832  }
833  }
834 
835  // store the typed blob with compressed data as return parameter
836  *ppBlob = (void*)tbh2;
837  }
838  }
839 
840  // if compressed data exceeds uncompressed size, it will be stored as
841  // uncompressed typed blob
842  if( !*ppBlob )
843  {
844  TypedBLOBHeaderV1* tbh1 = NULL;
845 
846  /* Without compression, raw data is copied into blob structure as is */
847  *pBlob_size = TypedBLOBHeaderV1::dataOffset( value.NumDims() ) + value.ByData();
848 
849  if( *pBlob_size > CONFIG_MKSQLITE_MAX_BLOB_SIZE )
850  {
851  err.set( MSG_BLOBTOOBIG );
852  goto finalize;
853  }
854 
855  tbh1 = (TypedBLOBHeaderV1*)sqlite3_malloc( (int)*pBlob_size );
856  if( NULL == tbh1 )
857  {
858  err.set( MSG_ERRMEMORY );
859  goto finalize;
860  }
861 
862  // blob typing...
863  tbh1->init( value.Item() );
864 
865  // and copy uncompressed data
867  // (Most platforms use little endian)
868  memcpy( tbh1->getData(), value.Data(), value.ByData() );
869 
870  *ppBlob = (void*)tbh1;
871  }
872 
873  // mark data type as "unknown", means that it holds a serialized item as byte stream
874  if( byteStream )
875  {
876  ((TypedBLOBHeaderV1*)*ppBlob)->m_clsid = mxUNKNOWN_CLASS;
877  }
878 
879 finalize:
880 
881  // cleanup
882  // free cdata and byteStream if left any
883  ::utils_destroy_array( byteStream );
884 
885  return err.getMsgId();
886 }
887 
888 
899 int blob_unpack( const void* pBlob, size_t blob_size, bool bStreamable,
900  mxArray** ppItem,
901  double* pdProcess_time, double* pdRatio )
902 {
903  Err err;
904  bool bIsByteStream = false;
905 
906  typedef TypedBLOBHeaderV1 tbhv1_t;
907  typedef TypedBLOBHeaderV2 tbhv2_t;
908 
909  mxArray* pItem = NULL;
910  NumberCompressor numericSequence;
911 
912  assert( NULL != ppItem && NULL != pdProcess_time && NULL != pdRatio );
913 
914  *ppItem = NULL;
915  *pdProcess_time = 0.0;
916  *pdRatio = 1.0;
917 
918  tbhv1_t* tbh1 = (tbhv1_t*)pBlob;
919  tbhv2_t* tbh2 = (tbhv2_t*)pBlob;
920 
921  /* test valid platform */
922  if( !tbh1->validPlatform() )
923  {
924  mexWarnMsgIdAndTxt( "MATLAB:MKSQLITE:BlobDiffArch", ::getLocaleMsg( MSG_WARNDIFFARCH ) );
926  // since mostly platforms (except SunOS) use LE encoding
927  // and unicode is not supported here, there is IMHO no need
928  // for conversions...
929 
930  // Warning can switched off via:
931  // warning( 'off', 'MATLAB:MKSQLITE:BlobDiffArch' );
932  }
933 
934  /* check for valid header */
935  if( !tbh1->validMagic() )
936  {
937  err.set( MSG_UNSUPPTBH );
938  goto finalize;
939  }
940 
941  // serialized array marked as "unknown class" is a byte stream
942  if( tbh1->m_clsid == mxUNKNOWN_CLASS )
943  {
944  bIsByteStream = true;
945  tbh1->m_clsid = mxUINT8_CLASS;
946  }
947 
948  switch( tbh1->m_ver )
949  {
950  // typed blob with uncompressed data
951  case sizeof( tbhv1_t ):
952  {
953  // get data from header "type 1" is easy
954  pItem = tbh1->createNumericArray( /* doCopyData */ true );
955  break;
956  }
957 
958  // typed blob with compressed data
959  case sizeof( tbhv2_t ):
960  {
961  if( !tbh2->validCompression() )
962  {
963  err.set( MSG_UNKCOMPRESSOR );
964  goto finalize;
965  }
966 
967  // create an empty MATLAB array
968  pItem = tbh2->createNumericArray( /* doCopyData */ false );
969 
970  // space allocated?
971  if( pItem )
972  {
973  numericSequence.setCompressor( tbh2->m_compression );
974 
975  double start_time = utils_get_wall_time();
976  void* cdata = tbh2->getData(); // get compressed data
977  size_t cdata_size = blob_size - tbh2->dataOffset(); // and its size
978 
979  // data will be unpacked directly into MATLAB variable data space
980  if( !numericSequence.unpack( cdata, cdata_size, ValueMex(pItem).Data(), ValueMex(pItem).ByData(), ValueMex(pItem).ByElement() ) )
981  {
982  err.set( MSG_ERRCOMPRESSION );
983  goto finalize;
984  }
985 
986  *pdProcess_time = utils_get_wall_time() - start_time;
987 
988  // any data omitted?
989  if( ValueMex(pItem).ByData() > 0 )
990  {
991  *pdRatio = (double)cdata_size / numericSequence.m_result_size;
992  }
993  else
994  {
995  *pdRatio = 0.0;
996  }
997 
999  }
1000  break;
1001  }
1002 
1003  default:
1004  err.set( MSG_UNSUPPTBH );
1005  goto finalize;
1006  }
1007 
1008 
1009  // revert if streaming preprocess was done
1010  if( bIsByteStream )
1011  {
1012  mxArray* pDeStreamed = NULL;
1013 
1014  if( !deserialize( pItem, pDeStreamed ) )
1015  {
1016  err.set( MSG_ERRMEMORY );
1017  goto finalize;
1018  }
1019 
1020  ::utils_destroy_array( pItem );
1021  pItem = pDeStreamed;
1022  }
1023 
1024  *ppItem = pItem;
1025  pItem = NULL;
1026 
1027 finalize:
1028 
1029  // cleanup
1030  // rdata is owned by a MATLAB variable (will be freed by MATLAB)
1031  // cdata is owned by the blob (const parameter pBlob)
1032  // so inhibit from freeing through destructor:
1033  ::utils_destroy_array( pItem );
1034 
1035  return err.getMsgId();
1036 }
1037 
1038 
1039 #endif
Encapsulating a MATLAB mxArray.
Definition: value.hpp:178
static size_t getDataSize(const mxArray *pItem)
Get data size of an array in bytes.
void * m_result
compressor output
bool deserialize(const mxArray *pByteStream, mxArray *&pItem)
Converts byte stream back into originally MATLAB variable.
Definition: serialize.hpp:62
void ln_func(sqlite3_context *ctx, int argc, sqlite3_value **argv)
Natural logarithm function implementation.
type_complexity_e Complexity(bool bCanSerialize=false) const
Get complexity information. Which storage level is necessary (scalar, vector, matrix, text, blob)
Definition: value.hpp:531
void BDC_pack_time_func(sqlite3_context *ctx, int argc, sqlite3_value **argv)
BDCPackTime function implementation.
const char * getLocaleMsg(int iMsgNr)
Returns the translation for a defined message.
Definition: locale.hpp:480
size_t ByElement() const
Returns size in bytes of one element.
Definition: value.hpp:493
int blob_unpack(const void *pBlob, size_t blob_size, bool bStreamable, mxArray **ppItem, double *pProcess_time, double *pdRatio)
uncompress a typed blob and return as MATLAB array
size_t ByData() const
Returns data size in bytes.
Definition: value.hpp:511
const char * getCompressorName()
Get compressor name.
void regex_func(sqlite3_context *ctx, int argc, sqlite3_value **argv)
Regular expression function implementation.
void init(mxClassID clsid, mwSize nDims, const mwSize *pSize)
Initialization (hides base class init() function)
Compression of numeric (real number) arrays.
double utils_get_wall_time()
Returns current counter time in seconds.
Definition: utils.hpp:350
void blob_free(void **pBlob)
Free memory allocated for a BLOB.
char TBH_endian[]
endian (little or big)
MATLAB hidden (officially undocumented) feature of serializing data.
bool pack(void *rdata, size_t rdata_size, size_t rdata_element_size, bool isDoubleClass)
Calls the qualified compressor (deflate) which always allocates sufficient memory (m_cdata) ...
size_t dataOffset()
Get header offset to begin of array data (initialized)
structs, cells, complex data (SQLite typed ByteStream BLOB)
Definition: value.hpp:190
bool isLossy()
Returns true, if current compressor modifies value data.
compressor class
void utils_destroy_array(mxArray *&pmxarr)
Freeing memory allocated by mxCreateNumericMatrix() or mxCreateNumericArray().
Definition: utils.hpp:302
int NumDims() const
Returns number of dimensions.
Definition: value.hpp:502
void MD5_func(sqlite3_context *ctx, int argc, sqlite3_value **argv)
MD5 hashing implementation.
bool can_serialize()
Returns true, if streaming is switched on (user setting) and serialization is accessible.
Definition: serialize.hpp:108
Helperclass for error message transport.
Definition: locale.hpp:116
Template class extending base class uniquely.
#define HC_NOTES(ptr, notes)
Definition: heap_check.hpp:25
int g_convertUTF8
Flag: String representation (utf8 or ansi)
Definition: global.hpp:253
int blob_pack(const mxArray *pcItem, bool bStreamable, void **ppBlob, size_t *pBlob_size, double *pdProcess_time, double *pdRatio, const char *compressor=g_compression_type, int level=g_compression_level)
create a compressed typed blob from a Matlab item (deep copy)
bool serialize(const mxArray *pItem, mxArray *&pByteStream)
Converts MATLAB variable of any complexity into byte stream.
Definition: serialize.hpp:43
#define CONFIG_MKSQLITE_MAX_BLOB_SIZE
SQLite itself limits BLOBs to 1MB, mksqlite limits to INT32_MAX.
Definition: config.h:63
void set(const char *strMsg, const char *strId=NULL)
Set error message to a constant string (without translation)
Definition: locale.hpp:150
void free_result()
Clear self created results with memory deallocation.
void utils_free_ptr(T *&pmxarr)
Freeing memory allocated by mxAlloc() or mxRealloc()
Definition: utils.hpp:322
void * Data() const
Returns pointer to raw data.
Definition: value.hpp:572
char * utils_strnewdup(const char *s, int flagConvertUTF8)
duplicate a string and recode from UTF8 to char due to flag flagConvertUTF8
Definition: utils.hpp:211
int utils_latin2utf(const unsigned char *s, unsigned char *buffer)
Convert char string to UTF-8 string.
Definition: utils.hpp:171
void pow_func(sqlite3_context *ctx, int argc, sqlite3_value **argv)
Power function implementation.
bool unpack(void *cdata, size_t cdata_size, void *rdata, size_t rdata_size, size_t rdata_element_size)
Calls the qualified compressor (inflate)
void BDC_unpack_time_func(sqlite3_context *ctx, int argc, sqlite3_value **argv)
BDCUnpackTime function implementation.
int getMsgId()
Get the current message identifier.
Definition: locale.hpp:278
void * getData(mwSize nDims)
Get pointer to array data (while initializing)
Packing MATLAB data in a memory block with type information for storing as SQL BLOB.
const mxArray * Item() const
Returns hosted MATLAB array.
Definition: value.hpp:351
void lg_func(sqlite3_context *ctx, int argc, sqlite3_value **argv)
Logarithm function to base 10 implementation.
void exp_func(sqlite3_context *ctx, int argc, sqlite3_value **argv)
Exponential function implementation.
void BDC_ratio_func(sqlite3_context *ctx, int argc, sqlite3_value **argv)
BDCRatio function implementation.
bool IsDoubleClass() const
Returns true if m_pcItem is of type mxDOUBLE_CLASS.
Definition: value.hpp:466
size_t m_result_size
size of compressor output in bytes
bool setCompressor(const char *strCompressorType, int iCompressionLevel=-1)
Converts compressor ID string to category enum.
#define MEM_ALLOC(count, bytes)
standard memory allocator
Definition: global.hpp:156