MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NdbPack.hpp
1 /*
2  Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 #ifndef NDB_PACK_HPP
19 #define NDB_PACK_HPP
20 
21 #include <ndb_global.h>
22 #include <my_sys.h>
23 #include <kernel/AttributeHeader.hpp>
24 #include <NdbSqlUtil.hpp>
25 #include <NdbEnv.h>
26 class NdbOut;
27 
28 /*
29  * Pack an array of NDB data values. The types are specified by an
30  * array of data types. There is no associated table or attribute ids.
31  * All or an initial sequence of the specified values are present.
32  *
33  * Currently used for ordered index keys and bounds in kernel (DBTUX)
34  * and in index statistics (mysqld). The comparison methods use the
35  * primitive type comparisons from NdbSqlUtil.
36  *
37  * Keys and bounds use same spec. However a value in an index bound can
38  * be NULL even if the key attribute is not nullable. Therefore bounds
39  * set the "allNullable" property and have a longer null mask.
40  *
41  * There are two distinct use occasions: 1) construction of data or
42  * bound 2) operating on previously constructed data or bound. There
43  * are classes Data/DataC and Bound/BoundC for these uses. The latter
44  * often can return a result without interpreting the full value.
45  *
46  * Methods return -1 on error and 0 on success. Comparison methods
47  * assume well-formed data and return negative, zero, positive for less,
48  * equal, greater.
49  */
50 
51 class NdbPack {
52 public:
53  class Endian;
54  class Type;
55  class Spec;
56  class Iter;
57  class DataC;
58  class Data;
59  class BoundC;
60  class Bound;
61 
62  /*
63  * Get SQL type.
64  */
65  static const NdbSqlUtil::Type& getSqlType(Uint32 typeId);
66 
67  /*
68  * Error codes for core dumps.
69  */
70  class Error {
71  public:
72  enum {
73  TypeNotSet = -101, // type id was not set
74  TypeOutOfRange = -102, // type id is out of range
75  TypeNotSupported = -103, // blob (and for now bit) types
76  TypeSizeZero = -104, // max size was set to zero
77  TypeFixSizeInvalid = -105, // fixed size specified wrong
78  TypeNullableNotBool = -106, // nullable must be 0 or 1
79  CharsetNotSpecified = -107, // char type with no charset number
80  CharsetNotFound = -108, // cannot install in all_charsets[]
81  CharsetNotAllowed = -109, // non-char type with charset
82  SpecBufOverflow = -201, // more spec items than allocated
83  DataCntOverflow = -301, // more data items than in spec
84  DataBufOverflow = -302, // more data bytes than allocated
85  DataValueOverflow = -303, // var length exceeds max size
86  DataNotNullable = -304, // NULL value to not-nullable type
87  InvalidAttrInfo = -305, // invalid plain old attr info
88  BoundEmptySide = -401, // side not 0 for empty bound
89  BoundNonemptySide = -402, // side not -1,+1 for non-empty bound
90  InternalError = -901,
91  ValidationError = -902,
92  NoError = 0
93  };
94  Error();
95  ~Error() {}
96  int get_error_code() const;
97  int get_error_line() const;
98 
99  private:
100  friend class Endian;
101  friend class Type;
102  friend class Spec;
103  friend class Iter;
104  friend class DataC;
105  friend class Data;
106  friend class BoundC;
107  friend class Bound;
108  void set_error(int code, int line) const;
109  void set_error(const Error& e2) const;
110  mutable int m_error_code;
111  mutable int m_error_line;
112  };
113 
114  /*
115  * Endian definitions.
116  */
117  class Endian {
118  public:
119  enum Value {
120  Native = 0, // replaced by actual value
121  Little = 1,
122  Big = 2
123  };
124  static Value get_endian();
125  static void convert(void* ptr, Uint32 len);
126  };
127 
128  /*
129  * Data type.
130  */
131  class Type : public Error {
132  public:
133  Type();
134  Type(int typeId, Uint32 byteSize, bool nullable, Uint32 csNumber);
135  ~Type() {}
136  /*
137  * Define the type. Size is fixed or max size. Values of variable
138  * length have length bytes. The definition is verified when the
139  * type is added to the specification. This also installs missing
140  * CHARSET_INFO* into all_charsets[].
141  */
142  void set(Uint32 typeId, Uint32 byteSize, bool nullable, Uint32 csNumber);
143  // getters
144  Uint32 get_type_id() const;
145  Uint32 get_byte_size() const;
146  bool get_nullable() const;
147  Uint32 get_cs_number() const;
148  Uint32 get_array_type() const;
149  // print
150  friend NdbOut& operator<<(NdbOut&, const Type&);
151  void print(NdbOut& out) const;
152  const char* print(char* buf, Uint32 bufsz) const;
153  int validate() const;
154 
155  private:
156  friend class Spec;
157  friend class Iter;
158  friend class DataC;
159  friend class Data;
160  // verify and complete when added to specification
161  int complete();
162  Uint16 m_typeId;
163  Uint16 m_byteSize; // fixed or max size in bytes
164  Uint16 m_nullable;
165  Uint16 m_csNumber;
166  Uint16 m_arrayType; // 0,1,2 length bytes
167  Uint16 m_nullbitPos; // computed as part of Spec
168  };
169 
170  /*
171  * Data specification i.e. array of types. Usually constructed on the
172  * heap, so keep fairly small. Used for boths keys and bounds.
173  */
174  class Spec : public Error {
175  public:
176  Spec();
177  ~Spec() {}
178  // set initial buffer (calls reset)
179  void set_buf(Type* buf, Uint32 bufMaxCnt);
180  // use if buffer is relocated
181  void set_buf(Type* buf);
182  // reset but keep buffer
183  void reset();
184  // add type to specification once or number of times
185  int add(Type type);
186  int add(Type type, Uint32 cnt);
187  // copy from
188  void copy(const Spec& s2);
189  // getters (bounds set allNullable)
190  const Type& get_type(Uint32 i) const;
191  Uint32 get_cnt() const;
192  Uint32 get_nullable_cnt(bool allNullable) const;
193  Uint32 get_nullmask_len(bool allNullable) const;
194  // max data length including null mask
195  Uint32 get_max_data_len(bool allNullable) const;
196  // minimum var bytes (if used by Data instance)
197  Uint32 get_min_var_bytes(bool allNullable) const;
198  // print
199  friend NdbOut& operator<<(NdbOut&, const Spec&);
200  void print(NdbOut& out) const;
201  const char* print(char* buf, Uint32 bufsz) const;
202  int validate() const;
203 
204  private:
205  friend class Iter;
206  friend class DataC;
207  friend class Data;
208  friend class BoundC;
209  // undefined
210  Spec(const Spec&);
211  Spec& operator=(const Spec&);
212  Type* m_buf;
213  Uint16 m_bufMaxCnt;
214  Uint16 m_cnt;
215  Uint16 m_nullableCnt;
216  Uint16 m_varsizeCnt;
217  Uint32 m_maxByteSize; // excludes null mask
218  };
219 
220  /*
221  * Iterator over data items. DataC uses external Iter instances in
222  * comparison methods etc. Data contains an Iter instance which
223  * iterates on items added.
224  */
225  class Iter : public Error {
226  public:
227  // the data instance is only used to set metadata
228  Iter(const DataC& data);
229  ~Iter() {}
230  void reset();
231 
232  private:
233  friend class DataC;
234  friend class Data;
235  friend class BoundC;
236  // undefined
237  Iter(const Iter&);
238  Iter& operator=(const Iter&);
239  // describe next non-null or null item and advance iterator
240  int desc(const Uint8* item);
241  int desc_null();
242  // compare current items (DataC buffers are passed)
243  int cmp(const Iter& r2, const Uint8* buf1, const Uint8* buf2) const;
244 
245  const Spec& m_spec;
246  const bool m_allNullable;
247  // iterator
248  Uint32 m_itemPos; // position of current item in DataC buffer
249  Uint32 m_cnt; // number of items described so far
250  Uint32 m_nullCnt;
251  // current item
252  Uint32 m_lenBytes; // 0-2
253  Uint32 m_bareLen; // excludes length bytes
254  Uint32 m_itemLen; // full length, value zero means null
255  };
256 
257  /*
258  * Read-only superclass of Data. Initialized from a previously
259  * constructed Data buffer (any var bytes skipped). Methods interpret
260  * one data item at a time. Values are native endian.
261  */
262  class DataC : public Error {
263  public:
264  DataC(const Spec& spec, bool allNullable);
265  // set buffer to previously constructed one with given item count
266  void set_buf(const void* buf, Uint32 bufMaxLen, Uint32 cnt);
267  // interpret next data item
268  int desc(Iter& r) const;
269  // compare cnt attrs and also return number of initial equal attrs
270  int cmp(const DataC& d2, Uint32 cnt, Uint32& num_eq) const;
271  // getters
272  const Spec& get_spec() const;
273  bool get_all_nullable() const;
274  const void* get_data_buf() const;
275  Uint32 get_cnt() const;
276  bool is_empty() const;
277  bool is_full() const;
278  // print
279  friend NdbOut& operator<<(NdbOut&, const DataC&);
280  void print(NdbOut& out) const;
281  const char* print(char* buf, Uint32 bufsz, bool convert_flag = false) const;
282  int validate() const { return 0; }
283 
284  private:
285  friend class Iter;
286  friend class Data;
287  friend class BoundC;
288  // undefined
289  DataC(const Data&);
290  DataC& operator=(const DataC&);
291  const Spec& m_spec;
292  const bool m_allNullable;
293  const Uint8* m_buf;
294  Uint32 m_bufMaxLen;
295  // can be updated as part of Data instance
296  Uint32 m_cnt;
297  };
298 
299  /*
300  * Instance of an array of data values. The values are packed into
301  * a byte buffer. The buffer is also maintained as a single varbinary
302  * value if non-zero var bytes (length bytes) is specified.
303  *
304  * Data instances can be received from another source (such as table
305  * in database) and may not be native-endian. Such instances must
306  * first be completed with desc_all() and convert().
307  */
308  class Data : public DataC {
309  public:
310  Data(const Spec& spec, bool allNullable, Uint32 varBytes);
311  // set buffer (calls reset)
312  void set_buf(void* buf, Uint32 bufMaxLen);
313  // reset but keep buffer (header is zeroed)
314  void reset();
315  // add non-null data items and return length in bytes
316  int add(const void* data, Uint32* len_out);
317  int add(const void* data, Uint32 cnt, Uint32* len_out);
318  // add null data items and return length 0 bytes
319  int add_null(Uint32* len_out);
320  int add_null(Uint32 cnt, Uint32* len_out);
321  // add from "plain old attr info"
322  int add_poai(const Uint32* poai, Uint32* len_out);
323  int add_poai(const Uint32* poai, Uint32 cnt, Uint32* len_out);
324  // call this before first use
325  int finalize();
326  // copy from
327  int copy(const DataC& d2);
328  // convert endian
329  int convert(Endian::Value to_endian);
330  // create complete instance from buffer contents
331  int desc_all(Uint32 cnt, Endian::Value from_endian);
332  // getters
333  Uint32 get_max_len() const;
334  Uint32 get_max_len4() const;
335  Uint32 get_var_bytes() const;
336  const void* get_full_buf() const;
337  Uint32 get_full_len() const;
338  Uint32 get_data_len() const;
339  Uint32 get_null_cnt() const;
340  Endian::Value get_endian() const;
341  // print
342  friend NdbOut& operator<<(NdbOut&, const Data&);
343  void print(NdbOut& out) const;
344  const char* print(char* buf, Uint32 bufsz) const;
345  int validate() const;
346 
347  private:
348  friend class Iter;
349  friend class Bound;
350  // undefined
351  Data(const Data&);
352  Data& operator=(const Data&);
353  int finalize_impl();
354  int convert_impl(Endian::Value to_endian);
355  const Uint32 m_varBytes;
356  Uint8* m_buf;
357  Uint32 m_bufMaxLen;
358  Endian::Value m_endian;
359  // iterator on items added
360  Iter m_iter;
361  };
362 
363  /*
364  * Read-only superclass of BoundC, analogous to DataC. Initialized
365  * from a previously constructed Bound or DataC buffer.
366  */
367  class BoundC : public Error {
368  public:
369  BoundC(DataC& data);
370  ~BoundC() {}
371  // call this before first use
372  int finalize(int side);
373  // compare bound to key (may return 0 if bound is longer)
374  int cmp(const DataC& d2, Uint32 cnt, Uint32& num_eq) const;
375  // compare bounds (may return 0 if cnt is less than min length)
376  int cmp(const BoundC& b2, Uint32 cnt, Uint32& num_eq) const;
377  // getters
378  DataC& get_data() const;
379  int get_side() const;
380  // print
381  friend NdbOut& operator<<(NdbOut&, const BoundC&);
382  void print(NdbOut& out) const;
383  const char* print(char* buf, Uint32 bufsz) const;
384  int validate() const;
385 
386  private:
387  friend class Bound;
388  // undefined
389  BoundC(const BoundC&);
390  BoundC& operator=(const BoundC&);
391  DataC& m_data;
392  int m_side;
393  };
394 
395  /*
396  * Ordered index range bound consists of a partial key and a "side".
397  * The partial key is a Data instance where some initial number of
398  * values are present. It is defined separately by the caller and
399  * passed to Bound ctor by reference.
400  */
401  class Bound : public BoundC {
402  public:
403  Bound(Data& data);
404  ~Bound() {}
405  void reset();
406  // call this before first use
407  int finalize(int side);
408  // getters
409  Data& get_data() const;
410  // print
411  friend NdbOut& operator<<(NdbOut&, const Bound&);
412  void print(NdbOut& out) const;
413  const char* print(char* buf, Uint32 bufsz) const;
414  int validate() const;
415 
416  private:
417  // undefined
418  Bound(const Bound&);
419  Bound& operator=(const Bound&);
420  Data& m_data;
421  };
422 
423  /*
424  * Helper for print() methods.
425  */
426  struct Print {
427  private:
428  friend class Endian;
429  friend class Type;
430  friend class Spec;
431  friend class Iter;
432  friend class DataC;
433  friend class Data;
434  friend class BoundC;
435  friend class Bound;
436  Print(char* buf, Uint32 bufsz);
437  void print(const char* frm, ...);
438  char* m_buf;
439  Uint32 m_bufsz;
440  Uint32 m_sz;
441  };
442 };
443 
444 // NdbPack
445 
446 inline const NdbSqlUtil::Type&
447 NdbPack::getSqlType(Uint32 typeId)
448 {
449  return NdbSqlUtil::m_typeList[typeId];
450 }
451 
452 // NdbPack::Error
453 
454 inline
455 NdbPack::Error::Error()
456 {
457  m_error_code = 0;
458  m_error_line = 0;
459 }
460 
461 // NdbPack::Endian
462 
463 inline NdbPack::Endian::Value
464 NdbPack::Endian::get_endian()
465 {
466 #ifndef WORDS_BIGENDIAN
467  return Little;
468 #else
469  return Big;
470 #endif
471 }
472 
473 // NdbPack::Type
474 
475 inline
476 NdbPack::Type::Type()
477 {
478  m_typeId = NDB_TYPE_UNDEFINED;
479  m_byteSize = 0;
480  m_nullable = true;
481  m_csNumber = 0;
482  m_arrayType = 0;
483  m_nullbitPos = 0;
484 }
485 
486 inline
487 NdbPack::Type::Type(int typeId, Uint32 byteSize, bool nullable, Uint32 csNumber)
488 {
489  set(typeId, byteSize, nullable, csNumber);
490 }
491 
492 inline void
493 NdbPack::Type::set(Uint32 typeId, Uint32 byteSize, bool nullable, Uint32 csNumber)
494 {
495  m_typeId = typeId;
496  m_byteSize = byteSize;
497  m_nullable = nullable;
498  m_csNumber = csNumber;
499 }
500 
501 inline Uint32
502 NdbPack::Type::get_type_id() const
503 {
504  return m_typeId;
505 }
506 
507 inline Uint32
508 NdbPack::Type::get_byte_size() const
509 {
510  return m_byteSize;
511 }
512 
513 inline bool
514 NdbPack::Type::get_nullable() const
515 {
516  return (bool)m_nullable;
517 }
518 
519 inline Uint32
520 NdbPack::Type::get_cs_number() const
521 {
522  return m_csNumber;
523 }
524 
525 inline Uint32
526 NdbPack::Type::get_array_type() const
527 {
528  return m_arrayType;
529 }
530 
531 // NdbPack::Spec
532 
533 inline
534 NdbPack::Spec::Spec()
535 {
536  reset();
537  m_buf = 0;
538  m_bufMaxCnt = 0;
539 }
540 
541 inline void
542 NdbPack::Spec::set_buf(Type* buf, Uint32 bufMaxCnt)
543 {
544  reset();
545  m_buf = buf;
546  m_bufMaxCnt = bufMaxCnt;
547 }
548 
549 inline void
550 NdbPack::Spec::set_buf(Type* buf)
551 {
552  m_buf = buf;
553 }
554 
555 inline void
556 NdbPack::Spec::reset()
557 {
558  m_cnt = 0;
559  m_nullableCnt = 0;
560  m_varsizeCnt = 0;
561  m_maxByteSize = 0;
562 }
563 
564 inline const NdbPack::Type&
565 NdbPack::Spec::get_type(Uint32 i) const
566 {
567  assert(i < m_cnt);
568  return m_buf[i];
569 }
570 
571 inline Uint32
572 NdbPack::Spec::get_cnt() const
573 {
574  return m_cnt;
575 }
576 
577 inline Uint32
578 NdbPack::Spec::get_nullable_cnt(bool allNullable) const
579 {
580  if (!allNullable)
581  return m_nullableCnt;
582  else
583  return m_cnt;
584 }
585 
586 inline Uint32
587 NdbPack::Spec::get_nullmask_len(bool allNullable) const
588 {
589  return (get_nullable_cnt(allNullable) + 7) / 8;
590 }
591 
592 inline Uint32
593 NdbPack::Spec::get_max_data_len(bool allNullable) const
594 {
595  return get_nullmask_len(allNullable) + m_maxByteSize;
596 }
597 
598 inline Uint32
599 NdbPack::Spec::get_min_var_bytes(bool allNullable) const
600 {
601  const Uint32 len = get_max_data_len(allNullable);
602  return (len < 256 ? 1 : 2);
603 }
604 
605 // NdbPack::Iter
606 
607 inline
608 NdbPack::Iter::Iter(const DataC& data) :
609  m_spec(data.m_spec),
610  m_allNullable(data.m_allNullable)
611 {
612  reset();
613 }
614 
615 inline void
616 NdbPack::Iter::reset()
617 {
618  m_itemPos = m_spec.get_nullmask_len(m_allNullable);
619  m_cnt = 0;
620  m_nullCnt = 0;
621  m_lenBytes = 0;
622  m_bareLen = 0;
623  m_itemLen = 0;
624 }
625 
626 // NdbPack::DataC
627 
628 inline
629 NdbPack::DataC::DataC(const Spec& spec, bool allNullable) :
630  m_spec(spec),
631  m_allNullable(allNullable)
632 {
633  m_buf = 0;
634  m_bufMaxLen = 0;
635  m_cnt = 0;
636 }
637 
638 inline void
639 NdbPack::DataC::set_buf(const void* buf, Uint32 bufMaxLen, Uint32 cnt)
640 {
641  m_buf = static_cast<const Uint8*>(buf);
642  m_bufMaxLen = bufMaxLen;
643  m_cnt = cnt;
644 }
645 
646 inline const NdbPack::Spec&
647 NdbPack::DataC::get_spec() const
648 {
649  return m_spec;
650 }
651 
652 inline bool
653 NdbPack::DataC::get_all_nullable() const
654 {
655  return &m_allNullable;
656 }
657 
658 inline const void*
659 NdbPack::DataC::get_data_buf() const
660 {
661  return &m_buf[0];
662 }
663 
664 inline Uint32
665 NdbPack::DataC::get_cnt() const
666 {
667  return m_cnt;
668 }
669 
670 inline bool
671 NdbPack::DataC::is_empty() const
672 {
673  return m_cnt == 0;
674 }
675 
676 inline bool
677 NdbPack::DataC::is_full() const
678 {
679  return m_cnt == m_spec.m_cnt;
680 }
681 
682 // NdbPack::Data
683 
684 inline
685 NdbPack::Data::Data(const Spec& spec, bool allNullable, Uint32 varBytes) :
686  DataC(spec, allNullable),
687  m_varBytes(varBytes),
688  m_iter(*this)
689 {
690  m_buf = 0;
691  m_bufMaxLen = 0;
692  m_endian = Endian::get_endian();
693 }
694 
695 inline void
696 NdbPack::Data::set_buf(void* buf, Uint32 bufMaxLen)
697 {
698  m_buf = static_cast<Uint8*>(buf);
699  m_bufMaxLen = bufMaxLen;
700  reset();
701  assert(bufMaxLen >= m_varBytes);
702  DataC::set_buf(&m_buf[m_varBytes], m_bufMaxLen - m_varBytes, 0);
703 }
704 
705 inline void
706 NdbPack::Data::reset()
707 {
708  m_cnt = 0; // in DataC
709  const Uint32 bytes = m_varBytes + m_spec.get_nullmask_len(m_allNullable);
710  memset(m_buf, 0, bytes);
711  m_endian = Endian::get_endian();
712  m_iter.reset();
713 }
714 
715 inline int
716 NdbPack::Data::finalize()
717 {
718  if (m_varBytes == 0 ||
719  finalize_impl() == 0)
720  return 0;
721  return -1;
722 }
723 
724 inline int
725 NdbPack::Data::convert(Endian::Value to_endian)
726 {
727  if (to_endian == Endian::Native)
728  to_endian = Endian::get_endian();
729  if (m_endian == to_endian)
730  return 0;
731  if (convert_impl(to_endian) == 0)
732  {
733  m_endian = to_endian;
734  return 0;
735  }
736  return -1;
737 }
738 
739 inline Uint32
740 NdbPack::Data::get_max_len() const
741 {
742  return m_varBytes + m_spec.get_max_data_len(m_allNullable);
743 }
744 
745 inline Uint32
746 NdbPack::Data::get_max_len4() const
747 {
748  Uint32 len4 = get_max_len();
749  len4 += 3;
750  len4 /= 4;
751  len4 *= 4;
752  return len4;
753 }
754 
755 inline Uint32
756 NdbPack::Data::get_var_bytes() const
757 {
758  return m_varBytes;
759 }
760 
761 inline const void*
762 NdbPack::Data::get_full_buf() const
763 {
764  return &m_buf[0];
765 }
766 
767 inline Uint32
768 NdbPack::Data::get_full_len() const
769 {
770  return m_varBytes + m_iter.m_itemPos + m_iter.m_itemLen;
771 }
772 
773 inline Uint32
774 NdbPack::Data::get_data_len() const
775 {
776  return m_iter.m_itemPos + m_iter.m_itemLen;
777 }
778 
779 inline Uint32
780 NdbPack::Data::get_null_cnt() const
781 {
782  return m_iter.m_nullCnt;
783 }
784 
785 inline NdbPack::Endian::Value
786 NdbPack::Data::get_endian() const
787 {
788  return m_endian;
789 }
790 
791 // NdbPack::BoundC
792 
793 inline
794 NdbPack::BoundC::BoundC(DataC& data) :
795  m_data(data)
796 {
797  m_side = 0;
798 }
799 
800 inline int
801 NdbPack::BoundC::cmp(const DataC& d2, Uint32 cnt, Uint32& num_eq) const
802 {
803  const BoundC& b1 = *this;
804  const DataC& d1 = b1.m_data;
805  int res = d1.cmp(d2, cnt, num_eq);
806  if (res == 0 && d1.m_cnt <= d2.m_cnt)
807  res = b1.m_side;
808  return res;
809 }
810 
811 inline NdbPack::DataC&
812 NdbPack::BoundC::get_data() const
813 {
814  return m_data;
815 }
816 
817 inline int
818 NdbPack::BoundC::get_side() const
819 {
820  return m_side;
821 }
822 
823 // NdbPack::Bound
824 
825 inline
826 NdbPack::Bound::Bound(Data& data) :
827  BoundC(data),
828  m_data(data)
829 {
830 }
831 
832 inline void
833 NdbPack::Bound::reset()
834 {
835  m_data.reset();
836  m_side = 0;
837 }
838 
839 inline int
840 NdbPack::Bound::finalize(int side)
841 {
842  if (m_data.finalize() == -1)
843  {
844  set_error(m_data);
845  return -1;
846  }
847  if (BoundC::finalize(side) == -1)
848  return -1;
849  return 0;
850 }
851 
852 inline NdbPack::Data&
853 NdbPack::Bound::get_data() const
854 {
855  return m_data;
856 }
857 
858 #endif // NDB_PACK_HPP