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