/* $Id: relation.h,v 1.21 1995-06-28 16:35:30 guy Exp $ */ // join.h // fv 12/8/93 // join class for isam files #ifndef __RELATION_H #define __RELATION_H #ifndef __ISAM_H #include #endif class TRelation : public TObject { friend class TRelationdef; friend class TRelation_description; friend class TCursor; TToken_string _status; // stato della relazione TArray _files; // file descriptors TArray _reldefs; // TRelationdef array int _errors; protected: 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]; } // 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 int position_rels(TIsamop op = _isequal, TReclock lockop = _nolock, TDate& atdate = (TDate&)botime, int first = 0); public: // TObject virtual bool ok() const { return good(); } virtual void print_on(ostream& out) const; public: 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 = 0, const bool on = TRUE) ; void write_enable(const char* name, const bool on = TRUE) ; void write_disable(int logicnum = 0) { 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); 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); // write methods 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); // status methods // return the status of the relation when called // with no args, or the status of the file when called with // a logical number bool eof( int logicnum = 0) const { return lfile(logicnum).eof(); } bool bof( int logicnum = 0) const { return lfile(logicnum).bof(); } bool status(int logicnum = 0) const { return lfile(logicnum).status(); } bool good( int logicnum = 0) const { return lfile(logicnum).good(); } bool bad( int logicnum = 0) const { return lfile(logicnum).bad(); } bool empty( int logicnum = 0) const { return lfile(logicnum).empty(); } // 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. 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); // items() ritorna il numero di files collegati int items() { return _reldefs.items(); } void save_status () ; void restore_status () ; // positioning operators. return status TRecnotype operator +=(const TRecnotype npos) { return skip(npos); } TRecnotype operator -=(const TRecnotype npos) { return skip(-npos); } TRecnotype operator ++() { return next(); } TRecnotype operator --() { return prev(); } TRelation(int logicnum); TRelation(const char* tabname); TRelation(TLocalisamfile* f); virtual ~TRelation(); }; /////////////////////////////////////////////////////////// // TRecord_Array /////////////////////////////////////////////////////////// class TRecord_array : private TArray { int _file; // Numero logico del file principale int _offset; // Offset iniziale del record array 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() + _offset; } // Ultima riga int first_row() const { return 1 + _offset ; } const TRectype& row(int r) const // Ennesima riga costante { CHECKD(r > _offset, "Bad record number ", r); return (const TRectype&)operator[](r - _offset); } 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, int first = 1); TRecord_array(int logicnum, const char* numfield, int first = 1); }; // Classe TCursor : public TObject class TExpression; typedef bool (*FILTERFUNCTION)(const TRelation* r); class TCursor : public TObject { 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; 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(); }; // Classe TFieldref : public TObject class TFieldref : public TObject { short _fileid; // Numero del file TString _id; // Nome tabella o stringa col numero del file TString _name; // Nome del campo int _from, _to; // Substring protected: virtual void print_on(ostream& out) const; public: 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 void set_file(int f); const TString& name() const { return _name; } // ritorna il nome del campo void set_name(const char* n) { _name = n; } void set_from(int f) { if (f > 0) f--; else f = 0; _from = f; } void set_to(int t) { _to = t; } int from() const { return _from; } int to() const { return _to; } int len(TRectype &rec) const; const char* read(const TRelation*) const; const char* read(const TRectype&) const; void write(const char* val, TRelation*) const; void write(const char* val, TRectype& rec) const; }; // Converte una stringa in numero logico o numero tabella int name2log(const char* name); class TRelation_description : public TObject { // gestisce l'uso interattivo di una relazione (scelta campi, descrizione) // domani o doman l'altro gestira' l'editing interattivo e grafico TRelation* _rel; // relation described TString_array _files; TArray _fields; int _cur_file; int _cur_field; bool _menu; TToken_string _cfile, _cfield; protected: void init_files_array(); void read_rel(); public: // TObject virtual bool ok() const { return _files.items() > 0; } public: // "choose" interface: after choosing a field (must return TRUE) // methods allow to know all data concerning the field // parameters set the one initially selected bool choose_file (int id = 0); bool set_cur_file(int id = 0); // file must have been chosen: first file in list if called // before choose_file bool choose_field(const char* fld = ""); // if wanted, build a menu tree and set current field upon // selecting it (should be popup) bool build_menu(const char* title = "Database"); bool remove_menu(); // if choose_file == TRUE or menu has been used these return valid data int file_num(); const char* file_desc(); void file_desc(const char* desc); bool set_field_description(const char* field, const char* des); const char* get_field_description(const char* field); // if choose_field == TRUE or menu has been used these return valid data const char* field_desc(); void field_desc(const char* desc); const char* field_name(); int field_len(); TFieldtypes field_type(); const TString_array& get_all_desc() const { return _files; } void change_relation(TRelation& rel, TString_array& arr); virtual void print_on(ostream& out) const; TRelation_description(TRelation& r); virtual ~TRelation_description(); }; #endif // ** EOF relation.h