sqlite-users is probably more appropriate than the development list so this 
should be carried on there.  Please use that list to continue this discussion 
as more people are likely to see it, participate, and benefit from the 
discussions.

Have you actually built some tables in SQLite and had it dump the VDBE code 
that it will execute to perform the query?  This will probably help enormously 
in understanding how SQLite works.

As an aside, SQLite does not join three tables by joining tables one and two 
into a temporary table, then joining in table three.  It plots the most 
efficient nested loop (navigational) solution and executes the resulting row 
generator which yields each result row as it is found.

See:  http://www.sqlite.org/optoverview.html

sqlite3_step() equates to:

def stepper():
        open table1
        open table2
        open table3
        rewind table1
        for each row in table1 matching the query constraints on table1
                rewind table2
                for each row in table2 matching the constraints in the query 
and provided by table1
                        rewind table3
                        for each row in table3 matching the constraints in the 
query and provided by table1 and table2
                                yield a result row
        close table3
        close table2
        close table1

where stepper is a generator.  the first call executes the code up until the 
yield whereupon the result is returned to the caller.  Subsequent calls carry 
on from the yield thus returning each result row one at a time.  when all the 
loops run out and there is nothing more to yield the generator terminates and 
returns an no more rows indication to the caller.

sqlite3_prepare prepares the stepper program by compiling the sql query that 
you have asked to be executed.

SQLite version 3.8.7 2014-09-12 04:28:33
Enter ".help" for usage hints.
Connected to a transient in-memory database.
Use ".open FILENAME" to reopen on a persistent database.
sqlite> create table employee(name, stuff);
sqlite> create table location(name, stuff);
sqlite> create table company(name, stuff);
sqlite> .explain
sqlite> explain select * from employee, company, location where employee.name = 
company.name and company.name = location.name;
SELECT item[0] = {0:0} AS name
       item[1] = {0:1} AS stuff
       item[2] = {1:0} AS name
       item[3] = {1:1} AS stuff
       item[4] = {2:0} AS name
       item[5] = {2:1} AS stuff
FROM {0,*} = employee
     {1,*} = company
     {2,*} = location
WHERE AND(EQ({0:0},{1:0}),EQ({1:0},{2:0}))
END
addr  opcode         p1    p2    p3    p4             p5  comment
----  -------------  ----  ----  ----  -------------  --  -------------
0     Init           0     51    0                    00  Start at 51
1     OpenRead       0     2     0     2              00  root=2 iDb=0; employee
2     OpenRead       1     4     0     2              00  root=4 iDb=0; company
3     OpenRead       2     3     0     2              00  root=3 iDb=0; location
4     Noop           0     0     0                    00  Begin WHERE-loop0: 
employee
5     Rewind         0     48    0                    00
6       Once           0     15    0                    00
7       OpenAutoindex  3     3     0     k(3,nil,nil,nil)  00  nColumn=3; for 
company
8       Rewind         1     15    0                    00
9         Column         1     0     2                    00  r[2]=company.name
10        Column         1     1     3                    00  r[3]=company.stuff
11        Rowid          1     4     0                    00  r[4]=rowid
12        MakeRecord     2     3     1                    00  
r[1]=mkrec(r[2..4])
13        IdxInsert      3     1     0                    10  key=r[1]
14      Next           1     9     0                    03
15      Noop           0     0     0                    00  Begin WHERE-loop1: 
company
16      Column         0     0     5                    00  r[5]=employee.name
17      IsNull         5     46    0                    00  if r[5]==NULL goto 
46
18      SeekGE         3     46    5     1              00  key=r[5]
19        IdxGT          3     46    5     1              00  key=r[5]
20        Once           1     29    0                    00
21        OpenAutoindex  4     3     0     k(3,nil,nil,nil)  00  nColumn=3; for 
location
22        Rewind         2     29    0                    00
23          Column         2     0     2                    00  
r[2]=location.name
24          Column         2     1     3                    00  
r[3]=location.stuff
25          Rowid          2     4     0                    00  r[4]=rowid
26          MakeRecord     2     3     1                    00  
r[1]=mkrec(r[2..4])
27          IdxInsert      4     1     0                    10  key=r[1]
28        Next           2     23    0                    03
29        Noop           0     0     0                    00  Begin 
WHERE-loop2: location
30        Column         3     0     6                    00  r[6]=company.name
31        IsNull         6     44    0                    00  if r[6]==NULL 
goto 44
32        SeekGE         4     44    6     1              00  key=r[6]
33          IdxGT          4     44    6     1              00  key=r[6]
34          Noop           0     0     0                    00  Begin WHERE-core
35          Copy           5     7     0                    00  r[7]=r[5]
36          Column         0     1     8                    00  
r[8]=employee.stuff
37          Copy           6     9     0                    00  r[9]=r[6]
38          Column         3     1     10                   00  
r[10]=company.stuff
39          Column         4     0     11                   00  
r[11]=location.name
40          Column         4     1     12                   00  
r[12]=location.stuff
41          ResultRow      7     6     0                    00  output=r[7..12]
42          Noop           0     0     0                    00  End WHERE-core
43        Next           4     33    0                    00
44        Noop           0     0     0                    00  End WHERE-loop2: 
location
45      Next           3     19    0                    00
46      Noop           0     0     0                    00  End WHERE-loop1: 
company
47    Next           0     6     0                    01
48    Noop           0     0     0                    00  End WHERE-loop0: 
employee
49    Close          0     0     0                    00
50    Halt           0     0     0                    00
51    Transaction    0     0     3     0              01
52    TableLock      0     2     0     employee       00  iDb=0 root=2 write=0
53    TableLock      0     4     0     company        00  iDb=0 root=4 write=0
54    TableLock      0     3     0     location       00  iDb=0 root=3 write=0
55    Goto           0     1     0                    00
sqlite>

