#include void TMultiple_rectype::set_body_key(TRectype & rowrec) { const RecDes* recd = rowrec.rec_des(); // Descrizione del record della testata const KeyDes& kd = recd->Ky[0]; // Elenco dei campi della chiave 1 // Copia tutti i campi chiave, tranne l'ultimo, in tutti i records for (int i = kd.NkFields-2; i >= 0; i--) { const int nf = kd.FieldSeq[i] % MaxFields; const RecFieldDes& rf = recd->Fd[nf]; const TString& val = get(rf.Name); rowrec.renum_key(rf.Name, val); } } void TMultiple_rectype::load_rows_file(int logicnum) { const int index = log2ind(logicnum); TRecord_array* r = (TRecord_array*)_files.objptr(index); if (r == NULL) { // crea r = new TRecord_array(logicnum, (TString &) _numfields[index]); _files.add(r, index); } TRectype* rec = new_body_record(logicnum); set_body_key(*rec); r->read(rec); // rilegge _changed.reset(index); } int TMultiple_rectype::find(int logicnum, const char* fieldname, const char* s, int from, bool reverse) const { const TRecord_array & recarray = body(logicnum); const int last = recarray.last_row(); const int len = s ? strlen(s) : 0; if (reverse) { if (from > 0) { if (len == 0) return from - 1; for (int i = recarray.pred_row(from); i > 0; i = recarray.pred_row(i)) if (recarray[i].get(fieldname) == s) return i; } } else { if (last > from) { if (len == 0) return from + 1; for (int i = recarray.succ_row(from); i <= last; i = recarray.succ_row(i)) if (recarray[i].get(fieldname) == s) return i; } } return -1; } int TMultiple_rectype::write_rewrite(TBaseisamfile & f, bool re) const { int err = NOERR; if (_nuovo && re) // E' nuovo di zecca! quindi ... re = FALSE; // ... non fare la rewrite if (re) { for (int i = _files.last(); err == NOERR && i >= 0 ; i = _files.pred(i)) { TRecord_array * r = (TRecord_array *) _files.objptr(i); if (r && !_changed[i]) err = r->write(re); } // rewrite: if (err == NOERR) { err = TRectype::rewrite(f); if (err != NOERR) err = TRectype::write(f); } } else { // write: TMultiple_rectype & myself = *(TMultiple_rectype *)this; const bool to_complete = !myself.key_complete(); if (to_complete) myself.renum(); myself.renum_key(); myself._nuovo |= to_complete; if (_nuovo) { do { err = TRectype::write(f); if (err == _isreinsert) if (myself.renum()) myself.renum_key(); else break; } while (err == _isreinsert); myself._nuovo = (err != NOERR); } else { err = TRectype::write(f); if (err != NOERR) err = TRectype::rewrite(f); } for (int i = _files.last(); err == NOERR && i >= 0 ; i = _files.pred(i)) { TRecord_array * r = (TRecord_array *)_files.objptr(i); if (r && !_changed[i]) err = r->write(re); } } return err; } void TMultiple_rectype::remove_body(int logicnum) { const int index = log2ind(logicnum); _files.destroy(index); } int TMultiple_rectype::log2ind(int logicnum) const { if (logicnum <= 0) return 0; for (int i = _logicnums.last(); i >= 0 ; i--) if (lognum(i) == logicnum) return i; NFCHECK("Can't find file %d in multiple record", logicnum); return 0; } TRecord_array& TMultiple_rectype::body(int logicnum) const { const int index = log2ind(logicnum); if (_files.objptr(index) == NULL || _changed[index]) ((TMultiple_rectype*) this)->load_rows_file(lognum(index)); return (TRecord_array&) _files[index]; } void TMultiple_rectype::renum_key() { TString oldkey; for (int i = _files.last(); i >= 0 ; i = _files.pred(i)) { const int logicnum = lognum(i); TRecord_array * b = & body(logicnum); if (b) { if (i==0) oldkey=b->key().build_key(); // convertire al piu' presto le seguenti righe ... TRectype * rec = new TRectype(b->key()); set_body_key(*rec); b->set_key(rec); // Aggiorna righe // .. nella piu' economiche //set_body_key(*b); // ...dove set_body_key(TRecarray & b) e' la nuova funzione virtuale da implementare // che realizza direttamente la rinumerazione del record array if (i==0) if (oldkey != b->key().build_key()) _nuovo = TRUE; } } } TRectype & TMultiple_rectype::operator =(const TRectype & r) { TRectype::operator=(r); reset_fields(*this); set_fields(*this); return *this; } TRectype & TMultiple_rectype::operator =(const char * r) { TRectype::operator=(r); reset_fields(*this); set_fields(*this); return *this; } void TMultiple_rectype::zero(char c) { reset_fields(*this); TAuto_variable_rectype::zero(c); for (int i = _files.last(); i >= 0 ; i = _files.pred(i)) ((TRecord_array &)_files[i]).destroy_rows(); _nuovo = TRUE; } int TMultiple_rectype::readat(TBaseisamfile& f, TRecnotype nrec, word lockop) { _nuovo = FALSE; int err = TRectype::readat(f, nrec, lockop); synchronize_bodies(); return err; } int TMultiple_rectype::read(TBaseisamfile & f, word op, word lockop) { int err = NOERR; _nuovo = FALSE; if (op == _isequal) { const TRectype oldr(*this); err = TRectype::read(f, op, lockop); if (err != NOERR) { *this = oldr; _nuovo = TRUE; } } else { err = TRectype::read(f, op, lockop); } synchronize_bodies(); return err; } void TMultiple_rectype::synchronize_bodies() { for (int i = _logicnums.last(); i >= 0 ; i--) { if (_nuovo) { TRecord_array * b = (TRecord_array *) _files.objptr(i); if (b == NULL) { b = new TRecord_array(lognum(i), (TString &) _numfields[i]); _files.add(b, i); } _changed.reset(i); b->destroy_rows(); TRectype * r = new_body_record(lognum(i)); set_body_key(*r); b->set_key(r); } else { if (_autoload[i]) load_rows_file(lognum(i)); else if (_files.objptr(i) != NULL) _changed.set(i); } } } // @mfunc Copia il multiple rectype r su quello corrente TMultiple_rectype & TMultiple_rectype::copy(const TMultiple_rectype& r) { // copia.. TAuto_variable_rectype::operator=((TAuto_variable_rectype&)r); _nuovo = r._nuovo; _files = r._files; _logicnums = r._logicnums; _changed = r._changed; _autoload = r._autoload; _numfields = r._numfields; return *this; } // @mfunc Copia il multiple rectype r su quello corrente int TMultiple_rectype::loaded_rows(int logicnum) const { const int index = log2ind(logicnum); TRecord_array* r = (TRecord_array*) ((TMultiple_rectype *) this)->_files.objptr(index); if (_changed[index] || r == NULL) return 0; return r->rows(); } // @mfunc confronta due record multipli // Affidabilitą 95% int TMultiple_rectype::compare(const TSortable& s) const { int res = TRectype::compare(s); TMultiple_rectype & m = (TMultiple_rectype &) s; for (int i = 0 ; res == 0 && i < _logicnums.items(); i++) { const int logicnum = lognum(i); TRecord_array & r = body(logicnum); TRecord_array & r1 = m.body(logicnum); res = r.rows() - r1.rows(); if (res == 0 && r.rows() > 0 && r1.rows() > 0) { for (int j = r.last_row(), k = r1.last_row(); res == 0 && j > 0 && k > 0; j = r.pred_row(j), k = r1.pred_row(k)) { res = j - k; // Controlla che non ci siano salti if (res == 0) res = r[j].compare(r1[j]); } } } return res; } // @mfunc controlla se due record multipli sono uguali // Affidabilitą 100% bool TMultiple_rectype::is_equal(const TMultiple_rectype& m) const { bool yes = TRectype::is_equal(m); const int last = _logicnums.last(); // qui for (int i = 0; yes && i < last; i++) { const int logicnum = lognum(i); TRecord_array & r = body(logicnum); TRecord_array & r1 = m.body(logicnum); yes = r.rows() == r1.rows(); if (yes && r.rows() > 0 && r1.rows() > 0) { for (int j = r.last_row(), k = r1.last_row(); yes && j > 0 && k > 0; j = r.pred_row(j), k = r1.pred_row(k)) { yes = (j == k) && r[j].is_equal(r1[k]); } } } return yes; } int TMultiple_rectype::remove(TBaseisamfile & f) const { int err = NOERR; for (int i = _logicnums.last(); err == NOERR && i >= 0 ; i = _logicnums.pred(i)) { TRecord_array & r = body(lognum(i)); err = r.remove(); } if (err == NOERR) err = TRectype::remove(f); return err; } void TMultiple_rectype::fill_transaction(TConfig& cfg, int row) const { CHECK(row == 0, "You can't specify a row for multiple rectypes"); TRectype::fill_transaction(cfg); const int last = _logicnums.last(); // qui for (int i = 0; i < last; i++) { TRecord_array& b = body(lognum(i)); for (int r = 1; b.exist(r); r++) b[r].fill_transaction(cfg, r); } } // @doc INTERNAL TMultiple_rectype::TMultiple_rectype(int hfn) : TAuto_variable_rectype(hfn), _nuovo(TRUE) { } void TMultiple_rectype::enable_autoload(int logicnum,bool on) { const int index = log2ind(logicnum); _autoload.set(index, on); } TRectype & TMultiple_rectype::insert_row(int row, int logicnum) { TRectype * r = new_body_record(logicnum); TRecord_array & b = body(logicnum); const int index = log2ind(logicnum); set_body_key(*r); r->put(_numfields.row(index), row); b.insert_row(r); return *r; } TRectype & TMultiple_rectype::new_row(int logicnum) { TRecord_array & b = body(logicnum); TRectype & r = b.row(-1, TRUE); return r; } bool TMultiple_rectype::autoload_enabled(int logicnum) { return _autoload[log2ind(logicnum)]; } // @cmember Aggiunge il corpo lgicnum void TMultiple_rectype::add_file(int logicnum, const char* numfield) { _logicnums.add_long(logicnum); _numfields.add(numfield); } TMultiple_rectype::TMultiple_rectype(const TBaseisamfile* file) :TAuto_variable_rectype(file), _nuovo(TRUE) { } // @ cmember costruttore dal record TMultiple_rectype::TMultiple_rectype(const TRectype & rec) :TAuto_variable_rectype(rec), _nuovo(TRUE) { } // @mfunc costruttore di copia TMultiple_rectype::TMultiple_rectype(const TMultiple_rectype& r) :TAuto_variable_rectype(r) { // copia.. copy(r); }