1/************ Valblk C++ Functions Source Code File (.CPP) *************/
2/* Name: VALBLK.CPP Version 2.3 */
3/* */
4/* (C) Copyright to the author Olivier BERTRAND 2005-2017 */
5/* */
6/* This file contains the VALBLK and derived classes functions. */
7/* Second family is VALBLK, representing simple suballocated arrays */
8/* of values treated sequentially by FIX, BIN and VCT tables and */
9/* columns, as well for min/max blocks as for VCT column blocks. */
10/* Q&A: why not using only one family ? Simple values are arrays that */
11/* have only one element and arrays could have functions for all kind */
12/* of processing. The answer is a-because historically it was simpler */
13/* to do that way, b-because of performance on single values, and c- */
14/* to avoid too complicated classes and unuseful duplication of many */
15/* functions used on one family only. The drawback is that for new */
16/* types of objects, we shall have more classes to update. */
17/* This is why we are now using a template class for many types. */
18/* Currently the only implemented types are PSZ, chars, int, short, */
19/* DATE, longlong, double and tiny. Fix numeric ones can be unsigned. */
20/***********************************************************************/
21
22/***********************************************************************/
23/* Include relevant MariaDB header file. */
24/***********************************************************************/
25#include "my_global.h"
26#if defined(__WIN__)
27//#include <windows.h>
28#else
29#include "osutil.h"
30#include "string.h"
31#endif
32
33/***********************************************************************/
34/* Include required application header files */
35/* global.h is header containing all global Plug declarations. */
36/* plgdbsem.h is header containing the DB applic. declarations. */
37/* valblk.h is header containing VALBLK derived classes declares. */
38/***********************************************************************/
39#include "global.h"
40#include "plgdbsem.h"
41#include "valblk.h"
42
43#define CheckBlanks assert(!Blanks);
44#define CheckParms(V, N) ChkIndx(N); ChkTyp(V);
45
46extern MBLOCK Nmblk; /* Used to initialize MBLOCK's */
47
48/***********************************************************************/
49/* AllocValBlock: allocate a VALBLK according to type. */
50/***********************************************************************/
51PVBLK AllocValBlock(PGLOBAL g, void *mp, int type, int nval, int len,
52 int prec, bool check, bool blank, bool un)
53 {
54 PVBLK blkp;
55
56 if (trace(1))
57 htrc("AVB: mp=%p type=%d nval=%d len=%d check=%u blank=%u\n",
58 mp, type, nval, len, check, blank);
59
60 switch (type) {
61 case TYPE_STRING:
62 case TYPE_BIN:
63 case TYPE_DECIM:
64 if (len)
65 blkp = new(g) CHRBLK(mp, nval, type, len, prec, blank);
66 else
67 blkp = new(g) STRBLK(g, mp, nval, type);
68
69 break;
70 case TYPE_SHORT:
71 if (un)
72 blkp = new(g) TYPBLK<ushort>(mp, nval, type, 0, true);
73 else
74 blkp = new(g) TYPBLK<short>(mp, nval, type);
75
76 break;
77 case TYPE_INT:
78 if (un)
79 blkp = new(g) TYPBLK<uint>(mp, nval, type, 0, true);
80 else
81 blkp = new(g) TYPBLK<int>(mp, nval, type);
82
83 break;
84 case TYPE_DATE: // ?????
85 blkp = new(g) DATBLK(mp, nval);
86 break;
87 case TYPE_BIGINT:
88 if (un)
89 blkp = new(g) TYPBLK<ulonglong>(mp, nval, type, 0, true);
90 else
91 blkp = new(g) TYPBLK<longlong>(mp, nval, type);
92
93 break;
94 case TYPE_DOUBLE:
95 blkp = new(g) TYPBLK<double>(mp, nval, type, prec);
96 break;
97 case TYPE_TINY:
98 if (un)
99 blkp = new(g) TYPBLK<uchar>(mp, nval, type, 0, true);
100 else
101 blkp = new(g) TYPBLK<char>(mp, nval, type);
102
103 break;
104 case TYPE_PCHAR:
105 blkp = new(g) PTRBLK(g, mp, nval);
106 break;
107 default:
108 sprintf(g->Message, MSG(BAD_VALBLK_TYPE), type);
109 return NULL;
110 } // endswitch Type
111
112 return (blkp->Init(g, check)) ? NULL : blkp;
113 } // end of AllocValBlock
114
115/* -------------------------- Class VALBLK --------------------------- */
116
117/***********************************************************************/
118/* Constructor. */
119/***********************************************************************/
120VALBLK::VALBLK(void *mp, int type, int nval, bool un)
121 {
122 Mblk = Nmblk;
123 Blkp = mp;
124 To_Nulls = NULL;
125 Check = true;
126 Nullable = false;
127 Unsigned = un;
128 Type = type;
129 Nval = nval;
130 Prec = 0;
131 } // end of VALBLK constructor
132
133/***********************************************************************/
134/* Raise error for numeric types. */
135/***********************************************************************/
136PSZ VALBLK::GetCharValue(int)
137 {
138 PGLOBAL& g = Global;
139
140 assert(g);
141 sprintf(g->Message, MSG(NO_CHAR_FROM), Type);
142 throw Type;
143 return NULL;
144 } // end of GetCharValue
145
146/***********************************************************************/
147/* Set format so formatted dates can be converted on input. */
148/***********************************************************************/
149bool VALBLK::SetFormat(PGLOBAL g, PCSZ, int, int)
150 {
151 sprintf(g->Message, MSG(NO_DATE_FMT), Type);
152 return true;
153 } // end of SetFormat
154
155/***********************************************************************/
156/* Set the index of the location of value and return true if found. */
157/* To be used on ascending sorted arrays only. */
158/* Currently used by some BLKFIL classes only. */
159/***********************************************************************/
160bool VALBLK::Locate(PVAL vp, int& i)
161 {
162 ChkTyp(vp);
163
164 int n = 1;
165
166 for (i = 0; i < Nval; i++)
167 if ((n = CompVal(vp, i)) <= 0)
168 break;
169
170 return (!n);
171 } // end of Locate
172
173/***********************************************************************/
174/* Set Nullable and allocate the Null array. */
175/***********************************************************************/
176void VALBLK::SetNullable(bool b)
177 {
178 if ((Nullable = b)) {
179 To_Nulls = (char*)PlugSubAlloc(Global, NULL, Nval);
180 memset(To_Nulls, 0, Nval);
181 } else
182 To_Nulls = NULL;
183
184 } // end of SetNullable
185
186/***********************************************************************/
187/* Buffer allocation routine. */
188/***********************************************************************/
189bool VALBLK::AllocBuff(PGLOBAL g, size_t size)
190 {
191 Mblk.Size = size;
192
193 if (!(Blkp = PlgDBalloc(g, NULL, Mblk))) {
194 sprintf(g->Message, MSG(MEM_ALLOC_ERR), "Blkp", (int) Mblk.Size);
195 fprintf(stderr, "%s\n", g->Message);
196 return true;
197 } // endif Blkp
198
199 return false;
200 } // end of AllocBuff
201
202/***********************************************************************/
203/* Check functions. */
204/***********************************************************************/
205void VALBLK::ChkIndx(int n)
206 {
207 if (n < 0 || n >= Nval) {
208 PGLOBAL& g = Global;
209 strcpy(g->Message, MSG(BAD_VALBLK_INDX));
210 throw Type;
211 } // endif n
212
213 } // end of ChkIndx
214
215void VALBLK::ChkTyp(PVAL v)
216 {
217 if (Check && (Type != v->GetType() || Unsigned != v->IsUnsigned())) {
218 PGLOBAL& g = Global;
219 strcpy(g->Message, MSG(VALTYPE_NOMATCH));
220 throw Type;
221 } // endif Type
222
223 } // end of ChkTyp
224
225void VALBLK::ChkTyp(PVBLK vb)
226 {
227 if (Check && (Type != vb->GetType() || Unsigned != vb->IsUnsigned())) {
228 PGLOBAL& g = Global;
229 strcpy(g->Message, MSG(VALTYPE_NOMATCH));
230 throw Type;
231 } // endif Type
232
233 } // end of ChkTyp
234
235/* -------------------------- Class TYPBLK --------------------------- */
236
237/***********************************************************************/
238/* Constructor. */
239/***********************************************************************/
240template <class TYPE>
241TYPBLK<TYPE>::TYPBLK(void *mp, int nval, int type, int prec, bool un)
242 : VALBLK(mp, type, nval, un), Typp((TYPE*&)Blkp)
243 {
244 Prec = prec;
245 Fmt = GetFmt(Type);
246 } // end of TYPBLK constructor
247
248/***********************************************************************/
249/* Initialization routine. */
250/***********************************************************************/
251template <class TYPE>
252bool TYPBLK<TYPE>::Init(PGLOBAL g, bool check)
253 {
254 if (!Blkp)
255 if (AllocBuff(g, Nval * sizeof(TYPE)))
256 return true;
257
258 Check = check;
259 Global = g;
260 return false;
261 } // end of Init
262
263/***********************************************************************/
264/* TYPVAL GetCharString: get string representation of a typed value. */
265/***********************************************************************/
266template <class TYPE>
267char *TYPBLK<TYPE>::GetCharString(char *p, int n)
268 {
269 sprintf(p, Fmt, Typp[n]);
270 return p;
271 } // end of GetCharString
272
273template <>
274char *TYPBLK<double>::GetCharString(char *p, int n)
275 {
276 sprintf(p, Fmt, Prec, Typp[n]);
277 return p;
278 } // end of GetCharString
279
280/***********************************************************************/
281/* Set one value in a block. */
282/***********************************************************************/
283template <class TYPE>
284void TYPBLK<TYPE>::SetValue(PVAL valp, int n)
285 {
286 bool b;
287
288 ChkIndx(n);
289 ChkTyp(valp);
290
291 if (!(b = valp->IsNull()))
292 Typp[n] = GetTypedValue(valp);
293 else
294 Reset(n);
295
296 SetNull(n, b && Nullable);
297 } // end of SetValue
298
299template <>
300int TYPBLK<int>::GetTypedValue(PVAL valp)
301 {return valp->GetIntValue();}
302
303template <>
304uint TYPBLK<uint>::GetTypedValue(PVAL valp)
305 {return valp->GetUIntValue();}
306
307template <>
308short TYPBLK<short>::GetTypedValue(PVAL valp)
309 {return valp->GetShortValue();}
310
311template <>
312ushort TYPBLK<ushort>::GetTypedValue(PVAL valp)
313 {return valp->GetUShortValue();}
314
315template <>
316longlong TYPBLK<longlong>::GetTypedValue(PVAL valp)
317 {return valp->GetBigintValue();}
318
319template <>
320ulonglong TYPBLK<ulonglong>::GetTypedValue(PVAL valp)
321 {return valp->GetUBigintValue();}
322
323template <>
324double TYPBLK<double>::GetTypedValue(PVAL valp)
325 {return valp->GetFloatValue();}
326
327template <>
328char TYPBLK<char>::GetTypedValue(PVAL valp)
329 {return valp->GetTinyValue();}
330
331template <>
332uchar TYPBLK<uchar>::GetTypedValue(PVAL valp)
333 {return valp->GetUTinyValue();}
334
335/***********************************************************************/
336/* Set one value in a block from a zero terminated string. */
337/***********************************************************************/
338template <class TYPE>
339void TYPBLK<TYPE>::SetValue(PCSZ p, int n)
340 {
341 ChkIndx(n);
342
343 if (Check) {
344 PGLOBAL& g = Global;
345 strcpy(g->Message, MSG(BAD_SET_STRING));
346 throw Type;
347 } // endif Check
348
349 bool minus;
350 ulonglong maxval = MaxVal();
351 ulonglong val = CharToNumber(p, strlen(p), maxval, Unsigned, &minus);
352
353 if (minus && val < maxval)
354 Typp[n] = (TYPE)(-(signed)val);
355 else
356 Typp[n] = (TYPE)val;
357
358 SetNull(n, false);
359 } // end of SetValue
360
361template <class TYPE>
362ulonglong TYPBLK<TYPE>::MaxVal(void) {DBUG_ASSERT(false); return 0;}
363
364template <>
365ulonglong TYPBLK<short>::MaxVal(void) {return INT_MAX16;}
366
367template <>
368ulonglong TYPBLK<ushort>::MaxVal(void) {return UINT_MAX16;}
369
370template <>
371ulonglong TYPBLK<int>::MaxVal(void) {return INT_MAX32;}
372
373template <>
374ulonglong TYPBLK<uint>::MaxVal(void) {return UINT_MAX32;}
375
376template <>
377ulonglong TYPBLK<char>::MaxVal(void) {return INT_MAX8;}
378
379template <>
380ulonglong TYPBLK<uchar>::MaxVal(void) {return UINT_MAX8;}
381
382template <>
383ulonglong TYPBLK<longlong>::MaxVal(void) {return INT_MAX64;}
384
385template <>
386ulonglong TYPBLK<ulonglong>::MaxVal(void) {return ULONGLONG_MAX;}
387
388template <>
389void TYPBLK<double>::SetValue(PCSZ p, int n)
390 {
391 ChkIndx(n);
392
393 if (Check) {
394 PGLOBAL& g = Global;
395 strcpy(g->Message, MSG(BAD_SET_STRING));
396 throw Type;
397 } // endif Check
398
399 Typp[n] = atof(p);
400 SetNull(n, false);
401 } // end of SetValue
402
403/***********************************************************************/
404/* Set one value in a block from an array of characters. */
405/***********************************************************************/
406template <class TYPE>
407void TYPBLK<TYPE>::SetValue(PCSZ sp, uint len, int n)
408 {
409 PGLOBAL& g = Global;
410 PSZ spz = (PSZ)PlugSubAlloc(g, NULL, 0); // Temporary
411
412 if (sp)
413 memcpy(spz, sp, len);
414
415 spz[len] = 0;
416 SetValue(spz, n);
417 } // end of SetValue
418
419/***********************************************************************/
420/* Set one value in a block from a value in another block. */
421/***********************************************************************/
422template <class TYPE>
423void TYPBLK<TYPE>::SetValue(PVBLK pv, int n1, int n2)
424 {
425 bool b;
426
427 ChkIndx(n1);
428 ChkTyp(pv);
429
430 if (!(b = pv->IsNull(n2) && Nullable))
431 Typp[n1] = GetTypedValue(pv, n2);
432 else
433 Reset(n1);
434
435 SetNull(n1, b);
436 } // end of SetValue
437
438template <>
439int TYPBLK<int>::GetTypedValue(PVBLK blk, int n)
440 {return blk->GetIntValue(n);}
441
442template <>
443uint TYPBLK<uint>::GetTypedValue(PVBLK blk, int n)
444 {return blk->GetUIntValue(n);}
445
446template <>
447short TYPBLK<short>::GetTypedValue(PVBLK blk, int n)
448 {return blk->GetShortValue(n);}
449
450template <>
451ushort TYPBLK<ushort>::GetTypedValue(PVBLK blk, int n)
452 {return blk->GetUShortValue(n);}
453
454template <>
455longlong TYPBLK<longlong>::GetTypedValue(PVBLK blk, int n)
456 {return blk->GetBigintValue(n);}
457
458template <>
459ulonglong TYPBLK<ulonglong>::GetTypedValue(PVBLK blk, int n)
460 {return blk->GetUBigintValue(n);}
461
462template <>
463double TYPBLK<double>::GetTypedValue(PVBLK blk, int n)
464 {return blk->GetFloatValue(n);}
465
466template <>
467char TYPBLK<char>::GetTypedValue(PVBLK blk, int n)
468 {return blk->GetTinyValue(n);}
469
470template <>
471uchar TYPBLK<uchar>::GetTypedValue(PVBLK blk, int n)
472 {return blk->GetUTinyValue(n);}
473
474/***********************************************************************/
475/* Set one value in a block if val is less than the current value. */
476/***********************************************************************/
477template <class TYPE>
478void TYPBLK<TYPE>::SetMin(PVAL valp, int n)
479 {
480 CheckParms(valp, n)
481 TYPE tval = GetTypedValue(valp);
482 TYPE& tmin = Typp[n];
483
484 if (tval < tmin)
485 tmin = tval;
486
487 } // end of SetMin
488
489/***********************************************************************/
490/* Set one value in a block if val is greater than the current value. */
491/***********************************************************************/
492template <class TYPE>
493void TYPBLK<TYPE>::SetMax(PVAL valp, int n)
494 {
495 CheckParms(valp, n)
496 TYPE tval = GetTypedValue(valp);
497 TYPE& tmin = Typp[n];
498
499 if (tval > tmin)
500 tmin = tval;
501
502 } // end of SetMax
503
504#if 0
505/***********************************************************************/
506/* Set many values in a block from values in another block. */
507/***********************************************************************/
508template <class TYPE>
509void TYPBLK<TYPE>::SetValues(PVBLK pv, int k, int n)
510 {
511 CheckType(pv)
512 TYPE *lp = ((TYPBLK*)pv)->Typp;
513
514 for (register int i = k; i < n; i++) // TODO
515 Typp[i] = lp[i];
516
517 } // end of SetValues
518#endif // 0
519
520/***********************************************************************/
521/* Move one value from i to j. */
522/***********************************************************************/
523template <class TYPE>
524void TYPBLK<TYPE>::Move(int i, int j)
525 {
526 Typp[j] = Typp[i];
527 MoveNull(i, j);
528 } // end of Move
529
530/***********************************************************************/
531/* Compare a Value object with the nth value of the block. */
532/***********************************************************************/
533template <class TYPE>
534int TYPBLK<TYPE>::CompVal(PVAL vp, int n)
535 {
536#if defined(_DEBUG)
537 ChkIndx(n);
538 ChkTyp(vp);
539#endif // _DEBUG
540 TYPE mlv = Typp[n];
541 TYPE vlv = GetTypedValue(vp);
542
543 return (vlv > mlv) ? 1 : (vlv < mlv) ? (-1) : 0;
544 } // end of CompVal
545
546/***********************************************************************/
547/* Compare two values of the block. */
548/***********************************************************************/
549template <class TYPE>
550int TYPBLK<TYPE>::CompVal(int i1, int i2)
551 {
552 TYPE lv1 = Typp[i1];
553 TYPE lv2 = Typp[i2];
554
555 return (lv1 > lv2) ? 1 : (lv1 < lv2) ? (-1) : 0;
556 } // end of CompVal
557
558/***********************************************************************/
559/* Get a pointer on the nth value of the block. */
560/***********************************************************************/
561template <class TYPE>
562void *TYPBLK<TYPE>::GetValPtr(int n)
563 {
564 ChkIndx(n);
565 return Typp + n;
566 } // end of GetValPtr
567
568/***********************************************************************/
569/* Get a pointer on the nth value of the block. */
570/***********************************************************************/
571template <class TYPE>
572void *TYPBLK<TYPE>::GetValPtrEx(int n)
573 {
574 ChkIndx(n);
575 return Typp + n;
576 } // end of GetValPtrEx
577
578/***********************************************************************/
579/* Returns index of matching value in block or -1. */
580/***********************************************************************/
581template <class TYPE>
582int TYPBLK<TYPE>::Find(PVAL vp)
583 {
584 ChkTyp(vp);
585
586 int i;
587 TYPE n = GetTypedValue(vp);
588
589 for (i = 0; i < Nval; i++)
590 if (n == Typp[i])
591 break;
592
593 return (i < Nval) ? i : (-1);
594 } // end of Find
595
596/***********************************************************************/
597/* Returns the length of the longest string in the block. */
598/***********************************************************************/
599template <class TYPE>
600int TYPBLK<TYPE>::GetMaxLength(void)
601 {
602 char buf[64];
603 int i, n, m;
604
605 for (i = n = 0; i < Nval; i++) {
606 m = sprintf(buf, Fmt, Typp[i]);
607 n = MY_MAX(n, m);
608 } // endfor i
609
610 return n;
611 } // end of GetMaxLength
612
613
614/* -------------------------- Class CHRBLK --------------------------- */
615
616/***********************************************************************/
617/* Constructor. */
618/***********************************************************************/
619CHRBLK::CHRBLK(void *mp, int nval, int type, int len, int prec, bool blank)
620 : VALBLK(mp, type, nval), Chrp((char*&)Blkp)
621 {
622 Valp = NULL;
623 Blanks = blank;
624 Ci = (prec != 0);
625 Long = len;
626 } // end of CHRBLK constructor
627
628/***********************************************************************/
629/* Initialization routine. */
630/***********************************************************************/
631bool CHRBLK::Init(PGLOBAL g, bool check)
632 {
633 Valp = (char*)PlugSubAlloc(g, NULL, Long + 1);
634 Valp[Long] = '\0';
635
636 if (!Blkp)
637 if (AllocBuff(g, Nval * Long))
638 return true;
639
640 Check = check;
641 Global = g;
642 return false;
643 } // end of Init
644
645/***********************************************************************/
646/* Reset nth element to a null string. */
647/***********************************************************************/
648void CHRBLK::Reset(int n)
649 {
650 if (Blanks)
651 memset(Chrp + n * Long, ' ', Long);
652 else
653 *(Chrp + n * Long) = '\0';
654
655 } // end of Reset
656
657/***********************************************************************/
658/* Return the zero ending value of the nth element. */
659/***********************************************************************/
660char *CHRBLK::GetCharValue(int n)
661 {
662 return (char *)GetValPtrEx(n);
663 } // end of GetCharValue
664
665/***********************************************************************/
666/* Return the value of the nth element converted to tiny int. */
667/***********************************************************************/
668char CHRBLK::GetTinyValue(int n)
669 {
670 bool m;
671 ulonglong val = CharToNumber((char*)GetValPtr(n), Long, INT_MAX8,
672 false, &m);
673
674 return (m && val < INT_MAX8) ? (char)(-(signed)val) : (char)val;
675 } // end of GetTinyValue
676
677/***********************************************************************/
678/* Return the value of the nth element converted to unsigned tiny int.*/
679/***********************************************************************/
680uchar CHRBLK::GetUTinyValue(int n)
681 {
682 return (uchar)CharToNumber((char*)GetValPtr(n), Long, UINT_MAX8, true);
683 } // end of GetTinyValue
684
685/***********************************************************************/
686/* Return the value of the nth element converted to short. */
687/***********************************************************************/
688short CHRBLK::GetShortValue(int n)
689 {
690 bool m;
691 ulonglong val = CharToNumber((char*)GetValPtr(n), Long, INT_MAX16,
692 false, &m);
693
694 return (m && val < INT_MAX16) ? (short)(-(signed)val) : (short)val;
695 } // end of GetShortValue
696
697/***********************************************************************/
698/* Return the value of the nth element converted to ushort. */
699/***********************************************************************/
700ushort CHRBLK::GetUShortValue(int n)
701 {
702 return (ushort)CharToNumber((char*)GetValPtr(n), Long, UINT_MAX16, true);
703 } // end of GetShortValue
704
705/***********************************************************************/
706/* Return the value of the nth element converted to int. */
707/***********************************************************************/
708int CHRBLK::GetIntValue(int n)
709 {
710 bool m;
711 ulonglong val = CharToNumber((char*)GetValPtr(n), Long, INT_MAX32,
712 false, &m);
713
714 return (m && val < INT_MAX32) ? (int)(-(signed)val) : (int)val;
715 } // end of GetIntValue
716
717/***********************************************************************/
718/* Return the value of the nth element converted to uint. */
719/***********************************************************************/
720uint CHRBLK::GetUIntValue(int n)
721 {
722 return (uint)CharToNumber((char*)GetValPtr(n), Long, UINT_MAX32, true);
723 } // end of GetIntValue
724
725/***********************************************************************/
726/* Return the value of the nth element converted to big int. */
727/***********************************************************************/
728longlong CHRBLK::GetBigintValue(int n)
729 {
730 bool m;
731 ulonglong val = CharToNumber((char*)GetValPtr(n), Long, INT_MAX64,
732 false, &m);
733
734 return (m && val < INT_MAX64) ? (longlong)(-(signed)val) : (longlong)val;
735 } // end of GetBigintValue
736
737/***********************************************************************/
738/* Return the value of the nth element converted to unsigned big int. */
739/***********************************************************************/
740ulonglong CHRBLK::GetUBigintValue(int n)
741 {
742 return CharToNumber((char*)GetValPtr(n), Long, ULONGLONG_MAX, true);
743 } // end of GetUBigintValue
744
745/***********************************************************************/
746/* Return the value of the nth element converted to double. */
747/***********************************************************************/
748double CHRBLK::GetFloatValue(int n)
749 {
750 return atof((char *)GetValPtrEx(n));
751 } // end of GetFloatValue
752
753/***********************************************************************/
754/* STRING GetCharString: get string representation of a char value. */
755/***********************************************************************/
756char *CHRBLK::GetCharString(char *, int n)
757 {
758 return (char *)GetValPtrEx(n);
759 } // end of GetCharString
760
761/***********************************************************************/
762/* Set one value in a block. */
763/***********************************************************************/
764void CHRBLK::SetValue(PVAL valp, int n)
765 {
766 bool b;
767
768 ChkIndx(n);
769 ChkTyp(valp);
770
771 if (!(b = valp->IsNull()))
772 SetValue((PSZ)valp->GetCharValue(), n);
773 else
774 Reset(n);
775
776 SetNull(n, b && Nullable);
777 } // end of SetValue
778
779/***********************************************************************/
780/* Set one value in a block from a zero terminated string. */
781/***********************************************************************/
782void CHRBLK::SetValue(PCSZ sp, int n)
783 {
784 uint len = (sp) ? strlen(sp) : 0;
785 SetValue(sp, len, n);
786 } // end of SetValue
787
788/***********************************************************************/
789/* Set one value in a block from an array of characters. */
790/***********************************************************************/
791void CHRBLK::SetValue(const char *sp, uint len, int n)
792 {
793 char *p = Chrp + n * Long;
794
795#if defined(_DEBUG)
796 if (Check && (signed)len > Long) {
797 PGLOBAL& g = Global;
798 strcpy(g->Message, MSG(SET_STR_TRUNC));
799 throw Type;
800 } // endif Check
801#endif // _DEBUG
802
803 if (sp)
804 memcpy(p, sp, MY_MIN((unsigned)Long, len));
805
806 if (Blanks) {
807 // Suppress eventual ending zero and right fill with blanks
808 for (register int i = len; i < Long; i++)
809 p[i] = ' ';
810
811 } else if ((signed)len < Long)
812 p[len] = 0;
813
814 SetNull(n, false);
815 } // end of SetValue
816
817/***********************************************************************/
818/* Set one value in a block from a value in another block. */
819/***********************************************************************/
820void CHRBLK::SetValue(PVBLK pv, int n1, int n2)
821 {
822 bool b;
823
824 if (Type != pv->GetType() || Long != ((CHRBLK*)pv)->Long) {
825 PGLOBAL& g = Global;
826 strcpy(g->Message, MSG(BLKTYPLEN_MISM));
827 throw Type;
828 } // endif Type
829
830 if (!(b = pv->IsNull(n2)))
831 memcpy(Chrp + n1 * Long, ((CHRBLK*)pv)->Chrp + n2 * Long, Long);
832 else
833 Reset(n1);
834
835 SetNull(n1, b && Nullable);
836 } // end of SetValue
837
838/***********************************************************************/
839/* Set one value in a block if val is less than the current value. */
840/***********************************************************************/
841void CHRBLK::SetMin(PVAL valp, int n)
842 {
843 CheckParms(valp, n)
844 CheckBlanks
845 char *vp = valp->GetCharValue();
846 char *bp = Chrp + n * Long;
847
848 if (((Ci) ? strnicmp(vp, bp, Long) : strncmp(vp, bp, Long)) < 0)
849 memcpy(bp, vp, Long);
850
851 } // end of SetMin
852
853/***********************************************************************/
854/* Set one value in a block if val is greater than the current value. */
855/***********************************************************************/
856void CHRBLK::SetMax(PVAL valp, int n)
857 {
858 CheckParms(valp, n)
859 CheckBlanks
860 char *vp = valp->GetCharValue();
861 char *bp = Chrp + n * Long;
862
863 if (((Ci) ? strnicmp(vp, bp, Long) : strncmp(vp, bp, Long)) > 0)
864 memcpy(bp, vp, Long);
865
866 } // end of SetMax
867
868#if 0
869/***********************************************************************/
870/* Set many values in a block from values in another block. */
871/***********************************************************************/
872void CHRBLK::SetValues(PVBLK pv, int k, int n)
873 {
874#if defined(_DEBUG)
875 if (Type != pv->GetType() || Long != ((CHRBLK*)pv)->Long) {
876 PGLOBAL& g = Global;
877 strcpy(g->Message, MSG(BLKTYPLEN_MISM));
878 throw Type;
879 } // endif Type
880#endif // _DEBUG
881 char *p = ((CHRBLK*)pv)->Chrp;
882
883 if (!k)
884 memcpy(Chrp, p, Long * n);
885 else
886 memcpy(Chrp + k * Long, p + k * Long, Long * (n - k));
887
888 } // end of SetValues
889#endif // 0
890
891/***********************************************************************/
892/* Move one value from i to j. */
893/***********************************************************************/
894void CHRBLK::Move(int i, int j)
895 {
896 if (i != j) {
897 memcpy(Chrp + j * Long, Chrp + i * Long, Long);
898 MoveNull(i, j);
899 } // endif i
900
901 } // end of Move
902
903/***********************************************************************/
904/* Compare a Value object with the nth value of the block. */
905/***********************************************************************/
906int CHRBLK::CompVal(PVAL vp, int n)
907 {
908 ChkIndx(n);
909 ChkTyp(vp);
910
911 char *xvp = vp->GetCharValue(); // Get Value zero ended string
912 bool ci = Ci || vp->IsCi(); // true if is case insensitive
913
914 GetValPtrEx(n); // Get a zero ended string in Valp
915 return (ci) ? stricmp(xvp, Valp) : strcmp(xvp, Valp);
916 } // end of CompVal
917
918/***********************************************************************/
919/* Compare two values of the block. */
920/***********************************************************************/
921int CHRBLK::CompVal(int i1, int i2)
922 {
923 return (Ci) ? strnicmp(Chrp + i1 * Long, Chrp + i2 * Long, Long)
924 : strncmp(Chrp + i1 * Long, Chrp + i2 * Long, Long);
925 } // end of CompVal
926
927/***********************************************************************/
928/* Get a pointer on the nth value of the block. */
929/***********************************************************************/
930void *CHRBLK::GetValPtr(int n)
931 {
932 ChkIndx(n);
933 return Chrp + n * Long;
934 } // end of GetValPtr
935
936/***********************************************************************/
937/* Get a pointer on a zero ended string equal to nth value. */
938/***********************************************************************/
939void *CHRBLK::GetValPtrEx(int n)
940 {
941 ChkIndx(n);
942 memcpy(Valp, Chrp + n * Long, Long);
943
944 if (IsNull(n))
945 return const_cast<char *>("");
946
947 if (Blanks) {
948 // The (fast) way this is done works only for blocks such
949 // as Min and Max where strings are stored with the ending 0
950 // except for those whose length is equal to Len.
951 // For VCT blocks we must remove rightmost blanks.
952 char *p = Valp + Long;
953
954 for (p--; p >= Valp && *p == ' '; p--) ;
955
956 *(++p) = '\0';
957 } // endif Blanks
958
959 return Valp;
960 } // end of GetValPtrEx
961
962/***********************************************************************/
963/* Returns index of matching value in block or -1. */
964/***********************************************************************/
965int CHRBLK::Find(PVAL vp)
966 {
967 ChkTyp(vp);
968
969 int i;
970 bool ci = Ci || vp->IsCi();
971 PSZ s = vp->GetCharValue();
972
973 if (vp->IsNull())
974 return -1;
975
976 for (i = 0; i < Nval; i++) {
977 if (IsNull(i))
978 continue;
979
980 GetValPtrEx(i); // Get a zero ended string in Valp
981
982 if (!((ci) ? strnicmp(s, Valp, Long) : strncmp(s, Valp, Long)))
983 break;
984
985 } // endfor i
986
987 return (i < Nval) ? i : (-1);
988 } // end of Find
989
990/***********************************************************************/
991/* Returns the length of the longest string in the block. */
992/***********************************************************************/
993int CHRBLK::GetMaxLength(void)
994 {
995 int i, n;
996
997 for (i = n = 0; i < Nval; i++)
998 if (!IsNull(i)) {
999 GetValPtrEx(i);
1000 n = MY_MAX(n, (signed)strlen(Valp));
1001 } // endif null
1002
1003 return n;
1004 } // end of GetMaxLength
1005
1006
1007/* -------------------------- Class STRBLK --------------------------- */
1008
1009/***********************************************************************/
1010/* Constructor. */
1011/***********************************************************************/
1012STRBLK::STRBLK(PGLOBAL g, void *mp, int nval, int type)
1013 : VALBLK(mp, type, nval), Strp((PSZ*&)Blkp)
1014 {
1015 Global = g;
1016 Nullable = true;
1017 Sorted = false;
1018 } // end of STRBLK constructor
1019
1020/***********************************************************************/
1021/* Initialization routine. */
1022/***********************************************************************/
1023bool STRBLK::Init(PGLOBAL g, bool check)
1024 {
1025 if (!Blkp)
1026 if (AllocBuff(g, Nval * sizeof(PSZ)))
1027 return true;
1028
1029 Check = check;
1030 Global = g;
1031 return false;
1032 } // end of Init
1033
1034/***********************************************************************/
1035/* Get the tiny value represented by the Strp string. */
1036/***********************************************************************/
1037char STRBLK::GetTinyValue(int n)
1038 {
1039 bool m;
1040 ulonglong val = CharToNumber(Strp[n], strlen(Strp[n]), INT_MAX8,
1041 false, &m);
1042
1043 return (m && val < INT_MAX8) ? (char)(-(signed)val) : (char)val;
1044 } // end of GetTinyValue
1045
1046/***********************************************************************/
1047/* Get the unsigned tiny value represented by the Strp string. */
1048/***********************************************************************/
1049uchar STRBLK::GetUTinyValue(int n)
1050 {
1051 return (uchar)CharToNumber(Strp[n], strlen(Strp[n]), UINT_MAX8, true);
1052 } // end of GetUTinyValue
1053
1054/***********************************************************************/
1055/* Get the short value represented by the Strp string. */
1056/***********************************************************************/
1057short STRBLK::GetShortValue(int n)
1058 {
1059 bool m;
1060 ulonglong val = CharToNumber(Strp[n], strlen(Strp[n]), INT_MAX16,
1061 false, &m);
1062
1063 return (m && val < INT_MAX16) ? (short)(-(signed)val) : (short)val;
1064 } // end of GetShortValue
1065
1066/***********************************************************************/
1067/* Get the unsigned short value represented by the Strp string. */
1068/***********************************************************************/
1069ushort STRBLK::GetUShortValue(int n)
1070 {
1071 return (ushort)CharToNumber(Strp[n], strlen(Strp[n]), UINT_MAX16, true);
1072 } // end of GetUshortValue
1073
1074/***********************************************************************/
1075/* Get the integer value represented by the Strp string. */
1076/***********************************************************************/
1077int STRBLK::GetIntValue(int n)
1078 {
1079 bool m;
1080 ulonglong val = CharToNumber(Strp[n], strlen(Strp[n]), INT_MAX32,
1081 false, &m);
1082
1083 return (m && val < INT_MAX32) ? (int)(-(signed)val) : (int)val;
1084 } // end of GetIntValue
1085
1086/***********************************************************************/
1087/* Get the unsigned integer value represented by the Strp string. */
1088/***********************************************************************/
1089uint STRBLK::GetUIntValue(int n)
1090 {
1091 return (uint)CharToNumber(Strp[n], strlen(Strp[n]), UINT_MAX32, true);
1092 } // end of GetUintValue
1093
1094/***********************************************************************/
1095/* Get the big integer value represented by the Strp string. */
1096/***********************************************************************/
1097longlong STRBLK::GetBigintValue(int n)
1098 {
1099 bool m;
1100 ulonglong val = CharToNumber(Strp[n], strlen(Strp[n]), INT_MAX64,
1101 false, &m);
1102
1103 return (m && val < INT_MAX64) ? (-(signed)val) : (longlong)val;
1104 } // end of GetBigintValue
1105
1106/***********************************************************************/
1107/* Get the unsigned big integer value represented by the Strp string. */
1108/***********************************************************************/
1109ulonglong STRBLK::GetUBigintValue(int n)
1110 {
1111 return CharToNumber(Strp[n], strlen(Strp[n]), ULONGLONG_MAX, true);
1112 } // end of GetUBigintValue
1113
1114/***********************************************************************/
1115/* Set one value in a block from a value in another block. */
1116/***********************************************************************/
1117void STRBLK::SetValue(PVBLK pv, int n1, int n2)
1118 {
1119 ChkTyp(pv);
1120 Strp[n1] = (!pv->IsNull(n2)) ? ((STRBLK*)pv)->Strp[n2] : NULL;
1121 } // end of SetValue
1122
1123#if 0
1124/***********************************************************************/
1125/* Set many values in a block from values in another block. */
1126/***********************************************************************/
1127void STRBLK::SetValues(PVBLK pv, int k, int n)
1128 {
1129 CheckType(pv)
1130 PSZ *sp = ((STRBLK*)pv)->Strp;
1131
1132 for (register int i = k; i < n; i++)
1133 Strp[i] = (!pv->IsNull(i)) ? sp[i] : NULL;
1134
1135 } // end of SetValues
1136#endif // 0
1137
1138/***********************************************************************/
1139/* Set one value in a block. */
1140/***********************************************************************/
1141void STRBLK::SetValue(PVAL valp, int n)
1142 {
1143 ChkIndx(n);
1144 ChkTyp(valp);
1145
1146 if (!valp->IsNull())
1147 SetValue((PSZ)valp->GetCharValue(), n);
1148 else
1149 Strp[n] = NULL;
1150
1151 } // end of SetValue
1152
1153/***********************************************************************/
1154/* Set one value in a block from a zero terminated string. */
1155/***********************************************************************/
1156void STRBLK::SetValue(PCSZ p, int n)
1157 {
1158 if (p) {
1159 if (!Sorted || !n || !Strp[n-1] || strcmp(p, Strp[n-1]))
1160 Strp[n] = (PSZ)PlugDup(Global, p);
1161 else
1162 Strp[n] = Strp[n-1];
1163
1164 } else
1165 Strp[n] = NULL;
1166
1167 } // end of SetValue
1168
1169/***********************************************************************/
1170/* Set one value in a block from an array of characters. */
1171/***********************************************************************/
1172void STRBLK::SetValue(const char *sp, uint len, int n)
1173 {
1174 PSZ p;
1175
1176 if (sp) {
1177 if (!Sorted || !n || !Strp[n-1] || strlen(Strp[n-1]) != len ||
1178 strncmp(sp, Strp[n-1], len)) {
1179 p = (PSZ)PlugSubAlloc(Global, NULL, len + 1);
1180 memcpy(p, sp, len);
1181 p[len] = 0;
1182 } else
1183 p = Strp[n-1];
1184
1185 } else
1186 p = NULL;
1187
1188 Strp[n] = p;
1189 } // end of SetValue
1190
1191/***********************************************************************/
1192/* Set one value in a block if val is less than the current value. */
1193/***********************************************************************/
1194void STRBLK::SetMin(PVAL valp, int n)
1195 {
1196 CheckParms(valp, n)
1197 char *vp = valp->GetCharValue();
1198 char *bp = Strp[n];
1199
1200 if (strcmp(vp, bp) < 0)
1201 SetValue(valp, n);
1202
1203 } // end of SetMin
1204
1205/***********************************************************************/
1206/* Set one value in a block if val is greater than the current value. */
1207/***********************************************************************/
1208void STRBLK::SetMax(PVAL valp, int n)
1209 {
1210 CheckParms(valp, n)
1211 char *vp = valp->GetCharValue();
1212 char *bp = Strp[n];
1213
1214 if (strcmp(vp, bp) > 0)
1215 SetValue(valp, n);
1216
1217 } // end of SetMax
1218
1219/***********************************************************************/
1220/* Move one value from i to j. */
1221/***********************************************************************/
1222void STRBLK::Move(int i, int j)
1223 {
1224 Strp[j] = Strp[i];
1225 } // end of Move
1226
1227/***********************************************************************/
1228/* Compare a Value object with the nth value of the block. */
1229/***********************************************************************/
1230int STRBLK::CompVal(PVAL vp, int n)
1231 {
1232 ChkIndx(n);
1233 ChkTyp(vp);
1234
1235 if (vp->IsNull() || !Strp[n])
1236 DBUG_ASSERT(false);
1237
1238 return strcmp(vp->GetCharValue(), Strp[n]);
1239 } // end of CompVal
1240
1241/***********************************************************************/
1242/* Compare two values of the block. */
1243/***********************************************************************/
1244int STRBLK::CompVal(int i1, int i2)
1245 {
1246 if (!Strp[i1] || !Strp[i2])
1247 DBUG_ASSERT(false);
1248
1249 return (strcmp(Strp[i1], Strp[i2]));
1250 } // end of CompVal
1251
1252/***********************************************************************/
1253/* Get a pointer on the nth value of the block. */
1254/***********************************************************************/
1255void *STRBLK::GetValPtr(int n)
1256 {
1257 ChkIndx(n);
1258 return Strp + n;
1259 } // end of GetValPtr
1260
1261/***********************************************************************/
1262/* Get a pointer on a zero ended string equal to nth value. */
1263/***********************************************************************/
1264void *STRBLK::GetValPtrEx(int n)
1265 {
1266 ChkIndx(n);
1267 return (Strp[n]) ? Strp[n] : const_cast<char*>("");
1268 } // end of GetValPtrEx
1269
1270/***********************************************************************/
1271/* Returns index of matching value in block or -1. */
1272/***********************************************************************/
1273int STRBLK::Find(PVAL vp)
1274 {
1275 int i;
1276 PSZ s;
1277
1278 ChkTyp(vp);
1279
1280 if (vp->IsNull())
1281 return -1;
1282 else
1283 s = vp->GetCharValue();
1284
1285 for (i = 0; i < Nval; i++)
1286 if (Strp[i] && !strcmp(s, Strp[i]))
1287 break;
1288
1289 return (i < Nval) ? i : (-1);
1290 } // end of Find
1291
1292/***********************************************************************/
1293/* Returns the length of the longest string in the block. */
1294/***********************************************************************/
1295int STRBLK::GetMaxLength(void)
1296 {
1297 int i, n;
1298
1299 for (i = n = 0; i < Nval; i++)
1300 if (Strp[i])
1301 n = MY_MAX(n, (signed)strlen(Strp[i]));
1302
1303 return n;
1304 } // end of GetMaxLength
1305
1306/* -------------------------- Class DATBLK --------------------------- */
1307
1308/***********************************************************************/
1309/* Constructor. */
1310/***********************************************************************/
1311DATBLK::DATBLK(void *mp, int nval) : TYPBLK<int>(mp, nval, TYPE_INT)
1312 {
1313 Type = TYPE_DATE;
1314 Dvalp = NULL;
1315 } // end of DATBLK constructor
1316
1317/***********************************************************************/
1318/* Set format so formatted dates can be converted on input. */
1319/***********************************************************************/
1320bool DATBLK::SetFormat(PGLOBAL g, PCSZ fmt, int len, int year)
1321 {
1322 if (!(Dvalp = AllocateValue(g, TYPE_DATE, len, year, false, fmt)))
1323 return true;
1324
1325 return false;
1326 } // end of SetFormat
1327
1328/***********************************************************************/
1329/* DTVAL GetCharString: get string representation of a date value. */
1330/***********************************************************************/
1331char *DATBLK::GetCharString(char *p, int n)
1332 {
1333 char *vp;
1334
1335 if (Dvalp) {
1336 Dvalp->SetValue(Typp[n]);
1337 vp = Dvalp->GetCharString(p);
1338 } else
1339 vp = TYPBLK<int>::GetCharString(p, n);
1340
1341 return vp;
1342 } // end of GetCharString
1343
1344/***********************************************************************/
1345/* Set one value in a block from a char string. */
1346/***********************************************************************/
1347void DATBLK::SetValue(PCSZ p, int n)
1348 {
1349 if (Dvalp) {
1350 // Decode the string according to format
1351 Dvalp->SetValue_psz(p);
1352 Typp[n] = Dvalp->GetIntValue();
1353 } else
1354 TYPBLK<int>::SetValue(p, n);
1355
1356 } // end of SetValue
1357
1358
1359/* -------------------------- Class PTRBLK --------------------------- */
1360
1361/***********************************************************************/
1362/* Compare two values of the block. */
1363/***********************************************************************/
1364int PTRBLK::CompVal(int i1, int i2)
1365 {
1366 return (Strp[i1] > Strp[i2]) ? 1 : (Strp[i1] < Strp[i2]) ? (-1) : 0;
1367 } // end of CompVal
1368
1369
1370/* -------------------------- Class MBVALS --------------------------- */
1371
1372/***********************************************************************/
1373/* Allocate a value block according to type,len, and nb of values. */
1374/***********************************************************************/
1375PVBLK MBVALS::Allocate(PGLOBAL g, int type, int len, int prec,
1376 int n, bool sub)
1377 {
1378 Mblk.Sub = sub;
1379 Mblk.Size = n * GetTypeSize(type, len);
1380
1381 if (!PlgDBalloc(g, NULL, Mblk)) {
1382 sprintf(g->Message, MSG(ALLOC_ERROR), "MBVALS::Allocate");
1383 return NULL;
1384 } else
1385 Vblk = AllocValBlock(g, Mblk.Memp, type, n, len, prec,
1386 TRUE, TRUE, FALSE);
1387
1388 return Vblk;
1389 } // end of Allocate
1390
1391/***********************************************************************/
1392/* Reallocate the value block according to the new size. */
1393/***********************************************************************/
1394bool MBVALS::ReAllocate(PGLOBAL g, int n)
1395 {
1396 if (!PlgDBrealloc(g, NULL, Mblk, n * Vblk->GetVlen())) {
1397 sprintf(g->Message, MSG(ALLOC_ERROR), "MBVALS::ReAllocate");
1398 return TRUE;
1399 } else
1400 Vblk->ReAlloc(Mblk.Memp, n);
1401
1402 return FALSE;
1403 } // end of ReAllocate
1404
1405/***********************************************************************/
1406/* Free the value block. */
1407/***********************************************************************/
1408void MBVALS::Free(void)
1409 {
1410 PlgDBfree(Mblk);
1411 Vblk = NULL;
1412 } // end of Free
1413
1414/* ------------------------- End of Valblk --------------------------- */
1415
1416