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 /***********************************************************************/
VirColumns(PGLOBAL g,bool info)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 /***********************************************************************/
GetTable(PGLOBAL g,MODE)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 /***********************************************************************/
TDBVIR(PVIRDEF tdp)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 /***********************************************************************/
TestFilter(PFIL filp,bool nop)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--; /* fall through */
172 case OP_LE: limit = l1; break;
173 default: ok = false;
174 } // endswitch op
175
176 else switch (op) {
177 case OP_GE: l1--; /* fall through */
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 /***********************************************************************/
MakeCol(PGLOBAL g,PCOLDEF cdp,PCOL cprec,int n)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 /***********************************************************************/
OpenDB(PGLOBAL g)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 /***********************************************************************/
ReadDB(PGLOBAL)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 /***********************************************************************/
WriteDB(PGLOBAL g)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 /***********************************************************************/
DeleteDB(PGLOBAL g,int)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 /***********************************************************************/
VIRCOL(PCOLDEF cdp,PTDB tdbp,PCOL cprec,int i,PCSZ)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 /***********************************************************************/
ReadColumn(PGLOBAL g)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 /***********************************************************************/
GetResult(PGLOBAL g)300 PQRYRES TDBVICL::GetResult(PGLOBAL g)
301 {
302 return VirColumns(g, false);
303 } // end of GetResult
304
305 /* ------------------------- End of Virtual -------------------------- */
306