Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Clarification on the best practices for using the _bytes() APIs. Change sqlite3_value_blob() to force the representation to be purely a BLOB and not a dual BLOB/String. Ticket #2360. (CVS 4005) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
cf2dd45b58380de7f3e167b5357848d1 |
User & Date: | drh 2007-05-15 13:27:07.000 |
Context
2007-05-15
| ||
14:10 | Fix to check-in (4005). A call to sqlite3_column_blob() should not make subsequent calls to sqlite3_column_type() return SQLITE_BLOB. Sqlite3_column_type() returns the initial type. (CVS 4006) (check-in: b5e85deb5a user: drh tags: trunk) | |
13:27 | Clarification on the best practices for using the _bytes() APIs. Change sqlite3_value_blob() to force the representation to be purely a BLOB and not a dual BLOB/String. Ticket #2360. (CVS 4005) (check-in: cf2dd45b58 user: drh tags: trunk) | |
11:55 | A new approach for UTF-8 translation. (CVS 4004) (check-in: 6c8ad2790e user: drh tags: trunk) | |
Changes
Changes to src/func.c.
︙ | ︙ | |||
12 13 14 15 16 17 18 | ** This file contains the C functions that implement various SQL ** functions of SQLite. ** ** There is only one exported symbol in this file - the function ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** | | | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | ** This file contains the C functions that implement various SQL ** functions of SQLite. ** ** There is only one exported symbol in this file - the function ** sqliteRegisterBuildinFunctions() found at the bottom of the file. ** All other code has file scope. ** ** $Id: func.c,v 1.158 2007/05/15 13:27:07 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* #include <math.h> */ #include <stdlib.h> #include <assert.h> #include "vdbeInt.h" |
︙ | ︙ | |||
172 173 174 175 176 177 178 179 180 181 182 183 184 185 | assert( argc==3 ); p0type = sqlite3_value_type(argv[0]); if( p0type==SQLITE_BLOB ){ len = sqlite3_value_bytes(argv[0]); z = sqlite3_value_blob(argv[0]); if( z==0 ) return; }else{ z = sqlite3_value_text(argv[0]); if( z==0 ) return; len = 0; for(z2=z; *z2; len++){ SQLITE_SKIP_UTF8(z2); } | > | 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | assert( argc==3 ); p0type = sqlite3_value_type(argv[0]); if( p0type==SQLITE_BLOB ){ len = sqlite3_value_bytes(argv[0]); z = sqlite3_value_blob(argv[0]); if( z==0 ) return; assert( len==sqlite3_value_bytes(argv[0]) ); }else{ z = sqlite3_value_text(argv[0]); if( z==0 ) return; len = 0; for(z2=z; *z2; len++){ SQLITE_SKIP_UTF8(z2); } |
︙ | ︙ | |||
238 239 240 241 242 243 244 245 | ** Implementation of the upper() and lower() SQL functions. */ static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ char *z1; const char *z2; int i, n; if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return; n = sqlite3_value_bytes(argv[0]); | > > | > > | | 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 | ** Implementation of the upper() and lower() SQL functions. */ static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ char *z1; const char *z2; int i, n; if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return; z2 = (char*)sqlite3_value_text(argv[0]); n = sqlite3_value_bytes(argv[0]); /* Verify that the call to _bytes() does not invalidate the _text() pointer */ assert( z2==(char*)sqlite3_value_text(argv[0]) ); if( z2 ){ z1 = sqlite3_malloc(n+1); if( z1 ){ memcpy(z1, z2, n+1); for(i=0; z1[i]; i++){ z1[i] = toupper(z1[i]); } sqlite3_result_text(context, z1, -1, sqlite3_free); } } } static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){ char *z1; const char *z2; int i, n; if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return; z2 = (char*)sqlite3_value_text(argv[0]); n = sqlite3_value_bytes(argv[0]); /* Verify that the call to _bytes() does not invalidate the _text() pointer */ assert( z2==(char*)sqlite3_value_text(argv[0]) ); if( z2 ){ z1 = sqlite3_malloc(n+1); if( z1 ){ memcpy(z1, z2, n+1); for(i=0; z1[i]; i++){ z1[i] = tolower(z1[i]); } |
︙ | ︙ | |||
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 | static void likeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *zA, *zB; int escape = 0; /* Limit the length of the LIKE or GLOB pattern to avoid problems ** of deep recursion and N*N behavior in patternCompare(). */ if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){ sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); return; } | > > > > < < | 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 | static void likeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *zA, *zB; int escape = 0; zB = sqlite3_value_text(argv[0]); zA = sqlite3_value_text(argv[1]); /* Limit the length of the LIKE or GLOB pattern to avoid problems ** of deep recursion and N*N behavior in patternCompare(). */ if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){ sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); return; } assert( zB==sqlite3_value_text(argv[0]) ); /* Encoding did not change */ if( argc==3 ){ /* The escape character string must consist of a single UTF-8 character. ** Otherwise, return an error. */ const unsigned char *zEsc = sqlite3_value_text(argv[2]); if( zEsc==0 ) return; if( sqlite3Utf8CharLen((char*)zEsc, -1)!=1 ){ |
︙ | ︙ | |||
651 652 653 654 655 656 657 658 | case SQLITE_INTEGER: case SQLITE_FLOAT: { sqlite3_result_value(context, argv[0]); break; } case SQLITE_BLOB: { char *zText = 0; int nBlob = sqlite3_value_bytes(argv[0]); | > | | 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 | case SQLITE_INTEGER: case SQLITE_FLOAT: { sqlite3_result_value(context, argv[0]); break; } case SQLITE_BLOB: { char *zText = 0; char const *zBlob = sqlite3_value_blob(argv[0]); int nBlob = sqlite3_value_bytes(argv[0]); assert( zBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */ if( 2*nBlob+4>SQLITE_MAX_LENGTH ){ sqlite3_result_error_toobig(context); return; } zText = (char *)sqliteMalloc((2*nBlob)+4); if( !zText ){ |
︙ | ︙ | |||
718 719 720 721 722 723 724 725 726 727 728 729 | int argc, sqlite3_value **argv ){ int i, n; const unsigned char *pBlob; char *zHex, *z; assert( argc==1 ); n = sqlite3_value_bytes(argv[0]); if( n*2+1>SQLITE_MAX_LENGTH ){ sqlite3_result_error_toobig(context); return; } | > | | 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 | int argc, sqlite3_value **argv ){ int i, n; const unsigned char *pBlob; char *zHex, *z; assert( argc==1 ); pBlob = sqlite3_value_blob(argv[0]); n = sqlite3_value_bytes(argv[0]); if( n*2+1>SQLITE_MAX_LENGTH ){ sqlite3_result_error_toobig(context); return; } assert( pBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */ z = zHex = sqlite3_malloc(n*2 + 1); if( zHex==0 ) return; for(i=0; i<n; i++, pBlob++){ unsigned char c = *pBlob; *(z++) = hexdigits[(c>>4)&0xf]; *(z++) = hexdigits[c&0xf]; } |
︙ | ︙ | |||
772 773 774 775 776 777 778 | int nPattern; /* Size of zPattern */ int nRep; /* Size of zRep */ i64 nOut; /* Maximum size of zOut */ int loopLimit; /* Last zStr[] that might match zPattern[] */ int i, j; /* Loop counters */ assert( argc==3 ); | < | > | > > > | 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 | int nPattern; /* Size of zPattern */ int nRep; /* Size of zRep */ i64 nOut; /* Maximum size of zOut */ int loopLimit; /* Last zStr[] that might match zPattern[] */ int i, j; /* Loop counters */ assert( argc==3 ); zStr = sqlite3_value_text(argv[0]); if( zStr==0 ) return; nStr = sqlite3_value_bytes(argv[0]); assert( zStr==sqlite3_value_text(argv[0]) ); /* No encoding change */ zPattern = sqlite3_value_text(argv[1]); if( zPattern==0 || zPattern[0]==0 ) return; nPattern = sqlite3_value_bytes(argv[1]); assert( zPattern==sqlite3_value_text(argv[1]) ); /* No encoding change */ zRep = sqlite3_value_text(argv[2]); if( zRep==0 ) return; nRep = sqlite3_value_bytes(argv[2]); assert( zRep==sqlite3_value_text(argv[2]) ); nOut = nStr + 1; assert( nOut<SQLITE_MAX_LENGTH ); zOut = sqlite3_malloc((int)nOut); if( zOut==0 ){ return; } loopLimit = nStr - nPattern; |
︙ | ︙ | |||
836 837 838 839 840 841 842 | unsigned char *aLen; /* Length of each character in zCharSet */ const unsigned char **azChar; /* Individual characters in zCharSet */ int nChar; /* Number of characters in zCharSet */ if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ return; } | < > > | 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 | unsigned char *aLen; /* Length of each character in zCharSet */ const unsigned char **azChar; /* Individual characters in zCharSet */ int nChar; /* Number of characters in zCharSet */ if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ return; } zIn = sqlite3_value_text(argv[0]); if( zIn==0 ) return; nIn = sqlite3_value_bytes(argv[0]); assert( zIn==sqlite3_value_text(argv[0]) ); if( argc==1 ){ static const unsigned char lenOne[] = { 1 }; static const unsigned char *azOne[] = { (u8*)" " }; nChar = 1; aLen = (u8*)lenOne; azChar = azOne; zCharSet = 0; |
︙ | ︙ |
Changes to src/vdbeapi.c.
︙ | ︙ | |||
34 35 36 37 38 39 40 | ** The following routines extract information from a Mem or sqlite3_value ** structure. */ const void *sqlite3_value_blob(sqlite3_value *pVal){ Mem *p = (Mem*)pVal; if( p->flags & (MEM_Blob|MEM_Str) ){ sqlite3VdbeMemExpandBlob(p); | < | < > > | 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | ** The following routines extract information from a Mem or sqlite3_value ** structure. */ const void *sqlite3_value_blob(sqlite3_value *pVal){ Mem *p = (Mem*)pVal; if( p->flags & (MEM_Blob|MEM_Str) ){ sqlite3VdbeMemExpandBlob(p); p->flags &= ~MEM_Str; p->flags |= MEM_Blob; p->type = SQLITE_BLOB; return p->z; }else{ return sqlite3_value_text(pVal); } } int sqlite3_value_bytes(sqlite3_value *pVal){ return sqlite3ValueBytes(pVal, SQLITE_UTF8); |
︙ | ︙ |
Changes to www/capi3ref.tcl.
|
| | | 1 2 3 4 5 6 7 8 | set rcsid {$Id: capi3ref.tcl,v 1.58 2007/05/15 13:27:08 drh Exp $} source common.tcl header {C/C++ Interface For SQLite Version 3} puts { <h2 class=pdf_section>C/C++ Interface For SQLite Version 3</h2> } proc api {name prototype desc {notused x}} { |
︙ | ︙ | |||
387 388 389 390 391 392 393 | the second argument is the index of the column for which information should be returned. iCol is zero-indexed. The left-most column has an index of 0. If the SQL statement is not currently point to a valid row, or if the the column index is out of range, the result is undefined. | | | | > | | | > | > | | | | | 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 | the second argument is the index of the column for which information should be returned. iCol is zero-indexed. The left-most column has an index of 0. If the SQL statement is not currently point to a valid row, or if the the column index is out of range, the result is undefined. If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes() routine returns the number of bytes in that BLOB or string. If the result is a UTF-16 string, then sqlite3_column_bytes() converts the string to UTF-8 and then returns the number of bytes. If the result is a numeric value then sqlite3_column_bytes() uses sqlite3_snprintf() to convert that value to a UTF-8 string and returns the number of bytes in that string. The value returned does not include the \\000 terminator at the end of the string. The sqlite3_column_bytes16() routine is similar to sqlite3_column_bytes() but leaves the result in UTF-16 instead of UTF-8. The \\u0000 terminator is not included in this count. These routines attempt to convert the value where appropriate. For example, if the internal representation is FLOAT and a text result is requested, sqlite3_snprintf() is used internally to do the conversion automatically. The following table details the conversions that are applied: <blockquote> <table border="1"> <tr><th>Internal Type</th><th>Requested Type</th><th>Conversion</th></tr> <tr><td> NULL </td><td> INTEGER</td><td>Result is 0</td></tr> |
︙ | ︙ | |||
455 456 457 458 459 460 461 | Conversions between UTF-16be and UTF-16le are always done in place and do not invalidate a prior pointer, though of course the content of the buffer that the prior pointer points to will have been modified. Other kinds of conversion are done in place when it is possible, but sometime it is not possible and in those cases prior pointers are invalidated. | | > | | | | | < < < | | < | | | | | 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 | Conversions between UTF-16be and UTF-16le are always done in place and do not invalidate a prior pointer, though of course the content of the buffer that the prior pointer points to will have been modified. Other kinds of conversion are done in place when it is possible, but sometime it is not possible and in those cases prior pointers are invalidated. The safest and easiest to remember policy is to invoke these routines in one of the following ways: <ul> <li>sqlite3_column_text() followed by sqlite3_column_bytes()</li> <li>sqlite3_column_blob() followed by sqlite3_column_bytes()</li> <li>sqlite3_column_text16() followed by sqlite3_column_bytes16()</li> </ul> In other words, you should call sqlite3_column_text(), sqlite3_column_blob(), or sqlite3_column_text16() first to force the result into the desired format, then invoke sqlite3_column_bytes() or sqlite3_column_bytes16() to find the size of the result. Do not mix call to sqlite3_column_text() or sqlite3_column_blob() with calls to sqlite3_column_bytes16(). And do not mix calls to sqlite3_column_text16() with calls to sqlite3_column_bytes(). } api {} { int sqlite3_column_count(sqlite3_stmt *pStmt); } { Return the number of columns in the result set returned by the prepared SQL statement. This routine returns 0 if pStmt is an SQL statement |
︙ | ︙ |