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