1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // CegoBTreeValue.cc
4 // -----------------
5 // Cego index value class implementation
6 //
7 // Design and Implementation by Bjoern Lemke
8 //
9 // (C)opyright 2000-2019 Bjoern Lemke
10 //
11 // IMPLEMENTATION MODULE
12 //
13 // Class: CegoBTreeValue
14 //
15 // Description: This class handles all operations on btree values. Since the values are sequentially stored
16 // in a byte array, conversion methods are required to store, retrieve and for compare these values
17 //
18 // Status: CLEAN
19 //
20 ///////////////////////////////////////////////////////////////////////////////
21
22 // LFC INCLUDES
23 #include <lfcbase/Exception.h>
24
25 // CEGO INCLUDES
26 #include "CegoFieldValue.h"
27 #include "CegoBTreeValue.h"
28
29 // POSIX INCLUDES
30 #include <string.h>
31 #include <stdlib.h>
32
CegoBTreeValue()33 CegoBTreeValue::CegoBTreeValue()
34 {
35 _idxArray = 0;
36 _pI = 0;
37 _len = 0;
38 }
39
CegoBTreeValue(char * p,int len)40 CegoBTreeValue::CegoBTreeValue(char* p, int len)
41 {
42 _idxArray = 0;
43 _pI = p;
44 _len = len;
45 }
46
~CegoBTreeValue()47 CegoBTreeValue::~CegoBTreeValue()
48 {
49 // is local memory allocated ? ( just used for valueFromSchema )
50 if ( _idxArray )
51 free(_idxArray);
52 }
53
isNullTerminated(CegoDataType type)54 bool CegoBTreeValue::isNullTerminated(CegoDataType type)
55 {
56 if ( type == VARCHAR_TYPE
57 || type == BIGINT_TYPE
58 || type == DECIMAL_TYPE
59 || type == FIXED_TYPE )
60 return true;
61 return false;
62 }
63
getKeyLen(const ListT<CegoField> & schema)64 int CegoBTreeValue::getKeyLen(const ListT<CegoField>& schema)
65 {
66 CegoField *pF = schema.First();
67 int keyLen = 0;
68 while ( pF )
69 {
70 keyLen += 1; // null value indicator
71 keyLen += getReservedLength(pF);
72
73 // we have to add an additional character, in case of the full length
74 // of the attribute size defintion is used by the value
75 if ( isNullTerminated( pF->getType() ) )
76 keyLen += 1; // termination character
77
78 pF = schema.Next();
79 }
80 return keyLen;
81 }
82
getKeyPos(const Chain & attrName,const ListT<CegoField> & schema)83 int CegoBTreeValue::getKeyPos(const Chain& attrName, const ListT<CegoField>& schema)
84 {
85 CegoField *pF = schema.First();
86 int keypos = 0;
87 while ( pF )
88 {
89 keypos += 1; // null value indicator
90 if ( pF->getAttrName() == attrName )
91 return keypos;
92
93 keypos += getReservedLength(pF);
94
95 if ( isNullTerminated(pF->getType() ) )
96 keypos++;
97
98 pF = schema.Next();
99 }
100 throw Exception(EXLOC, "Attribute not found");
101 }
102
isNull(const ListT<CegoField> & schema) const103 bool CegoBTreeValue::isNull(const ListT<CegoField>& schema) const
104 {
105 CegoField* pF = schema.First();
106 char* idxPtr = _pI;
107 while (pF)
108 {
109 int len = getReservedLength(pF);
110
111 char nullIndicator;
112 memcpy(&nullIndicator, idxPtr, 1);
113 idxPtr += 1;
114
115 if ( nullIndicator == 1 )
116 {
117 return false;
118 }
119 else
120 {
121 idxPtr += len + 1;
122 if ( isNullTerminated(pF->getType() ) )
123 {
124 idxPtr += 1;
125 }
126 }
127
128 pF = schema.Next();
129 }
130 return true;
131 }
132
hasNull(const ListT<CegoField> & schema) const133 bool CegoBTreeValue::hasNull(const ListT<CegoField>& schema) const
134 {
135 CegoField* pF = schema.First();
136 char* idxPtr = _pI;
137 while (pF)
138 {
139 char nullIndicator;
140 memcpy(&nullIndicator, idxPtr, 1);
141 idxPtr += 1;
142
143 if ( nullIndicator == 1 )
144 {
145 int len = getReservedLength(pF);
146
147 idxPtr+=len;
148
149 if ( isNullTerminated(pF->getType() ) )
150 idxPtr+=1;
151 }
152 else
153 {
154 return true;
155 }
156
157 pF = schema.Next();
158 }
159 return false;
160 }
161
valueFromSchema(ListT<CegoField> * pSchema)162 void CegoBTreeValue::valueFromSchema(ListT<CegoField>* pSchema)
163 {
164
165 // check if local memory already allocated, do if not
166 if ( _idxArray == 0 )
167 _idxArray = (char*)malloc(TABMNG_MAXINDEXVALUE);
168 _pI = _idxArray;
169
170 char* idxPtr = _pI;
171 CegoField *pF = pSchema->First();
172
173 int vlen = 0;
174 while (pF)
175 {
176 int len = pF->getValue().getLength();
177
178 // checking reserved length + 1 because value length includes zero byte
179 if ( len > getReservedLength(pF) + 1 )
180 throw Exception(EXLOC, "Reserved btree length for floating type exceeded");
181
182 vlen += getReservedLength(pF);
183
184 if ( vlen > TABMNG_MAXINDEXVALUE )
185 throw Exception(EXLOC, "Index value exceeded");
186
187 if ( len > 0 )
188 {
189 char nullIndicator = 1;
190 memcpy(idxPtr, &nullIndicator, 1);
191 idxPtr += 1;
192
193 memcpy(idxPtr, pF->getValue().getValue(), len);
194
195 idxPtr += getReservedLength(pF);
196
197 // treat all string stored values
198 if ( isNullTerminated(pF->getType() ) )
199 idxPtr+=1;
200
201 // terminate in any case
202 *idxPtr=0;
203 }
204 else
205 {
206 char nullIndicator = 0;
207 memcpy(idxPtr, &nullIndicator, 1);
208 idxPtr += getReservedLength(pF) + 1;
209
210 if ( isNullTerminated(pF->getType() ) )
211 idxPtr+=1;
212 }
213 pF = pSchema->Next();
214 }
215 // cout << "Value from schema : " << toChain(pSchema) << endl;
216 }
217
valueFromSchema(const ListT<CegoField> tableSchema,const ListT<CegoField> indexSchema)218 void CegoBTreeValue::valueFromSchema(const ListT<CegoField> tableSchema, const ListT<CegoField> indexSchema)
219 {
220 int len = 0;
221 CegoField* pIF = indexSchema.First();
222 while (pIF)
223 {
224 len += getReservedLength(pIF);
225 pIF = indexSchema.Next();
226 }
227
228 if ( len > TABMNG_MAXINDEXVALUE )
229 throw Exception(EXLOC, "Index value exceeded");
230
231 // check if local memory already allocated, do if not
232 if ( _idxArray == 0 )
233 _idxArray = (char*)malloc(TABMNG_MAXINDEXVALUE);
234 _pI = _idxArray;
235
236 char* idxPtr = _pI;
237 pIF = indexSchema.First();
238 while (pIF)
239 {
240 CegoField *pTF = tableSchema.First();
241
242 while ( pTF )
243 {
244 if ( (Chain)pTF->getAttrName() == (Chain)pIF->getAttrName() )
245 {
246 int len = pTF->getValue().getLength();
247
248 if ( len > 0 )
249 {
250
251 // checking reserved length + 1 because value length includes zero byte
252 if ( pTF->getValue().getLength() > getReservedLength(pTF) + 1 )
253 throw Exception(EXLOC, "Reserved btree length for floating type exceeded");
254
255 char nullIndicator = 1;
256 memcpy(idxPtr, &nullIndicator, 1);
257 idxPtr += 1;
258
259 memcpy(idxPtr, pTF->getValue().getValue(), len);
260
261 idxPtr += getReservedLength(pTF);
262
263 // treat all string stored values
264 if ( isNullTerminated(pTF->getType() ) )
265 {
266 idxPtr+=1;
267 }
268 // terminate in any case
269 *idxPtr=0;
270 }
271 else
272 {
273 char nullIndicator = 0;
274 memcpy(idxPtr, &nullIndicator, 1);
275 idxPtr += getReservedLength(pTF) + 1;
276
277 if ( isNullTerminated(pTF->getType() ) )
278 idxPtr+=1;
279 }
280 }
281 pTF = tableSchema.Next();
282 }
283 pIF = indexSchema.Next();
284 }
285 }
286
valueToFVL(const ListT<CegoField> & schema) const287 ListT<CegoFieldValue> CegoBTreeValue::valueToFVL(const ListT<CegoField>& schema) const
288 {
289 ListT<CegoFieldValue> fvl;
290
291 char* idxPtr = _pI;
292 CegoField* pF = schema.First();
293 while (pF)
294 {
295 char nullIndicator;
296 memcpy(&nullIndicator, idxPtr, 1);
297 idxPtr += 1;
298
299 CegoFieldValue fv;
300 int len = getReservedLength(pF);
301
302 if ( nullIndicator == 1 )
303 {
304 // treat all string stored values
305 if ( isNullTerminated(pF->getType() ) )
306 {
307 fv = CegoFieldValue(pF->getType(), Chain(idxPtr));
308 idxPtr += len + 1;
309 }
310 else
311 {
312 fv = CegoFieldValue(pF->getType(), idxPtr, len);
313 idxPtr+=len;
314 }
315 }
316 else
317 {
318 idxPtr += len + 1;
319 if ( isNullTerminated(pF->getType() ) )
320 {
321 idxPtr += 1;
322 }
323 }
324
325 fvl.Insert(fv);
326 pF = schema.Next();
327 }
328 return fvl;
329 }
330
setPtr(char * p,int len)331 void CegoBTreeValue::setPtr(char* p, int len)
332 {
333 _pI = p;
334 _len = len;
335 }
336
getPtr() const337 char* CegoBTreeValue::getPtr() const
338 {
339 return _pI;
340 }
341
operator =(const CegoBTreeValue & iv)342 CegoBTreeValue& CegoBTreeValue::operator = (const CegoBTreeValue& iv)
343 {
344 if ( iv._idxArray )
345 {
346 if ( _idxArray == 0 )
347 _idxArray = (char*)malloc(TABMNG_MAXINDEXVALUE);
348 memcpy(_idxArray, iv._idxArray, _len);
349 _pI = _idxArray;
350 }
351 else
352 {
353 _pI = iv._pI;
354 }
355 _len = iv._len;
356
357 return (*this);
358 }
359
comp(const CegoBTreeValue & iv,ListT<CegoField> * pSchema) const360 CegoBTreeValue::Comparison CegoBTreeValue::comp(const CegoBTreeValue& iv, ListT<CegoField>* pSchema) const
361 {
362 char* idxPtr1 = _pI;
363 char* idxPtr2 = iv.getPtr();
364
365 CegoField* pF = pSchema->First();
366 while (pF)
367 {
368 int len = getReservedLength(pF);
369
370 CegoFieldValue fv1;
371 CegoFieldValue fv2;
372
373 /* for performance reasons, we construct fieldvalue with pointer reference
374 in case of VARCHAR & friend values len might be not correct, but for
375 the used methods, it does't matter */
376
377 char nullIndicator1;
378 memcpy(&nullIndicator1, idxPtr1, 1);
379 idxPtr1 += 1;
380
381 char nullIndicator2;
382 memcpy(&nullIndicator2, idxPtr2, 1);
383 idxPtr2 += 1;
384
385 if ( nullIndicator1 == 1 )
386 {
387 if ( isNullTerminated(pF->getType() ) )
388 {
389 fv1 = CegoFieldValue(pF->getType(), Chain(idxPtr1));
390 }
391 else
392 {
393 fv1 = CegoFieldValue(pF->getType(), idxPtr1, len);
394 }
395 }
396
397 if ( nullIndicator2 == 1 )
398 {
399 if ( isNullTerminated(pF->getType() ) )
400 {
401 fv2 = CegoFieldValue(pF->getType(), Chain(idxPtr2));
402 }
403 else
404 {
405 fv2 = CegoFieldValue(pF->getType(), idxPtr2, len);
406 }
407 }
408
409 CegoFieldValue::Comparison c = fv1.comp(fv2);
410
411 if ( c == CegoFieldValue::MORE )
412 {
413 return MORE;
414 }
415 else if ( c == CegoFieldValue::LESS )
416 {
417 return LESS;
418 }
419
420 if ( isNullTerminated(pF->getType() ) )
421 {
422 len++;
423 }
424
425 idxPtr1+=len;
426 idxPtr2+=len;
427 pF = pSchema->Next();
428
429 }
430
431 return EQUAL;
432 }
433
isHigher(const CegoBTreeValue & iv,ListT<CegoField> * pSchema) const434 bool CegoBTreeValue::isHigher(const CegoBTreeValue& iv, ListT<CegoField>* pSchema) const
435 {
436 Comparison c = comp(iv, pSchema);
437 return c == MORE;
438 }
439
isEqualHigher(const CegoBTreeValue & iv,ListT<CegoField> * pSchema) const440 bool CegoBTreeValue::isEqualHigher(const CegoBTreeValue& iv, ListT<CegoField>* pSchema) const
441 {
442 Comparison c = comp(iv, pSchema);
443 return c == MORE || c == EQUAL;
444 }
445
isEqual(const CegoBTreeValue & iv,ListT<CegoField> * pSchema) const446 bool CegoBTreeValue::isEqual(const CegoBTreeValue& iv, ListT<CegoField>* pSchema) const
447 {
448 Comparison c = comp(iv, pSchema);
449 return c == EQUAL;
450 }
451
toChain(ListT<CegoField> * pSchema) const452 Chain CegoBTreeValue::toChain(ListT<CegoField>* pSchema) const
453 {
454 Chain s;
455
456 char* idxPtr = _pI;
457 CegoField* pF = pSchema->First();
458 while (pF)
459 {
460 char nullIndicator;
461 memcpy(&nullIndicator, idxPtr, 1);
462 idxPtr += 1;
463
464 CegoFieldValue fv;
465
466 int len = getReservedLength(pF);
467 if ( nullIndicator == 1 )
468 {
469 if ( isNullTerminated(pF->getType() ) )
470 {
471 fv = CegoFieldValue(pF->getType(), Chain(idxPtr));
472 idxPtr += len + 1;
473 }
474 else
475 {
476 fv = CegoFieldValue(pF->getType(), idxPtr, len);
477 idxPtr+=len;
478 }
479 }
480 else
481 {
482 idxPtr+=len;
483 if ( isNullTerminated(pF->getType() ) )
484 {
485 idxPtr+=1;
486 }
487 }
488
489 s += fv.valAsChain();
490 pF = pSchema->Next();
491 if ( pF )
492 s += Chain(",");
493 }
494
495 return s;
496 }
497
getReservedLength(CegoField * pF)498 int CegoBTreeValue::getReservedLength(CegoField* pF)
499 {
500 switch ( pF->getType() )
501 {
502 case DECIMAL_TYPE:
503 case FIXED_TYPE:
504 // return RESERVED_BTREE_FLOATLEN;
505 // changed with 2.46.0
506 return pF->getLength();
507 case BIGINT_TYPE:
508 case VARCHAR_TYPE:
509 return pF->getLength();
510 case INT_TYPE:
511 case LONG_TYPE:
512 case BOOL_TYPE:
513 case DATETIME_TYPE:
514 case FLOAT_TYPE:
515 case DOUBLE_TYPE:
516 case SMALLINT_TYPE:
517 case TINYINT_TYPE:
518 return pF->getLength();
519 case BLOB_TYPE:
520 case CLOB_TYPE:
521 case NULL_TYPE:
522 case PAGEID_TYPE:
523 throw Exception(EXLOC, Chain("Data type not supported"));
524 }
525 }
526