1 /************* Tabext C++ Functions Source Code File (.CPP) ************/
2 /* Name: TABEXT.CPP Version 1.1 */
3 /* */
4 /* (C) Copyright to the author Olivier BERTRAND 2017 - 2019 */
5 /* */
6 /* This file contains the TBX, TDB and OPJOIN classes functions. */
7 /***********************************************************************/
8
9 /***********************************************************************/
10 /* Include relevant MariaDB header file. */
11 /***********************************************************************/
12 #define MYSQL_SERVER 1
13 #include "my_global.h"
14 #include "sql_class.h"
15 #include "sql_servers.h"
16 #include "sql_string.h"
17 #if !defined(_WIN32)
18 #include "osutil.h"
19 #endif
20
21 /***********************************************************************/
22 /* Include required application header files */
23 /* global.h is header containing all global Plug declarations. */
24 /* plgdbsem.h is header containing the DB applic. declarations. */
25 /* xobject.h is header containing XOBJECT derived classes declares. */
26 /***********************************************************************/
27 #include "global.h"
28 #include "plgdbsem.h"
29 #include "xtable.h"
30 #include "tabext.h"
31 #include "ha_connect.h"
32
33 /* -------------------------- Class CONDFIL -------------------------- */
34
35 /***********************************************************************/
36 /* CONDFIL Constructor. */
37 /***********************************************************************/
CONDFIL(uint idx,AMT type)38 CONDFIL::CONDFIL(uint idx, AMT type)
39 {
40 //Cond = cond;
41 Idx = idx;
42 Type = type;
43 Op = OP_XX;
44 Cmds = NULL;
45 Alist = NULL;
46 All = true;
47 Bd = false;
48 Hv = false;
49 Body = NULL,
50 Having = NULL;
51 } // end of CONDFIL constructor
52
53 /***********************************************************************/
54 /* Make and allocate the alias list. */
55 /***********************************************************************/
Init(PGLOBAL g,PHC hc)56 int CONDFIL::Init(PGLOBAL g, PHC hc)
57 {
58 PTOS options = hc->GetTableOptionStruct();
59 char *p, *cn, *cal, *alt = NULL;
60 int rc = RC_OK;
61 bool h;
62
63 if (options)
64 alt = (char*)GetListOption(g, "Alias", options->oplist, NULL);
65
66 while (alt) {
67 if (!(p = strchr(alt, '='))) {
68 strcpy(g->Message, "Invalid alias list");
69 rc = RC_FX;
70 break;
71 } // endif !p
72
73 cal = alt; // Alias
74 *p++ = 0;
75
76 if ((h = *p == '*')) {
77 rc = RC_INFO;
78 p++;
79 } // endif h
80
81 cn = p; // Remote column name
82
83 if ((alt = strchr(p, ';')))
84 *alt++ = 0;
85
86 if (*cn == 0)
87 cn = alt;
88
89 Alist = new(g) ALIAS(Alist, cn, cal, h);
90 } // endwhile alt
91
92 return rc;
93 } // end of Init
94
95 /***********************************************************************/
96 /* Make and allocate the alias list. */
97 /***********************************************************************/
Chk(const char * fln,bool * h)98 const char *CONDFIL::Chk(const char *fln, bool *h)
99 {
100 for (PAL pal = Alist; pal; pal = pal->Next)
101 if (!stricmp(fln, pal->Alias)) {
102 *h = pal->Having;
103 return pal->Name;
104 } // endif fln
105
106 *h = false;
107 return fln;
108 } // end of Chk
109
110 /* --------------------------- Class EXTDEF -------------------------- */
111
112 /***********************************************************************/
113 /* EXTDEF Constructor. */
114 /***********************************************************************/
EXTDEF(void)115 EXTDEF::EXTDEF(void)
116 {
117 Tabname = Tabschema = Username = Password = Tabcat = Tabtyp = NULL;
118 Colpat = Srcdef = Qchar = Qrystr = Sep = Phpos = NULL;
119 Options = Cto = Qto = Quoted = Maxerr = Maxres = Memory = 0;
120 Scrollable = Xsrc = false;
121 } // end of EXTDEF constructor
122
123 /***********************************************************************/
124 /* DefineAM: define specific AM block values from XDB file. */
125 /***********************************************************************/
DefineAM(PGLOBAL g,LPCSTR am,int poff)126 bool EXTDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
127 {
128 if (g->Createas) {
129 strcpy(g->Message,
130 "Multiple-table UPDATE/DELETE commands are not supported");
131 return true;
132 } // endif multi
133
134 Desc = NULL;
135 Tabname = GetStringCatInfo(g, "Name",
136 (Catfunc & (FNC_TABLE | FNC_COL)) ? NULL : Name);
137 Tabname = GetStringCatInfo(g, "Tabname", Tabname);
138 Tabschema = GetStringCatInfo(g, "Dbname", NULL);
139 Tabschema = GetStringCatInfo(g, "Schema", Tabschema);
140 Tabcat = GetStringCatInfo(g, "Qualifier", NULL);
141 Tabcat = GetStringCatInfo(g, "Catalog", Tabcat);
142 Username = GetStringCatInfo(g, "User", NULL);
143 Password = GetStringCatInfo(g, "Password", NULL);
144
145 // Memory was Boolean, it is now integer
146 if (!(Memory = GetIntCatInfo("Memory", 0)))
147 Memory = GetBoolCatInfo("Memory", false) ? 1 : 0;
148
149 if ((Srcdef = GetStringCatInfo(g, "Srcdef", NULL))) {
150 Read_Only = true;
151 if (Memory == 2) Memory = 1;
152 } // endif Srcdef
153
154 Qrystr = GetStringCatInfo(g, "Query_String", "?");
155 Sep = GetStringCatInfo(g, "Separator", NULL);
156 //Alias = GetStringCatInfo(g, "Alias", NULL);
157 Phpos = GetStringCatInfo(g, "Phpos", NULL);
158 Xsrc = GetBoolCatInfo("Execsrc", FALSE);
159 Maxerr = GetIntCatInfo("Maxerr", 0);
160 Maxres = GetIntCatInfo("Maxres", 0);
161 Quoted = GetIntCatInfo("Quoted", 0);
162 Options = 0;
163 Cto = 0;
164 Qto = 0;
165
166 if ((Scrollable = GetBoolCatInfo("Scrollable", false)) && !Elemt)
167 Elemt = 1; // Cannot merge SQLFetch and SQLExtendedFetch
168
169 if (Catfunc == FNC_COL)
170 Colpat = GetStringCatInfo(g, "Colpat", NULL);
171
172 if (Catfunc == FNC_TABLE)
173 Tabtyp = GetStringCatInfo(g, "Tabtype", NULL);
174
175 Pseudo = 2; // FILID is Ok but not ROWID
176 return false;
177 } // end of DefineAM
178
179 /* ---------------------------TDBEXT class --------------------------- */
180
181 /***********************************************************************/
182 /* Implementation of the TDBEXT class. */
183 /***********************************************************************/
TDBEXT(EXTDEF * tdp)184 TDBEXT::TDBEXT(EXTDEF *tdp) : TDB(tdp)
185 {
186 Qrp = NULL;
187
188 if (tdp) {
189 TableName = tdp->Tabname;
190 Schema = tdp->Tabschema;
191 User = tdp->Username;
192 Pwd = tdp->Password;
193 Catalog = tdp->Tabcat;
194 Srcdef = tdp->Srcdef;
195 Qrystr = tdp->Qrystr;
196 Sep = tdp->GetSep();
197 Options = tdp->Options;
198 Cto = tdp->Cto;
199 Qto = tdp->Qto;
200 Quoted = MY_MAX(0, tdp->GetQuoted());
201 Rows = tdp->GetElemt();
202 Memory = tdp->Memory;
203 Scrollable = tdp->Scrollable;
204 } else {
205 TableName = NULL;
206 Schema = NULL;
207 User = NULL;
208 Pwd = NULL;
209 Catalog = NULL;
210 Srcdef = NULL;
211 Qrystr = NULL;
212 Sep = 0;
213 Options = 0;
214 Cto = 0;
215 Qto = 0;
216 Quoted = 0;
217 Rows = 0;
218 Memory = 0;
219 Scrollable = false;
220 } // endif tdp
221
222 Quote = NULL;
223 Query = NULL;
224 Count = NULL;
225 //Where = NULL;
226 MulConn = NULL;
227 DBQ = NULL;
228 Qrp = NULL;
229 Fpos = 0;
230 Curpos = 0;
231 AftRows = 0;
232 CurNum = 0;
233 Rbuf = 0;
234 BufSize = 0;
235 Nparm = 0;
236 Ncol = 0;
237 Placed = false;
238 } // end of TDBEXT constructor
239
TDBEXT(PTDBEXT tdbp)240 TDBEXT::TDBEXT(PTDBEXT tdbp) : TDB(tdbp)
241 {
242 Qrp = tdbp->Qrp;
243 TableName = tdbp->TableName;
244 Schema = tdbp->Schema;
245 User = tdbp->User;
246 Pwd = tdbp->Pwd;
247 Catalog = tdbp->Catalog;
248 Srcdef = tdbp->Srcdef;
249 Qrystr = tdbp->Qrystr;
250 Sep = tdbp->Sep;
251 Options = tdbp->Options;
252 Cto = tdbp->Cto;
253 Qto = tdbp->Qto;
254 Quoted = tdbp->Quoted;
255 Rows = tdbp->Rows;
256 Memory = tdbp->Memory;
257 Scrollable = tdbp->Scrollable;
258 Quote = tdbp->Quote;
259 Query = tdbp->Query;
260 Count = tdbp->Count;
261 //Where = tdbp->Where;
262 MulConn = tdbp->MulConn;
263 DBQ = tdbp->DBQ;
264 Fpos = 0;
265 Curpos = 0;
266 AftRows = 0;
267 CurNum = 0;
268 Rbuf = 0;
269 BufSize = tdbp->BufSize;
270 Nparm = tdbp->Nparm;
271 Ncol = tdbp->Ncol;
272 Placed = false;
273 } // end of TDBEXT copy constructor
274
275 /******************************************************************/
276 /* Convert an UTF-8 string to latin characters. */
277 /******************************************************************/
Decode(PCSZ txt,char * buf,size_t n)278 int TDBEXT::Decode(PCSZ txt, char *buf, size_t n)
279 {
280 uint dummy_errors;
281 uint32 len = copy_and_convert(buf, n, &my_charset_latin1,
282 txt, strlen(txt),
283 &my_charset_utf8_general_ci,
284 &dummy_errors);
285 buf[len] = '\0';
286 return 0;
287 } // end of Decode
288
289 /*
290 Count number of %s placeholders in string.
291 Returns -1 if other sprintf placeholders are found, .g %d
292 */
count_placeholders(const char * fmt)293 static int count_placeholders(const char *fmt)
294 {
295 int cnt= 0;
296 for (const char *p=fmt; *p; p++)
297 {
298 if (*p == '%')
299 {
300 switch (p[1])
301 {
302 case 's':
303 /* %s found */
304 cnt++;
305 p++;
306 break;
307 case '%':
308 /* masking char for % found */
309 p++;
310 break;
311 default:
312 /* some other placeholder found */
313 return -1;
314 }
315 }
316 }
317 return cnt;
318 }
319
320 /***********************************************************************/
321 /* MakeSrcdef: make the SQL statement from SRDEF option. */
322 /***********************************************************************/
MakeSrcdef(PGLOBAL g)323 bool TDBEXT::MakeSrcdef(PGLOBAL g)
324 {
325 char *catp = strstr(Srcdef, "%s");
326
327 if (catp) {
328 char *fil1 = 0, *fil2;
329 PCSZ ph = ((EXTDEF*)To_Def)->Phpos;
330
331 if (!ph)
332 ph = (strstr(catp + 2, "%s")) ? "WH" : "W";
333
334 if (stricmp(ph, "H")) {
335 fil1 = (To_CondFil && *To_CondFil->Body)
336 ? To_CondFil->Body : PlugDup(g, "1=1");
337 } // endif ph
338
339 if (stricmp(ph, "W")) {
340 fil2 = (To_CondFil && To_CondFil->Having && *To_CondFil->Having)
341 ? To_CondFil->Having : PlugDup(g, "1=1");
342 } // endif ph
343
344 int n_placeholders = count_placeholders(Srcdef);
345 if (n_placeholders < 0)
346 {
347 strcpy(g->Message, "MakeSQL: Wrong place holders specification");
348 return true;
349 }
350
351 if (!stricmp(ph, "W") && n_placeholders <= 1) {
352 Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1));
353 Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil1));
354 }
355 else if (!stricmp(ph, "WH") && n_placeholders <= 2)
356 {
357 Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1) + strlen(fil2));
358 Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil1, fil2));
359 }
360 else if (!stricmp(ph, "H") && n_placeholders <= 1)
361 {
362 Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil2));
363 Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil2));
364 }
365 else if (!stricmp(ph, "HW") && n_placeholders <= 2)
366 {
367 Query = new(g)STRING(g, strlen(Srcdef) + strlen(fil1) + strlen(fil2));
368 Query->SetLength(sprintf(Query->GetStr(), Srcdef, fil2, fil1));
369 } else {
370 strcpy(g->Message, "MakeSQL: Wrong place holders specification");
371 return true;
372 } // endif's ph
373
374 } else
375 Query = new(g)STRING(g, 0, Srcdef);
376
377 return false;
378 } // end of MakeSrcdef
379
380 /***********************************************************************/
381 /* MakeSQL: make the SQL statement use with remote connection. */
382 /* TODO: when implementing remote filtering, column only used in */
383 /* local filter should be removed from column list. */
384 /***********************************************************************/
MakeSQL(PGLOBAL g,bool cnt)385 bool TDBEXT::MakeSQL(PGLOBAL g, bool cnt)
386 {
387 PCSZ schmp = NULL;
388 char *catp = NULL, buf[NAM_LEN * 3];
389 int len;
390 bool first = true;
391 PTABLE tablep = To_Table;
392 PCOL colp;
393
394 if (Srcdef)
395 return MakeSrcdef(g);
396
397 // Allocate the string used to contain the Query
398 Query = new(g)STRING(g, 1023, "SELECT ");
399
400 if (!cnt) {
401 if (Columns) {
402 // Normal SQL statement to retrieve results
403 for (colp = Columns; colp; colp = colp->GetNext())
404 if (!colp->IsSpecial()) {
405 if (!first)
406 Query->Append(", ");
407 else
408 first = false;
409
410 // Column name can be encoded in UTF-8
411 Decode(colp->GetName(), buf, sizeof(buf));
412
413 if (Quote) {
414 // Put column name between identifier quotes in case in contains blanks
415 Query->Append(Quote);
416 Query->Append(buf);
417 Query->Append(Quote);
418 } else
419 Query->Append(buf);
420
421 ((PEXTCOL)colp)->SetRank(++Ncol);
422 } // endif colp
423
424 } else
425 // !Columns can occur for queries such that sql count(*) from...
426 // for which we will count the rows from sql * from...
427 Query->Append('*');
428
429 } else
430 // SQL statement used to retrieve the size of the result
431 Query->Append("count(*)");
432
433 Query->Append(" FROM ");
434
435 if (Catalog && *Catalog)
436 catp = Catalog;
437
438 //if (tablep->GetSchema())
439 // schmp = (char*)tablep->GetSchema();
440 //else
441 if (Schema && *Schema)
442 schmp = Schema;
443
444 if (catp) {
445 Query->Append(catp);
446
447 if (schmp) {
448 Query->Append('.');
449 Query->Append(schmp);
450 } // endif schmp
451
452 Query->Append('.');
453 } else if (schmp) {
454 Query->Append(schmp);
455 Query->Append('.');
456 } // endif schmp
457
458 // Table name can be encoded in UTF-8
459 Decode(TableName, buf, sizeof(buf));
460
461 if (Quote) {
462 // Put table name between identifier quotes in case in contains blanks
463 Query->Append(Quote);
464 Query->Append(buf);
465 Query->Append(Quote);
466 } else
467 Query->Append(buf);
468
469 len = Query->GetLength();
470
471 if (To_CondFil) {
472 if (Mode == MODE_READ) {
473 Query->Append(" WHERE ");
474 Query->Append(To_CondFil->Body);
475 len = Query->GetLength() + 1;
476 } else
477 len += (strlen(To_CondFil->Body) + 256);
478
479 } else
480 len += ((Mode == MODE_READX) ? 256 : 1);
481
482 if (Query->IsTruncated()) {
483 strcpy(g->Message, "MakeSQL: Out of memory");
484 return true;
485 } else
486 Query->Resize(len);
487
488 if (trace(33))
489 htrc("Query=%s\n", Query->GetStr());
490
491 return false;
492 } // end of MakeSQL
493
494 /***********************************************************************/
495 /* Remove the NAME_CONST functions that are added by procedures. */
496 /***********************************************************************/
RemoveConst(PGLOBAL g,char * stmt)497 void TDBEXT::RemoveConst(PGLOBAL g, char *stmt)
498 {
499 char *p, *p2;
500 char val[1025], nval[1025];
501 int n, nc;
502
503 while ((p = strstr(stmt, "NAME_CONST")))
504 if ((n = sscanf(p, "%*[^,],%1024[^)])%n", val, &nc))) {
505 if (trace(33))
506 htrc("p=%s\nn=%d val=%s nc=%d\n", p, n, val, nc);
507
508 *p = 0;
509
510 if ((p2 = strstr(val, "'"))) {
511 if ((n = sscanf(p2, "%*['\\]%1024[^'\\]", nval))) {
512 if (trace(33))
513 htrc("p2=%s\nn=%d nval=%s\n", p2, n, nval);
514
515 strcat(strcat(strcat(strcat(stmt, "'"), nval), "'"), p + nc);
516 } else
517 break;
518
519 } else
520 strcat(strcat(strcat(strcat(stmt, "("), val), ")"), p + nc);
521
522 if (trace(33))
523 htrc("stmt=%s\n", stmt);
524
525 } else
526 break;
527
528 return;
529 } // end of RemoveConst
530
531 /***********************************************************************/
532 /* MakeCommand: make the Update or Delete statement to send to the */
533 /* MySQL server. Limited to remote values and filtering. */
534 /***********************************************************************/
MakeCommand(PGLOBAL g)535 bool TDBEXT::MakeCommand(PGLOBAL g)
536 {
537 PCSZ schmp = NULL;
538 char *p, *stmt, name[132], *body = NULL;
539 char *qrystr = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 1);
540 bool qtd = Quoted > 0;
541 char q = qtd ? *Quote : ' ';
542 int i = 0, k = 0;
543
544 // Make a lower case copy of the originale query and change
545 // back ticks to the data source identifier quoting character
546 do {
547 qrystr[i] = (Qrystr[i] == '`') ? q : tolower(Qrystr[i]);
548 } while (Qrystr[i++]);
549
550 if (To_CondFil && (p = strstr(qrystr, " where "))) {
551 p[7] = 0; // Remove where clause
552 Qrystr[(p - qrystr) + 7] = 0;
553 body = To_CondFil->Body;
554 stmt = (char*)PlugSubAlloc(g, NULL, strlen(qrystr)
555 + strlen(body) + 64);
556 } else
557 stmt = (char*)PlugSubAlloc(g, NULL, strlen(Qrystr) + 64);
558
559 // Check whether the table name is equal to a keyword
560 // If so, it must be quoted in the original query
561 strlwr(strcat(strcat(strcpy(name, " "), Name), " "));
562
563 if (strstr(" update delete low_priority ignore quick from ", name)) {
564 if (Quote) {
565 strlwr(strcat(strcat(strcpy(name, Quote), Name), Quote));
566 k += 2;
567 } else {
568 strcpy(g->Message, "Quoted must be specified");
569 return true;
570 } // endif Quote
571
572 } else
573 strlwr(strcpy(name, Name)); // Not a keyword
574
575 if ((p = strstr(qrystr, name))) {
576 for (i = 0; i < p - qrystr; i++)
577 stmt[i] = (Qrystr[i] == '`') ? q : Qrystr[i];
578
579 stmt[i] = 0;
580
581 k += i + (int)strlen(Name);
582
583 if (Schema && *Schema)
584 schmp = Schema;
585
586 if (qtd && *(p - 1) == ' ') {
587 if (schmp)
588 strcat(strcat(stmt, schmp), ".");
589
590 strcat(strcat(strcat(stmt, Quote), TableName), Quote);
591 } else {
592 if (schmp) {
593 if (qtd && *(p - 1) != ' ') {
594 stmt[i - 1] = 0;
595 strcat(strcat(strcat(stmt, schmp), "."), Quote);
596 } else
597 strcat(strcat(stmt, schmp), ".");
598
599 } // endif schmp
600
601 strcat(stmt, TableName);
602 } // endif's
603
604 i = (int)strlen(stmt);
605
606 do {
607 stmt[i++] = (Qrystr[k] == '`') ? q : Qrystr[k];
608 } while (Qrystr[k++]);
609
610 RemoveConst(g, stmt);
611
612 if (body)
613 strcat(stmt, body);
614
615 } else {
616 sprintf(g->Message, "Cannot use this %s command",
617 (Mode == MODE_UPDATE) ? "UPDATE" : "DELETE");
618 return true;
619 } // endif p
620
621 if (trace(33))
622 htrc("Command=%s\n", stmt);
623
624 Query = new(g)STRING(g, 0, stmt);
625 return (!Query->GetSize());
626 } // end of MakeCommand
627
628 /***********************************************************************/
629 /* GetRecpos: return the position of last read record. */
630 /***********************************************************************/
GetRecpos(void)631 int TDBEXT::GetRecpos(void)
632 {
633 return Fpos;
634 } // end of GetRecpos
635
636 /***********************************************************************/
637 /* ODBC GetMaxSize: returns table size estimate in number of lines. */
638 /***********************************************************************/
GetMaxSize(PGLOBAL g)639 int TDBEXT::GetMaxSize(PGLOBAL g)
640 {
641 if (MaxSize < 0) {
642 if (Mode == MODE_DELETE)
643 // Return 0 in mode DELETE in case of delete all.
644 MaxSize = 0;
645 else if (!Cardinality(NULL))
646 MaxSize = 10; // To make MySQL happy
647 else if ((MaxSize = Cardinality(g)) < 0)
648 MaxSize = 12; // So we can see an error occurred
649
650 } // endif MaxSize
651
652 return MaxSize;
653 } // end of GetMaxSize
654
655 /***********************************************************************/
656 /* Return max size value. */
657 /***********************************************************************/
GetProgMax(PGLOBAL g)658 int TDBEXT::GetProgMax(PGLOBAL g)
659 {
660 return GetMaxSize(g);
661 } // end of GetProgMax
662
663 /* ---------------------------EXTCOL class --------------------------- */
664
665 /***********************************************************************/
666 /* EXTCOL public constructor. */
667 /***********************************************************************/
EXTCOL(PCOLDEF cdp,PTDB tdbp,PCOL cprec,int i,PCSZ am)668 EXTCOL::EXTCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
669 : COLBLK(cdp, tdbp, i)
670 {
671 if (cprec) {
672 Next = cprec->GetNext();
673 cprec->SetNext(this);
674 } else {
675 Next = tdbp->GetColumns();
676 tdbp->SetColumns(this);
677 } // endif cprec
678
679 if (trace(1))
680 htrc(" making new %sCOL C%d %s at %p\n", am, Index, Name, this);
681
682 // Set additional remote access method information for column.
683 Crp = NULL;
684 Long = Precision;
685 To_Val = NULL;
686 Bufp = NULL;
687 Blkp = NULL;
688 Rank = 0; // Not known yet
689 } // end of JDBCCOL constructor
690
691 /***********************************************************************/
692 /* EXTCOL private constructor. */
693 /***********************************************************************/
EXTCOL(void)694 EXTCOL::EXTCOL(void) : COLBLK()
695 {
696 Crp = NULL;
697 Buf_Type = TYPE_INT; // This is a count(*) column
698
699 // Set additional Dos access method information for column.
700 Long = sizeof(int);
701 To_Val = NULL;
702 Bufp = NULL;
703 Blkp = NULL;
704 Rank = 1;
705 } // end of EXTCOL constructor
706
707 /***********************************************************************/
708 /* EXTCOL constructor used for copying columns. */
709 /* tdbp is the pointer to the new table descriptor. */
710 /***********************************************************************/
EXTCOL(PEXTCOL col1,PTDB tdbp)711 EXTCOL::EXTCOL(PEXTCOL col1, PTDB tdbp) : COLBLK(col1, tdbp)
712 {
713 Crp = col1->Crp;
714 Long = col1->Long;
715 To_Val = col1->To_Val;
716 Bufp = col1->Bufp;
717 Blkp = col1->Blkp;
718 Rank = col1->Rank;
719 } // end of JDBCCOL copy constructor
720
721 /***********************************************************************/
722 /* SetBuffer: prepare a column block for write operation. */
723 /***********************************************************************/
SetBuffer(PGLOBAL g,PVAL value,bool ok,bool check)724 bool EXTCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
725 {
726 if (!(To_Val = value)) {
727 sprintf(g->Message, MSG(VALUE_ERROR), Name);
728 return true;
729 } else if (Buf_Type == value->GetType()) {
730 // Values are of the (good) column type
731 if (Buf_Type == TYPE_DATE) {
732 // If any of the date values is formatted
733 // output format must be set for the receiving table
734 if (GetDomain() || ((DTVAL *)value)->IsFormatted())
735 goto newval; // This will make a new value;
736
737 } else if (Buf_Type == TYPE_DOUBLE)
738 // Float values must be written with the correct (column) precision
739 // Note: maybe this should be forced by ShowValue instead of this ?
740 value->SetPrec(GetScale());
741
742 Value = value; // Directly access the external value
743 } else {
744 // Values are not of the (good) column type
745 if (check) {
746 sprintf(g->Message, MSG(TYPE_VALUE_ERR), Name,
747 GetTypeName(Buf_Type), GetTypeName(value->GetType()));
748 return true;
749 } // endif check
750
751 newval:
752 if (InitValue(g)) // Allocate the matching value block
753 return true;
754
755 } // endif's Value, Buf_Type
756
757 // Because Colblk's have been made from a copy of the original TDB in
758 // case of Update, we must reset them to point to the original one.
759 if (To_Tdb->GetOrig())
760 To_Tdb = (PTDB)To_Tdb->GetOrig();
761
762 // Set the Column
763 Status = (ok) ? BUF_EMPTY : BUF_NO;
764 return false;
765 } // end of SetBuffer
766
767