Files correlati : Ricompilazione Demo : [ ] Commento : Riportata la versione 2.1 598 git-svn-id: svn://10.65.10.50/trunk@13909 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			495 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			495 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| #include <stdlib.h>
 | ||
| 
 | ||
| #include <multirec.h>
 | ||
| #include <relation.h>
 | ||
| 
 | ||
| bool TMultiple_rectype::key_complete() const
 | ||
| {
 | ||
|   const RecDes& recd = *rec_des();    // Descrizione del record
 | ||
|   const KeyDes& kd = recd.Ky[0];
 | ||
|   const int nf = kd.FieldSeq[kd.NkFields - 1] % MaxFields; //posizione ultimo campo chiave principale
 | ||
|   const RecFieldDes& rf = recd.Fd[nf];
 | ||
| 
 | ||
|   const TString& val = get(rf.Name);
 | ||
|   bool ok = !val.blank();
 | ||
|   if (ok)
 | ||
|   {
 | ||
| 	  const int type = rf.TypeF;  // Controllo meglio i campi numerici
 | ||
| 	  if (type == _intfld || type == _longfld || type == _intzerofld || type == _longzerofld)
 | ||
| 	    ok = atol(val) > 0;
 | ||
|   }
 | ||
| 
 | ||
|   return ok;
 | ||
| }
 | ||
| 
 | ||
| //assegna il prossimo numero all'ultimo campo della chiave principale della testata
 | ||
| bool TMultiple_rectype::renum()
 | ||
| {
 | ||
|   const RecDes& recd = *rec_des();    // Descrizione del record
 | ||
|   const KeyDes& kd = recd.Ky[0];
 | ||
|   const int nf = kd.FieldSeq[kd.NkFields - 1] % MaxFields; //posizione ultimo campo chiave principale
 | ||
|   const RecFieldDes& rf = recd.Fd[nf];
 | ||
| 
 | ||
|   const int type = rf.TypeF;  // Controllo che il campo sia numerico
 | ||
|   if (type != _intfld && type != _longfld && type != _intzerofld && type != _longzerofld)
 | ||
|     return false;
 | ||
| 
 | ||
|   TRectype::zero(rf.Name); //azzera il contenuto del campo chiave numerico
 | ||
|   long next_num = 1;
 | ||
| 
 | ||
|   if (kd.NkFields == 1)  //chiave principale con un solo campo
 | ||
|   {
 | ||
|     TLocalisamfile file(num());
 | ||
|     if (file.last() == NOERR)
 | ||
|       next_num += file.get_long(rf.Name);
 | ||
|   }
 | ||
|   else  //chiave principale con piu' campi
 | ||
|   {
 | ||
|     TRelation rel(num()); //relazione sul file principale
 | ||
|     TCursor cur(&rel, "", 1, this, this); //cursore generale per chiavi multicampo
 | ||
|     const long items = cur.items();
 | ||
|   
 | ||
|     if (items > 0)
 | ||
|     {
 | ||
|       cur.freeze();
 | ||
|       cur = items - 1;  //va sull'ultimo record del file
 | ||
|       next_num += cur.curr().get_long(rf.Name);
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   put(rf.Name, next_num);
 | ||
| 
 | ||
|   return true;
 | ||
| }
 | ||
| 
 | ||
| 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, _numfields.row(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 Ritorna il numero di righe caricate
 | ||
| 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<69> 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<69> 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);
 | ||
| }
 | ||
| 
 |