| 1 | /************* Colblk C++ Functions Source Code File (.CPP) ************/ |
| 2 | /* Name: COLBLK.CPP Version 2.2 */ |
| 3 | /* */ |
| 4 | /* (C) Copyright to the author Olivier BERTRAND 1998-2017 */ |
| 5 | /* */ |
| 6 | /* This file contains the COLBLK class functions. */ |
| 7 | /***********************************************************************/ |
| 8 | |
| 9 | /***********************************************************************/ |
| 10 | /* Include relevant MariaDB header file. */ |
| 11 | /***********************************************************************/ |
| 12 | #include "my_global.h" |
| 13 | |
| 14 | /***********************************************************************/ |
| 15 | /* Include required application header files */ |
| 16 | /* global.h is header containing all global Plug declarations. */ |
| 17 | /* plgdbsem.h is header containing the DB applic. declarations. */ |
| 18 | /***********************************************************************/ |
| 19 | #include "global.h" |
| 20 | #include "plgdbsem.h" |
| 21 | #include "tabcol.h" |
| 22 | #include "colblk.h" |
| 23 | #include "xindex.h" |
| 24 | #include "xtable.h" |
| 25 | |
| 26 | /***********************************************************************/ |
| 27 | /* COLBLK protected constructor. */ |
| 28 | /***********************************************************************/ |
| 29 | COLBLK::COLBLK(PCOLDEF cdp, PTDB tdbp, int i) |
| 30 | { |
| 31 | Next = NULL; |
| 32 | Index = i; |
| 33 | //Number = 0; |
| 34 | ColUse = 0; |
| 35 | |
| 36 | if ((Cdp = cdp)) { |
| 37 | Name = cdp->Name; |
| 38 | Format = cdp->F; |
| 39 | Opt = cdp->Opt; |
| 40 | Long = cdp->Long; |
| 41 | Precision = cdp->Precision; |
| 42 | Freq = cdp->Freq; |
| 43 | Buf_Type = cdp->Buf_Type; |
| 44 | ColUse |= cdp->Flags; // Used by CONNECT |
| 45 | Nullable = !!(cdp->Flags & U_NULLS); |
| 46 | Unsigned = !!(cdp->Flags & U_UNSIGNED); |
| 47 | } else { |
| 48 | Name = NULL; |
| 49 | memset(&Format, 0, sizeof(FORMAT)); |
| 50 | Opt = 0; |
| 51 | Long = 0; |
| 52 | Precision = 0; |
| 53 | Freq = 0; |
| 54 | Buf_Type = TYPE_ERROR; |
| 55 | Nullable = false; |
| 56 | Unsigned = false; |
| 57 | } // endif cdp |
| 58 | |
| 59 | To_Tdb = tdbp; |
| 60 | Status = BUF_NO; |
| 61 | //Value = NULL; done in XOBJECT constructor |
| 62 | To_Kcol = NULL; |
| 63 | } // end of COLBLK constructor |
| 64 | |
| 65 | /***********************************************************************/ |
| 66 | /* COLBLK constructor used for copying columns. */ |
| 67 | /* tdbp is the pointer to the new table descriptor. */ |
| 68 | /***********************************************************************/ |
| 69 | COLBLK::COLBLK(PCOL col1, PTDB tdbp) |
| 70 | { |
| 71 | PCOL colp; |
| 72 | |
| 73 | // Copy the old column block to the new one |
| 74 | *this = *col1; |
| 75 | Next = NULL; |
| 76 | //To_Orig = col1; |
| 77 | To_Tdb = tdbp; |
| 78 | |
| 79 | if (trace(2)) |
| 80 | htrc(" copying COLBLK %s from %p to %p\n" , Name, col1, this); |
| 81 | |
| 82 | if (tdbp) |
| 83 | // Attach the new column to the table block |
| 84 | if (!tdbp->GetColumns()) |
| 85 | tdbp->SetColumns(this); |
| 86 | else { |
| 87 | for (colp = tdbp->GetColumns(); colp->Next; colp = colp->Next) ; |
| 88 | |
| 89 | colp->Next = this; |
| 90 | } // endelse |
| 91 | |
| 92 | } // end of COLBLK copy constructor |
| 93 | |
| 94 | /***********************************************************************/ |
| 95 | /* Reset the column descriptor to non evaluated yet. */ |
| 96 | /***********************************************************************/ |
| 97 | void COLBLK::Reset(void) |
| 98 | { |
| 99 | Status &= ~BUF_READ; |
| 100 | } // end of Reset |
| 101 | |
| 102 | /***********************************************************************/ |
| 103 | /* Compare: compares itself to an (expression) object and returns */ |
| 104 | /* true if it is equivalent. */ |
| 105 | /***********************************************************************/ |
| 106 | bool COLBLK::Compare(PXOB xp) |
| 107 | { |
| 108 | return (this == xp); |
| 109 | } // end of Compare |
| 110 | |
| 111 | /***********************************************************************/ |
| 112 | /* SetFormat: function used to set SELECT output format. */ |
| 113 | /***********************************************************************/ |
| 114 | bool COLBLK::SetFormat(PGLOBAL, FORMAT& fmt) |
| 115 | { |
| 116 | fmt = Format; |
| 117 | |
| 118 | if (trace(2)) |
| 119 | htrc("COLBLK: %p format=%c(%d,%d)\n" , |
| 120 | this, *fmt.Type, fmt.Length, fmt.Prec); |
| 121 | |
| 122 | return false; |
| 123 | } // end of SetFormat |
| 124 | |
| 125 | /***********************************************************************/ |
| 126 | /* Eval: get the column value from the last read record or from a */ |
| 127 | /* matching Index column if there is one. */ |
| 128 | /***********************************************************************/ |
| 129 | bool COLBLK::Eval(PGLOBAL g) |
| 130 | { |
| 131 | if (trace(2)) |
| 132 | htrc("Col Eval: %s status=%.4X\n" , Name, Status); |
| 133 | |
| 134 | if (!GetStatus(BUF_READ)) { |
| 135 | // if (To_Tdb->IsNull()) |
| 136 | // Value->Reset(); |
| 137 | if (To_Kcol) |
| 138 | To_Kcol->FillValue(Value); |
| 139 | else |
| 140 | ReadColumn(g); |
| 141 | |
| 142 | AddStatus(BUF_READ); |
| 143 | } // endif |
| 144 | |
| 145 | return false; |
| 146 | } // end of Eval |
| 147 | |
| 148 | /***********************************************************************/ |
| 149 | /* InitValue: prepare a column block for read operation. */ |
| 150 | /* Now we use Format.Length for the len parameter to avoid strings */ |
| 151 | /* to be truncated when converting from string to coded string. */ |
| 152 | /* Added in version 1.5 is the arguments GetScale() and Domain */ |
| 153 | /* in calling AllocateValue. Domain is used for TYPE_DATE only. */ |
| 154 | /***********************************************************************/ |
| 155 | bool COLBLK::InitValue(PGLOBAL g) |
| 156 | { |
| 157 | if (Value) |
| 158 | return false; // Already done |
| 159 | |
| 160 | // Allocate a Value object |
| 161 | if (!(Value = AllocateValue(g, Buf_Type, Precision, |
| 162 | GetScale(), Unsigned, GetDomain()))) |
| 163 | return true; |
| 164 | |
| 165 | AddStatus(BUF_READY); |
| 166 | Value->SetNullable(Nullable); |
| 167 | |
| 168 | if (trace(2)) |
| 169 | htrc(" colp=%p type=%d value=%p coluse=%.4X status=%.4X\n" , |
| 170 | this, Buf_Type, Value, ColUse, Status); |
| 171 | |
| 172 | return false; |
| 173 | } // end of InitValue |
| 174 | |
| 175 | /***********************************************************************/ |
| 176 | /* SetBuffer: prepare a column block for write operation. */ |
| 177 | /***********************************************************************/ |
| 178 | bool COLBLK::SetBuffer(PGLOBAL g, PVAL, bool, bool) |
| 179 | { |
| 180 | sprintf(g->Message, MSG(UNDEFINED_AM), "SetBuffer" ); |
| 181 | return true; |
| 182 | } // end of SetBuffer |
| 183 | |
| 184 | /***********************************************************************/ |
| 185 | /* GetLength: returns an evaluation of the column string length. */ |
| 186 | /***********************************************************************/ |
| 187 | int COLBLK::GetLengthEx(void) |
| 188 | { |
| 189 | return Long; |
| 190 | } // end of GetLengthEx |
| 191 | |
| 192 | /***********************************************************************/ |
| 193 | /* ReadColumn: what this routine does is to access the last line */ |
| 194 | /* read from the corresponding table, extract from it the field */ |
| 195 | /* corresponding to this column and convert it to buffer type. */ |
| 196 | /***********************************************************************/ |
| 197 | void COLBLK::ReadColumn(PGLOBAL g) |
| 198 | { |
| 199 | sprintf(g->Message, MSG(UNDEFINED_AM), "ReadColumn" ); |
| 200 | throw (int)TYPE_COLBLK; |
| 201 | } // end of ReadColumn |
| 202 | |
| 203 | /***********************************************************************/ |
| 204 | /* WriteColumn: what this routine does is to access the last line */ |
| 205 | /* read from the corresponding table, and rewrite the field */ |
| 206 | /* corresponding to this column from the column buffer and type. */ |
| 207 | /***********************************************************************/ |
| 208 | void COLBLK::WriteColumn(PGLOBAL g) |
| 209 | { |
| 210 | sprintf(g->Message, MSG(UNDEFINED_AM), "WriteColumn" ); |
| 211 | throw (int)TYPE_COLBLK; |
| 212 | } // end of WriteColumn |
| 213 | |
| 214 | /***********************************************************************/ |
| 215 | /* Make file output of a column descriptor block. */ |
| 216 | /***********************************************************************/ |
| 217 | void COLBLK::Printf(PGLOBAL, FILE *f, uint n) |
| 218 | { |
| 219 | char m[64]; |
| 220 | int i; |
| 221 | PCOL colp; |
| 222 | |
| 223 | memset(m, ' ', n); // Make margin string |
| 224 | m[n] = '\0'; |
| 225 | |
| 226 | for (colp = To_Tdb->GetColumns(), i = 1; colp; colp = colp->Next, i++) |
| 227 | if (colp == this) |
| 228 | break; |
| 229 | |
| 230 | fprintf(f, "%sR%dC%d type=%d F=%.2s(%d,%d)" , m, To_Tdb->GetTdb_No(), |
| 231 | i, GetAmType(), Format.Type, Format.Length, Format.Prec); |
| 232 | fprintf(f, |
| 233 | " coluse=%04X status=%04X buftyp=%d value=%p name=%s\n" , |
| 234 | ColUse, Status, Buf_Type, Value, Name); |
| 235 | } // end of Printf |
| 236 | |
| 237 | /***********************************************************************/ |
| 238 | /* Make string output of a column descriptor block. */ |
| 239 | /***********************************************************************/ |
| 240 | void COLBLK::Prints(PGLOBAL, char *ps, uint) |
| 241 | { |
| 242 | sprintf(ps, "R%d.%s" , To_Tdb->GetTdb_No(), Name); |
| 243 | } // end of Prints |
| 244 | |
| 245 | |
| 246 | /***********************************************************************/ |
| 247 | /* SPCBLK constructor. */ |
| 248 | /***********************************************************************/ |
| 249 | SPCBLK::SPCBLK(PCOLUMN cp) |
| 250 | : COLBLK((PCOLDEF)NULL, cp->GetTo_Table()->GetTo_Tdb(), 0) |
| 251 | { |
| 252 | Name = (char*)cp->GetName(); |
| 253 | Precision = Long = 0; |
| 254 | Buf_Type = TYPE_ERROR; |
| 255 | } // end of SPCBLK constructor |
| 256 | |
| 257 | /***********************************************************************/ |
| 258 | /* WriteColumn: what this routine does is to access the last line */ |
| 259 | /* read from the corresponding table, and rewrite the field */ |
| 260 | /* corresponding to this column from the column buffer and type. */ |
| 261 | /***********************************************************************/ |
| 262 | void SPCBLK::WriteColumn(PGLOBAL g) |
| 263 | { |
| 264 | sprintf(g->Message, MSG(SPCOL_READONLY), Name); |
| 265 | throw (int)TYPE_COLBLK; |
| 266 | } // end of WriteColumn |
| 267 | |
| 268 | /***********************************************************************/ |
| 269 | /* RIDBLK constructor for the ROWID special column. */ |
| 270 | /***********************************************************************/ |
| 271 | RIDBLK::RIDBLK(PCOLUMN cp, bool rnm) : SPCBLK(cp) |
| 272 | { |
| 273 | Precision = Long = 10; |
| 274 | Buf_Type = TYPE_INT; |
| 275 | Rnm = rnm; |
| 276 | *Format.Type = 'N'; |
| 277 | Format.Length = 10; |
| 278 | } // end of RIDBLK constructor |
| 279 | |
| 280 | /***********************************************************************/ |
| 281 | /* ReadColumn: what this routine does is to return the ordinal */ |
| 282 | /* number of the current row in the table (if Rnm is true) or in the */ |
| 283 | /* current file (if Rnm is false) the same except for multiple tables.*/ |
| 284 | /***********************************************************************/ |
| 285 | void RIDBLK::ReadColumn(PGLOBAL g) |
| 286 | { |
| 287 | Value->SetValue(To_Tdb->RowNumber(g, Rnm)); |
| 288 | } // end of ReadColumn |
| 289 | |
| 290 | /***********************************************************************/ |
| 291 | /* FIDBLK constructor for the FILEID special column. */ |
| 292 | /***********************************************************************/ |
| 293 | FIDBLK::FIDBLK(PCOLUMN cp, OPVAL op) : SPCBLK(cp), Op(op) |
| 294 | { |
| 295 | //Is_Key = 2; for when the MUL table indexed reading will be implemented. |
| 296 | Precision = Long = _MAX_PATH; |
| 297 | Buf_Type = TYPE_STRING; |
| 298 | *Format.Type = 'C'; |
| 299 | Format.Length = Long; |
| 300 | #if defined(__WIN__) |
| 301 | Format.Prec = 1; // Case insensitive |
| 302 | #endif // __WIN__ |
| 303 | Constant = (!To_Tdb->GetDef()->GetMultiple() && |
| 304 | To_Tdb->GetAmType() != TYPE_AM_PLG && |
| 305 | To_Tdb->GetAmType() != TYPE_AM_PLM); |
| 306 | Fn = NULL; |
| 307 | } // end of FIDBLK constructor |
| 308 | |
| 309 | /***********************************************************************/ |
| 310 | /* ReadColumn: what this routine does is to return the current */ |
| 311 | /* file ID of the table (can change for Multiple tables). */ |
| 312 | /***********************************************************************/ |
| 313 | void FIDBLK::ReadColumn(PGLOBAL g) |
| 314 | { |
| 315 | if (Fn != To_Tdb->GetFile(g)) { |
| 316 | char filename[_MAX_PATH]; |
| 317 | |
| 318 | Fn = To_Tdb->GetFile(g); |
| 319 | PlugSetPath(filename, Fn, To_Tdb->GetPath()); |
| 320 | |
| 321 | if (Op != OP_XX) { |
| 322 | char buff[_MAX_PATH]; |
| 323 | |
| 324 | Value->SetValue_psz(ExtractFromPath(g, buff, filename, Op)); |
| 325 | } else |
| 326 | Value->SetValue_psz(filename); |
| 327 | |
| 328 | } // endif Fn |
| 329 | |
| 330 | } // end of ReadColumn |
| 331 | |
| 332 | /***********************************************************************/ |
| 333 | /* TIDBLK constructor for the TABID special column. */ |
| 334 | /***********************************************************************/ |
| 335 | TIDBLK::TIDBLK(PCOLUMN cp) : SPCBLK(cp) |
| 336 | { |
| 337 | //Is_Key = 2; for when the MUL table indexed reading will be implemented. |
| 338 | Precision = Long = 64; |
| 339 | Buf_Type = TYPE_STRING; |
| 340 | *Format.Type = 'C'; |
| 341 | Format.Length = Long; |
| 342 | Format.Prec = 1; // Case insensitive |
| 343 | Constant = (To_Tdb->GetAmType() != TYPE_AM_TBL); |
| 344 | Tname = NULL; |
| 345 | } // end of TIDBLK constructor |
| 346 | |
| 347 | /***********************************************************************/ |
| 348 | /* ReadColumn: what this routine does is to return the table ID. */ |
| 349 | /***********************************************************************/ |
| 350 | void TIDBLK::ReadColumn(PGLOBAL) |
| 351 | { |
| 352 | if (Tname == NULL) { |
| 353 | Tname = (char*)To_Tdb->GetName(); |
| 354 | Value->SetValue_psz(Tname); |
| 355 | } // endif Tname |
| 356 | |
| 357 | } // end of ReadColumn |
| 358 | |
| 359 | /***********************************************************************/ |
| 360 | /* PRTBLK constructor for the PARTID special column. */ |
| 361 | /***********************************************************************/ |
| 362 | PRTBLK::PRTBLK(PCOLUMN cp) : SPCBLK(cp) |
| 363 | { |
| 364 | //Is_Key = 2; for when the MUL table indexed reading will be implemented. |
| 365 | Precision = Long = 64; |
| 366 | Buf_Type = TYPE_STRING; |
| 367 | *Format.Type = 'C'; |
| 368 | Format.Length = Long; |
| 369 | Format.Prec = 1; // Case insensitive |
| 370 | Constant = true; // TODO: check whether this is true indeed |
| 371 | Pname = NULL; |
| 372 | } // end of PRTBLK constructor |
| 373 | |
| 374 | /***********************************************************************/ |
| 375 | /* ReadColumn: what this routine does is to return the partition ID. */ |
| 376 | /***********************************************************************/ |
| 377 | void PRTBLK::ReadColumn(PGLOBAL g) |
| 378 | { |
| 379 | if (Pname == NULL) { |
| 380 | const char *p; |
| 381 | |
| 382 | Pname = To_Tdb->GetDef()->GetStringCatInfo(g, "partname" , "?" ); |
| 383 | p = strrchr(Pname, '#'); |
| 384 | Value->SetValue_psz((p) ? p + 1 : Pname); |
| 385 | } // endif Pname |
| 386 | |
| 387 | } // end of ReadColumn |
| 388 | |
| 389 | /***********************************************************************/ |
| 390 | /* SIDBLK constructor for the SERVID special column. */ |
| 391 | /***********************************************************************/ |
| 392 | SIDBLK::SIDBLK(PCOLUMN cp) : SPCBLK(cp) |
| 393 | { |
| 394 | //Is_Key = 2; for when the MUL table indexed reading will be implemented. |
| 395 | Precision = Long = 64; |
| 396 | Buf_Type = TYPE_STRING; |
| 397 | *Format.Type = 'C'; |
| 398 | Format.Length = Long; |
| 399 | Format.Prec = 1; // Case insensitive |
| 400 | Constant = (To_Tdb->GetAmType() != TYPE_AM_TBL); |
| 401 | Sname = NULL; |
| 402 | } // end of TIDBLK constructor |
| 403 | |
| 404 | /***********************************************************************/ |
| 405 | /* ReadColumn: what this routine does is to return the server ID. */ |
| 406 | /***********************************************************************/ |
| 407 | void SIDBLK::ReadColumn(PGLOBAL) |
| 408 | { |
| 409 | //if (Sname == NULL) { |
| 410 | Sname = To_Tdb->GetServer(); |
| 411 | Value->SetValue_psz(Sname); |
| 412 | // } // endif Sname |
| 413 | |
| 414 | } // end of ReadColumn |
| 415 | |