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