Source: hk_classes/hk_classes/hk_datasource.h


Annotated List
Files
Globals
Hierarchy
Index
// ****************************************************************************
// copyright (c) 2000-2002 Horst Knorr 
// This file is part of the hk_classes library.
// This file may be distributed and/or modified under the terms of the
// GNU Library Public License version 2 as published by the Free Software
// Foundation and appearing in the file COPYING included in the
// packaging of this file.
// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
// ****************************************************************************
#ifndef HK_DATASOURCE
#define HK_DATASOURCE
//#include 
#include "hk_data.h"
#include 
#include 
#include "hk_column.h"
using namespace std;

class hk_database;
class hk_dsvisible;
class hk_presentation;
class hk_actionquery;
class hk_datasourceprivate;
/**
 *
 *@short  represents a resultquery or a table of a database.
 *@version $Revision: 1.2 $
 *@author Horst Knorr (hk_classes@knoda.org)

 *hk_datasource is the basic class which represents a resultquery or a table of a database.
 * Never create this table directly. Use the @ref hk_database::new_table method instead.
 *
 * Two types of this class can be distinguished. Tables and Resultqueries.
 *
 *Resultqueries are Queries with
 * a SELECT - SQL-statement. The resulting data cannot be edited or manipulated.
 *
 *Tables are a special form of resultqueries. The SQL-statement is fixed ("SELECT * FROM ),
 * but the resulting dataset can be edited.
 */

class hk_datasource:public hk_data
{
    friend class hk_column;
    friend class hk_dsvisible;
    friend class hk_database;
    friend class hk_presentation;
    public:
        virtual     ~hk_datasource();
/**
 *sets the name of the datasource
 *@param n the name
 *@param registerchange if this class is part of a hk_presentation object (i.e. a form or a report) and registerchange
 *is true, then the changes will be stored when the hk_presentation object is closed.
 */
        virtual void    set_name(const hk_string& n,bool registerchange=true);
        virtual hk_string name(void);
        enum enum_tablemodes {mode_normal,mode_createtable,mode_altertable,mode_disabled,mode_insertrow,mode_deleterow,mode_unknown};
/**
 *if this datasource is a table, it can be in different "modes".
 *For example if you want to create a new table and define
 *the different columns, the table has to be in "mode_create"
 *See @ref enum_tablemodes for the different modetypes.
 */
        enum_tablemodes mode(void);
/**
 *brings the datasource in insertmode. To add a new row call this function, set the data of the new row
 *as usual in the columns (i.e.with @ref hk_column::ashk_string ) and finally call
 *either @ref setmode_normal or @ref store_changed_data.
 */
        void    setmode_insertrow(void);
/**
 *this function tries to delete the actual row. If there is a depending datasource with equivalent rows
 *the actual row will not be deleted.
 */
        void    delete_actualrow(void);
/**
 *This is the usual mode, where you can browse the data and if the data is not readonly change the data.
 */
        void    setmode_normal(void);

/**
 *If you want to create a new table first  bring the table in createmode. Define new columns with
 *@ref  new_column. Afterwards you can create the table by calling @ref create_table_now
 */
        void    setmode_createtable(void);

/**
 *If you want to alter an existing table first  bring the table in altermode. Define new columns with
 *@ref  new_column. Alter it with @ref alter_column and delete a column by calling @ref alter_column.
 * Afterwards you can alter the table by calling @ref alter_table_now
 */
        void setmode_altertable(void);

/**
 *if this datasource is of type "table" and in mode "create" or "alter" you can
 *create a new column to define its parameters.
 */
        hk_column* new_column(void);

/**
 *if this datasource is of type "table" and in mode "alter" you can
 *alter an existing column. NULL values mean, that this part will not be changed
 */

