1// handler.cpp --
2// $Id: handler.cpp 1230 2007-03-09 15:58:53Z jcw $
3// This is part of Metakit, see http://www.equi4.com/metakit.html
4
5/** @file
6 * Handlers store data in column-wise format
7 */
8
9#include "header.h"
10#include "handler.h"
11#include "format.h"
12#include "field.h"
13#include "column.h"
14#include "persist.h"
15
16#if !q4_INLINE
17#include "handler.inl"
18#endif
19
20/////////////////////////////////////////////////////////////////////////////
21// c4_Handler
22
23void c4_Handler::ClearBytes(c4_Bytes &buf_)const {
24  static char zeros[8];
25
26  int n = f4_ClearFormat(Property().Type());
27  d4_assert(n <= sizeof zeros);
28
29  buf_ = c4_Bytes(zeros, n);
30}
31
32int c4_Handler::Compare(int index_, const c4_Bytes &buf_) {
33  // create a copy for small data, since ints use a common _item buffer
34  c4_Bytes copy(buf_.Contents(), buf_.Size(), buf_.Size() <= 8);
35
36  c4_Bytes data;
37  GetBytes(index_, data);
38
39  return f4_CompareFormat(Property().Type(), data, copy);
40}
41
42void c4_Handler::Commit(c4_SaveContext &) {
43  d4_assert(0);
44}
45
46void c4_Handler::OldDefine(char, c4_Persist &) {
47  d4_assert(0);
48}
49
50// this is how the old "Get" was, keep it until no longer needed
51void c4_Handler::GetBytes(int index_, c4_Bytes &buf_, bool copySmall_) {
52  int n;
53  const void *p = Get(index_, n);
54  buf_ = c4_Bytes(p, n, copySmall_ && n <= 8);
55}
56
57void c4_Handler::Move(int from_, int to_) {
58  if (from_ != to_) {
59    c4_Bytes data;
60    GetBytes(from_, data);
61
62    Remove(from_, 1);
63
64    if (to_ > from_)
65      --to_;
66
67    Insert(to_, data, 1);
68  }
69}
70
71/////////////////////////////////////////////////////////////////////////////
72// c4_HandlerSeq
73
74c4_HandlerSeq::c4_HandlerSeq(c4_Persist *persist_): _persist(persist_), _field
75  (0), _parent(0), _numRows(0){}
76
77c4_HandlerSeq::c4_HandlerSeq(c4_HandlerSeq &owner_, c4_Handler *handler_):
78  _persist(owner_.Persist()), _field(owner_.FindField(handler_)), _parent
79  (&owner_), _numRows(0) {
80  for (int i = 0; i < NumFields(); ++i) {
81    c4_Field &field = Field(i);
82    c4_Property prop(field.Type(), field.Name());
83
84    d4_dbgdef(int n = )AddHandler(f4_CreateFormat(prop,  *this));
85    d4_assert(n == i);
86  }
87}
88
89c4_HandlerSeq::~c4_HandlerSeq() {
90  const bool rootLevel = _parent == this;
91  c4_Persist *pers = _persist;
92
93  if (rootLevel && pers != 0)
94    pers->DoAutoCommit();
95
96  DetachFromParent();
97  DetachFromStorage(true);
98
99  for (int i = 0; i < NumHandlers(); ++i)
100    delete  &NthHandler(i);
101  _handlers.SetSize(0);
102
103  ClearCache();
104
105  if (rootLevel) {
106    delete _field;
107
108    d4_assert(pers != 0);
109    delete pers;
110  }
111}
112
113c4_Persist *c4_HandlerSeq::Persist()const {
114  return _persist;
115}
116
117void c4_HandlerSeq::DefineRoot() {
118  d4_assert(_field == 0);
119  d4_assert(_parent == 0);
120
121  SetNumRows(1);
122
123  const char *desc = "[]";
124  _field = d4_new c4_Field(desc);
125  d4_assert(! *desc);
126
127  _parent = this;
128}
129
130c4_Handler *c4_HandlerSeq::CreateHandler(const c4_Property &prop_) {
131  return f4_CreateFormat(prop_,  *this);
132}
133
134c4_Field &c4_HandlerSeq::Definition()const {
135  d4_assert(_field != 0);
136
137  return  *_field;
138}
139
140void c4_HandlerSeq::DetachFromParent() {
141  if (_field != 0) {
142    const char *desc = "[]";
143    c4_Field f(desc);
144    d4_assert(! *desc);
145    Restructure(f, false);
146    _field = 0;
147  }
148
149  _parent = 0;
150}
151
152void c4_HandlerSeq::DetachFromStorage(bool full_) {
153  if (_persist != 0) {
154    int limit = full_ ? 0 : NumFields();
155
156    // get rid of all handlers which might do I/O
157    for (int c = NumHandlers(); --c >= 0;) {
158      c4_Handler &h = NthHandler(c);
159
160      // all nested fields are detached recursively
161      if (IsNested(c))
162        for (int r = 0; r < NumRows(); ++r)
163          if (h.HasSubview(r))
164            SubEntry(c, r).DetachFromStorage(full_);
165
166      if (c >= limit) {
167        if (h.IsPersistent()) {
168          delete  &h;
169          _handlers.RemoveAt(c);
170          ClearCache();
171        }
172      }
173    }
174
175    if (full_) {
176      //UnmappedAll();
177      _persist = 0;
178    }
179  }
180}
181
182void c4_HandlerSeq::DetermineSpaceUsage() {
183  for (int c = 0; c < NumFields(); ++c)
184  if (IsNested(c)) {
185    c4_Handler &h = NthHandler(c);
186    for (int r = 0; r < NumRows(); ++r)
187      if (h.HasSubview(r))
188        SubEntry(c, r).DetermineSpaceUsage();
189  }
190}
191
192void c4_HandlerSeq::SetNumRows(int numRows_) {
193  d4_assert(_numRows >= 0);
194
195  _numRows = numRows_;
196}
197
198int c4_HandlerSeq::AddHandler(c4_Handler *handler_) {
199  d4_assert(handler_ != 0);
200
201  return _handlers.Add(handler_);
202}
203
204const char *c4_HandlerSeq::Description() {
205  // 19-01-2003: avoid too dense code, since Sun CC seems to choke on it
206  //return _field != 0 ? UseTempBuffer(Definition().DescribeSubFields()) : 0;
207  if (_field == 0)
208    return 0;
209  c4_String s = _field->DescribeSubFields();
210  return UseTempBuffer(s);
211}
212
213void c4_HandlerSeq::Restructure(c4_Field &field_, bool remove_) {
214  //d4_assert(_field != 0);
215
216  // all nested fields must be set up, before we shuffle them around
217  for (int k = 0; k < NumHandlers(); ++k)
218  if (IsNested(k)) {
219    c4_Handler &h = NthHandler(k);
220    for (int n = 0; n < NumRows(); ++n)
221      if (h.HasSubview(n))
222        SubEntry(k, n);
223  }
224
225  for (int i = 0; i < field_.NumSubFields(); ++i) {
226    c4_Field &nf = field_.SubField(i);
227    c4_Property prop(nf.Type(), nf.Name());
228
229    int n = PropIndex(prop.GetId());
230    if (n == i)
231      continue;
232
233    if (n < 0) {
234      _handlers.InsertAt(i, f4_CreateFormat(prop,  *this));
235      NthHandler(i).Define(NumRows(), 0);
236    } else {
237      // move the handler to the front
238      d4_assert(n > i);
239      _handlers.InsertAt(i, _handlers.GetAt(n));
240      _handlers.RemoveAt(++n);
241    }
242
243    ClearCache(); // we mess with the order of handler, keep clearing it
244
245    d4_assert(PropIndex(prop.GetId()) == i);
246  }
247
248  c4_Field *ofld = _field;
249  // special case if we're "restructuring a view out of persistence", see below
250
251  _field = remove_ ? 0 : &field_;
252
253  // let handler do additional init once all have been prepared
254  //for (int n = 0; n < NumHandlers(); ++n)
255  //    NthHandler(n).Define(NumRows(), 0);
256
257  const char *desc = "[]";
258  c4_Field temp(desc);
259
260  // all nested fields are restructured recursively
261  for (int j = 0; j < NumHandlers(); ++j)
262  if (IsNested(j)) {
263    c4_Handler &h = NthHandler(j);
264    for (int n = 0; n < NumRows(); ++n)
265    if (h.HasSubview(n)) {
266      c4_HandlerSeq &seq = SubEntry(j, n);
267      if (j < NumFields())
268        seq.Restructure(field_.SubField(j), false);
269      else if (seq._field != 0)
270        seq.Restructure(temp, true);
271    }
272  }
273
274  if (_parent == this)
275    delete ofld;
276  // the root table owns its field structure tree
277}
278
279int c4_HandlerSeq::NumFields()const {
280  return _field != 0 ? _field->NumSubFields(): 0;
281}
282
283char c4_HandlerSeq::ColumnType(int index_)const {
284  return NthHandler(index_).Property().Type();
285}
286
287bool c4_HandlerSeq::IsNested(int index_)const {
288  return ColumnType(index_) == 'V';
289}
290
291c4_Field &c4_HandlerSeq::Field(int index_)const {
292  d4_assert(_field != 0);
293
294  return _field->SubField(index_);
295}
296
297void c4_HandlerSeq::Prepare(const t4_byte **ptr_, bool selfDesc_) {
298  if (ptr_ != 0) {
299    d4_dbgdef(t4_i32 sias = )c4_Column::PullValue(*ptr_);
300    d4_assert(sias == 0); // not yet
301
302    if (selfDesc_) {
303      t4_i32 n = c4_Column::PullValue(*ptr_);
304      if (n > 0) {
305        c4_String s = "[" + c4_String((const char*) * ptr_, n) + "]";
306        const char *desc = s;
307
308        c4_Field *f = d4_new c4_Field(desc);
309        d4_assert(! *desc);
310
311        Restructure(*f, false);
312        *ptr_ += n;
313      }
314    }
315
316    int rows = (int)c4_Column::PullValue(*ptr_);
317    if (rows > 0) {
318      SetNumRows(rows);
319
320      for (int i = 0; i < NumFields(); ++i)
321        NthHandler(i).Define(rows, ptr_);
322    }
323  }
324}
325
326void c4_HandlerSeq::OldPrepare() {
327  d4_assert(_persist != 0);
328
329  for (int i = 0; i < NumFields(); ++i) {
330    char origType = _field->SubField(i).OrigType();
331    NthHandler(i).OldDefine(origType,  *_persist);
332  }
333}
334
335void c4_HandlerSeq::FlipAllBytes() {
336  for (int i = 0; i < NumHandlers(); ++i) {
337    c4_Handler &h = NthHandler(i);
338    h.FlipBytes();
339  }
340}
341
342// New 19990903: swap rows in tables without touching the memo fields
343// or subviews on disk.  This is used by the new c4_View::RelocateRows.
344
345void c4_HandlerSeq::ExchangeEntries(int srcPos_, c4_HandlerSeq &dst_, int
346  dstPos_) {
347  d4_assert(NumHandlers() == dst_.NumHandlers());
348
349  c4_Bytes t1, t2;
350
351  for (int col = 0; col < NumHandlers(); ++col) {
352    if (IsNested(col)) {
353      d4_assert(dst_.IsNested(col));
354
355      int n;
356      c4_HandlerSeq **e1 = (c4_HandlerSeq **)NthHandler(col).Get(srcPos_, n);
357      c4_HandlerSeq **e2 = (c4_HandlerSeq **)dst_.NthHandler(col).Get(dstPos_,
358        n);
359      d4_assert(*e1 != 0 &&  *e2 != 0);
360
361      // swap the two entries
362      c4_HandlerSeq *e =  *e1;
363      *e1 =  *e2;
364      *e2 = e;
365
366      // shorthand, *after* the swap
367      c4_HandlerSeq &t1 = SubEntry(col, srcPos_);
368      c4_HandlerSeq &t2 = dst_.SubEntry(col, dstPos_);
369
370      // adjust the parents
371      t1._parent = this;
372      t2._parent = &dst_;
373
374      // reattach the proper field structures
375      t1.Restructure(Field(col), false);
376      t2.Restructure(dst_.Field(col), false);
377    } else {
378      d4_assert(ColumnType(col) == dst_.ColumnType(col));
379
380      c4_Handler &h1 = NthHandler(col);
381      c4_Handler &h2 = dst_.NthHandler(col);
382
383#if 0 // memo's are 'B' now, but tricky to deal with, so copy them for now
384      if (ColumnType(col) == 'M') {
385        c4_Column *c1 = h1.GetNthMemoCol(srcPos_, true);
386        c4_Column *c2 = h2.GetNthMemoCol(dstPos_, true);
387
388        t4_i32 p1 = c1 ? c1->Position(): 0;
389        t4_i32 p2 = c2 ? c2->Position(): 0;
390
391        t4_i32 s1 = c1 ? c1->ColSize(): 0;
392        t4_i32 s2 = c2 ? c2->ColSize(): 0;
393
394        d4_assert(false); // broken
395        //!h1.SetNthMemoPos(srcPos_, p2, s2, c2);
396        //!h2.SetNthMemoPos(dstPos_, p1, s1, c1);
397      }
398#endif
399      // 10-4-2002: Need to use copies in case either item points into
400      // memory that could move, or if access re-uses a shared buffer.
401      // The special cases are sufficiently tricky that it's NOT being
402      // optimized for now (temp bufs, mmap ptrs, c4_Bytes buffering).
403
404      int n1, n2;
405      const void *p1 = h1.Get(srcPos_, n1);
406      const void *p2 = h2.Get(dstPos_, n2);
407
408      c4_Bytes t1(p1, n1, true);
409      c4_Bytes t2(p2, n2, true);
410
411      h1.Set(srcPos_, t2);
412      h2.Set(dstPos_, t1);
413    }
414  }
415}
416
417c4_HandlerSeq &c4_HandlerSeq::SubEntry(int col_, int row_)const {
418  d4_assert(IsNested(col_));
419
420  c4_Bytes temp;
421  NthHandler(col_).GetBytes(row_, temp);
422
423  d4_assert(temp.Size() == sizeof(c4_HandlerSeq **));
424  c4_HandlerSeq **p = (c4_HandlerSeq **)temp.Contents(); // loses const
425
426  d4_assert(p != 0 &&  *p != 0);
427
428  return  **p;
429}
430
431c4_Field *c4_HandlerSeq::FindField(const c4_Handler *handler_) {
432  for (int i = 0; i < NumFields(); ++i)
433    if (handler_ ==  &NthHandler(i))
434      return  &Field(i);
435  return 0;
436}
437
438void c4_HandlerSeq::UnmappedAll() {
439  for (int i = 0; i < NumFields(); ++i)
440    NthHandler(i).Unmapped();
441}
442
443// construct meta view from a pre-parsed field tree structure
444// this will one day be converted to directly parse the description string
445void c4_HandlerSeq::BuildMeta(int parent_, int colnum_, c4_View &meta_, const
446  c4_Field &field_) {
447  c4_IntProp pP("P"), pC("C");
448  c4_ViewProp pF("F");
449  c4_StringProp pN("N"), pT("T");
450
451  int n = meta_.Add(pP[parent_] + pC[colnum_]);
452  c4_View fields = pF(meta_[n]);
453
454  for (int i = 0; i < field_.NumSubFields(); ++i) {
455    const c4_Field &f = field_.SubField(i);
456    char type = f.Type();
457    fields.Add(pN[f.Name()] + pT[c4_String(&type, 1)]);
458    if (type == 'V')
459      BuildMeta(n, i, meta_, f);
460  }
461}
462
463/////////////////////////////////////////////////////////////////////////////
464