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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | /***********************************************************************/ |
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 | |