/* $Id: relation.h,v 1.15 1995-04-18 08:40:18 guy Exp $ */ // join.h // fv 12/8/93 // join class for isam files #ifndef __RELATION_H #define __RELATION_H #ifndef __ISAM_H #include #endif // @C class TRelation : public TObject { friend class TRelationdef; // class TRelation : public TLocalisamfile // @END // @DPRIV TToken_string _status; // stato della relazione TArray _files; // file descriptors TArray _reldefs; // TRelationdef array int _errors; // @END // @FPROT protected: virtual void print_on(ostream& out) const; int log2ind(int logicnum) const; int alias2ind(int alias) const; int name2ind(const char* name) const; TRelationdef& reldef(int i) const { return (TRelationdef&)_reldefs[i]; } TLocalisamfile& file(int i = 0) const { return (TLocalisamfile&)_files[i]; } // @LONGDES // position_rels fa tutto il lavoro: se non trova un record // adatto su un file, svuota il record corrente e non ritorna errore. // write etc. poi procedono normalmente // @END int position_rels(TIsamop op = _isequal, TReclock lockop = _nolock, TDate& atdate = (TDate&)botime, int first = 0); friend class TCursor; public: // @FPUB int update() { return position_rels(_isequal, _nolock);} void zero(); virtual int next(TReclock lockop = _nolock) { return file().next(lockop) == NOERR ? position_rels(_isequal, lockop) : file().status(); } virtual int prev(TReclock lockop = _nolock) { return file().prev(lockop) == NOERR ? position_rels(_isequal, lockop) : file().status(); } virtual int next(TDate& atdate) { return file().next(atdate) == NOERR ? position_rels(_isequal, _nolock, atdate) : file().status(); } virtual int prev(TDate& atdate) { return file().prev(atdate) == NOERR ? position_rels(_isequal, _nolock, atdate) : file().status(); } virtual int first(TReclock lockop = _nolock) { return file().first(lockop) == NOERR ? position_rels(_isequal, lockop) : file().status(); } virtual int last(TReclock lockop = _nolock) { return file().last(lockop) == NOERR ? position_rels(_isequal, lockop) : file().status(); } virtual int skip(TRecnotype nrec, TReclock lockop = _nolock) { return file().skip(nrec, lockop) == NOERR ? position_rels(_isequal, lockop) : file().status(); } virtual int read(TIsamop op = _isgteq, TReclock lockop = _nolock, TDate& atdate = (TDate&)botime) { return file().read(op, lockop, atdate) == NOERR ? position_rels(_isequal, lockop, atdate) : file().status();} TLocalisamfile& lfile(int logicnum = 0) const; TLocalisamfile& lfile(const char* name) const; void write_enable(int logicnum = -1, const bool on = TRUE) ; void write_enable(const char* name, const bool on = TRUE) ; void write_disable(int logicnum = -1) { write_enable(logicnum, FALSE); } void write_disable(const char* name) { write_enable(name, FALSE); } TRectype& curr(int logicnum = 0) const { return lfile(logicnum).curr(); } // next_match for 0ne-to-many relations; positions logicnum (!= main) // on next matching record; returns TRUE or FALSE if no more matches; in // any case relation is kept consistent except when inconsistent in // first place bool next_match(int logicnum, const char* fieldlist = NULL, int nkey = 0); // @DES add relation // @FPUB bool add(TLocalisamfile* f, const char* relexprs, int key, int linkto, int alias, bool allow_lock); bool add(int logicnum, const char* relexprs, int key = 1, int linkto = 0, int alias = 0, bool allow_lock = FALSE); bool add(const char* tabname, const char* relexprs, int key = 1, int linkto = 0, int alias = 0, bool allow_lock = FALSE); void replace(TLocalisamfile* f, int index = 0); // @DES write methods // @FPUB virtual int write (bool force = TRUE, TDate& atdate = (TDate&)botime); virtual int rewrite(bool force = TRUE, TDate& atdate = (TDate&)botime); virtual int remove (TDate& atdate = (TDate&)botime); // @DES checking methods // @FPUB bool eof( int logicnum = 0) { return lfile(logicnum).eof(); } bool bof( int logicnum = 0) { return lfile(logicnum).bof(); } // @N // status(), good() and bad() return the status of the relation when called // with no args, or the status of the file when called with // a logical number // @END bool status(int logicnum = 0) { return lfile(logicnum).status(); } bool good( int logicnum = 0) { return lfile(logicnum).good(); } bool bad( int logicnum = 0) { return lfile(logicnum).bad(); } bool empty( int logicnum = 0) { return lfile(logicnum).empty(); } // @END // @LONGDES // isconsistent() returns TRUE if every file in the relation is // OK, current record is non-empty, and relation is consistent. // If it's not and reset is TRUE, it tries to reset the relation // to a consistent state (based on main record) -- no further check // is done. // Also called internally by update and remove. // @END bool isconsistent(bool reset = FALSE); // TRUE se c'e' un record ed e' il primo match (non si e' mai fatta // position_rels) bool is_first_match(int logicnum); void save_status () ; void restore_status () ; // @DES positioning operators. return status // @FPUB TRecnotype operator +=(const TRecnotype npos) { return skip(npos); } TRecnotype operator -=(const TRecnotype npos) { return skip(-npos); } TRecnotype operator ++() { return next(); } TRecnotype operator --() { return prev(); } void print_on(TArray& a) const; // Mette la descrizione in un array di TToken_string TRelation(int logicnum, bool linkrecinst = FALSE); TRelation(const char* tabname, bool linkrecinst = FALSE); TRelation(TLocalisamfile* f); virtual ~TRelation(); }; /////////////////////////////////////////////////////////// // TRecord_Array /////////////////////////////////////////////////////////// class TRecord_array : private TArray { int _file; // Numero logico del file principale TString16 _num; // Nome del campo col numero di riga private: int rec2row(const TRectype& r) const; // Estrae il numero riga di un record const TRectype& key() const; public: int rows() const { return items()-1; } // Numero di righe presenti int last_row() const { return last(); } // Ultima riga const TRectype& row(int r) const // Ennesima riga costante { CHECKD(r > 0, "Bad record number ", r); return (const TRectype&)operator[](r); } TRectype& row(int r, bool create); // Ennesima riga virtual int add_row(const TRectype& r); // Aggiungi/cambia una riga virtual bool destroy_row(int n, bool pack = FALSE); // Cancella una riga virtual bool destroy_row(const TRectype& r, bool pack = FALSE) { return destroy_row(rec2row(r), pack); } void destroy_rows(); // Cancella tutte le righe bool renum_key(const char* field, const TString& num); bool renum_key(const char* field, long num); // Rinumera campo chiave in seguito a reinsert virtual int read(const TRectype& r); // Leggi tutto l'array da file virtual int write(bool re = FALSE); // Aggiorna il file virtual int rewrite() { return write(TRUE); } virtual int remove(); // Cancella tutti i record dal file TRecord_array(const TRectype& r, const char* numfield); TRecord_array(int logicnum, const char* numfield); }; // @C // Classe TCursor : public TObject // // @END class TExpression; typedef bool (*FILTERFUNCTION)(const TRelation* r); class TCursor : public TObject { // @DPRIV TRelation* _if; int _nkey; TRecnotype _pos; // Posizione corrente TRecnotype _totrec; TRecnotype _lastrec; TRecnotype _lastkrec; TFilename _filename; TString _filter; // Filtro TString _keyfrom; // chiave iniziale TString _keyto; // chiave finale TExpression* _fexpr; // Espressione relativo filtro bool _frozen; FILTERFUNCTION _filterfunction; TFilename _indexname; // @END // @FPRIV virtual TRecnotype buildcursor(TRecnotype rp); int filtercursor(int pagecnt, TRecnotype* page); bool changed(); FILE* open_index(bool create = FALSE); TRecnotype update(); protected: TRecnotype readrec(); void filter(const char* filter, const TRectype* from = NULL, const TRectype* to = NULL); public: // @FPUB TRecnotype operator =(const TRecnotype nr); // Va alla posizione nr TRecnotype operator +=(const TRecnotype nr); TRecnotype operator -=(const TRecnotype npos) { return operator +=(-npos); } TRecnotype operator ++() { return operator +=(1); } TRecnotype operator --() { return operator -=(1); } TRecnotype pos() const { return _pos; } TRecnotype items(); TRecnotype size() const { return file().eod(); } const TString& from() const { return _keyfrom; } const TString& to() const { return _keyto; } TRectype& curr(int log = 0) const { return _if->curr(log); } TRectype& curr(const char * tab) const { return _if->lfile(tab).curr(); } TRecnotype read(TIsamop op = _isgteq, TReclock lockop = _nolock, TDate& atdate = (TDate&)botime); int lock(TReclock = _lock); int unlock() { return lock(_unlock); } virtual bool ok() const; const char* filter() const { return _filter; } void freeze(bool on = TRUE) { _frozen = on; } bool frozen() const { return _frozen; } void setfilter(const char* filter_expr) { filter(filter_expr); } void setregion(const TRectype& from, const TRectype& to) { filter(NULL,&from, &to); } TRelation* relation() const { return _if; } TLocalisamfile& file(int lnum = 0) const { return _if->lfile(lnum); } TLocalisamfile& file(const char* name) const { return _if->lfile(name); } int repos() { return _if->position_rels(); } void setkey() { file().setkey(_nkey); } void setkey(int nkey); int key() const { return _nkey; } bool next_match(int lognum, const char* fl = NULL, int nk = 0); bool is_first_match(int ln); void set_filterfunction(FILTERFUNCTION ff) { _filterfunction = ff; _lastrec = 0L;} bool has_filter() const { return _filter.not_empty() || _filterfunction; } void save_status () { _if->save_status(); } void restore_status () { _if->restore_status(); } TCursor(TRelation* f, const char* filter = "", int key = 1, const TRectype* from = NULL, const TRectype* to = NULL); virtual ~TCursor(); }; // @C // Classe TFieldref : public TObject // @END class TFieldref : public TObject { // @DPRIV short _fileid; // Numero del file TString16 _id; // Nome tabella o stringa col numero del file TString80 _name; // Nome del campo int _from, _to; // Substring protected: virtual void print_on(ostream& out) const; public: // @FPUB TFieldref(); TFieldref(const TString&, short defid); TFieldref& operator =(const TString& s); // Operatore di assegnazione virtual bool ok() const { return _name.not_empty(); } // Vero se il numero del file e' valido int file() const { return _fileid; } // ritorna il file const char* name() const { return (const char*) _name; } // ritorna il nome del campo int from() const { return _from; } int to() const { return _to; } int len(TRectype &rec) const; const char* read(const TRelation* = NULL) const; const char* read(const TRectype&) const; void write(const char* val, TRelation* = NULL) const; void write(const char* val, TRectype& rec) const; }; // Converte una stringa in numero logico o numero tabella int name2log(const char* name); #endif // ** EOF relation.h