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