📄 vdbe.html
字号:
11 Commit 0 0<br> 12 Halt 0 0</tt></blockquote><p>With tracing mode on, the VDBE prints each instruction priorto executing it. After the instruction is executed, the top fewentries in the stack are displayed. The stack display is omittedif the stack is empty.</p><p>On the stack display, most entries are shown with a prefixthat tells the datatype of that stack entry. Integers beginwith "<tt>i:</tt>". Floating point values begin with "<tt>r:</tt>".(The "r" stands for "real-number".) Strings begin with either"<tt>s:</tt>", "<tt>t:</tt>", "<tt>e:</tt>" or "<tt>z:</tt>". The difference among the string prefixes is caused by how their memory is allocated. The z: strings are stored in memory obtainedfrom <b>malloc()</b>. The t: strings are statically allocated. The e: strings are ephemeral. All other strings have the s: prefix. This doesn't make any difference to you,the observer, but it is vitally important to the VDBE since thez: strings need to be passed to <b>free()</b> when they arepopped to avoid a memory leak. Note that only the first 10characters of string values are displayed and that binaryvalues (such as the result of the MakeRecord instruction) aretreated as strings. The only other datatype that can be storedon the VDBE stack is a NULL, which is display without prefixas simply "<tt>NULL</tt>". If an integer has been placed on the stack as both an integer and a string, its prefix is "<tt>si:</tt>".<a name="query1"></a><h2>Simple Queries</h2><p>At this point, you should understand the basics of how the VDBEwrites to a database. Now let's look at how it does queries.We will use the following simple SELECT statement as our example:</p><blockquote><pre>SELECT * FROM examp;</pre></blockquote><p>The VDBE program generated for this SQL statement is as follows:</p><blockquote><tt>sqlite> <b>EXPLAIN SELECT * FROM examp;</b><br>addr opcode p1 p2 p3 <br>---- ------------ ----- ----- -----------------------------------<br>0 ColumnName 0 0 one <br>1 ColumnName 1 0 two <br>2 Integer 0 0 <br>3 OpenRead 0 3 examp <br>4 VerifyCookie 0 81 <br>5 Rewind 0 10 <br>6 Column 0 0 <br>7 Column 0 1 <br>8 Callback 2 0 <br>9 Next 0 6 <br>10 Close 0 0 <br>11 Halt 0 0</tt></blockquote><p>Before we begin looking at this problem, let's briefly reviewhow queries work in SQLite so that we will know what we are tryingto accomplish. For each row in the result of a query,SQLite will invoke a callback function with the followingprototype:</p><blockquote><pre>int Callback(void *pUserData, int nColumn, char *azData[], char *azColumnName[]);</pre></blockquote><p>The SQLite library supplies the VDBE with a pointer to the callback functionand the <b>pUserData</b> pointer. (Both the callback and the user data wereoriginally passed in as arguments to the <b>sqlite_exec()</b> API function.)The job of the VDBE is tocome up with values for <b>nColumn</b>, <b>azData[]</b>, and <b>azColumnName[]</b>.<b>nColumn</b> is the number of columns in the results, of course.<b>azColumnName[]</b> is an array of strings where each string is the nameof one of the result columns. <b>azData[]</b> is an array of strings holdingthe actual data.</p><blockquote><tt>0 ColumnName 0 0 one <br>1 ColumnName 1 0 two</tt></blockquote><p>The first two instructions in the VDBE program for our query areconcerned with setting up values for <b>azColumn</b>.The <a href="opcode.html#ColumnName">ColumnName</a> instructions tell the VDBE what values to fill in for each element of the <b>azColumnName[]</b> array. Every query will begin with one ColumnName instruction for each column in the result, and there will be a matching Column instruction for each one later in the query.</p><blockquote><tt>2 Integer 0 0 <br>3 OpenRead 0 3 examp <br>4 VerifyCookie 0 81</tt></blockquote><p>Instructions 2 and 3 open a read cursor on the database table that is to be queried. This works the same as the OpenWrite instruction in the INSERT example except that the cursor is opened for reading this time instead of for writing. Instruction 4 verifies the database schema as in the INSERT example.</p><blockquote><tt>5 Rewind 0 10</tt></blockquote><p> The <a href="opcode.html#Rewind">Rewind</a> instruction initializes a loop that iterates over the "examp" table. It rewinds the cursor P1 to the first entry in its table. This is required by the the Column and Next instructions, which use the cursor to iterate through the table. If the table is empty, then jump to P2 (10), which is the instruction just past the loop. If the table is not empty, fall through to the following instruction at 6, which is the beginning of the loop body.</p><blockquote><tt>6 Column 0 0 <br>7 Column 0 1 <br>8 Callback 2 0</tt></blockquote><p> The instructions 6 through 8 form the body of the loop that will execute once for each record in the database file. The <a href="opcode.html#Column">Column</a> instructions at addresses 6 and 7 each take the P2-th column from the P1-th cursor and push it onto the stack. In this example, the first Column instruction is pushing the value for the column "one" onto the stack and the second Column instruction is pushing the value for column "two". The <a href="opcode.html#Callback">Callback</a> instruction at address 8 invokes the callback() function. The P1 operand to Callback becomes the value for <b>nColumn</b>. The Callback instruction pops P1 values fromthe stack and uses them to fill the <b>azData[]</b> array.</p><blockquote><tt>9 Next 0 6</tt></blockquote><p>The instruction at address 9 implements the branching part of the loop. Together with the Rewind at address 5 it forms the loop logic. This is a key concept that you should pay close attention to. The <a href="opcode.html#Next">Next</a> instruction advances the cursor P1 to the next record. If the cursor advance was successful, then jump immediately to P2 (6, the beginning of the loop body). If the cursor was at the end, then fall through to the following instruction, which ends the loop.</p><blockquote><tt>10 Close 0 0 <br>11 Halt 0 0</tt></blockquote><p>The Close instruction at the end of the program closes thecursor that points into the table "examp". It is not really necessaryto call Close here since all cursors will be automatically closedby the VDBE when the program halts. But we needed an instructionfor the Rewind to jump to so we might as well go ahead and have thatinstruction do something useful.The Halt instruction ends the VDBE program.</p><p>Note that the program for this SELECT query didn't contain the Transaction and Commit instructions used in the INSERT example. Because the SELECT is a read operation that doesn't alter the database, it doesn't require a transaction.</p><a name="query2"></a><h2>A Slightly More Complex Query</h2><p>The key points of the previous example were the use of the Callbackinstruction to invoke the callback function, and the use of the Nextinstruction to implement a loop over all records of the database file.This example attempts to drive home those ideas by demonstrating aslightly more complex query that involves more columns ofoutput, some of which are computed values, and a WHERE clause thatlimits which records actually make it to the callback function.Consider this query:</p><blockquote><pre>SELECT one, two, one || two AS 'both'FROM exampWHERE one LIKE 'H%'</pre></blockquote><p>This query is perhaps a bit contrived, but it does serve to
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -