1/************* Tabxml C++ Program Source Code File (.CPP) **************/
2/* PROGRAM NAME: TABXML */
3/* ------------- */
4/* Version 3.0 */
5/* */
6/* Author Olivier BERTRAND 2007 - 2017 */
7/* */
8/* This program are the XML tables classes using MS-DOM or libxml2. */
9/***********************************************************************/
10
11/***********************************************************************/
12/* Include required compiler header files. */
13/***********************************************************************/
14#include "my_global.h"
15#include <stdio.h>
16#include <fcntl.h>
17#include <errno.h>
18#if defined(__WIN__)
19#include <io.h>
20#include <winsock2.h>
21//#include <windows.h>
22#include <comdef.h>
23#else // !__WIN__
24#include <sys/types.h>
25#include <sys/socket.h>
26#include <netinet/in.h>
27#include <unistd.h>
28//#include <ctype.h>
29#include "osutil.h"
30#define _O_RDONLY O_RDONLY
31#endif // !__WIN__
32#include "resource.h" // for IDS_COLUMNS
33
34#define INCLUDE_TDBXML
35#define NODE_TYPE_LIST
36
37/***********************************************************************/
38/* Include application header files: */
39/* global.h is header containing all global declarations. */
40/* plgdbsem.h is header containing the DB application declarations. */
41/* tabdos.h is header containing the TABDOS class declarations. */
42/***********************************************************************/
43#include "global.h"
44#include "plgdbsem.h"
45//#include "reldef.h"
46#include "xtable.h"
47#include "colblk.h"
48#include "mycat.h"
49#include "xindex.h"
50#include "plgxml.h"
51#include "tabxml.h"
52#include "tabmul.h"
53
54extern "C" char version[];
55
56#if defined(__WIN__) && defined(DOMDOC_SUPPORT)
57#define XMLSUP "MS-DOM"
58#else // !__WIN__
59#define XMLSUP "libxml2"
60#endif // !__WIN__
61
62#define TYPE_UNKNOWN 12 /* Must be greater than other types */
63#define XLEN(M) sizeof(M) - strlen(M) - 1 /* To avoid overflow*/
64
65/***********************************************************************/
66/* Class and structure used by XMLColumns. */
67/***********************************************************************/
68typedef class XMCOL *PXCL;
69
70class XMCOL : public BLOCK {
71 public:
72 // Constructors
73 XMCOL(void) {Next = NULL;
74 Name[0] = 0;
75 Fmt = NULL;
76 Type = 1;
77 Len = Scale = 0;
78 Cbn = false;
79 Found = true;}
80 XMCOL(PGLOBAL g, PXCL xp, char *fmt, int i) {
81 Next = NULL;
82 strcpy(Name, xp->Name);
83 Fmt = (*fmt) ? PlugDup(g, fmt) : NULL;
84 Type = xp->Type;
85 Len = xp->Len;
86 Scale = xp->Scale;
87 Cbn = (xp->Cbn || i > 1);
88 Found = true;}
89
90 // Members
91 PXCL Next;
92 char Name[64];
93 char *Fmt;
94 int Type;
95 int Len;
96 int Scale;
97 bool Cbn;
98 bool Found;
99}; // end of class XMCOL
100
101typedef struct LVL {
102 PXNODE pn;
103 PXLIST nl;
104 PXATTR atp;
105 bool b;
106 long k;
107 int m, n;
108} *PLVL;
109
110/***********************************************************************/
111/* XMLColumns: construct the result blocks containing the description */
112/* of all the columns of a table contained inside an XML file. */
113/***********************************************************************/
114PQRYRES XMLColumns(PGLOBAL g, char *db, char *tab, PTOS topt, bool info)
115{
116 static int buftyp[] = {TYPE_STRING, TYPE_SHORT, TYPE_STRING, TYPE_INT,
117 TYPE_INT, TYPE_SHORT, TYPE_SHORT, TYPE_STRING};
118 static XFLD fldtyp[] = {FLD_NAME, FLD_TYPE, FLD_TYPENAME, FLD_PREC,
119 FLD_LENGTH, FLD_SCALE, FLD_NULL, FLD_FORMAT};
120 static unsigned int length[] = {0, 6, 8, 10, 10, 6, 6, 0};
121 char colname[65], fmt[129], buf[512];
122 int i, j, lvl, n = 0;
123 int ncol = sizeof(buftyp) / sizeof(int);
124 bool ok = true;
125 PCSZ fn, op;
126 PXCL xcol, xcp, fxcp = NULL, pxcp = NULL;
127 PLVL *lvlp, vp;
128 PXNODE node = NULL;
129 PXMLDEF tdp;
130 PTDBXML txmp;
131 PQRYRES qrp;
132 PCOLRES crp;
133
134 if (info) {
135 length[0] = 128;
136 length[7] = 256;
137 goto skipit;
138 } // endif info
139
140 if (GetIntegerTableOption(g, topt, "Multiple", 0)) {
141 strcpy(g->Message, "Cannot find column definition for multiple table");
142 return NULL;
143 } // endif Multiple
144
145 /*********************************************************************/
146 /* Open the input file. */
147 /*********************************************************************/
148 if (!(fn = GetStringTableOption(g, topt, "Filename", NULL))) {
149 strcpy(g->Message, MSG(MISSING_FNAME));
150 return NULL;
151 } else {
152 lvl = GetIntegerTableOption(g, topt, "Level", 0);
153 lvl = (lvl < 0) ? 0 : (lvl > 16) ? 16 : lvl;
154 } // endif fn
155
156 if (trace(1))
157 htrc("File %s lvl=%d\n", topt->filename, lvl);
158
159 tdp = new(g) XMLDEF;
160 tdp->Fn = fn;
161
162 if (!(tdp->Database = SetPath(g, db)))
163 return NULL;
164
165 tdp->Tabname = tab;
166 tdp->Zipped = GetBooleanTableOption(g, topt, "Zipped", false);
167 tdp->Entry = GetStringTableOption(g, topt, "Entry", NULL);
168
169 if (!(op = GetStringTableOption(g, topt, "Xmlsup", NULL)))
170#if defined(__WIN__)
171 tdp->Usedom = true;
172#else // !__WIN__
173 tdp->Usedom = false;
174#endif // !__WIN__
175 else
176 tdp->Usedom = (toupper(*op) == 'M' || toupper(*op) == 'D');
177
178 txmp = new(g) TDBXML(tdp);
179
180 if (txmp->Initialize(g))
181 goto err;
182
183 xcol = new(g) XMCOL;
184 colname[64] = 0;
185 fmt[128] = 0;
186 lvlp = (PLVL*)PlugSubAlloc(g, NULL, sizeof(PLVL) * (lvl + 1));
187
188 for (j = 0; j <= lvl; j++)
189 lvlp[j] = (PLVL)PlugSubAlloc(g, NULL, sizeof(LVL));
190
191 /*********************************************************************/
192 /* Analyse the XML tree and define columns. */
193 /*********************************************************************/
194 for (i = 1; ; i++) {
195 // Get next row
196 switch (txmp->ReadDB(g)) {
197 case RC_EF:
198 vp = NULL;
199 break;
200 case RC_FX:
201 goto err;
202 default:
203 vp = lvlp[0];
204 vp->pn = txmp->RowNode;
205 vp->atp = vp->pn->GetAttribute(g, NULL);
206 vp->nl = vp->pn->GetChildElements(g);
207 vp->b = true;
208 vp->k = 0;
209 vp->m = vp->n = 0;
210 j = 0;
211 } // endswitch ReadDB
212
213 if (!vp)
214 break;
215
216 while (true) {
217 if (!vp->atp &&
218 !(node = (vp->nl) ? vp->nl->GetItem(g, vp->k++, tdp->Usedom ? node : NULL)
219 : NULL))
220 if (j) {
221 vp = lvlp[--j];
222
223 if (!tdp->Usedom) // nl was destroyed
224 vp->nl = vp->pn->GetChildElements(g);
225
226 if (!lvlp[j+1]->b) {
227 vp->k--;
228 ok = false;
229 } // endif b
230
231 continue;
232 } else
233 break;
234
235 xcol->Name[vp->n] = 0;
236 fmt[vp->m] = 0;
237
238 more:
239 if (vp->atp) {
240 strncpy(colname, vp->atp->GetName(g), sizeof(colname));
241 strncat(xcol->Name, colname, XLEN(xcol->Name));
242
243 switch (vp->atp->GetText(g, buf, sizeof(buf))) {
244 case RC_INFO:
245 PushWarning(g, txmp);
246 case RC_OK:
247 strncat(fmt, "@", XLEN(fmt));
248 break;
249 default:
250 goto err;
251 } // enswitch rc
252
253 if (j)
254 strncat(fmt, colname, XLEN(fmt));
255
256 } else {
257 if (tdp->Usedom && node->GetType() != 1)
258 continue;
259
260 strncpy(colname, node->GetName(g), sizeof(colname));
261 strncat(xcol->Name, colname, XLEN(xcol->Name));
262
263 if (j)
264 strncat(fmt, colname, XLEN(fmt));
265
266 if (j < lvl && ok) {
267 vp = lvlp[j+1];
268 vp->k = 0;
269 vp->pn = node;
270 vp->atp = node->GetAttribute(g, NULL);
271 vp->nl = node->GetChildElements(g);
272
273 if (tdp->Usedom && vp->nl->GetLength() == 1) {
274 node = vp->nl->GetItem(g, 0, node);
275 vp->b = (node->GetType() == 1); // Must be ab element
276 } else
277 vp->b = (vp->nl && vp->nl->GetLength());
278
279 if (vp->atp || vp->b) {
280 if (!vp->atp)
281 node = vp->nl->GetItem(g, vp->k++, tdp->Usedom ? node : NULL);
282
283 strncat(fmt, colname, XLEN(fmt));
284 strncat(fmt, "/", XLEN(fmt));
285 strncat(xcol->Name, "_", XLEN(xcol->Name));
286 j++;
287 vp->n = (int)strlen(xcol->Name);
288 vp->m = (int)strlen(fmt);
289 goto more;
290 } else {
291 vp = lvlp[j];
292
293 if (!tdp->Usedom) // nl was destroyed
294 vp->nl = vp->pn->GetChildElements(g);
295
296 } // endif vp
297
298 } else
299 ok = true;
300
301 switch (node->GetContent(g, buf, sizeof(buf))) {
302 case RC_INFO:
303 PushWarning(g, txmp);
304 case RC_OK:
305 break;
306 default:
307 goto err;
308 } // enswitch rc
309
310 } // endif atp;
311
312 xcol->Len = strlen(buf);
313
314 // Check whether this column was already found
315 for (xcp = fxcp; xcp; xcp = xcp->Next)
316 if (!strcmp(xcol->Name, xcp->Name))
317 break;
318
319 if (xcp) {
320 if (xcp->Type != xcol->Type)
321 xcp->Type = TYPE_STRING;
322
323 if (*fmt && (!xcp->Fmt || strlen(xcp->Fmt) < strlen(fmt))) {
324 xcp->Fmt = PlugDup(g, fmt);
325 length[7] = MY_MAX(length[7], strlen(fmt));
326 } // endif *fmt
327
328 xcp->Len = MY_MAX(xcp->Len, xcol->Len);
329 xcp->Scale = MY_MAX(xcp->Scale, xcol->Scale);
330 xcp->Cbn |= xcol->Cbn;
331 xcp->Found = true;
332 } else {
333 // New column
334 xcp = new(g) XMCOL(g, xcol, fmt, i);
335 length[0] = MY_MAX(length[0], strlen(xcol->Name));
336 length[7] = MY_MAX(length[7], strlen(fmt));
337
338 if (pxcp) {
339 xcp->Next = pxcp->Next;
340 pxcp->Next = xcp;
341 } else
342 fxcp = xcp;
343
344 n++;
345 } // endif xcp
346
347 pxcp = xcp;
348
349 if (vp->atp)
350 vp->atp = vp->atp->GetNext(g);
351
352 } // endwhile
353
354 // Missing column can be null
355 for (xcp = fxcp; xcp; xcp = xcp->Next) {
356 xcp->Cbn |= !xcp->Found;
357 xcp->Found = false;
358 } // endfor xcp
359
360 } // endor i
361
362 txmp->CloseDB(g);
363
364 skipit:
365 if (trace(1))
366 htrc("XMLColumns: n=%d len=%d\n", n, length[0]);
367
368 /*********************************************************************/
369 /* Allocate the structures used to refer to the result set. */
370 /*********************************************************************/
371 qrp = PlgAllocResult(g, ncol, n, IDS_COLUMNS + 3,
372 buftyp, fldtyp, length, false, false);
373
374 crp = qrp->Colresp->Next->Next->Next->Next->Next->Next;
375 crp->Name = "Nullable";
376 crp->Next->Name = "Xpath";
377
378 if (info || !qrp)
379 return qrp;
380
381 qrp->Nblin = n;
382
383 /*********************************************************************/
384 /* Now get the results into blocks. */
385 /*********************************************************************/
386 for (i = 0, xcp = fxcp; xcp; i++, xcp = xcp->Next) {
387 if (xcp->Type == TYPE_UNKNOWN) // Void column
388 xcp->Type = TYPE_STRING;
389
390 crp = qrp->Colresp; // Column Name
391 crp->Kdata->SetValue(xcp->Name, i);
392 crp = crp->Next; // Data Type
393 crp->Kdata->SetValue(xcp->Type, i);
394 crp = crp->Next; // Type Name
395 crp->Kdata->SetValue(GetTypeName(xcp->Type), i);
396 crp = crp->Next; // Precision
397 crp->Kdata->SetValue(xcp->Len, i);
398 crp = crp->Next; // Length
399 crp->Kdata->SetValue(xcp->Len, i);
400 crp = crp->Next; // Scale (precision)
401 crp->Kdata->SetValue(xcp->Scale, i);
402 crp = crp->Next; // Nullable
403 crp->Kdata->SetValue(xcp->Cbn ? 1 : 0, i);
404 crp = crp->Next; // Field format
405
406 if (crp->Kdata)
407 crp->Kdata->SetValue(xcp->Fmt, i);
408
409 } // endfor i
410
411 /*********************************************************************/
412 /* Return the result pointer. */
413 /*********************************************************************/
414 return qrp;
415
416err:
417 txmp->CloseDB(g);
418 return NULL;
419 } // end of XMLColumns
420
421/* -------------- Implementation of the XMLDEF class ---------------- */
422
423/***********************************************************************/
424/* Constructor. */
425/***********************************************************************/
426XMLDEF::XMLDEF(void)
427 {
428 Pseudo = 3;
429 Fn = NULL;
430 Encoding = NULL;
431 Tabname = NULL;
432 Rowname = NULL;
433 Colname = NULL;
434 Mulnode = NULL;
435 XmlDB = NULL;
436 Nslist = NULL;
437 DefNs = NULL;
438 Attrib = NULL;
439 Hdattr = NULL;
440 Entry = NULL;
441 Coltype = 1;
442 Limit = 0;
443 Header = 0;
444 Xpand = false;
445 Usedom = false;
446 Zipped = false;
447 Mulentries = false;
448 } // end of XMLDEF constructor
449
450/***********************************************************************/
451/* DefineAM: define specific AM block values from XDB file. */
452/***********************************************************************/
453bool XMLDEF::DefineAM(PGLOBAL g, LPCSTR am, int poff)
454 {
455 PCSZ defrow, defcol;
456 char buf[10];
457
458 Fn = GetStringCatInfo(g, "Filename", NULL);
459 Encoding = GetStringCatInfo(g, "Encoding", "UTF-8");
460
461 if (*Fn == '?') {
462 strcpy(g->Message, MSG(MISSING_FNAME));
463 return true;
464 } // endif fn
465
466 if ((signed)GetIntCatInfo("Flag", -1) != -1) {
467 strcpy(g->Message, MSG(DEPREC_FLAG));
468 return true;
469 } // endif flag
470
471 defrow = defcol = NULL;
472 GetCharCatInfo("Coltype", "", buf, sizeof(buf));
473
474 switch (toupper(*buf)) {
475 case 'A': // Attribute
476 case '@':
477 case '0':
478 Coltype = 0;
479 break;
480 case '\0': // Default
481 case 'T': // Tag
482 case 'N': // Node
483 case '1':
484 Coltype = 1;
485 break;
486 case 'C': // Column
487 case 'P': // Position
488 case 'H': // HTML
489 case '2':
490 Coltype = 2;
491 defrow = "TR";
492 defcol = "TD";
493 break;
494 default:
495 sprintf(g->Message, MSG(INV_COL_TYPE), buf);
496 return true;
497 } // endswitch typname
498
499 Tabname = GetStringCatInfo(g, "Name", Name); // Deprecated
500 Tabname = GetStringCatInfo(g, "Table_name", Tabname); // Deprecated
501 Tabname = GetStringCatInfo(g, "Tabname", Tabname);
502 Rowname = GetStringCatInfo(g, "Rownode", defrow);
503 Colname = GetStringCatInfo(g, "Colnode", defcol);
504 Mulnode = GetStringCatInfo(g, "Mulnode", NULL);
505 XmlDB = GetStringCatInfo(g, "XmlDB", NULL);
506 Nslist = GetStringCatInfo(g, "Nslist", NULL);
507 DefNs = GetStringCatInfo(g, "DefNs", NULL);
508 Limit = GetIntCatInfo("Limit", 10);
509 Xpand = GetBoolCatInfo("Expand", false);
510 Header = GetIntCatInfo("Header", 0);
511 GetCharCatInfo("Xmlsup", "*", buf, sizeof(buf));
512
513 // Note that if no support is specified, the default is MS-DOM
514 // on Windows and libxml2 otherwise
515 if (*buf == '*')
516#if defined(__WIN__)
517 Usedom = true;
518#else // !__WIN__
519 Usedom = false;
520#endif // !__WIN__
521 else
522 Usedom = (toupper(*buf) == 'M' || toupper(*buf) == 'D');
523
524 // Get eventual table node attribute
525 Attrib = GetStringCatInfo(g, "Attribute", NULL);
526 Hdattr = GetStringCatInfo(g, "HeadAttr", NULL);
527
528 // Specific for zipped files
529 if ((Zipped = GetBoolCatInfo("Zipped", false)))
530 Mulentries = ((Entry = GetStringCatInfo(g, "Entry", NULL)))
531 ? strchr(Entry, '*') || strchr(Entry, '?')
532 : GetBoolCatInfo("Mulentries", false);
533
534 return false;
535 } // end of DefineAM
536
537/***********************************************************************/
538/* GetTable: makes a new TDB of the proper type. */
539/***********************************************************************/
540PTDB XMLDEF::GetTable(PGLOBAL g, MODE m)
541 {
542 if (Catfunc == FNC_COL)
543 return new(g) TDBXCT(this);
544
545 if (Zipped && !(m == MODE_READ || m == MODE_ANY)) {
546 strcpy(g->Message, "ZIpped XML tables are read only");
547 return NULL;
548 } // endif Zipped
549
550 PTDBASE tdbp = new(g) TDBXML(this);
551
552 if (Multiple)
553 tdbp = new(g) TDBMUL(tdbp);
554
555 return tdbp;
556 } // end of GetTable
557
558/* ------------------------- TDBXML Class ---------------------------- */
559
560/***********************************************************************/
561/* Implementation of the TDBXML constuctor. */
562/***********************************************************************/
563TDBXML::TDBXML(PXMLDEF tdp) : TDBASE(tdp)
564 {
565 Docp = NULL;
566 Root = NULL;
567 Curp = NULL;
568 DBnode = NULL;
569 TabNode = NULL;
570 RowNode = NULL;
571 ColNode = NULL;
572 Nlist = NULL;
573 Clist = NULL;
574 To_Xb = NULL;
575 Colp = NULL;
576 Xfile = tdp->Fn;
577 Enc = tdp->Encoding;
578 Tabname = tdp->Tabname;
579#if 0 // why all these?
580 Rowname = (tdp->Rowname) ? tdp->Rowname : NULL;
581 Colname = (tdp->Colname) ? tdp->Colname : NULL;
582 Mulnode = (tdp->Mulnode) ? tdp->Mulnode : NULL;
583 XmlDB = (tdp->XmlDB) ? tdp->XmlDB : NULL;
584 Nslist = (tdp->Nslist) ? tdp->Nslist : NULL;
585 DefNs = (tdp->DefNs) ? tdp->DefNs : NULL;
586 Attrib = (tdp->Attrib) ? tdp->Attrib : NULL;
587 Hdattr = (tdp->Hdattr) ? tdp->Hdattr : NULL;
588#endif // 0
589 Rowname = tdp->Rowname;
590 Colname = tdp->Colname;
591 Mulnode = tdp->Mulnode;
592 XmlDB = tdp->XmlDB;
593 Nslist = tdp->Nslist;
594 DefNs = tdp->DefNs;
595 Attrib = tdp->Attrib;
596 Hdattr = tdp->Hdattr;
597 Entry = tdp->Entry;
598 Coltype = tdp->Coltype;
599 Limit = tdp->Limit;
600 Xpand = tdp->Xpand;
601 Zipped = tdp->Zipped;
602 Mulentries = tdp->Mulentries;
603 Changed = false;
604 Checked = false;
605 NextSame = false;
606 NewRow = false;
607 Hasnod = false;
608 Write = false;
609 Bufdone = false;
610 Nodedone = false;
611 Void = false;
612 Usedom = tdp->Usedom;
613 Header = tdp->Header;
614 Multiple = tdp->Multiple;
615 Nrow = -1;
616 Irow = Header - 1;
617 Nsub = 0;
618 N = 0;
619 } // end of TDBXML constructor
620
621TDBXML::TDBXML(PTDBXML tdbp) : TDBASE(tdbp)
622 {
623 Docp = tdbp->Docp;
624 Root = tdbp->Root;
625 Curp = tdbp->Curp;
626 DBnode = tdbp->DBnode;
627 TabNode = tdbp->TabNode;
628 RowNode = tdbp->RowNode;
629 ColNode = tdbp->ColNode;
630 Nlist = tdbp->Nlist;
631 Clist = tdbp->Clist;
632 To_Xb = tdbp->To_Xb;
633 Colp = tdbp->Colp;
634 Xfile = tdbp->Xfile;
635 Enc = tdbp->Enc;
636 Tabname = tdbp->Tabname;
637 Rowname = tdbp->Rowname;
638 Colname = tdbp->Colname;
639 Mulnode = tdbp->Mulnode;
640 XmlDB = tdbp->XmlDB;
641 Nslist = tdbp->Nslist;
642 DefNs = tdbp->DefNs;
643 Attrib = tdbp->Attrib;
644 Hdattr = tdbp->Hdattr;
645 Entry = tdbp->Entry;
646 Coltype = tdbp->Coltype;
647 Limit = tdbp->Limit;
648 Xpand = tdbp->Xpand;
649 Zipped = tdbp->Zipped;
650 Mulentries = tdbp->Mulentries;
651 Changed = tdbp->Changed;
652 Checked = tdbp->Checked;
653 NextSame = tdbp->NextSame;
654 NewRow = tdbp->NewRow;
655 Hasnod = tdbp->Hasnod;
656 Write = tdbp->Write;
657 Void = tdbp->Void;
658 Usedom = tdbp->Usedom;
659 Header = tdbp->Header;
660 Multiple = tdbp->Multiple;
661 Nrow = tdbp->Nrow;
662 Irow = tdbp->Irow;
663 Nsub = tdbp->Nsub;
664 N = tdbp->N;
665 } // end of TDBXML copy constructor
666
667// Used for update
668PTDB TDBXML::Clone(PTABS t)
669 {
670 PTDB tp;
671 PXMLCOL cp1, cp2;
672 PGLOBAL g = t->G;
673
674 tp = new(g) TDBXML(this);
675
676 for (cp1 = (PXMLCOL)Columns; cp1; cp1 = (PXMLCOL)cp1->GetNext()) {
677 cp2 = new(g) XMLCOL(cp1, tp); // Make a copy
678 NewPointer(t, cp1, cp2);
679 } // endfor cp1
680
681 return tp;
682 } // end of Clone
683
684/***********************************************************************/
685/* Allocate XML column description block. */
686/***********************************************************************/
687PCOL TDBXML::MakeCol(PGLOBAL g, PCOLDEF cdp, PCOL cprec, int n)
688 {
689 if (trace(1))
690 htrc("TDBXML: MakeCol %s n=%d\n", (cdp) ? cdp->GetName() : "<null>", n);
691
692 return new(g) XMLCOL(cdp, this, cprec, n);
693 } // end of MakeCol
694
695/***********************************************************************/
696/* InsertSpecialColumn: Put a special column ahead of the column list.*/
697/***********************************************************************/
698PCOL TDBXML::InsertSpecialColumn(PCOL colp)
699 {
700 if (!colp->IsSpecial())
701 return NULL;
702
703//if (Xpand && ((SPCBLK*)colp)->GetRnm())
704// colp->SetKey(0); // Rownum is no more a key
705
706 colp->SetNext(Columns);
707 Columns = colp;
708 return colp;
709 } // end of InsertSpecialColumn
710
711/***********************************************************************/
712/* LoadTableFile: Load and parse an XML file. */
713/***********************************************************************/
714int TDBXML::LoadTableFile(PGLOBAL g, char *filename)
715 {
716 int rc = RC_OK, type = (Usedom) ? TYPE_FB_XML : TYPE_FB_XML2;
717 PFBLOCK fp = NULL;
718 PDBUSER dup = (PDBUSER)g->Activityp->Aptr;
719
720 if (Docp)
721 return rc; // Already done
722
723 if (trace(1))
724 htrc("TDBXML: loading %s\n", filename);
725
726 /*********************************************************************/
727 /* Firstly we check whether this file have been already loaded. */
728 /*********************************************************************/
729 if ((Mode == MODE_READ || Mode == MODE_ANY) && !Zipped)
730 for (fp = dup->Openlist; fp; fp = fp->Next)
731 if (fp->Type == type && fp->Length && fp->Count)
732 if (!stricmp(fp->Fname, filename))
733 break;
734
735 if (fp) {
736 /*******************************************************************/
737 /* File already loaded. Just increment use count and get pointer. */
738 /*******************************************************************/
739 fp->Count++;
740 Docp = (Usedom) ? GetDomDoc(g, Nslist, DefNs, Enc, fp)
741 : GetLibxmlDoc(g, Nslist, DefNs, Enc, fp);
742 } else {
743 /*******************************************************************/
744 /* Parse the XML file. */
745 /*******************************************************************/
746 if (!(Docp = (Usedom) ? GetDomDoc(g, Nslist, DefNs, Enc)
747 : GetLibxmlDoc(g, Nslist, DefNs, Enc)))
748 return RC_FX;
749
750 // Initialize the implementation
751 if (Docp->Initialize(g, Entry, Zipped)) {
752 sprintf(g->Message, MSG(INIT_FAILED), (Usedom) ? "DOM" : "libxml2");
753 return RC_FX;
754 } // endif init
755
756 if (trace(1))
757 htrc("TDBXML: parsing %s rc=%d\n", filename, rc);
758
759 // Parse the XML file
760 if (Docp->ParseFile(g, filename)) {
761 // Does the file exist?
762 int h= global_open(g, MSGID_NONE, filename, _O_RDONLY);
763
764 if (h != -1) {
765 rc = (!_filelength(h)) ? RC_EF : RC_INFO;
766 close(h);
767 } else
768 rc = (errno == ENOENT) ? RC_NF : RC_INFO;
769
770 // Cannot make a Xblock until document is made
771 return rc;
772 } // endif Docp
773
774 /*******************************************************************/
775 /* Link a Xblock. This make possible to reuse already opened docs */
776 /* and also to automatically close them in case of error g->jump. */
777 /*******************************************************************/
778 fp = Docp->LinkXblock(g, Mode, rc, filename);
779 } // endif xp
780
781 To_Xb = fp; // Useful when closing
782 return rc;
783 } // end of LoadTableFile
784
785/***********************************************************************/
786/* Initialize the processing of the XML file. */
787/* Note: this function can be called several times, eventally before */
788/* the columns are known (from TBL for instance) */
789/***********************************************************************/
790bool TDBXML::Initialize(PGLOBAL g)
791 {
792 int rc;
793 PXMLCOL colp;
794
795 if (Void)
796 return false;
797
798 if (Columns && !Bufdone) {
799 // Allocate the buffers that will contain node values
800 for (colp = (PXMLCOL)Columns; colp; colp = (PXMLCOL)colp->GetNext())
801 if (!colp->IsSpecial()) // Not a pseudo column
802 if (colp->AllocBuf(g, Mode == MODE_INSERT))
803 return true;
804
805 Bufdone = true;
806 } // endif Bufdone
807
808#if !defined(UNIX)
809 if (!Root) try {
810#else
811 if (!Root) {
812#endif
813 char tabpath[64], filename[_MAX_PATH];
814
815 // We used the file name relative to recorded datapath
816 PlugSetPath(filename, Xfile, GetPath());
817
818 // Load or re-use the table file
819 rc = LoadTableFile(g, filename);
820
821 if (rc == RC_OK) {
822 // Get root node
823 if (!(Root = Docp->GetRoot(g))) {
824 // This should never happen as load should have failed
825 strcpy(g->Message, MSG(EMPTY_DOC));
826 goto error;
827 } // endif Root
828
829 // If tabname is not an Xpath,
830 // construct one that will find it anywhere
831 if (!strchr(Tabname, '/'))
832 strcat(strcpy(tabpath, "//"), Tabname);
833 else
834 strcpy(tabpath, Tabname);
835
836 // Evaluate table xpath
837 if ((TabNode = Root->SelectSingleNode(g, tabpath))) {
838 if (TabNode->GetType() != XML_ELEMENT_NODE) {
839 sprintf(g->Message, MSG(BAD_NODE_TYPE), TabNode->GetType());
840 goto error;
841 } // endif Type
842
843 } else if (Mode == MODE_INSERT && XmlDB) {
844 // We are adding a new table to a multi-table file
845
846 // If XmlDB is not an Xpath,
847 // construct one that will find it anywhere
848 if (!strchr(XmlDB, '/'))
849 strcat(strcpy(tabpath, "//"), XmlDB);
850 else
851 strcpy(tabpath, XmlDB);
852
853 if (!(DBnode = Root->SelectSingleNode(g, tabpath))) {
854 // DB node does not exist yet; we cannot create it
855 // because we don't know where it should be placed
856 sprintf(g->Message, MSG(MISSING_NODE), XmlDB, Xfile);
857 goto error;
858 } // endif DBnode
859
860 if (!(TabNode = DBnode->AddChildNode(g, Tabname))) {
861 sprintf(g->Message, MSG(FAIL_ADD_NODE), Tabname);
862 goto error;
863 } // endif TabNode
864
865 DBnode->AddText(g, "\n");
866 } else
867 TabNode = Root; // Try this ?
868
869 } else if (rc == RC_NF || rc == RC_EF) {
870 // The XML file does not exist or is void
871 if (Mode == MODE_INSERT) {
872 // New Document
873 char buf[64];
874
875 // Create the XML node
876 if (Docp->NewDoc(g, "1.0")) {
877 strcpy(g->Message, MSG(NEW_DOC_FAILED));
878 goto error;
879 } // endif NewDoc
880
881 // Now we can link the Xblock
882 To_Xb = Docp->LinkXblock(g, Mode, rc, filename);
883
884 // Add a CONNECT comment node
885 strcpy(buf, " Created by the MariaDB CONNECT Storage Engine");
886 Docp->AddComment(g, buf);
887
888 if (XmlDB) {
889 // This is a multi-table file
890 DBnode = Root = Docp->NewRoot(g, XmlDB);
891 DBnode->AddText(g, "\n");
892 TabNode = DBnode->AddChildNode(g, Tabname);
893 DBnode->AddText(g, "\n");
894 } else
895 TabNode = Root = Docp->NewRoot(g, Tabname);
896
897 if (TabNode == NULL || Root == NULL) {
898 strcpy(g->Message, MSG(XML_INIT_ERROR));
899 goto error;
900 } else if (SetTabNode(g))
901 goto error;
902
903 } else {
904 sprintf(g->Message, MSG(FILE_UNFOUND), Xfile);
905
906 if (Mode == MODE_READ) {
907 PushWarning(g, this);
908 Void = true;
909 } // endif Mode
910
911 goto error;
912 } // endif Mode
913
914 } else if (rc == RC_INFO) {
915 // Loading failed
916 sprintf(g->Message, MSG(LOADING_FAILED), Xfile);
917 goto error;
918 } else // (rc == RC_FX)
919 goto error;
920
921 // Get row node list
922 if (Rowname)
923 Nlist = TabNode->SelectNodes(g, Rowname);
924 else
925 Nlist = TabNode->GetChildElements(g);
926
927 Docp->SetNofree(true); // For libxml2
928#if defined(__WIN__)
929 } catch(_com_error e) {
930 // We come here if a DOM command threw an error
931 char buf[128];
932
933 rc = WideCharToMultiByte(CP_ACP, 0, e.Description(), -1,
934 buf, sizeof(buf), NULL, NULL);
935
936 if (rc)
937 sprintf(g->Message, "%s: %s", MSG(COM_ERROR), buf);
938 else
939 sprintf(g->Message, "%s hr=%x", MSG(COM_ERROR), e.Error());
940
941 goto error;
942#endif // __WIN__
943#if !defined(UNIX)
944 } catch(...) {
945 // Other errors
946 strcpy(g->Message, MSG(XMLTAB_INIT_ERR));
947 goto error;
948#endif
949 } // end of try-catches
950
951 if (Root && Columns && (Multiple || !Nodedone)) {
952 // Allocate class nodes to avoid dynamic allocation
953 for (colp = (PXMLCOL)Columns; colp; colp = (PXMLCOL)colp->GetNext())
954 if (!colp->IsSpecial()) // Not a pseudo column
955 colp->AllocNodes(g, Docp);
956
957 Nodedone = true;
958 } // endif Nodedone
959
960 if (Nrow < 0)
961 Nrow = (Nlist) ? Nlist->GetLength() : 0;
962
963 // Init is Ok
964 return false;
965
966error:
967 if (Docp)
968 Docp->CloseDoc(g, To_Xb);
969
970 return !Void;
971} // end of Initialize
972
973/***********************************************************************/
974/* Set TabNode attributes or header. */
975/***********************************************************************/
976bool TDBXML::SetTabNode(PGLOBAL g)
977 {
978 assert(Mode == MODE_INSERT);
979
980 if (Attrib)
981 SetNodeAttr(g, Attrib, TabNode);
982
983 if (Header) {
984 PCOLDEF cdp;
985 PXNODE rn, cn;
986
987 if (Rowname) {
988 TabNode->AddText(g, "\n\t");
989 rn = TabNode->AddChildNode(g, Rowname, NULL);
990 } else {
991 strcpy(g->Message, MSG(NO_ROW_NODE));
992 return true;
993 } // endif Rowname
994
995 if (Hdattr)
996 SetNodeAttr(g, Hdattr, rn);
997
998 for (cdp = To_Def->GetCols(); cdp; cdp = cdp->GetNext()) {
999 rn->AddText(g, "\n\t\t");
1000 cn = rn->AddChildNode(g, "TH", NULL);
1001 cn->SetContent(g, (char *)cdp->GetName(),
1002 strlen(cdp->GetName()) + 1);
1003 } // endfor cdp
1004
1005 rn->AddText(g, "\n\t");
1006 } // endif ColType
1007
1008 return false;
1009 } // end of SetTabNode
1010
1011/***********************************************************************/
1012/* Set attributes of a table or header node. */
1013/***********************************************************************/
1014void TDBXML::SetNodeAttr(PGLOBAL g, char *attr, PXNODE node)
1015 {
1016 char *p, *pa, *pn = attr;
1017 PXATTR an;
1018
1019 do {
1020 if ((p = strchr(pn, '='))) {
1021 pa = pn;
1022 *p++ = 0;
1023
1024 if ((pn = strchr(p, ';')))
1025 *pn++ = 0;
1026
1027 an = node->AddProperty(g, pa, NULL);
1028 an->SetText(g, p, strlen(p) + 1);
1029 } else
1030 break;
1031
1032 } while (pn);
1033
1034 } // end of SetNodeAttr
1035
1036/***********************************************************************/
1037/* XML Cardinality: returns table cardinality in number of rows. */
1038/* This function can be called with a null argument to test the */
1039/* availability of Cardinality implementation (1 yes, 0 no). */
1040/***********************************************************************/
1041int TDBXML::Cardinality(PGLOBAL g)
1042 {
1043 if (!g)
1044 return (Multiple || Xpand || Coltype == 2) ? 0 : 1;
1045
1046 if (Multiple)
1047 return 10;
1048
1049 if (Nrow < 0)
1050 if (Initialize(g))
1051 return -1;
1052
1053 return (Void) ? 0 : Nrow - Header;
1054 } // end of Cardinality
1055
1056/***********************************************************************/
1057/* XML GetMaxSize: returns the number of tables in the database. */
1058/***********************************************************************/
1059int TDBXML::GetMaxSize(PGLOBAL g)
1060 {
1061 if (MaxSize < 0) {
1062 if (!Multiple)
1063 MaxSize = Cardinality(g) * ((Xpand) ? Limit : 1);
1064 else
1065 MaxSize = 10;
1066
1067 } // endif MaxSize
1068
1069 return MaxSize;
1070 } // end of GetMaxSize
1071
1072/***********************************************************************/
1073/* Return the position in the table. */
1074/***********************************************************************/
1075int TDBXML::GetRecpos(void)
1076 {
1077 union {
1078 uint Rpos;
1079 BYTE Spos[4];
1080 };
1081
1082 Rpos = htonl(Irow);
1083 Spos[0] = (BYTE)Nsub;
1084 return Rpos;
1085 } // end of GetRecpos
1086
1087/***********************************************************************/
1088/* RowNumber: return the ordinal number of the current row. */
1089/***********************************************************************/
1090int TDBXML::RowNumber(PGLOBAL g, bool b)
1091 {
1092 if (To_Kindex && (Xpand || Coltype == 2) && !b) {
1093 /*******************************************************************/
1094 /* Don't know how to retrieve RowID for expanded XML tables. */
1095 /*******************************************************************/
1096 sprintf(g->Message, MSG(NO_ROWID_FOR_AM),
1097 GetAmName(g, GetAmType()));
1098 return 0; // Means error
1099 } else
1100 return (b || !(Xpand || Coltype == 2)) ? Irow - Header + 1 : N;
1101
1102 } // end of RowNumber
1103
1104/***********************************************************************/
1105/* XML Access Method opening routine. */
1106/***********************************************************************/
1107bool TDBXML::OpenDB(PGLOBAL g)
1108 {
1109 if (Use == USE_OPEN) {
1110 /*******************************************************************/
1111 /* Table already open replace it at its beginning. */
1112 /*******************************************************************/
1113 if (!To_Kindex) {
1114 Irow = Header - 1;
1115 Nsub = 0;
1116 } else
1117 /*****************************************************************/
1118 /* Table is to be accessed through a sorted index table. */
1119 /*****************************************************************/
1120 To_Kindex->Reset();
1121
1122 return false;
1123 } // endif use
1124
1125 /*********************************************************************/
1126 /* OpenDB: initialize the XML file processing. */
1127 /*********************************************************************/
1128 Write = (Mode == MODE_INSERT || Mode == MODE_UPDATE);
1129
1130 if (Initialize(g))
1131 return true;
1132
1133 NewRow = (Mode == MODE_INSERT);
1134 Nsub = 0;
1135 Use = USE_OPEN; // Do it now in case we are recursively called
1136 return false;
1137 } // end of OpenDB
1138
1139/***********************************************************************/
1140/* Data Base read routine for XML access method. */
1141/***********************************************************************/
1142int TDBXML::ReadDB(PGLOBAL g)
1143 {
1144 bool same;
1145
1146 if (Void)
1147 return RC_EF;
1148
1149 /*********************************************************************/
1150 /* Now start the pseudo reading process. */
1151 /*********************************************************************/
1152 if (To_Kindex) {
1153 /*******************************************************************/
1154 /* Reading is by an index table. */
1155 /*******************************************************************/
1156 union {
1157 uint Rpos;
1158 BYTE Spos[4];
1159 };
1160
1161 int recpos = To_Kindex->Fetch(g);
1162
1163 switch (recpos) {
1164 case -1: // End of file reached
1165 return RC_EF;
1166 case -2: // No match for join
1167 return RC_NF;
1168 case -3: // Same record as last non null one
1169 same = true;
1170 return RC_OK;
1171 default:
1172 Rpos = recpos;
1173 Nsub = Spos[0];
1174 Spos[0] = 0;
1175
1176 if (Irow != (signed)ntohl(Rpos)) {
1177 Irow = ntohl(Rpos);
1178 same = false;
1179 } else
1180 same = true;
1181
1182 } // endswitch recpos
1183
1184 } else {
1185 if (trace(1))
1186 htrc("TDBXML ReadDB: Irow=%d Nrow=%d\n", Irow, Nrow);
1187
1188 // This is to force the table to be expanded when constructing
1189 // an index for which the expand column is not specified.
1190 if (Colp && Irow >= Header) {
1191 Colp->Eval(g);
1192 Colp->Reset();
1193 } // endif Colp
1194
1195 if (!NextSame) {
1196 if (++Irow == Nrow)
1197 return RC_EF;
1198
1199 same = false;
1200 Nsub = 0;
1201 } else {
1202 // Not sure the multiple column read will be called
1203 NextSame = false;
1204 same = true;
1205 Nsub++;
1206 } // endif NextSame
1207
1208 N++; // RowID
1209 } // endif To_Kindex
1210
1211 if (!same) {
1212 if (trace(2))
1213 htrc("TDBXML ReadDB: Irow=%d RowNode=%p\n", Irow, RowNode);
1214
1215 // Get the new row node
1216 if ((RowNode = Nlist->GetItem(g, Irow, RowNode)) == NULL) {
1217 sprintf(g->Message, MSG(MISSING_ROWNODE), Irow);
1218 return RC_FX;
1219 } // endif RowNode
1220
1221 if (Colname && Coltype == 2)
1222 Clist = RowNode->SelectNodes(g, Colname, Clist);
1223
1224 } // endif same
1225
1226 return RC_OK;
1227 } // end of ReadDB
1228
1229/***********************************************************************/
1230/* CheckRow: called On Insert and Update. Must create the Row node */
1231/* if it does not exist (Insert) and update the Clist if called by */
1232/* a column having an Xpath because it can use an existing node that */
1233/* was added while inserting or Updating this row. */
1234/***********************************************************************/
1235bool TDBXML::CheckRow(PGLOBAL g, bool b)
1236 {
1237 if (NewRow && Mode == MODE_INSERT)
1238 if (Rowname) {
1239 TabNode->AddText(g, "\n\t");
1240 RowNode = TabNode->AddChildNode(g, Rowname, RowNode);
1241 } else {
1242 strcpy(g->Message, MSG(NO_ROW_NODE));
1243 return true;
1244 } // endif Rowname
1245
1246 if (Colname && (NewRow || b))
1247 Clist = RowNode->SelectNodes(g, Colname, Clist);
1248
1249 return NewRow = false;
1250 } // end of CheckRow
1251
1252/***********************************************************************/
1253/* WriteDB: Data Base write routine for XDB access methods. */
1254/***********************************************************************/
1255int TDBXML::WriteDB(PGLOBAL g)
1256 {
1257 if (Mode == MODE_INSERT) {
1258 if (Hasnod)
1259 RowNode->AddText(g, "\n\t");
1260
1261 NewRow = true;
1262 } // endif Mode
1263
1264 // Something was changed in the document
1265 Changed = true;
1266 return RC_OK;
1267 } // end of WriteDB
1268
1269/***********************************************************************/
1270/* Data Base delete line routine for XDB access methods. */
1271/***********************************************************************/
1272int TDBXML::DeleteDB(PGLOBAL g, int irc)
1273 {
1274 if (irc == RC_FX) {
1275 // Delete all rows
1276 for (Irow = 0; Irow < Nrow; Irow++)
1277 if ((RowNode = Nlist->GetItem(g, Irow, RowNode)) == NULL) {
1278 sprintf(g->Message, MSG(MISSING_ROWNODE), Irow);
1279 return RC_FX;
1280 } else {
1281 TabNode->DeleteChild(g, RowNode);
1282
1283 if (Nlist->DropItem(g, Irow))
1284 return RC_FX;
1285
1286 } // endif RowNode
1287
1288 Changed = true;
1289 } else if (irc != RC_EF) {
1290 TabNode->DeleteChild(g, RowNode);
1291
1292 if (Nlist->DropItem(g, Irow))
1293 return RC_FX;
1294
1295 Changed = true;
1296 } // endif's irc
1297
1298 return RC_OK;
1299 } // end of DeleteDB
1300
1301/***********************************************************************/
1302/* Data Base close routine for XDB access methods. */
1303/***********************************************************************/
1304void TDBXML::CloseDB(PGLOBAL g)
1305 {
1306 if (Docp) {
1307 if (Changed) {
1308 char filename[_MAX_PATH];
1309
1310 // We used the file name relative to recorded datapath
1311 PlugSetPath(filename, Xfile, GetPath());
1312
1313 if (Mode == MODE_INSERT)
1314 TabNode->AddText(g, "\n");
1315
1316 // Save the modified document
1317 if (Docp->DumpDoc(g, filename)) {
1318 PushWarning(g, this);
1319 Docp->CloseDoc(g, To_Xb);
1320
1321 // This causes a crash in Diagnostics_area::set_error_status
1322// throw (int)TYPE_AM_XML;
1323 } // endif DumpDoc
1324
1325 } // endif Changed
1326
1327 // Free the document and terminate XML processing
1328 Docp->CloseDoc(g, To_Xb);
1329 } // endif docp
1330
1331 if (Multiple) {
1332 // Reset all constants to start a new parse
1333 Docp = NULL;
1334 Root = NULL;
1335 Curp = NULL;
1336 DBnode = NULL;
1337 TabNode = NULL;
1338 RowNode = NULL;
1339 ColNode = NULL;
1340 Nlist = NULL;
1341 Clist = NULL;
1342 To_Xb = NULL;
1343 Colp = NULL;
1344 Changed = false;
1345 Checked = false;
1346 NextSame = false;
1347 NewRow = false;
1348 Hasnod = false;
1349 Write = false;
1350 Nodedone = false;
1351 Void = false;
1352 Nrow = -1;
1353 Irow = Header - 1;
1354 Nsub = 0;
1355 N = 0;
1356 } // endif Multiple
1357
1358 } // end of CloseDB
1359
1360// ------------------------ XMLCOL functions ----------------------------
1361
1362/***********************************************************************/
1363/* XMLCOL public constructor. */
1364/***********************************************************************/
1365XMLCOL::XMLCOL(PCOLDEF cdp, PTDB tdbp, PCOL cprec, int i, PCSZ am)
1366 : COLBLK(cdp, tdbp, i)
1367 {
1368 if (cprec) {
1369 Next = cprec->GetNext();
1370 cprec->SetNext(this);
1371 } else {
1372 Next = tdbp->GetColumns();
1373 tdbp->SetColumns(this);
1374 } // endif cprec
1375
1376 // Set additional XML access method information for column.
1377 Tdbp = (PTDBXML)tdbp;
1378 Nl = NULL;
1379 Nlx = NULL;
1380 ColNode = NULL;
1381 ValNode = NULL;
1382 Cxnp = NULL;
1383 Vxnp = NULL;
1384 Vxap = NULL;
1385 AttNode = NULL;
1386 Nodes = NULL;
1387 Nod = 0;
1388 Inod = -1;
1389 Mul = false;
1390 Checked = false;
1391 Xname = cdp->GetFmt();
1392 Long = cdp->GetLong();
1393 Rank = cdp->GetOffset();
1394 Type = Tdbp->Coltype;
1395 Nx = -1;
1396 Sx = -1;
1397 N = 0;
1398 Valbuf = NULL;
1399 To_Val = NULL;
1400 } // end of XMLCOL constructor
1401
1402/***********************************************************************/
1403/* XMLCOL constructor used for copying columns. */
1404/* tdbp is the pointer to the new table descriptor. */
1405/***********************************************************************/
1406XMLCOL::XMLCOL(XMLCOL *col1, PTDB tdbp) : COLBLK(col1, tdbp)
1407 {
1408 Tdbp = col1->Tdbp;
1409 Nl = col1->Nl;
1410 Nlx = col1->Nlx;
1411 ColNode = col1->ColNode;
1412 ValNode = col1->ValNode;
1413 Cxnp = col1->Cxnp;
1414 Vxnp = col1->Vxnp;
1415 Vxap = col1->Vxap;
1416 AttNode = col1->AttNode;
1417 Nodes = col1->Nodes;
1418 Nod = col1->Nod;
1419 Inod = col1->Inod;
1420 Mul = col1->Mul;
1421 Checked = col1->Checked;
1422 Xname = col1->Xname;
1423 Valbuf = col1->Valbuf;
1424 Long = col1->Long;
1425 Rank = col1->Rank;
1426 Nx = col1->Nx;
1427 Sx = col1->Sx;
1428 N = col1->N;
1429 Type = col1->Type;
1430 To_Val = col1->To_Val;
1431 } // end of XMLCOL copy constructor
1432
1433/***********************************************************************/
1434/* Allocate a buffer of the proper size. */
1435/***********************************************************************/
1436bool XMLCOL::AllocBuf(PGLOBAL g, bool mode)
1437 {
1438 if (Valbuf)
1439 return false; // Already done
1440
1441 return ParseXpath(g, mode);
1442 } // end of AllocBuf
1443
1444/***********************************************************************/
1445/* Parse the eventual passed Xpath information. */
1446/* This information can be specified in the Xpath (or Fieldfmt) */
1447/* column option when creating the table. It permits to indicate the */
1448/* position of the node corresponding to that column in a Xpath-like */
1449/* language (but not a truly compliant one). */
1450/***********************************************************************/
1451bool XMLCOL::ParseXpath(PGLOBAL g, bool mode)
1452 {
1453 char *p, *p2, *pbuf = NULL;
1454 int i, n = 1, len = strlen(Name);
1455
1456 len += ((Tdbp->Colname) ? strlen(Tdbp->Colname) : 0);
1457 len += ((Xname) ? strlen(Xname) : 0);
1458 pbuf = (char*)PlugSubAlloc(g, NULL, len + 3);
1459 *pbuf = '\0';
1460
1461 if (!mode)
1462 // Take care of an eventual extra column node a la html
1463 if (Tdbp->Colname) {
1464 sprintf(pbuf, Tdbp->Colname, Rank + ((Tdbp->Usedom) ? 0 : 1));
1465 strcat(pbuf, "/");
1466 } // endif Colname
1467
1468 if (Xname) {
1469 if (Type == 2) {
1470 sprintf(g->Message, MSG(BAD_COL_XPATH), Name, Tdbp->Name);
1471 return true;
1472 } else
1473 strcat(pbuf, Xname);
1474
1475 if (trace(1))
1476 htrc("XMLCOL: pbuf=%s\n", pbuf);
1477
1478 // For Update or Insert the Xpath must be analyzed
1479 if (mode) {
1480 for (i = 0, p = pbuf; (p = strchr(p, '/')); i++, p++)
1481 Nod++; // One path node found
1482
1483 if (Nod)
1484 Nodes = (char**)PlugSubAlloc(g, NULL, Nod * sizeof(char*));
1485
1486 } // endif mode
1487
1488 // Analyze the Xpath for this column
1489 for (i = 0, p = pbuf; (p2 = strchr(p, '/')); i++, p = p2 + 1) {
1490 if (Tdbp->Mulnode && !strncmp(p, Tdbp->Mulnode, p2 - p))
1491 if (!Tdbp->Xpand && mode) {
1492 strcpy(g->Message, MSG(CONCAT_SUBNODE));
1493 return true;
1494 } else
1495 Inod = i; // Index of multiple node
1496
1497 if (mode) {
1498 // For Update or Insert the Xpath must be explicit
1499 if (strchr("@/.*", *p)) {
1500 sprintf(g->Message, MSG(XPATH_NOT_SUPP), Name);
1501 return true;
1502 } else
1503 Nodes[i] = p;
1504
1505 *p2 = '\0';
1506 } // endif mode
1507
1508 } // endfor i, p
1509
1510 if (*p == '/' || *p == '.') {
1511 sprintf(g->Message, MSG(XPATH_NOT_SUPP), Name);
1512 return true;
1513 } else if (*p == '@') {
1514 p++; // Remove the @ if mode
1515 Type = 0; // Column is an attribute
1516 } else
1517 Type = 1; // Column is a node
1518
1519 if (!*p)
1520 strcpy(p, Name); // Xname is column name
1521
1522 if (Type && Tdbp->Mulnode && !strcmp(p, Tdbp->Mulnode))
1523 Inod = Nod; // Index of multiple node
1524
1525 if (mode) // Prepare Xname
1526 pbuf = p;
1527
1528 } else if (Type == 2) {
1529 // HTML like table, columns are retrieved by position
1530 new(this) XPOSCOL(Value); // Change the class of this column
1531 Inod = -1;
1532 } else if (Type == 0 && !mode) {
1533 strcat(strcat(pbuf, "@"), Name);
1534 } else { // Type == 1
1535 if (Tdbp->Mulnode && !strcmp(Name, Tdbp->Mulnode))
1536 Inod = 0; // Nod
1537
1538 strcat(pbuf, Name);
1539 } // endif,s
1540
1541 if (Inod >= 0) {
1542 Tdbp->Colp = this; // To force expand
1543
1544 if (Tdbp->Xpand)
1545 n = Tdbp->Limit;
1546
1547 new(this) XMULCOL(Value); // Change the class of this column
1548 } // endif Inod
1549
1550 Valbuf = (char*)PlugSubAlloc(g, NULL, n * (Long + 1));
1551
1552 for (i = 0; i < n; i++)
1553 Valbuf[Long + (i * (Long + 1))] = '\0';
1554
1555 if (Type || Nod)
1556 Tdbp->Hasnod = true;
1557
1558 if (trace(1))
1559 htrc("XMLCOL: Xname=%s\n", pbuf);
1560
1561 // Save the calculated Xpath
1562 Xname = pbuf;
1563 return false;
1564 } // end of ParseXpath
1565
1566/***********************************************************************/
1567/* SetBuffer: prepare a column block for write operation. */
1568/***********************************************************************/
1569bool XMLCOL::SetBuffer(PGLOBAL g, PVAL value, bool ok, bool check)
1570 {
1571 if (!(To_Val = value)) {
1572 sprintf(g->Message, MSG(VALUE_ERROR), Name);
1573 return true;
1574 } else if (Buf_Type == value->GetType()) {
1575 // Values are of the (good) column type
1576 if (Buf_Type == TYPE_DATE) {
1577 // If any of the date values is formatted
1578 // output format must be set for the receiving table
1579 if (GetDomain() || ((DTVAL *)value)->IsFormatted())
1580 goto newval; // This will make a new value;
1581
1582 } else if (Buf_Type == TYPE_DOUBLE)
1583 // Float values must be written with the correct (column) precision
1584 // Note: maybe this should be forced by ShowValue instead of this ?
1585 value->SetPrec(GetScale());
1586
1587 Value = value; // Directly access the external value
1588 } else {
1589 // Values are not of the (good) column type
1590 if (check) {
1591 sprintf(g->Message, MSG(TYPE_VALUE_ERR), Name,
1592 GetTypeName(Buf_Type), GetTypeName(value->GetType()));
1593 return true;
1594 } // endif check
1595
1596 newval:
1597 if (InitValue(g)) // Allocate the matching value block
1598 return true;
1599
1600 } // endif's Value, Buf_Type
1601
1602 // Because Colblk's have been made from a copy of the original TDB in
1603 // case of Update, we must reset them to point to the original one.
1604 if (To_Tdb->GetOrig()) {
1605 To_Tdb = (PTDB)To_Tdb->GetOrig();
1606 Tdbp = (PTDBXML)To_Tdb; // Specific of XMLCOL
1607
1608 // Allocate the XML buffer
1609 if (AllocBuf(g, true)) // In Write mode
1610 return true;
1611
1612 } // endif GetOrig
1613
1614 // Set the Column
1615 Status = (ok) ? BUF_EMPTY : BUF_NO;
1616 return false;
1617 } // end of SetBuffer
1618
1619/***********************************************************************/
1620/* Alloc the nodes that will be used during the whole process. */
1621/***********************************************************************/
1622void XMLCOL::AllocNodes(PGLOBAL g, PXDOC dp)
1623{
1624 Cxnp = dp->NewPnode(g);
1625 Vxnp = dp->NewPnode(g);
1626 Vxap = dp->NewPattr(g);
1627} // end of AllocNodes
1628
1629/***********************************************************************/
1630/* ReadColumn: what this routine does is to access the column node */
1631/* from the corresponding table, extract from it the node text and */
1632/* convert it to the column type. */
1633/***********************************************************************/
1634void XMLCOL::ReadColumn(PGLOBAL g)
1635 {
1636 if (Nx == Tdbp->Irow)
1637 return; // Same row than the last read
1638
1639 ValNode = Tdbp->RowNode->SelectSingleNode(g, Xname, Vxnp);
1640
1641 if (ValNode) {
1642 if (ValNode->GetType() != XML_ELEMENT_NODE &&
1643 ValNode->GetType() != XML_ATTRIBUTE_NODE) {
1644 sprintf(g->Message, MSG(BAD_VALNODE), ValNode->GetType(), Name);
1645 throw (int)TYPE_AM_XML;
1646 } // endif type
1647
1648 // Get the Xname value from the XML file
1649 switch (ValNode->GetContent(g, Valbuf, Long + 1)) {
1650 case RC_OK:
1651 break;
1652 case RC_INFO:
1653 PushWarning(g, Tdbp);
1654 break;
1655 default:
1656 throw (int)TYPE_AM_XML;
1657 } // endswitch
1658
1659 Value->SetValue_psz(Valbuf);
1660 } else {
1661 if (Nullable)
1662 Value->SetNull(true);
1663
1664 Value->Reset(); // Null value
1665 } // endif ValNode
1666
1667 Nx = Tdbp->Irow;
1668 } // end of ReadColumn
1669
1670/***********************************************************************/
1671/* WriteColumn: what this routine does is to access the last row of */
1672/* the corresponding table, and rewrite the content corresponding */
1673/* to this column node from the column buffer and type. */
1674/***********************************************************************/
1675void XMLCOL::WriteColumn(PGLOBAL g)
1676 {
1677 char *p, buf[16];
1678 int done = 0;
1679 int i, n, k = 0;
1680 PXNODE TopNode = NULL;
1681
1682 if (trace(2))
1683 htrc("XML WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
1684 Name, Tdbp->GetTdb_No(), ColUse, Status);
1685
1686 /*********************************************************************/
1687 /* Check whether this node must be written. */
1688 /*********************************************************************/
1689 if (Value != To_Val)
1690 Value->SetValue_pval(To_Val, false); // Convert the updated value
1691
1692 /*********************************************************************/
1693 /* If a check pass was done while updating, all node contruction */
1694 /* has been already one. */
1695 /*********************************************************************/
1696 if (Status && Tdbp->Checked && !Value->IsNull()) {
1697 assert (ColNode != NULL);
1698 assert ((Type ? (void *)ValNode : (void *)AttNode) != NULL);
1699 goto fin;
1700 } // endif Checked
1701
1702 /*********************************************************************/
1703 /* On Insert, a Row node must be created for each row; */
1704 /* For columns having an Xpath, the Clist must be updated. */
1705 /*********************************************************************/
1706 if (Tdbp->CheckRow(g, Nod || Tdbp->Colname))
1707 throw (int)TYPE_AM_XML;
1708
1709 /*********************************************************************/
1710 /* Null values are represented by no node. */
1711 /*********************************************************************/
1712 if (Value->IsNull())
1713 return;
1714
1715 /*********************************************************************/
1716 /* Find the column and value nodes to update or insert. */
1717 /*********************************************************************/
1718 if (Tdbp->Clist) {
1719 n = Tdbp->Clist->GetLength();
1720 ColNode = NULL;
1721 } else {
1722 n = 1;
1723 ColNode = Tdbp->RowNode->Clone(g, ColNode);
1724 } // endif Clist
1725
1726 ValNode = NULL;
1727
1728 for (i = 0; i < n; i++) {
1729 if (Tdbp->Clist)
1730 ColNode = Tdbp->Clist->GetItem(g, i, Cxnp);
1731
1732 /*******************************************************************/
1733 /* Check whether an Xpath was provided to go to the column node. */
1734 /*******************************************************************/
1735 for (k = 0; k < Nod; k++)
1736 if ((ColNode = ColNode->SelectSingleNode(g, Nodes[k], Cxnp)))
1737 TopNode = ColNode;
1738 else
1739 break;
1740
1741 if (ColNode)
1742 if (Type)
1743 ValNode = ColNode->SelectSingleNode(g, Xname, Vxnp);
1744 else
1745 AttNode = ColNode->GetAttribute(g, Xname, Vxap);
1746
1747 if (TopNode || ValNode || AttNode)
1748 break; // We found the good column
1749 else if (Tdbp->Clist)
1750 ColNode = NULL;
1751
1752 } // endfor i
1753
1754 /*********************************************************************/
1755 /* Create missing nodes. */
1756 /*********************************************************************/
1757 if (ColNode == NULL) {
1758 if (TopNode == NULL)
1759 if (Tdbp->Clist) {
1760 Tdbp->RowNode->AddText(g, "\n\t\t");
1761 ColNode = Tdbp->RowNode->AddChildNode(g, Tdbp->Colname);
1762 done = 2;
1763 TopNode = ColNode;
1764 } else
1765 TopNode = Tdbp->RowNode;
1766
1767 for (; k < Nod && TopNode; k++) {
1768 if (!done) {
1769 TopNode->AddText(g, "\n\t\t");
1770 done = 1;
1771 } // endif done
1772
1773 ColNode = TopNode->AddChildNode(g, Nodes[k], Cxnp);
1774 TopNode = ColNode;
1775 } // endfor k
1776
1777 if (ColNode == NULL) {
1778 strcpy(g->Message, MSG(COL_ALLOC_ERR));
1779 throw (int)TYPE_AM_XML;
1780 } // endif ColNode
1781
1782 } // endif ColNode
1783
1784 if (Type == 1) {
1785 if (ValNode == NULL) {
1786 if (done < 2)
1787 ColNode->AddText(g, "\n\t\t");
1788
1789 ValNode = ColNode->AddChildNode(g, Xname, Vxnp);
1790 } // endif ValNode
1791
1792 } else // (Type == 0)
1793 if (AttNode == NULL)
1794 AttNode = ColNode->AddProperty(g, Xname, Vxap);
1795
1796 if (ValNode == NULL && AttNode == NULL) {
1797 strcpy(g->Message, MSG(VAL_ALLOC_ERR));
1798 throw (int)TYPE_AM_XML;
1799 } // endif ValNode
1800
1801 /*********************************************************************/
1802 /* Get the string representation of Value according to column type. */
1803 /*********************************************************************/
1804 p = Value->GetCharString(buf);
1805
1806 if (strlen(p) > (unsigned)Long) {
1807 sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
1808 throw (int)TYPE_AM_XML;
1809 } else
1810 strcpy(Valbuf, p);
1811
1812 /*********************************************************************/
1813 /* Updating must be done only when not in checking pass. */
1814 /*********************************************************************/
1815 fin:
1816 if (Status) {
1817 if (Type) {
1818 ValNode->SetContent(g, Valbuf, Long);
1819 } else
1820 AttNode->SetText(g, Valbuf, Long);
1821
1822 } // endif Status
1823
1824 } // end of WriteColumn
1825
1826// ------------------------ XMULCOL functions ---------------------------
1827
1828/***********************************************************************/
1829/* ReadColumn: what this routine does is to access the column node */
1830/* from the corresponding table, extract from it the node text and */
1831/* convert it to the column type. */
1832/***********************************************************************/
1833void XMULCOL::ReadColumn(PGLOBAL g)
1834 {
1835 char *p;
1836 int i, len;
1837 bool b = Tdbp->Xpand;
1838
1839 if (Nx != Tdbp->Irow) { // New row
1840 Nl = Tdbp->RowNode->SelectNodes(g, Xname, Nl);
1841
1842 if ((N = Nl->GetLength())) {
1843 *(p = Valbuf) = '\0';
1844 len = Long;
1845
1846 if (N > Tdbp->Limit) {
1847 N = Tdbp->Limit;
1848 sprintf(g->Message, "Mutiple values limited to %d", Tdbp->Limit);
1849 PushWarning(g, Tdbp);
1850 } // endif N
1851
1852 for (i = 0; i < N; i++) {
1853 ValNode = Nl->GetItem(g, i, Vxnp);
1854
1855 if (ValNode->GetType() != XML_ELEMENT_NODE &&
1856 ValNode->GetType() != XML_ATTRIBUTE_NODE) {
1857 sprintf(g->Message, MSG(BAD_VALNODE), ValNode->GetType(), Name);
1858 throw (int)TYPE_AM_XML;
1859 } // endif type
1860
1861 // Get the Xname value from the XML file
1862 switch (ValNode->GetContent(g, p, (b ? Long : len))) {
1863 case RC_OK:
1864 break;
1865 case RC_INFO:
1866 PushWarning(g, Tdbp);
1867 break;
1868 default:
1869 throw (int)TYPE_AM_XML;
1870 } // endswitch
1871
1872 if (!b) {
1873 // Concatenate all values
1874 if (N - i > 1)
1875 strncat(Valbuf, ", ", len - strlen(p));
1876
1877 if ((len -= strlen(p)) <= 0)
1878 break;
1879
1880 p += strlen(p);
1881 } else // Xpand
1882 p += (Long + 1);
1883
1884 } // endfor i
1885
1886 Value->SetValue_psz(Valbuf);
1887 } else {
1888 if (Nullable)
1889 Value->SetNull(true);
1890
1891 Value->Reset(); // Null value
1892 } // endif ValNode
1893
1894 } else if (Sx == Tdbp->Nsub)
1895 return; // Same row
1896 else // Expanded value
1897 Value->SetValue_psz(Valbuf + (Tdbp->Nsub * (Long + 1)));
1898
1899 Nx = Tdbp->Irow;
1900 Sx = Tdbp->Nsub;
1901 Tdbp->NextSame = (Tdbp->Xpand && N - Sx > 1);
1902 } // end of ReadColumn
1903
1904/***********************************************************************/
1905/* WriteColumn: what this routine does is to access the last line */
1906/* read from the corresponding table, and rewrite the field */
1907/* corresponding to this column from the column buffer and type. */
1908/***********************************************************************/
1909void XMULCOL::WriteColumn(PGLOBAL g)
1910 {
1911 char *p, buf[16];
1912 int done = 0;
1913 int i, n, len, k = 0;
1914 PXNODE TopNode = NULL;
1915
1916 if (trace(1))
1917 htrc("XML WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
1918 Name, Tdbp->GetTdb_No(), ColUse, Status);
1919
1920 /*********************************************************************/
1921 /* Check whether this node must be written. */
1922 /*********************************************************************/
1923 if (Value != To_Val)
1924 Value->SetValue_pval(To_Val, false); // Convert the updated value
1925
1926 if (Value->IsNull())
1927 return;
1928
1929 /*********************************************************************/
1930 /* If a check pass was done while updating, all node contruction */
1931 /* has been already one. */
1932 /*********************************************************************/
1933 if (Status && Tdbp->Checked) {
1934 assert (ColNode);
1935 assert ((Type ? (void *)ValNode : (void *)AttNode) != NULL);
1936 goto fin;
1937 } // endif Checked
1938
1939 /*********************************************************************/
1940 /* On Insert, a Row node must be created for each row; */
1941 /* For columns having an Xpath, the Clist must be updated. */
1942 /*********************************************************************/
1943 if (Tdbp->CheckRow(g, Nod))
1944 throw (int)TYPE_AM_XML;
1945
1946 /*********************************************************************/
1947 /* Find the column and value nodes to update or insert. */
1948 /*********************************************************************/
1949 if (Tdbp->Clist) {
1950 n = Tdbp->Clist->GetLength();
1951 ColNode = NULL;
1952 } else {
1953 n = 1;
1954 ColNode = Tdbp->RowNode->Clone(g, ColNode);
1955 } // endif Clist
1956
1957 ValNode = NULL;
1958
1959 for (i = 0; i < n; i++) {
1960 if (Tdbp->Clist)
1961 ColNode = Tdbp->Clist->GetItem(g, i, Cxnp);
1962
1963 /*******************************************************************/
1964 /* Check whether an Xpath was provided to go to the column node. */
1965 /*******************************************************************/
1966 for (k = 0; k < Nod; k++) {
1967 if (k == Inod) {
1968 // This is the multiple node
1969 Nlx = ColNode->SelectNodes(g, Nodes[k], Nlx);
1970 ColNode = Nlx->GetItem(g, Tdbp->Nsub, Cxnp);
1971 } else
1972 ColNode = ColNode->SelectSingleNode(g, Nodes[k], Cxnp);
1973
1974 if (ColNode == NULL)
1975 break;
1976
1977 TopNode = ColNode;
1978 } // endfor k
1979
1980 if (ColNode)
1981 if (Inod == Nod) {
1982 /***************************************************************/
1983 /* The node value can be multiple. */
1984 /***************************************************************/
1985 assert (Type);
1986
1987 // Get the value Node from the XML list
1988 Nlx = ColNode->SelectNodes(g, Xname, Nlx);
1989 len = Nlx->GetLength();
1990
1991 if (len > 1 && !Tdbp->Xpand) {
1992 sprintf(g->Message, MSG(BAD_VAL_UPDATE), Name);
1993 throw (int)TYPE_AM_XML;
1994 } else
1995 ValNode = Nlx->GetItem(g, Tdbp->Nsub, Vxnp);
1996
1997 } else // Inod != Nod
1998 if (Type)
1999 ValNode = ColNode->SelectSingleNode(g, Xname, Vxnp);
2000 else
2001 AttNode = ColNode->GetAttribute(g, Xname, Vxap);
2002
2003 if (TopNode || ValNode || AttNode)
2004 break; // We found the good column
2005 else if (Tdbp->Clist)
2006 ColNode = NULL;
2007
2008 } // endfor i
2009
2010 /*********************************************************************/
2011 /* Create missing nodes. */
2012 /*********************************************************************/
2013 if (ColNode == NULL) {
2014 if (TopNode == NULL)
2015 if (Tdbp->Clist) {
2016 Tdbp->RowNode->AddText(g, "\n\t\t");
2017 ColNode = Tdbp->RowNode->AddChildNode(g, Tdbp->Colname);
2018 done = 2;
2019 TopNode = ColNode;
2020 } else
2021 TopNode = Tdbp->RowNode;
2022
2023 for (; k < Nod && TopNode; k++) {
2024 if (!done) {
2025 TopNode->AddText(g, "\n\t\t");
2026 done = 1;
2027 } // endif done
2028
2029 ColNode = TopNode->AddChildNode(g, Nodes[k], Cxnp);
2030 TopNode = ColNode;
2031 } // endfor k
2032
2033 if (ColNode == NULL) {
2034 strcpy(g->Message, MSG(COL_ALLOC_ERR));
2035 throw (int)TYPE_AM_XML;
2036 } // endif ColNode
2037
2038 } // endif ColNode
2039
2040 if (Type == 1) {
2041 if (ValNode == NULL) {
2042 if (done < 2)
2043 ColNode->AddText(g, "\n\t\t");
2044
2045 ValNode = ColNode->AddChildNode(g, Xname, Vxnp);
2046 } // endif ValNode
2047
2048 } else // (Type == 0)
2049 if (AttNode == NULL)
2050 AttNode = ColNode->AddProperty(g, Xname, Vxap);
2051
2052 if (ValNode == NULL && AttNode == NULL) {
2053 strcpy(g->Message, MSG(VAL_ALLOC_ERR));
2054 throw (int)TYPE_AM_XML;
2055 } // endif ValNode
2056
2057 /*********************************************************************/
2058 /* Get the string representation of Value according to column type. */
2059 /*********************************************************************/
2060 p = Value->GetCharString(buf);
2061
2062 if (strlen(p) > (unsigned)Long) {
2063 sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
2064 throw (int)TYPE_AM_XML;
2065 } else
2066 strcpy(Valbuf, p);
2067
2068 /*********************************************************************/
2069 /* Updating must be done only when not in checking pass. */
2070 /*********************************************************************/
2071 fin:
2072 if (Status) {
2073 if (Type) {
2074 ValNode->SetContent(g, Valbuf, Long);
2075 } else
2076 AttNode->SetText(g, Valbuf, Long);
2077
2078 } // endif Status
2079
2080 } // end of WriteColumn
2081
2082/* ------------------------ XPOSCOL functions ------------------------ */
2083
2084/***********************************************************************/
2085/* ReadColumn: what this routine does is to access the column node */
2086/* from the corresponding table, extract from it the node text and */
2087/* convert it to the column type. */
2088/***********************************************************************/
2089void XPOSCOL::ReadColumn(PGLOBAL g)
2090 {
2091 if (Nx == Tdbp->Irow)
2092 return; // Same row than the last read
2093
2094 if (Tdbp->Clist == NULL) {
2095 strcpy(g->Message, MSG(MIS_TAG_LIST));
2096 throw (int)TYPE_AM_XML;
2097 } // endif Clist
2098
2099 if ((ValNode = Tdbp->Clist->GetItem(g, Rank, Vxnp))) {
2100 // Get the column value from the XML file
2101 switch (ValNode->GetContent(g, Valbuf, Long + 1)) {
2102 case RC_OK:
2103 break;
2104 case RC_INFO:
2105 PushWarning(g, Tdbp);
2106 break;
2107 default:
2108 throw (int)TYPE_AM_XML;
2109 } // endswitch
2110
2111 Value->SetValue_psz(Valbuf);
2112 } else {
2113 if (Nullable)
2114 Value->SetNull(true);
2115
2116 Value->Reset(); // Null value
2117 } // endif ValNode
2118
2119 Nx = Tdbp->Irow;
2120 } // end of ReadColumn
2121
2122/***********************************************************************/
2123/* WriteColumn: what this routine does is to access the last line */
2124/* read from the corresponding table, and rewrite the field */
2125/* corresponding to this column from the column buffer and type. */
2126/***********************************************************************/
2127void XPOSCOL::WriteColumn(PGLOBAL g)
2128 {
2129 char *p, buf[16];
2130 int i, k, n;
2131
2132 if (trace(1))
2133 htrc("XML WriteColumn: col %s R%d coluse=%.4X status=%.4X\n",
2134 Name, Tdbp->GetTdb_No(), ColUse, Status);
2135
2136 /*********************************************************************/
2137 /* Check whether this node must be written. */
2138 /*********************************************************************/
2139 if (Value != To_Val)
2140 Value->SetValue_pval(To_Val, false); // Convert the updated value
2141
2142 if (Value->IsNull())
2143 return;
2144
2145 /*********************************************************************/
2146 /* If a check pass was done while updating, all node contruction */
2147 /* has been already one. */
2148 /*********************************************************************/
2149 if (Status && Tdbp->Checked) {
2150 assert (ValNode);
2151 goto fin;
2152 } // endif Checked
2153
2154 /*********************************************************************/
2155 /* On Insert, a Row node must be created for each row; */
2156 /* For all columns the Clist must be updated. */
2157 /*********************************************************************/
2158 if (Tdbp->CheckRow(g, true))
2159 throw (int)TYPE_AM_XML;
2160
2161 /*********************************************************************/
2162 /* Find the column and value nodes to update or insert. */
2163 /*********************************************************************/
2164 if (Tdbp->Clist == NULL) {
2165 strcpy(g->Message, MSG(MIS_TAG_LIST));
2166 throw (int)TYPE_AM_XML;
2167 } // endif Clist
2168
2169 n = Tdbp->Clist->GetLength();
2170 k = Rank;
2171
2172 if (!(ValNode = Tdbp->Clist->GetItem(g, k, Vxnp))) {
2173 /*******************************************************************/
2174 /* Create missing column nodes. */
2175 /*******************************************************************/
2176 Tdbp->RowNode->AddText(g, "\n\t\t");
2177
2178 for (i = n; i <= k; i++)
2179 ValNode = Tdbp->RowNode->AddChildNode(g, Tdbp->Colname, Vxnp);
2180
2181 assert (ValNode);
2182 } // endif ValNode
2183
2184 /*********************************************************************/
2185 /* Get the string representation of Value according to column type. */
2186 /*********************************************************************/
2187 p = Value->GetCharString(buf);
2188
2189 if (strlen(p) > (unsigned)Long) {
2190 sprintf(g->Message, MSG(VALUE_TOO_LONG), p, Name, Long);
2191 throw (int)TYPE_AM_XML;
2192 } else
2193 strcpy(Valbuf, p);
2194
2195 /*********************************************************************/
2196 /* Updating must be done only when not in checking pass. */
2197 /*********************************************************************/
2198 fin:
2199 if (Status)
2200 ValNode->SetContent(g, Valbuf, Long);
2201
2202 } // end of WriteColumn
2203
2204/* ---------------------------TDBXCT class --------------------------- */
2205
2206/***********************************************************************/
2207/* TDBXCT class constructor. */
2208/***********************************************************************/
2209TDBXCT::TDBXCT(PXMLDEF tdp) : TDBCAT(tdp)
2210 {
2211 Topt = tdp->GetTopt();
2212 Db = (char*)tdp->GetDB();
2213 Tabn = tdp->Tabname;
2214 } // end of TDBXCT constructor
2215
2216/***********************************************************************/
2217/* GetResult: Get the list the JSON file columns. */
2218/***********************************************************************/
2219PQRYRES TDBXCT::GetResult(PGLOBAL g)
2220 {
2221 return XMLColumns(g, Db, Tabn, Topt, false);
2222 } // end of GetResult
2223
2224/* ------------------------ End of Tabxml ---------------------------- */
2225