forked from georgebarwood/Database
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathIdSet.cs
200 lines (172 loc) · 5.13 KB
/
IdSet.cs
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
namespace DBNS {
using G = System.Collections.Generic;
using SQLNS;
/*
IdSet is for optimising WHERE clauses for SELECT,UPDATE,DELETE.
When accessing a large table, we only want to access a small subset of the records.
The id values may be explicit as in
SELECT .... FROM dbo.Cust WHERE id in ( 3,4,5 )
or they may come from an index as in
SELECT .... FROM dbo.Cust WHERE Name = 'Smith'
where an index has been defined CREATE INDEX CustByName ON dbo.Cust(Name)
*/
abstract class IdSet
{
public abstract G.IEnumerable<long>All( EvalEnv ee );
}
class ExpListIdSet : IdSet
{
Exp[] List;
public ExpListIdSet( Exp[] list, EvalEnv e ) { List = list; }
public override G.IEnumerable<long>All( EvalEnv ee )
{
for ( int i = 0; i < List.Length; i += 1 )
{
yield return List[i].Eval( ee ).L;
}
}
}
class TableExpressionIdSet : IdSet
{
SingleResultSet S = new SingleResultSet();
public TableExpressionIdSet( TableExpression te, EvalEnv ee )
{
te.FetchTo( S, ee );
}
public override G.IEnumerable<long>All( EvalEnv ee )
{
StoredTable t = S.Table;
G.List<Value[]> rows = t.Rows;
for ( int i = 0; i < rows.Count; i += 1 )
{
Value[] row = rows[ i ];
yield return row[0].L;
}
}
} // end class TableExpressionIdSet
class IdCopy : IdSet
{
G.SortedSet<long> Copy = new G.SortedSet<long>();
public IdCopy( IdSet x, EvalEnv ee )
{
foreach ( long id in x.All( ee ) ) Copy.Add( id );
}
public override G.IEnumerable<long>All( EvalEnv ee )
{
foreach ( long id in Copy ) yield return id;
}
}
class SingleId : IdSet
{
Exp X;
public SingleId( Exp x ){ X = x; }
public override G.IEnumerable<long>All( EvalEnv ee )
{
Value v = X.Eval( ee );
yield return v.L;
}
}
class UpTo : IdSet
{
long N;
public UpTo( long n ){ N = n; }
public override G.IEnumerable<long>All( EvalEnv ee ){ for ( int i=1; i<=N; i+=1 ) yield return i; }
}
// Uses an index to look up a set of id values, optimises select ... from t where indexedcol in ( .... )
class Lookup : IdSet
{
G.IEnumerable<Value> Values;
IndexFile Ix;
public Lookup( IndexFile ix, G.IEnumerable<Value> values )
{
Values = values;
Ix = ix;
}
public override G.IEnumerable<long>All( EvalEnv ee )
{
foreach ( Value v in Values )
{
DataType t = Ix.Inf.Types[0];
int idCol = Ix.Inf.KeyCount-1;
var start = new ValueStart( v, t );
foreach ( IndexFileRecord r in Ix.From( start.Compare, false ) )
{
if ( Util.Compare( v, r.Col[0], t ) == 0 )
{
yield return r.Col[ idCol ].L;
}
else break;
}
}
}
} // end class Lookup
class IndexFrom : IdSet
{
Exp K;
IndexFile F;
DataType Type;
Token Op;
Value V;
int Compare( ref IndexFileRecord r ) // This make not be quite optimal for Less and Greater.
{
int cf = 0;
if ( Op <= Token.LessEqual ) // Op == Token.Less || Op == Token.LessEqual
{
switch ( Type )
{
case DataType.Binary:
cf = Util.Compare( (byte[])V._O, (byte[])r.Col[0]._O );
if ( cf == 0 ) cf = +1; // Should be -1 if Op == Less ?
break;
case DataType.String:
cf = string.Compare( (string)V._O, (string)r.Col[0]._O );
if ( cf == 0 ) cf = +1; // Should be -1 if Op == Less ?
break;
case DataType.Bigint:
cf = V.L < r.Col[0].L ? -1 : +1; // Should be <= if Op == Less ?
break;
default: throw new System.Exception( "Type error" );
}
}
else // ( Op == Token.Greater || Op == Token.GreaterEqual || Op == Token.Equal )
{
switch ( Type )
{
case DataType.Binary:
cf = Util.Compare( (byte[])V._O, (byte[])r.Col[0]._O );
if ( cf == 0 ) cf = -1;
break;
case DataType.String:
cf = string.Compare( (string)V._O, (string)r.Col[0]._O );
if ( cf == 0 ) cf = -1;
break;
case DataType.Bigint:
cf = V.L <= r.Col[0].L ? -1 : +1;
break;
default: throw new System.Exception( "Type error" );
}
}
return cf;
}
public IndexFrom( IndexFile f, Exp k, Token op )
{
F = f; K = k; Op = op;
}
public override G.IEnumerable<long>All( EvalEnv ee )
{
V = K.Eval( ee );
Type = K.Type;
foreach ( IndexFileRecord r in F.From( Compare, Op <= Token.LessEqual /* Op == Token.Less || Op == Token.LessEqual */ ) )
{
if ( Op == Token.Equal ) switch ( K.Type )
{
case DataType.Bigint: if ( r.Col[0].L != V.L ) yield break; break;
case DataType.Binary: if ( Util.Compare( (byte[])r.Col[0]._O, (byte[])V._O ) != 0 ) yield break; break;
case DataType.String: if ( ((string)r.Col[0]._O) != (string)V._O ) yield break; break;
default: throw new System.Exception( "Type error" );
}
yield return r.Col[ F.Inf.KeyCount-1 ].L;
}
}
} // end class IndexFrom
} // end namespace DBNS