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(__WIN__)
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/***********************************************************************/
62XCLDEF::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/***********************************************************************/
72bool 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/***********************************************************************/
86PTDB 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/***********************************************************************/
100TDBXCL::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/***********************************************************************/
115PCOL 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/***********************************************************************/
131int 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/***********************************************************************/
147int TDBXCL::RowNumber(PGLOBAL, bool b)
148 {
149 return (b) ? M : N;
150 } // end of RowNumber
151
152/***********************************************************************/
153/* XCL Access Method opening routine. */
154/***********************************************************************/
155bool 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/***********************************************************************/
199int 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/***********************************************************************/
235XCLCOL::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/***********************************************************************/
249bool 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/***********************************************************************/
263void 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