        bool alter_column(const hk_string& col, const hk_string* name=NULL,hk_column::enum_columntype* newtype=NULL,long* size=NULL,const hk_string* defaultvalue=NULL,const bool* primary=NULL,const bool* notnull=NULL);
/**
 *if this datasource is of type "table" and in mode "alter" you can
 *delete an existing column.Just enter the name here.
 */
        bool delete_column(const hk_string& col);
/**
 * After defining a new table with setmode_createtable and new_column this function
 *creates physically the table
 */
        bool create_table_now(void);
/**
 * After altering an existing table with setmode_altertable, new_column
 *,alter_column and delete_column this function
 *alters physically the table
 */
        bool alter_table_now(void);

/**
 *Goto a specific row. The first row number is 0, the last n-1 where n
 *is the number of rows as delivered from @ref max_rows().All depending objects
 *will be informed (visible objects, depending datasources etc)
 * @param r is the wished new row number to go.
 * @return true if success, else false.
 */
        virtual bool    goto_row(unsigned long r);
/**
 *move the row selector to the first row. All depending objects
 *will be informed (visible objects, depending datasources etc)
 * @return true if success, else false.
 */
        bool    goto_first(void);
/**
 *move the row selector to the last row. All depending objects
 *will be informed (visible objects, depending datasources etc)
 * @return true if success, else false.
 */
        bool    goto_last(void);
/**
 *move the row selector to the next row. All depending objects
 *will be informed (visible objects, depending datasources etc)
 * @return true if success, else false.
 */
        bool    goto_next(void);
/**
 *move the row selector to the previous row.  All depending objects
 *will be informed (visible objects, depending datasources etc)
 * @return true if success, else false.
 */
        bool    goto_previous(void);
/**
 *moves the rowselector to a random row.
 */
        bool    goto_random(void);
/**
 *number of the current row.
 */
        unsigned long row_position(void);
/**
 *number of rows in this query.
 */
        unsigned long max_rows(void);
/**
 * the accessmode regulates the behaviour of the datasource.
 * In mode 'standard' the datasource is readable and writeable, but usually first loads all the data from the
 * SQL server. This is in some cases not necessary. If you just need to serially read one row after another, you
 * can use the 'batchread' mode. In this case random access is not possible and it is not possible to edit the data
 * or insert rows (e.g. this is used in @ref hk_report). In 'batchwrite' mode data can't be read and is only used
 * for inserting data (e.g. used @ref hk_importcsv)
 *The batchmodes do not need as much memory as the standard mode.
 */
        enum enum_accessmode {standard,batchread,batchwrite};
        bool set_accessmode(enum_accessmode);
        enum_accessmode accessmode(void) const;

/**
 *if hk_connection is connected, this method will enable the datasource. The SQL-Statement in @ref SQL
 *will be executed. If the SQL-statement is ok, the resulting data can be reached via the columns in @ref columns. You can browse
 *the data by using the methods @ref goto_row, @ref goto_first,
 *@ref goto_last, @ref goto_next and @ref goto_previous.
 *@return true if enable was successful.
 */
        bool    enable(void);
/**
 *if the datasource is enabled, this function will disable it. The columnlist will be deleted.
 */
        bool    disable(void);
/**
 *convenience function: if e is true the datasource will be enabled by calling @ref enable
 *else it will disable the datasource by calling @ref disable.
 */

        bool    set_enabled(bool e);
/**
 *shows if the datasource is enabled.
 */
        bool    is_enabled(void);
/**
 * @return true if data in this datasource can be changed.
 * Always false if this datasource is a dml_query.
 */
        bool    is_readonly(void);
/**
 *  If the datasource is of type ds_table you can allow or disallow data changes.
 */
        void    set_readonly(bool r);
/**
 *if the datasource is enabled you get a list of all columns.
 *The fields can be reached by columns. See @ref hk_column for details.

 */
        list* columns(void);
/**
 *if the datasource is enabled, you can reach a particular column by name
 *@return @ref hk_column if there is a column with this name else NULL.
 */
        hk_column* column_by_name(const hk_string& c);
/**
 *if the datasource is enabled, you can reach a particular column by name.
 * @param colnumber If there are more than 1 columns with the same name this parameter tells which one to
 *take (1 is the first column)
 *
 *@return @ref hk_column if there is a column with this name else NULL.
 */

