1 | /************* tdbvir C++ Program Source Code File (.CPP) **************/ |
2 | /* PROGRAM NAME: tdbvir.cpp Version 1.2 */ |
3 | /* (C) Copyright to the author Olivier BERTRAND 2014-2017 */ |
4 | /* This program are the VIR classes DB execution routines. */ |
5 | /***********************************************************************/ |
6 | |
7 | /***********************************************************************/ |
8 | /* Include relevant sections of the MariaDB header file. */ |
9 | /***********************************************************************/ |
10 | #include <my_global.h> |
11 | |
12 | /***********************************************************************/ |
13 | /* Include application header files: */ |
14 | /* global.h is header containing all global declarations. */ |
15 | /* plgdbsem.h is header containing the DB application declarations. */ |
16 | /* xtable.h is header containing the TDBASE declarations. */ |
17 | /* tdbvir.h is header containing the VIR classes declarations. */ |
18 | /***********************************************************************/ |
19 | #include "global.h" |
20 | #include "plgdbsem.h" |
21 | #include "filter.h" |
22 | #include "xtable.h" |
23 | //#include "reldef.h" |
24 | #include "colblk.h" |
25 | #include "mycat.h" // for FNC_COL |
26 | #include "tabvir.h" |
27 | #include "resource.h" // for IDS_COLUMNS |
28 | |
29 | /***********************************************************************/ |
30 | /* Return the unique column definition to MariaDB. */ |
31 | /***********************************************************************/ |
32 | PQRYRES VirColumns(PGLOBAL g, bool info) |
33 | { |
34 | int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, |
35 | TYPE_INT, TYPE_STRING, TYPE_STRING}; |
36 | XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, |
37 | FLD_PREC, FLD_KEY, FLD_EXTRA}; |
38 | unsigned int length[] = {8, 4, 16, 4, 16, 16}; |
39 | int i, n, ncol = sizeof(buftyp) / sizeof(int); |
40 | PQRYRES qrp; |
41 | PCOLRES crp; |
42 | |
43 | n = (info) ? 0 : 1; |
44 | |
45 | /**********************************************************************/ |
46 | /* Allocate the structures used to refer to the result set. */ |
47 | /**********************************************************************/ |
48 | if (!(qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3, |
49 | buftyp, fldtyp, length, false, true))) |
50 | return NULL; |
51 | |
52 | // Some columns must be renamed before info |
53 | for (i = 0, crp = qrp->Colresp; crp; crp = crp->Next) |
54 | switch (++i) { |
55 | case 5: crp->Name = "Key" ; break; |
56 | case 6: crp->Name = "Extra" ; break; |
57 | } // endswitch i |
58 | |
59 | if (info) |
60 | return qrp; |
61 | |
62 | /**********************************************************************/ |
63 | /* Now get the results into blocks. */ |
64 | /**********************************************************************/ |
65 | // Set column name |
66 | crp = qrp->Colresp; // Column_Name |
67 | crp->Kdata->SetValue("n" , 0); |
68 | |
69 | // Set type, type name, precision |
70 | crp = crp->Next; // Data_Type |
71 | crp->Kdata->SetValue(TYPE_INT, 0); |
72 | |
73 | crp = crp->Next; // Type_Name |
74 | crp->Kdata->SetValue(GetTypeName(TYPE_INT), 0); |
75 | |
76 | crp = crp->Next; // Precision |
77 | crp->Kdata->SetValue(11, 0); |
78 | |
79 | crp = crp->Next; // Key |
80 | crp->Kdata->SetValue("KEY" , 0); |
81 | |
82 | crp = crp->Next; // Extra |
83 | crp->Kdata->SetValue("SPECIAL=ROWID" , 0); |
84 | |
85 | qrp->Nblin = 1; |
86 | |
87 | /**********************************************************************/ |
88 | /* Return the result pointer for use by discovery routines. */ |
89 | /**********************************************************************/ |
90 | return qrp; |
91 | } // end of VirColumns |
92 | |
93 | /* --------------------------- Class VIRDEF --------------------------- */ |
94 | |
95 | /***********************************************************************/ |
96 | /* GetTable: makes a new Table Description Block. */ |
97 | /***********************************************************************/ |
98 | PTDB VIRDEF::GetTable(PGLOBAL g, MODE) |
99 | { |
100 | // Column blocks will be allocated only when needed. |
101 | if (Catfunc == FNC_COL) |
102 | return new(g) TDBVICL(this); |
103 | else |
104 | return new(g) TDBVIR(this); |
105 | |
106 | } // end of GetTable |
107 | |
108 | /* ------------------------ TDBVIR functions ------------------------- */ |
109 | |
110 | /***********************************************************************/ |
111 | /* Implementation of the TDBVIR class. */ |
112 | /***********************************************************************/ |
113 | TDBVIR::TDBVIR(PVIRDEF tdp) : TDBASE(tdp) |
114 | { |
115 | Size = (tdp->GetElemt()) ? tdp->GetElemt() : 1; |
116 | N = -1; |
117 | } // end of TDBVIR constructor |
118 | |
119 | /***********************************************************************/ |
120 | /* Analyze the filter and reset the size limit accordingly. */ |
121 | /* This is possible when a filter contains predicates implying the */ |
122 | /* special column ROWID. Here we just test for when no more good */ |
123 | /* records can be met in the remaining of the table. */ |
124 | /***********************************************************************/ |
125 | int TDBVIR::TestFilter(PFIL filp, bool nop) |
126 | { |
127 | int i, op = filp->GetOpc(), n = 0, type[2] = {0,0}; |
128 | int l1 = 0, l2, limit = Size; |
129 | PXOB arg[2] = {NULL,NULL}; |
130 | |
131 | if (op == OP_GT || op == OP_GE || op == OP_LT || op == OP_LE) { |
132 | for (i = 0; i < 2; i++) { |
133 | arg[i] = filp->Arg(i); |
134 | |
135 | switch (filp->GetArgType(i)) { |
136 | case TYPE_CONST: |
137 | if ((l1 = arg[i]->GetIntValue()) >= 0) |
138 | type[i] = 1; |
139 | |
140 | break; |
141 | case TYPE_COLBLK: |
142 | if (((PCOL)arg[i])->GetTo_Tdb() == this && |
143 | ((PCOL)arg[i])->GetAmType() == TYPE_AM_ROWID) |
144 | type[i] = 2; |
145 | |
146 | break; |
147 | default: |
148 | break; |
149 | } // endswitch ArgType |
150 | |
151 | if (!type[i]) |
152 | break; |
153 | |
154 | n += type[i]; |
155 | } // endfor i |
156 | |
157 | if (n == 3) { |
158 | // If true it will be ok to delete the filter |
159 | BOOL ok = (filp == To_Filter); |
160 | |
161 | if (type[0] == 1) |
162 | // Make it always a Column-op-Value |
163 | switch (op) { |
164 | case OP_GT: op = OP_LT; break; |
165 | case OP_GE: op = OP_LE; break; |
166 | case OP_LT: op = OP_GT; break; |
167 | case OP_LE: op = OP_GE; break; |
168 | } // endswitch op |
169 | |
170 | if (!nop) switch (op) { |
171 | case OP_LT: l1--; |
172 | case OP_LE: limit = l1; break; |
173 | default: ok = false; |
174 | } // endswitch op |
175 | |
176 | else switch (op) { |
177 | case OP_GE: l1--; |
178 | case OP_GT: limit = l1; break; |
179 | default: ok = false; |
180 | } // endswitch op |
181 | |
182 | limit = MY_MIN(MY_MAX(0, limit), Size); |
183 | |
184 | // Just one where clause such as Rowid < limit; |
185 | if (ok) |
186 | To_Filter = NULL; |
187 | |
188 | } else |
189 | limit = Size; |
190 | |
191 | } else if ((op == OP_AND && !nop) || (op == OP_OR && nop)) { |
192 | l1 = TestFilter((PFIL)filp->Arg(0), nop); |
193 | l2 = TestFilter((PFIL)filp->Arg(1), nop); |
194 | limit = MY_MIN(l1, l2); |
195 | } else if (op == OP_NOT) |
196 | limit = TestFilter((PFIL)filp->Arg(0), !nop); |
197 | |
198 | return limit; |
199 | } // end of TestFilter |
200 | |
201 | /***********************************************************************/ |
202 | /* Allocate source column description block. */ |
203 | /***********************************************************************/ |
204 | PCOL TDBVIR::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) |
205 | { |
206 | PCOL colp = NULL; |
207 | |
208 | if (cdp->IsVirtual()) { |
209 | colp = new(g) VIRCOL(cdp, this, cprec, n); |
210 | } else strcpy(g->Message, |
211 | "Virtual tables accept only special or virtual columns" ); |
212 | |
213 | return colp; |
214 | } // end of MakeCol |
215 | |
216 | /***********************************************************************/ |
217 | /* VIR Access Method opening routine. */ |
218 | /***********************************************************************/ |
219 | bool TDBVIR::OpenDB(PGLOBAL g) |
220 | { |
221 | if (Use == USE_OPEN) { |
222 | // Table already open |
223 | N = -1; |
224 | return false; |
225 | } // endif use |
226 | |
227 | if (Mode != MODE_READ) { |
228 | strcpy(g->Message, "Virtual tables are read only" ); |
229 | return true; |
230 | } // endif Mode |
231 | |
232 | /*********************************************************************/ |
233 | /* Analyze the filter and refine Size accordingly. */ |
234 | /*********************************************************************/ |
235 | if (To_Filter) |
236 | Size = TestFilter(To_Filter, false); |
237 | |
238 | return false; |
239 | } // end of OpenDB |
240 | |
241 | /***********************************************************************/ |
242 | /* Data Base read routine for the VIR access method. */ |
243 | /***********************************************************************/ |
244 | int TDBVIR::ReadDB(PGLOBAL) |
245 | { |
246 | return (++N >= Size) ? RC_EF : RC_OK; |
247 | } // end of ReadDB |
248 | |
249 | /***********************************************************************/ |
250 | /* WriteDB: Data Base write routine for the VIR access methods. */ |
251 | /***********************************************************************/ |
252 | int TDBVIR::WriteDB(PGLOBAL g) |
253 | { |
254 | sprintf(g->Message, MSG(VIR_READ_ONLY), To_Def->GetType()); |
255 | return RC_FX; |
256 | } // end of WriteDB |
257 | |
258 | /***********************************************************************/ |
259 | /* Data Base delete line routine for the VIR access methods. */ |
260 | /***********************************************************************/ |
261 | int TDBVIR::DeleteDB(PGLOBAL g, int) |
262 | { |
263 | sprintf(g->Message, MSG(VIR_NO_DELETE), To_Def->GetType()); |
264 | return RC_FX; |
265 | } // end of DeleteDB |
266 | |
267 | /* ---------------------------- VIRCOL ------------------------------- */ |
268 | |
269 | /***********************************************************************/ |
270 | /* VIRCOL public constructor. */ |
271 | /***********************************************************************/ |
272 | VIRCOL::VIRCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ) |
273 | : COLBLK(cdp, tdbp, i) |
274 | { |
275 | if (cprec) { |
276 | Next = cprec->GetNext(); |
277 | cprec->SetNext(this); |
278 | } else { |
279 | Next = tdbp->GetColumns(); |
280 | tdbp->SetColumns(this); |
281 | } // endif cprec |
282 | |
283 | } // end of VIRCOL constructor |
284 | |
285 | /***********************************************************************/ |
286 | /* ReadColumn: */ |
287 | /***********************************************************************/ |
288 | void VIRCOL::ReadColumn(PGLOBAL g) |
289 | { |
290 | // This should never be called |
291 | sprintf(g->Message, "ReadColumn: Column %s is not virtual" , Name); |
292 | throw (int)TYPE_COLBLK; |
293 | } // end of ReadColumn |
294 | |
295 | /* ---------------------------TDBVICL class -------------------------- */ |
296 | |
297 | /***********************************************************************/ |
298 | /* GetResult: Get the list the VIRTUAL table columns. */ |
299 | /***********************************************************************/ |
300 | PQRYRES TDBVICL::GetResult(PGLOBAL g) |
301 | { |
302 | return VirColumns(g, false); |
303 | } // end of GetResult |
304 | |
305 | /* ------------------------- End of Virtual -------------------------- */ |
306 | |