From 72b2622d084a15dcf468c545a489e4e6927ba344 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Mon, 16 Apr 2018 22:46:25 +0000 Subject: [PATCH] some work in morm - support for fetching rows from db - support for inserting/updating rows git-svn-id: svn://ttmath.org/publicrep/morm/trunk@1081 e52654a7-88a9-db11-a3e9-0013d4bc506e --- src/Makefile.dep | 20 +- src/baseexpression.cpp | 26 ++- src/baseexpression.h | 67 +++++- src/dbconnector.cpp | 279 +++++++++++++++++++++-- src/dbconnector.h | 85 ++++++- src/dbexpression.cpp | 13 +- src/dbexpression.h | 2 + src/finder.h | 70 +++++- src/jsonexpression.cpp | 11 + src/jsonexpression.h | 4 + src/model.cpp | 32 +++ src/model.h | 31 ++- src/modelconnector.cpp | 95 ++++++-- src/modelconnector.h | 83 ++++++- src/morm_types.h | 12 +- src/postgresqlconnector.cpp | 437 ++++++++++++++++-------------------- src/postgresqlconnector.h | 17 +- 17 files changed, 965 insertions(+), 319 deletions(-) diff --git a/src/Makefile.dep b/src/Makefile.dep index f2ccd4e..d940ecb 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep @@ -11,7 +11,9 @@ baseexpression.o: ../../pikotools/convert/text.h baseexpression.o: ../../pikotools/convert/misc.h baseexpression.o: ../../pikotools/membuffer/membuffer.h baseexpression.o: ../../pikotools/textstream/types.h morm_types.h model.h -baseexpression.o: modelconnector.h ../../pikotools/utf8/utf8.h +baseexpression.o: modelconnector.h dbconnector.h dbexpression.h +baseexpression.o: flatexpression.h flatconnector.h +baseexpression.o: ../../pikotools/utf8/utf8.h dbconnector.o: dbconnector.h dbexpression.h baseexpression.h dbconnector.o: ../../pikotools/textstream/textstream.h dbconnector.o: ../../pikotools/space/space.h @@ -22,7 +24,8 @@ dbconnector.o: ../../pikotools/convert/strtoint.h dbconnector.o: ../../pikotools/convert/text.h ../../pikotools/convert/misc.h dbconnector.o: ../../pikotools/membuffer/membuffer.h dbconnector.o: ../../pikotools/textstream/types.h morm_types.h model.h -dbconnector.o: modelconnector.h +dbconnector.o: modelconnector.h flatexpression.h flatconnector.h +dbconnector.o: ../../pikotools/utf8/utf8.h dbexpression.o: dbexpression.h baseexpression.h dbexpression.o: ../../pikotools/textstream/textstream.h dbexpression.o: ../../pikotools/space/space.h @@ -42,6 +45,7 @@ finder.o: ../../pikotools/convert/misc.h finder.o: ../../pikotools/membuffer/membuffer.h finder.o: ../../pikotools/textstream/types.h modelconnector.h finder.o: baseexpression.h morm_types.h dbconnector.h dbexpression.h +finder.o: flatexpression.h flatconnector.h flatconnector.o: flatconnector.h flatexpression.h baseexpression.h flatconnector.o: ../../pikotools/textstream/textstream.h flatconnector.o: ../../pikotools/space/space.h @@ -54,7 +58,7 @@ flatconnector.o: ../../pikotools/convert/text.h flatconnector.o: ../../pikotools/convert/misc.h flatconnector.o: ../../pikotools/membuffer/membuffer.h flatconnector.o: ../../pikotools/textstream/types.h morm_types.h model.h -flatconnector.o: modelconnector.h +flatconnector.o: modelconnector.h dbconnector.h dbexpression.h flatexpression.o: flatexpression.h baseexpression.h flatexpression.o: ../../pikotools/textstream/textstream.h flatexpression.o: ../../pikotools/space/space.h @@ -99,7 +103,8 @@ model.o: ../../pikotools/convert/inttostr.h model.o: ../../pikotools/convert/strtoint.h ../../pikotools/convert/text.h model.o: ../../pikotools/convert/misc.h ../../pikotools/membuffer/membuffer.h model.o: ../../pikotools/textstream/types.h modelconnector.h baseexpression.h -model.o: morm_types.h +model.o: morm_types.h dbconnector.h dbexpression.h flatexpression.h +model.o: flatconnector.h modelconnector.o: modelconnector.h baseexpression.h modelconnector.o: ../../pikotools/textstream/textstream.h modelconnector.o: ../../pikotools/space/space.h @@ -111,9 +116,9 @@ modelconnector.o: ../../pikotools/convert/strtoint.h modelconnector.o: ../../pikotools/convert/text.h modelconnector.o: ../../pikotools/convert/misc.h modelconnector.o: ../../pikotools/membuffer/membuffer.h -modelconnector.o: ../../pikotools/textstream/types.h morm_types.h model.h -modelconnector.o: flatconnector.h flatexpression.h dbconnector.h -modelconnector.o: dbexpression.h +modelconnector.o: ../../pikotools/textstream/types.h morm_types.h +modelconnector.o: dbconnector.h dbexpression.h flatexpression.h +modelconnector.o: flatconnector.h model.h postgresqlconnector.o: postgresqlconnector.h dbconnector.h dbexpression.h postgresqlconnector.o: baseexpression.h postgresqlconnector.o: ../../pikotools/textstream/textstream.h @@ -128,6 +133,7 @@ postgresqlconnector.o: ../../pikotools/convert/misc.h postgresqlconnector.o: ../../pikotools/membuffer/membuffer.h postgresqlconnector.o: ../../pikotools/textstream/types.h morm_types.h postgresqlconnector.o: ../../pikotools/utf8/utf8.h postgresqlexpression.h +postgresqlconnector.o: ../../pikotools/convert/strtoint.h postgresqlexpression.o: postgresqlexpression.h dbexpression.h postgresqlexpression.o: baseexpression.h postgresqlexpression.o: ../../pikotools/textstream/textstream.h diff --git a/src/baseexpression.cpp b/src/baseexpression.cpp index f4bba3e..0c6ea5e 100644 --- a/src/baseexpression.cpp +++ b/src/baseexpression.cpp @@ -63,15 +63,21 @@ void BaseExpression::set_work_mode(int work_mode) void BaseExpression::generate_from_model(PT::TextStream & stream, Model & model) { this->out_stream = &stream; - - before_generate_from_model(); - model.map_fields(); - after_generate_from_model(); - + generate_from_model(model); this->out_stream = nullptr; } +void BaseExpression::generate_from_model(Model & model) +{ + if( out_stream ) + { + before_generate_from_model(); + model.map_fields(); + after_generate_from_model(); + } +} + void BaseExpression::before_generate_from_model() { is_first_field = true; @@ -161,6 +167,14 @@ void BaseExpression::after_field_value(const char *) { } +void BaseExpression::before_field_value(const PT::Date &) +{ +} + +void BaseExpression::after_field_value(const PT::Date &) +{ +} + void BaseExpression::put_name_value_separator() @@ -315,7 +329,7 @@ void BaseExpression::esc(void* val, PT::TextStream & stream) void BaseExpression::esc(const PT::Date & date, PT::TextStream & stream) { - stream << "'" << date << "'"; + stream << date; } diff --git a/src/baseexpression.h b/src/baseexpression.h index 6a1f166..db193bf 100644 --- a/src/baseexpression.h +++ b/src/baseexpression.h @@ -35,7 +35,7 @@ #ifndef headerfile_morm_baseexpression #define headerfile_morm_baseexpression - +#include #include "textstream/textstream.h" #include "morm_types.h" #include "date/date.h" @@ -86,6 +86,34 @@ public: } + template + void field_list(const wchar_t * field_name, const std::list & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + { + if( out_stream && can_field_be_generated(insertable, updatable, is_primary_key) ) + { + field_before(); + +// if( work_mode == MORM_WORK_MODE_MODEL_FIELDS ) +// { +// put_field_name(field_name); +// } +// else +// if( work_mode == MORM_WORK_MODE_MODEL_VALUES ) +// { +// put_field_value(field_value); +// } +// else + if( work_mode == MORM_WORK_MODE_MODEL_FIELDS_VALUES ) + { + put_field_name(field_name); + put_name_value_separator(); + put_field_value_list(field_value); + } + + field_after(); + } + } + template void field(PT::TextStream & stream, const wchar_t * field_name, const FieldValue & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { @@ -144,6 +172,8 @@ protected: // generate_from_model(); // } + virtual void generate_from_model(Model & model); + virtual void before_generate_from_model(); virtual void after_generate_from_model(); virtual bool can_field_be_generated(bool insertable, bool updatable, bool is_primary_key); @@ -162,6 +192,38 @@ protected: after_field_value(field_value); } + template + void put_field_value_list(const std::list & field_value) + { + if( out_stream ) + { + (*out_stream) << "[";// make a virtual method + } + + bool is_first = true; + + for(ModelClass m : field_value) + { + if( out_stream ) + { + if( !is_first ) + { + if( out_stream ) + (*out_stream) << ","; // make a virtual method + } + + //before_field_value(field_value); + generate_from_model(m); + //after_field_value(field_value); + is_first = false; + } + } + + if( out_stream ) + { + (*out_stream) << "]";// make a virtual method + } + } virtual void before_field_name(); virtual void after_field_name(); @@ -178,6 +240,9 @@ protected: virtual void before_field_value(const char *); virtual void after_field_value(const char *); + virtual void before_field_value(const PT::Date &); + virtual void after_field_value(const PT::Date &); + template void before_field_value(const FieldValue &) diff --git a/src/dbconnector.cpp b/src/dbconnector.cpp index be0cf75..bdc8c1a 100644 --- a/src/dbconnector.cpp +++ b/src/dbconnector.cpp @@ -32,8 +32,10 @@ * */ +#include #include "dbconnector.h" #include "model.h" +#include "utf8/utf8.h" namespace morm @@ -45,6 +47,12 @@ DbConnector::DbConnector() expression_allocated = false; } +DbConnector::DbConnector(const DbConnector &) +{ + db_expression = nullptr; + expression_allocated = false; +} + DbConnector::~DbConnector() { @@ -100,13 +108,27 @@ bool DbConnector::query_insert(const PT::TextStream & stream) return false; } - -virtual void DbConnector::map_values_from_query(Model & model) +size_t DbConnector::last_select_size() { - model.clear(); + return 0; } +void DbConnector::set_current_row_at_beginning() +{ +} + +void DbConnector::advance_current_row() +{ +} + + +//void DbConnector::map_values_from_query(Model & model) +//{ +// model.clear(); +//} + + DbExpression * DbConnector::get_expression() { allocate_default_expression_if_needed(); @@ -159,15 +181,12 @@ void DbConnector::generate_update_query(PT::TextStream & stream, Model & model) stream << "update "; model.table_name(stream); - stream << " set ("; - db_expression->set_work_mode(MORM_WORK_MODE_MODEL_FIELDS); + stream << " set "; + + db_expression->set_work_mode(MORM_WORK_MODE_MODEL_FIELDS_VALUES); db_expression->generate_from_model(stream, model); - stream << ") values ("; - db_expression->set_work_mode(MORM_WORK_MODE_MODEL_VALUES); - db_expression->generate_from_model(stream, model); - - stream << ") where "; + stream << " where "; db_expression->set_work_mode(MORM_WORK_MODE_MODEL_FIELDS_VALUES); db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_PRIMARY_KEY); db_expression->generate_from_model(stream, model); @@ -176,21 +195,17 @@ void DbConnector::generate_update_query(PT::TextStream & stream, Model & model) -void DbConnector::insert(PT::TextStream & stream, Model & model) +bool DbConnector::insert(PT::TextStream & stream, Model & model) { generate_insert_query(stream, model); - // do the real inserting - // query(stream); - // and get autogenerated columns + return query_insert(stream); } -void DbConnector::update(PT::TextStream & stream, Model & model) +bool DbConnector::update(PT::TextStream & stream, Model & model) { generate_update_query(stream, model); - // do the real updating - // query(stream); - // and get autogenerated columns + return query_update(stream); } @@ -214,7 +229,235 @@ void DbConnector::allocate_default_expression_if_needed() } } +const char * DbConnector::get_field_string_value(const wchar_t * field_name) +{ + return nullptr; +} +void DbConnector::clear_value(char & field_value) +{ + field_value = 0; +} + +void DbConnector::clear_value(unsigned char & field_value) +{ + field_value = 0; +} + +void DbConnector::clear_value(std::wstring & field_value) +{ + field_value.clear(); +} + +void DbConnector::clear_value(std::string & field_value) +{ + field_value.clear(); +} + +void DbConnector::clear_value(bool & field_value) +{ + field_value = false; +} + +void DbConnector::clear_value(short & field_value) +{ + field_value = 0; +} + +void DbConnector::clear_value(unsigned short & field_value) +{ + field_value = 0; +} + +void DbConnector::clear_value(int & field_value) +{ + field_value = 0; +} + +void DbConnector::clear_value(unsigned int & field_value) +{ + field_value = 0; +} + +void DbConnector::clear_value(long & field_value) +{ + field_value = 0; +} + +void DbConnector::clear_value(unsigned long & field_value) +{ + field_value = 0; +} + +void DbConnector::clear_value(long long & field_value) +{ + field_value = 0; +} + +void DbConnector::clear_value(unsigned long long & field_value) +{ + field_value = 0; +} + +void DbConnector::clear_value(float & field_value) +{ + field_value = 0.0f; +} + +void DbConnector::clear_value(double & field_value) +{ + field_value = 0.0; +} + +void DbConnector::clear_value(long double & field_value) +{ + field_value = 0.0; +} + +void DbConnector::clear_value(PT::Date & field_value) +{ + field_value.Clear(); +} + + + + +void DbConnector::get_value(const char * value_str, char & field_value) +{ + field_value = *value_str; + value_str += 1; + + if( *value_str != 0 ) + { + // value has more than one charater, put some error? + } +} + + +void DbConnector::get_value(const char * value_str, unsigned char & field_value) +{ + field_value = *(const unsigned char*)value_str; + value_str += 1; + + if( *value_str != 0 ) + { + // value has more than one charater, put some error? + } +} + + +void DbConnector::get_value(const char * value_str, std::wstring & field_value) +{ + // CHECKME + // what about \0 in val_str? + // it is escaped somehow? + PT::UTF8ToWide(value_str, field_value); +} + + +void DbConnector::get_value(const char * value_str, std::string & field_value) +{ + field_value = value_str; +} + + +void DbConnector::get_value(const char * value_str, bool & field_value) +{ + // IMPROVE ME + // this 't' is locale dependent + field_value = (value_str[0]=='t' || value_str[0]=='y' || value_str[0]=='1'); +} + + +void DbConnector::get_value(const char * value_str, short & field_value) +{ + // IMPROVE ME give some overflow checking + field_value = (short)PT::Toi(value_str, 10); +} + + +void DbConnector::get_value(const char * value_str, unsigned short & field_value) +{ + // IMPROVE ME give some overflow checking + field_value = (unsigned short)PT::Toui(value_str, 10); +} + + +void DbConnector::get_value(const char * value_str, int & field_value) +{ + // IMPROVE ME give some overflow checking + field_value = PT::Toi(value_str, 10); +} + + +void DbConnector::get_value(const char * value_str, unsigned int & field_value) +{ + // IMPROVE ME give some overflow checking + field_value = PT::Toui(value_str, 10); +} + + +void DbConnector::get_value(const char * value_str, long & field_value) +{ + // IMPROVE ME give some overflow checking + field_value = PT::Tol(value_str, 10); +} + + +void DbConnector::get_value(const char * value_str, unsigned long & field_value) +{ + // IMPROVE ME give some overflow checking + field_value = PT::Toul(value_str, 10); +} + + +void DbConnector::get_value(const char * value_str, long long & field_value) +{ + // IMPROVE ME give some overflow checking + field_value = PT::Toll(value_str, 10); +} + + +void DbConnector::get_value(const char * value_str, unsigned long long & field_value) +{ + // IMPROVE ME give some overflow checking + field_value = PT::Toull(value_str, 10); +} + + +void DbConnector::get_value(const char * value_str, float & field_value) +{ + // IMPROVE ME give some overflow checking + field_value = strtof(value_str, 0); +} + + +void DbConnector::get_value(const char * value_str, double & field_value) +{ + // IMPROVE ME give some overflow checking + field_value = strtod(value_str, 0); +} + + +void DbConnector::get_value(const char * value_str, long double & field_value) +{ + // IMPROVE ME give some overflow checking + field_value = strtold(value_str, 0); +} + + +void DbConnector::get_value(const char * value_str, PT::Date & field_value) +{ + // IMPROVE ME give some log if parsing failed + bool res = field_value.Parse(value_str); +} + + +const char * DbConnector::query_last_sequence(const wchar_t * sequence_table_name) +{ + return nullptr; +} + } diff --git a/src/dbconnector.h b/src/dbconnector.h index a95e2de..082a10c 100644 --- a/src/dbconnector.h +++ b/src/dbconnector.h @@ -50,6 +50,7 @@ class DbConnector public: DbConnector(); + DbConnector(const DbConnector &); virtual ~DbConnector(); DbExpression * get_expression(); @@ -58,8 +59,11 @@ public: virtual void generate_insert_query(PT::TextStream & stream, Model & model); virtual void generate_update_query(PT::TextStream & stream, Model & model); - virtual void insert(PT::TextStream & stream, Model & model); - virtual void update(PT::TextStream & stream, Model & model); + virtual bool insert(PT::TextStream & stream, Model & model); + virtual bool update(PT::TextStream & stream, Model & model); + + //void ModelConnector::get_values_from_db(Model & model) + virtual bool query(const PT::TextStream & stream); //virtual bool query(const std::wstring & query); @@ -71,7 +75,76 @@ public: virtual bool query_update(const PT::TextStream & stream); virtual bool query_insert(const PT::TextStream & stream); - virtual void map_values_from_query(Model & model); + virtual size_t last_select_size(); + + // give me a better name + virtual void set_current_row_at_beginning(); + virtual void advance_current_row(); + + //virtual void map_values_from_query(Model & model); + + // these methods should be somewhere else + // flat_parsers (json parser) can use them as well + virtual void clear_value(char & field_value); + virtual void clear_value(unsigned char & field_value); + virtual void clear_value(std::wstring & field_value); + virtual void clear_value(std::string & field_value); + virtual void clear_value(bool & field_value); + virtual void clear_value(short & field_value); + virtual void clear_value(unsigned short & field_value); + virtual void clear_value(int & field_value); + virtual void clear_value(unsigned int & field_value); + virtual void clear_value(long & field_value); + virtual void clear_value(unsigned long & field_value); + virtual void clear_value(long long & field_value); + virtual void clear_value(unsigned long long & field_value); + virtual void clear_value(float & field_value); + virtual void clear_value(double & field_value); + virtual void clear_value(long double & field_value); + virtual void clear_value(PT::Date & field_value); + + + virtual void get_value(const char * value_str, char & field_value); + virtual void get_value(const char * value_str, unsigned char & field_value); + virtual void get_value(const char * value_str, std::wstring & field_value); + virtual void get_value(const char * value_str, std::string & field_value); + virtual void get_value(const char * value_str, bool & field_value); + virtual void get_value(const char * value_str, short & field_value); + virtual void get_value(const char * value_str, unsigned short & field_value); + virtual void get_value(const char * value_str, int & field_value); + virtual void get_value(const char * value_str, unsigned int & field_value); + virtual void get_value(const char * value_str, long & field_value); + virtual void get_value(const char * value_str, unsigned long & field_value); + virtual void get_value(const char * value_str, long long & field_value); + virtual void get_value(const char * value_str, unsigned long long & field_value); + virtual void get_value(const char * value_str, float & field_value); + virtual void get_value(const char * value_str, double & field_value); + virtual void get_value(const char * value_str, long double & field_value); + virtual void get_value(const char * value_str, PT::Date & field_value); + //virtual void get_value(const char * value_str, void* & field_value); + + + template + void get_value_by_field_name(const wchar_t * field_name, FieldValue & field_value) + { + const char * val_str = get_field_string_value(field_name); + + if( val_str ) + { + get_value(val_str, field_value); + } + } + + template + void get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value) + { + const char * val_str = query_last_sequence(sequence_table_name); + + if( val_str ) + { + get_value(val_str, field_value); + } + } protected: @@ -82,6 +155,12 @@ protected: virtual void allocate_default_expression() = 0; virtual void allocate_default_expression_if_needed(); virtual void deallocate_expression(); + virtual const char * get_field_string_value(const wchar_t * field_name); + + virtual const char * query_last_sequence(const wchar_t * sequence_table_name); + + + }; diff --git a/src/dbexpression.cpp b/src/dbexpression.cpp index c1e25ba..e62a199 100644 --- a/src/dbexpression.cpp +++ b/src/dbexpression.cpp @@ -127,7 +127,8 @@ void DbExpression::field_before() void DbExpression::put_name_value_separator() { if( output_type == MORM_OUTPUT_TYPE_DB_PRIMARY_KEY || - output_type == MORM_OUTPUT_TYPE_WHERE_EQ ) + output_type == MORM_OUTPUT_TYPE_WHERE_EQ || + output_type == MORM_OUTPUT_TYPE_DB_UPDATE) { (*out_stream) << " = "; } @@ -218,6 +219,16 @@ void DbExpression::after_field_value(const char *) after_field_value_string(); } +void DbExpression::before_field_value(const PT::Date &) +{ + before_field_value_string(); +} + +void DbExpression::after_field_value(const PT::Date &) +{ + after_field_value_string(); +} + void DbExpression::prepare_to_where_clause() { diff --git a/src/dbexpression.h b/src/dbexpression.h index cd058ae..2e10766 100644 --- a/src/dbexpression.h +++ b/src/dbexpression.h @@ -83,6 +83,8 @@ protected: void before_field_value(const char *); void after_field_value(const char *); + void before_field_value(const PT::Date &); + void after_field_value(const PT::Date &); void put_name_value_separator(); diff --git a/src/finder.h b/src/finder.h index 7721051..a91b463 100644 --- a/src/finder.h +++ b/src/finder.h @@ -263,8 +263,51 @@ public: } - void get_list(std::list & result, bool clear_list = true) + bool get(ModelClass & result) { + bool res = false; + result.clear(); + result.set_object_exists(false); + + if( model_connector && out_stream ) + { + DbConnector * db_connector = model_connector->get_db_connector(); + + if( db_connector ) + { + res = db_connector->query_select(*out_stream); + + if( res ) + { + result.set_object_exists(true); + result.set_connector(*model_connector); + result.before_select(); + model_connector->map_values_from_query(result); + result.after_select(); + } + + if( !res ) + { + // put some log here? + } + } + } + + return res; + } + + + ModelClass get() + { + get(model); + return model; + } + + + bool get_list(std::list & result, bool clear_list = true) + { + bool res = false; + if( clear_list ) { result.clear(); @@ -276,31 +319,40 @@ public: if( db_connector ) { - bool res = db_connector->query_select(*out_stream); + res = db_connector->query_select(*out_stream); if( res ) { - //ModelClass model; - //db_connector->map_values_from_query(model); + size_t len = db_connector->last_select_size(); + db_connector->set_current_row_at_beginning(); + for(size_t i = 0 ; i < len ; ++i) + { + model.clear(); + model.set_object_exists(true); + model.set_connector(*model_connector); + model.before_select(); + model_connector->map_values_from_query(model); + model.after_select(); + result.push_back(model); + db_connector->advance_current_row(); + } } if( !res ) { // put some log here? } - - - - } } + + return res; } std::list get_list() { std::list result; - get_list(result); + get_list(result, false); return result; } diff --git a/src/jsonexpression.cpp b/src/jsonexpression.cpp index c4344a8..6987460 100644 --- a/src/jsonexpression.cpp +++ b/src/jsonexpression.cpp @@ -119,6 +119,17 @@ void JSONExpression::after_field_value(const std::string &) after_field_value_string(); } +void JSONExpression::before_field_value(const PT::Date &) +{ + before_field_value_string(); +} + +void JSONExpression::after_field_value(const PT::Date &) +{ + after_field_value_string(); +} + + void JSONExpression::put_name_value_separator() { diff --git a/src/jsonexpression.h b/src/jsonexpression.h index 892c29e..abbdb24 100644 --- a/src/jsonexpression.h +++ b/src/jsonexpression.h @@ -61,6 +61,10 @@ protected: void after_field_value(const std::string &); void put_name_value_separator(); + void before_field_value(const PT::Date &); + void after_field_value(const PT::Date &); + + template void print_field_name_value(const wchar_t * field_name, const FieldValue & field_value) { diff --git a/src/model.cpp b/src/model.cpp index b3c3d5b..4351a98 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -146,8 +146,40 @@ void Model::update() void Model::clear() { + if( model_connector ) + { + model_connector->clear_values(*this); + } + morm_object_exists = false; } + +void Model::before_select() +{ +} + +void Model::before_insert() +{ +} + +void Model::before_update() +{ +} + +void Model::after_select() +{ +} + +void Model::after_insert() +{ +} + +void Model::after_update() +{ +} + + + } // namespace diff --git a/src/model.h b/src/model.h index 41e3b21..d37fdb1 100644 --- a/src/model.h +++ b/src/model.h @@ -89,6 +89,7 @@ public: // set object to default values virtual void clear(); + protected: ModelConnector * model_connector; @@ -97,9 +98,16 @@ protected: Model(); virtual ~Model(); + virtual void before_select(); + virtual void before_insert(); + virtual void before_update(); + + virtual void after_select(); + virtual void after_insert(); + virtual void after_update(); template - void field(const wchar_t * field_name, const FieldValue & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, FieldValue & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) { if( model_connector ) { @@ -107,9 +115,28 @@ protected: } } + template + void field_list(const wchar_t * field_name, std::list & field_list, bool insertable = true, bool updatable = true, bool is_primary_key = false) + { + if( model_connector ) + { + model_connector->field_list(field_name, field_list, insertable, updatable, is_primary_key); + } + } + + template + void get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value) + { + if( model_connector ) + { + model_connector->get_last_sequence(sequence_table_name, field_value); + } + } + //void field(const wchar_t * field_name, Model & field, bool insertable = true, bool updatable = true); - + template friend class Finder; + friend class ModelConnector; }; } // namespace diff --git a/src/modelconnector.cpp b/src/modelconnector.cpp index 95e7f94..32e34a1 100644 --- a/src/modelconnector.cpp +++ b/src/modelconnector.cpp @@ -43,9 +43,13 @@ namespace morm ModelConnector::ModelConnector() { + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; flat_connector = nullptr; db_connector = nullptr; - expression_callback = nullptr; + + + //expression_callback = nullptr; + //db_connector_callback = nullptr; out_stream = nullptr; out_stream_allocated = false; @@ -140,14 +144,16 @@ void ModelConnector::to_text(PT::TextStream & stream, Model & model) { if( flat_connector ) { - expression_callback = flat_connector->get_expression(); + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_EXPRESSION; + //expression_callback = flat_connector->get_expression(); - if( expression_callback ) - { + //if( expression_callback ) + //{ flat_connector->to_text(stream, model); - } + //} - expression_callback = nullptr; + //expression_callback = nullptr; + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; } } @@ -156,14 +162,16 @@ void ModelConnector::generate_select_columns(PT::TextStream & stream, Model & mo { if( db_connector ) { - expression_callback = db_connector->get_expression(); + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION; + //expression_callback = db_connector->get_expression(); - if( expression_callback ) - { + //if( expression_callback ) + //{ db_connector->generate_select_columns(stream, model); - } + //} - expression_callback = nullptr; + //expression_callback = nullptr; + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; } } @@ -173,14 +181,16 @@ void ModelConnector::generate_insert_query(PT::TextStream & stream, Model & mode { if( db_connector ) { - expression_callback = db_connector->get_expression(); + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION; + //expression_callback = db_connector->get_expression(); - if( expression_callback ) - { + //if( expression_callback ) + //{ db_connector->generate_insert_query(stream, model); - } + //} - expression_callback = nullptr; + //expression_callback = nullptr; + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; } } @@ -189,14 +199,16 @@ void ModelConnector::generate_update_query(PT::TextStream & stream, Model & mode { if( db_connector ) { - expression_callback = db_connector->get_expression(); + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION; + //expression_callback = db_connector->get_expression(); - if( expression_callback ) - { + //if( expression_callback ) + //{ db_connector->generate_update_query(stream, model); - } + //} - expression_callback = nullptr; + //expression_callback = nullptr; + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; } } @@ -207,8 +219,16 @@ void ModelConnector::insert(Model & model) if( db_connector && out_stream ) { + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION; + //db_connector_callback = db_connector; + + model.before_insert(); out_stream->clear(); db_connector->insert(*out_stream, model); + model.after_insert(); + + //db_connector_callback = nullptr; + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; } } @@ -219,11 +239,44 @@ void ModelConnector::update(Model & model) if( db_connector && out_stream ) { + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION; + //db_connector_callback = db_connector; + + model.before_update(); out_stream->clear(); db_connector->update(*out_stream, model); + model.after_update(); + + //db_connector_callback = nullptr; + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; } } +void ModelConnector::map_values_from_query(Model & model) +{ + if( db_connector ) + { + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB; + //db_connector_callback = db_connector; + model.map_fields(); + //db_connector_callback = nullptr; + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; + } +} + + +void ModelConnector::clear_values(Model & model) +{ + if( db_connector ) + { + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE; + model.map_fields(); + model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE; + } + +} + + } diff --git a/src/modelconnector.h b/src/modelconnector.h index cfb063b..8b2218c 100644 --- a/src/modelconnector.h +++ b/src/modelconnector.h @@ -36,14 +36,15 @@ #define headerfile_morm_modelconnector #include "baseexpression.h" -//#include "finder.h" +#include "dbconnector.h" +#include "flatexpression.h" +#include "flatconnector.h" namespace morm { class Model; -class FlatConnector; -class DbConnector; + template class Finder; @@ -81,6 +82,10 @@ public: virtual void insert(Model & model); virtual void update(Model & model); + virtual void map_values_from_query(Model & model); + + virtual void clear_values(Model & model); + // template // Finder & find() @@ -92,13 +97,16 @@ public: protected: + int model_connector_mode; + FlatConnector * flat_connector; DbConnector * db_connector; PT::TextStream * out_stream; // IMPROVE ME give here an interface to the base stream (implement him) bool out_stream_allocated; - BaseExpression * expression_callback; + //BaseExpression * expression_callback; + //DbConnector * db_connector_callback; void allocate_default_stream(); void allocate_default_stream_if_needed(); @@ -108,12 +116,75 @@ protected: template void field(const wchar_t * field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key) { - if( expression_callback ) + // may we need only db_connector_callback? + +// if( expression_callback ) +// { +// expression_callback->field(field_name, field_value, insertable, updatable, is_primary_key); +// } + +// if( db_connector_callback ) +// { +// db_connector_callback->get_value_by_field_name(field_name, field_value); +// } + + if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_EXPRESSION && flat_connector ) { - expression_callback->field(field_name, field_value, insertable, updatable, is_primary_key); + FlatExpression * flat_expression = flat_connector->get_expression(); + + if( flat_expression ) + { + flat_expression->field(field_name, field_value, insertable, updatable, is_primary_key); + } + } + + if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION && db_connector ) + { + DbExpression * db_expression = db_connector->get_expression(); + + if( db_expression ) + { + db_expression->field(field_name, field_value, insertable, updatable, is_primary_key); + } + } + + if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB && db_connector ) + { + db_connector->get_value_by_field_name(field_name, field_value); + } + + if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE && db_connector ) + { + // IMPROVE ME those clearing should be moved to a better place + db_connector->clear_value(field_value); } } + template + void field_list(const wchar_t * field_name, std::list & field_list, bool insertable = true, bool updatable = true, bool is_primary_key = false) + { + if( model_connector_mode == MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_EXPRESSION && flat_connector && out_stream ) + { + FlatExpression * flat_expression = flat_connector->get_expression(); + + if( flat_expression ) + { + flat_expression->field_list(field_name, field_list, insertable, updatable, is_primary_key); + } + } + } + + + template + void get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value) + { + if( db_connector ) + { + db_connector->get_last_sequence(sequence_table_name, field_value); + } + } + + /* * Model is using field() method */ diff --git a/src/morm_types.h b/src/morm_types.h index 03fffd4..14e4ee6 100644 --- a/src/morm_types.h +++ b/src/morm_types.h @@ -35,13 +35,23 @@ #ifndef headerfile_morm_morm_types #define headerfile_morm_morm_types +#define MORM_MODEL_CONNECTOR_MODE_NONE 0 +#define MORM_MODEL_CONNECTOR_MODE_GENERATING_FLAT_EXPRESSION 1 +#define MORM_MODEL_CONNECTOR_MODE_GENERATING_DB_EXPRESSION 2 + +// not used at the moment, there are not any flat parsers (json parser) +#define MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_FLAT 3 + +#define MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB 4 +#define MORM_MODEL_CONNECTOR_MODE_CLEARING_VALUE 5 + #define MORM_WORK_MODE_MODEL_FIELDS 1 #define MORM_WORK_MODE_MODEL_VALUES 2 #define MORM_WORK_MODE_MODEL_FIELDS_VALUES 3 // IMPROVE ME give me a better name -#define MORM_WORK_MODE_MODEL_SELECT_FROM_DB 3 +//#define MORM_WORK_MODE_MODEL_SELECT_FROM_DB 4 //#define MORM_OUTPUT_TYPE_JSON 1 #define MORM_OUTPUT_TYPE_DB_INSERT 2 diff --git a/src/postgresqlconnector.cpp b/src/postgresqlconnector.cpp index 5f64392..0bdc521 100644 --- a/src/postgresqlconnector.cpp +++ b/src/postgresqlconnector.cpp @@ -38,6 +38,7 @@ #include "postgresqlconnector.h" #include "utf8/utf8.h" #include "postgresqlexpression.h" +#include "convert/strtoint.h" namespace morm @@ -49,6 +50,8 @@ PostgreSQLConnector::PostgreSQLConnector() log_queries = false; last_status = PGRES_EMPTY_QUERY; last_result = nullptr; + last_result_rows = 0; + cur_row = 0; } PostgreSQLConnector::~PostgreSQLConnector() @@ -77,6 +80,7 @@ bool PostgreSQLConnector::query(const char * query_str) // log << log1 << "Db: executing query: " << q << logend; last_status = PGRES_EMPTY_QUERY; // or something else? + last_result_rows = 0; last_result = PQexec(pg_conn, query_str); if( !last_result ) @@ -91,6 +95,7 @@ bool PostgreSQLConnector::query(const char * query_str) if( last_result ) { last_status = PQresultStatus(last_result); + last_result_rows = static_cast(PQntuples(last_result)); } else { @@ -102,6 +107,36 @@ return last_result != nullptr; } + +const char * PostgreSQLConnector::query_last_sequence(const wchar_t * sequence_table_name) +{ + allocate_default_expression_if_needed(); + + if( db_expression ) + { + stream.clear(); + stream << "select currval(E'"; + db_expression->esc(sequence_table_name, stream); + stream << "');"; + + if( query_select(stream) ) + { + if( last_result_rows == 1 ) + { + return get_value(0, 0); + } + else + { + //log << log1 << "Db: error (currval) for table: " << table << ", " << PQerrorMessage(db_conn->GetPgConn()) << logend; + } + } + } + + return nullptr; +} + + + bool PostgreSQLConnector::query(const PT::TextStream & stream) { stream.to_string(query_str); @@ -152,219 +187,18 @@ bool PostgreSQLConnector::query_insert(const PT::TextStream & stream) -//Error PostgreSQLConnector::DoCommand(const char * command) -//{ -// PGresult * r = 0; -// Error status = WINIX_ERR_OK; -// -// try -// { -// r = AssertQuery(command); -// AssertResult(r, PGRES_COMMAND_OK); -// } -// catch(const Error & e) -// { -// status = e; -// } -// -// ClearResult(r); -// -//return status; -//} - - - bool PostgreSQLConnector::is_last_result(ExecStatusType t) { return (last_result && PQresultStatus(last_result) == t); } - -void PostgreSQLConnector::map_values_from_query(Model & model) +// to nie tylko dla selectow moze byc uzywane +size_t PostgreSQLConnector::last_select_size() { - if( db_expression ) - { - db_expression->set_work_mode(MORM_WORK_MODE_MODEL_SELECT_FROM_DB); - //db_expression->set_output_type() - - - - - - - - - } + return last_result_rows; } - - - - - -int PostgreSQLConnector::get_column_index(const char * column_name) -{ - int c = PQfnumber(last_result, column_name); - // returns -1 if there is no such a column - -return c; -} - - - -const char * PostgreSQLConnector::get_value(int row, int col) -{ - const char * res = PQgetvalue(last_result, row, col); - // can return a null pointer if there is no such an item in the last result - -return res; -} - - -bool PostgreSQLConnector::get_value(int row, int col, std::string & result, bool clear_string) -{ - if( clear_string ) - result.clear(); - - const char * raw_result = get_value(row, col); - - if( raw_result ) - { - result += raw_result; - } - - return raw_result != nullptr; -} - - -bool PostgreSQLConnector::get_value(int row, int col, std::wstring & result, bool clear_string) -{ - if( clear_string ) - result.clear(); - - const char * raw_result = get_value(row, col); - - if( raw_result ) - { - PT::UTF8ToWide(raw_result, result); - } - - return raw_result != nullptr; -} - - - -//void PostgreSQLConnector::get_value_bin(int row, int col, std::string & result, bool clear_string) -//{ -// if( clear_string ) -// result.clear(); -// -// const char * raw_result = get_value(row, col); -// -// if( raw_result ) -// { -// int len = PQgetlength(last_result, row, col); -// -// if( len > 0 ) -// { -// unescape_bin(raw_result, len, result); -// } -// } -//} - - - -//long PostgreSQLConnector::AssertValueLong(PGresult * r, int row, int col) -//{ -// return strtol( AssertValue(r, row, col), 0, 10 ); -//} -// -// -//int PostgreSQLConnector::AssertValueInt(PGresult * r, int row, int col) -//{ -// return (int)strtol( AssertValue(r, row, col), 0, 10 ); -//} -// -// -//bool PostgreSQLConnector::AssertValueBool(PGresult * r, int row, int col) -//{ -// const char * s = AssertValue(r, row, col); -// return (s[0]=='t' || s[0]=='y' || s[0]=='1'); -//} -// -// -//unsigned long PostgreSQLConnector::AssertValueULong(PGresult * r, int row, int col) -//{ -// return strtoul( AssertValue(r, row, col), 0, 10 ); -//} -// -// -//unsigned int PostgreSQLConnector::AssertValueUInt(PGresult * r, int row, int col) -//{ -// return (unsigned int)strtoul( AssertValue(r, row, col), 0, 10 ); -//} -// -// -// -//PT::Date PostgreSQLConnector::AssertValueDate(PGresult * r, int row, int col) -//{ -// PT::Date date = AssertValue(r, row, col); -// -//return date; -//} -// -// -//bool PostgreSQLConnector::AssertValueSpace(PGresult * r, int row, int col, PT::Space & space) -//{ -// const char * res = AssertValue(r, row, col); -// -// conf_parser.SetSpace(space); -// space.Clear(); -// -// PT::SpaceParser::Status status = conf_parser.ParseString(res); -// -// if( status != PT::SpaceParser::ok ) -// { -// log << log1 << "Db: a problem with parsing a PT::Space"; -// -// if( status == PT::SpaceParser::syntax_error ) -// log << ", syntax error at line: " << conf_parser.line; -// -// log << logend; -// -// space.Clear(); -// return false; -// } -// -//return true; -//} -// -// - - - -void PostgreSQLConnector::clear_result() -{ - if( last_result ) - { - PQclear(last_result); - last_result = nullptr; - } -} - - -bool PostgreSQLConnector::is_null(int row, int col) -{ - if( last_result ) - { - return PQgetisnull(last_result, row, col) == 1; - } - - return true; -} - - //int PostgreSQLConnector::Rows(PGresult * r) //{ // // PQntuples - Returns the number of rows (tuples) in the query result. Because it returns @@ -379,7 +213,6 @@ bool PostgreSQLConnector::is_null(int row, int col) // return PQnfields(r); //} - //long PostgreSQLConnector::AffectedRows(PGresult * r) //{ // // PQcmdTuples - This function returns a string containing the number of rows affected by the SQL @@ -404,27 +237,126 @@ bool PostgreSQLConnector::is_null(int row, int col) //} -//long PostgreSQLConnector::AssertCurrval(const char * table) + + +void PostgreSQLConnector::set_current_row_at_beginning() +{ + cur_row = 0; +} + + +void PostgreSQLConnector::advance_current_row() +{ + cur_row += 1; +} + + + +int PostgreSQLConnector::get_column_index(const char * column_name) +{ + int c = PQfnumber(last_result, column_name); + // returns -1 if there is no such a column + +return c; +} + + +int PostgreSQLConnector::get_column_index(const wchar_t * column_name) +{ + // temporary + std::string s; // move me somewhere? + PT::WideToUTF8(column_name, s); + return get_column_index(s.c_str()); +} + + +const char * PostgreSQLConnector::get_value(int row, int col) +{ + const char * res = PQgetvalue(last_result, row, col); + // can return a null pointer if there is no such an item in the last result + +return res; +} + + +int PostgreSQLConnector::get_value_length(int row, int col) +{ + int len = PQgetlength(last_result, row, col); + return len; +} + + + +//void PostgreSQLConnector::get_value_bin(int row, int col, std::string & result, bool clear_string) //{ -// PGresult * r; +// if( clear_string ) +// result.clear(); // -// bquery.Clear(); -// bquery << R("select currval(") -// << table -// << R(");"); +// const char * raw_result = get_value(row, col); // -// r = AssertQuery(bquery); -// AssertResult(r, PGRES_TUPLES_OK); -// -// if( Rows(r) != 1 ) +// if( raw_result ) // { -// log << log1 << "Db: error (currval) for table: " << table << ", " << PQerrorMessage(db_conn->GetPgConn()) << logend; -// throw Error(WINIX_ERR_DB_ERR_CURRVAL); +// int len = PQgetlength(last_result, row, col); +// +// if( len > 0 ) +// { +// unescape_bin(raw_result, len, result); +// } +// } +//} + + +//bool PostgreSQLConnector::AssertValueSpace(PGresult * r, int row, int col, PT::Space & space) +//{ +// const char * res = AssertValue(r, row, col); +// +// conf_parser.SetSpace(space); +// space.Clear(); +// +// PT::SpaceParser::Status status = conf_parser.ParseString(res); +// +// if( status != PT::SpaceParser::ok ) +// { +// log << log1 << "Db: a problem with parsing a PT::Space"; +// +// if( status == PT::SpaceParser::syntax_error ) +// log << ", syntax error at line: " << conf_parser.line; +// +// log << logend; +// +// space.Clear(); +// return false; // } // -//return AssertValueLong(r, 0, 0); +//return true; //} -// + + + +void PostgreSQLConnector::clear_result() +{ + if( last_result ) + { + PQclear(last_result); + last_result = nullptr; + last_result_rows = 0; + } +} + + +bool PostgreSQLConnector::is_null(int row, int col) +{ + if( last_result ) + { + return PQgetisnull(last_result, row, col) == 1; + } + + return true; +} + + + + @@ -665,23 +597,27 @@ void PostgreSQLConnector::connect() { close(); - stream.clear(); - stream << "dbname='"; - db_expression->esc(db_database, stream); + allocate_default_expression_if_needed(); - stream << "' user='"; - db_expression->esc(db_user, stream); + if( db_expression ) + { + stream.clear(); + stream << "dbname='"; + db_expression->esc(db_database, stream); - stream << "' password='"; - db_expression->esc(db_pass, stream); - stream << "'"; + stream << "' user='"; + db_expression->esc(db_user, stream); - std::string str; - stream.to_string(str); - pg_conn = PQconnectdb(str.c_str()); + stream << "' password='"; + db_expression->esc(db_pass, stream); + stream << "'"; - overwrite(stream); + std::string str; + stream.to_string(str); + pg_conn = PQconnectdb(str.c_str()); + overwrite(stream); + } // warning! pg_conn can be not null but there cannnot be a connection established // use PQstatus(pg_conn) to check whether the connection works fine } @@ -692,13 +628,13 @@ void PostgreSQLConnector::connect() void PostgreSQLConnector::log_connection_socket() { - //log << log2 << "Db: connection to the database works fine" << logend; - //log << log3 << "Db: connection socket: " << PQsocket(pg_conn) << logend; - if( pg_conn ) { - std::cout << "Db: connection to the database works fine" << std::endl; - std::cout << "Db: connection socket: " << PQsocket(pg_conn) << std::endl; + //log << log2 << "Db: connection to the database works fine" << logend; + //log << log3 << "Db: connection socket: " << PQsocket(pg_conn) << logend; + + //std::cout << "Db: connection to the database works fine" << std::endl; + //std::cout << "Db: connection socket: " << PQsocket(pg_conn) << std::endl; } } @@ -707,7 +643,7 @@ void PostgreSQLConnector::wait_for_connection() if( !pg_conn || PQstatus(pg_conn) != CONNECTION_OK ) { //log << log3 << "Db: waiting for the db to be ready...." << logend << logsave; - std::cout << "Db: waiting for the db to be ready...." << std::endl; + //std::cout << "Db: waiting for the db to be ready...." << std::endl; while( !assert_connection(false, false) ) { @@ -726,6 +662,8 @@ void PostgreSQLConnector::close() { PQfinish(pg_conn); pg_conn = nullptr; + last_result = nullptr; + last_result_rows = 0; } } @@ -746,7 +684,7 @@ bool was_connection = true; if( put_log ) { //log << log2 << "Db: connection to the database is lost, trying to recover" << logend; - std::cout << "Db: connection to the database is lost, trying to recover" << std::endl; + //std::cout << "Db: connection to the database is lost, trying to recover" << std::endl; } was_connection = false; @@ -771,7 +709,7 @@ bool was_connection = true; if( put_log ) { //log << log1 << "Db: connection to db server cannot be established" << logend; - std::cout << "Db: connection to db server cannot be established" << std::endl; + //std::cout << "Db: connection to db server cannot be established" << std::endl; } if( throw_if_no_connection ) @@ -789,9 +727,28 @@ void PostgreSQLConnector::set_db_parameters() if( PQsetClientEncoding(pg_conn, "UTF8") == -1 ) { //log << log1 << "Db: Can't set the proper client encoding" << logend; - std::cout << "Db: Can't set the proper client encoding" << std::endl; + //std::cout << "Db: Can't set the proper client encoding" << std::endl; } } +const char * PostgreSQLConnector::get_field_string_value(const wchar_t * field_name) +{ + int c = get_column_index(field_name); + + if( c != -1 ) + { + if( cur_row < last_result_rows ) + { + return get_value(cur_row, c); + } + } + + return nullptr; +} + + + + + } diff --git a/src/postgresqlconnector.h b/src/postgresqlconnector.h index 856fb6b..b15d244 100644 --- a/src/postgresqlconnector.h +++ b/src/postgresqlconnector.h @@ -64,7 +64,12 @@ public: bool query_update(const PT::TextStream & stream); bool query_insert(const PT::TextStream & stream); - void map_values_from_query(Model & model); + // give me a better name + virtual size_t last_select_size(); + + // give me a better name + virtual void set_current_row_at_beginning(); + virtual void advance_current_row(); bool is_last_result(ExecStatusType t); @@ -75,6 +80,7 @@ public: * */ int get_column_index(const char * column_name); + int get_column_index(const wchar_t * column_name); bool is_null(int row, int col); @@ -84,10 +90,8 @@ public: * */ const char * get_value(int row, int col); + int get_value_length(int row, int col); - bool get_value(int row, int col, std::string & result, bool clear_string = true); - bool get_value(int row, int col, std::wstring & result, bool clear_string = true); - void get_value_bin(int row, int col, std::string & result, bool clear_string = true); void clear_result(); @@ -106,10 +110,12 @@ protected: PGconn * pg_conn; PGresult * last_result; // can be null + size_t last_result_rows; // how many rows in the last result query ExecStatusType last_status; bool log_queries; PT::TextStream stream; std::string query_str; + size_t cur_row; std::wstring db_database; std::wstring db_user; @@ -119,6 +125,9 @@ protected: void allocate_default_expression(); void overwrite(PT::TextStream & stream); + virtual const char * get_field_string_value(const wchar_t * field_name); + + const char * query_last_sequence(const wchar_t * sequence_table_name); }; }