| 1 | /************* TabFix C++ Program Source Code File (.CPP) **************/ |
| 2 | /* PROGRAM NAME: TABFIX */ |
| 3 | /* ------------- */ |
| 4 | /* Version 4.9.2 */ |
| 5 | /* */ |
| 6 | /* COPYRIGHT: */ |
| 7 | /* ---------- */ |
| 8 | /* (C) Copyright to the author Olivier BERTRAND 1998-2017 */ |
| 9 | /* */ |
| 10 | /* WHAT THIS PROGRAM DOES: */ |
| 11 | /* ----------------------- */ |
| 12 | /* This program are the TDBFIX class DB routines. */ |
| 13 | /* */ |
| 14 | /***********************************************************************/ |
| 15 | |
| 16 | /***********************************************************************/ |
| 17 | /* Include relevant section of system dependant header files. */ |
| 18 | /***********************************************************************/ |
| 19 | #include "my_global.h" |
| 20 | #if defined(__WIN__) |
| 21 | #include <io.h> |
| 22 | #include <fcntl.h> |
| 23 | #include <errno.h> |
| 24 | #if defined(__BORLANDC__) |
| 25 | #define __MFC_COMPAT__ // To define min/max as macro |
| 26 | #endif // __BORLANDC__ |
| 27 | //#include <windows.h> |
| 28 | #else // !__WIN__ |
| 29 | #if defined(UNIX) |
| 30 | #include <sys/types.h> |
| 31 | #include <sys/stat.h> |
| 32 | #include <unistd.h> |
| 33 | #include <errno.h> |
| 34 | #else // !UNIX |
| 35 | #include <io.h> |
| 36 | #endif // !UNIX |
| 37 | #include <fcntl.h> |
| 38 | #endif // !__WIN__ |
| 39 | |
| 40 | /***********************************************************************/ |
| 41 | /* Include application header files: */ |
| 42 | /***********************************************************************/ |
| 43 | #include "global.h" // global declares |
| 44 | #include "plgdbsem.h" // DB application declares |
| 45 | #include "filamfix.h" |
| 46 | #include "filamdbf.h" |
| 47 | #include "tabfix.h" // TDBFIX, FIXCOL classes declares |
| 48 | #include "array.h" |
| 49 | #include "blkfil.h" |
| 50 | |
| 51 | /***********************************************************************/ |
| 52 | /* DB static variables. */ |
| 53 | /***********************************************************************/ |
| 54 | extern int num_read, num_there, num_eq[2]; // Statistics |
| 55 | static const longlong M2G = 0x80000000; |
| 56 | static const longlong M4G = (longlong)2 * M2G; |
| 57 | char BINCOL::Endian = 'H'; |
| 58 | |
| 59 | /***********************************************************************/ |
| 60 | /* External function. */ |
| 61 | /***********************************************************************/ |
| 62 | USETEMP UseTemp(void); |
| 63 | |
| 64 | /* ------------------------------------------------------------------- */ |
| 65 | |
| 66 | /***********************************************************************/ |
| 67 | /* Implementation of the TDBFIX class. */ |
| 68 | /***********************************************************************/ |
| 69 | TDBFIX::TDBFIX(PDOSDEF tdp, PTXF txfp) : TDBDOS(tdp, txfp) |
| 70 | { |
| 71 | Teds = tdp->Teds; // For BIN tables |
| 72 | } // end of TDBFIX standard constructor |
| 73 | |
| 74 | TDBFIX::TDBFIX(PGLOBAL g, PTDBFIX tdbp) : TDBDOS(g, tdbp) |
| 75 | { |
| 76 | Teds = tdbp->Teds; |
| 77 | } // end of TDBFIX copy constructor |
| 78 | |
| 79 | // Method |
| 80 | PTDB TDBFIX::Clone(PTABS t) |
| 81 | { |
| 82 | PTDB tp; |
| 83 | PGLOBAL g = t->G; |
| 84 | |
| 85 | tp = new(g) TDBFIX(g, this); |
| 86 | |
| 87 | if (Ftype < 2) { |
| 88 | // File is text |
| 89 | PDOSCOL cp1, cp2; |
| 90 | |
| 91 | for (cp1 = (PDOSCOL)Columns; cp1; cp1 = (PDOSCOL)cp1->GetNext()) { |
| 92 | cp2 = new(g) DOSCOL(cp1, tp); // Make a copy |
| 93 | NewPointer(t, cp1, cp2); |
| 94 | } // endfor cp1 |
| 95 | |
| 96 | } else { |
| 97 | // File is binary |
| 98 | PBINCOL cp1, cp2; |
| 99 | |
| 100 | for (cp1 = (PBINCOL)Columns; cp1; cp1 = (PBINCOL)cp1->GetNext()) { |
| 101 | cp2 = new(g) BINCOL(cp1, tp); // Make a copy |
| 102 | NewPointer(t, cp1, cp2); |
| 103 | } // endfor cp1 |
| 104 | |
| 105 | } // endif Ftype |
| 106 | |
| 107 | return tp; |
| 108 | } // end of Clone |
| 109 | |
| 110 | /***********************************************************************/ |
| 111 | /* Reset read/write position values. */ |
| 112 | /***********************************************************************/ |
| 113 | void TDBFIX::ResetDB(void) |
| 114 | { |
| 115 | TDBDOS::ResetDB(); |
| 116 | } // end of ResetDB |
| 117 | |
| 118 | /***********************************************************************/ |
| 119 | /* Allocate FIX (DOS) or BIN column description block. */ |
| 120 | /***********************************************************************/ |
| 121 | PCOL TDBFIX::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n) |
| 122 | { |
| 123 | if (Ftype == RECFM_BIN) |
| 124 | return new(g) BINCOL(g, cdp, this, cprec, n); |
| 125 | else |
| 126 | return new(g) DOSCOL(g, cdp, this, cprec, n); |
| 127 | |
| 128 | } // end of MakeCol |
| 129 | |
| 130 | /***********************************************************************/ |
| 131 | /* Remake the indexes after the table was modified. */ |
| 132 | /***********************************************************************/ |
| 133 | int TDBFIX::ResetTableOpt(PGLOBAL g, bool dop, bool dox) |
| 134 | { |
| 135 | int prc, rc = RC_OK; |
| 136 | |
| 137 | To_Filter = NULL; // Disable filtering |
| 138 | //To_BlkIdx = NULL; // and block filtering |
| 139 | To_BlkFil = NULL; // and index filtering |
| 140 | Cardinality(g); // If called by create |
| 141 | RestoreNrec(); // May have been modified |
| 142 | MaxSize = -1; // Size must be recalculated |
| 143 | Cardinal = -1; // as well as Cardinality |
| 144 | |
| 145 | // After the table was modified the indexes |
| 146 | // are invalid and we should mark them as such... |
| 147 | rc = ((PDOSDEF)To_Def)->InvalidateIndex(g); |
| 148 | |
| 149 | if (dop) { |
| 150 | Columns = NULL; // Not used anymore |
| 151 | Txfp->Reset(); |
| 152 | // OldBlk = CurBlk = -1; |
| 153 | // ReadBlks = CurNum = Rbuf = Modif = 0; |
| 154 | Use = USE_READY; // So the table can be reopened |
| 155 | Mode = MODE_ANY; // Just to be clean |
| 156 | rc = MakeBlockValues(g); // Redo optimization |
| 157 | } // endif dop |
| 158 | |
| 159 | if (dox && (rc == RC_OK || rc == RC_INFO)) { |
| 160 | // Remake eventual indexes |
| 161 | Columns = NULL; // Not used anymore |
| 162 | Txfp->Reset(); // New start |
| 163 | Use = USE_READY; // So the table can be reopened |
| 164 | Mode = MODE_READ; // New mode |
| 165 | prc = rc; |
| 166 | |
| 167 | if (PlgGetUser(g)->Check & CHK_OPT) |
| 168 | // We must remake indexes. |
| 169 | rc = MakeIndex(g, NULL, FALSE); |
| 170 | |
| 171 | rc = (rc == RC_INFO) ? prc : rc; |
| 172 | } // endif dox |
| 173 | |
| 174 | return rc; |
| 175 | } // end of ResetTableOpt |
| 176 | |
| 177 | /***********************************************************************/ |
| 178 | /* Reset the Nrec and BlkSize values that can have been modified. */ |
| 179 | /***********************************************************************/ |
| 180 | void TDBFIX::RestoreNrec(void) |
| 181 | { |
| 182 | if (!Txfp->Padded) { |
| 183 | Txfp->Nrec = (To_Def && To_Def->GetElemt()) ? To_Def->GetElemt() |
| 184 | : DOS_BUFF_LEN; |
| 185 | Txfp->Blksize = Txfp->Nrec * Txfp->Lrecl; |
| 186 | |
| 187 | if (Cardinal >= 0) |
| 188 | Txfp->Block = (Cardinal > 0) |
| 189 | ? (Cardinal + Txfp->Nrec - 1) / Txfp->Nrec : 0; |
| 190 | |
| 191 | } // endif Padded |
| 192 | |
| 193 | } // end of RestoreNrec |
| 194 | |
| 195 | /***********************************************************************/ |
| 196 | /* FIX Cardinality: returns table cardinality in number of rows. */ |
| 197 | /* This function can be called with a null argument to test the */ |
| 198 | /* availability of Cardinality implementation (1 yes, 0 no). */ |
| 199 | /***********************************************************************/ |
| 200 | int TDBFIX::Cardinality(PGLOBAL g) |
| 201 | { |
| 202 | if (!g) |
| 203 | return Txfp->Cardinality(g); |
| 204 | |
| 205 | if (Cardinal < 0) |
| 206 | Cardinal = Txfp->Cardinality(g); |
| 207 | |
| 208 | return Cardinal; |
| 209 | } // end of Cardinality |
| 210 | |
| 211 | /***********************************************************************/ |
| 212 | /* FIX GetMaxSize: returns file size in number of lines. */ |
| 213 | /***********************************************************************/ |
| 214 | int TDBFIX::GetMaxSize(PGLOBAL g) |
| 215 | { |
| 216 | if (MaxSize < 0) { |
| 217 | MaxSize = Cardinality(g); |
| 218 | |
| 219 | if (MaxSize > 0 && (To_BlkFil = InitBlockFilter(g, To_Filter)) |
| 220 | && !To_BlkFil->Correlated()) { |
| 221 | // Use BlockTest to reduce the estimated size |
| 222 | MaxSize = Txfp->MaxBlkSize(g, MaxSize); |
| 223 | ResetBlockFilter(g); |
| 224 | } // endif To_BlkFil |
| 225 | |
| 226 | } // endif MaxSize |
| 227 | |
| 228 | return MaxSize; |
| 229 | } // end of GetMaxSize |
| 230 | |
| 231 | /***********************************************************************/ |
| 232 | /* FIX ResetSize: Must reset Headlen for DBF tables only. */ |
| 233 | /***********************************************************************/ |
| 234 | void TDBFIX::ResetSize(void) |
| 235 | { |
| 236 | if (Txfp->GetAmType() == TYPE_AM_DBF) |
| 237 | Txfp->Headlen = 0; |
| 238 | |
| 239 | MaxSize = Cardinal = -1; |
| 240 | } // end of ResetSize |
| 241 | |
| 242 | /***********************************************************************/ |
| 243 | /* FIX GetProgMax: get the max value for progress information. */ |
| 244 | /***********************************************************************/ |
| 245 | int TDBFIX::GetProgMax(PGLOBAL g) |
| 246 | { |
| 247 | return Cardinality(g); |
| 248 | } // end of GetProgMax |
| 249 | |
| 250 | /***********************************************************************/ |
| 251 | /* RowNumber: return the ordinal number of the current row. */ |
| 252 | /***********************************************************************/ |
| 253 | int TDBFIX::RowNumber(PGLOBAL g, bool b) |
| 254 | { |
| 255 | if (Txfp->GetAmType() == TYPE_AM_DBF) { |
| 256 | if (!b && To_Kindex) { |
| 257 | /*****************************************************************/ |
| 258 | /* Don't know how to retrieve Rows from DBF file address */ |
| 259 | /* because of eventual deleted lines still in the file. */ |
| 260 | /*****************************************************************/ |
| 261 | sprintf(g->Message, MSG(NO_ROWID_FOR_AM), |
| 262 | GetAmName(g, Txfp->GetAmType())); |
| 263 | return 0; |
| 264 | } // endif To_Kindex |
| 265 | |
| 266 | if (!b) |
| 267 | return Txfp->GetRows(); |
| 268 | |
| 269 | } // endif DBF |
| 270 | |
| 271 | return Txfp->GetRowID(); |
| 272 | } // end of RowNumber |
| 273 | |
| 274 | /***********************************************************************/ |
| 275 | /* FIX tables don't use temporary files except if specified as do it. */ |
| 276 | /***********************************************************************/ |
| 277 | bool TDBFIX::IsUsingTemp(PGLOBAL) |
| 278 | { |
| 279 | // Not ready yet to handle using a temporary file with mapping |
| 280 | // or while deleting from DBF files. |
| 281 | return ((UseTemp() == TMP_YES && Txfp->GetAmType() != TYPE_AM_MAP && |
| 282 | !(Mode == MODE_DELETE && Txfp->GetAmType() == TYPE_AM_DBF)) || |
| 283 | UseTemp() == TMP_FORCE || UseTemp() == TMP_TEST); |
| 284 | } // end of IsUsingTemp |
| 285 | |
| 286 | /***********************************************************************/ |
| 287 | /* FIX Access Method opening routine (also used by the BIN a.m.) */ |
| 288 | /* New method now that this routine is called recursively (last table */ |
| 289 | /* first in reverse order): index blocks are immediately linked to */ |
| 290 | /* join block of next table if it exists or else are discarted. */ |
| 291 | /***********************************************************************/ |
| 292 | bool TDBFIX::OpenDB(PGLOBAL g) |
| 293 | { |
| 294 | if (trace(1)) |
| 295 | htrc("FIX OpenDB: tdbp=%p tdb=R%d use=%d key=%p mode=%d Ftype=%d\n" , |
| 296 | this, Tdb_No, Use, To_Key_Col, Mode, Ftype); |
| 297 | |
| 298 | if (Use == USE_OPEN) { |
| 299 | /*******************************************************************/ |
| 300 | /* Table already open, just replace it at its beginning. */ |
| 301 | /*******************************************************************/ |
| 302 | if (To_Kindex) |
| 303 | /*****************************************************************/ |
| 304 | /* Table is to be accessed through a sorted index table. */ |
| 305 | /*****************************************************************/ |
| 306 | To_Kindex->Reset(); |
| 307 | else |
| 308 | Txfp->Rewind(); // see comment in Work.log |
| 309 | |
| 310 | ResetBlockFilter(g); |
| 311 | return false; |
| 312 | } // endif use |
| 313 | |
| 314 | if (Mode == MODE_DELETE && Txfp->GetAmType() == TYPE_AM_MAP && |
| 315 | (!Next || UseTemp() == TMP_FORCE)) { |
| 316 | // Delete all lines or using temp. Not handled in MAP mode |
| 317 | Txfp = new(g) FIXFAM((PDOSDEF)To_Def); |
| 318 | Txfp->SetTdbp(this); |
| 319 | } // endif Mode |
| 320 | |
| 321 | /*********************************************************************/ |
| 322 | /* Call Cardinality to calculate Block in the case of Func queries. */ |
| 323 | /* and also in the case of multiple tables. */ |
| 324 | /*********************************************************************/ |
| 325 | if (Cardinality(g) < 0) |
| 326 | return true; |
| 327 | |
| 328 | /*********************************************************************/ |
| 329 | /* Open according to required logical input/output mode. */ |
| 330 | /* Use conventionnal input/output functions. */ |
| 331 | /* Treat fixed length text files as binary. */ |
| 332 | /*********************************************************************/ |
| 333 | if (Txfp->OpenTableFile(g)) |
| 334 | return true; |
| 335 | |
| 336 | Use = USE_OPEN; // Do it now in case we are recursively called |
| 337 | |
| 338 | /*********************************************************************/ |
| 339 | /* Initialize To_Line at the beginning of the block buffer. */ |
| 340 | /*********************************************************************/ |
| 341 | To_Line = Txfp->GetBuf(); // For WriteDB |
| 342 | |
| 343 | /*********************************************************************/ |
| 344 | /* Allocate the block filter tree if evaluation is possible. */ |
| 345 | /*********************************************************************/ |
| 346 | To_BlkFil = InitBlockFilter(g, To_Filter); |
| 347 | |
| 348 | if (trace(1)) |
| 349 | htrc("OpenFix: R%hd mode=%d BlkFil=%p\n" , Tdb_No, Mode, To_BlkFil); |
| 350 | |
| 351 | /*********************************************************************/ |
| 352 | /* Reset buffer access according to indexing and to mode. */ |
| 353 | /*********************************************************************/ |
| 354 | Txfp->ResetBuffer(g); |
| 355 | |
| 356 | /*********************************************************************/ |
| 357 | /* Reset statistics values. */ |
| 358 | /*********************************************************************/ |
| 359 | num_read = num_there = num_eq[0] = num_eq[1] = 0; |
| 360 | return false; |
| 361 | } // end of OpenDB |
| 362 | |
| 363 | /***********************************************************************/ |
| 364 | /* WriteDB: Data Base write routine for FIX access method. */ |
| 365 | /***********************************************************************/ |
| 366 | int TDBFIX::WriteDB(PGLOBAL g) |
| 367 | { |
| 368 | return Txfp->WriteBuffer(g); |
| 369 | } // end of WriteDB |
| 370 | |
| 371 | // ------------------------ BINCOL functions ---------------------------- |
| 372 | |
| 373 | /***********************************************************************/ |
| 374 | /* BINCOL public constructor. */ |
| 375 | /***********************************************************************/ |
| 376 | BINCOL::BINCOL(PGLOBAL g, PCOLDEF cdp, PTDB tp, PCOL cp, int i, PCSZ am) |
| 377 | : DOSCOL(g, cdp, tp, cp, i, am) |
| 378 | { |
| 379 | char c, *fmt = cdp->GetFmt(); |
| 380 | |
| 381 | Fmt = GetDomain() ? 'C' : 'X'; |
| 382 | Buff = NULL; |
| 383 | Eds = ((PTDBFIX)tp)->Teds; |
| 384 | N = 0; |
| 385 | M = GetTypeSize(Buf_Type, sizeof(longlong)); |
| 386 | Lim = 0; |
| 387 | |
| 388 | if (fmt) { |
| 389 | for (N = 0, i = 0; fmt[i]; i++) { |
| 390 | c = toupper(fmt[i]); |
| 391 | |
| 392 | if (isdigit(c)) |
| 393 | N = (N * 10 + (c - '0')); |
| 394 | else if (c == 'L' || c == 'B' || c == 'H') |
| 395 | Eds = c; |
| 396 | else |
| 397 | Fmt = c; |
| 398 | |
| 399 | } // endfor i |
| 400 | |
| 401 | // M is the size of the source value |
| 402 | switch (Fmt) { |
| 403 | case 'C': Eds = 0; break; |
| 404 | case 'X': break; |
| 405 | case 'S': M = sizeof(short); break; |
| 406 | case 'T': M = sizeof(char); break; |
| 407 | case 'I': M = sizeof(int); break; |
| 408 | case 'G': M = sizeof(longlong); break; |
| 409 | case 'R': // Real |
| 410 | case 'F': M = sizeof(float); break; |
| 411 | case 'D': M = sizeof(double); break; |
| 412 | default: |
| 413 | sprintf(g->Message, MSG(BAD_BIN_FMT), Fmt, Name); |
| 414 | throw 11; |
| 415 | } // endswitch Fmt |
| 416 | |
| 417 | } else if (IsTypeChar(Buf_Type)) |
| 418 | Eds = 0; |
| 419 | |
| 420 | if (Eds) { |
| 421 | // This is a byte order specification |
| 422 | if (!N) |
| 423 | N = M; |
| 424 | |
| 425 | if (Eds != 'L' && Eds != 'B') |
| 426 | Eds = Endian; |
| 427 | |
| 428 | if (N != M || Eds != Endian || IsTypeChar(Buf_Type)) { |
| 429 | Buff = (char*)PlugSubAlloc(g, NULL, M); |
| 430 | memset(Buff, 0, M); |
| 431 | Lim = MY_MIN(N, M); |
| 432 | } else |
| 433 | Eds = 0; // New format is a no op |
| 434 | |
| 435 | } // endif Eds |
| 436 | |
| 437 | } // end of BINCOL constructor |
| 438 | |
| 439 | /***********************************************************************/ |
| 440 | /* BINCOL constructor used for copying columns. */ |
| 441 | /* tdbp is the pointer to the new table descriptor. */ |
| 442 | /***********************************************************************/ |
| 443 | BINCOL::BINCOL(BINCOL *col1, PTDB tdbp) : DOSCOL(col1, tdbp) |
| 444 | { |
| 445 | Eds = col1->Eds; |
| 446 | Fmt = col1->Fmt; |
| 447 | N = col1->N; |
| 448 | M = col1->M; |
| 449 | Lim = col1->Lim; |
| 450 | } // end of BINCOL copy constructor |
| 451 | |
| 452 | /***********************************************************************/ |
| 453 | /* Set Endian according to the host setting. */ |
| 454 | /***********************************************************************/ |
| 455 | void BINCOL::SetEndian(void) |
| 456 | { |
| 457 | union { |
| 458 | short S; |
| 459 | char C[sizeof(short)]; |
| 460 | }; |
| 461 | |
| 462 | S = 1; |
| 463 | Endian = (C[0] == 1) ? 'L' : 'B'; |
| 464 | } // end of SetEndian |
| 465 | |
| 466 | /***********************************************************************/ |
| 467 | /* ReadColumn: what this routine does is to access the last line */ |
| 468 | /* read from the corresponding table and extract from it the field */ |
| 469 | /* corresponding to this column. */ |
| 470 | /***********************************************************************/ |
| 471 | void BINCOL::ReadColumn(PGLOBAL g) |
| 472 | { |
| 473 | char *p = NULL; |
| 474 | int rc; |
| 475 | PTDBFIX tdbp = (PTDBFIX)To_Tdb; |
| 476 | |
| 477 | if (trace(2)) |
| 478 | htrc("BIN ReadColumn: col %s R%d coluse=%.4X status=%.4X buf_type=%d\n" , |
| 479 | Name, tdbp->GetTdb_No(), ColUse, Status, Buf_Type); |
| 480 | |
| 481 | /*********************************************************************/ |
| 482 | /* If physical reading of the line was deferred, do it now. */ |
| 483 | /*********************************************************************/ |
| 484 | if (!tdbp->IsRead()) |
| 485 | if ((rc = tdbp->ReadBuffer(g)) != RC_OK) { |
| 486 | if (rc == RC_EF) |
| 487 | sprintf(g->Message, MSG(INV_DEF_READ), rc); |
| 488 | |
| 489 | throw 11; |
| 490 | } // endif |
| 491 | |
| 492 | p = tdbp->To_Line + Deplac; |
| 493 | |
| 494 | /*********************************************************************/ |
| 495 | /* Set Value from the line field. */ |
| 496 | /*********************************************************************/ |
| 497 | if (Eds) { |
| 498 | for (int i = 0; i < Lim; i++) |
| 499 | if (Eds == 'B' && Endian == 'L') |
| 500 | Buff[i] = p[N - i - 1]; |
| 501 | else if (Eds == 'L' && Endian == 'B') |
| 502 | Buff[M - i - 1] = p[i]; |
| 503 | else if (Endian == 'B') |
| 504 | Buff[M - i - 1] = p[N - i - 1]; |
| 505 | else |
| 506 | Buff[i] = p[i]; |
| 507 | |
| 508 | p = Buff; |
| 509 | } // endif Eds |
| 510 | |
| 511 | switch (Fmt) { |
| 512 | case 'X': // Standard not converted values |
| 513 | if (Eds && IsTypeChar(Buf_Type)) |
| 514 | Value->SetValueNonAligned<longlong>(p); |
| 515 | else |
| 516 | Value->SetBinValue(p); |
| 517 | |
| 518 | break; |
| 519 | case 'S': // Short integer |
| 520 | Value->SetValueNonAligned<short>(p); |
| 521 | break; |
| 522 | case 'T': // Tiny integer |
| 523 | Value->SetValue(*p); |
| 524 | break; |
| 525 | case 'I': // Integer |
| 526 | Value->SetValueNonAligned<int>(p); |
| 527 | break; |
| 528 | case 'G': // Large (great) integer |
| 529 | Value->SetValueNonAligned<longlong>(p); |
| 530 | break; |
| 531 | case 'F': // Float |
| 532 | case 'R': // Real |
| 533 | Value->SetValueNonAligned<float>(p); |
| 534 | break; |
| 535 | case 'D': // Double |
| 536 | Value->SetValueNonAligned<double>(p); |
| 537 | break; |
| 538 | case 'C': // Text |
| 539 | if (Value->SetValue_char(p, Long)) { |
| 540 | sprintf(g->Message, "Out of range value for column %s at row %d" , |
| 541 | Name, tdbp->RowNumber(g)); |
| 542 | PushWarning(g, tdbp); |
| 543 | } // endif SetValue_char |
| 544 | |
| 545 | break; |
| 546 | default: |
| 547 | sprintf(g->Message, MSG(BAD_BIN_FMT), Fmt, Name); |
| 548 | throw 11; |
| 549 | } // endswitch Fmt |
| 550 | |
| 551 | // Set null when applicable |
| 552 | if (Nullable) |
| 553 | Value->SetNull(Value->IsZero()); |
| 554 | |
| 555 | } // end of ReadColumn |
| 556 | |
| 557 | /***********************************************************************/ |
| 558 | /* WriteColumn: what this routine does is to access the last line */ |
| 559 | /* read from the corresponding table, and rewrite the field */ |
| 560 | /* corresponding to this column from the column buffer. */ |
| 561 | /***********************************************************************/ |
| 562 | void BINCOL::WriteColumn(PGLOBAL g) |
| 563 | { |
| 564 | char *p, *s; |
| 565 | longlong n; |
| 566 | PTDBFIX tdbp = (PTDBFIX)To_Tdb; |
| 567 | |
| 568 | if (trace(1)) { |
| 569 | htrc("BIN WriteColumn: col %s R%d coluse=%.4X status=%.4X" , |
| 570 | Name, tdbp->GetTdb_No(), ColUse, Status); |
| 571 | htrc(" Lrecl=%d\n" , tdbp->Lrecl); |
| 572 | htrc("Long=%d deplac=%d coltype=%d ftype=%c\n" , |
| 573 | Long, Deplac, Buf_Type, *Format.Type); |
| 574 | } // endif trace |
| 575 | |
| 576 | /*********************************************************************/ |
| 577 | /* Check whether the new value has to be converted to Buf_Type. */ |
| 578 | /*********************************************************************/ |
| 579 | if (Value != To_Val) |
| 580 | Value->SetValue_pval(To_Val, false); // Convert the updated value |
| 581 | |
| 582 | p = (Eds) ? Buff : tdbp->To_Line + Deplac; |
| 583 | |
| 584 | /*********************************************************************/ |
| 585 | /* Check whether updating is Ok, meaning col value is not too long. */ |
| 586 | /* Updating will be done only during the second pass (Status=true) */ |
| 587 | /* Conversion occurs if the external format Fmt is specified. */ |
| 588 | /*********************************************************************/ |
| 589 | switch (Fmt) { |
| 590 | case 'X': |
| 591 | // Standard not converted values |
| 592 | if (Eds && IsTypeChar(Buf_Type)) { |
| 593 | if (Status) |
| 594 | Value->GetValueNonAligned<longlong>(p, Value->GetBigintValue()); |
| 595 | } else if (Value->GetBinValue(p, Long, Status)) { |
| 596 | sprintf(g->Message, MSG(BIN_F_TOO_LONG), |
| 597 | Name, Value->GetSize(), Long); |
| 598 | throw 31; |
| 599 | } // endif p |
| 600 | |
| 601 | break; |
| 602 | case 'S': // Short integer |
| 603 | n = Value->GetBigintValue(); |
| 604 | |
| 605 | if (n > 32767LL || n < -32768LL) { |
| 606 | sprintf(g->Message, MSG(VALUE_TOO_BIG), n, Name); |
| 607 | throw 31; |
| 608 | } else if (Status) |
| 609 | Value->GetValueNonAligned<short>(p, (short)n); |
| 610 | |
| 611 | break; |
| 612 | case 'T': // Tiny integer |
| 613 | n = Value->GetBigintValue(); |
| 614 | |
| 615 | if (n > 255LL || n < -256LL) { |
| 616 | sprintf(g->Message, MSG(VALUE_TOO_BIG), n, Name); |
| 617 | throw 31; |
| 618 | } else if (Status) |
| 619 | *p = (char)n; |
| 620 | |
| 621 | break; |
| 622 | case 'I': // Integer |
| 623 | n = Value->GetBigintValue(); |
| 624 | |
| 625 | if (n > INT_MAX || n < INT_MIN) { |
| 626 | sprintf(g->Message, MSG(VALUE_TOO_BIG), n, Name); |
| 627 | throw 31; |
| 628 | } else if (Status) |
| 629 | Value->GetValueNonAligned<int>(p, (int)n); |
| 630 | |
| 631 | break; |
| 632 | case 'G': // Large (great) integer |
| 633 | if (Status) |
| 634 | *(longlong *)p = Value->GetBigintValue(); |
| 635 | |
| 636 | break; |
| 637 | case 'F': // Float |
| 638 | case 'R': // Real |
| 639 | if (Status) |
| 640 | Value->GetValueNonAligned<float>(p, (float)Value->GetFloatValue()); |
| 641 | |
| 642 | break; |
| 643 | case 'D': // Double |
| 644 | if (Status) |
| 645 | Value->GetValueNonAligned<double>(p, Value->GetFloatValue()); |
| 646 | |
| 647 | break; |
| 648 | case 'C': // Characters |
| 649 | if ((n = (signed)strlen(Value->GetCharString(Buf))) > Long) { |
| 650 | sprintf(g->Message, MSG(BIN_F_TOO_LONG), Name, (int) n, Long); |
| 651 | throw 31; |
| 652 | } // endif n |
| 653 | |
| 654 | if (Status) { |
| 655 | s = Value->GetCharString(Buf); |
| 656 | memset(p, ' ', Long); |
| 657 | memcpy(p, s, strlen(s)); |
| 658 | } // endif Status |
| 659 | |
| 660 | break; |
| 661 | default: |
| 662 | sprintf(g->Message, MSG(BAD_BIN_FMT), Fmt, Name); |
| 663 | throw 31; |
| 664 | } // endswitch Fmt |
| 665 | |
| 666 | if (Eds && Status) { |
| 667 | p = tdbp->To_Line + Deplac; |
| 668 | |
| 669 | for (int i = 0; i < Lim; i++) |
| 670 | if (Eds == 'B' && Endian == 'L') |
| 671 | p[N - i - 1] = Buff[i]; |
| 672 | else if (Eds == 'L' && Endian == 'B') |
| 673 | p[i] = Buff[M - i - 1]; |
| 674 | else if (Endian == 'B') |
| 675 | p[N - i - 1] = Buff[M - i - 1]; |
| 676 | else |
| 677 | p[i] = Buff[i]; |
| 678 | |
| 679 | } // endif Eds |
| 680 | |
| 681 | } // end of WriteColumn |
| 682 | |
| 683 | /* ------------------------ End of TabFix ---------------------------- */ |
| 684 | |