1 /************* TabXcl CPP Declares Source Code File (.CPP) *************/
2 /*  Name: TABXCL.CPP   Version 1.0                                     */
3 /*                                                                     */
4 /*  (C) Copyright to the author Olivier BERTRAND          2013-2017    */
5 /*                                                                     */
6 /*  XCOL: Table having one column containing several values            */
7 /*  comma separated. When creating the table, the name of the X        */
8 /*  column is given by the Name option.       					               */
9 /*  This first version has one limitation:                             */
10 /*  - The X column has the same length than in the physical file.      */
11 /*  This tables produces as many rows for a physical row than the      */
12 /*  number of items in the X column (eventually 0).                    */
13 /***********************************************************************/
14 
15 /***********************************************************************/
16 /*  Include relevant section of system dependant header files.         */
17 /***********************************************************************/
18 #include "my_global.h"
19 #include "table.h"       // MySQL table definitions
20 #if defined(_WIN32)
21 #include <stdlib.h>
22 #include <stdio.h>
23 #if defined(__BORLANDC__)
24 #define __MFC_COMPAT__                   // To define min/max as macro
25 #endif
26 //#include <windows.h>
27 #else
28 #if defined(UNIX)
29 #include <fnmatch.h>
30 #include <errno.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include "osutil.h"
35 #else
36 //#include <io.h>
37 #endif
38 //#include <fcntl.h>
39 #endif
40 
41 /***********************************************************************/
42 /*  Include application header files:                                  */
43 /***********************************************************************/
44 #include "global.h"
45 #include "plgdbsem.h"
46 #include "plgcnx.h"                       // For DB types
47 #include "resource.h"
48 #include "xtable.h"
49 #include "tabext.h"
50 #include "filamtxt.h"
51 #include "tabdos.h"
52 #include "tabcol.h"
53 #include "tabxcl.h"
54 #include "tabmysql.h"
55 #include "ha_connect.h"
56 
57 /* -------------- Implementation of the XCOL classes	---------------- */
58 
59 /***********************************************************************/
60 /*  XCLDEF constructor.                                                */
61 /***********************************************************************/
XCLDEF(void)62 XCLDEF::XCLDEF(void)
63   {
64   Xcol = NULL;
65   Sep = ',';
66   Mult = 10;
67 } // end of XCLDEF constructor
68 
69 /***********************************************************************/
70 /*  DefineAM: define specific AM block values from XCOL table.         */
71 /***********************************************************************/
DefineAM(PGLOBAL g,LPCSTR am,int poff)72 bool XCLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
73   {
74   char buf[8];
75 
76   Xcol = GetStringCatInfo(g, "Colname", "");
77   GetCharCatInfo("Separator", ",", buf, sizeof(buf));
78   Sep = (strlen(buf) == 2 && buf[0] == '\\' && buf[1] == 't') ? '\t' : *buf;
79   Mult = GetIntCatInfo("Mult", 10);
80   return PRXDEF::DefineAM(g, am, poff);
81   } // end of DefineAM
82 
83 /***********************************************************************/
84 /*  GetTable: makes a new TDB of the proper type.                      */
85 /***********************************************************************/
GetTable(PGLOBAL g,MODE)86 PTDB XCLDEF::GetTable(PGLOBAL g, MODE)
87   {
88   if (Catfunc == FNC_COL)
89     return new(g) TDBTBC(this);
90   else
91     return new(g) TDBXCL(this);
92 
93   } // end of GetTable
94 
95 /* ------------------------------------------------------------------- */
96 
97 /***********************************************************************/
98 /*  Implementation of the TDBXCL class.                                */
99 /***********************************************************************/
TDBXCL(PXCLDEF tdp)100 TDBXCL::TDBXCL(PXCLDEF tdp) : TDBPRX(tdp)
101   {
102 	Xcolumn = tdp->Xcol;						// CSV column name
103 	Xcolp = NULL;										// To the XCLCOL column
104 	Mult = tdp->Mult;								// Multiplication factor
105 	N = 0;													// The current table index
106 	M = 0;                          // The occurence rank
107 	RowFlag = 0;    								// 0: Ok, 1: Same, 2: Skip
108 	New = TRUE;						          // TRUE for new line
109 	Sep = tdp->Sep;                 // The Xcol separator
110   } // end of TDBXCL constructor
111 
112 /***********************************************************************/
113 /*  Allocate XCL column description block.                             */
114 /***********************************************************************/
MakeCol(PGLOBAL g,PCOLDEF cdp,PCOL cprec,int n)115 PCOL TDBXCL::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
116   {
117   PCOL colp;
118 
119   if (!stricmp(cdp->GetName(), Xcolumn)) {
120 		Xcolp = new(g) XCLCOL(cdp, this, cprec, n);
121     colp = Xcolp;
122   } else
123     colp = new(g) PRXCOL(cdp, this, cprec, n);
124 
125   return colp;
126   } // end of MakeCol
127 
128 /***********************************************************************/
129 /*  XCL GetMaxSize: returns the maximum number of rows in the table.   */
130 /***********************************************************************/
GetMaxSize(PGLOBAL g)131 int TDBXCL::GetMaxSize(PGLOBAL g)
132   {
133   if (MaxSize < 0) {
134     if (InitTable(g))
135       return 0;
136 
137   	MaxSize = Mult * Tdbp->GetMaxSize(g);
138     } // endif MaxSize
139 
140   return MaxSize;
141   } // end of GetMaxSize
142 
143 /***********************************************************************/
144 /*  For this table type, ROWID is the (virtual) row number,            */
145 /*  while ROWNUM is be the occurence rank in the multiple column.      */
146 /***********************************************************************/
RowNumber(PGLOBAL,bool b)147 int TDBXCL::RowNumber(PGLOBAL, bool b)
148 	{
149 	return (b) ? M : N;
150 	} // end of RowNumber
151 
152 /***********************************************************************/
153 /*  XCL Access Method opening routine.                                 */
154 /***********************************************************************/
OpenDB(PGLOBAL g)155 bool TDBXCL::OpenDB(PGLOBAL g)
156   {
157   if (Use == USE_OPEN) {
158     /*******************************************************************/
159     /*  Table already open, just replace it at its beginning.          */
160     /*******************************************************************/
161 		M = N = 0;
162 		RowFlag = 0;
163     New = TRUE;
164 		return Tdbp->OpenDB(g);
165     } // endif use
166 
167   if (Mode != MODE_READ) {
168     /*******************************************************************/
169     /* Currently XCOL tables cannot be modified.                       */
170     /*******************************************************************/
171     strcpy(g->Message, "XCOL tables are read only");
172     return TRUE;
173     } // endif Mode
174 
175   if (InitTable(g))
176     return TRUE;
177 
178   /*********************************************************************/
179   /*  Check and initialize the subtable columns.                       */
180   /*********************************************************************/
181   for (PCOL cp = Columns; cp; cp = cp->GetNext())
182     if (!cp->IsSpecial())
183       if (((PPRXCOL)cp)->Init(g, NULL))
184         return TRUE;
185 
186   /*********************************************************************/
187   /*  Physically open the object table.                                */
188   /*********************************************************************/
189 	if (Tdbp->OpenDB(g))
190 		return TRUE;
191 
192   Use = USE_OPEN;
193 	return FALSE;
194   } // end of OpenDB
195 
196 /***********************************************************************/
197 /*  Data Base read routine for XCL access method.                      */
198 /***********************************************************************/
ReadDB(PGLOBAL g)199 int TDBXCL::ReadDB(PGLOBAL g)
200   {
201 	int rc = RC_OK;
202 
203   /*********************************************************************/
204   /*  Now start the multi reading process.                             */
205   /*********************************************************************/
206 	do {
207 		if (RowFlag != 1) {
208 			if ((rc = Tdbp->ReadDB(g)) != RC_OK)
209 				break;
210 
211       New = TRUE;
212 			M = 1;
213     } else {
214       New = FALSE;
215 			M++;
216     } // endif RowFlag
217 
218     if (Xcolp) {
219   		RowFlag = 0;
220 	  	Xcolp->ReadColumn(g);
221       } // endif Xcolp
222 
223   	N++;
224 		} while (RowFlag == 2);
225 
226 	return rc;
227   } // end of ReadDB
228 
229 
230 // ------------------------ XCLCOL functions ----------------------------
231 
232 /***********************************************************************/
233 /*  XCLCOL public constructor.                                         */
234 /***********************************************************************/
XCLCOL(PCOLDEF cdp,PTDB tdbp,PCOL cprec,int i)235 XCLCOL::XCLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i)
236 			: PRXCOL(cdp, tdbp, cprec, i, "XCL")
237   {
238   // Set additional XXL access method information for column.
239   Cbuf = NULL;                // Will be allocated later
240 	Cp = NULL;						      // Pointer to current position in Cbuf
241 	Sep = ((PTDBXCL)tdbp)->Sep;
242 	AddStatus(BUF_READ);	      // Only evaluated from TDBXCL::ReadDB
243   } // end of XCLCOL constructor
244 
245 /***********************************************************************/
246 /*  XCLCOL initialization routine.                                     */
247 /*  Allocate Cbuf that will contain the Colp value.                    */
248 /***********************************************************************/
Init(PGLOBAL g,PTDB tp)249 bool XCLCOL::Init(PGLOBAL g, PTDB tp)
250   {
251   if (PRXCOL::Init(g, tp))
252     return true;
253 
254   Cbuf = (char*)PlugSubAlloc(g, NULL, Colp->GetLength() + 1);
255   return false;
256   } // end of Init
257 
258 /***********************************************************************/
259 /*  What this routine does is to get the comma-separated string        */
260 /*  from the source table column, extract the single values and        */
261 /*  set the flag for the table ReadDB function.                        */
262 /***********************************************************************/
ReadColumn(PGLOBAL g)263 void XCLCOL::ReadColumn(PGLOBAL g)
264   {
265 	if (((PTDBXCL)To_Tdb)->New) {
266     Colp->Reset();           // Moved here in case of failed filtering
267 		Colp->Eval(g);
268 		strncpy(Cbuf, To_Val->GetCharValue(), Colp->GetLength());
269     Cbuf[Colp->GetLength()] = 0;
270 		Cp = Cbuf;
271 		} // endif New
272 
273 	if (*Cp) {
274 		PSZ p;
275 
276     // Trim left
277     for (p = Cp; *p == ' '; p++) ;
278 
279 		if ((Cp = strchr(Cp, Sep)))
280 			// Separator is found
281 			*Cp++ = '\0';
282 
283 		Value->SetValue_psz(p);
284   } else if (Nullable) {
285     Value->Reset();
286     Value->SetNull(true);
287   } else {
288     // Skip that row
289 		((PTDBXCL)To_Tdb)->RowFlag = 2;
290     Colp->Reset();
291   } // endif Cp
292 
293 	if (Cp && *Cp)
294 		// More to come from the same row
295 		((PTDBXCL)To_Tdb)->RowFlag = 1;
296 
297   } // end of ReadColumn
298