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_utf8mb3_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 	PCOL   colp;
392 
393 	if (Srcdef)
394 		return MakeSrcdef(g);
395 
396 	// Allocate the string used to contain the Query
397 	Query = new(g)STRING(g, 1023, "SELECT ");
398 
399 	if (!cnt) {
400 		if (Columns) {
401 			// Normal SQL statement to retrieve results
402 			for (colp = Columns; colp; colp = colp->GetNext())
403 				if (!colp->IsSpecial()) {
404 					if (!first)
405 						Query->Append(", ");
406 					else
407 						first = false;
408 
409 					// Column name can be encoded in UTF-8
410 					Decode(colp->GetName(), buf, sizeof(buf));
411 
412 					if (Quote) {
413 						// Put column name between identifier quotes in case in contains blanks
414 						Query->Append(Quote);
415 						Query->Append(buf);
416 						Query->Append(Quote);
417 					} else
418 						Query->Append(buf);
419 
420 					((PEXTCOL)colp)->SetRank(++Ncol);
421 				} // endif colp
422 
423 		} else
424 			// !Columns can occur for queries such that sql count(*) from...
425 			// for which we will count the rows from sql * from...
426 			Query->Append('*');
427 
428 	} else
429 		// SQL statement used to retrieve the size of the result
430 		Query->Append("count(*)");
431 
432 	Query->Append(" FROM ");
433 
434 	if (Catalog && *Catalog)
435 		catp = Catalog;
436 
437 	//if (tablep->GetSchema())
438 	//	schmp = (char*)tablep->GetSchema();
439 	//else
440 	if (Schema && *Schema)
441 		schmp = Schema;
442 
443 	if (catp) {
444 		Query->Append(catp);
445 
446 		if (schmp) {
447 			Query->Append('.');
448 			Query->Append(schmp);
449 		} // endif schmp
450 
451 		Query->Append('.');
452 	} else if (schmp) {
453 		Query->Append(schmp);
454 		Query->Append('.');
455 	} // endif schmp
456 
457 	// Table name can be encoded in UTF-8
458 	Decode(TableName, buf, sizeof(buf));
459 
460 	if (Quote) {
461 		// Put table name between identifier quotes in case in contains blanks
462 		Query->Append(Quote);
463 		Query->Append(buf);
464 		Query->Append(Quote);
465 	} else
466 		Query->Append(buf);
467 
468 	len = Query->GetLength();
469 
470 	if (To_CondFil) {
471 		if (Mode == MODE_READ) {
472 			Query->Append(" WHERE ");
473 			Query->Append(To_CondFil->Body);
474 			len = Query->GetLength() + 1;
475 		} else
476 			len += (strlen(To_CondFil->Body) + 256);
477 
478 	} else
479 		len += ((Mode == MODE_READX) ? 256 : 1);
480 
481 	if (Query->IsTruncated()) {
482 		strcpy(g->Message, "MakeSQL: Out of memory");
483 		return true;
484 	} else
485 		Query->Resize(len);
486 
487 	if (trace(33))
488 		htrc("Query=%s\n", Query->GetStr());
489 
490 	return false;
491 } // end of MakeSQL
492 
493 /***********************************************************************/
494 /*  Remove the NAME_CONST functions that are added by procedures.      */
495 /***********************************************************************/
RemoveConst(PGLOBAL g,char * stmt)496 void TDBEXT::RemoveConst(PGLOBAL g, char *stmt)
497 {
498 	char *p, *p2;
499 	char  val[1025], nval[1025];
500 	int   n, nc;
501 
502 	while ((p = strstr(stmt, "NAME_CONST")))
503         {
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