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