In this case "MakeRecord" makes a record for insertion in the indexes that the 
optimizer has decided should be created temporarily to service this query 
because the designer neglected to do so.  Automatic Indexing is an optimization 
that has been chosen by the optimizer so that full table scans in each nested 
loop can be avoided.

You can turn off automatic indexing optimization with a pragma which will tell 
the query optimizer not to generate indexes, thus full table scans will have to 
be used.  This results in the following code, which is pretty much the same 
except without index creation and using full table scans in the nested loops -- 
it does not use MakeRecord because there is no need to construct records (for 
indexes in this example):

sqlite> pragma automatic_index=0;
sqlite> explain select * from employee, company, location where employee.name = 
company.name and company.name = location.name;
SELECT item[0] = {0:0} AS name
       item[1] = {0:1} AS stuff
       item[2] = {1:0} AS name
       item[3] = {1:1} AS stuff
       item[4] = {2:0} AS name
       item[5] = {2:1} AS stuff
FROM {0,*} = employee
     {1,*} = company
     {2,*} = location
WHERE AND(EQ({0:0},{1:0}),EQ({1:0},{2:0}))
END
addr  opcode         p1    p2    p3    p4             p5  comment
----  -------------  ----  ----  ----  -------------  --  -------------
0     Init           0     36    0                    00  Start at 36
1     OpenRead       0     2     0     2              00  root=2 iDb=0; employee
2     OpenRead       1     4     0     2              00  root=4 iDb=0; company
3     OpenRead       2     3     0     2              00  root=3 iDb=0; location
4     Noop           0     0     0                    00  Begin WHERE-loop0: 
employee
5     Rewind         0     31    0                    00
6       Noop           0     0     0                    00  Begin WHERE-loop1: 
company
7       Rewind         1     29    0                    00
8         Column         0     0     1                    00  r[1]=employee.name
9         Column         1     0     2                    00  r[2]=company.name
10        Ne             2     28    1     (BINARY)       6a  if r[2]!=r[1] 
goto 28
11        Noop           0     0     0                    00  begin transitive 
constraint
12        Ne             1     28    2     (BINARY)       6a  if r[1]!=r[2] 
goto 28
13        Noop           0     0     0                    00  Begin 
WHERE-loop2: location
14        Rewind         2     27    0                    00
15          Column         2     0     3                    00  
r[3]=location.name
16          Ne             3     26    2     (BINARY)       6a  if r[3]!=r[2] 
goto 26
17          Noop           0     0     0                    00  Begin WHERE-core
18          Copy           1     4     0                    00  r[4]=r[1]
19          Column         0     1     5                    00  
r[5]=employee.stuff
20          Copy           2     6     0                    00  r[6]=r[2]
21          Column         1     1     7                    00  
r[7]=company.stuff
22          Copy           3     8     0                    00  r[8]=r[3]
23          Column         2     1     9                    00  
r[9]=location.stuff
24          ResultRow      4     6     0                    00  output=r[4..9]
25          Noop           0     0     0                    00  End WHERE-core
26        Next           2     15    0                    01
27        Noop           0     0     0                    00  End WHERE-loop2: 
location
28      Next           1     8     0                    01
29      Noop           0     0     0                    00  End WHERE-loop1: 
company
30    Next           0     6     0                    01
31    Noop           0     0     0                    00  End WHERE-loop0: 
employee
32    Close          0     0     0                    00
33    Close          1     0     0                    00
34    Close          2     0     0                    00
35    Halt           0     0     0                    00
36    Transaction    0     0     3     0              01
37    TableLock      0     2     0     employee       00  iDb=0 root=2 write=0
38    TableLock      0     4     0     company        00  iDb=0 root=4 write=0
39    TableLock      0     3     0     location       00  iDb=0 root=3 write=0
40    Goto           0     1     0                    00
sqlite>

If it helps, all operations in SQLite are navigational.  VDBE programs can 
navigate around the tables and move specific items from a current record into a 
register, do things with registers, and create a record (MakeRecord) from 
register(s) for insertion in an index or other table.  There can only be one 
"current" record from any table-cursor or index at any point in time.

You can think of MakeRecord as creating a list of pointers to the data items 
that will be used when then record is passed to some storage method (ie, 
written to a table, index, temp table, temp index, etc).  Within the VDBE 
program there are no sets of records -- only persisted tables/indexes, so to 
create temporary index or for group by, etc, the result data is collected via 
MakeRecord then inserted into another table/index.  This is then subsequently 
navigated to generate the ResultRow's.  ie -- exactly how you would do it if 
all you had were ISAM  files to work with and your programming language did not 
have the ability to create collections and data structures in memory but could 
only access the fields within the records and registers to contain the data 
temporarily.


>-----Original Message-----
>From: sqlite-dev-boun...@sqlite.org [mailto:sqlite-dev-
>boun...@sqlite.org] On Behalf Of Prakash Premkumar
>Sent: Friday, 12 September, 2014 08:21
>To: sqlite-...@sqlite.org
>Subject: [sqlite-dev] SQLite Vdbe Opcode MakeRecord
>
>Hi,
>Can you please explain what the opcode Make Record does ? I was not able
>to understand it from the docs.
>
>Let's assume that there are three tables that are to be joined
>
>
>       example : select * from employee,company,location where
>location.name = company.name and location.name = employee.name;
>
>
>how do I get the result of the first join between location and company ?
>Where is that result stored and how is the result joined with the result
>of the next join ?
>
>Can you please explain me with reference to the source code ?
>
>Thanks
>Prakash



_______________________________________________
sqlite-users mailing list
sqlite-users@sqlite.org
http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to