1 /********** PlgDBUtl Fpe C++ Program Source Code File (.CPP) ***********/
2 /* PROGRAM NAME: PLGDBUTL */
3 /* ------------- */
4 /* Version 4.1 */
5 /* */
6 /* COPYRIGHT: */
7 /* ---------- */
8 /* (C) Copyright to the author Olivier BERTRAND 1998-2020 */
9 /* */
10 /* WHAT THIS PROGRAM DOES: */
11 /* ----------------------- */
12 /* Utility functions used by DB semantic routines. */
13 /* */
14 /* WHAT YOU NEED TO COMPILE THIS PROGRAM: */
15 /* -------------------------------------- */
16 /* */
17 /* REQUIRED FILES: */
18 /* --------------- */
19 /* See Readme.C for a list and description of required SYSTEM files. */
20 /* */
21 /* PLGDBUTL.C - Source code */
22 /* GLOBAL.H - Global declaration file */
23 /* PLGDBSEM.H - DB application declaration file */
24 /* */
25 /* REQUIRED LIBRARIES: */
26 /* ------------------- */
27 /* OS2.LIB - OS2 libray */
28 /* LLIBCE.LIB - Protect mode/standard combined large model C */
29 /* library */
30 /* */
31 /* REQUIRED PROGRAMS: */
32 /* ------------------ */
33 /* IBM, MS, Borland or GNU C++ Compiler */
34 /* IBM, MS, Borland or GNU Linker */
35 /***********************************************************************/
36
37 /***********************************************************************/
38 /* Include relevant MariaDB header file. */
39 /***********************************************************************/
40 #include "my_global.h"
41 #include "my_pthread.h"
42 #if defined(_WIN32)
43 #include <io.h>
44 #include <fcntl.h>
45 #include <errno.h>
46 #define BIGMEM 1048576 // 1 Megabyte
47 #else // !_WIN32
48 #include <unistd.h>
49 #include <fcntl.h>
50 //#if defined(THREAD)
51 #include <pthread.h>
52 //#endif // THREAD
53 #include <stdarg.h>
54 #define BIGMEM 2147483647 // Max int value
55 #endif // !_WIN32
56 #include <locale.h>
57
58 /***********************************************************************/
59 /* Include application header files */
60 /***********************************************************************/
61 #include "global.h" // header containing all global declarations.
62 #include "plgdbsem.h" // header containing the DB applic. declarations.
63 #include "preparse.h" // For DATPAR
64 #include "osutil.h"
65 #include "maputil.h"
66 #include "catalog.h"
67 #include "colblk.h"
68 #include "xtable.h" // header of TBX, TDB and TDBASE classes
69 #include "tabcol.h" // header of XTAB and COLUMN classes
70 #include "valblk.h"
71 #include "rcmsg.h"
72 #ifdef ZIP_SUPPORT
73 #include "filamzip.h"
74 #endif // ZIP_SUPPORT
75 #ifdef JAVA_SUPPORT
76 #include "javaconn.h"
77 #endif // JAVA_SUPPORT
78 #ifdef CMGO_SUPPORT
79 #include "cmgoconn.h"
80 #endif // JAVA_SUPPORT
81
82 /***********************************************************************/
83 /* DB static variables. */
84 /***********************************************************************/
85 bool Initdone = false;
86 bool plugin = false; // True when called by the XDB plugin handler
87
88 extern "C" {
89 extern char version[];
90 } // extern "C"
91
92 //#if defined(_WIN32)
93 //extern CRITICAL_SECTION parsec; // Used calling the Flex parser
94 //#else // !_WIN32
95 extern pthread_mutex_t parmut;
96 //#endif // !_WIN32
97
98 // The debug trace used by the main thread
99 FILE *pfile = NULL;
100
101 MBLOCK Nmblk = {NULL, false, 0, false, NULL}; // Used to init MBLOCK's
102
103 /***********************************************************************/
104 /* Routines called externally and internally by utility routines. */
105 /***********************************************************************/
106 bool PlugEvalLike(PGLOBAL, LPCSTR, LPCSTR, bool);
107 bool EvalLikePattern(LPCSTR, LPCSTR);
108 void PlugConvertConstant(PGLOBAL, void* &, short&);
109
110 #ifdef DOMDOC_SUPPORT
111 void CloseXMLFile(PGLOBAL, PFBLOCK, bool);
112 #endif // DOMDOC_SUPPORT
113
114 #ifdef LIBXML2_SUPPORT
115 #include "libdoc.h"
116 #endif // LIBXML2_SUPPORT
117
118 #ifdef ODBC_SUPPORT
119 void OdbcClose(PGLOBAL g, PFBLOCK fp);
120 #endif // ODBC_SUPPORT
121
122 /***********************************************************************/
123 /* Routines for file IO with error reporting to g->Message */
124 /* Note: errno and strerror must be called before the message file */
125 /* is read in the case of XMSG compile. */
126 /***********************************************************************/
global_open_error_msg(GLOBAL * g,int msgid,const char * path,const char * mode)127 static void global_open_error_msg(GLOBAL *g, int msgid, const char *path,
128 const char *mode)
129 {
130 int len, rno= (int)errno;
131 char errmsg[256]= "";
132
133 strncat(errmsg, strerror(errno), 255);
134
135 switch (msgid)
136 {
137 case MSGID_CANNOT_OPEN:
138 len= snprintf(g->Message, sizeof(g->Message) - 1,
139 MSG(CANNOT_OPEN), // Cannot open %s
140 path);
141 break;
142
143 case MSGID_OPEN_MODE_ERROR:
144 len= snprintf(g->Message, sizeof(g->Message) - 1,
145 MSG(OPEN_MODE_ERROR), // "Open(%s) error %d on %s"
146 mode, rno, path);
147 break;
148
149 case MSGID_OPEN_MODE_STRERROR:
150 {char fmt[256];
151 strcat(strcpy(fmt, MSG(OPEN_MODE_ERROR)), ": %s");
152 len= snprintf(g->Message, sizeof(g->Message) - 1,
153 fmt, // Open(%s) error %d on %s: %s
154 mode, rno, path, errmsg);
155 }break;
156
157 case MSGID_OPEN_STRERROR:
158 len= snprintf(g->Message, sizeof(g->Message) - 1,
159 MSG(OPEN_STRERROR), // "open error: %s"
160 errmsg);
161 break;
162
163 case MSGID_OPEN_ERROR_AND_STRERROR:
164 len= snprintf(g->Message, sizeof(g->Message) - 1,
165 //OPEN_ERROR does not work, as it wants mode %d (not %s)
166 //MSG(OPEN_ERROR) "%s",// "Open error %d in mode %d on %s: %s"
167 "Open error %d in mode %s on %s: %s",
168 rno, mode, path, errmsg);
169 break;
170
171 case MSGID_OPEN_EMPTY_FILE:
172 len= snprintf(g->Message, sizeof(g->Message) - 1,
173 MSG(OPEN_EMPTY_FILE), // "Opening empty file %s: %s"
174 path, errmsg);
175 break;
176
177 default:
178 DBUG_ASSERT(0);
179 /* Fall through*/
180 case 0:
181 len= 0;
182 }
183 g->Message[len]= '\0';
184 }
185
186
global_fopen(GLOBAL * g,int msgid,const char * path,const char * mode)187 FILE *global_fopen(GLOBAL *g, int msgid, const char *path, const char *mode)
188 {
189 FILE *f;
190 if (!(f= fopen(path, mode)))
191 global_open_error_msg(g, msgid, path, mode);
192 return f;
193 }
194
195
global_open(GLOBAL * g,int msgid,const char * path,int flags)196 int global_open(GLOBAL *g, int msgid, const char *path, int flags)
197 {
198 int h;
199 if ((h= open(path, flags)) <= 0)
200 global_open_error_msg(g, msgid, path, "");
201 return h;
202 }
203
204
global_open(GLOBAL * g,int msgid,const char * path,int flags,int mode)205 int global_open(GLOBAL *g, int msgid, const char *path, int flags, int mode)
206 {
207 int h;
208 if ((h= open(path, flags, mode)) <= 0)
209 {
210 char modestr[64];
211 snprintf(modestr, sizeof(modestr), "%d", mode);
212 global_open_error_msg(g, msgid, path, modestr);
213 }
214 return h;
215 }
216
SetTrc(void)217 DllExport void SetTrc(void)
218 {
219 // If tracing is on, debug must be initialized.
220 debug = pfile;
221 } // end of SetTrc
222
223 /**************************************************************************/
224 /* SubAllocate the result structure that will contain result data. */
225 /**************************************************************************/
PlgAllocResult(PGLOBAL g,int ncol,int maxres,int ids,int * buftyp,XFLD * fldtyp,unsigned int * length,bool blank,bool nonull)226 PQRYRES PlgAllocResult(PGLOBAL g, int ncol, int maxres, int ids,
227 int *buftyp, XFLD *fldtyp,
228 unsigned int *length, bool blank, bool nonull)
229 {
230 char cname[NAM_LEN+1];
231 int i;
232 PCOLRES *pcrp, crp;
233 PQRYRES qrp;
234
235 try {
236 /**********************************************************************/
237 /* Allocate the structure used to contain the result set. */
238 /**********************************************************************/
239 qrp = (PQRYRES)PlugSubAlloc(g, NULL, sizeof(QRYRES));
240 pcrp = &qrp->Colresp;
241 qrp->Continued = false;
242 qrp->Truncated = false;
243 qrp->Info = false;
244 qrp->Suball = true;
245 qrp->Maxres = maxres;
246 qrp->Maxsize = 0;
247 qrp->Nblin = 0;
248 qrp->Nbcol = 0; // will be ncol
249 qrp->Cursor = 0;
250 qrp->BadLines = 0;
251
252 for (i = 0; i < ncol; i++) {
253 *pcrp = (PCOLRES)PlugSubAlloc(g, NULL, sizeof(COLRES));
254 crp = *pcrp;
255 pcrp = &crp->Next;
256 memset(crp, 0, sizeof(COLRES));
257 crp->Colp = NULL;
258 crp->Ncol = ++qrp->Nbcol;
259 crp->Type = buftyp[i];
260 crp->Length = length[i];
261 crp->Clen = GetTypeSize(crp->Type, length[i]);
262 crp->Prec = 0;
263
264 if (ids > 0) {
265 #if defined(XMSG)
266 // Get header from message file
267 strncpy(cname, PlugReadMessage(g, ids + crp->Ncol, NULL), NAM_LEN);
268 cname[NAM_LEN] = 0; // for truncated long names
269 #else // !XMSG
270 GetRcString(ids + crp->Ncol, cname, sizeof(cname));
271 #endif // !XMSG
272 crp->Name = (PSZ)PlugDup(g, cname);
273 } else
274 crp->Name = NULL; // Will be set by caller
275
276 if (fldtyp)
277 crp->Fld = fldtyp[i];
278 else
279 crp->Fld = FLD_NO;
280
281 // Allocate the Value Block that will contain data
282 if (crp->Length || nonull)
283 crp->Kdata = AllocValBlock(g, NULL, crp->Type, maxres,
284 crp->Length, 0, true, blank, false);
285 else
286 crp->Kdata = NULL;
287
288 if (trace(1))
289 htrc("Column(%d) %s type=%d len=%d value=%p\n",
290 crp->Ncol, crp->Name, crp->Type, crp->Length, crp->Kdata);
291
292 } // endfor i
293
294 *pcrp = NULL;
295
296 } catch (int n) {
297 htrc("Exception %d: %s\n", n, g->Message);
298 qrp = NULL;
299 } catch (const char *msg) {
300 strcpy(g->Message, msg);
301 htrc("%s\n", g->Message);
302 qrp = NULL;
303 } // end catch
304
305 return qrp;
306 } // end of PlgAllocResult
307
308 /***********************************************************************/
309 /* Allocate and initialize the new DB User Block. */
310 /***********************************************************************/
PlgMakeUser(PGLOBAL g)311 PDBUSER PlgMakeUser(PGLOBAL g)
312 {
313 PDBUSER dbuserp;
314
315 if (!(dbuserp = (PDBUSER)malloc(sizeof(DBUSERBLK)))) {
316 sprintf(g->Message, MSG(MALLOC_ERROR), "PlgMakeUser");
317 return NULL;
318 } // endif dbuserp
319
320 memset(dbuserp, 0, sizeof(DBUSERBLK));
321 dbuserp->Maxbmp = MAXBMP;
322 //dbuserp->UseTemp = TMP_AUTO;
323 dbuserp->Check = CHK_ALL;
324 strcpy(dbuserp->Server, "CONNECT");
325 return dbuserp;
326 } // end of PlgMakeUser
327
328 /***********************************************************************/
329 /* PlgGetUser: returns DBUSER block pointer. */
330 /***********************************************************************/
PlgGetUser(PGLOBAL g)331 PDBUSER PlgGetUser(PGLOBAL g)
332 {
333 PDBUSER dup = (PDBUSER)((g->Activityp) ? g->Activityp->Aptr : NULL);
334
335 if (!dup)
336 strcpy(g->Message, MSG(APPL_NOT_INIT));
337
338 return dup;
339 } // end of PlgGetUser
340
341 /***********************************************************************/
342 /* PlgGetCatalog: returns CATALOG class pointer. */
343 /***********************************************************************/
PlgGetCatalog(PGLOBAL g,bool jump)344 PCATLG PlgGetCatalog(PGLOBAL g, bool jump)
345 {
346 PDBUSER dbuserp = PlgGetUser(g);
347 PCATLG cat = (dbuserp) ? dbuserp->Catalog : NULL;
348
349 if (!cat && jump) {
350 // Raise exception so caller doesn't have to check return value
351 strcpy(g->Message, MSG(NO_ACTIVE_DB));
352 throw 1;
353 } // endif cat
354
355 return cat;
356 } // end of PlgGetCatalog
357
358 #if 0
359 /***********************************************************************/
360 /* PlgGetDataPath: returns the default data path. */
361 /***********************************************************************/
362 char *PlgGetDataPath(PGLOBAL g)
363 {
364 PCATLG cat = PlgGetCatalog(g, false);
365
366 return (cat) ? cat->GetDataPath() : NULL;
367 } // end of PlgGetDataPath
368 #endif // 0
369
370 /***********************************************************************/
371 /* This function returns a database path. */
372 /***********************************************************************/
SetPath(PGLOBAL g,const char * path)373 char *SetPath(PGLOBAL g, const char *path)
374 {
375 char *buf= NULL;
376
377 if (path) {
378 size_t len = strlen(path) + (*path != '.' ? 4 : 1);
379
380 if (!(buf = (char*)PlgDBSubAlloc(g, NULL, len)))
381 return NULL;
382
383 if (PlugIsAbsolutePath(path)) {
384 strcpy(buf, path);
385 return buf;
386 } // endif path
387
388 if (*path != '.') {
389 #if defined(_WIN32)
390 const char *s = "\\";
391 #else // !_WIN32
392 const char *s = "/";
393 #endif // !_WIN32
394 strcat(strcat(strcat(strcpy(buf, "."), s), path), s);
395 } else
396 strcpy(buf, path);
397
398 } // endif path
399
400 return buf;
401 } // end of SetPath
402
403 /***********************************************************************/
404 /* Extract from a path name the required component. */
405 /* This function assumes there is enough space in the buffer. */
406 /***********************************************************************/
ExtractFromPath(PGLOBAL g,char * pBuff,char * FileName,OPVAL op)407 char *ExtractFromPath(PGLOBAL g, char *pBuff, char *FileName, OPVAL op)
408 {
409 char *drive = NULL, *direc = NULL, *fname = NULL, *ftype = NULL;
410
411 switch (op) { // Determine which part to extract
412 #if defined(_WIN32)
413 case OP_FDISK: drive = pBuff; break;
414 #endif // !UNIX
415 case OP_FPATH: direc = pBuff; break;
416 case OP_FNAME: fname = pBuff; break;
417 case OP_FTYPE: ftype = pBuff; break;
418 default:
419 sprintf(g->Message, MSG(INVALID_OPER), op, "ExtractFromPath");
420 return NULL;
421 } // endswitch op
422
423 // Now do the extraction
424 _splitpath(FileName, drive, direc, fname, ftype);
425 return pBuff;
426 } // end of PlgExtractFromPath
427
428 /***********************************************************************/
429 /* Check the occurence and matching of a pattern against a string. */
430 /* Because this function is only used for catalog name checking, */
431 /* it must be case insensitive. */
432 /***********************************************************************/
433 #ifdef NOT_USED
PlugCheckPattern(PGLOBAL g,LPCSTR string,LPCSTR pat)434 static bool PlugCheckPattern(PGLOBAL g, LPCSTR string, LPCSTR pat)
435 {
436 if (pat && strlen(pat)) {
437 // This leaves 2048 bytes (MAX_STR / 2) for each components
438 LPSTR name = g->Message + MAX_STR / 2;
439
440 strlwr(strcpy(name, string));
441 strlwr(strcpy(g->Message, pat)); // Can be modified by Eval
442 return EvalLikePattern(name, g->Message);
443 } else
444 return true;
445
446 } // end of PlugCheckPattern
447 #endif
448
449 /***********************************************************************/
450 /* PlugEvalLike: evaluates a LIKE clause. */
451 /* Syntaxe: M like P escape C. strg->M, pat->P, C not implemented yet */
452 /***********************************************************************/
PlugEvalLike(PGLOBAL g,LPCSTR strg,LPCSTR pat,bool ci)453 bool PlugEvalLike(PGLOBAL g, LPCSTR strg, LPCSTR pat, bool ci)
454 {
455 char *tp, *sp;
456 bool b;
457
458 if (trace(2))
459 htrc("LIKE: strg='%s' pattern='%s'\n", strg, pat);
460
461 if (ci) { /* Case insensitive test */
462 if (strlen(pat) + strlen(strg) + 1 < MAX_STR)
463 tp = g->Message;
464 else if (!(tp = new char[strlen(pat) + strlen(strg) + 2])) {
465 strcpy(g->Message, MSG(NEW_RETURN_NULL));
466 throw (int)OP_LIKE;
467 } /* endif tp */
468
469 sp = tp + strlen(pat) + 1;
470 strlwr(strcpy(tp, pat)); /* Make a lower case copy of pat */
471 strlwr(strcpy(sp, strg)); /* Make a lower case copy of strg */
472 } else { /* Case sensitive test */
473 if (strlen(pat) < MAX_STR) /* In most of the case for small pat */
474 tp = g->Message; /* Use this as temporary work space. */
475 else if (!(tp = new char[strlen(pat) + 1])) {
476 strcpy(g->Message, MSG(NEW_RETURN_NULL));
477 throw (int)OP_LIKE;
478 } /* endif tp */
479
480 strcpy(tp, pat); /* Make a copy to be worked into */
481 sp = (char*)strg;
482 } /* endif ci */
483
484 b = EvalLikePattern(sp, tp);
485
486 if (tp != g->Message) /* If working space was obtained */
487 delete [] tp; /* by the use of new, delete it. */
488
489 return (b);
490 } /* end of PlugEvalLike */
491
492 /***********************************************************************/
493 /* M and P are variable length character string. If M and P are zero */
494 /* length strings then the Like predicate is true. */
495 /* */
496 /* The Like predicate is true if: */
497 /* */
498 /* 1- A subtring of M is a sequence of 0 or more contiguous <CR> of M */
499 /* and each <CR> of M is part of exactly one substring. */
500 /* */
501 /* 2- If the i-th <subtring-specifyer> of P is an <arbitrary-char- */
502 /* specifier>, the i-th subtring of M is any single <CR>. */
503 /* */
504 /* 3- If the i-th <subtring-specifyer> of P is an <arbitrary-string- */
505 /* specifier>, then the i-th subtring of M is any sequence of zero */
506 /* or more <CR>. */
507 /* */
508 /* 4- If the i-th <subtring-specifyer> of P is neither an <arbitrary- */
509 /* character-specifier> nor an <arbitrary-string-specifier>, then */
510 /* the i-th substring of M is equal to that <substring-specifier> */
511 /* according to the collating sequence of the <like-predicate>, */
512 /* without the appending of <space-character>, and has the same */
513 /* length as that <substring-specifier>. */
514 /* */
515 /* 5- The number of substrings of M is equal to the number of */
516 /* <subtring-specifiers> of P. */
517 /* */
518 /* Otherwise M like P is false. */
519 /***********************************************************************/
EvalLikePattern(LPCSTR sp,LPCSTR tp)520 bool EvalLikePattern(LPCSTR sp, LPCSTR tp)
521 {
522 LPSTR p;
523 char c;
524 ssize_t n;
525 bool b, t = false;
526
527 if (trace(2))
528 htrc("Eval Like: sp=%s tp=%s\n",
529 (sp) ? sp : "Null", (tp) ? tp : "Null");
530
531 /********************************************************************/
532 /* If pattern is void, Like is true only if string is also void. */
533 /********************************************************************/
534 if (!*tp)
535 return (!*sp);
536
537 /********************************************************************/
538 /* Analyse eventual arbitrary specifications ahead of pattern. */
539 /********************************************************************/
540 for (p = (LPSTR)tp; p;)
541 switch (*p) { /* it can contain % and/or _ */
542 case '%': /* An % has been found */
543 t = true; /* Note eventual character skip */
544 p++;
545 break;
546 case '_': /* An _ has been found */
547 if (*sp) { /* If more character in string */
548 sp++; /* skip it */
549 p++;
550 } else
551 return false; /* Like condition is not met */
552
553 break;
554 default:
555 tp = p; /* Point to rest of template */
556 p = NULL; /* To stop For loop */
557 break;
558 } /* endswitch */
559
560 if ((p = (LPSTR)strpbrk(tp, "%_"))) /* Get position of next % or _ */
561 n = p - tp;
562 else
563 n = strlen(tp); /* Get length of pattern head */
564
565 if (trace(2))
566 htrc(" testing: t=%d sp=%s tp=%s p=%p\n", t, sp, tp, p);
567
568 if (n > (signed)strlen(sp)) /* If head is longer than strg */
569 b = false; /* Like condition is not met */
570 else if (n == 0) /* If void <substring-specifier> */
571 b = (t || !*sp); /* true if % or void strg. */
572 else if (!t) {
573 /*******************************************************************/
574 /* No character to skip, check occurence of <subtring-specifier> */
575 /* at the very beginning of remaining string. */
576 /*******************************************************************/
577 if (p) {
578 if ((b = !strncmp(sp, tp, n)))
579 b = EvalLikePattern(sp + n, p);
580
581 } else
582 b = !strcmp(sp, tp); /* strg and tmp heads match */
583
584 } else
585 if (p)
586 /*****************************************************************/
587 /* Here is the case explaining why we need a recursive routine. */
588 /* The test must be done not only against the first occurence */
589 /* of the <substring-specifier> in the remaining string, */
590 /* but also with all eventual succeeding ones. */
591 /*****************************************************************/
592 for (b = false, c = *p; !b && (signed)strlen(sp) >= n; sp++) {
593 *p = '\0'; /* Separate pattern header */
594
595 if ((sp = strstr(sp, tp))) {
596 *p = c;
597 b = EvalLikePattern(sp + n, p);
598 } else {
599 *p = c;
600 b = false;
601 break;
602 } /* endif s */
603
604 } /* endfor b, sp */
605
606 else {
607 sp += (strlen(sp) - n);
608 b = !strcmp(sp, tp);
609 } /* endif p */
610
611 if (trace(2))
612 htrc(" done: b=%d n=%d sp=%s tp=%s\n",
613 b, n, (sp) ? sp : "Null", tp);
614
615 return (b);
616 } /* end of EvalLikePattern */
617
618 /***********************************************************************/
619 /* MakeEscape: Escape some characters in a string. */
620 /***********************************************************************/
MakeEscape(PGLOBAL g,char * str,char q)621 char *MakeEscape(PGLOBAL g, char* str, char q)
622 {
623 char *bufp;
624 int i, k, n = 0, len = (int)strlen(str);
625
626 for (i = 0; i < len; i++)
627 if (str[i] == q || str[i] == '\\')
628 n++;
629
630 if (!n)
631 return str;
632 else
633 bufp = (char*)PlugSubAlloc(g, NULL, len + n + 1);
634
635 for (i = k = 0; i < len; i++) {
636 if (str[i] == q || str[i] == '\\')
637 bufp[k++] = '\\';
638
639 bufp[k++] = str[i];
640 } // endfor i
641
642 bufp[k] = 0;
643 return bufp;
644 } /* end of MakeEscape */
645
646 /***********************************************************************/
647 /* PlugConvertConstant: convert a Plug constant to an Xobject. */
648 /***********************************************************************/
PlugConvertConstant(PGLOBAL g,void * & value,short & type)649 void PlugConvertConstant(PGLOBAL g, void* & value, short& type)
650 {
651 if (trace(1))
652 htrc("PlugConvertConstant: value=%p type=%hd\n", value, type);
653
654 if (type != TYPE_XOBJECT) {
655 value = new(g) CONSTANT(g, value, type);
656 type = TYPE_XOBJECT;
657 } // endif type
658
659 } // end of PlugConvertConstant
660
661 /***********************************************************************/
662 /* Call the Flex preparser to convert a date format to a sscanf input */
663 /* format and a Strftime output format. Flag if not 0 indicates that */
664 /* non quoted blanks are not included in the output format. */
665 /***********************************************************************/
MakeDateFormat(PGLOBAL g,PCSZ dfmt,bool in,bool out,int flag)666 PDTP MakeDateFormat(PGLOBAL g, PCSZ dfmt, bool in, bool out, int flag)
667 {
668 int rc;
669 PDTP pdp = (PDTP)PlugSubAlloc(g, NULL, sizeof(DATPAR));
670
671 if (trace(1))
672 htrc("MakeDateFormat: dfmt=%s\n", dfmt);
673
674 memset(pdp, 0, sizeof(DATPAR));
675 pdp->Format = pdp->Curp = PlugDup(g, dfmt);
676 pdp->Outsize = 2 * strlen(dfmt) + 1;
677
678 if (in)
679 pdp->InFmt = (char*)PlugSubAlloc(g, NULL, pdp->Outsize);
680
681 if (out)
682 pdp->OutFmt = (char*)PlugSubAlloc(g, NULL, pdp->Outsize);
683
684 pdp->Flag = flag;
685
686 /*********************************************************************/
687 /* Call the FLEX generated parser. In multi-threading mode the next */
688 /* instruction is protected by mutex fmdflex using static variables. */
689 /*********************************************************************/
690 pthread_mutex_lock(&parmut);
691 rc = fmdflex(pdp);
692 pthread_mutex_unlock(&parmut);
693
694 if (trace(1))
695 htrc("Done: in=%s out=%s rc=%d\n", SVP(pdp->InFmt), SVP(pdp->OutFmt), rc);
696
697 return pdp;
698 } // end of MakeDateFormat
699
700 /***********************************************************************/
701 /* Extract the date from a formatted string according to format. */
702 /***********************************************************************/
ExtractDate(char * dts,PDTP pdp,int defy,int val[6])703 int ExtractDate(char *dts, PDTP pdp, int defy, int val[6])
704 {
705 PCSZ fmt;
706 char c, d, e, W[8][12];
707 int i, k, m, numval;
708 int n, y = 30;
709 bool b = true; // true for null dates
710
711 if (pdp)
712 fmt = pdp->InFmt;
713 else // assume standard MySQL date format
714 fmt = "%4d-%2d-%2d %2d:%2d:%2d";
715
716 if (trace(2))
717 htrc("ExtractDate: dts=%s fmt=%s defy=%d\n", dts, fmt, defy);
718
719 // Set default values for time only use
720 if (defy) {
721 // This may be a default value for year
722 y = defy;
723 val[0] = y;
724 y = (y < 100) ? y : 30;
725 } else
726 val[0] = 70;
727
728 val[1] = 1;
729 val[2] = 1;
730
731 for (i = 3; i < 6; i++)
732 val[i] = 0;
733
734 numval = 0;
735
736 // Get the date field parse it with derived input format
737 m = sscanf(dts, fmt, W[0], W[1], W[2], W[3], W[4], W[5], W[6], W[7]);
738
739 if (m > pdp->Num)
740 m = pdp->Num;
741
742 for (i = 0; i < m; i++) {
743 if ((n = *(int*)W[i]))
744 b = false;
745
746 switch (k = pdp->Index[i]) {
747 case 0:
748 if (n < y)
749 n += 100;
750
751 val[0] = n;
752 numval = MY_MAX(numval, 1);
753 break;
754 case 1:
755 case 2:
756 case 3:
757 case 4:
758 case 5:
759 val[k] = n;
760 numval = MY_MAX(numval, k + 1);
761 break;
762 case -1:
763 c = toupper(W[i][0]);
764 d = toupper(W[i][1]);
765 e = toupper(W[i][2]);
766
767 switch (c) {
768 case 'J':
769 n = (d == 'A') ? 1
770 : (e == 'N') ? 6 : 7; break;
771 case 'F': n = 2; break;
772 case 'M':
773 n = (e == 'R') ? 3 : 5; break;
774 case 'A':
775 n = (d == 'P') ? 4 : 8; break;
776 break;
777 case 'S': n = 9; break;
778 case 'O': n = 10; break;
779 case 'N': n = 11; break;
780 case 'D': n = 12; break;
781 } /* endswitch c */
782
783 val[1] = n;
784 numval = MY_MAX(numval, 2);
785 break;
786 case -6:
787 c = toupper(W[i][0]);
788 n = val[3] % 12;
789
790 if (c == 'P')
791 n += 12;
792
793 val[3] = n;
794 break;
795 } // endswitch Plugpar
796
797 } // endfor i
798
799 if (trace(2))
800 htrc("numval=%d val=(%d,%d,%d,%d,%d,%d)\n",
801 numval, val[0], val[1], val[2], val[3], val[4], val[5]);
802
803 return (b) ? 0 : numval;
804 } // end of ExtractDate
805
806 /***********************************************************************/
807 /* Open file routine: the purpose of this routine is to make a list */
808 /* of all open file so they can be closed in SQLINIT on error jump. */
809 /***********************************************************************/
PlugOpenFile(PGLOBAL g,LPCSTR fname,LPCSTR ftype)810 FILE *PlugOpenFile(PGLOBAL g, LPCSTR fname, LPCSTR ftype)
811 {
812 FILE *fop;
813 PFBLOCK fp;
814 PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
815
816 if (trace(1)) {
817 htrc("PlugOpenFile: fname=%s ftype=%s\n", fname, ftype);
818 htrc("dbuserp=%p\n", dbuserp);
819 } // endif trace
820
821 if ((fop= global_fopen(g, MSGID_OPEN_MODE_STRERROR, fname, ftype)) != NULL) {
822 if (trace(1))
823 htrc(" fop=%p\n", fop);
824
825 fp = (PFBLOCK)PlugSubAlloc(g, NULL, sizeof(FBLOCK));
826
827 if (trace(1))
828 htrc(" fp=%p\n", fp);
829
830 // fname may be in volatile memory such as stack
831 fp->Fname = PlugDup(g, fname);
832 fp->Count = 1;
833 fp->Type = TYPE_FB_FILE;
834 fp->File = fop;
835 fp->Mode = MODE_ANY; // ???
836 fp->Next = dbuserp->Openlist;
837 dbuserp->Openlist = fp;
838 } /* endif fop */
839
840 if (trace(1))
841 htrc(" returning fop=%p\n", fop);
842
843 return (fop);
844 } // end of PlugOpenFile
845
846 /***********************************************************************/
847 /* Close file routine: the purpose of this routine is to avoid */
848 /* double closing that freeze the system on some Unix platforms. */
849 /***********************************************************************/
PlugReopenFile(PGLOBAL g,PFBLOCK fp,LPCSTR md)850 FILE *PlugReopenFile(PGLOBAL g, PFBLOCK fp, LPCSTR md)
851 {
852 FILE *fop;
853
854 if ((fop = global_fopen(g, MSGID_OPEN_MODE_STRERROR, fp->Fname, md))) {
855 fp->Count = 1;
856 fp->Type = TYPE_FB_FILE;
857 fp->File = fop;
858 } /* endif fop */
859
860 return (fop);
861 } // end of PlugOpenFile
862
863 /***********************************************************************/
864 /* Close file routine: the purpose of this routine is to avoid */
865 /* double closing that freeze the system on some Unix platforms. */
866 /***********************************************************************/
PlugCloseFile(PGLOBAL g,PFBLOCK fp,bool all)867 int PlugCloseFile(PGLOBAL g, PFBLOCK fp, bool all)
868 {
869 int rc = 0;
870
871 if (trace(1))
872 htrc("PlugCloseFile: fp=%p count=%hd type=%hd\n",
873 fp, ((fp) ? fp->Count : 0), ((fp) ? fp->Type : 0));
874
875 if (!fp || !fp->Count)
876 return rc;
877
878 switch (fp->Type) {
879 case TYPE_FB_FILE:
880 if (fclose((FILE *)fp->File) == EOF)
881 rc = errno;
882
883 fp->File = NULL;
884 fp->Mode = MODE_ANY;
885 fp->Count = 0;
886 break;
887 case TYPE_FB_MAP:
888 if ((fp->Count = (all) ? 0 : fp->Count - 1))
889 break;
890
891 if (CloseMemMap(fp->Memory, fp->Length))
892 rc = (int)GetLastError();
893
894 fp->Memory = NULL;
895 fp->Mode = MODE_ANY;
896 // fall through
897 case TYPE_FB_HANDLE:
898 if (fp->Handle && fp->Handle != INVALID_HANDLE_VALUE)
899 if (CloseFileHandle(fp->Handle))
900 rc = (rc) ? rc : (int)GetLastError();
901
902 fp->Handle = INVALID_HANDLE_VALUE;
903 fp->Mode = MODE_ANY;
904 fp->Count = 0;
905 break;
906 #ifdef DOMDOC_SUPPORT
907 case TYPE_FB_XML:
908 CloseXMLFile(g, fp, all);
909 break;
910 #endif // DOMDOC_SUPPORT
911 #ifdef LIBXML2_SUPPORT
912 case TYPE_FB_XML2:
913 CloseXML2File(g, fp, all);
914 break;
915 #endif // LIBXML2_SUPPORT
916 #ifdef ODBC_SUPPORT
917 case TYPE_FB_ODBC:
918 OdbcClose(g, fp);
919 fp->Count = 0;
920 fp->File = NULL;
921 break;
922 #endif // ODBC_SUPPORT
923 #ifdef ZIP_SUPPORT
924 case TYPE_FB_ZIP:
925 if (fp->Mode == MODE_INSERT)
926 ((ZIPUTIL*)fp->File)->close();
927 else
928 ((UNZIPUTL*)fp->File)->close();
929
930 fp->Memory = NULL;
931 fp->Mode = MODE_ANY;
932 fp->Count = 0;
933 fp->File = NULL;
934 break;
935 #endif // ZIP_SUPPORT
936 #ifdef JAVA_SUPPORT
937 case TYPE_FB_JAVA:
938 ((JAVAConn*)fp->File)->Close();
939 fp->Count = 0;
940 fp->File = NULL;
941 break;
942 #endif // JAVA_SUPPORT
943 #ifdef CMGO_SUPPORT
944 case TYPE_FB_MONGO:
945 ((CMgoConn*)fp->File)->Close();
946 fp->Count = 0;
947 fp->File = NULL;
948 break;
949 #endif // JAVA_SUPPORT
950 default:
951 rc = RC_FX;
952 } // endswitch Type
953
954 return rc;
955 } // end of PlugCloseFile
956
957 /***********************************************************************/
958 /* PlugCleanup: Cleanup remaining items of a SQL query. */
959 /***********************************************************************/
PlugCleanup(PGLOBAL g,bool dofree)960 void PlugCleanup(PGLOBAL g, bool dofree)
961 {
962 PCATLG cat;
963 PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
964
965 // The test on Catalog is to avoid a Windows bug that can make
966 // LoadString in PlugGetMessage to fail in some case
967 if (!dbuserp || !(cat = dbuserp->Catalog))
968 return;
969
970 /*********************************************************************/
971 /* Close eventually still open/mapped files. */
972 /*********************************************************************/
973 for (PFBLOCK fp = dbuserp->Openlist; fp; fp = fp->Next)
974 PlugCloseFile(g, fp, true);
975
976 dbuserp->Openlist = NULL;
977
978 if (dofree) {
979 /*******************************************************************/
980 /* Cleanup any non suballocated memory still not freed. */
981 /*******************************************************************/
982 for (PMBLOCK mp = dbuserp->Memlist; mp; mp = mp->Next)
983 PlgDBfree(*mp);
984
985 dbuserp->Memlist = NULL;
986
987 /*******************************************************************/
988 /* If not using permanent storage catalog, reset volatile values. */
989 /*******************************************************************/
990 cat->Reset();
991
992 /*******************************************************************/
993 /* This is the place to reset the pointer on domains. */
994 /*******************************************************************/
995 dbuserp->Subcor = false;
996 dbuserp->Step = "New query"; // was STEP(PARSING_QUERY);
997 dbuserp->ProgMax = dbuserp->ProgCur = dbuserp->ProgSav = 0;
998 } // endif dofree
999
1000 } // end of PlugCleanup
1001
1002 #if 0
1003 /***********************************************************************/
1004 /* That stupid Windows 98 does not provide this function. */
1005 /***********************************************************************/
1006 bool WritePrivateProfileInt(LPCSTR sec, LPCSTR key, int n, LPCSTR ini)
1007 {
1008 char buf[12];
1009
1010 sprintf(buf, "%d", n);
1011 return WritePrivateProfileString(sec, key, buf, ini);
1012 } // end of WritePrivateProfileInt
1013
1014 /***********************************************************************/
1015 /* Retrieve a size from an INI file with eventual K or M following. */
1016 /***********************************************************************/
1017 int GetIniSize(char *section, char *key, char *def, char *ini)
1018 {
1019 char c, buff[32];
1020 int i;
1021 int n = 0;
1022
1023 GetPrivateProfileString(section, key, def, buff, sizeof(buff), ini);
1024
1025 if ((i = sscanf(buff, " %d %c ", &n, &c)) == 2)
1026 switch (toupper(c)) {
1027 case 'M':
1028 n *= 1024;
1029 case 'K':
1030 n *= 1024;
1031 } // endswitch c
1032
1033 if (trace(1))
1034 htrc("GetIniSize: key=%s buff=%s i=%d n=%d\n", key, buff, i, n);
1035
1036 return n;
1037 } // end of GetIniSize
1038
1039 /***********************************************************************/
1040 /* Allocate a string retrieved from an INI file and return its address */
1041 /***********************************************************************/
1042 DllExport PSZ GetIniString(PGLOBAL g, void *mp, LPCSTR sec, LPCSTR key,
1043 LPCSTR def, LPCSTR ini)
1044 {
1045 char buff[_MAX_PATH];
1046 PSZ p;
1047 int n, m = sizeof(buff);
1048 char *buf = buff;
1049
1050 #if defined(_DEBUG)
1051 assert (sec && key);
1052 #endif
1053
1054 again:
1055 n = GetPrivateProfileString(sec, key, def, buf, m, ini);
1056
1057 if (n == m - 1) {
1058 // String may have been truncated, make sure to have all
1059 if (buf != buff)
1060 delete [] buf;
1061
1062 m *= 2;
1063 buf = new char[m];
1064 goto again;
1065 } // endif n
1066
1067 p = (PSZ)PlugSubAlloc(g, mp, n + 1);
1068
1069 if (trace(1))
1070 htrc("GetIniString: sec=%s key=%s buf=%s\n", sec, key, buf);
1071
1072 strcpy(p, buf);
1073
1074 if (buf != buff)
1075 delete [] buf;
1076
1077 return p;
1078 } // end of GetIniString
1079 #endif // 0
1080
1081 /***********************************************************************/
1082 /* GetAmName: return the name correponding to an AM code. */
1083 /***********************************************************************/
GetAmName(PGLOBAL g,AMT am,void * memp)1084 char *GetAmName(PGLOBAL g, AMT am, void *memp)
1085 {
1086 char *amn= (char*)PlugSubAlloc(g, memp, 16);
1087
1088 switch (am) {
1089 case TYPE_AM_ERROR: strcpy(amn, "ERROR"); break;
1090 case TYPE_AM_ROWID: strcpy(amn, "ROWID"); break;
1091 case TYPE_AM_FILID: strcpy(amn, "FILID"); break;
1092 case TYPE_AM_VIEW: strcpy(amn, "VIEW"); break;
1093 case TYPE_AM_COUNT: strcpy(amn, "COUNT"); break;
1094 case TYPE_AM_DCD: strcpy(amn, "DCD"); break;
1095 case TYPE_AM_CMS: strcpy(amn, "CMS"); break;
1096 case TYPE_AM_MAP: strcpy(amn, "MAP"); break;
1097 case TYPE_AM_FMT: strcpy(amn, "FMT"); break;
1098 case TYPE_AM_CSV: strcpy(amn, "CSV"); break;
1099 case TYPE_AM_MCV: strcpy(amn, "MCV"); break;
1100 case TYPE_AM_DOS: strcpy(amn, "DOS"); break;
1101 case TYPE_AM_FIX: strcpy(amn, "FIX"); break;
1102 case TYPE_AM_BIN: strcpy(amn, "BIN"); break;
1103 case TYPE_AM_VCT: strcpy(amn, "VEC"); break;
1104 case TYPE_AM_VMP: strcpy(amn, "VMP"); break;
1105 case TYPE_AM_DBF: strcpy(amn, "DBF"); break;
1106 case TYPE_AM_QRY: strcpy(amn, "QRY"); break;
1107 case TYPE_AM_SQL: strcpy(amn, "SQL"); break;
1108 case TYPE_AM_PLG: strcpy(amn, "PLG"); break;
1109 case TYPE_AM_PLM: strcpy(amn, "PLM"); break;
1110 case TYPE_AM_DOM: strcpy(amn, "DOM"); break;
1111 case TYPE_AM_DIR: strcpy(amn, "DIR"); break;
1112 case TYPE_AM_ODBC: strcpy(amn, "ODBC"); break;
1113 case TYPE_AM_JDBC: strcpy(amn, "JDBC"); break;
1114 case TYPE_AM_MAC: strcpy(amn, "MAC"); break;
1115 case TYPE_AM_OEM: strcpy(amn, "OEM"); break;
1116 case TYPE_AM_OUT: strcpy(amn, "OUT"); break;
1117 default: sprintf(amn, "OEM(%d)", am);
1118 } // endswitch am
1119
1120 return amn;
1121 } // end of GetAmName
1122
1123 #if defined(SE_CATCH)
1124 /***********************************************************************/
1125 /* GetExceptionDesc: return the description of an exception code. */
1126 /***********************************************************************/
GetExceptionDesc(PGLOBAL g,unsigned int e)1127 char *GetExceptionDesc(PGLOBAL g, unsigned int e)
1128 {
1129 char *p;
1130
1131 switch (e) {
1132 case EXCEPTION_GUARD_PAGE:
1133 p = MSG(GUARD_PAGE);
1134 break;
1135 case EXCEPTION_DATATYPE_MISALIGNMENT:
1136 p = MSG(DATA_MISALIGN);
1137 break;
1138 case EXCEPTION_BREAKPOINT:
1139 p = MSG(BREAKPOINT);
1140 break;
1141 case EXCEPTION_SINGLE_STEP:
1142 p = MSG(SINGLE_STEP);
1143 break;
1144 case EXCEPTION_ACCESS_VIOLATION:
1145 p = MSG(ACCESS_VIOLATN);
1146 break;
1147 case EXCEPTION_IN_PAGE_ERROR:
1148 p = MSG(PAGE_ERROR);
1149 break;
1150 case EXCEPTION_INVALID_HANDLE:
1151 p = MSG(INVALID_HANDLE);
1152 break;
1153 case EXCEPTION_ILLEGAL_INSTRUCTION:
1154 p = MSG(ILLEGAL_INSTR);
1155 break;
1156 case EXCEPTION_NONCONTINUABLE_EXCEPTION:
1157 p = MSG(NONCONT_EXCEPT);
1158 break;
1159 case EXCEPTION_INVALID_DISPOSITION:
1160 p = MSG(INVALID_DISP);
1161 break;
1162 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
1163 p = MSG(ARRAY_BNDS_EXCD);
1164 break;
1165 case EXCEPTION_FLT_DENORMAL_OPERAND:
1166 p = MSG(FLT_DENORMAL_OP);
1167 break;
1168 case EXCEPTION_FLT_DIVIDE_BY_ZERO:
1169 p = MSG(FLT_ZERO_DIVIDE);
1170 break;
1171 case EXCEPTION_FLT_INEXACT_RESULT:
1172 p = MSG(FLT_BAD_RESULT);
1173 break;
1174 case EXCEPTION_FLT_INVALID_OPERATION:
1175 p = MSG(FLT_INVALID_OP);
1176 break;
1177 case EXCEPTION_FLT_OVERFLOW:
1178 p = MSG(FLT_OVERFLOW);
1179 break;
1180 case EXCEPTION_FLT_STACK_CHECK:
1181 p = MSG(FLT_STACK_CHECK);
1182 break;
1183 case EXCEPTION_FLT_UNDERFLOW:
1184 p = MSG(FLT_UNDERFLOW);
1185 break;
1186 case EXCEPTION_INT_DIVIDE_BY_ZERO:
1187 p = MSG(INT_ZERO_DIVIDE);
1188 break;
1189 case EXCEPTION_INT_OVERFLOW:
1190 p = MSG(INT_OVERFLOW);
1191 break;
1192 case EXCEPTION_PRIV_INSTRUCTION:
1193 p = MSG(PRIV_INSTR);
1194 break;
1195 case EXCEPTION_STACK_OVERFLOW:
1196 p = MSG(STACK_OVERFLOW);
1197 break;
1198 case CONTROL_C_EXIT:
1199 p = MSG(CONTROL_C_EXIT);
1200 break;
1201 case STATUS_NO_MEMORY:
1202 p = MSG(NO_MEMORY);
1203 break;
1204 default:
1205 p = MSG(UNKNOWN_EXCPT);
1206 break;
1207 } // endswitch nSE
1208
1209 return p;
1210 } // end of GetExceptionDesc
1211 #endif // SE_CATCH
1212
1213 /***********************************************************************/
1214 /* PlgDBalloc: allocates or suballocates memory conditionally. */
1215 /* If mp.Sub is true at entry, this forces suballocation. */
1216 /* If the memory is allocated, makes an entry in an allocation list */
1217 /* so it can be freed at the normal or error query completion. */
1218 /***********************************************************************/
PlgDBalloc(PGLOBAL g,void * area,MBLOCK & mp)1219 void *PlgDBalloc(PGLOBAL g, void *area, MBLOCK& mp)
1220 {
1221 //bool b;
1222 size_t maxsub, minsub;
1223 void *arp = (area) ? area : g->Sarea;
1224 PPOOLHEADER pph = (PPOOLHEADER)arp;
1225
1226 if (mp.Memp) {
1227 // This is a reallocation. If this block is not suballocated, it
1228 // was already placed in the chain of memory blocks and we must
1229 // not do it again as it can trigger a loop when freeing them.
1230 // Note: this works if blocks can be reallocated only once.
1231 // Otherwise a new boolean must be added to the block that
1232 // indicate that it is chained, or a test on the whole chain be
1233 // done to check whether the block is already there.
1234 // b = mp.Sub;
1235 mp.Sub = false; // Restrict suballocation to one quarter
1236 } // endif Memp
1237
1238 // Suballoc when possible if mp.Sub is initially true, but leaving
1239 // a minimum amount of storage for future operations such as the
1240 // optimize recalculation after insert; otherwise
1241 // suballoc only if size is smaller than one quarter of free mem.
1242 minsub = (pph->FreeBlk + pph->To_Free + 524248) >> 2;
1243 maxsub = (pph->FreeBlk < minsub) ? 0 : pph->FreeBlk - minsub;
1244 mp.Sub = mp.Size <= ((mp.Sub) ? maxsub : (maxsub >> 2));
1245
1246 if (trace(2))
1247 htrc("PlgDBalloc: in %p size=%zd used=%zd free=%zd sub=%d\n",
1248 arp, mp.Size, pph->To_Free, pph->FreeBlk, mp.Sub);
1249
1250 if (!mp.Sub) {
1251 // For allocations greater than one fourth of remaining storage
1252 // in the area, do allocate from virtual storage.
1253 const char*v = "malloc";
1254 #if defined(_WIN32)
1255 if (mp.Size >= BIGMEM) {
1256 v = "VirtualAlloc";
1257 mp.Memp = VirtualAlloc(NULL, mp.Size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
1258 } else
1259 #endif
1260 mp.Memp = malloc(mp.Size);
1261
1262 if (trace(8))
1263 htrc("PlgDBalloc: %s(%zd) at %p\n", v, mp.Size, mp.Memp);
1264
1265 if (!mp.Inlist && mp.Memp) {
1266 // New allocated block, put it in the memory block chain.
1267 PDBUSER dbuserp = (PDBUSER)g->Activityp->Aptr;
1268
1269 mp.Next = dbuserp->Memlist;
1270 dbuserp->Memlist = ∓
1271 mp.Inlist = true;
1272 } // endif mp
1273
1274 } else
1275 // Suballocating is Ok.
1276 mp.Memp = PlugSubAlloc(g, area, mp.Size);
1277
1278 return mp.Memp;
1279 } // end of PlgDBalloc
1280
1281 /***********************************************************************/
1282 /* PlgDBrealloc: reallocates memory conditionally. */
1283 /* Note that this routine can fail only when block size is increased */
1284 /* because otherwise we keep the old storage on failure. */
1285 /***********************************************************************/
PlgDBrealloc(PGLOBAL g,void * area,MBLOCK & mp,size_t newsize)1286 void *PlgDBrealloc(PGLOBAL g, void *area, MBLOCK& mp, size_t newsize)
1287 {
1288 MBLOCK m;
1289
1290 #if defined(_DEBUG)
1291 // assert (mp.Memp != NULL);
1292 #endif
1293
1294 if (trace(2))
1295 htrc("PlgDBrealloc: %p size=%zd sub=%d\n", mp.Memp, mp.Size, mp.Sub);
1296
1297 if (newsize == mp.Size)
1298 return mp.Memp; // Nothing to do
1299 else
1300 m = mp;
1301
1302 if (!mp.Sub && mp.Size < BIGMEM && newsize < BIGMEM) {
1303 // Allocation was done by malloc, try to use realloc but
1304 // suballoc if newsize is smaller than one quarter of free mem.
1305 size_t maxsub;
1306 PPOOLHEADER pph = (PPOOLHEADER)((area) ? area : g->Sarea);
1307
1308 maxsub = (pph->FreeBlk < 131072) ? 0 : pph->FreeBlk - 131072;
1309
1310 if ((mp.Sub = (newsize <= (maxsub >> 2)))) {
1311 mp.Memp = PlugSubAlloc(g, area, newsize);
1312 memcpy(mp.Memp, m.Memp, MY_MIN(m.Size, newsize));
1313 PlgDBfree(m); // Free the old block
1314 } else {
1315 if (!(mp.Memp = realloc(mp.Memp, newsize))) {
1316 mp = m; // Possible only if newsize > Size
1317 return NULL; // Failed
1318 } else if (trace(8))
1319 htrc("PlgDBrealloc: realloc(%ld) at %p\n", newsize, mp.Memp);
1320
1321 } // endif's
1322
1323 mp.Size = newsize;
1324 } else if (!mp.Sub || newsize > mp.Size) {
1325 // Was suballocated or Allocation was done by VirtualAlloc
1326 // Make a new allocation and copy the useful part
1327 // Note: DO NOT reset Memp and Sub so we know that this
1328 // is a reallocation in PlgDBalloc
1329 mp.Size = newsize;
1330
1331 if (PlgDBalloc(g, area, mp)) {
1332 memcpy(mp.Memp, m.Memp, MY_MIN(m.Size, newsize));
1333 PlgDBfree(m); // Free the old block
1334 } else {
1335 mp = m; // No space to realloc, do nothing
1336
1337 if (newsize > m.Size)
1338 return NULL; // Failed
1339
1340 } // endif PlgDBalloc
1341
1342 } // endif's
1343
1344 if (trace(8))
1345 htrc(" newsize=%zd newp=%p sub=%d\n", mp.Size, mp.Memp, mp.Sub);
1346
1347 return mp.Memp;
1348 } // end of PlgDBrealloc
1349
1350 /***********************************************************************/
1351 /* PlgDBfree: free memory if not suballocated. */
1352 /***********************************************************************/
PlgDBfree(MBLOCK & mp)1353 void PlgDBfree(MBLOCK& mp)
1354 {
1355 if (!mp.Sub && mp.Memp) {
1356 const char*v = "free";
1357 #if defined(_WIN32)
1358 if (mp.Size >= BIGMEM) {
1359 v = "VirtualFree";
1360 VirtualFree(mp.Memp, 0, MEM_RELEASE);
1361 } else
1362 #endif
1363 free(mp.Memp);
1364
1365 if (trace(8))
1366 htrc("PlgDBfree: %s(%p) size=%d\n", v, mp.Memp, mp.Size);
1367
1368 } // endif mp
1369
1370 // Do not reset Next to avoid cutting the Mblock chain
1371 mp.Memp = NULL;
1372 mp.Sub = false;
1373 mp.Size = 0;
1374 } // end of PlgDBfree
1375
1376 /***********************************************************************/
1377 /* Program for sub-allocating one item in a storage area. */
1378 /* Note: This function is equivalent to PlugSubAlloc except that in */
1379 /* case of insufficient memory, it returns NULL instead of doing a */
1380 /* throw. The caller must test the return value for error. */
1381 /***********************************************************************/
PlgDBSubAlloc(PGLOBAL g,void * memp,size_t size)1382 void *PlgDBSubAlloc(PGLOBAL g, void *memp, size_t size)
1383 {
1384 PPOOLHEADER pph; // Points on area header.
1385
1386 if (!memp)
1387 /*******************************************************************/
1388 /* Allocation is to be done in the Sarea. */
1389 /*******************************************************************/
1390 memp = g->Sarea;
1391
1392 //size = ((size + 3) / 4) * 4; /* Round up size to multiple of 4 */
1393 size = ((size + 7) / 8) * 8; /* Round up size to multiple of 8 */
1394 pph = (PPOOLHEADER)memp;
1395
1396 if (trace(16))
1397 htrc("PlgDBSubAlloc: memp=%p size=%zd used=%zd free=%zd\n",
1398 memp, size, pph->To_Free, pph->FreeBlk);
1399
1400 if (size > pph->FreeBlk) { /* Not enough memory left in pool */
1401 sprintf(g->Message,
1402 "Not enough memory in Work area for request of %zd (used=%zd free=%zd)",
1403 size, pph->To_Free, pph->FreeBlk);
1404
1405 if (trace(1))
1406 htrc("%s\n", g->Message);
1407
1408 return NULL;
1409 } // endif size
1410
1411 /*********************************************************************/
1412 /* Do the suballocation the simplest way. */
1413 /*********************************************************************/
1414 memp = MakePtr(memp, pph->To_Free); // Points to suballocated block
1415 pph->To_Free += size; // New offset of pool free block
1416 pph->FreeBlk -= size; // New size of pool free block
1417
1418 if (trace(16))
1419 htrc("Done memp=%p used=%zd free=%zd\n",
1420 memp, pph->To_Free, pph->FreeBlk);
1421
1422 return (memp);
1423 } // end of PlgDBSubAlloc
1424
1425 /***********************************************************************/
1426 /* Program for sub-allocating and copying a string in a storage area. */
1427 /***********************************************************************/
PlgDBDup(PGLOBAL g,const char * str)1428 char *PlgDBDup(PGLOBAL g, const char *str)
1429 {
1430 if (str) {
1431 char *sm = (char*)PlgDBSubAlloc(g, NULL, strlen(str) + 1);
1432
1433 if (sm)
1434 strcpy(sm, str);
1435
1436 return sm;
1437 } else
1438 return NULL;
1439
1440 } // end of PlgDBDup
1441
1442 /***********************************************************************/
1443 /* PUTOUT: Plug DB object typing routine. */
1444 /***********************************************************************/
PlugPutOut(PGLOBAL g,FILE * f,short t,void * v,uint n)1445 void PlugPutOut(PGLOBAL g, FILE *f, short t, void *v, uint n)
1446 {
1447 char m[64];
1448
1449 if (trace(1))
1450 htrc("PUTOUT: f=%p t=%d v=%p n=%d\n", f, t, v, n);
1451
1452 if (!v)
1453 return;
1454
1455 memset(m, ' ', n); /* Make margin string */
1456 m[n] = '\0';
1457 n += 2; /* Increase margin */
1458
1459 switch (t) {
1460 case TYPE_ERROR:
1461 fprintf(f, "--> %s\n", (PSZ)v);
1462 break;
1463
1464 case TYPE_STRING:
1465 case TYPE_PSZ:
1466 fprintf(f, "%s%s\n", m, (PSZ)v);
1467 break;
1468
1469 case TYPE_DOUBLE:
1470 fprintf(f, "%s%lf\n", m, *(double *)v);
1471 break;
1472
1473 case TYPE_LIST:
1474 case TYPE_COLIST:
1475 case TYPE_COL:
1476 {PPARM p;
1477
1478 if (t == TYPE_LIST)
1479 fprintf(f, "%s%s\n", m, MSG(LIST));
1480 else
1481 fprintf(f, "%s%s\n", m, "Colist:");
1482
1483 for (p = (PPARM)v; p; p = p->Next)
1484 PlugPutOut(g, f, p->Type, p->Value, n);
1485
1486 } break;
1487
1488 case TYPE_INT:
1489 fprintf(f, "%s%d\n", m, *(int *)v);
1490 break;
1491
1492 case TYPE_SHORT:
1493 fprintf(f, "%s%hd\n", m, *(short *)v);
1494 break;
1495
1496 case TYPE_TINY:
1497 fprintf(f, "%s%d\n", m, (int)*(char *)v);
1498 break;
1499
1500 case TYPE_VOID:
1501 break;
1502
1503 case TYPE_SQL:
1504 case TYPE_TABLE:
1505 case TYPE_TDB:
1506 case TYPE_XOBJECT:
1507 ((PBLOCK)v)->Printf(g, f, n-2);
1508 break;
1509
1510 default:
1511 fprintf(f, "%s%s %d\n", m, MSG(ANSWER_TYPE), t);
1512 } /* endswitch */
1513
1514 return;
1515 } /* end of PlugPutOut */
1516
1517 /***********************************************************************/
1518 /* NewPointer: makes a table of pointer values to be changed later. */
1519 /***********************************************************************/
NewPointer(PTABS t,void * oldv,void * newv)1520 DllExport void NewPointer(PTABS t, void *oldv, void *newv)
1521 {
1522 PTABPTR tp;
1523
1524 if (!oldv) /* error ?????????? */
1525 return;
1526
1527 if (!t->P1 || t->P1->Num == 50)
1528 {
1529 if (!(tp = new TABPTR)) {
1530 PGLOBAL g = t->G;
1531
1532 sprintf(g->Message, "NewPointer: %s", MSG(MEM_ALLOC_ERROR));
1533 throw 3;
1534 } else {
1535 tp->Next = t->P1;
1536 tp->Num = 0;
1537 t->P1 = tp;
1538 } /* endif tp */
1539 }
1540
1541 t->P1->Old[t->P1->Num] = oldv;
1542 t->P1->New[t->P1->Num++] = newv;
1543 } /* end of NewPointer */
1544
1545 #if 0
1546 /***********************************************************************/
1547 /* Compare two files and return 0 if they are identical, else 1. */
1548 /***********************************************************************/
1549 int FileComp(PGLOBAL g, char *file1, char *file2)
1550 {
1551 char *fn[2], *bp[2], buff1[4096], buff2[4096];
1552 int i, k, n[2], h[2] = {-1,-1};
1553 int len[2], rc = -1;
1554
1555 fn[0] = file1; fn[1] = file2;
1556 bp[0] = buff1; bp[1] = buff2;
1557
1558 for (i = 0; i < 2; i++) {
1559 #if defined(_WIN32)
1560 h[i]= global_open(g, MSGID_NONE, fn[i], _O_RDONLY | _O_BINARY);
1561 #else // !_WIN32
1562 h[i]= global_open(g, MSGOD_NONE, fn[i], O_RDONLY);
1563 #endif // !_WIN32
1564
1565 if (h[i] == -1) {
1566 // if (errno != ENOENT) {
1567 sprintf(g->Message, MSG(OPEN_MODE_ERROR),
1568 "rb", (int)errno, fn[i]);
1569 strcat(strcat(g->Message, ": "), strerror(errno));
1570 throw 666;
1571 // } else
1572 // len[i] = 0; // File does not exist yet
1573
1574 } else {
1575 if ((len[i] = _filelength(h[i])) < 0) {
1576 sprintf(g->Message, MSG(FILELEN_ERROR), "_filelength", fn[i]);
1577 throw 666;
1578 } // endif len
1579
1580 } // endif h
1581
1582 } // endfor i
1583
1584 if (len[0] != len[1])
1585 rc = 1;
1586
1587 while (rc == -1) {
1588 for (i = 0; i < 2; i++)
1589 if ((n[i] = read(h[i], bp[i], 4096)) < 0) {
1590 sprintf(g->Message, MSG(READ_ERROR), fn[i], strerror(errno));
1591 goto fin;
1592 } // endif n
1593
1594 if (n[0] != n[1])
1595 rc = 1;
1596 else if (*n == 0)
1597 rc = 0;
1598 else for (k = 0; k < *n; k++)
1599 if (*(bp[0] + k) != *(bp[1] + k)) {
1600 rc = 1;
1601 goto fin;
1602 } // endif bp
1603
1604 } // endwhile
1605
1606 fin:
1607 for (i = 0; i < 2; i++)
1608 if (h[i] != -1)
1609 close(h[i]);
1610
1611 return rc;
1612 } // end of FileComp
1613 #endif // 0
1614