        hk_column* column_by_name(const hk_string& c, int colnumber);
/**
 *returns how many columns exist in this datasource with the name 'colname'.
 * Usually columnnames should be unique, but it is unfortunately technically possible to create
 * SQL statements that return ambigous columnnames
 */
        int columnname_occurances(const hk_string& colname);
/**
 * returns if this is the first, second ... nth column with this name
 */
        int columnname_occurance(hk_column*);

/**
 * set your own SQL statement, that will be executed when you enable the datasource.
 * if this datasource is of type "table" it will be automatically created.
 *@param  s is the sql statement
 *@param rawsql if true the sql statement will used as is (otherwise it may be changed to fit
 *@param registerchange if this class is part of a hk_presentation object (i.e. a form or a report) and registerchange
 *is true, then the changes will be stored when the hk_presentation object is closed.
 *sorting, filtering or depending on statements). So it is possible to execute driver specific
 *result queries which do not contain the "SELECT" statement, i.e. SHOW FIELDS in Mysql.
 */
        bool    set_sql(const hk_string& s,bool rawsql=false,bool registerchange=true);
        hk_string   sql(void);
        bool    is_rawsql(void);
        typedef class
        {
            public:
                hk_string  name;
                bool    unique;
                list fields;
        } indexclass;
/**
 * returns the list of all existing indices of a table or NULL in case of an error (i.e. not a table)
 */
        list* indices(void);
/**
 * deletes an index of a table. returns true if successful otherwise false;
 *@param i name of the index
 */
        bool    drop_index(const hk_string& i);
/**
 * creates an index of a table. returns true if successful otherwise false;
 * make sure you have set the tablename first.
 *@param name new name of the index
 *@param unique true if this should be a unique index
 *@param fields the field(column) names used by this index
 *@return true if successful otherwise false;
 */
        bool    create_index(const hk_string& name,bool unique, list& fields);
/**
 * Alters an existing index by first dropping it with @ref drop_index and then by trying to recreate it
 * with @ref create_index
 */
        bool    alter_index(const hk_string& name,bool unique,list& fields);
/**
 *See @ref dependingmode for details
 */
        enum enum_dependingmodes {depending_nohandle,depending_standard,depending_change,depending_delete,depending_changedelete};
/**
*   depending_nohandle     = ignore that this is a depending datasource
*   depending_standard     = can't delete a master row when there are
*                            depending rows in the depending datasource
*                            and can't change the value of a master connection field.
*   depending_change       = if a master connection field is changed, the
*                            equivalent depending fields will change their values too.
*   depending_delete       = if the master row is deleted the depending rows will also be deleted
*   depending_changedelete = combination of depending_change and depending_delete
See also @ref set_depending_on for details */ enum_dependingmodes dependingmode(void); /** *if there are 2 datasources in a 1:n relation it is possible to connect the 2 datasources. *Add the master datasource here ( it's the '1'-datasource in the '1:n'-relation). *Except of the master datasource you also have to add the connected fields with @ref add_depending_fields *This (the depending) datasource will enable/disable automatically *when the master datasource will enable/disable. *if this datasource is part of a @ref hk_presentation use @ref set_depending_on_presentationdatasource instead *@param d is the master datasource *@param react_on_data_changes true if the datasource should react when a value of the masterdatasource is changed *but not yet stored *@param mode how to react when the masterdatasource changes its data. See @ref enum_dependingmodes for details. */ bool set_depending_on(hk_datasource* d,bool react_on_data_changes=false,enum_dependingmodes mode=depending_standard); hk_datasource* depending_on(void); /** *See @ref dependingmode for details */ bool depending_on_react_on_data_changes(void); /** * a list of the depending on columns of this datasource set with @ref add_depending_fields */ list* depending_on_thisfields(void); /** * a list of the depending on columns of the master datasource set with @ref add_depending_fields */ list* depending_on_masterfields(void); /** *if this datasource is part of a hk_presentation object (form or report) then set the depending on datasource with *this function. You can get the unique datasource number of a datasource with @ref presentationnumber *@param d the presentationnumber of the master datasource *@param registerchange if this class is part of a hk_presentation object (i.e. a form or a report) and registerchange *is true, then the changes will be stored when the hk_presentation object is closed. */ bool set_depending_on_presentationdatasource(long d,bool react_on_data_changes=false,enum_dependingmodes mode=depending_standard,bool registerchange=true); long depending_on_presentationdatasource(void); /** * use this method in connection with @ref depending_on. *@param this_ds_field fieldname of a column of this datasource which has to be connected to the master datasource. *@param master_ds_field columnname of the masterdatasource which value has to be equal with the value of this_ds_field. *@param registerchange if this class is part of a hk_presentation object (i.e. a form or a report) and registerchange *is true, then the changes will be stored when the hk_presentation object is closed. */ void add_depending_fields(const hk_string& this_ds_field, const hk_string& master_ds_field,bool registerchange=true); /** *clears the depending list. */ void clear_depending_fields(void); /** * if the data of the actual row has changed you can manually send the changes to the SQL Server * by calling this function. The function will be called automatically before the datasource disables * or the row selector will be moved to another row. */ bool store_changed_data(void); void set_ignore_changed_data(void); bool ignore_changed_data(void) const; /** * it is possible to filter only specific rows from a datasource by setting this filter. * just add the conditions with this function. *@param f same syntax as a SQL statement in the 'WHERE' section, but without the word 'WHERE' *@param registerchange if this class is part of a hk_presentation object (i.e. a form or a report) and registerchange *is true, then the changes will be stored when the hk_presentation object is closed. *Example: SELECT * from addresses WHERE city="München", so you would call set_filter("city=\"München\""); * */ void set_filter(const hk_string& f,bool registerchange=true); hk_string filter(void); /** *temporary filters just work like filters (see @ref set_filter ), but have to be manually activated with *@ref set_use_temporaryfilter. When loaded with @ref loaddata temporaryfilters are deactivated by default. */ void set_temporaryfilter(const hk_string&f); hk_string temporaryfilter(void); void set_use_temporaryfilter(bool use); bool use_temporaryfilter(void); /** * clears the filter which was set with @ref set_filter *@param registerchange if this class is part of a hk_presentation object (i.e. a form or a report) and registerchange *is true, then the changes will be stored when the hk_presentation object is closed. */ void clear_filter(bool registerchange=true); /** * it is possible to sort the datasource. * just add the conditions with this function. *@param f same syntax as a SQL statement in the "ORDER BY" section, but without the word "ORDER BY" *@param registerchange if this class is part of a hk_presentation object (i.e. a form or a report) and registerchange *is true, then the changes will be stored when the hk_presentation object is closed. *Example: SELECT * from addresses ORDER BY city DESC , so you would call set_sorting("city DESC"); */ void set_sorting(const hk_string& s,bool registerchange=true); hk_string sorting(void); void set_temporarysorting(const hk_string& s); hk_string temporarysorting(void); void set_use_temporarysorting(bool use); bool use_temporarysorting(void); /** *clears the sorting instruction *@param registerchange if this class is part of a hk_presentation object (i.e. a form or a report) and registerchange *is true, then the changes will be stored when the hk_presentation object is closed. */ void clear_sorting(bool registerchange=true); /** *when data has changed and the row selector is moved to another row, usually the datasource will *be automatically updated. If the value is set to false, you have to update the data manually by calling * @ref store_changed_data. *@param u If you don't want the automatic update of data changes, set this paramter to false. The default *value is true. */ void set_automatic_data_update(bool u); bool is_automatic_data_update(void); void set_sqldelimiter(const hk_string&); /** *sets the default date and timeformats for new created columns */ void set_datetimeformat(const hk_string& datetime,const hk_string& date,const hk_string& time) { p_datetimeformat=datetime; p_dateformat=date; p_timeformat=time; } hk_database* database(void); /** *stores the object's values to stream s. The following tags will be used * * either QUERY or TABLE * * the name set with @ref set_name * * the used sql statement * *Additionally the section has the following tags * * the filter set with @ref set_filter * * the sorting direction set with @ref set_sorting * * * * * * * *if this datasource is part of a @ref hk_presentation also the following tags will be stored * * the unique presentation number. See @ref presentationnumber * * the depending on datasource set with @ref set_depending_on_presentationdatasource * *one or more sections with the following tags * * set with @ref add_depending_fields * * set with @ref add_depending_fields * *@param s the stream to which the data will be written *@param saveall if true the section will be stored additionally to the normal data */ void savedata(ostream& s,bool saveall=true); /** *loads the object's values out of the definition string. */ void loaddata(const hk_string& definition,bool loadsql=true); /** * stores the datasource as a query file *@return true if successful else false */ // bool savequerytofile(void); /** * load the datasource with the values of a query file *@return true if successful else false */ // bool loadqueryfromfile(void); /** * if the datasource is part of a @ref hk_presentation each datasource gets a unique datasource number *as an identifier *@return the unique datasource number if part of a presenation else -1 */ long presentationnumber(void) const {return p_dscounter;} /** * @return true if a hk_visible object or a depeding datasource is using this datasource *else false */ bool datasource_used(void) const; #ifdef HK_DEBUG /** *@internal * prints all data of this datasource to the standard output */ virtual void dump_data() ; #endif /** *asks interactively for a name */ bool ask_name(void); /** * Delete rows beginning from row number "from" to row number "to" */ bool delete_rows(unsigned long from,unsigned long to,bool check_depending_datasources=true,bool ask=true); /** * Start a transaction. If the SQL server does not support transaction this function does nothing *@param name the name of the transaction */ void transaction_begin(hk_string name=""); /** * Commits a transaction. If the SQL server does not support transaction this function does nothing *@param name the name of the transaction */ void transaction_commit(hk_string name=""); /** * Undo a transaction. If the SQL server does not support transaction this function does nothing *@param name the name of the transaction */ void transaction_rollback(hk_string name=""); /** *if true no visual objects will be informed when data changes in any kind, except the datasource will be deleted *Default is false */ void set_blockvisiblesignals(bool v); bool blockvisiblesignals(void); /** *if true no data will be sent to the database server when data changes in any kind *Default is false */ void set_blockserversignals(bool); bool blockserversignals(void); /** *if true no depending datasources will be informed when data changes in any kind *Default is false */ void set_blockdatasourcesignals(bool); bool blockdatasourcesignals(void); /** *stores the structure of the datasource (fields,indices) in an xml format file and is database driver independent */ void save_datasourcedefinition(ostream& s); /** *loads the structure of the datasource (fields,indices) in an xml format file and creates the tableand is database driver independent */ bool load_datasourcedefinition(const hk_string& definition,bool use_xmltablename=true ,bool ask=true); hk_presentation* presentation(void); protected: hk_string p_sqltextdelimiter; /** *if database driver supports cassensitive column and table names p_casesensitive is true else p_casesensitive is false. *Then internally column_by_name() and name() return values in small letters */ bool p_casesensitive; hk_datasource(hk_database* db,hk_presentation* p=NULL); void column_remove(hk_column* col); void visible_add(hk_dsvisible* v); void visible_remove(hk_dsvisible* v); virtual void driver_specific_transaction_begin(hk_string); virtual void driver_specific_transaction_commit(hk_string); virtual void driver_specific_transaction_rollback(hk_string); virtual unsigned long driver_specific_max_rows(void){return 0;} virtual bool driver_specific_set_accessmode(enum_accessmode){return true;} virtual bool driver_specific_batch_enable(void){return false;} virtual bool driver_specific_batch_disable(void){return false;} virtual bool driver_specific_batch_goto_next(void){return false;} virtual bool driver_specific_batch_goto_previous(void){return false;} /** * has to make sure that the columns-list has been created. It also has to provide access to the data * of the datasource */ virtual bool driver_specific_enable(void){return false;} virtual bool driver_specific_disable(void){return false;} /** * returns a list of the columns of the datasource. If the datasource is a table the list hast to be created * even if the datasource is disabled. Fill the p_columns list for this reason and then return it. * If necessary has to create one hk_column object per column and to add them to p_columns. Each column object has to * get a unique number in its (protected) hk_column::p_fieldnr . */ virtual list* driver_specific_columns(void){return NULL;} virtual bool driver_specific_goto_row(unsigned long r); virtual hk_column* driver_specific_new_column(void){return NULL;} virtual bool driver_specific_update_data(void){return true;} virtual bool driver_specific_delete_data_at(unsigned long){return true;} virtual bool driver_specific_insert_data(void){return true;} virtual bool driver_specific_create_table_now(void){return false;} virtual bool driver_specific_alter_table_now(void){return false;} virtual void driver_specific_before_drop_table(void){} virtual void filelist_changes(filetype t); virtual list* driver_specific_indices(void){return NULL;} virtual bool driver_specific_drop_index(const hk_string& i); virtual bool driver_specific_create_index(const hk_string& name,bool unique,list& fields); virtual void before_connection_disconnects(void); virtual void before_source_vanishes(void); void depending_ds_add(hk_datasource* d); void depending_ds_remove(hk_datasource* d); void depending_on_datasource_row_change(bool take_changed_data=false); void depending_on_datasource_data_has_changed(void); void depending_on_datasource_after_store_changed_data(void); void depending_on_datasource_insertmode(void); bool depending_on_datasource_deleterow_ok(void); bool depending_on_datasource_before_delete_row(void); bool depending_on_datasource_updaterow_ok(void); void depending_on_datasource_before_update_row(void); void depending_on_datasource_after_update_row(void); void reload_data(bool take_changed_data=false); void create_actual_row_where_statement(void); hk_string create_row_where_statement_at(unsigned long int position,bool withwhere=true); void create_new_sql_statement(bool take_changed_data=false); hk_string whole_datasource_where_statement(bool take_changed_data=false); bool p_enabled; bool p_readonly; bool p_primary_key_used; bool p_ignore_changed_data; void clear_columnlist(void); void clear_modecolumnlists(void); void clear_visiblelist(void); void parse_sql(void); virtual void update_row(void); virtual void insert_row(void); virtual void delete_row(void); unsigned long p_counter; // actual row number hk_database* p_database; list* p_columns; typedef class { public: hk_string name; hk_string newname; hk_column::enum_columntype type; long size; hk_string defaultvalue; bool primary; bool notnull; } class_altercolumns; list p_altercolumns; list p_deletecolumns; list p_newcolumns; list depending_this_fields; list depending_master_fields; /** *struct_parsed_sql is needed for parsing th SQL-statement in hk_datasource */ typedef class { public: hk_string select_part, from_part, where_part, groupby_part, having_part, orderby_part ; } struct_parsed_sql; struct_parsed_sql* p_parsed_sql; hk_string p_sql; hk_string p_actual_row_where; bool p_automatic_data_update; hk_actionquery* p_actionquery; hk_string p_datetimeformat; hk_string p_dateformat; hk_string p_timeformat; hk_string p_sql_delimiter; hk_string p_true; hk_string p_false; hk_string p_identifierdelimiter; bool p_tablesql_set; void set_has_changed(void); void set_has_not_changed(void); private: enum_tablemodes p_mode; hk_string p_original_sql; unsigned long p_length; bool p_has_changed; list p_visibles; list p_dependinglist; hk_datasource* p_depending_on_datasource; bool p_depending_on_datasource_react_on_changed_data; void inform_before_row_change(void); void inform_visible_objects_before_store_changed_data(void); void inform_visible_objects_after_store_changed_data(void); void inform_visible_objects_row_change(void); void inform_visible_objects_row_add(void); void inform_visible_objects_row_delete(void); void inform_visible_objects_before_insert_row(void); void inform_before_enable(void); void inform_before_disable(void); void inform_visible_objects_ds_disable(void); void inform_visible_objects_ds_enable(void); void inform_depending_ds_goto_row(void); void inform_depending_ds_store_data(void); void inform_depending_ds_data_has_changed(void); void inform_depending_ds_after_store_changed_data(void); void inform_depending_ds_disable(void); void inform_depending_ds_enable(void); void inform_depending_ds_insertmode(void); void inform_visible_objects_new_columns_created(void); void inform_visible_objects_before_columns_deleted(void); void inform_visible_objects_insertmode(void); void reset_changed_data(void); void inform_when_table_structure_changes(void); void inform_when_indexlist_changes(void); void mark_visible_objects_as_not_handled(void); void execute_visible_object_script_before_update(void); void execute_visible_object_script_after_update(void); void execute_visible_object_before_row_change(void); void execute_visible_object_after_row_change(void); void execute_visible_object_before_delete(void); void execute_visible_object_after_delete(void); void execute_visible_object_before_insert(void); void execute_visible_object_after_insert(void); hk_presentation* p_presentation; // unique number given from a hk_presentation object long p_dscounter; hk_datasourceprivate* p_private; } ; #endif

Generated by: horst on horstnotebook on Wed Sep 24 10:38:50 2003, using kdoc 2.0a54.