Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add support for zero-blobs to the OP_MakeRecord opcode. First test cases of zeroblob functionality. (CVS 3897) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
e6d560ddeeb48fb0cbd9f5a10612280b |
User & Date: | drh 2007-05-02 13:30:27.000 |
Context
2007-05-02
| ||
15:36 | Fix an invalid UTF8 encoding in the tests for the trim function. (CVS 3898) (check-in: 4dbbfff4a7 user: drh tags: trunk) | |
13:30 | Add support for zero-blobs to the OP_MakeRecord opcode. First test cases of zeroblob functionality. (CVS 3897) (check-in: e6d560ddee user: drh tags: trunk) | |
13:16 | Use the pointer-map pages to make the incremental blob API more efficient. (CVS 3896) (check-in: 93a3bf71d5 user: danielk1977 tags: trunk) | |
Changes
Changes to src/vdbe.c.
︙ | ︙ | |||
39 40 41 42 43 44 45 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** | | | 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | ** ** Various scripts scan this source file in order to generate HTML ** documentation, headers files, or other derived files. The formatting ** of the code in this file is, therefore, important. See other comments ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** ** $Id: vdbe.c,v 1.604 2007/05/02 13:30:27 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> #include "vdbeInt.h" /* |
︙ | ︙ | |||
307 308 309 310 311 312 313 | }else{ c = 's'; } zCsr += sprintf(zCsr, "%c", c); zCsr += sprintf(zCsr, "%d[", pMem->n); for(i=0; i<16 && i<pMem->n; i++){ | | > > > | 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 | }else{ c = 's'; } zCsr += sprintf(zCsr, "%c", c); zCsr += sprintf(zCsr, "%d[", pMem->n); for(i=0; i<16 && i<pMem->n; i++){ zCsr += sprintf(zCsr, "%02X", ((int)pMem->z[i] & 0xFF)); } for(i=0; i<16 && i<pMem->n; i++){ char z = pMem->z[i]; if( z<32 || z>126 ) *zCsr++ = '.'; else *zCsr++ = z; } zCsr += sprintf(zCsr, "]"); if( f & MEM_Zero ){ zCsr += sprintf(zCsr,"+%lldz",pMem->u.i); } *zCsr = '\0'; }else if( f & MEM_Str ){ int j, k; zBuf[0] = ' '; if( f & MEM_Dyn ){ zBuf[1] = 'z'; assert( (f & (MEM_Static|MEM_Ephem))==0 ); |
︙ | ︙ | |||
2181 2182 2183 2184 2185 2186 2187 | ** the top of the stack. ** ** Each type field is a varint representing the serial type of the ** corresponding data element (see sqlite3VdbeSerialType()). The ** hdr-size field is also a varint which is the offset from the beginning ** of the record to data0. */ | | < | | | > < | < > > | 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 | ** the top of the stack. ** ** Each type field is a varint representing the serial type of the ** corresponding data element (see sqlite3VdbeSerialType()). The ** hdr-size field is also a varint which is the offset from the beginning ** of the record to data0. */ u8 *zNewRecord; /* A buffer to hold the data for the new record */ Mem *pRec; /* The new record */ Mem *pRowid = 0; /* Rowid appended to the new record */ int nData = 0; /* Number of bytes of data space */ int nHdr = 0; /* Number of bytes of header space */ int nByte = 0; /* Data space required for this record */ int nZero = 0; /* Number of zero bytes at the end of the record */ int nVarint; /* Number of bytes in a varint */ u32 serial_type; /* Type field */ int containsNull = 0; /* True if any of the data fields are NULL */ Mem *pData0; /* Bottom of the stack */ int leaveOnStack; /* If true, leave the entries on the stack */ int nField; /* Number of fields in the record */ int jumpIfNull; /* Jump here if non-zero and any entries are NULL. */ int addRowid; /* True to append a rowid column at the end */ char *zAffinity; /* The affinity string for the record */ int file_format; /* File format to use for encoding */ int i; /* Space used in zNewRecord[] */ char zTemp[NBFS]; /* Space to hold small records */ leaveOnStack = ((pOp->p1<0)?1:0); nField = pOp->p1 * (leaveOnStack?-1:1); jumpIfNull = pOp->p2; addRowid = pOp->opcode==OP_MakeIdxRec; zAffinity = pOp->p3; |
︙ | ︙ | |||
2225 2226 2227 2228 2229 2230 2231 | } if( pRec->flags&MEM_Null ){ containsNull = 1; } serial_type = sqlite3VdbeSerialType(pRec, file_format); nData += sqlite3VdbeSerialTypeLen(serial_type); nHdr += sqlite3VarintLen(serial_type); | > > > > > > > | | > | | > | < | | | | | | | > > > > | 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 | } if( pRec->flags&MEM_Null ){ containsNull = 1; } serial_type = sqlite3VdbeSerialType(pRec, file_format); nData += sqlite3VdbeSerialTypeLen(serial_type); nHdr += sqlite3VarintLen(serial_type); if( pRec->flags & MEM_Zero ){ /* Only pure zero-filled BLOBs can be input to this Opcode. ** We do not allow blobs with a prefix and a zero-filled tail. */ assert( pRec->n==0 ); nZero += pRec->u.i; }else{ nZero = 0; } } /* If we have to append a varint rowid to this record, set pRowid ** to the value of the rowid and increase nByte by the amount of space ** required to store it. */ if( addRowid ){ pRowid = &pTos[0-nField]; assert( pRowid>=p->aStack ); sqlite3VdbeMemIntegerify(pRowid); serial_type = sqlite3VdbeSerialType(pRowid, 0); nData += sqlite3VdbeSerialTypeLen(serial_type); nHdr += sqlite3VarintLen(serial_type); nZero = 0; } /* Add the initial header varint and total the size */ nHdr += nVarint = sqlite3VarintLen(nHdr); if( nVarint<sqlite3VarintLen(nHdr) ){ nHdr++; } nByte = nHdr+nData-nZero; /* Allocate space for the new record. */ if( nByte>sizeof(zTemp) ){ zNewRecord = sqliteMallocRaw(nByte); if( !zNewRecord ){ goto no_mem; } }else{ zNewRecord = (u8*)zTemp; } /* Write the record */ i = sqlite3PutVarint(zNewRecord, nHdr); for(pRec=pData0; pRec<=pTos; pRec++){ serial_type = sqlite3VdbeSerialType(pRec, file_format); i += sqlite3PutVarint(&zNewRecord[i], serial_type); /* serial type */ } if( addRowid ){ i += sqlite3PutVarint(&zNewRecord[i], sqlite3VdbeSerialType(pRowid, 0)); } for(pRec=pData0; pRec<=pTos; pRec++){ /* serial data */ i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRec, file_format); } if( addRowid ){ i += sqlite3VdbeSerialPut(&zNewRecord[i], nByte-i, pRowid, 0); } assert( i==nByte ); /* Pop entries off the stack if required. Push the new record on. */ if( !leaveOnStack ){ popStack(&pTos, nField+addRowid); } pTos++; pTos->n = nByte; if( nByte<=sizeof(zTemp) ){ assert( zNewRecord==(unsigned char *)zTemp ); pTos->z = pTos->zShort; memcpy(pTos->zShort, zTemp, nByte); pTos->flags = MEM_Blob | MEM_Short; }else{ assert( zNewRecord!=(unsigned char *)zTemp ); pTos->z = (char*)zNewRecord; pTos->flags = MEM_Blob | MEM_Dyn; pTos->xDel = 0; } if( nZero ){ pTos->u.i = nZero; pTos->flags |= MEM_Zero; } pTos->enc = SQLITE_UTF8; /* In case the blob is ever converted to text */ /* If a NULL was encountered and jumpIfNull is non-zero, take the jump. */ if( jumpIfNull && containsNull ){ pc = jumpIfNull - 1; } break; |
︙ | ︙ | |||
4993 4994 4995 4996 4997 4998 4999 | }else if( (pTos[i].flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){ fprintf(p->trace, " si:%lld", pTos[i].u.i); }else if( pTos[i].flags & MEM_Int ){ fprintf(p->trace, " i:%lld", pTos[i].u.i); }else if( pTos[i].flags & MEM_Real ){ fprintf(p->trace, " r:%g", pTos[i].r); }else{ | | | 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 | }else if( (pTos[i].flags & (MEM_Int|MEM_Str))==(MEM_Int|MEM_Str) ){ fprintf(p->trace, " si:%lld", pTos[i].u.i); }else if( pTos[i].flags & MEM_Int ){ fprintf(p->trace, " i:%lld", pTos[i].u.i); }else if( pTos[i].flags & MEM_Real ){ fprintf(p->trace, " r:%g", pTos[i].r); }else{ char zBuf[200]; sqlite3VdbeMemPrettyPrint(&pTos[i], zBuf); fprintf(p->trace, " "); fprintf(p->trace, "%s", zBuf); } } if( rc!=0 ) fprintf(p->trace," rc=%d",rc); fprintf(p->trace,"\n"); |
︙ | ︙ |
Changes to src/vdbeInt.h.
︙ | ︙ | |||
129 130 131 132 133 134 135 | i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ } u; double r; /* Real value */ char *z; /* String or BLOB value */ int n; /* Number of characters in string value, including '\0' */ u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ | | | | 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | i64 i; /* Integer value. Or FuncDef* when flags==MEM_Agg */ FuncDef *pDef; /* Used only when flags==MEM_Agg */ } u; double r; /* Real value */ char *z; /* String or BLOB value */ int n; /* Number of characters in string value, including '\0' */ u16 flags; /* Some combination of MEM_Null, MEM_Str, MEM_Dyn, etc. */ u8 type; /* One of SQLITE_NULL, SQLITE_TEXT, SQLITE_INTEGER, etc */ u8 enc; /* SQLITE_UTF8, SQLITE_UTF16BE, SQLITE_UTF16LE */ void (*xDel)(void *); /* If not null, call this function to delete Mem.z */ char zShort[NBFS]; /* Space for short strings */ }; typedef struct Mem Mem; /* One or more of the following flags are set to indicate the validOK ** representations of the value stored in the Mem struct. |
︙ | ︙ | |||
360 361 362 363 364 365 366 | void sqlite3VdbePrintOp(FILE*, int, Op*); #endif #ifdef SQLITE_DEBUG void sqlite3VdbePrintSql(Vdbe*); #endif int sqlite3VdbeSerialTypeLen(u32); u32 sqlite3VdbeSerialType(Mem*, int); | | | 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 | void sqlite3VdbePrintOp(FILE*, int, Op*); #endif #ifdef SQLITE_DEBUG void sqlite3VdbePrintSql(Vdbe*); #endif int sqlite3VdbeSerialTypeLen(u32); u32 sqlite3VdbeSerialType(Mem*, int); int sqlite3VdbeSerialPut(unsigned char*, int, Mem*, int); int sqlite3VdbeSerialGet(const unsigned char*, u32, Mem*); void sqlite3VdbeDeleteAuxData(VdbeFunc*, int); int sqlite2BtreeKeyCompare(BtCursor *, const void *, int, int, int *); int sqlite3VdbeIdxKeyCompare(Cursor*, int , const unsigned char*, int*); int sqlite3VdbeIdxRowid(BtCursor *, i64 *); int sqlite3MemCompare(const Mem*, const Mem*, const CollSeq*); |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 | */ /* ** Return the serial-type for the value stored in pMem. */ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){ int flags = pMem->flags; if( flags&MEM_Null ){ return 0; } if( flags&MEM_Int ){ /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */ # define MAX_6BYTE ((((i64)0x00001000)<<32)-1) | > | 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 | */ /* ** Return the serial-type for the value stored in pMem. */ u32 sqlite3VdbeSerialType(Mem *pMem, int file_format){ int flags = pMem->flags; int n; if( flags&MEM_Null ){ return 0; } if( flags&MEM_Int ){ /* Figure out whether to use 1, 2, 4, 6 or 8 bytes. */ # define MAX_6BYTE ((((i64)0x00001000)<<32)-1) |
︙ | ︙ | |||
1741 1742 1743 1744 1745 1746 1747 | if( u<=2147483647 ) return 4; if( u<=MAX_6BYTE ) return 5; return 6; } if( flags&MEM_Real ){ return 7; } | | | | | | | > > > > > > > > > > > > > | > > | > > > > > > > > > | 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 | if( u<=2147483647 ) return 4; if( u<=MAX_6BYTE ) return 5; return 6; } if( flags&MEM_Real ){ return 7; } assert( flags&(MEM_Str|MEM_Blob) ); n = pMem->n; if( flags & MEM_Zero ){ n += pMem->u.i; } assert( n>=0 ); return ((n*2) + 12 + ((flags&MEM_Str)!=0)); } /* ** Return the length of the data corresponding to the supplied serial-type. */ int sqlite3VdbeSerialTypeLen(u32 serial_type){ if( serial_type>=12 ){ return (serial_type-12)/2; }else{ static const u8 aSize[] = { 0, 1, 2, 3, 4, 6, 8, 8, 0, 0, 0, 0 }; return aSize[serial_type]; } } /* ** Write the serialized data blob for the value stored in pMem into ** buf. It is assumed that the caller has allocated sufficient space. ** Return the number of bytes written. ** ** nBuf is the amount of space left in buf[]. nBuf must always be ** large enough to hold the entire field. Except, if the field is ** a blob with a zero-filled tail, then buf[] might be just the right ** size to hold everything except for the zero-filled tail. If buf[] ** is only big enough to hold the non-zero prefix, then only write that ** prefix into buf[]. But if buf[] is large enough to hold both the ** prefix and the tail then write the prefix and set the tail to all ** zeros. ** ** Return the number of bytes actually written into buf[]. The number ** of bytes in the zero-filled tail is included in the return value only ** if those bytes were zeroed in buf[]. */ int sqlite3VdbeSerialPut(u8 *buf, int nBuf, Mem *pMem, int file_format){ u32 serial_type = sqlite3VdbeSerialType(pMem, file_format); int len; /* Integer and Real */ if( serial_type<=7 && serial_type>0 ){ u64 v; int i; if( serial_type==7 ){ assert( sizeof(v)==sizeof(pMem->r) ); memcpy(&v, &pMem->r, sizeof(v)); }else{ v = pMem->u.i; } len = i = sqlite3VdbeSerialTypeLen(serial_type); assert( len<=nBuf ); while( i-- ){ buf[i] = (v&0xFF); v >>= 8; } return len; } /* String or blob */ if( serial_type>=12 ){ assert( pMem->n + ((pMem->flags & MEM_Zero)?pMem->u.i:0) == sqlite3VdbeSerialTypeLen(serial_type) ); assert( pMem->n<=nBuf ); len = pMem->n; memcpy(buf, pMem->z, len); if( pMem->flags & MEM_Zero ){ len += pMem->u.i; if( len>nBuf ){ len = nBuf; } memset(&buf[pMem->n], 0, len-pMem->n); } return len; } /* NULL or constants 0 or 1 */ return 0; } |
︙ | ︙ |
Changes to src/vdbemem.c.
︙ | ︙ | |||
80 81 82 83 84 85 86 | z[n+1] = 0; pMem->z = (char*)z; pMem->flags &= ~(MEM_Ephem|MEM_Static|MEM_Short); return SQLITE_OK; } /* | | | | > | 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | z[n+1] = 0; pMem->z = (char*)z; pMem->flags &= ~(MEM_Ephem|MEM_Static|MEM_Short); return SQLITE_OK; } /* ** If the given Mem* has a zero-filled tail, turn it into an ordinary ** blob stored in dynamically allocated space. */ int sqlite3VdbeMemExpandBlob(Mem *pMem){ if( pMem->flags & MEM_Zero ){ char *pNew; assert( (pMem->flags & MEM_Blob)!=0 ); pNew = sqliteMalloc(pMem->n+pMem->u.i); if( pNew==0 ){ return SQLITE_NOMEM; } memcpy(pNew, pMem->z, pMem->n); memset(&pNew[pMem->n], 0, pMem->u.i); sqlite3VdbeMemRelease(pMem); pMem->z = pNew; pMem->n += pMem->u.i; pMem->u.i = 0; pMem->flags &= MEM_Zero|MEM_Static|MEM_Ephem|MEM_Short; pMem->flags |= MEM_Term|MEM_Dyn; } return SQLITE_OK; } |
︙ | ︙ | |||
376 377 378 379 380 381 382 | /* ** Delete any previous value and set the value to be a BLOB of length ** n containing all zeros. */ void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ sqlite3VdbeMemRelease(pMem); | | > | 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 | /* ** Delete any previous value and set the value to be a BLOB of length ** n containing all zeros. */ void sqlite3VdbeMemSetZeroBlob(Mem *pMem, int n){ sqlite3VdbeMemRelease(pMem); pMem->flags = MEM_Blob|MEM_Zero|MEM_Short; pMem->type = SQLITE_BLOB; pMem->n = 0; pMem->u.i = n; pMem->z = pMem->zShort; } /* ** Delete any previous value and set the value stored in *pMem to val, ** manifest type INTEGER. */ void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ |
︙ | ︙ | |||
738 739 740 741 742 743 744 | void sqlite3VdbeMemSanity(Mem *pMem){ int flags = pMem->flags; assert( flags!=0 ); /* Must define some type */ if( flags & (MEM_Str|MEM_Blob) ){ int x = flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short); assert( x!=0 ); /* Strings must define a string subtype */ assert( (x & (x-1))==0 ); /* Only one string subtype can be defined */ | | | 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 | void sqlite3VdbeMemSanity(Mem *pMem){ int flags = pMem->flags; assert( flags!=0 ); /* Must define some type */ if( flags & (MEM_Str|MEM_Blob) ){ int x = flags & (MEM_Static|MEM_Dyn|MEM_Ephem|MEM_Short); assert( x!=0 ); /* Strings must define a string subtype */ assert( (x & (x-1))==0 ); /* Only one string subtype can be defined */ assert( pMem->z!=0 ); /* Strings must have a value */ /* Mem.z points to Mem.zShort iff the subtype is MEM_Short */ assert( (x & MEM_Short)==0 || pMem->z==pMem->zShort ); assert( (x & MEM_Short)!=0 || pMem->z!=pMem->zShort ); /* No destructor unless there is MEM_Dyn */ assert( pMem->xDel==0 || (pMem->flags & MEM_Dyn)!=0 ); if( (flags & MEM_Str) ){ |
︙ | ︙ |
Added test/zeroblob.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | # 2007 May 02 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this file is testing of the zero-filled blob functionality # including the sqlite3_bind_zeroblob(), sqlite3_result_zeroblob(), # and the built-in zeroblob() SQL function. # # $Id: zeroblob.test,v 1.1 2007/05/02 13:30:27 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create the database # do_test zeroblob-1.1 { execsql { CREATE TABLE t1(a,b,c,d); INSERT INTO t1 VALUES(1,2,3,zeroblob(10000)); SELECT count(*) FROM t1; } } {1} do_test zeroblob-1.2 { execsql { SELECT length(d) FROM t1 } } {10000} do_test zeroblob-1.3 { execsql { INSERT INTO t1 VALUES(2,3,zeroblob(10000),4); SELECT count(*) FROM t1; } } {2} do_test zeroblob-1.4 { execsql { SELECT length(c), length(d) FROM t1 } } {1 10000 10000 1} do_test zeroblob-1.5 { execsql { INSERT INTO t1 VALUES(3,4,zeroblob(10000),zeroblob(10000)); SELECT count(*) FROM t1; } } {3} do_test zeroblob-1.6 { execsql { SELECT length(c), length(d) FROM t1 } } {1 10000 10000 1 10000 10000} finish_test |