Revision | $Id: //open/dev/farrago/src/net/sf/farrago/query/package.html#18 $ |
---|---|
Copyright | Copyright (C) 2005-2009 The Eigenbase Project
Copyright (C) 2005-2009 SQLstream, Inc. Copyright (C) 2005-2009 LucidEra, Inc. |
Author | John V. Sichi |
We'll use a simple, innocent-looking statement as an example:
select *,42 as the_answer
from sales.depts as d
where deptno = 10
TODO: details on caching
EXPLAIN PLAN
statement can be used to see the
translated tree for our example:
explain plan without implementation for
select *,42 as the_answer
from sales.depts as d
where deptno = 10
This yields:
ProjectRel(DEPTNO=[$0], NAME=[$1], THE_ANSWER=[42])
FilterRel(condition=[=($0,10)])
TableAccessRel(table=[SALES.DEPTS])
Here's a graphical representation:
$N
(hence the $0
in the
ProjectRel's expression refers to something different from the
$0
in the FilterRel's condition expression, since
the expression is relative to the containing RelNode).
Farrago constrains the optimizer to the following calling conventions:
EXPLAIN
PLAN
again:
explain plan for
select *,42 as the_answer
from sales.depts as d
where deptno = 10
(This time WITHOUT IMPLEMENTATION
was left out, and the
default is WITH IMPLEMENTATION, which is what we want.) This yields:
IterCalcRel(DEPTNO=[$0], NAME=[$1], THE_ANSWER=[42])
FennelToIteratorConverter
FtrsIndexSearchRel(table=[SALES.DEPTS], projection=[*], index=[SYS$CONSTRAINT_INDEX$DEPTS$SYS$PRIMARY_KEY], uniqueKey=[true], preserveOrder=[false],outer=[false],inputKeyProj=[*],inputJoinProj=[[]])
IteratorToFennelConverter
IterCalcRel($f0=[CAST(10)])
IterOneRowRel
which corresponds to the following relational expression tree:
$f0
since Fennel accesses data by tuple position, not
name.) Now, the optimizer wants to feed this into the Fennel search
as the input key, but the search has FENNEL_PULL calling convention, while
IterCalcRel has ITERATOR calling convention. So, a {@link
org.eigenbase.rel.convert.ConverterRel} is required; in this case,
{@link net.sf.farrago.query.IteratorToFennelConverter}.
But wait, there's more! The FtrsIndexSearchRel is going to produce matching rows in FENNEL_PULL representation, but in order to compute the select list and return results via JDBC, we need another converter: {@link net.sf.farrago.query.FennelToIteratorConverter}. The top-level IterCalcRel then implements the original abstract ProjectRel.
package net.sf.farrago.dynamic.stmt39449;
public class ExecutableStmt
{
public static class Ojp_0 extends net.sf.farrago.type.runtime.FarragoSyntheticObject
{
public Ojp_0()
{
}
}
public static class Ojp_1 extends net.sf.farrago.type.runtime.FarragoSyntheticObject
{
public int $f0;
public Ojp_1()
{
}
public Ojp_1( int $f0 )
{
this.$f0 = $f0;
}
}
public static class Oj_VARCHAR_128_ISO_8859_1 extends net.sf.farrago.type.runtime.EncodedCharPointer
{
protected java.lang.String getCharsetName()
{
return "ISO-8859-1";
}
}
public static class Ojp_2 extends net.sf.farrago.type.runtime.FarragoSyntheticObject
{
public int DEPTNO;
public net.sf.farrago.dynamic.stmt39449.ExecutableStmt$Oj_VARCHAR_128_ISO_8859_1 NAME;
public Ojp_2()
{
}
public Ojp_2( int DEPTNO, net.sf.farrago.dynamic.stmt39449.ExecutableStmt$Oj_VARCHAR_128_ISO_8859_1 NAME )
{
this.DEPTNO = DEPTNO;
this.NAME = NAME;
}
}
public static class Ojp_3 extends net.sf.farrago.type.runtime.FarragoSyntheticObject
{
public int DEPTNO;
public net.sf.farrago.dynamic.stmt39449.ExecutableStmt$Oj_VARCHAR_128_ISO_8859_1 NAME;
public long THE_ANSWER;
public Ojp_3()
{
}
public Ojp_3( int DEPTNO, net.sf.farrago.dynamic.stmt39449.ExecutableStmt$Oj_VARCHAR_128_ISO_8859_1 NAME, long THE_ANSWER )
{
this.DEPTNO = DEPTNO;
this.NAME = NAME;
this.THE_ANSWER = THE_ANSWER;
}
}
public static java.lang.Object execute( net.sf.farrago.runtime.FarragoRuntimeContext connection_p )
throws java.sql.SQLException
{
final net.sf.farrago.runtime.FarragoRuntimeContext connection = connection_p;
return new org.eigenbase.runtime.CalcIterator( connection.newFennelIterator( new net.sf.farrago.runtime.FennelTupleReader(){
private net.sf.farrago.dynamic.stmt39449.ExecutableStmt$Ojp_2 oj_var3 = new net.sf.farrago.dynamic.stmt39449.ExecutableStmt$Ojp_2();
public java.lang.Object unmarshalTuple( java.nio.ByteBuffer byteBuffer, byte[] byteArray, java.nio.ByteBuffer sliceBuffer )
{
int oj_var4 = byteBuffer.position();
oj_var3.DEPTNO = sliceBuffer.getInt( 0 );
int oj_var5 = oj_var4 + sliceBuffer.getShort( 4 );
oj_var3.NAME.setPointer( byteArray, 6 + oj_var4, oj_var5 );
sliceBuffer.position( oj_var5 - oj_var4 );
return oj_var3;
}
}, "FtrsIndexSearchRel#74:315", connection.newJavaTupleStream( 96, new net.sf.farrago.runtime.FennelTupleWriter(){
protected void marshalTupleOrThrow( java.nio.ByteBuffer sliceBuffer, java.lang.Object object )
{
net.sf.farrago.dynamic.stmt39449.ExecutableStmt$Ojp_1 oj_var2 = (net.sf.farrago.dynamic.stmt39449.ExecutableStmt$Ojp_1) object;
sliceBuffer.putInt( 0, oj_var2.$f0 );
sliceBuffer.position( 4 );
}
}, new org.eigenbase.runtime.CalcIterator( java.util.Collections.singletonList( new net.sf.farrago.dynamic.stmt39449.ExecutableStmt$Ojp_0() ).iterator() ){
private net.sf.farrago.dynamic.stmt39449.ExecutableStmt$Ojp_1 oj_var1 = new net.sf.farrago.dynamic.stmt39449.ExecutableStmt$Ojp_1();
protected java.lang.Object calcNext()
{
while (inputIterator.hasNext()) {
net.sf.farrago.dynamic.stmt39449.ExecutableStmt$Ojp_0 oj_var0 = (net.sf.farrago.dynamic.stmt39449.ExecutableStmt$Ojp_0) inputIterator.next();
oj_var1.$f0 = (int) (int) 10;
return oj_var1;
}
return null;
}
} ) ) ){
private net.sf.farrago.dynamic.stmt39449.ExecutableStmt$Ojp_3 oj_var7 = new net.sf.farrago.dynamic.stmt39449.ExecutableStmt$Ojp_3();
protected java.lang.Object calcNext()
{
while (inputIterator.hasNext()) {
net.sf.farrago.dynamic.stmt39449.ExecutableStmt$Ojp_2 oj_var6 = (net.sf.farrago.dynamic.stmt39449.ExecutableStmt$Ojp_2) inputIterator.next();
oj_var7.DEPTNO = (int) oj_var6.DEPTNO;
oj_var7.NAME.assignFrom( oj_var6.NAME );
oj_var7.THE_ANSWER = (long) 42;
return oj_var7;
}
return null;
}
};
}
}
Yeesh, that's ugly! How can we interpret this jumble in the context
of the implementation plan?
FtrsIndexSearchRel#74:315
. This is the generated name of a stream
within the Fennel plan. On execution, this stream name will be used
to obtain a handle to a C++ execution object from the graph of Fennel
TupleStreams. More on this below.
newJavaTupleStream
call
creates a Java execution object which will be called directly from C++
code. The generated identifier argument 96
is referenced
from the Fennel plan.
<XMI xmi.version = '1.2' xmlns:CWM = 'org.omg.xmi.namespace.CWM' xmlns:FEM = 'org.omg.xmi.namespace.FEM'
xmlns:CWMRDB = 'org.omg.xmi.namespace.CWMRDB' xmlns:FEMFennel = 'org.omg.xmi.namespace.FEMFennel'
xmlns:FEMConfig = 'org.omg.xmi.namespace.FEMConfig' timestamp = 'Tue May 11 11:01:22 PDT 2004'>
<XMI.header>
<XMI.documentation>
<XMI.exporter>Netbeans XMI Writer</XMI.exporter>
<XMI.exporterVersion>1.0</XMI.exporterVersion>
</XMI.documentation>
</XMI.header>
<XMI.content>
<FEMFennel:CmdPrepareExecutionStreamGraph xmi.id = 'a1'>
<FEMFennel:CmdPrepareExecutionStreamGraph.streamDefs>
<FEMFennel:IndexSearchDef xmi.id = 'a2' name = 'FtrsIndexSearchRel#74:315'
cachePageQuota = '2' cachePageMin = '2' cachePageMax = '2' rootPageId = '3'
segmentId = '1' indexId = '2709' uniqueKey = 'true' outerJoin = 'false'>
<FEMFennel:KeyAccessorDef.keyProj>
<FEMFennel:TupleProjection xmi.id = 'a3'>
<FEMFennel:TupleProjection.AttrProjection>
<FEMFennel:TupleAttrProjection xmi.id = 'a4' attributeIndex = '0'/>
</FEMFennel:TupleProjection.AttrProjection>
</FEMFennel:TupleProjection>
</FEMFennel:KeyAccessorDef.keyProj>
<FEMFennel:IndexAccessorDef.tupleDesc>
<FEMFennel:TupleDescriptor xmi.id = 'a5'>
<FEMFennel:TupleDescriptor.AttrDescriptor>
<FEMFennel:TupleAttrDescriptor xmi.id = 'a6' typeOrdinal = '5' isNullable = 'false'
byteLength = '0'/>
<FEMFennel:TupleAttrDescriptor xmi.id = 'a7' typeOrdinal = '13' isNullable = 'false'
byteLength = '128'/>
</FEMFennel:TupleDescriptor.AttrDescriptor>
</FEMFennel:TupleDescriptor>
</FEMFennel:IndexAccessorDef.tupleDesc>
<FEMFennel:IndexScanDef.outputProj>
<FEMFennel:TupleProjection xmi.id = 'a8'>
<FEMFennel:TupleProjection.AttrProjection>
<FEMFennel:TupleAttrProjection xmi.id = 'a9' attributeIndex = '0'/>
<FEMFennel:TupleAttrProjection xmi.id = 'a10' attributeIndex = '1'/>
</FEMFennel:TupleProjection.AttrProjection>
</FEMFennel:TupleProjection>
</FEMFennel:IndexScanDef.outputProj>
<FEMFennel:ExecutionStreamDef.Input>
<FEMFennel:JavaTupleStreamDef xmi.idref = 'a11'/>
</FEMFennel:ExecutionStreamDef.Input>
</FEMFennel:IndexSearchDef>
<FEMFennel:JavaTupleStreamDef xmi.id = 'a11' name = 'IteratorToFennelConverter#96:324'
cachePageQuota = '1' cachePageMin = '1' cachePageMax = '1' streamId = '96'>
<FEMFennel:JavaTupleStreamDef.tupleDesc>
<FEMFennel:TupleDescriptor xmi.id = 'a12'>
<FEMFennel:TupleDescriptor.AttrDescriptor>
<FEMFennel:TupleAttrDescriptor xmi.id = 'a13' typeOrdinal = '5' isNullable = 'false'
byteLength = '0'/>
</FEMFennel:TupleDescriptor.AttrDescriptor>
</FEMFennel:TupleDescriptor>
</FEMFennel:JavaTupleStreamDef.tupleDesc>
<FEMFennel:ExecutionStreamDef.Consumer>
<FEMFennel:IndexSearchDef xmi.idref = 'a2'/>
</FEMFennel:ExecutionStreamDef.Consumer>
</FEMFennel:JavaTupleStreamDef>
</FEMFennel:CmdPrepareExecutionStreamGraph.streamDefs>
<FEMFennel:TupleStreamGraphCmd.StreamGraphHandle>
<FEMFennel:StreamGraphHandle xmi.idref = 'a14'/>
</FEMFennel:TupleStreamGraphCmd.StreamGraphHandle>
</FEMFennel:CmdPrepareExecutionStreamGraph>
<FEMFennel:StreamGraphHandle xmi.id = 'a14' longHandle = '137731624'/>
</XMI.content>
</XMI>
(The easiest way to obtain this XML is to set
net.sf.farrago.fennel.level=FINE in FarragoTrace.properties and then
dig through FarragoTrace.log after executing an SQL statement. Search
for "CmdPrepareExecutionStreamGraph". For more information on the
Java representation of Fennel TupleStreams, see the JNI design doc.)
The root of the TupleStream tree above is the FEMFennel:IndexSearchDef node (whose name attribute corresponds to the stream name referenced in the generated Java code above). The leaf is the FEMFennel:JavaTupleStreamDef node, which tells Fennel how to get the search key from the lower-level Java iterators. (TBD: more about this and {@link net.sf.farrago.query.IteratorToFennelConverter}).
May 11, 2004 11:08:27 AM net.sf.farrago.db.FarragoDbSession prepare
INFO: select *,42 as the_answer from sales.depts d where deptno=10
May 11, 2004 11:08:32 AM net.sf.farrago.db.FarragoDbStmtContext traceExecute
FINE: select *,42 as the_answer from sales.depts d where deptno=10
May 11, 2004 11:08:33 AM net.sf.fennel.xo.IteratorToFennelConverter#96:324 <native>
FINE: [ 10 ]
May 11, 2004 11:08:33 AM net.sf.fennel.xo.FtrsIndexSearchRel#74:315 <native>
FINE: [ 10, 'Sales' ]
The entry for IteratorToFennelConverter is the search key read from Java,
and the entry for FtrsIndexSearchRel is the result of the search which
is returned to Java.