diff --git a/.gitignore b/.gitignore index 2da86a3..6bbc54f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ .settings/ *.o *.a +log.txt +samples/log.txt +samples/mormsample diff --git a/samples/Makefile b/samples/Makefile index 0a3dd00..fdbcbd1 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -7,13 +7,13 @@ GLOBAL_WORKING_DIR := $(shell pwd)/../.. endif -CXX = g++7 +CXX = g++10 #CXX = clang++ # -fsanitize=address # -Wl,-rpath=/usr/local/lib/gcc5 or just compile with -static-libstdc++ -CXXFLAGS = -Wl,-rpath=/usr/local/lib/gcc7 -Wfatal-errors -fPIC -Wall -pedantic -O0 -g3 -gdwarf-2 -pthread -std=c++17 -I/usr/local/include -I$(GLOBAL_WORKING_DIR)/pikotools -I$(GLOBAL_WORKING_DIR)/morm/src +CXXFLAGS = -Wl,-rpath=/usr/local/lib/gcc10 -Wfatal-errors -fPIC -Wall -pedantic -O0 -g3 -gdwarf-2 -pthread -std=c++20 -I/usr/local/include -I$(GLOBAL_WORKING_DIR)/pikotools -I$(GLOBAL_WORKING_DIR)/morm/src LDFLAGS = -L/usr/local/lib @@ -27,11 +27,12 @@ current_path := $(shell pwd) global_relative_working_dir := $(shell relative_path $(current_path) $(GLOBAL_WORKING_DIR)) - +# IMPROVE ME +# add dependency to pikotools all: morm $(name) -$(name): $(o) +$(name): morm $(o) $(CXX) -o $(name) $(CXXFLAGS) $(LDFLAGS) $(o) $(GLOBAL_WORKING_DIR)/morm/src/morm.a $(GLOBAL_WORKING_DIR)/pikotools/log/log.a $(GLOBAL_WORKING_DIR)/pikotools/space/space.a $(GLOBAL_WORKING_DIR)/pikotools/mainspaceparser/mainspaceparser.a $(GLOBAL_WORKING_DIR)/pikotools/date/date.a $(GLOBAL_WORKING_DIR)/pikotools/convert/convert.a $(GLOBAL_WORKING_DIR)/pikotools/utf8/utf8.a $(LDFLAGS) -lpq -lpthread diff --git a/samples/Makefile.dep b/samples/Makefile.dep index 2150a94..dfcdfb0 100644 --- a/samples/Makefile.dep +++ b/samples/Makefile.dep @@ -2,11 +2,10 @@ main.o: ../../pikotools/mainspaceparser/mainspaceparser.h main.o: ../../pikotools/space/space.h ../../pikotools/textstream/types.h -main.o: sample01.h basesample.h ../../morm/src/morm.h -main.o: ../../morm/src/morm_types.h ../../morm/src/model.h -main.o: ../../pikotools/textstream/textstream.h ../../pikotools/date/date.h -main.o: ../../pikotools/convert/inttostr.h -main.o: ../../pikotools/membuffer/membuffer.h +main.o: ../../pikotools/convert/inttostr.h sample01.h basesample.h +main.o: ../../morm/src/morm.h ../../morm/src/morm_types.h +main.o: ../../morm/src/model.h ../../pikotools/textstream/textstream.h +main.o: ../../pikotools/date/date.h ../../pikotools/membuffer/membuffer.h main.o: ../../pikotools/textstream/types.h ../../morm/src/modelconnector.h main.o: ../../morm/src/clearer.h ../../morm/src/dbconnector.h main.o: ../../pikotools/log/log.h ../../pikotools/log/filelog.h @@ -14,10 +13,11 @@ main.o: ../../morm/src/queryresult.h ../../morm/src/flatconnector.h main.o: ../../morm/src/dbexpression.h ../../morm/src/baseexpression.h main.o: ../../morm/src/modelenv.h ../../morm/src/modeldata.h main.o: ../../morm/src/cursorhelper.h ../../morm/src/finderhelper.h -main.o: ../../morm/src/fieldvaluehelper.h ../../morm/src/flatexpression.h -main.o: ../../morm/src/finder.h ../../pikotools/utf8/utf8.h -main.o: ../../morm/src/cursor.h ../../morm/src/jsonexpression.h -main.o: ../../morm/src/postgresqlexpression.h ../../morm/src/jsonconnector.h -main.o: ../../morm/src/postgresqlconnector.h +main.o: ../../morm/src/fieldvaluehelper.h ../../morm/src/ft.h +main.o: ../../morm/src/flatexpression.h ../../morm/src/finder.h +main.o: ../../pikotools/utf8/utf8.h ../../pikotools/utf8/utf8_templates.h +main.o: ../../pikotools/utf8/utf8_private.h ../../morm/src/cursor.h +main.o: ../../morm/src/jsonexpression.h ../../morm/src/postgresqlexpression.h +main.o: ../../morm/src/jsonconnector.h ../../morm/src/postgresqlconnector.h main.o: ../../morm/src/postgresqlqueryresult.h person.h language.h -main.o: attachment.h type.h +main.o: attachment.h type.h attachment2.h diff --git a/samples/attachment.h b/samples/attachment.h index 176cf4a..ca8e256 100644 --- a/samples/attachment.h +++ b/samples/attachment.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2019, Tomasz Sowa + * Copyright (c) 2019-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,7 +38,7 @@ #include #include "morm.h" #include "type.h" - +#include "language.h" namespace morm @@ -54,7 +54,7 @@ CREATE TABLE public.attachment ( content text, some_flags bool, created_date timestamp with time zone, - bigint language_id, + language_id bigint, primary key(id) ); @@ -71,32 +71,39 @@ public: std::string content; std::vector types; bool some_flags; - PT::Date created_date; + pt::Date created_date; Language language; void map_fields() { - field(L"id", id, false, false, true); + field(L"id", id, FT::no_insertable | FT::no_updatable | FT::primary_key); field(L"person_id", person_id); field(L"name", name); field(L"content", content); - field(L"attachment_id", L"types", types); - //field(L"types", types); + field(L"attachment_id", L"types", types, FT::foreign_key_in_child); field(L"some_flags", some_flags); field(L"created_date", created_date); - field(L"language_id", L"language", language); + field(L"language_id", L"language", language, FT::foreign_key); } - void table_name(PT::TextStream & stream) + void prepare_table() { - // schema.table_name or just table_name - stream << "public.attachment"; + table(L"public", L"attachment"); + } + + void after_select() + { + if( has_primary_key_set ) + { + morm::Finder finder(model_connector); + types = finder.select().where().eq(L"attachment_id", id).get_vector(); + } } void after_insert() { - get_last_sequence(L"public.attachment_id_seq", id); + get_last_sequence_for_primary_key(L"public.attachment_id_seq", id); } diff --git a/samples/attachment2.h b/samples/attachment2.h new file mode 100644 index 0000000..6961707 --- /dev/null +++ b/samples/attachment2.h @@ -0,0 +1,119 @@ +/* + * This file is a part of morm + * and is distributed under the 2-Clause BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2021, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef headerfile_morm_samples_attachment2 +#define headerfile_morm_samples_attachment2 + +#include +#include "morm.h" +#include "type.h" +#include "language.h" + + +namespace morm +{ +namespace samples +{ + +/* +CREATE TABLE public.attachment2 ( + id bigserial, + person_id bigint, + name varchar(64), + content text, + some_flags bool, + created_date timestamp with time zone, + language_id bigint, + + primary key(id) +); +*/ + +// copied from Attachment and changed the table name +class Attachment2 : public morm::Model +{ +public: + + long id; + long person_id; + std::wstring name; + std::string content; + std::vector types; + bool some_flags; + pt::Date created_date; + Language language; + + + void map_fields() + { + field(L"id", id, FT::no_insertable | FT::no_updatable | FT::primary_key); + field(L"person_id", person_id); + field(L"name", name); + field(L"content", content); + field(L"attachment_id", L"types", types, FT::foreign_key_in_child); + field(L"some_flags", some_flags); + field(L"created_date", created_date); + field(L"language_id", L"language", language, FT::foreign_key); + } + + void prepare_table() + { + table(L"public", L"attachment2"); + } + + void after_select() + { + if( has_primary_key_set ) + { + morm::Finder finder(model_connector); + types = finder.select().where().eq(L"attachment_id", id).get_vector(); + } + } + + void after_insert() + { + get_last_sequence_for_primary_key(L"public.attachment2_id_seq", id); + } + + +}; + + + +} +} + + +#endif + diff --git a/samples/language.h b/samples/language.h index 4fa2088..4c79951 100644 --- a/samples/language.h +++ b/samples/language.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2019, Tomasz Sowa + * Copyright (c) 2019-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -70,23 +70,21 @@ public: void map_fields() { - field(L"id", id, false, false, true); + field(L"id", id, FT::no_insertable | FT::no_updatable | FT::primary_key); field(L"english_name", english_name); field(L"local_name", local_name); field(L"code_str", code_str); field(L"code_int", code_int); } - - void table_name(PT::TextStream & stream) + void prepare_table() { - // schema.table_name or just table_name - stream << "public.language"; + table(L"public", L"language"); } void after_insert() { - get_last_sequence(L"public.language_id_seq", id); + get_last_sequence_for_primary_key(L"public.language_id_seq", id); } diff --git a/samples/main.cpp b/samples/main.cpp index 413aa3b..063199e 100644 --- a/samples/main.cpp +++ b/samples/main.cpp @@ -61,17 +61,17 @@ void print_syntax() int main(int argc, const char ** argv) { -PT::Space args; -PT::Space & args_options = args.FindAddSpace(L"options"); +pt::Space args; +pt::Space & args_options = args.FindAddSpace(L"options"); args_options.Add(L"c", 1); // one argument - config file args_options.Add(L"config", 1); - PT::MainSpaceParser main_parser; + pt::MainSpaceParser main_parser; main_parser.UTF8(true); main_parser.SetSpace(args); - PT::MainSpaceParser::Status args_status = main_parser.Parse(argc, argv); + pt::MainSpaceParser::Status args_status = main_parser.Parse(argc, argv); - if( args_status != PT::MainSpaceParser::status_ok ) + if( args_status != pt::MainSpaceParser::status_ok ) { std::cout << "Syntax error in arguments" << std::endl; return 1; @@ -101,9 +101,9 @@ args_options.Add(L"config", 1); * create database morm_test owner morm_test; * */ - PT::Log log; - PT::FileLog file_log; - PT::WTextStream log_buffer; + pt::Log log; + pt::FileLog file_log; + pt::WTextStream log_buffer; file_log.init(L"log.txt", true, 4, true); log.SetLogBuffer(&log_buffer); diff --git a/samples/person.h b/samples/person.h index f906d59..54a72c3 100644 --- a/samples/person.h +++ b/samples/person.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2019, Tomasz Sowa + * Copyright (c) 2019-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,6 +39,7 @@ #include "morm.h" #include "language.h" #include "attachment.h" +#include "attachment2.h" @@ -64,48 +65,49 @@ class Person : public morm::Model public: long id; + std::wstring first_name; std::wstring last_name; std::wstring email; Language language; std::list attachments; - Attachment attachment; + Attachment2 attachment2; void map_fields() { - field(L"id", id, false, false, true); - //field(L"id", id, f::no_insertable | f::no_updatable | f::primary_key); - + field(L"id", id, FT::no_insertable | FT::no_updatable | FT::primary_key); + field(L"language_id", L"language", language, FT::foreign_key); field(L"first_name", first_name); field(L"last_name", last_name); field(L"email", email); - field(L"language_id", L"language", language); - - field(L"person_id", L"attachments", attachments); - - field(L"person_id", L"attachment", attachment, true, true, false); - - //field(L"person_id", attachment, f::insertable | f::updatable | f::foreign_key); - //field(L"person_id", attachment, f::insertable, f::updatable, f::foreign_key); + field(L"person_id", L"attachments", attachments, FT::foreign_key_in_child); + field(L"person_id", L"attachment2", attachment2, FT::foreign_key_in_child | FT::no_insertable | FT::no_updatable); } - void table_name(PT::TextStream & stream) + + void prepare_table() { - // schema.table_name or just table_name - stream << "public.person"; + table(L"public", L"person"); } + void after_select() { - morm::Finder finder(model_connector); - attachments = finder.select().where().eq(L"person_id", id).get_list(); + if( has_primary_key_set ) + { + morm::Finder finder(model_connector); + attachments = finder.select().where().eq(L"person_id", id).get_list(); + + morm::Finder finder2(model_connector); + attachment2 = finder2.select().where().eq(L"person_id", id).get(); + } } void after_insert() { - get_last_sequence(L"public.person_id_seq", id); + get_last_sequence_for_primary_key(L"public.person_id_seq", id); } diff --git a/samples/sample01.h b/samples/sample01.h index 0558729..95dc80a 100644 --- a/samples/sample01.h +++ b/samples/sample01.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2019, Tomasz Sowa + * Copyright (c) 2019-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,6 +32,9 @@ * */ +#ifndef headerfile_morm_samples_sample01 +#define headerfile_morm_samples_sample01 + #include #include "basesample.h" #include "person.h" @@ -51,23 +54,37 @@ public: void make() { + // delete all datas + // delete from attachment; delete from attachment2; delete from language; delete from person; delete from types; + + // select * from person; select * from attachment; select * from attachment2 ; select * from types; select * from language; + + std::string str; + + person.set_connector(model_connector); load_defaults(person); - std::wstring sss = L"cosik wstawiony dynamicznie"; - person.set_field_value_generic(L"email", L"email", sss); + //std::wstring sss = L"some text put dynamically"; + //person.set_field_value_generic(L"email", L"email", sss); + + //person.insert(); //person.update(); - person.save(); + //person.save(); //person.remove(); + //person.to_text(str, true, true); morm::Finder finder(model_connector); + Person p = finder.select().where().eq(L"id", 210).get(); + p.to_text(str, true, true); + + //std::list plist = finder.use_table_prefix(false).select().where().eq(L"id", 120).get_list(); - //Person p = finder.use_table_prefix(false).select().where().eq(L"id", 120).get(); // Person p = finder.prepare_to_select().use_table_prefix(true).raw("select person.id as \"person.id\", person.first_name as \"person.first_name\", person.last_name as \"person.last_name\", person.email as \"person.email\", " // "language.id as \"language.id\", language.english_name as \"language.english_name\", language.local_name as \"language.local_name\", language.code_str as \"language.code_str\", language.code_int as \"language.code_int\", " @@ -79,14 +96,13 @@ void make() // "LEFT JOIN public.language AS language2 ON attachment.language_id = language2.id " // "where person.id=120").get(); - std::cout << "--------------------------------" << std::endl; + //std::cout << "--------------------------------" << std::endl; //p.remove(); //std::cout << "--------------------------------" << std::endl; - std::string str; //str += "--------\n"; - person.to_text(str, true, true); + // for(Person & person : plist) // { @@ -112,6 +128,7 @@ private: person.first_name = L"MyFirstName"; person.last_name = L"MyLastName"; person.email = L"myemail@mydomain.ltd"; + //person.set_save_mode(Model::DO_NOTHING_ON_SAVE); person.set_save_mode(Model::DO_INSERT_ON_SAVE); //person.set_save_mode(Model::DO_UPDATE_ON_SAVE); @@ -120,29 +137,38 @@ private: person.language.local_name = L"polish"; person.language.code_str = L"en"; person.language.code_int = 200; + //person.language.set_save_mode(Model::DO_NOTHING_ON_SAVE); person.language.set_save_mode(Model::DO_INSERT_ON_SAVE); //person.language.set_save_mode(Model::DO_UPDATE_ON_SAVE); std::time_t t = std::time(0); -// person.attachment.id = 40; - person.attachment.person_id = person.id; - person.attachment.created_date.FromTime(t); - person.attachment.name = L"attachment name"; - person.attachment.content = "long binary content"; - person.attachment.some_flags = true; - person.attachment.set_save_mode(Model::DO_INSERT_ON_SAVE); -// //person.attachment.set_save_mode(Model::DO_UPDATE_ON_SAVE); -// - person.attachment.language.id = 86; - person.attachment.language.english_name = L"attachment language"; - person.attachment.language.local_name = L"attachment local name"; - person.attachment.language.code_str = L"loen"; - person.attachment.language.code_int = 300; -// person.attachment.language.set_save_mode(Model::DO_UPDATE_ON_SAVE); - Type type; type.id = 0; + type.set_save_mode(Model::DO_INSERT_ON_SAVE); + + person.attachment2.id = 40; + person.attachment2.person_id = person.id; + person.attachment2.created_date.FromTime(t); + person.attachment2.name = L"attachment name"; + person.attachment2.content = "long binary content"; + person.attachment2.some_flags = true; + person.attachment2.set_save_mode(Model::DO_INSERT_ON_SAVE); +// //person.attachment.set_save_mode(Model::DO_UPDATE_ON_SAVE); + + person.attachment2.language.id = 86; + person.attachment2.language.english_name = L"attachment language"; + person.attachment2.language.local_name = L"attachment local name"; + person.attachment2.language.code_str = L"loen"; + person.attachment2.language.code_int = 300; + person.attachment2.language.set_save_mode(Model::DO_INSERT_ON_SAVE); + person.attachment2.language.set_has_primary_key_set(true); + + type.name = L"abcde - fghi"; + person.attachment2.types.push_back(type); + + type.name = L"second type"; + person.attachment2.types.push_back(type); Attachment attachment; attachment.id = 0; @@ -186,7 +212,6 @@ private: type.name = L"Typ dla attachment 3 - 3"; person.attachments.back().types.push_back(type); - //type.name = L"Typik"; //person.attachment.types.push_back(type); @@ -201,3 +226,5 @@ private: } } +#endif + diff --git a/samples/type.h b/samples/type.h index 2fb43f7..cfa1399 100644 --- a/samples/type.h +++ b/samples/type.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2019, Tomasz Sowa + * Copyright (c) 2019-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -65,21 +65,19 @@ public: void map_fields() { - field(L"id", id, false, false, true); + field(L"id", id, FT::no_insertable | FT::no_updatable | FT::primary_key); field(L"attachment_id", attachment_id); field(L"name", name); } - - void table_name(PT::TextStream & stream) + void prepare_table() { - // schema.table_name or just table_name - stream << "public.types"; + table(L"public", L"types"); } void after_insert() { - get_last_sequence(L"public.types_id_seq", id); + get_last_sequence_for_primary_key(L"public.types_id_seq", id); } diff --git a/src/Makefile.dep b/src/Makefile.dep index c7b9f44..6940b12 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep @@ -1,162 +1,49 @@ # DO NOT DELETE -baseexpression.o: baseexpression.h ../../pikotools/textstream/textstream.h -baseexpression.o: ../../pikotools/space/space.h -baseexpression.o: ../../pikotools/textstream/types.h -baseexpression.o: ../../pikotools/date/date.h -baseexpression.o: ../../pikotools/convert/inttostr.h -baseexpression.o: ../../pikotools/membuffer/membuffer.h -baseexpression.o: ../../pikotools/textstream/types.h morm_types.h modelenv.h -baseexpression.o: modeldata.h cursorhelper.h queryresult.h -baseexpression.o: ../../pikotools/log/log.h ../../pikotools/log/filelog.h -baseexpression.o: finderhelper.h fieldvaluehelper.h model.h modelconnector.h -baseexpression.o: clearer.h dbconnector.h flatconnector.h dbexpression.h -baseexpression.o: flatexpression.h ../../pikotools/utf8/utf8.h -clearer.o: clearer.h ../../pikotools/date/date.h -clearer.o: ../../pikotools/convert/inttostr.h model.h -clearer.o: ../../pikotools/textstream/textstream.h -clearer.o: ../../pikotools/space/space.h ../../pikotools/textstream/types.h -clearer.o: ../../pikotools/membuffer/membuffer.h -clearer.o: ../../pikotools/textstream/types.h modelconnector.h dbconnector.h -clearer.o: ../../pikotools/log/log.h ../../pikotools/log/filelog.h -clearer.o: queryresult.h flatconnector.h dbexpression.h baseexpression.h -clearer.o: morm_types.h modelenv.h modeldata.h cursorhelper.h finderhelper.h +baseexpression.o: baseexpression.h morm_types.h modelenv.h modeldata.h +baseexpression.o: cursorhelper.h queryresult.h finderhelper.h +baseexpression.o: fieldvaluehelper.h ft.h model.h modelconnector.h clearer.h +baseexpression.o: dbconnector.h flatconnector.h dbexpression.h +baseexpression.o: flatexpression.h +clearer.o: clearer.h model.h modelconnector.h dbconnector.h queryresult.h +clearer.o: ft.h flatconnector.h dbexpression.h baseexpression.h morm_types.h +clearer.o: modelenv.h modeldata.h cursorhelper.h finderhelper.h clearer.o: fieldvaluehelper.h flatexpression.h -dbconnector.o: dbconnector.h ../../pikotools/textstream/textstream.h -dbconnector.o: ../../pikotools/space/space.h -dbconnector.o: ../../pikotools/textstream/types.h ../../pikotools/date/date.h -dbconnector.o: ../../pikotools/convert/inttostr.h -dbconnector.o: ../../pikotools/membuffer/membuffer.h -dbconnector.o: ../../pikotools/textstream/types.h ../../pikotools/log/log.h -dbconnector.o: ../../pikotools/log/filelog.h queryresult.h dbexpression.h +dbconnector.o: dbconnector.h queryresult.h ft.h dbexpression.h dbconnector.o: baseexpression.h morm_types.h modelenv.h modeldata.h dbconnector.o: cursorhelper.h finderhelper.h fieldvaluehelper.h model.h dbconnector.o: modelconnector.h clearer.h flatconnector.h flatexpression.h -dbconnector.o: ../../pikotools/utf8/utf8.h ../../pikotools/convert/convert.h -dbconnector.o: ../../pikotools/convert/inttostr.h -dbconnector.o: ../../pikotools/convert/patternreplacer.h -dbconnector.o: ../../pikotools/convert/strtoint.h -dbconnector.o: ../../pikotools/convert/text.h ../../pikotools/convert/misc.h -dbexpression.o: dbexpression.h baseexpression.h -dbexpression.o: ../../pikotools/textstream/textstream.h -dbexpression.o: ../../pikotools/space/space.h -dbexpression.o: ../../pikotools/textstream/types.h -dbexpression.o: ../../pikotools/date/date.h -dbexpression.o: ../../pikotools/convert/inttostr.h -dbexpression.o: ../../pikotools/membuffer/membuffer.h -dbexpression.o: ../../pikotools/textstream/types.h morm_types.h modelenv.h -dbexpression.o: modeldata.h cursorhelper.h queryresult.h -dbexpression.o: ../../pikotools/log/log.h ../../pikotools/log/filelog.h -dbexpression.o: finderhelper.h fieldvaluehelper.h -flatconnector.o: flatconnector.h ../../pikotools/textstream/textstream.h -flatconnector.o: ../../pikotools/space/space.h -flatconnector.o: ../../pikotools/textstream/types.h -flatconnector.o: ../../pikotools/date/date.h -flatconnector.o: ../../pikotools/convert/inttostr.h -flatconnector.o: ../../pikotools/membuffer/membuffer.h -flatconnector.o: ../../pikotools/textstream/types.h flatexpression.h -flatconnector.o: baseexpression.h morm_types.h modelenv.h modeldata.h -flatconnector.o: cursorhelper.h queryresult.h ../../pikotools/log/log.h -flatconnector.o: ../../pikotools/log/filelog.h finderhelper.h -flatconnector.o: fieldvaluehelper.h model.h modelconnector.h clearer.h -flatconnector.o: dbconnector.h dbexpression.h -flatexpression.o: flatexpression.h baseexpression.h -flatexpression.o: ../../pikotools/textstream/textstream.h -flatexpression.o: ../../pikotools/space/space.h -flatexpression.o: ../../pikotools/textstream/types.h -flatexpression.o: ../../pikotools/date/date.h -flatexpression.o: ../../pikotools/convert/inttostr.h -flatexpression.o: ../../pikotools/membuffer/membuffer.h -flatexpression.o: ../../pikotools/textstream/types.h morm_types.h modelenv.h -flatexpression.o: modeldata.h cursorhelper.h queryresult.h -flatexpression.o: ../../pikotools/log/log.h ../../pikotools/log/filelog.h -flatexpression.o: finderhelper.h fieldvaluehelper.h -jsonconnector.o: jsonconnector.h flatconnector.h -jsonconnector.o: ../../pikotools/textstream/textstream.h -jsonconnector.o: ../../pikotools/space/space.h -jsonconnector.o: ../../pikotools/textstream/types.h -jsonconnector.o: ../../pikotools/date/date.h -jsonconnector.o: ../../pikotools/convert/inttostr.h -jsonconnector.o: ../../pikotools/membuffer/membuffer.h -jsonconnector.o: ../../pikotools/textstream/types.h jsonexpression.h +dbexpression.o: dbexpression.h baseexpression.h morm_types.h modelenv.h +dbexpression.o: modeldata.h cursorhelper.h queryresult.h finderhelper.h +dbexpression.o: fieldvaluehelper.h ft.h +flatconnector.o: flatconnector.h flatexpression.h baseexpression.h +flatconnector.o: morm_types.h modelenv.h modeldata.h cursorhelper.h +flatconnector.o: queryresult.h finderhelper.h fieldvaluehelper.h ft.h model.h +flatconnector.o: modelconnector.h clearer.h dbconnector.h dbexpression.h +flatexpression.o: flatexpression.h baseexpression.h morm_types.h modelenv.h +flatexpression.o: modeldata.h cursorhelper.h queryresult.h finderhelper.h +flatexpression.o: fieldvaluehelper.h ft.h +jsonconnector.o: jsonconnector.h flatconnector.h jsonexpression.h jsonconnector.o: flatexpression.h baseexpression.h morm_types.h modelenv.h -jsonconnector.o: modeldata.h cursorhelper.h queryresult.h -jsonconnector.o: ../../pikotools/log/log.h ../../pikotools/log/filelog.h -jsonconnector.o: finderhelper.h fieldvaluehelper.h +jsonconnector.o: modeldata.h cursorhelper.h queryresult.h finderhelper.h +jsonconnector.o: fieldvaluehelper.h ft.h jsonexpression.o: jsonexpression.h flatexpression.h baseexpression.h -jsonexpression.o: ../../pikotools/textstream/textstream.h -jsonexpression.o: ../../pikotools/space/space.h -jsonexpression.o: ../../pikotools/textstream/types.h -jsonexpression.o: ../../pikotools/date/date.h -jsonexpression.o: ../../pikotools/convert/inttostr.h -jsonexpression.o: ../../pikotools/membuffer/membuffer.h -jsonexpression.o: ../../pikotools/textstream/types.h morm_types.h modelenv.h -jsonexpression.o: modeldata.h cursorhelper.h queryresult.h -jsonexpression.o: ../../pikotools/log/log.h ../../pikotools/log/filelog.h -jsonexpression.o: finderhelper.h fieldvaluehelper.h -model.o: model.h ../../pikotools/textstream/textstream.h -model.o: ../../pikotools/space/space.h ../../pikotools/textstream/types.h -model.o: ../../pikotools/date/date.h ../../pikotools/convert/inttostr.h -model.o: ../../pikotools/membuffer/membuffer.h -model.o: ../../pikotools/textstream/types.h modelconnector.h clearer.h -model.o: dbconnector.h ../../pikotools/log/log.h -model.o: ../../pikotools/log/filelog.h queryresult.h flatconnector.h -model.o: dbexpression.h baseexpression.h morm_types.h modelenv.h modeldata.h -model.o: cursorhelper.h finderhelper.h fieldvaluehelper.h flatexpression.h -modelconnector.o: modelconnector.h clearer.h ../../pikotools/date/date.h -modelconnector.o: ../../pikotools/convert/inttostr.h dbconnector.h -modelconnector.o: ../../pikotools/textstream/textstream.h -modelconnector.o: ../../pikotools/space/space.h -modelconnector.o: ../../pikotools/textstream/types.h -modelconnector.o: ../../pikotools/membuffer/membuffer.h -modelconnector.o: ../../pikotools/textstream/types.h -modelconnector.o: ../../pikotools/log/log.h ../../pikotools/log/filelog.h -modelconnector.o: queryresult.h flatconnector.h -postgresqlconnector.o: postgresqlconnector.h dbconnector.h -postgresqlconnector.o: ../../pikotools/textstream/textstream.h -postgresqlconnector.o: ../../pikotools/space/space.h -postgresqlconnector.o: ../../pikotools/textstream/types.h -postgresqlconnector.o: ../../pikotools/date/date.h -postgresqlconnector.o: ../../pikotools/convert/inttostr.h -postgresqlconnector.o: ../../pikotools/membuffer/membuffer.h -postgresqlconnector.o: ../../pikotools/textstream/types.h -postgresqlconnector.o: ../../pikotools/log/log.h -postgresqlconnector.o: ../../pikotools/log/filelog.h queryresult.h -postgresqlconnector.o: postgresqlqueryresult.h ../../pikotools/utf8/utf8.h -postgresqlconnector.o: postgresqlexpression.h dbexpression.h baseexpression.h -postgresqlconnector.o: morm_types.h modelenv.h modeldata.h cursorhelper.h -postgresqlconnector.o: finderhelper.h fieldvaluehelper.h -postgresqlconnector.o: ../../pikotools/convert/strtoint.h -postgresqlconnector.o: ../../pikotools/convert/text.h -postgresqlconnector.o: ../../pikotools/convert/misc.h +jsonexpression.o: morm_types.h modelenv.h modeldata.h cursorhelper.h +jsonexpression.o: queryresult.h finderhelper.h fieldvaluehelper.h ft.h +model.o: model.h modelconnector.h clearer.h dbconnector.h queryresult.h ft.h +model.o: flatconnector.h dbexpression.h baseexpression.h morm_types.h +model.o: modelenv.h modeldata.h cursorhelper.h finderhelper.h +model.o: fieldvaluehelper.h flatexpression.h +modelconnector.o: modelconnector.h clearer.h dbconnector.h queryresult.h ft.h +modelconnector.o: flatconnector.h +postgresqlconnector.o: postgresqlconnector.h dbconnector.h queryresult.h ft.h +postgresqlconnector.o: postgresqlqueryresult.h postgresqlexpression.h +postgresqlconnector.o: dbexpression.h baseexpression.h morm_types.h +postgresqlconnector.o: modelenv.h modeldata.h cursorhelper.h finderhelper.h +postgresqlconnector.o: fieldvaluehelper.h postgresqlexpression.o: postgresqlexpression.h dbexpression.h -postgresqlexpression.o: baseexpression.h -postgresqlexpression.o: ../../pikotools/textstream/textstream.h -postgresqlexpression.o: ../../pikotools/space/space.h -postgresqlexpression.o: ../../pikotools/textstream/types.h -postgresqlexpression.o: ../../pikotools/date/date.h -postgresqlexpression.o: ../../pikotools/convert/inttostr.h -postgresqlexpression.o: ../../pikotools/membuffer/membuffer.h -postgresqlexpression.o: ../../pikotools/textstream/types.h morm_types.h -postgresqlexpression.o: modelenv.h modeldata.h cursorhelper.h queryresult.h -postgresqlexpression.o: ../../pikotools/log/log.h -postgresqlexpression.o: ../../pikotools/log/filelog.h finderhelper.h -postgresqlexpression.o: fieldvaluehelper.h +postgresqlexpression.o: baseexpression.h morm_types.h modelenv.h modeldata.h +postgresqlexpression.o: cursorhelper.h queryresult.h finderhelper.h +postgresqlexpression.o: fieldvaluehelper.h ft.h postgresqlqueryresult.o: postgresqlqueryresult.h queryresult.h -postgresqlqueryresult.o: ../../pikotools/log/log.h -postgresqlqueryresult.o: ../../pikotools/textstream/textstream.h -postgresqlqueryresult.o: ../../pikotools/space/space.h -postgresqlqueryresult.o: ../../pikotools/textstream/types.h -postgresqlqueryresult.o: ../../pikotools/date/date.h -postgresqlqueryresult.o: ../../pikotools/convert/inttostr.h -postgresqlqueryresult.o: ../../pikotools/membuffer/membuffer.h -postgresqlqueryresult.o: ../../pikotools/textstream/types.h -postgresqlqueryresult.o: ../../pikotools/log/filelog.h -queryresult.o: queryresult.h ../../pikotools/log/log.h -queryresult.o: ../../pikotools/textstream/textstream.h -queryresult.o: ../../pikotools/space/space.h -queryresult.o: ../../pikotools/textstream/types.h ../../pikotools/date/date.h -queryresult.o: ../../pikotools/convert/inttostr.h -queryresult.o: ../../pikotools/membuffer/membuffer.h -queryresult.o: ../../pikotools/textstream/types.h -queryresult.o: ../../pikotools/log/filelog.h ../../pikotools/utf8/utf8.h +queryresult.o: queryresult.h diff --git a/src/baseexpression.cpp b/src/baseexpression.cpp index 475cd20..ede7e5c 100644 --- a/src/baseexpression.cpp +++ b/src/baseexpression.cpp @@ -74,7 +74,21 @@ int BaseExpression::get_work_mode() -PT::TextStream * BaseExpression::get_current_stream() +pt::TextStream * BaseExpression::get_text_stream() +{ + return out_stream; +} + +void BaseExpression::set_text_stream(pt::TextStream * out_stream) +{ + this->out_stream = out_stream; +} + + + + + +pt::TextStream * BaseExpression::get_current_stream() { return out_stream; } @@ -93,7 +107,7 @@ bool BaseExpression::get_allow_to_use_prefix() -void BaseExpression::generate_from_model(PT::TextStream & stream, Model & model) +void BaseExpression::generate_from_model(pt::TextStream & stream, Model & model) { this->out_stream = &stream; generate_from_model(model); @@ -107,7 +121,7 @@ void BaseExpression::generate_from_model(Model & model) { before_generate_from_model(); dump_additional_info(model); - model.map_fields(); + model.fields(); after_generate_from_model(); } } @@ -117,7 +131,8 @@ void BaseExpression::dump_additional_info(Model & model) { if( model.model_env && model.model_env->dump_mode ) { - field(L"model_save_mode", model.save_mode, false, false, false, model.model_env); + field(L"model_save_mode", model.save_mode, FT::no_insertable | FT::no_updatable | FT::no_fetchable, model.model_env); + field(L"has_primary_key_set", model.has_primary_key_set, FT::no_insertable | FT::no_updatable | FT::no_fetchable, model.model_env); } } @@ -133,7 +148,7 @@ void BaseExpression::after_generate_from_model() } -bool BaseExpression::can_field_be_generated(bool insertable, bool updatable, bool is_primary_key) +bool BaseExpression::can_field_be_generated(const FT &) { return true; } @@ -154,132 +169,50 @@ void BaseExpression::field_after() } -bool BaseExpression::is_long_field_name(const wchar_t * field_name) -{ - bool is_long = false; - while( *field_name != 0 ) - { - if( *field_name == '.' ) - { - is_long = true; - break; - } - - field_name += 1; - } - - return is_long; -} - - -bool BaseExpression::is_long_field_name(const PT::TextStream & field_name) -{ - PT::TextStream::const_iterator i = field_name.begin(); - bool is_long = false; - - while( i != field_name.end() ) - { - if( *i == '.' ) - { - is_long = true; - break; - } - - ++i; - } - - return is_long; -} - - -bool BaseExpression::is_long_table_name(const wchar_t * table_name) -{ - return is_long_field_name(table_name); -} - -bool BaseExpression::is_long_table_name(const PT::TextStream & table_name) -{ - return is_long_field_name(table_name); -} - - - -void BaseExpression::put_field_name(const wchar_t * field_name, ModelEnv * model_env) -{ - if( is_long_field_name(field_name) ) - put_long_field_name(field_name); - else - put_short_field_name(field_name, model_env); -} - - -const wchar_t * BaseExpression::put_long_part_field_name(const wchar_t * field_name) -{ - while( *field_name != 0 && *field_name != '.' ) - { - esc(*field_name, *out_stream); - field_name += 1; - } - - return field_name; -} - - -void BaseExpression::put_long_field_name(const wchar_t * field_name) -{ - before_first_part_long_field_name(); - field_name = put_long_part_field_name(field_name); - after_first_part_long_field_name(); - - if( *field_name == '.' ) - { - field_name += 1; - (*out_stream) << '.'; - - before_second_part_long_field_name(); - field_name = put_long_part_field_name(field_name); - after_second_part_long_field_name(); - } -} - - -void BaseExpression::put_short_field_name(const wchar_t * field_name, ModelEnv * model_env) +void BaseExpression::put_field_name_and_table_if_needed(const wchar_t * field_name, const FT & field_type, ModelEnv * model_env) { if( use_prefix && model_env ) { - before_first_part_long_field_name(); - esc(model_env->table_name_short, *out_stream); - - if( model_env->table_index > 1 ) + if( !is_empty_field(model_env->table2_name) ) { - (*out_stream) << model_env->table_index; + put_table_with_index_and_field(model_env->table2_name, model_env->table2_index, field_name, field_type); + } + else + { + put_table_with_index_and_field(model_env->table_name, model_env->table_index, field_name, field_type); } - - after_first_part_long_field_name(); - - (*out_stream) << '.'; - - before_second_part_long_field_name(); - esc(field_name, *out_stream); - after_second_part_long_field_name(); } else { - before_short_field_name(); - esc(field_name, *out_stream); - after_short_field_name(); + put_field_name(field_name, field_type, model_env); } - } -void BaseExpression::save_foreign_key(const wchar_t * field_name, ModelEnv * model_env) + + +void BaseExpression::put_field_name(const wchar_t * field_name, const FT & field_type, ModelEnv * model_env) { - PT::TextStream str; - PT::TextStream * old_out_stream = out_stream; + if( field_type.is_raw_field_name() ) + { + (*out_stream) << field_name; + } + else + { + before_field_name(); + esc(field_name, *out_stream); + after_field_name(); + } +} + + +void BaseExpression::save_foreign_key(const wchar_t * field_name, const FT & field_type, ModelEnv * model_env) +{ + pt::TextStream str; + pt::TextStream * old_out_stream = out_stream; out_stream = &str; - put_field_name(field_name, model_env); + put_field_name(field_name, field_type, model_env); out_stream = old_out_stream; if( model_env && model_env->finder_helper ) @@ -291,85 +224,139 @@ void BaseExpression::save_foreign_key(const wchar_t * field_name, ModelEnv * mod } -void BaseExpression::before_short_field_name() + +void BaseExpression::schema_table_separator() { } -void BaseExpression::after_short_field_name() -{ -} - - -void BaseExpression::before_first_part_long_field_name() -{ -} - - -void BaseExpression::after_first_part_long_field_name() -{ -} - - -void BaseExpression::before_second_part_long_field_name() -{ -} - - -void BaseExpression::after_second_part_long_field_name() +void BaseExpression::table_field_separator() { } -void BaseExpression::before_field_value(const std::wstring &) +void BaseExpression::before_schema_name() { } -void BaseExpression::before_field_value(const std::string &) +void BaseExpression::after_schema_name() { } -void BaseExpression::after_field_value(const std::wstring &) +void BaseExpression::before_table_name() { } -void BaseExpression::after_field_value(const std::string &) +void BaseExpression::after_table_name() { } -void BaseExpression::before_field_value(const wchar_t *) +void BaseExpression::before_field_name() { } -void BaseExpression::after_field_value(const wchar_t *) +void BaseExpression::after_field_name() { } -void BaseExpression::before_field_value(const char *) +void BaseExpression::before_field_value(const std::wstring &, const FT & field_type) { + before_field_value_string(field_type); } -void BaseExpression::after_field_value(const char *) +void BaseExpression::before_field_value(const std::string &, const FT & field_type) { + before_field_value_string(field_type); } -void BaseExpression::before_field_value(const PT::Date &) + +void BaseExpression::after_field_value(const std::wstring &, const FT & field_type) { + after_field_value_string(field_type); } -void BaseExpression::after_field_value(const PT::Date &) + +void BaseExpression::after_field_value(const std::string &, const FT & field_type) { + after_field_value_string(field_type); } +void BaseExpression::before_field_value(const wchar_t *, const FT & field_type) +{ + before_field_value_string(field_type); +} + + +void BaseExpression::after_field_value(const wchar_t *, const FT & field_type) +{ + after_field_value_string(field_type); +} + + +void BaseExpression::before_field_value(const char *, const FT & field_type) +{ + before_field_value_string(field_type); +} + + +void BaseExpression::after_field_value(const char *, const FT & field_type) +{ + after_field_value_string(field_type); +} + + +void BaseExpression::before_field_value(wchar_t, const FT & field_type) +{ + before_field_value_string(field_type); +} + + +void BaseExpression::after_field_value(wchar_t, const FT & field_type) +{ + after_field_value_string(field_type); +} + + +void BaseExpression::before_field_value(char, const FT & field_type) +{ + before_field_value_string(field_type); +} + + +void BaseExpression::after_field_value(char, const FT & field_type) +{ + after_field_value_string(field_type); +} + +void BaseExpression::before_field_value(const pt::Date &, const FT & field_type) +{ + before_field_value_string(field_type); +} + +void BaseExpression::after_field_value(const pt::Date &, const FT & field_type) +{ + after_field_value_string(field_type); +} + +void BaseExpression::before_field_value(const pt::Space &, const FT & field_type) +{ + before_field_value_string(field_type); +} + +void BaseExpression::after_field_value(const pt::Space &, const FT & field_type) +{ + after_field_value_string(field_type); +} + void BaseExpression::put_name_value_separator() { @@ -377,82 +364,120 @@ void BaseExpression::put_name_value_separator() } -void BaseExpression::esc(char val, PT::TextStream & stream) +char BaseExpression::char_to_hex_part(char c) { - stream << val; + if( c < 10 ) + return c + '0'; + + return c - 10 + 'A'; } -void BaseExpression::esc(unsigned char val, PT::TextStream & stream) +void BaseExpression::char_to_hex(char c, pt::TextStream & stream) { - esc(static_cast(val), stream); + stream << char_to_hex_part(((unsigned char)c) >> 4); + stream << char_to_hex_part(((unsigned char)c) & 0x0f); } -void BaseExpression::esc(wchar_t val, PT::TextStream & stream) + + +void BaseExpression::esc(char val, pt::TextStream & stream, const FT & field_type) { - char utf8_buf[10]; - - size_t utf8_len = PT::IntToUTF8((int)val, utf8_buf, sizeof(utf8_buf)); - - for(size_t a = 0 ; a < utf8_len ; ++a) + if( field_type.is_binary() || field_type.is_hexadecimal() ) { - esc(utf8_buf[a], stream); + char_to_hex(val, stream); + } + else + { + stream << val; } } -void BaseExpression::esc(const std::wstring & val, PT::TextStream & stream) +void BaseExpression::esc(unsigned char val, pt::TextStream & stream, const FT & field_type) { - char utf8_buf[10]; + esc(static_cast(val), stream, field_type); +} - for(size_t i = 0 ; i < val.size() ; ++i) + +void BaseExpression::esc(wchar_t val, pt::TextStream & stream, const FT & field_type) +{ + if( field_type.use_utf8() ) { - size_t utf8_len = PT::IntToUTF8((int)val[i], utf8_buf, sizeof(utf8_buf)); + char utf8_buf[10]; + + size_t utf8_len = pt::int_to_utf8((int)val, utf8_buf, sizeof(utf8_buf)); for(size_t a = 0 ; a < utf8_len ; ++a) { - esc(utf8_buf[a], stream); + esc(utf8_buf[a], stream, field_type); + } + } + else + { + esc(static_cast(val), stream, field_type); + } +} + + +void BaseExpression::esc(const wchar_t * val, bool has_known_length, size_t len, pt::TextStream & stream, const FT & field_type) +{ + if( field_type.use_utf8() ) + { + char utf8_buf[10]; + + for(size_t i = 0 ; has_known_length ? (i < len) : val[i] != 0 ; ++i) + { + size_t utf8_len = pt::int_to_utf8((int)val[i], utf8_buf, sizeof(utf8_buf)); + + for(size_t a = 0 ; a < utf8_len ; ++a) + { + esc(utf8_buf[a], stream, field_type); + } + } + } + else + { + for(size_t i = 0 ; has_known_length ? (i < len) : val[i] != 0 ; ++i) + { + esc(static_cast(val[i]), stream, field_type); } } } -void BaseExpression::esc(const wchar_t * val, PT::TextStream & stream) +void BaseExpression::esc(const std::wstring & val, pt::TextStream & stream, const FT & field_type) { - char utf8_buf[10]; - - for(size_t i = 0 ; val[i] != 0 ; ++i) - { - size_t utf8_len = PT::IntToUTF8((int)val[i], utf8_buf, sizeof(utf8_buf)); - - for(size_t a = 0 ; a < utf8_len ; ++a) - { - esc(utf8_buf[a], stream); - } - } + esc(val.c_str(), true, val.size(), stream, field_type); } -void BaseExpression::esc(const std::string & val, PT::TextStream & stream) +void BaseExpression::esc(const wchar_t * val, pt::TextStream & stream, const FT & field_type) +{ + esc(val, false, 0, stream, field_type); +} + + +void BaseExpression::esc(const std::string & val, pt::TextStream & stream, const FT & field_type) { for(size_t i = 0 ; i < val.size() ; ++i) { - esc(val[i], stream); + esc(val[i], stream, field_type); } } -void BaseExpression::esc(const char * val, PT::TextStream & stream) +void BaseExpression::esc(const char * val, pt::TextStream & stream, const FT & field_type) { for(size_t i = 0 ; val[i] != 0 ; ++i) { - esc(val[i], stream); + esc(val[i], stream, field_type); } } -void BaseExpression::esc(bool val, PT::TextStream & stream) +void BaseExpression::esc(bool val, pt::TextStream & stream, const FT & field_type) { if( val ) stream << "true"; @@ -461,196 +486,470 @@ void BaseExpression::esc(bool val, PT::TextStream & stream) } -void BaseExpression::esc(short val, PT::TextStream & stream) +void BaseExpression::esc(short val, pt::TextStream & stream, const FT & field_type) { stream << val; } -void BaseExpression::esc(unsigned short val, PT::TextStream & stream) +void BaseExpression::esc(unsigned short val, pt::TextStream & stream, const FT & field_type) { stream << val; } -void BaseExpression::esc(int val, PT::TextStream & stream) +void BaseExpression::esc(int val, pt::TextStream & stream, const FT & field_type) { stream << val; } -void BaseExpression::esc(unsigned int val, PT::TextStream & stream) +void BaseExpression::esc(unsigned int val, pt::TextStream & stream, const FT & field_type) { stream << val; } -void BaseExpression::esc(long val, PT::TextStream & stream) +void BaseExpression::esc(long val, pt::TextStream & stream, const FT & field_type) { stream << val; } -void BaseExpression::esc(unsigned long val, PT::TextStream & stream) +void BaseExpression::esc(unsigned long val, pt::TextStream & stream, const FT & field_type) { stream << val; } -void BaseExpression::esc(long long val, PT::TextStream & stream) +void BaseExpression::esc(long long val, pt::TextStream & stream, const FT & field_type) { - // not implemented in PT::TextStream yet + // not implemented in pt::TextStream yet //stream << val; } -void BaseExpression::esc(unsigned long long val, PT::TextStream & stream) +void BaseExpression::esc(unsigned long long val, pt::TextStream & stream, const FT & field_type) { //stream << val; } -void BaseExpression::esc(float val, PT::TextStream & stream) +void BaseExpression::esc(float val, pt::TextStream & stream, const FT & field_type) { stream << val; } -void BaseExpression::esc(double val, PT::TextStream & stream) +void BaseExpression::esc(double val, pt::TextStream & stream, const FT & field_type) { stream << val; } -void BaseExpression::esc(long double val, PT::TextStream & stream) +void BaseExpression::esc(long double val, pt::TextStream & stream, const FT & field_type) { - // IMPLEMENT ME in PT::TextStream + // IMPLEMENT ME in pt::TextStream //stream << val; } -void BaseExpression::esc(const PT::Date & date, PT::TextStream & stream) +void BaseExpression::esc(const pt::Date & date, pt::TextStream & stream, const FT & field_type) { stream << date; } -void BaseExpression::esc(const PT::TextStream & val, PT::TextStream & stream) +void BaseExpression::esc(const pt::TextStream & val, pt::TextStream & stream, const FT & field_type) { - PT::TextStream::const_iterator i = val.begin(); + pt::TextStream::const_iterator i = val.begin(); for(; i != val.end() ; ++i) { - esc(*i, stream); + esc(*i, stream, field_type); + } +} + +void BaseExpression::esc(const pt::WTextStream & val, pt::TextStream & stream, const FT & field_type) +{ + pt::WTextStream::const_iterator i = val.begin(); + + for(; i != val.end() ; ++i) + { + esc(*i, stream, field_type); + } +} + +void BaseExpression::esc(const pt::Space & space, pt::TextStream & stream, const FT & field_type) +{ + pt::WTextStream tmp_stream; + + space.serialize_to_space_stream(tmp_stream, true); + esc(tmp_stream, stream, field_type); +} + + +//void BaseExpression::put_type(char val, pt::TextStream & stream) +//{ +// stream << "char"; +//} +// +//void BaseExpression::put_type(unsigned char val, pt::TextStream & stream) +//{ +// stream << "unsigned char"; +//} +// +// +//void BaseExpression::put_type(const std::wstring & val, pt::TextStream & stream) +//{ +// stream << "text"; +//} +// +//void BaseExpression::put_type(const wchar_t * val, pt::TextStream & stream) +//{ +// stream << "text"; +//} +// +// +//void BaseExpression::put_type(const std::string & val, pt::TextStream & stream) +//{ +// stream << "text"; +//} +// +//void BaseExpression::put_type(const char * val, pt::TextStream & stream) +//{ +// stream << "text"; +//} +// +// +//void BaseExpression::put_type(bool val, pt::TextStream & stream) +//{ +// stream << "boolean"; +//} +// +//void BaseExpression::put_type(short val, pt::TextStream & stream) +//{ +// stream << "short integer"; +//} +// +//void BaseExpression::put_type(unsigned short val, pt::TextStream & stream) +//{ +// stream << "unsigned short integer"; +//} +// +//void BaseExpression::put_type(int val, pt::TextStream & stream) +//{ +// stream << "integer"; +//} +// +//void BaseExpression::put_type(unsigned int val, pt::TextStream & stream) +//{ +// stream << "unsigned integer"; +//} +// +//void BaseExpression::put_type(long val, pt::TextStream & stream) +//{ +// stream << "long integer"; +//} +// +//void BaseExpression::put_type(unsigned long val, pt::TextStream & stream) +//{ +// stream << "unsigned long integer"; +//} +// +//void BaseExpression::put_type(long long val, pt::TextStream & stream) +//{ +// stream << "very long integer"; +//} +// +//void BaseExpression::put_type(unsigned long long val, pt::TextStream & stream) +//{ +// stream << "unsigned very long integer"; +//} +// +//void BaseExpression::put_type(float val, pt::TextStream & stream) +//{ +// stream << "float"; +//} +// +//void BaseExpression::put_type(double val, pt::TextStream & stream) +//{ +// stream << "double"; +//} +// +//void BaseExpression::put_type(long double val, pt::TextStream & stream) +//{ +// stream << "long double"; +//} +// +////void BaseExpression::put_type(void* val, pt::TextStream & stream) +////{ +////} +// +// +//void BaseExpression::put_type(const pt::Date & date, pt::TextStream & stream) +//{ +// stream << "date"; +//} +// +//void BaseExpression::put_type(const Model & model, pt::TextStream & stream) +//{ +// stream << "object"; +//} + + +void BaseExpression::before_field_value_string(const FT & field_type) +{ +} + +void BaseExpression::after_field_value_string(const FT & field_type) +{ +} + + +/* + * schema_name can be a null pointer or just pointing to an empty string + * in such a case we do not put the schema name + */ +void BaseExpression::put_schema_table(const wchar_t * schema_name, const wchar_t * table_name) +{ + if( out_stream ) + { + bool has_schema = false; + + if( !is_empty_field(schema_name) ) + { + has_schema = true; + before_schema_name(); + esc(schema_name, *out_stream); + after_schema_name(); + } + + if( !is_empty_field(table_name) ) + { + if( has_schema ) + schema_table_separator(); + + before_table_name(); + esc(table_name, *out_stream); + after_table_name(); + } } } -void BaseExpression::put_type(char val, PT::TextStream & stream) +/* + * schema_name can be empty - in such a case we do not put the schema name + */ +void BaseExpression::put_schema_table(const pt::WTextStream & schema_name, const pt::WTextStream & table_name) { - stream << "char"; + if( out_stream ) + { + bool has_schema = false; + + if( !schema_name.empty() ) + { + has_schema = true; + before_schema_name(); + esc(schema_name, *out_stream); + after_schema_name(); + } + + if( !table_name.empty() ) + { + if( has_schema ) + schema_table_separator(); + + before_table_name(); + esc(table_name, *out_stream); + after_table_name(); + } + } } -void BaseExpression::put_type(unsigned char val, PT::TextStream & stream) + +void BaseExpression::put_table(const wchar_t * table_name) { - stream << "unsigned char"; + if( out_stream ) + { + before_table_name(); + esc(table_name, *out_stream); + after_table_name(); + } } -void BaseExpression::put_type(const std::wstring & val, PT::TextStream & stream) +void BaseExpression::put_table(const pt::WTextStream & table_name) { - stream << "text"; + if( out_stream ) + { + before_table_name(); + esc(table_name, *out_stream); + after_table_name(); + } } -void BaseExpression::put_type(const wchar_t * val, PT::TextStream & stream) + +void BaseExpression::put_table_with_index(const wchar_t * table_name, int index) { - stream << "text"; + if( out_stream ) + { + before_table_name(); + esc(table_name, *out_stream); + + if( index > 1 ) + { + (*out_stream) << index; + } + + after_table_name(); + } } -void BaseExpression::put_type(const std::string & val, PT::TextStream & stream) +void BaseExpression::put_table_with_index(const pt::WTextStream & table_name, int index) { - stream << "text"; + if( out_stream ) + { + before_table_name(); + esc(table_name, *out_stream); + + if( index > 1 ) + { + (*out_stream) << index; + } + + after_table_name(); + } } -void BaseExpression::put_type(const char * val, PT::TextStream & stream) + +void BaseExpression::put_table_with_index_and_field(const wchar_t * table_name, int index, const wchar_t * field_name, const FT & field_type) { - stream << "text"; + if( out_stream ) + { + put_table_with_index(table_name, index); + table_field_separator(); + put_field_name(field_name, field_type, nullptr); + } } - -void BaseExpression::put_type(bool val, PT::TextStream & stream) +void BaseExpression::put_table_with_index_and_field(const pt::WTextStream & table_name, int index, const wchar_t * field_name, const FT & field_type) { - stream << "boolean"; + if( out_stream ) + { + put_table_with_index(table_name, index); + table_field_separator(); + put_field_name(field_name, field_type, nullptr); + } } -void BaseExpression::put_type(short val, PT::TextStream & stream) + +void BaseExpression::put_table_and_field(const wchar_t * table_name, const wchar_t * field_name, const FT & field_type) { - stream << "short integer"; + if( out_stream ) + { + put_table(table_name); + table_field_separator(); + put_field_name(field_name, field_type, nullptr); + } } -void BaseExpression::put_type(unsigned short val, PT::TextStream & stream) +void BaseExpression::put_table_and_field(const pt::WTextStream & table_name, const wchar_t * field_name, const FT & field_type) { - stream << "unsigned short integer"; + if( out_stream ) + { + put_table(table_name); + table_field_separator(); + put_field_name(field_name, field_type, nullptr); + } } -void BaseExpression::put_type(int val, PT::TextStream & stream) + + +void BaseExpression::schema_table_to_stream(pt::TextStream & stream, const wchar_t * schema_name, const wchar_t * table_name) { - stream << "integer"; + this->out_stream = &stream; + put_schema_table(schema_name, table_name); + this->out_stream = nullptr; } -void BaseExpression::put_type(unsigned int val, PT::TextStream & stream) + +void BaseExpression::schema_table_to_stream(pt::TextStream & stream, const pt::WTextStream & schema_name, const pt::WTextStream & table_name) { - stream << "unsigned integer"; + this->out_stream = &stream; + put_schema_table(schema_name, table_name); + this->out_stream = nullptr; } -void BaseExpression::put_type(long val, PT::TextStream & stream) + +void BaseExpression::table_to_stream(pt::TextStream & stream, const wchar_t * table_name) { - stream << "long integer"; + this->out_stream = &stream; + put_table(table_name); + this->out_stream = nullptr; } -void BaseExpression::put_type(unsigned long val, PT::TextStream & stream) + +void BaseExpression::table_to_stream(pt::TextStream & stream, const pt::WTextStream & table_name) { - stream << "unsigned long integer"; + this->out_stream = &stream; + put_table(table_name); + this->out_stream = nullptr; } -void BaseExpression::put_type(long long val, PT::TextStream & stream) + +void BaseExpression::table_with_index_to_stream(pt::TextStream & stream, const wchar_t * table_name, int index) { - stream << "very long integer"; + this->out_stream = &stream; + put_table_with_index(table_name, index); + this->out_stream = nullptr; } -void BaseExpression::put_type(unsigned long long val, PT::TextStream & stream) + +void BaseExpression::table_with_index_to_stream(pt::TextStream & stream, const pt::WTextStream & table_name, int index) { - stream << "unsigned very long integer"; + this->out_stream = &stream; + put_table_with_index(table_name, index); + this->out_stream = nullptr; } -void BaseExpression::put_type(float val, PT::TextStream & stream) + +void BaseExpression::table_with_index_and_field_to_stream(pt::TextStream & stream, const wchar_t * table_name, int index, const wchar_t * field_name, const FT & field_type) { - stream << "float"; + this->out_stream = &stream; + put_table_with_index_and_field(table_name, index, field_name, field_type); + this->out_stream = nullptr; } -void BaseExpression::put_type(double val, PT::TextStream & stream) + +void BaseExpression::table_with_index_and_field_to_stream(pt::TextStream & stream, const pt::WTextStream & table_name, int index, const wchar_t * field_name, const FT & field_type) { - stream << "double"; + this->out_stream = &stream; + put_table_with_index_and_field(table_name, index, field_name, field_type); + this->out_stream = nullptr; } -void BaseExpression::put_type(long double val, PT::TextStream & stream) + +void BaseExpression::table_and_field_to_stream(pt::TextStream & stream, const wchar_t * table_name, const wchar_t * field_name, const FT & field_type) { - stream << "long double"; + this->out_stream = &stream; + put_table_and_field(table_name, field_name, field_type); + this->out_stream = nullptr; } -//void BaseExpression::put_type(void* val, PT::TextStream & stream) -//{ -//} - -void BaseExpression::put_type(const PT::Date & date, PT::TextStream & stream) +void BaseExpression::table_and_field_to_stream(pt::TextStream & stream, const pt::WTextStream & table_name, const wchar_t * field_name, const FT & field_type) { - stream << "date"; + this->out_stream = &stream; + put_table_and_field(table_name, field_name, field_type); + this->out_stream = nullptr; } -void BaseExpression::put_type(const Model & model, PT::TextStream & stream) + + +bool BaseExpression::is_empty_field(const wchar_t * value) { - stream << "object"; + return (!value || *value == '\0'); } diff --git a/src/baseexpression.h b/src/baseexpression.h index 66372cd..c702422 100644 --- a/src/baseexpression.h +++ b/src/baseexpression.h @@ -41,7 +41,7 @@ #include "date/date.h" #include "morm_types.h" #include "modelenv.h" - +#include "ft.h" namespace morm @@ -60,11 +60,14 @@ public: virtual void set_work_mode(int work_mode); virtual int get_work_mode(); + virtual pt::TextStream * get_text_stream(); + virtual void set_text_stream(pt::TextStream * out_stream); + virtual void clear(); - virtual void generate_from_model(PT::TextStream & stream, Model & model); + virtual void generate_from_model(pt::TextStream & stream, Model & model); - virtual PT::TextStream * get_current_stream(); + virtual pt::TextStream * get_current_stream(); // rename me virtual void allow_to_use_prefix(bool use_prefix); @@ -73,25 +76,25 @@ public: template - void field(const wchar_t * field_name, const FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key, ModelEnv * model_env) + void field(const wchar_t * field_name, const FieldValue & field_value, const FT & field_type, ModelEnv * model_env) { - if( out_stream && can_field_be_generated(insertable, updatable, is_primary_key) ) + if( out_stream && can_field_be_generated(field_type) ) { field_before(); if( work_mode == MORM_WORK_MODE_MODEL_FIELDS ) { - put_field_name(field_name, model_env); + put_field_name_and_table_if_needed(field_name, field_type, model_env); } else if( work_mode == MORM_WORK_MODE_MODEL_SAVE_FIELDS ) { - save_foreign_key(field_name, model_env); + save_foreign_key(field_name, field_type, model_env); } else if( work_mode == MORM_WORK_MODE_MODEL_VALUES ) { - put_field_value(field_value); + put_field_value_or_null(field_value, field_type, model_env); } else if( work_mode == MORM_WORK_MODE_MODEL_FIELDS_VALUES ) @@ -100,18 +103,18 @@ public: { if( (size_t)model_env->field_index < model_env->set_field_name_helper->size() ) { - put_field_name((*model_env->set_field_name_helper)[model_env->field_index], model_env); + put_field_name_and_table_if_needed((*model_env->set_field_name_helper)[model_env->field_index], field_type, model_env); put_name_value_separator(); - put_field_value(field_value); + put_field_value_or_null(field_value, field_type, model_env); } model_env->field_index += 1; } else { - put_field_name(field_name, model_env); + put_field_name_and_table_if_needed(field_name, field_type, model_env); put_name_value_separator(); - put_field_value(field_value); + put_field_value_or_null(field_value, field_type, model_env); } } @@ -121,43 +124,60 @@ public: } + + template - void field_in(PT::TextStream & stream, const wchar_t * field_name, const std::set & container, ModelEnv * model_env) + void put_field_value_or_null(const FieldValue & field_value, const FT & field_type, ModelEnv * model_env) + { + if( field_type.is_primary_key() ) + { + if( model_env && model_env->has_primary_key_set ) + put_field_value(field_value, field_type); + else + put_null_value(); + } + else + { + put_field_value(field_value, field_type); + } + } + + template + void field_in(pt::TextStream & stream, const wchar_t * field_name, const std::set & container, ModelEnv * model_env) { field_in_generic>(stream, field_name, container, model_env); } template - void field_in(PT::TextStream & stream, const wchar_t * field_name, const std::list & container, ModelEnv * model_env) + void field_in(pt::TextStream & stream, const wchar_t * field_name, const std::list & container, ModelEnv * model_env) { field_in_generic>(stream, field_name, container, model_env); } template - void field_in(PT::TextStream & stream, const wchar_t * field_name, const std::vector & container, ModelEnv * model_env) + void field_in(pt::TextStream & stream, const wchar_t * field_name, const std::vector & container, ModelEnv * model_env) { field_in_generic>(stream, field_name, container, model_env); } template - void field_list(const wchar_t * field_name, ModelContainer & field_value, bool insertable, bool updatable, bool is_primary_key, - ModelConnector * model_connector, ModelEnv * model_env) + void field_list(const wchar_t * field_name, ModelContainer & field_value, const FT & field_type, ModelConnector * model_connector, ModelEnv * model_env) { - if( out_stream && can_field_be_generated(insertable, updatable, is_primary_key) ) + if( out_stream && can_field_be_generated(field_type) ) { field_before(); // if( work_mode == MORM_WORK_MODE_MODEL_FIELDS ) // { -// put_field_name(field_name); +// put_field_name_and_table_if_needed(field_name); // } // else if( work_mode == MORM_WORK_MODE_MODEL_FIELDS_VALUES ) { - put_field_name(field_name, model_env); + put_field_name_and_table_if_needed(field_name, field_type, model_env); put_name_value_separator(); put_field_value_list(field_value, model_connector, model_env); } @@ -167,15 +187,15 @@ public: } template - void field_model(const wchar_t * field_name, ModelClass & field_model, bool insertable, bool updatable, bool is_primary_key, ModelEnv * model_env) + void field_model(const wchar_t * field_name, ModelClass & field_model, const FT & field_type, ModelEnv * model_env) { - if( out_stream && can_field_be_generated(insertable, updatable, is_primary_key) ) + if( out_stream && can_field_be_generated(field_type) ) { field_before(); if( work_mode == MORM_WORK_MODE_MODEL_FIELDS ) { - put_field_name(field_name, model_env); + put_field_name_and_table_if_needed(field_name, field_type, model_env); } else if( work_mode == MORM_WORK_MODE_MODEL_VALUES ) @@ -185,7 +205,7 @@ public: else if( work_mode == MORM_WORK_MODE_MODEL_FIELDS_VALUES ) { - put_field_name(field_name, model_env); + put_field_name_and_table_if_needed(field_name, field_type, model_env); put_name_value_separator(); generate_from_model(field_model); } @@ -195,53 +215,71 @@ public: } template - void field_to_stream(PT::TextStream & stream, const wchar_t * field_name, const FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key, - ModelEnv * model_env) + void field_to_stream(pt::TextStream & stream, const wchar_t * field_name, const FieldValue & field_value, const FT & field_type, ModelEnv * model_env) { this->out_stream = &stream; - field(field_name, field_value, insertable, updatable, is_primary_key, model_env); + field(field_name, field_value, field_type, model_env); this->out_stream = nullptr; } + virtual void put_schema_table(const wchar_t * schema_name, const wchar_t * table_name); + virtual void put_schema_table(const pt::WTextStream & schema_name, const pt::WTextStream & table_name); + virtual void put_table(const wchar_t * table_name); + virtual void put_table(const pt::WTextStream & table_name); + virtual void put_table_with_index(const wchar_t * table_name, int index); + virtual void put_table_with_index(const pt::WTextStream & table_name, int index); + virtual void put_table_with_index_and_field(const wchar_t * table_name, int index, const wchar_t * field_name, const FT & field_type); + virtual void put_table_with_index_and_field(const pt::WTextStream & table_name, int index, const wchar_t * field_name, const FT & field_type); + virtual void put_table_and_field(const wchar_t * table_name, const wchar_t * field_name, const FT & field_type); + virtual void put_table_and_field(const pt::WTextStream & table_name, const wchar_t * field_name, const FT & field_type); + + virtual void schema_table_to_stream(pt::TextStream & stream, const wchar_t * schema_name, const wchar_t * table_name); + virtual void schema_table_to_stream(pt::TextStream & stream, const pt::WTextStream & schema_name, const pt::WTextStream & table_name); + virtual void table_to_stream(pt::TextStream & stream, const wchar_t * table_name); + virtual void table_to_stream(pt::TextStream & stream, const pt::WTextStream & table_name); + virtual void table_with_index_to_stream(pt::TextStream & stream, const wchar_t * table_name, int index); + virtual void table_with_index_to_stream(pt::TextStream & stream, const pt::WTextStream & table_name, int index); + virtual void table_with_index_and_field_to_stream(pt::TextStream & stream, const wchar_t * table_name, int index, const wchar_t * field_name, const FT & field_type); + virtual void table_with_index_and_field_to_stream(pt::TextStream & stream, const pt::WTextStream & table_name, int index, const wchar_t * field_name, const FT & field_type); + virtual void table_and_field_to_stream(pt::TextStream & stream, const wchar_t * table_name, const wchar_t * field_name, const FT & field_type); + virtual void table_and_field_to_stream(pt::TextStream & stream, const pt::WTextStream & table_name, const wchar_t * field_name, const FT & field_type); + + /* * IMPLEMENT ME * esc for: signed char, wchar_t, char16_t, char32_t * */ - virtual void esc(char val, PT::TextStream & stream); - virtual void esc(unsigned char val, PT::TextStream & stream); + virtual void esc(char val, pt::TextStream & stream, const FT & field_type = FT::default_type); + virtual void esc(unsigned char val, pt::TextStream & stream, const FT & field_type = FT::default_type); - virtual void esc(wchar_t val, PT::TextStream & stream); + virtual void esc(wchar_t val, pt::TextStream & stream, const FT & field_type = FT::default_type); - virtual void esc(const std::wstring & val, PT::TextStream & stream); - virtual void esc(const wchar_t * val, PT::TextStream & stream); + virtual void esc(const std::wstring & val, pt::TextStream & stream, const FT & field_type = FT::default_type); + virtual void esc(const wchar_t * val, pt::TextStream & stream, const FT & field_type = FT::default_type); - virtual void esc(const std::string & val, PT::TextStream & stream); - virtual void esc(const char * val, PT::TextStream & stream); + virtual void esc(const std::string & val, pt::TextStream & stream, const FT & field_type = FT::default_type); + virtual void esc(const char * val, pt::TextStream & stream, const FT & field_type = FT::default_type); - virtual void esc(bool val, PT::TextStream & stream); - virtual void esc(short val, PT::TextStream & stream); - virtual void esc(unsigned short val, PT::TextStream & stream); - virtual void esc(int val, PT::TextStream & stream); - virtual void esc(unsigned int val, PT::TextStream & stream); - virtual void esc(long val, PT::TextStream & stream); - virtual void esc(unsigned long val, PT::TextStream & stream); - virtual void esc(long long val, PT::TextStream & stream); - virtual void esc(unsigned long long val, PT::TextStream & stream); - virtual void esc(float val, PT::TextStream & stream); - virtual void esc(double val, PT::TextStream & stream); - virtual void esc(long double val, PT::TextStream & stream); - //virtual void esc(void* val, PT::TextStream & stream); + virtual void esc(bool val, pt::TextStream & stream, const FT & field_type = FT::default_type); + virtual void esc(short val, pt::TextStream & stream, const FT & field_type = FT::default_type); + virtual void esc(unsigned short val, pt::TextStream & stream, const FT & field_type = FT::default_type); + virtual void esc(int val, pt::TextStream & stream, const FT & field_type = FT::default_type); + virtual void esc(unsigned int val, pt::TextStream & stream, const FT & field_type = FT::default_type); + virtual void esc(long val, pt::TextStream & stream, const FT & field_type = FT::default_type); + virtual void esc(unsigned long val, pt::TextStream & stream, const FT & field_type = FT::default_type); + virtual void esc(long long val, pt::TextStream & stream, const FT & field_type = FT::default_type); + virtual void esc(unsigned long long val, pt::TextStream & stream, const FT & field_type = FT::default_type); + virtual void esc(float val, pt::TextStream & stream, const FT & field_type = FT::default_type); + virtual void esc(double val, pt::TextStream & stream, const FT & field_type = FT::default_type); + virtual void esc(long double val, pt::TextStream & stream, const FT & field_type = FT::default_type); + //virtual void esc(void* val, pt::TextStream & stream); - virtual void esc(const PT::Date & date, PT::TextStream & stream); - virtual void esc(const PT::TextStream & val,PT::TextStream & stream); - - virtual bool is_long_field_name(const wchar_t * field_name); - virtual bool is_long_field_name(const PT::TextStream & table_name); - - virtual bool is_long_table_name(const wchar_t * field_name); - virtual bool is_long_table_name(const PT::TextStream & table_name); + virtual void esc(const pt::Date & date, pt::TextStream & stream, const FT & field_type = FT::default_type); + virtual void esc(const pt::TextStream & val,pt::TextStream & stream, const FT & field_type = FT::default_type); + virtual void esc(const pt::WTextStream & val,pt::TextStream & stream, const FT & field_type = FT::default_type); + virtual void esc(const pt::Space & space, pt::TextStream & stream, const FT & field_type = FT::default_type); @@ -250,7 +288,7 @@ protected: int work_mode; /* what to do: generating fields list, values list or fields-values list */ bool is_first_field; - PT::TextStream * out_stream; + pt::TextStream * out_stream; bool use_prefix; @@ -258,30 +296,34 @@ protected: 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); + virtual bool can_field_be_generated(const FT &); virtual void field_before(); virtual void field_after(); - //void field(const wchar_t * field_name, Model & field, bool insertable = true, bool updatable = true); - - virtual void put_field_name(const wchar_t * field_name, ModelEnv * model_env); - - virtual void save_foreign_key(const wchar_t * field_name, ModelEnv * model_env); + virtual void put_field_name_and_table_if_needed(const wchar_t * field_name, const FT & field_type, ModelEnv * model_env); + virtual void put_field_name(const wchar_t * field_name, const FT & field_type, ModelEnv * model_env); + virtual void save_foreign_key(const wchar_t * field_name, const FT & field_type, ModelEnv * model_env); virtual void dump_additional_info(Model & model); template - void put_field_value(const FieldValue & field_value) + void put_field_value(const FieldValue & field_value, const FT & field_type) { if( out_stream ) { - before_field_value(field_value); - esc(field_value, *out_stream); - after_field_value(field_value); + before_field_value(field_value, field_type); + esc(field_value, *out_stream, field_type); + after_field_value(field_value, field_type); } } + virtual void put_null_value() + { + (*out_stream) << "null"; + } + + virtual void before_field_value_list() { } @@ -323,16 +365,7 @@ protected: field_value_list_separator(); } - //ModelEnv model_env_local(*model_env); - //m.model_env = &model_env_local; - //before_field_value(field_value); - //m.set_connector(model_connector); - - put_field_value(m); - - //generate_from_model(m); - //m.model_env = nullptr; - //after_field_value(field_value); + put_field_value(m, FT::default_type); is_first = false; } @@ -358,11 +391,12 @@ protected: ModelEnv model_env_local(*model_env); m.model_env = &model_env_local; - //before_field_value(field_value); + m.model_env->has_primary_key_set = m.get_has_primary_key_set(); m.set_connector(model_connector); + generate_from_model(m); + m.model_env = nullptr; - //after_field_value(field_value); is_first = false; } @@ -451,7 +485,7 @@ protected: put_field_value_list_non_model(field_value, model_connector); } - void put_field_value_list(std::vector & field_value, ModelConnector * model_connector, ModelEnv *) + void put_field_value_list(std::vector & field_value, ModelConnector * model_connector, ModelEnv *) { put_field_value_list_non_model(field_value, model_connector); } @@ -540,7 +574,7 @@ protected: put_field_value_list_non_model(field_value, model_connector); } - void put_field_value_list(std::list & field_value, ModelConnector * model_connector, ModelEnv *) + void put_field_value_list(std::list & field_value, ModelConnector * model_connector, ModelEnv *) { put_field_value_list_non_model(field_value, model_connector); } @@ -549,7 +583,7 @@ protected: // used in 'in()' statements, may should be renamed? template - void field_in_generic(PT::TextStream & stream, const wchar_t * field_name, const Container & container, ModelEnv * model_env) + void field_in_generic(pt::TextStream & stream, const wchar_t * field_name, const Container & container, ModelEnv * model_env) { // IMPROVE ME // what about if container is empty? @@ -557,7 +591,7 @@ protected: this->out_stream = &stream; field_before(); - put_field_name(field_name, model_env); + put_field_name_and_table_if_needed(field_name, FT::default_type, model_env); put_name_value_separator(); bool is_first = true; @@ -570,7 +604,7 @@ protected: field_value_list_separator(); } - put_field_value(v); + put_field_value(v, FT::default_type); is_first = false; } @@ -580,50 +614,50 @@ protected: } - /* - * escaping column names in a case when using short form - just only column_name - * [before_short_field_name]column_name[after_short_field_name] - */ - virtual void before_short_field_name(); - virtual void after_short_field_name(); + virtual void schema_table_separator(); + virtual void table_field_separator(); - /* - * escaping column names in a case when using long form: table_name.column_name - * [before_first_part_long_field_name]table_name[after_first_part_long_field_name].[before_second_part_long_field_name]column_name[after_second_part_long_field_name] - * - */ - virtual void before_first_part_long_field_name(); - virtual void after_first_part_long_field_name(); - virtual void before_second_part_long_field_name(); - virtual void after_second_part_long_field_name(); + virtual void before_schema_name(); + virtual void after_schema_name(); - virtual const wchar_t * put_long_part_field_name(const wchar_t * field_name); - virtual void put_long_field_name(const wchar_t * field_name); - virtual void put_short_field_name(const wchar_t * field_name, ModelEnv * model_env); + virtual void before_table_name(); + virtual void after_table_name(); - virtual void before_field_value(const std::wstring &); - virtual void after_field_value(const std::wstring &); + virtual void before_field_name(); + virtual void after_field_name(); - virtual void before_field_value(const std::string &); - virtual void after_field_value(const std::string &); - virtual void before_field_value(const wchar_t *); - virtual void after_field_value(const wchar_t *); + virtual void before_field_value(const std::wstring &, const FT & field_type); + virtual void after_field_value(const std::wstring &, const FT & field_type); - virtual void before_field_value(const char *); - virtual void after_field_value(const char *); + virtual void before_field_value(const std::string &, const FT & field_type); + virtual void after_field_value(const std::string &, const FT & field_type); - virtual void before_field_value(const PT::Date &); - virtual void after_field_value(const PT::Date &); + virtual void before_field_value(const wchar_t *, const FT & field_type); + virtual void after_field_value(const wchar_t *, const FT & field_type); + virtual void before_field_value(const char *, const FT & field_type); + virtual void after_field_value(const char *, const FT & field_type); + + virtual void before_field_value(wchar_t, const FT & field_type); + virtual void after_field_value(wchar_t, const FT & field_type); + + virtual void before_field_value(char, const FT & field_type); + virtual void after_field_value(char, const FT & field_type); + + virtual void before_field_value(const pt::Date &, const FT & field_type); + virtual void after_field_value(const pt::Date &, const FT & field_type); + + virtual void before_field_value(const pt::Space &, const FT & field_type); + virtual void after_field_value(const pt::Space &, const FT & field_type); template - void before_field_value(const FieldValue &) + void before_field_value(const FieldValue &, const FT & field_type) { } template - void after_field_value(const FieldValue &) + void after_field_value(const FieldValue &, const FT & field_type) { } @@ -635,44 +669,55 @@ protected: * put_type for: signed char, wchar_t, char16_t, char32_t * */ - virtual void put_type(char val, PT::TextStream & stream); - virtual void put_type(unsigned char val, PT::TextStream & stream); +// virtual void put_type(char val, pt::TextStream & stream); +// virtual void put_type(unsigned char val, pt::TextStream & stream); +// +// virtual void put_type(const std::wstring & val, pt::TextStream & stream); +// virtual void put_type(const wchar_t * val, pt::TextStream & stream); +// +// virtual void put_type(const std::string & val, pt::TextStream & stream); +// virtual void put_type(const char * val, pt::TextStream & stream); +// +// virtual void put_type(bool val, pt::TextStream & stream); +// virtual void put_type(short val, pt::TextStream & stream); +// virtual void put_type(unsigned short val, pt::TextStream & stream); +// virtual void put_type(int val, pt::TextStream & stream); +// virtual void put_type(unsigned int val, pt::TextStream & stream); +// virtual void put_type(long val, pt::TextStream & stream); +// virtual void put_type(unsigned long val, pt::TextStream & stream); +// virtual void put_type(long long val, pt::TextStream & stream); +// virtual void put_type(unsigned long long val, pt::TextStream & stream); +// virtual void put_type(float val, pt::TextStream & stream); +// virtual void put_type(double val, pt::TextStream & stream); +// virtual void put_type(long double val, pt::TextStream & stream); + //virtual void put_type(void* val, pt::TextStream & stream); - virtual void put_type(const std::wstring & val, PT::TextStream & stream); - virtual void put_type(const wchar_t * val, PT::TextStream & stream); +// virtual void put_type(const pt::Date & date, pt::TextStream & stream); +// virtual void put_type(const Model & model, pt::TextStream & stream); +// +// template +// void put_type(const std::list & model, pt::TextStream & stream) +// { +// stream << "table"; // may just use std::list? +// } +// +// template +// void put_type(const std::vector & model, pt::TextStream & stream) +// { +// stream << "table"; // may just just std::vector? +// } - virtual void put_type(const std::string & val, PT::TextStream & stream); - virtual void put_type(const char * val, PT::TextStream & stream); - virtual void put_type(bool val, PT::TextStream & stream); - virtual void put_type(short val, PT::TextStream & stream); - virtual void put_type(unsigned short val, PT::TextStream & stream); - virtual void put_type(int val, PT::TextStream & stream); - virtual void put_type(unsigned int val, PT::TextStream & stream); - virtual void put_type(long val, PT::TextStream & stream); - virtual void put_type(unsigned long val, PT::TextStream & stream); - virtual void put_type(long long val, PT::TextStream & stream); - virtual void put_type(unsigned long long val, PT::TextStream & stream); - virtual void put_type(float val, PT::TextStream & stream); - virtual void put_type(double val, PT::TextStream & stream); - virtual void put_type(long double val, PT::TextStream & stream); - //virtual void put_type(void* val, PT::TextStream & stream); - virtual void put_type(const PT::Date & date, PT::TextStream & stream); - virtual void put_type(const Model & model, PT::TextStream & stream); + virtual void before_field_value_string(const FT & field_type); + virtual void after_field_value_string(const FT & field_type); - template - void put_type(const std::list & model, PT::TextStream & stream) - { - stream << "table"; // may just use std::list? - } + char char_to_hex_part(char c); + void char_to_hex(char c, pt::TextStream & stream); - template - void put_type(const std::vector & model, PT::TextStream & stream) - { - stream << "table"; // may just just std::vector? - } + void esc(const wchar_t * val, bool has_known_length, size_t len, pt::TextStream & stream, const FT & field_type = FT::default_type); + bool is_empty_field(const wchar_t * value); }; } diff --git a/src/clearer.cpp b/src/clearer.cpp index 8fe9f1c..97a2270 100644 --- a/src/clearer.cpp +++ b/src/clearer.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2018, Tomasz Sowa + * Copyright (c) 2018-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -61,6 +61,10 @@ void Clearer::clear_value(unsigned char & field_value) field_value = 0; } +void Clearer::clear_value(wchar_t & field_value) +{ + field_value = 0; +} void Clearer::clear_value(std::wstring & field_value) { @@ -134,11 +138,16 @@ void Clearer::clear_value(long double & field_value) field_value = 0.0; } -void Clearer::clear_value(PT::Date & field_value) +void Clearer::clear_value(pt::Date & field_value) { field_value.Clear(); } +void Clearer::clear_value(pt::Space & field_value) +{ + field_value.clear(); +} + void Clearer::clear_model(Model & field_value) { field_value.clear(); diff --git a/src/clearer.h b/src/clearer.h index 9f1efbb..5427de2 100644 --- a/src/clearer.h +++ b/src/clearer.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2018, Tomasz Sowa + * Copyright (c) 2018-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,6 +37,7 @@ #include #include "date/date.h" +#include "space/space.h" namespace morm @@ -53,6 +54,7 @@ public: virtual void clear_value(char & field_value); virtual void clear_value(unsigned char & field_value); + virtual void clear_value(wchar_t & 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); @@ -67,7 +69,8 @@ public: 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 clear_value(pt::Date & field_value); + virtual void clear_value(pt::Space & field_value); virtual void clear_model(Model & field_value); diff --git a/src/cursor.h b/src/cursor.h index 47d639c..b3ec707 100644 --- a/src/cursor.h +++ b/src/cursor.h @@ -193,7 +193,7 @@ public: if( !cursor_helper.has_autogenerated_select && cursor_helper.use_table_prefix_for_fetching_values ) { - result.prepare_table_names(); + result.model_env->add_table_name_to_finder_helper(); } result.before_select(); @@ -369,7 +369,7 @@ protected: if( !cursor_helper.has_autogenerated_select && cursor_helper.use_table_prefix_for_fetching_values ) { - added_model.prepare_table_names(); + added_model.model_env->add_table_name_to_finder_helper(); } added_model.before_select(); diff --git a/src/dbconnector.cpp b/src/dbconnector.cpp index c1ac2cb..86a292c 100644 --- a/src/dbconnector.cpp +++ b/src/dbconnector.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2018-2019, Tomasz Sowa + * Copyright (c) 2018-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,6 +34,7 @@ #include #include +#include "space/spaceparser.h" #include "dbconnector.h" #include "dbexpression.h" #include "model.h" @@ -66,13 +67,13 @@ DbConnector::~DbConnector() } -void DbConnector::set_logger(PT::Log * log) +void DbConnector::set_logger(pt::Log * log) { this->log = log; } -void DbConnector::set_logger(PT::Log & log) +void DbConnector::set_logger(pt::Log & log) { this->log = &log; } @@ -84,7 +85,29 @@ void DbConnector::set_log_queries(bool log_queries) } -bool DbConnector::query(const PT::TextStream & stream, QueryResult & query_result) +bool DbConnector::query(const pt::TextStream & stream) +{ + std::unique_ptr query_result_ptr(create_query_result()); + return query(stream, *query_result_ptr); +} + + +bool DbConnector::query(const std::string & query_str) +{ + std::unique_ptr query_result_ptr(create_query_result()); + return query(query_str, *query_result_ptr); +} + + +bool DbConnector::query(const char * query_str) +{ + std::unique_ptr query_result_ptr(create_query_result()); + return query(query_str, *query_result_ptr); +} + + + +bool DbConnector::query(const pt::TextStream & stream, QueryResult & query_result) { std::string query_str; stream.to_string(query_str); @@ -129,22 +152,22 @@ bool DbConnector::query_remove(const char * query_str, QueryResult & query_resul -bool DbConnector::query_select(const PT::TextStream & stream, QueryResult & query_result) +bool DbConnector::query_select(const pt::TextStream & stream, QueryResult & query_result) { return query(stream, query_result); } -bool DbConnector::query_update(const PT::TextStream & stream, QueryResult & query_result) +bool DbConnector::query_update(const pt::TextStream & stream, QueryResult & query_result) { return query(stream, query_result); } -bool DbConnector::query_insert(const PT::TextStream & stream, QueryResult & query_result) +bool DbConnector::query_insert(const pt::TextStream & stream, QueryResult & query_result) { return query(stream, query_result); } -bool DbConnector::query_remove(const PT::TextStream & stream, QueryResult & query_result) +bool DbConnector::query_remove(const pt::TextStream & stream, QueryResult & query_result) { return query(stream, query_result); } @@ -158,7 +181,7 @@ DbExpression * DbConnector::get_expression() } -void DbConnector::generate_select_columns(PT::TextStream & stream, Model & model) +void DbConnector::generate_select_columns(pt::TextStream & stream, Model & model) { allocate_default_expression_if_needed(); @@ -173,7 +196,7 @@ void DbConnector::generate_select_columns(PT::TextStream & stream, Model & model } -void DbConnector::generate_insert_query(PT::TextStream & stream, Model & model) +void DbConnector::generate_insert_query(pt::TextStream & stream, Model & model) { allocate_default_expression_if_needed(); @@ -183,7 +206,7 @@ void DbConnector::generate_insert_query(PT::TextStream & stream, Model & model) db_expression->allow_to_use_prefix(false); stream << "insert into "; - model.table_name(stream); + db_expression->schema_table_to_stream(stream, model.model_env->schema_name, model.model_env->table_name); stream << " ("; db_expression->set_work_mode(MORM_WORK_MODE_MODEL_FIELDS); @@ -198,7 +221,7 @@ void DbConnector::generate_insert_query(PT::TextStream & stream, Model & model) } -void DbConnector::generate_update_query(PT::TextStream & stream, Model & model) +void DbConnector::generate_update_query(pt::TextStream & stream, Model & model) { allocate_default_expression_if_needed(); @@ -208,7 +231,7 @@ void DbConnector::generate_update_query(PT::TextStream & stream, Model & model) db_expression->allow_to_use_prefix(false); stream << "update "; - model.table_name(stream); + db_expression->schema_table_to_stream(stream, model.model_env->schema_name, model.model_env->table_name); stream << " set "; db_expression->set_work_mode(MORM_WORK_MODE_MODEL_FIELDS_VALUES); @@ -223,7 +246,7 @@ void DbConnector::generate_update_query(PT::TextStream & stream, Model & model) } -void DbConnector::generate_remove_query(PT::TextStream & stream, Model & model) +void DbConnector::generate_remove_query(pt::TextStream & stream, Model & model) { allocate_default_expression_if_needed(); @@ -233,7 +256,8 @@ void DbConnector::generate_remove_query(PT::TextStream & stream, Model & model) db_expression->allow_to_use_prefix(false); stream << "delete from "; - model.table_name(stream); + db_expression->schema_table_to_stream(stream, model.model_env->schema_name, model.model_env->table_name); + stream << " where "; db_expression->set_work_mode(MORM_WORK_MODE_MODEL_FIELDS_VALUES); db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_PRIMARY_KEY); @@ -241,7 +265,7 @@ void DbConnector::generate_remove_query(PT::TextStream & stream, Model & model) } } -bool DbConnector::insert(PT::TextStream & stream, Model & model) +bool DbConnector::insert(pt::TextStream & stream, Model & model) { std::unique_ptr query_result_ptr(create_query_result()); @@ -250,7 +274,7 @@ bool DbConnector::insert(PT::TextStream & stream, Model & model) } -bool DbConnector::update(PT::TextStream & stream, Model & model) +bool DbConnector::update(pt::TextStream & stream, Model & model) { std::unique_ptr query_result_ptr(create_query_result()); @@ -259,7 +283,7 @@ bool DbConnector::update(PT::TextStream & stream, Model & model) } -bool DbConnector::remove(PT::TextStream & stream, Model & model) +bool DbConnector::remove(pt::TextStream & stream, Model & model) { std::unique_ptr query_result_ptr(create_query_result()); @@ -289,52 +313,310 @@ void DbConnector::allocate_default_expression_if_needed() } - - - - - -void DbConnector::get_value(const char * value_str, char & field_value) +char DbConnector::unescape_hex_char_part(char hex) { - field_value = *value_str; - value_str += 1; - - if( *value_str != 0 ) + if( hex>='0' && hex<='9' ) { - // value has more than one charater, put some error? + return hex - '0'; + } + else + if( hex>='a' && hex<='f' ) + { + return hex - 'a' + 10; + } + else + if( hex>='A' && hex<='F' ) + { + return hex - 'A' + 10; + } + else + { + if( log ) + { + (*log) << pt::Log::log2 << "Morm: incorrect character when reading a hex string, char code: " << (int)(unsigned char)hex; + + if( hex >= 32 ) + { + (*log) << " '" << hex << "'"; + } + + (*log) << pt::Log::logend; + } + } + + return 0; +} + + +char DbConnector::unescape_hex_char(char char1, char char2) +{ + int c1 = unescape_hex_char_part(char1); + int c2 = unescape_hex_char_part(char2); + + return static_cast(((c1 << 4) | c2)); +} + + +void DbConnector::unescape_hex_string(const char * str, std::string & out) +{ + for(size_t i=0 ; str[i] != 0 ; i+=2 ) + { + out += unescape_hex_char(str[i], str[i+1]); + } +} + + +void DbConnector::unescape_hex_string(const char * str, std::wstring & out, const FT & field_type) +{ + if( field_type.use_utf8() ) + { + size_t len; + wchar_t c; + + while( *str != 0 && (len = unescape_hex_char(str, c, field_type)) > 0 ) + { + out += c; + str += len; + } + } + else + { + for(size_t i=0 ; str[i] != 0 ; i+=2 ) + { + out += static_cast(static_cast(unescape_hex_char(str[i], str[i+1]))); + } + } +} + + +void DbConnector::unescape_bin_string(const char * str, std::string & out) +{ + unescape_hex_string(str, out); +} + + +void DbConnector::unescape_bin_string(const char * str, std::wstring & out, const FT & field_type) +{ + unescape_hex_string(str, out, field_type); +} + + +// returns how many characters have been provided to utf8_str buffer +// min size of utf8_str should be 5 bytes (max 4 bytes for utf8 sequence + terminating null) +size_t DbConnector::unescape_hex_char(const char * value_str, char * utf8_str, size_t utf8_str_max_len) +{ + size_t value_str_index = 0; + size_t utf8_str_index = 0; + + utf8_str[0] = 0; + + while( utf8_str_index + 1 < utf8_str_max_len ) + { + if( value_str[value_str_index] != 0 && value_str[value_str_index+1] != 0 ) + { + utf8_str[utf8_str_index] = unescape_hex_char(value_str[value_str_index], value_str[value_str_index+1]); + utf8_str[utf8_str_index+1] = 0; + } + else + { + break; + } + + value_str_index += 2; + utf8_str_index += 1; + } + + return utf8_str_index; +} + + +// CHECKME need to be tested +// returns how many characters were used from value_str +size_t DbConnector::unescape_hex_char(const char * value_str, wchar_t & field_value, const FT & field_type) +{ + size_t len = 0; + + if( field_type.use_utf8() ) + { + char utf8_str[4 + 1]; // max utf8 sequence length + terminating zero + size_t utf8_str_len = unescape_hex_char(value_str, utf8_str, sizeof(utf8_str) / sizeof(char)); + + int value_int; + bool is_correct; + len = pt::utf8_to_int(utf8_str, utf8_str_len, value_int, is_correct); + len = len * 2; + + if( is_correct ) + { + field_value = static_cast(value_int); + } + else + { + if( log ) + { + (*log) << pt::Log::log2 << "Morm: incorrect utf-8 sequence (ignoring)" << pt::Log::logend; + } + } + } + else + { + if( value_str[0] != 0 && value_str[1] != 0 ) + { + field_value = static_cast(static_cast(unescape_hex_char(value_str[0], value_str[1]))); + len = 2; + } + else + { + if( log ) + { + (*log) << pt::Log::log2 << "Morm: unexpected end of string (ignoring)" << pt::Log::logend; + } + } + } + + return len; +} + + +size_t DbConnector::unescape_bin_char(const char * value_str, wchar_t & field_value, const FT & field_type) +{ + return unescape_hex_char(value_str, field_value, field_type); +} + + + +// CHECKME need to be tested +void DbConnector::get_value(const char * value_str, char & field_value, const FT & field_type) +{ + wchar_t c; + + field_value = 0; + get_value(value_str, c, field_type); + + if( field_type.use_utf8() ) + { + if( c <= 127 ) + { + field_value = static_cast(c); + } + else + { + if( log ) + { + (*log) << pt::Log::log2 << "Morm: a character greater than 127 cannot be stored in char type, code point: " + << (int)c << " '" << c << "'" << pt::Log::logend; + } + } + } + else + { + field_value = static_cast(c); } } -void DbConnector::get_value(const char * value_str, unsigned char & field_value) +// CHECKME need to be tested +void DbConnector::get_value(const char * value_str, unsigned char & field_value, const FT & field_type) { - field_value = *(const unsigned char*)value_str; - value_str += 1; + char tmp_char; + get_value(value_str, tmp_char, field_type); - if( *value_str != 0 ) + field_value = static_cast(tmp_char); +} + + + +// CHECKME need to be tested +void DbConnector::get_value(const char * value_str, wchar_t & field_value, const FT & field_type) +{ + field_value = 0; + + if( field_type.is_binary() ) { - // value has more than one charater, put some error? + unescape_bin_char(value_str, field_value, field_type); + } + else + if( field_type.is_hexadecimal() ) + { + unescape_hex_char(value_str, field_value, field_type); + } + else + { + if( field_type.use_utf8() ) + { + int value_int; + bool is_correct; + + pt::utf8_to_int(value_str, value_int, is_correct); + + if( is_correct ) + { + field_value = static_cast(value_int); + } + else + { + // report an error? + } + } + else + { + field_value = static_cast((unsigned char)*value_str); + } } } -void DbConnector::get_value(const char * value_str, std::wstring & field_value) + +// CHECKME need to be tested +void DbConnector::get_value(const char * value_str, std::wstring & field_value, const FT & field_type) { - // CHECKME - // what about \0 in val_str? - // it is escaped somehow? - PT::UTF8ToWide(value_str, field_value); + if( field_type.is_binary() ) + { + unescape_bin_string(value_str, field_value, field_type); + } + else + if( field_type.is_hexadecimal() ) + { + unescape_hex_string(value_str, field_value, field_type); + } + else + { + if( field_type.use_utf8() ) + { + pt::utf8_to_wide(value_str, field_value); + } + else + { + for(size_t i=0 ; value_str[i] != 0 ; ++i) + { + field_value += static_cast(value_str[i]); + } + } + } } -void DbConnector::get_value(const char * value_str, std::string & field_value) +// CHECKME need to be tested +void DbConnector::get_value(const char * value_str, std::string & field_value, const FT & field_type) { - field_value = value_str; + if( field_type.is_binary() ) + { + unescape_bin_string(value_str, field_value); + } + else + if( field_type.is_hexadecimal() ) + { + unescape_hex_string(value_str, field_value); + } + else + { + field_value = value_str; + } } -void DbConnector::get_value(const char * value_str, bool & field_value) +void DbConnector::get_value(const char * value_str, bool & field_value, const FT & field_type) { // IMPROVE ME // this 't' is locale dependent @@ -342,90 +624,112 @@ void DbConnector::get_value(const char * value_str, bool & field_value) } -void DbConnector::get_value(const char * value_str, short & field_value) +void DbConnector::get_value(const char * value_str, short & field_value, const FT & field_type) { // IMPROVE ME give some overflow checking - field_value = (short)PT::Toi(value_str, 10); + field_value = (short)pt::Toi(value_str, 10); } -void DbConnector::get_value(const char * value_str, unsigned short & field_value) +void DbConnector::get_value(const char * value_str, unsigned short & field_value, const FT & field_type) { // IMPROVE ME give some overflow checking - field_value = (unsigned short)PT::Toui(value_str, 10); + field_value = (unsigned short)pt::Toui(value_str, 10); } -void DbConnector::get_value(const char * value_str, int & field_value) +void DbConnector::get_value(const char * value_str, int & field_value, const FT & field_type) { // IMPROVE ME give some overflow checking - field_value = PT::Toi(value_str, 10); + field_value = pt::Toi(value_str, 10); } -void DbConnector::get_value(const char * value_str, unsigned int & field_value) +void DbConnector::get_value(const char * value_str, unsigned int & field_value, const FT & field_type) { // IMPROVE ME give some overflow checking - field_value = PT::Toui(value_str, 10); + field_value = pt::Toui(value_str, 10); } -void DbConnector::get_value(const char * value_str, long & field_value) +void DbConnector::get_value(const char * value_str, long & field_value, const FT & field_type) { // IMPROVE ME give some overflow checking - field_value = PT::Tol(value_str, 10); + field_value = pt::Tol(value_str, 10); } -void DbConnector::get_value(const char * value_str, unsigned long & field_value) +void DbConnector::get_value(const char * value_str, unsigned long & field_value, const FT & field_type) { // IMPROVE ME give some overflow checking - field_value = PT::Toul(value_str, 10); + field_value = pt::Toul(value_str, 10); } -void DbConnector::get_value(const char * value_str, long long & field_value) +void DbConnector::get_value(const char * value_str, long long & field_value, const FT & field_type) { // IMPROVE ME give some overflow checking - field_value = PT::Toll(value_str, 10); + field_value = pt::Toll(value_str, 10); } -void DbConnector::get_value(const char * value_str, unsigned long long & field_value) +void DbConnector::get_value(const char * value_str, unsigned long long & field_value, const FT & field_type) { // IMPROVE ME give some overflow checking - field_value = PT::Toull(value_str, 10); + field_value = pt::Toull(value_str, 10); } -void DbConnector::get_value(const char * value_str, float & field_value) +void DbConnector::get_value(const char * value_str, float & field_value, const FT & field_type) { // IMPROVE ME give some overflow checking field_value = strtof(value_str, 0); } -void DbConnector::get_value(const char * value_str, double & field_value) +void DbConnector::get_value(const char * value_str, double & field_value, const FT & field_type) { // IMPROVE ME give some overflow checking field_value = strtod(value_str, 0); } -void DbConnector::get_value(const char * value_str, long double & field_value) +void DbConnector::get_value(const char * value_str, long double & field_value, const FT & field_type) { // IMPROVE ME give some overflow checking field_value = strtold(value_str, 0); } -void DbConnector::get_value(const char * value_str, PT::Date & field_value) +void DbConnector::get_value(const char * value_str, pt::Date & field_value, const FT & field_type) { // IMPROVE ME give some log if parsing failed field_value.Parse(value_str); } +void DbConnector::get_value(const char * value_str, pt::Space & field_value, const FT & field_type) +{ + field_value.clear(); + + if( *value_str != '\0' ) + { + pt::SpaceParser space_parser; + + if( space_parser.parse_space(value_str, field_value) != pt::SpaceParser::ok ) + { + field_value.clear(); + + if( log ) + { + (*log) << pt::Log::log2 << "Morm: I cannot correctly parse the Space struct from the datebase" + << ", the raw string is: " << value_str << pt::Log::logend; + } + } + } +} + + 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 7e2753d..e4f76e5 100644 --- a/src/dbconnector.h +++ b/src/dbconnector.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2018-2019, Tomasz Sowa + * Copyright (c) 2018-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,6 +38,7 @@ #include "textstream/textstream.h" #include "log/log.h" #include "queryresult.h" +#include "ft.h" namespace morm @@ -54,29 +55,29 @@ public: DbConnector(const DbConnector &); virtual ~DbConnector(); - virtual void set_logger(PT::Log * log); - virtual void set_logger(PT::Log & log); + virtual void set_logger(pt::Log * log); + virtual void set_logger(pt::Log & log); virtual void set_log_queries(bool log_queries); DbExpression * get_expression(); - //virtual void clear_last_query_result(); + virtual void generate_select_columns(pt::TextStream & stream, Model & model); + virtual void generate_insert_query(pt::TextStream & stream, Model & model); + virtual void generate_update_query(pt::TextStream & stream, Model & model); + virtual void generate_remove_query(pt::TextStream & stream, Model & model); - virtual void generate_select_columns(PT::TextStream & stream, Model & model); - virtual void generate_insert_query(PT::TextStream & stream, Model & model); - virtual void generate_update_query(PT::TextStream & stream, Model & model); - virtual void generate_remove_query(PT::TextStream & stream, Model & model); + virtual bool insert(pt::TextStream & stream, Model & model); + virtual bool update(pt::TextStream & stream, Model & model); + virtual bool remove(pt::TextStream & stream, Model & model); - virtual bool insert(PT::TextStream & stream, Model & model); - virtual bool update(PT::TextStream & stream, Model & model); - virtual bool remove(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::string & query_str); + virtual bool query(const char * query_str); virtual QueryResult * create_query_result() = 0; - virtual bool query(const PT::TextStream & stream, QueryResult & query_result); + virtual bool query(const pt::TextStream & stream, QueryResult & query_result); virtual bool query(const std::string & query_str, QueryResult & query_result); virtual bool query(const char * query_str, QueryResult & query_result); @@ -85,32 +86,35 @@ public: virtual bool query_insert(const char * query_str, QueryResult & query_result); virtual bool query_remove(const char * query_str, QueryResult & query_result); - virtual bool query_select(const PT::TextStream & stream, QueryResult & query_result); - virtual bool query_update(const PT::TextStream & stream, QueryResult & query_result); - virtual bool query_insert(const PT::TextStream & stream, QueryResult & query_result); - virtual bool query_remove(const PT::TextStream & stream, QueryResult & query_result); + virtual bool query_select(const pt::TextStream & stream, QueryResult & query_result); + virtual bool query_update(const pt::TextStream & stream, QueryResult & query_result); + virtual bool query_insert(const pt::TextStream & stream, QueryResult & query_result); + virtual bool query_remove(const pt::TextStream & stream, QueryResult & query_result); - 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, char & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, unsigned char & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, wchar_t & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, std::wstring & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, std::string & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, bool & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, short & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, unsigned short & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, int & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, unsigned int & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, long & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, unsigned long & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, long long & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, unsigned long long & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, float & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, double & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, long double & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, pt::Date & field_value, const FT & field_type = FT::default_type); + virtual void get_value(const char * value_str, pt::Space & field_value, const FT & field_type = FT::default_type); + // add get_value for pt::TextStream and pt::WTextStream template - void get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value) + bool get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value) { const char * val_str = query_last_sequence(sequence_table_name); @@ -120,9 +124,13 @@ public: if( log && log_queries ) { - (*log) << PT::Log::log3 << "Morm: sequence value: " << field_value << PT::Log::logend; + (*log) << pt::Log::log3 << "Morm: sequence value: " << field_value << pt::Log::logend; } + + return true; } + + return false; } @@ -130,7 +138,7 @@ protected: DbExpression * db_expression; bool expression_allocated; - PT::Log * log; + pt::Log * log; bool log_queries; @@ -140,6 +148,23 @@ protected: virtual const char * query_last_sequence(const wchar_t * sequence_table_name); + virtual void unescape_hex_string(const char * str, std::string & out); + virtual void unescape_hex_string(const char * str, std::wstring & out, const FT & field_type); + + virtual void unescape_bin_string(const char * str, std::string & out); + virtual void unescape_bin_string(const char * str, std::wstring & out, const FT & field_type); + + virtual size_t unescape_hex_char(const char * value_str, char * utf8_str, size_t utf8_str_max_len); + virtual size_t unescape_hex_char(const char * value_str, wchar_t & field_value, const FT & field_type); + virtual size_t unescape_bin_char(const char * value_str, wchar_t & field_value, const FT & field_type); + +private: + + char unescape_hex_char_part(char hex); + char unescape_hex_char(char char1, char char2); + + + }; diff --git a/src/dbexpression.cpp b/src/dbexpression.cpp index d496f2d..ac92a2e 100644 --- a/src/dbexpression.cpp +++ b/src/dbexpression.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2018-2019, Tomasz Sowa + * Copyright (c) 2018-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -62,23 +62,23 @@ int DbExpression::get_output_type() } -bool DbExpression::can_field_be_generated(bool insertable, bool updatable, bool is_primary_key) +bool DbExpression::can_field_be_generated(const FT & field_type) { if( output_type == MORM_OUTPUT_TYPE_DB_INSERT ) { - return insertable; + return field_type.is_insertable(); } else if( output_type == MORM_OUTPUT_TYPE_DB_UPDATE ) { - return updatable; + return field_type.is_updatable(); } else if( output_type == MORM_OUTPUT_TYPE_DB_PRIMARY_KEY || output_type == MORM_OUTPUT_TYPE_JOIN_TABLES || output_type == MORM_OUTPUT_TYPE_DB_INSERT_PRIMARY_KEY ) { - return is_primary_key; + return field_type.is_primary_key(); } else { @@ -182,78 +182,64 @@ void DbExpression::put_name_value_separator() } - -void DbExpression::before_field_value_string() +void DbExpression::schema_table_separator() { -// if( output_type == MORM_OUTPUT_TYPE_SELECT_COLUMNS || -// output_type == MORM_OUTPUT_TYPE_DB_INSERT || -// output_type == MORM_OUTPUT_TYPE_DB_UPDATE || -// output_type == MORM_OUTPUT_TYPE_DB_PRIMARY_KEY ) - { - (*out_stream) << "'"; - } -} - -void DbExpression::after_field_value_string() -{ -// if( output_type == MORM_OUTPUT_TYPE_SELECT_COLUMNS || -// output_type == MORM_OUTPUT_TYPE_DB_INSERT || -// output_type == MORM_OUTPUT_TYPE_DB_UPDATE || -// output_type == MORM_OUTPUT_TYPE_DB_PRIMARY_KEY ) - { - (*out_stream) << "'"; - } + (*out_stream) << '.'; } -void DbExpression::before_field_value(const std::wstring &) +void DbExpression::table_field_separator() { - before_field_value_string(); + (*out_stream) << '.'; } -void DbExpression::after_field_value(const std::wstring &) + +void DbExpression::before_schema_name() { - after_field_value_string(); + (*out_stream) << '"'; } -void DbExpression::before_field_value(const std::string &) + +void DbExpression::after_schema_name() { - before_field_value_string(); + (*out_stream) << '"'; } -void DbExpression::after_field_value(const std::string &) + +void DbExpression::before_table_name() { - after_field_value_string(); + (*out_stream) << '"'; } -void DbExpression::before_field_value(const wchar_t *) + +void DbExpression::after_table_name() { - before_field_value_string(); + (*out_stream) << '"'; } -void DbExpression::after_field_value(const wchar_t *) + +void DbExpression::before_field_name() { - after_field_value_string(); + (*out_stream) << '"'; } -void DbExpression::before_field_value(const char *) + +void DbExpression::after_field_name() { - before_field_value_string(); + (*out_stream) << '"'; } -void DbExpression::after_field_value(const char *) + + +void DbExpression::before_field_value_string(const FT & field_type) { - after_field_value_string(); + (*out_stream) << "'"; } -void DbExpression::before_field_value(const PT::Date &) -{ - before_field_value_string(); -} -void DbExpression::after_field_value(const PT::Date &) +void DbExpression::after_field_value_string(const FT & field_type) { - after_field_value_string(); + (*out_stream) << "'"; } @@ -265,7 +251,7 @@ void DbExpression::prepare_to_where_clause() } -DbExpression & DbExpression::group_or(PT::TextStream & stream) +DbExpression & DbExpression::group_or(pt::TextStream & stream) { out_stream = &stream; field_before(); @@ -277,7 +263,7 @@ DbExpression & DbExpression::group_or(PT::TextStream & stream) return *this; } -DbExpression & DbExpression::group_and(PT::TextStream & stream) +DbExpression & DbExpression::group_and(pt::TextStream & stream) { out_stream = &stream; field_before(); @@ -289,7 +275,7 @@ DbExpression & DbExpression::group_and(PT::TextStream & stream) return *this; } -DbExpression & DbExpression::group_end(PT::TextStream & stream) +DbExpression & DbExpression::group_end(pt::TextStream & stream) { out_stream = &stream; @@ -305,7 +291,7 @@ DbExpression & DbExpression::group_end(PT::TextStream & stream) } -DbExpression & DbExpression::page(PT::TextStream & stream, size_t page_number, size_t page_size) +DbExpression & DbExpression::page(pt::TextStream & stream, size_t page_number, size_t page_size) { stream << " limit " << page_number << "," << page_size << " "; return *this; @@ -314,37 +300,4 @@ DbExpression & DbExpression::page(PT::TextStream & stream, size_t page_number, s - -void DbExpression::prepare_short_table_name(const PT::TextStream & table_name, PT::TextStream & short_table_name) -{ - short_table_name.clear(); - - if( is_long_table_name(table_name) ) - { - PT::TextStream::const_iterator i = table_name.begin(); - bool was_dot = false; - - while( i != table_name.end() ) - { - if( was_dot ) - { - short_table_name << *i; - } - else - if( *i == '.' ) - { - was_dot = true; - } - - ++i; - } - } - - if( short_table_name.empty() ) - { - short_table_name = table_name; - } -} - - } diff --git a/src/dbexpression.h b/src/dbexpression.h index 53d2dba..0de03ab 100644 --- a/src/dbexpression.h +++ b/src/dbexpression.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2018, Tomasz Sowa + * Copyright (c) 2018-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -56,14 +56,14 @@ public: virtual void prepare_to_where_clause(); - virtual DbExpression & group_or(PT::TextStream & stream); - virtual DbExpression & group_and(PT::TextStream & stream); - virtual DbExpression & group_end(PT::TextStream & stream); + virtual DbExpression & group_or(pt::TextStream & stream); + virtual DbExpression & group_and(pt::TextStream & stream); + virtual DbExpression & group_end(pt::TextStream & stream); - virtual DbExpression & page(PT::TextStream & stream, size_t page_number, size_t page_size); + virtual DbExpression & page(pt::TextStream & stream, size_t page_number, size_t page_size); template - void add_field_for_select(const wchar_t * new_column_expression, const wchar_t * new_column_name, FieldValue & field_value) + void add_field_for_select(const wchar_t * new_column_expression, const wchar_t * new_column_name, FieldValue & field_value, const FT & field_type, ModelEnv * model_env) { std::wstring column_expression; // field() methods can be called recursively, so don't make it as class object @@ -71,47 +71,37 @@ public: column_expression += L" as "; column_expression += new_column_name; - // put nullptr to ModelEnv* to not allow to use prefix - // or may better remember current value of use_prefix and set it to false for a while? - field(column_expression.c_str(), field_value, false, false, false, nullptr); + field(column_expression.c_str(), field_value, field_type, model_env); } - virtual void prepare_short_table_name(const PT::TextStream & table_name, PT::TextStream & short_table_name); - protected: int output_type; std::vector conjunctions; - - bool can_field_be_generated(bool insertable, bool updatable, bool is_primary_key); - + bool can_field_be_generated(const FT & field_type); void field_before(); - - void before_field_value(const std::wstring &); - void after_field_value(const std::wstring &); - - void before_field_value(const std::string &); - void after_field_value(const std::string &); - - void before_field_value(const wchar_t *); - void after_field_value(const wchar_t *); - - 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(); + void schema_table_separator(); + void table_field_separator(); + + void before_schema_name(); + void after_schema_name(); + + void before_table_name(); + void after_table_name(); + + void before_field_name(); + void after_field_name(); + private: - void before_field_value_string(); - void after_field_value_string(); + void before_field_value_string(const FT & field_type); + void after_field_value_string(const FT & field_type); }; diff --git a/src/finder.h b/src/finder.h index 1bc7466..e37ebb9 100644 --- a/src/finder.h +++ b/src/finder.h @@ -66,7 +66,7 @@ public: } - Finder(PT::TextStream & out_stream) + Finder(pt::TextStream & out_stream) { this->out_stream = &out_stream; this->model_connector = nullptr; @@ -95,7 +95,7 @@ public: set_out_stream(); } - Finder(PT::TextStream & out_stream, ModelConnector & model_connector) + Finder(pt::TextStream & out_stream, ModelConnector & model_connector) { this->out_stream = &out_stream; this->model_connector = &model_connector; @@ -104,7 +104,7 @@ public: model_data = nullptr; } - Finder(PT::TextStream & out_stream, ModelConnector * model_connector) + Finder(pt::TextStream & out_stream, ModelConnector * model_connector) { this->out_stream = &out_stream; this->model_connector = model_connector; @@ -116,7 +116,7 @@ public: - Finder & set_out_stream(PT::TextStream * out_stream) + Finder & set_out_stream(pt::TextStream * out_stream) { this->out_stream = out_stream; return *this; @@ -173,6 +173,17 @@ public: last_query_error = L"model connector object is required"; } + model.set_connector(model_connector); + + finder_helper.clear(); + model_env.clear(); + + model.model_env = &model_env; + model.model_env->model_data = model_data; + model.model_env->finder_helper = &finder_helper; + model.table(); + model.model_env->add_table_name_to_finder_helper(); + return *this; } @@ -193,7 +204,7 @@ public: return select(); } - Finder & select(PT::TextStream & out_stream, ModelConnector & model_connector) + Finder & select(pt::TextStream & out_stream, ModelConnector & model_connector) { this->out_stream = &out_stream; this->model_connector = &model_connector; @@ -202,7 +213,7 @@ public: return select(); } - Finder & select(PT::TextStream & out_stream, ModelConnector * model_connector) + Finder & select(pt::TextStream & out_stream, ModelConnector * model_connector) { this->out_stream = &out_stream; this->model_connector = model_connector; @@ -219,27 +230,31 @@ public: prepare_to_select(); } - model.set_connector(model_connector); - - finder_helper.clear(); - model_env.clear(); - - model.model_env = &model_env; - model.model_env->model_data = model_data; - model.model_env->finder_helper = &finder_helper; - has_autogenerated_select = true; if( model_connector && out_stream && db_expression ) { - model.prepare_table_names(); - (*out_stream) << "SELECT "; model.generate_select_columns(*out_stream); - (*out_stream) << " FROM " << model.model_env->table_name << " AS "; - (*out_stream) << model.model_env->table_name_short; - (*out_stream) << " "; - (*out_stream) << finder_helper.join_tables_str; + (*out_stream) << " FROM "; + + if( !model.model_env->schema_name.empty() ) + { + db_expression->schema_table_to_stream(*out_stream, model.model_env->schema_name, model.model_env->table_name); + } + else + { + db_expression->table_to_stream(*out_stream, model.model_env->table_name); + } + + (*out_stream) << " AS "; + db_expression->table_to_stream(*out_stream, model.model_env->table_name); + + if( !finder_helper.join_tables_str.empty() ) + { + (*out_stream) << " "; + (*out_stream) << finder_helper.join_tables_str; + } } return *this; @@ -326,14 +341,39 @@ public: - template Finder & eq(const wchar_t * field_name, const FieldValue & field_value) { if( db_expression ) { db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_EQ); - db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false, &model_env); + db_expression->field_to_stream(*out_stream, field_name, field_value, FT::default_type, &model_env); + } + + return *this; + } + + + template + Finder & eq(const wchar_t * table_name, const wchar_t * field_name, const FieldValue & field_value) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_EQ); + field_to_stream(table_name, 1, field_name, field_value); + } + + return *this; + } + + + template + Finder & eq(const wchar_t * table_name, int table_index, const wchar_t * field_name, const FieldValue & field_value) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_EQ); + field_to_stream(table_name, table_index, field_name, field_value); } return *this; @@ -346,19 +386,72 @@ public: if( db_expression ) { db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_NOT_EQ); - db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false, &model_env); + db_expression->field_to_stream(*out_stream, field_name, field_value, FT::default_type, &model_env); } return *this; } + + template + Finder & neq(const wchar_t * table_name, const wchar_t * field_name, const FieldValue & field_value) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_NOT_EQ); + field_to_stream(table_name, 1, field_name, field_value); + } + + return *this; + } + + + template + Finder & neq(const wchar_t * table_name, int table_index, const wchar_t * field_name, const FieldValue & field_value) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_NOT_EQ); + field_to_stream(table_name, table_index, field_name, field_value); + } + + return *this; + } + + template Finder & lt(const wchar_t * field_name, const FieldValue & field_value) { if( db_expression ) { db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_LT); - db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false, &model_env); + db_expression->field_to_stream(*out_stream, field_name, field_value, FT::default_type, &model_env); + } + + return *this; + } + + + template + Finder & lt(const wchar_t * table_name, const wchar_t * field_name, const FieldValue & field_value) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_LT); + field_to_stream(table_name, 1, field_name, field_value); + } + + return *this; + } + + + template + Finder & lt(const wchar_t * table_name, int table_index, const wchar_t * field_name, const FieldValue & field_value) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_LT); + field_to_stream(table_name, table_index, field_name, field_value); } return *this; @@ -371,7 +464,33 @@ public: if( db_expression ) { db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_GT); - db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false, &model_env); + db_expression->field_to_stream(*out_stream, field_name, field_value, FT::default_type, &model_env); + } + + return *this; + } + + + template + Finder & gt(const wchar_t * table_name, const wchar_t * field_name, const FieldValue & field_value) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_GT); + field_to_stream(table_name, 1, field_name, field_value); + } + + return *this; + } + + + template + Finder & gt(const wchar_t * table_name, int table_index, const wchar_t * field_name, const FieldValue & field_value) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_GT); + field_to_stream(table_name, table_index, field_name, field_value); } return *this; @@ -384,20 +503,75 @@ public: if( db_expression ) { db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_LE); - db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false, &model_env); + db_expression->field_to_stream(*out_stream, field_name, field_value, FT::default_type, &model_env); } return *this; } + template + Finder & le(const wchar_t * table_name, const wchar_t * field_name, const FieldValue & field_value) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_LE); + field_to_stream(table_name, 1, field_name, field_value); + } + + return *this; + } + + + + template + Finder & le(const wchar_t * table_name, int table_index, const wchar_t * field_name, const FieldValue & field_value) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_LE); + field_to_stream(table_name, table_index, field_name, field_value); + } + + return *this; + } + + + template Finder & ge(const wchar_t * field_name, const FieldValue & field_value) { if( db_expression ) { db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_GE); - db_expression->field_to_stream(*out_stream, field_name, field_value, false, false, false, &model_env); + db_expression->field_to_stream(*out_stream, field_name, field_value, FT::default_type, &model_env); + } + + return *this; + } + + + template + Finder & ge(const wchar_t * table_name, const wchar_t * field_name, const FieldValue & field_value) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_GE); + field_to_stream(table_name, 1, field_name, field_value); + } + + return *this; + } + + + + template + Finder & ge(const wchar_t * table_name, int table_index, const wchar_t * field_name, const FieldValue & field_value) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_GE); + field_to_stream(table_name, table_index, field_name, field_value); } return *this; @@ -417,6 +591,33 @@ public: return *this; } + + template + Finder & in(const wchar_t * table_name, const wchar_t * field_name, const std::set & container) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_IN); + field_in(table_name, 1, field_name, container); + } + + return *this; + } + + + template + Finder & in(const wchar_t * table_name, int table_index, const wchar_t * field_name, const std::set & container) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_IN); + field_in(table_name, table_index, field_name, container); + } + + return *this; + } + + template Finder & in(const wchar_t * field_name, const std::list & container) { @@ -429,6 +630,33 @@ public: return *this; } + + template + Finder & in(const wchar_t * table_name, const wchar_t * field_name, const std::list & container) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_IN); + field_in(table_name, 1, field_name, container); + } + + return *this; + } + + + template + Finder & in(const wchar_t * table_name, int table_index, const wchar_t * field_name, const std::list & container) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_IN); + field_in(table_name, table_index, field_name, container); + } + + return *this; + } + + template Finder & in(const wchar_t * field_name, const std::vector & container) { @@ -441,6 +669,35 @@ public: return *this; } + + template + Finder & in(const wchar_t * table_name, const wchar_t * field_name, const std::vector & container) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_IN); + field_in(table_name, 1, field_name, container); + } + + return *this; + } + + + template + Finder & in(const wchar_t * table_name, int table_index, const wchar_t * field_name, const std::vector & container) + { + if( db_expression ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_WHERE_IN); + field_in(table_name, table_index, field_name, container); + } + + return *this; + } + + + + Finder & page(size_t page_number, size_t page_size) { if( out_stream && db_expression ) @@ -469,7 +726,7 @@ public: } - Finder & raw(PT::TextStream & sql, bool add_spaces = true) + Finder & raw(pt::TextStream & sql, bool add_spaces = true) { if( out_stream ) { @@ -598,7 +855,7 @@ protected: private: - PT::TextStream * out_stream; + pt::TextStream * out_stream; ModelConnector * model_connector; DbExpression * db_expression; ModelClass model; @@ -625,6 +882,35 @@ private: } + template + void field_to_stream(const wchar_t * table_name, int table_index, const wchar_t * field_name, const FieldValue & field_value) + { + if( db_expression ) + { + model_env.table2_name = table_name; + model_env.table2_index = table_index; + + db_expression->field_to_stream(*out_stream, field_name, field_value, FT::default_type, &model_env); + + model_env.table2_name = nullptr; + model_env.table2_index = 0; + } + } + + template + void field_in(const wchar_t * table_name, int table_index, const wchar_t * field_name, const Container & container) + { + if( db_expression ) + { + model_env.table2_name = table_name; + model_env.table2_index = table_index; + + db_expression->field_in(*out_stream, field_name, container, &model_env); + + model_env.table2_name = nullptr; + model_env.table2_index = 0; + } + } }; diff --git a/src/finderhelper.h b/src/finderhelper.h index 4898fe8..b0adf7b 100644 --- a/src/finderhelper.h +++ b/src/finderhelper.h @@ -46,9 +46,9 @@ class FinderHelper { public: - PT::TextStream join_tables_str; + pt::TextStream join_tables_str; - std::map join_tables_map; + std::map join_tables_map; std::list foreign_keys; @@ -72,16 +72,16 @@ public: } - virtual int add_join_table(const PT::TextStream & table_name) + virtual int add_join_table(const pt::WTextStream & table_name) { - std::string table_name_str; + std::wstring table_name_str; table_name.to_string(table_name_str); return add_join_table(table_name_str); } - virtual int add_join_table(const std::string & table_name) + virtual int add_join_table(const std::wstring & table_name) { auto res = join_tables_map.insert(std::make_pair(table_name, 1)); diff --git a/src/flatconnector.cpp b/src/flatconnector.cpp index 99bdb7d..2a0d2b8 100644 --- a/src/flatconnector.cpp +++ b/src/flatconnector.cpp @@ -68,7 +68,7 @@ FlatExpression * FlatConnector::get_expression() -void FlatConnector::to_text(PT::TextStream & stream, Model & model) +void FlatConnector::to_text(pt::TextStream & stream, Model & model) { allocate_default_expression_if_needed(); diff --git a/src/flatconnector.h b/src/flatconnector.h index d1e403a..a762b13 100644 --- a/src/flatconnector.h +++ b/src/flatconnector.h @@ -51,7 +51,7 @@ public: FlatConnector(); virtual ~FlatConnector(); - virtual void to_text(PT::TextStream & stream, Model & model); + virtual void to_text(pt::TextStream & stream, Model & model); virtual void set_expression(FlatExpression & expression); virtual FlatExpression * get_expression(); diff --git a/src/flatexpression.cpp b/src/flatexpression.cpp index 4252d47..7a14d87 100644 --- a/src/flatexpression.cpp +++ b/src/flatexpression.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2018, Tomasz Sowa + * Copyright (c) 2018-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -39,7 +39,7 @@ namespace morm { -void FlatExpression::esc(const PT::Date & date, PT::TextStream & stream) +void FlatExpression::esc(const pt::Date & date, pt::TextStream & stream, const FT & field_type) { date.SerializeISO(stream); } diff --git a/src/flatexpression.h b/src/flatexpression.h index b928607..075a14e 100644 --- a/src/flatexpression.h +++ b/src/flatexpression.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2018, Tomasz Sowa + * Copyright (c) 2018-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -45,7 +45,7 @@ class FlatExpression : public BaseExpression { public: - void esc(const PT::Date & date, PT::TextStream & stream); + void esc(const pt::Date & date, pt::TextStream & stream, const FT & field_type); diff --git a/src/ft.h b/src/ft.h new file mode 100644 index 0000000..deacf1f --- /dev/null +++ b/src/ft.h @@ -0,0 +1,167 @@ +/* + * This file is a part of morm + * and is distributed under the 2-Clause BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2021, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef headerfile_morm_ft +#define headerfile_morm_ft + +namespace morm +{ + + + +/* + * field types + */ +class FT +{ +public: + + enum FieldType + { + default_type = 0, + primary_key = 1, + foreign_key = 2, + foreign_key_in_child = 4, + no_insertable = 8, + no_updatable = 16, + no_fetchable = 32, /* not supported yet */ + no_removable = 64, + raw_field_name = 128, + dont_use_utf8 = 256, + hexadecimal = 512, + binary = 1024, + }; + + /* + * type can be a superposition from FieldType values + */ + int type; + + + + FT() + { + type = 0; + } + + FT(const FT & field_type) + { + type = field_type.type; + } + + FT(FieldType type) + { + this->type = static_cast(type); + } + + FT(int type) + { + this->type = type; + } + + FT & operator=(const FT & field_type) + { + type = field_type.type; + return *this; + } + + bool is_flag_set(int flag_mask) const + { + return (type & flag_mask) != 0; + } + + + bool is_primary_key() const + { + return is_flag_set(primary_key); + } + + + bool is_foreign_key() const + { + return is_flag_set(foreign_key); + } + + bool is_foreign_key_in_child() const + { + return is_flag_set(foreign_key_in_child); + } + + bool is_insertable() const + { + return !is_flag_set(no_insertable); + } + + bool is_updatable() const + { + return !is_flag_set(no_updatable); + } + + bool is_fetchable() const + { + return !is_flag_set(no_fetchable); + } + + bool is_removable() const + { + return !is_flag_set(no_removable); + } + + bool is_raw_field_name() const + { + return is_flag_set(raw_field_name); + } + + bool use_utf8() const + { + return !is_flag_set(dont_use_utf8); + } + + bool is_hexadecimal() const + { + return is_flag_set(hexadecimal); + } + + bool is_binary() const + { + return is_flag_set(binary); + } + + +}; + +} + +#endif + diff --git a/src/jsonexpression.cpp b/src/jsonexpression.cpp index e9ef3e9..9b1db1b 100644 --- a/src/jsonexpression.cpp +++ b/src/jsonexpression.cpp @@ -76,80 +76,29 @@ void JSONExpression::field_before() -void JSONExpression::before_short_field_name() +void JSONExpression::before_field_name() { (*out_stream) << "\""; } -void JSONExpression::after_short_field_name() -{ - (*out_stream) << "\""; -} - -void JSONExpression::before_first_part_long_field_name() -{ - (*out_stream) << "\""; -} - -void JSONExpression::after_first_part_long_field_name() -{ -} - -void JSONExpression::before_second_part_long_field_name() -{ -} - -void JSONExpression::after_second_part_long_field_name() +void JSONExpression::after_field_name() { (*out_stream) << "\""; } - -void JSONExpression::before_field_value_string() +void JSONExpression::before_field_value_string(const FT & field_type) { (*out_stream) << "\""; } -void JSONExpression::after_field_value_string() +void JSONExpression::after_field_value_string(const FT & field_type) { (*out_stream) << "\""; } -void JSONExpression::before_field_value(const std::wstring &) -{ - before_field_value_string(); -} - -void JSONExpression::before_field_value(const std::string &) -{ - before_field_value_string(); -} - -void JSONExpression::after_field_value(const std::wstring &) -{ - after_field_value_string(); -} - -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() { (*out_stream) << ':'; @@ -168,20 +117,48 @@ void JSONExpression::after_field_value_list() } -void JSONExpression::esc(char val, PT::TextStream & stream) +void JSONExpression::esc(char val, pt::TextStream & stream, const FT & field_type) { - switch( val ) + if( field_type.is_hexadecimal() || field_type.is_binary() ) { - case 0: stream << '\\'; stream << '0'; break; // may to skip this character is better? - case '\r': stream << '\\'; stream << 'r'; break; - case '\n': stream << '\\'; stream << 'n'; break; - case '\t': stream << '\\'; stream << 't'; break; - case 0x08: stream << '\\'; stream << 'b'; break; - case 0x0c: stream << '\\'; stream << 'f'; break; - case '\\': stream << '\\'; stream << '\\'; break; - case '"': stream << '\\'; stream << '\"'; break; - default: - stream << val; + char_to_hex(val, stream); + } + else + { + if( (unsigned char)val < 32 ) + { + char buf[10]; + size_t len; + pt::Toa((unsigned char)val, buf, sizeof(buf)/sizeof(char), 16, &len); + + stream << "\\u"; + + if( len < 4 ) + { + for(size_t i=0 ; i < (4-len) ; ++i) + { + stream << '0'; + } + } + + stream << buf; + } + else + { + switch( val ) + { + case 0: stream << '\\'; stream << '0'; break; // may to skip this character is better? + case '\r': stream << '\\'; stream << 'r'; break; + case '\n': stream << '\\'; stream << 'n'; break; + case '\t': stream << '\\'; stream << 't'; break; + case 0x08: stream << '\\'; stream << 'b'; break; + case 0x0c: stream << '\\'; stream << 'f'; break; + case '\\': stream << '\\'; stream << '\\'; break; + case '"': stream << '\\'; stream << '\"'; break; + default: + stream << val; + } + } } } diff --git a/src/jsonexpression.h b/src/jsonexpression.h index 79a91da..ebc78ca 100644 --- a/src/jsonexpression.h +++ b/src/jsonexpression.h @@ -54,22 +54,11 @@ protected: void field_before(); - void before_short_field_name(); - void after_short_field_name(); - void before_first_part_long_field_name(); - void after_first_part_long_field_name(); - void before_second_part_long_field_name(); - void after_second_part_long_field_name(); + void before_field_name(); + void after_field_name(); - void before_field_value(const std::wstring &); - void before_field_value(const std::string &); - void after_field_value(const std::wstring &); - 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 &); - void before_field_value_list(); void after_field_value_list(); @@ -77,13 +66,13 @@ protected: // 'morm::JSONExpression::esc' hides overloaded virtual function [-Woverloaded-virtual] using FlatExpression::esc; - void esc(char val, PT::TextStream & stream); + void esc(char val, pt::TextStream & stream, const FT & field_type); private: - void before_field_value_string(); - void after_field_value_string(); + void before_field_value_string(const FT & field_type); + void after_field_value_string(const FT & field_type); }; diff --git a/src/model.cpp b/src/model.cpp index 8c4b63f..56bb39b 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -33,6 +33,7 @@ */ #include "model.h" +#include "utf8/utf8.h" namespace morm @@ -43,6 +44,7 @@ Model::Model() model_connector = nullptr; model_env = nullptr; save_mode = DO_INSERT_ON_SAVE; + has_primary_key_set = false; } @@ -50,7 +52,8 @@ Model::Model(const Model & m) { model_connector = m.model_connector; save_mode = m.save_mode; - model_env = m.model_env; // or just set to null? + model_env = nullptr; + has_primary_key_set = m.has_primary_key_set; } @@ -71,6 +74,19 @@ Model::SaveMode Model::get_save_mode() } +void Model::set_has_primary_key_set(bool has_primary_key) +{ + this->has_primary_key_set = has_primary_key; +} + + +bool Model::get_has_primary_key_set() +{ + return this->has_primary_key_set; +} + + + void Model::mark_to_delete() { save_mode = DO_DELETE_ON_SAVE; @@ -94,12 +110,6 @@ void Model::mark_to_update() -void Model::table_name(PT::TextStream & stream) -{ -} - - - void Model::set_connector(ModelConnector & connector) { set_connector(&connector); @@ -118,6 +128,44 @@ ModelConnector * Model::get_connector() } +void Model::table() +{ + if( model_connector ) + { + pt::Log * plog = model_connector->get_logger(); + + if( plog ) + { + (*plog) << pt::Log::log1 << "Morm: you should provide the table name e.g. provide table() method and call table(...) there" << pt::Log::logend; + } + } +} + +void Model::table_name(const wchar_t * table_name) +{ + if( model_env ) + { + model_env->schema_name.clear(); + model_env->table_name.clear(); + + model_env->table_name << table_name; + } +} + +void Model::table_name(const wchar_t * schema_name, const wchar_t * table_name) +{ + if( model_env ) + { + model_env->schema_name.clear(); + model_env->table_name.clear(); + + model_env->schema_name << schema_name; + model_env->table_name << table_name; + } +} + + + bool Model::object_exists() { return save_mode == DO_UPDATE_ON_SAVE; @@ -130,7 +178,69 @@ bool Model::found() } -void Model::to_text(PT::TextStream & stream, ModelData * model_data, bool clear_stream, bool dump_mode) +void Model::get_table_name(pt::WTextStream & stream, bool with_schema_name, ModelData * model_data, bool clear_stream) +{ + if( clear_stream ) + { + stream.clear(); + } + + ModelEnv model_env_local; + model_env = &model_env_local; + model_env->model_data = model_data; + + if( model_connector ) + { + DbConnector * db_connector = model_connector->get_db_connector(); + + if( db_connector ) + { + try + { + table(); + + if( with_schema_name && !model_env->schema_name.empty() ) + { + stream << model_env->schema_name; + stream << '.'; + } + + stream << model_env->table_name; + } + catch(...) + { + model_env = nullptr; + throw; + } + } + } + + model_env = nullptr; +} + + +void Model::get_table_name(std::wstring & str, bool with_schema_name, ModelData * model_data, bool clear_string) +{ + pt::WTextStream stream; + + if( clear_string ) + str.clear(); + + get_table_name(stream, with_schema_name, model_data, false); + stream.to_string(str); +} + + +void Model::get_table_name(std::string & str, bool with_schema_name, ModelData * model_data, bool clear_string) +{ + pt::WTextStream stream; + + get_table_name(stream, with_schema_name, model_data, false); + pt::wide_stream_to_utf8(stream, str, clear_string); +} + + +void Model::to_text(pt::TextStream & stream, ModelData * model_data, bool clear_stream, bool dump_mode) { if( clear_stream ) { @@ -140,8 +250,10 @@ void Model::to_text(PT::TextStream & stream, ModelData * model_data, bool clear_ ModelEnv model_env_local; model_env = &model_env_local; + model_env->has_primary_key_set = has_primary_key_set; model_env->model_work_mode = MORM_MODEL_WORK_MODE_GENERATING_FLAT_STRING; model_env->dump_mode = dump_mode; + model_env->model_data = model_data; if( model_connector ) { @@ -149,24 +261,30 @@ void Model::to_text(PT::TextStream & stream, ModelData * model_data, bool clear_ if( flat_connector ) { - model_env->model_data = model_data; - flat_connector->to_text(stream, *this); - model_env->model_data = nullptr; + try + { + // table(); at the moment flat strings (json/space) do not need a table name + flat_connector->to_text(stream, *this); + } + catch(...) + { + model_env = nullptr; + throw; + } } } - // what about if an exception was thrown? this pointer will not be null model_env = nullptr; } -void Model::to_text(PT::TextStream & stream, ModelData & model_data, bool clear_stream, bool dump_mode) +void Model::to_text(pt::TextStream & stream, ModelData & model_data, bool clear_stream, bool dump_mode) { to_text(stream, &model_data, clear_stream, dump_mode); } -void Model::to_text(PT::TextStream & stream, bool clear_stream, bool dump_mode) +void Model::to_text(pt::TextStream & stream, bool clear_stream, bool dump_mode) { to_text(stream, nullptr, clear_stream, dump_mode); } @@ -178,7 +296,7 @@ void Model::to_text(std::string & str, ModelData * model_data, bool clear_string if( model_connector ) { // CHECK ME what if the stream is being used by something other? - PT::TextStream * out_stream = model_connector->get_stream(); + pt::TextStream * out_stream = model_connector->get_stream(); if( out_stream ) { @@ -217,10 +335,12 @@ std::string Model::to_string() -void Model::generate_insert_query(PT::TextStream & stream, ModelData * model_data) + +void Model::generate_insert_query(pt::TextStream & stream, ModelData * model_data) { ModelEnv model_env_local; model_env = &model_env_local; + model_env->has_primary_key_set = has_primary_key_set; model_env->model_data = model_data; model_env->model_work_mode = MORM_MODEL_WORK_MODE_GENERATING_DB_SQL; @@ -230,11 +350,19 @@ void Model::generate_insert_query(PT::TextStream & stream, ModelData * model_dat if( db_connector ) { - db_connector->generate_insert_query(stream, *this); + try + { + table(); + db_connector->generate_insert_query(stream, *this); + } + catch(...) + { + model_env = nullptr; + throw; + } } } - // what about if an exception was thrown? this pointer will not be null model_env = nullptr; } @@ -257,11 +385,20 @@ bool Model::insert(ModelData * model_data, bool insert_whole_tree) model_env = &model_env_local; model_env->model_data = model_data; - bool status = insert_tree(insert_whole_tree); + bool status = false; + + try + { + table(); + status = insert_tree(insert_whole_tree); + } + catch(...) + { + model_env = nullptr; + throw; + } - // what about if an exception was thrown? this pointer will not be null model_env = nullptr; - return status; } @@ -271,12 +408,13 @@ bool Model::insert(ModelData * model_data, bool insert_whole_tree) bool Model::insert_tree(bool insert_whole_tree) { bool result = false; + model_env->has_primary_key_set = has_primary_key_set; if( insert_whole_tree ) { model_env->model_work_mode = MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITH_FOREIGN_KEY; model_env->model_work_submode = MORM_MODEL_WORK_SUBMODE_INSERT; - map_fields(); + fields(); } if( model_connector ) @@ -285,7 +423,7 @@ bool Model::insert_tree(bool insert_whole_tree) DbConnector * db_connector = model_connector->get_db_connector(); // CHECK ME what if the stream is being used by something other? - PT::TextStream * out_stream = model_connector->get_stream(); + pt::TextStream * out_stream = model_connector->get_stream(); if( db_connector && out_stream ) { @@ -296,9 +434,21 @@ bool Model::insert_tree(bool insert_whole_tree) if( result ) { - save_mode = DO_UPDATE_ON_SAVE; // IMPROVE ME check if there is a primary key + /* + * after_insert() should read the new primary key and set has_primary_key_set flag if the key was read correctly + */ after_insert(); - set_parent_key_in_childs(); + model_env->has_primary_key_set = has_primary_key_set; + + if( has_primary_key_set ) + { + save_mode = DO_UPDATE_ON_SAVE; + set_parent_key_in_childs(); // may it would be better to set it even if we do not have a primary key? set it to zero or something? + } + else + { + save_mode = DO_NOTHING_ON_SAVE; + } } else { @@ -311,7 +461,7 @@ bool Model::insert_tree(bool insert_whole_tree) { model_env->model_work_mode = MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITHOUT_FOREIGN_KEY; model_env->model_work_submode = MORM_MODEL_WORK_SUBMODE_INSERT; - map_fields(); + fields(); } return result; @@ -319,10 +469,11 @@ bool Model::insert_tree(bool insert_whole_tree) -void Model::generate_update_query(PT::TextStream & stream, ModelData * model_data) +void Model::generate_update_query(pt::TextStream & stream, ModelData * model_data) { ModelEnv model_env_local; model_env = &model_env_local; + model_env->has_primary_key_set = has_primary_key_set; model_env->model_data = model_data; model_env->model_work_mode = MORM_MODEL_WORK_MODE_GENERATING_DB_SQL; @@ -332,6 +483,7 @@ void Model::generate_update_query(PT::TextStream & stream, ModelData * model_dat if( db_connector ) { + table(); db_connector->generate_update_query(stream, *this); } } @@ -359,11 +511,20 @@ bool Model::update(ModelData * model_data, bool update_whole_tree) model_env = &model_env_local; model_env->model_data = model_data; - bool status = update_tree(update_whole_tree); + bool status = false; + + try + { + table(); + status = update_tree(update_whole_tree); + } + catch(...) + { + model_env = nullptr; + throw; + } - // what about if an exception was thrown? this pointer will not be null model_env = nullptr; - return status; } @@ -372,12 +533,19 @@ bool Model::update(ModelData * model_data, bool update_whole_tree) bool Model::update_tree(bool update_whole_tree) { bool result = false; + model_env->has_primary_key_set = has_primary_key_set; + + if( !has_primary_key_set ) + { + put_to_log(L"Morm: call update but model doesn't have a primary key set"); + return result; + } if( update_whole_tree ) { model_env->model_work_mode = MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITH_FOREIGN_KEY; model_env->model_work_submode = MORM_MODEL_WORK_SUBMODE_UPDATE; - map_fields(); + fields(); } if( model_connector ) @@ -386,7 +554,7 @@ bool Model::update_tree(bool update_whole_tree) DbConnector * db_connector = model_connector->get_db_connector(); // CHECK ME what if the stream is being used by something other? - PT::TextStream * out_stream = model_connector->get_stream(); + pt::TextStream * out_stream = model_connector->get_stream(); if( db_connector && out_stream ) { @@ -405,17 +573,18 @@ bool Model::update_tree(bool update_whole_tree) { model_env->model_work_mode = MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITHOUT_FOREIGN_KEY; model_env->model_work_submode = MORM_MODEL_WORK_SUBMODE_UPDATE; - map_fields(); + fields(); } return result; } -void Model::generate_remove_query(PT::TextStream & stream, ModelData * model_data) +void Model::generate_remove_query(pt::TextStream & stream, ModelData * model_data) { ModelEnv model_env_local; model_env = &model_env_local; + model_env->has_primary_key_set = has_primary_key_set; model_env->model_data = model_data; model_env->model_work_mode = MORM_MODEL_WORK_MODE_GENERATING_DB_SQL; @@ -425,6 +594,7 @@ void Model::generate_remove_query(PT::TextStream & stream, ModelData * model_dat if( db_connector ) { + table(); db_connector->generate_remove_query(stream, *this); } } @@ -453,11 +623,20 @@ bool Model::remove(ModelData * model_data, bool remove_whole_tree) model_env = &model_env_local; model_env->model_data = model_data; - bool status = remove_tree(remove_whole_tree); + bool status = false; + + try + { + table(); + status = remove_tree(remove_whole_tree); + } + catch(...) + { + model_env = nullptr; + throw; + } - // what about if an exception was thrown? this pointer will not be null model_env = nullptr; - return status; } @@ -466,12 +645,19 @@ bool Model::remove(ModelData * model_data, bool remove_whole_tree) bool Model::remove_tree(bool remove_whole_tree) { bool result = false; + model_env->has_primary_key_set = has_primary_key_set; + + if( !has_primary_key_set ) + { + put_to_log(L"Morm: call remove but model doesn't have a primary key set"); + return result; + } if( remove_whole_tree ) { model_env->model_work_mode = MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITHOUT_FOREIGN_KEY; model_env->model_work_submode = MORM_MODEL_WORK_SUBMODE_REMOVE; - map_fields(); + fields(); } if( model_connector ) @@ -480,7 +666,7 @@ bool Model::remove_tree(bool remove_whole_tree) DbConnector * db_connector = model_connector->get_db_connector(); // CHECK ME what if the stream is being used by something other? - PT::TextStream * out_stream = model_connector->get_stream(); + pt::TextStream * out_stream = model_connector->get_stream(); if( db_connector && out_stream ) { @@ -490,7 +676,9 @@ bool Model::remove_tree(bool remove_whole_tree) if( result ) { - save_mode = DO_INSERT_ON_SAVE; // CHECKME may it would be better to set DO_NOTHING_ON_SAVE? + save_mode = DO_NOTHING_ON_SAVE; + has_primary_key_set = false; + model_env->has_primary_key_set = false; after_remove(); } else @@ -504,7 +692,7 @@ bool Model::remove_tree(bool remove_whole_tree) { model_env->model_work_mode = MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITH_FOREIGN_KEY; model_env->model_work_submode = MORM_MODEL_WORK_SUBMODE_REMOVE; - map_fields(); + fields(); } return result; @@ -531,11 +719,20 @@ bool Model::save(ModelData * model_data, bool save_whole_tree) model_env = &model_env_local; model_env->model_data = model_data; - bool status = save_tree(save_whole_tree); + bool status = false; + + try + { + table(); + status = save_tree(save_whole_tree); + } + catch(...) + { + model_env = nullptr; + throw; + } - // what about if an exception was thrown? this pointer will not be null model_env = nullptr; - return status; } @@ -544,6 +741,7 @@ bool Model::save(ModelData * model_data, bool save_whole_tree) bool Model::save_tree(bool save_whole_tree) { bool result = false; + model_env->has_primary_key_set = has_primary_key_set; if( save_whole_tree ) { @@ -553,7 +751,7 @@ bool Model::save_tree(bool save_whole_tree) model_env->model_work_mode = MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITH_FOREIGN_KEY; model_env->model_work_submode = MORM_MODEL_WORK_SUBMODE_SAVE; - map_fields(); + fields(); } ModelEnv * old_model_env = model_env; // remove, insert or update will set model_env to nullptr @@ -587,14 +785,14 @@ bool Model::save_tree(bool save_whole_tree) model_env->model_work_mode = MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITHOUT_FOREIGN_KEY; model_env->model_work_submode = MORM_MODEL_WORK_SUBMODE_SAVE; - map_fields(); + fields(); } return result; } -void Model::generate_select_columns(PT::TextStream & stream) +void Model::generate_select_columns(pt::TextStream & stream) { if( model_connector && model_env ) { @@ -617,17 +815,20 @@ void Model::map_values_from_query() if( model_env ) { model_env->model_work_mode = MORM_MODEL_WORK_MODE_READING_VALUE_FROM_DB_RESULTSET; - model_env->all_fields_are_null = true; - map_fields(); + model_env->was_primary_key_read = false; // whether or not there was at least one column with primary_key flag + model_env->has_primary_key_set = true; // whether all primary_columns were different than null + fields(); model_env->model_work_mode = MORM_MODEL_WORK_MODE_NONE; - if( model_env->all_fields_are_null ) + if( model_env->was_primary_key_read && model_env->has_primary_key_set ) { - save_mode = DO_NOTHING_ON_SAVE; + has_primary_key_set = true; + save_mode = DO_UPDATE_ON_SAVE; } else { - save_mode = DO_UPDATE_ON_SAVE; + has_primary_key_set = false; + save_mode = DO_NOTHING_ON_SAVE; } } } @@ -640,14 +841,29 @@ void Model::clear() model_env = &model_env_local; model_env->model_work_mode = MORM_MODEL_WORK_MODE_CLEARING_VALUE; - map_fields(); - model_env = nullptr; + try + { + // table() doesn't have to be called + fields(); + } + catch(...) + { + model_env = nullptr; + throw; + } + + model_env = nullptr; save_mode = DO_INSERT_ON_SAVE; + has_primary_key_set = false; } +bool Model::do_migration(int & current_table_version) +{ + return true; +} @@ -758,43 +974,72 @@ bool Model::is_the_same_field(const wchar_t * field1, const wchar_t * field2) -void Model::prepare_table_names(bool prepare_table_index) +void Model::log_table_name(bool put_schema_name) { - DbConnector * db_connector = model_connector->get_db_connector(); - - if( db_connector && model_env ) + if( model_connector && model_env ) { - DbExpression * db_expression = db_connector->get_expression(); + pt::Log * plog = model_connector->get_logger(); - if( db_expression ) + if( plog ) { - table_name(model_env->table_name); - db_expression->prepare_short_table_name(model_env->table_name, model_env->table_name_short); - - if( prepare_table_index && model_env->finder_helper ) + if( put_schema_name && !model_env->schema_name.empty() ) { - model_env->table_index = model_env->finder_helper->add_join_table(model_env->table_name_short); + (*plog) << model_env->schema_name; + + // although in BaseExpression there is schema_table_separator() method + // but for logging purposes we can use just a dot here + (*plog) << '.'; + } + + (*plog) << model_env->table_name; + } + } +} + + +void Model::log_table_name_with_field(const wchar_t * db_field_name, bool put_schema_name) +{ + if( model_connector && model_env ) + { + pt::Log * plog = model_connector->get_logger(); + + if( plog ) + { + bool is_empty_field_name = is_empty_field(db_field_name); + + if( put_schema_name && !model_env->schema_name.empty() ) + { + (*plog) << model_env->schema_name; + (*plog) << '.'; + } + + (*plog) << model_env->table_name; + + if( !is_empty_field_name ) + { + (*plog) << '.'; + (*plog) << db_field_name; } } } } -void Model::put_table_name_with_index(PT::TextStream & str) +void Model::put_to_log(const wchar_t * str) { - if( model_env ) + if( model_connector ) { - str << model_env->table_name_short; + pt::Log * log = model_connector->get_logger(); - if( model_env->table_index > 1 ) + if( log ) { - str << model_env->table_index; + (*log) << str << pt::Log::logend; } } } -void Model::put_fields_to_log(PT::Log & log, const wchar_t * db_field_name, const wchar_t * flat_field_name) +void Model::put_fields_to_log(pt::Log & log, const wchar_t * db_field_name, const wchar_t * flat_field_name) { bool was_db_field_put = false; bool was_flat_field_put = false; @@ -821,5 +1066,508 @@ void Model::put_fields_to_log(PT::Log & log, const wchar_t * db_field_name, cons } +/* + * IMPROVE ME there can be more rows in the result set when there are more items on the left hand side of the join + * this is only in a case when has_foreign_key is false, may it can be ignored? we can use unique index in such a case + * + */ +void Model::field_model_left_join(const wchar_t * db_field_name, Model & field_model, const FT & field_type, DbExpression * db_expression) +{ + if( model_env && field_model.model_env && model_env->finder_helper ) + { + model_env->finder_helper->foreign_keys.clear(); + pt::TextStream & join_tables_str = model_env->finder_helper->join_tables_str; + field_model.model_env->add_table_name_to_finder_helper(); + + join_tables_str << "LEFT JOIN "; + + pt::TextStream * db_expression_stream = db_expression->get_text_stream(); + int expr_work_mode = db_expression->get_work_mode(); + int expr_output_type = db_expression->get_output_type(); + bool expr_allow_prefix = db_expression->get_allow_to_use_prefix(); + + db_expression->schema_table_to_stream(join_tables_str, field_model.model_env->schema_name, field_model.model_env->table_name); + join_tables_str << " AS "; + db_expression->table_with_index_to_stream(join_tables_str, field_model.model_env->table_name, field_model.model_env->table_index); + + db_expression->set_work_mode(MORM_WORK_MODE_MODEL_SAVE_FIELDS); + db_expression->set_output_type(MORM_OUTPUT_TYPE_JOIN_TABLES); + db_expression->allow_to_use_prefix(false); + db_expression->set_text_stream(db_expression_stream); // restore original value because schema_table_to_stream() will set the stream to null + + if( field_type.is_foreign_key() ) + { + field_model.fields(); + + join_tables_str << " ON "; + db_expression->table_with_index_and_field_to_stream(join_tables_str, model_env->table_name, model_env->table_index, db_field_name, field_type); + join_tables_str << " = "; + + db_expression->table_with_index_to_stream(join_tables_str, field_model.model_env->table_name, field_model.model_env->table_index); + join_tables_str << '.'; + + // IMPROVE ME at the moment support only for foreign keys consisting of only one column + if( model_env->finder_helper->foreign_keys.size() == 1 ) + { + join_tables_str << model_env->finder_helper->foreign_keys.front(); + } + } + else + { + ModelEnv * old_model_env = field_model.model_env; + fields(); // fields() will set field_model.model_env to null + field_model.model_env = old_model_env; + + join_tables_str << " ON "; + db_expression->table_with_index_to_stream(join_tables_str, model_env->table_name, model_env->table_index); + join_tables_str << '.'; + + // IMPROVE ME at the moment support only for foreign keys consisting of only one column + if( model_env->finder_helper->foreign_keys.size() == 1 ) + { + join_tables_str << model_env->finder_helper->foreign_keys.front(); + } + + join_tables_str << " = "; + db_expression->table_with_index_and_field_to_stream(join_tables_str, field_model.model_env->table_name, field_model.model_env->table_index, db_field_name, field_type); + } + + join_tables_str << ' '; + + db_expression->set_work_mode(expr_work_mode); + db_expression->set_output_type(expr_output_type); + db_expression->allow_to_use_prefix(expr_allow_prefix); + db_expression->set_text_stream(db_expression_stream); + } +} + + +/* + * first we iterate through fields and save primary key values to helper_tab + */ +void Model::field_model_save_key(const wchar_t * db_field_name) +{ + DbConnector * db_connector = model_connector->get_db_connector(); + pt::Log * plog = model_connector->get_logger(); + + if( db_connector ) + { + DbExpression * db_expression = db_connector->get_expression(); + + if( db_expression && !is_empty_field(db_field_name) && model_env->field_value_helper_tab ) + { + int old_work_mode = model_env->model_work_mode; + model_env->model_work_mode = MORM_MODEL_WORK_MODE_ITERATE_PRIMARY_KEY_VALUES; + model_env->field_index = 0; + fields(); + model_env->model_work_mode = old_work_mode; + + if( model_env->field_value_helper_tab->empty() && plog ) + { + (*plog) << pt::Log::log1 << "Morm: I cannot find a primary key in "; + log_table_name(); + (*plog) << pt::Log::logend; + } + } + } +} + + +/* + * now we iterate through fields in field_model and save primary key values from *this object to the specified fields in field_model + */ +void Model::field_model_set_parent_key_in_child(const wchar_t * db_field_name, Model & field_model) +{ + DbConnector * db_connector = model_connector->get_db_connector(); + pt::Log * log = model_connector->get_logger(); + + if( db_connector ) + { + DbExpression * db_expression = db_connector->get_expression(); + + if( db_expression && !is_empty_field(db_field_name) && model_env->field_value_helper_tab ) + { + std::vector & helper_tab = *model_env->field_value_helper_tab; + + if( (size_t)model_env->field_index == helper_tab.size() ) + { + ModelEnv model_env_local; + model_env_local.copy_global_objects(*model_env); + model_env_local.has_primary_key_set = field_model.has_primary_key_set; + model_env_local.model_work_mode = MORM_MODEL_WORK_MODE_SET_FIELD_VALUE; + model_env_local.field_value_helper_tab = &helper_tab; + model_env_local.field_index = 0; + field_model.model_env = &model_env_local; + field_model.table(); + + field_model.fields(); + + if( (size_t)field_model.model_env->field_index != helper_tab.size() && log ) + { + if( field_model.model_env->field_index == 0 ) + { + (*log) << pt::Log::log1 << "Morm: there is no a foreign key in "; + field_model.log_table_name(); + (*log) << " called " << db_field_name << " pointing to "; + log_table_name(); + (*log) << pt::Log::logend; + } + else + { + (*log) << pt::Log::log1 << "Morm: primary key in "; + log_table_name(); + (*log) << " consists of " << model_env->field_index << " column(s) but foreign key in "; + field_model.log_table_name(); + (*log) << " consists of " << field_model.model_env->field_index << " column(s)" << pt::Log::logend; + } + } + + field_model.model_env = nullptr; + } + else + if( log ) + { + (*log) << pt::Log::log1 << "Morm: primary key in "; + log_table_name(); + (*log) << " consists of incorrect number of columns, expected " << helper_tab.size() + << " column(s) but got " << model_env->field_index << pt::Log::logend; + } + } + } +} + + +void Model::field_model_set_parent_key(const wchar_t * db_field_name, Model & field_model) +{ + FieldValueHelper helper; + helper.db_field_name = db_field_name; + helper.flat_field_name = nullptr; + helper.compare_flat_field_name = false; + + std::vector helper_tab; + helper_tab.push_back(helper); + // only one column at the moment, in the future we can have a primary key from more than one column + + model_env->field_value_helper_tab = &helper_tab; + + field_model_save_key(db_field_name); + field_model_set_parent_key_in_child(db_field_name, field_model); + + model_env->field_value_helper_tab = nullptr; +} + + +void Model::field_model_iterate_through_childs(const wchar_t * db_field_name, Model & field_model, const FT & field_type) +{ + if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_INSERT ) + { + if( field_type.is_insertable() ) + field_model.insert_tree(true); + } + + if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_UPDATE ) + { + if( field_type.is_updatable() ) + field_model.update_tree(true); + } + + if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_REMOVE ) + { + if( field_type.is_removable() ) + field_model.remove_tree(true); + } + + if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_SAVE ) + { + if( (field_model.save_mode == Model::DO_INSERT_ON_SAVE && field_type.is_insertable()) || + (field_model.save_mode == Model::DO_UPDATE_ON_SAVE && field_type.is_updatable()) || + (field_model.save_mode == Model::DO_DELETE_ON_SAVE && field_type.is_removable()) ) + { + field_model.save_tree(true); + } + } +} + + + +void Model::field_model_generate_flat_string(const wchar_t * flat_field_name, Model & field_model, const FT & field_type) +{ + FlatConnector * flat_connector = model_connector->get_flat_connector(); + + if( flat_connector ) + { + FlatExpression * flat_expression = flat_connector->get_expression(); + + if( flat_expression ) + { + if( model_env->dump_mode || field_model.save_mode == DO_INSERT_ON_SAVE || field_model.save_mode == DO_UPDATE_ON_SAVE ) + { + field_model.model_env->model_work_mode = MORM_MODEL_WORK_MODE_GENERATING_FLAT_STRING; + flat_expression->field_model(flat_field_name, field_model, field_type, model_env); + } + } + } +} + + +void Model::field_model_generate_db_sql(const wchar_t * db_field_name, Model & field_model, const FT & field_type) +{ + DbConnector * db_connector = model_connector->get_db_connector(); + + if( db_connector ) + { + DbExpression * db_expression = db_connector->get_expression(); + + if( db_expression && !is_empty_field(db_field_name) ) + { + field_model.model_env->model_work_mode = MORM_MODEL_WORK_MODE_GENERATING_DB_SQL; + + if( db_expression->get_output_type() == MORM_OUTPUT_TYPE_SELECT_COLUMNS ) + { + field_model_left_join(db_field_name, field_model, field_type, db_expression); + } + + if( field_type.is_foreign_key() ) + { + if( db_expression->get_work_mode() == MORM_WORK_MODE_MODEL_FIELDS && db_expression->get_output_type() == MORM_OUTPUT_TYPE_DB_INSERT ) + { + if( field_type.is_insertable() ) + { + int not_used_object = 0; + db_expression->field(db_field_name, not_used_object, field_type, model_env); + } + } + + if( db_expression->get_work_mode() == MORM_WORK_MODE_MODEL_VALUES && db_expression->get_output_type() == MORM_OUTPUT_TYPE_DB_INSERT ) + { + if( field_type.is_insertable() ) + { + db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_INSERT_PRIMARY_KEY); + field_model.fields(); + db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_INSERT); + } + } + + if( db_expression->get_work_mode() == MORM_WORK_MODE_MODEL_FIELDS_VALUES && db_expression->get_output_type() == MORM_OUTPUT_TYPE_DB_UPDATE ) + { + if( field_type.is_updatable() ) + { + std::vector key_fields; + key_fields.push_back(db_field_name); // at the moment only one key + + db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_UPDATE_PRIMARY_KEY); + field_model.model_env->field_index = 0; + field_model.model_env->set_field_name_helper = &key_fields; + field_model.fields(); + db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_UPDATE); + + if( (size_t)field_model.model_env->field_index != key_fields.size() ) + { + // IMPROVEME + // number of keys are different + // put error log here + } + } + } + } + + if( db_expression->get_output_type() != MORM_OUTPUT_TYPE_JOIN_TABLES && + db_expression->get_output_type() != MORM_OUTPUT_TYPE_DB_PRIMARY_KEY && + db_expression->get_output_type() != MORM_OUTPUT_TYPE_DB_INSERT && + db_expression->get_output_type() != MORM_OUTPUT_TYPE_DB_UPDATE ) + { + field_model.fields(); + } + + field_model.model_env->model_work_mode = MORM_MODEL_WORK_MODE_NONE; + } + } +} + + +void Model::field_model_clear_values(Model & field_model) +{ + Clearer * clearer = model_connector->get_clearer(); + + if( clearer ) + { + clearer->clear_model(field_model); + } +} + + +void Model::field_model_read_values_from_queryresult(const wchar_t * db_field_name, Model & field_model, const FT & field_type) +{ + DbConnector * db_connector = model_connector->get_db_connector(); + + if( db_connector ) + { + DbExpression * db_expression = db_connector->get_expression(); + + if( db_expression ) + { + if( model_env->cursor_helper && + !model_env->cursor_helper->has_autogenerated_select && + model_env->cursor_helper->use_table_prefix_for_fetching_values ) + { + field_model.model_env->add_table_name_to_finder_helper(); + } + + field_model.before_select(); + field_model.map_values_from_query(); + + if( field_model.found() ) + { + field_model.after_select(); + } + } + } +} + + +void Model::field_model(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model, const FT & field_type) +{ + if( model_connector && model_env ) + { + ModelEnv model_env_local; + model_env_local.copy_global_objects(*model_env); + + field_model.model_env = &model_env_local; + field_model.model_env->has_primary_key_set = field_model.has_primary_key_set; + field_model.set_connector(model_connector); + + if( !is_empty_field(db_field_name) ) + { + field_model.table(); + + if( field_type.is_foreign_key() || field_type.is_foreign_key_in_child() ) + { + field_model_for_db(db_field_name, field_model, field_type); + } + else + { + pt::Log * plog = model_connector->get_logger(); + + if( plog ) + { + (*plog) << pt::Log::log1 << "Morm: error in "; + log_table_name_with_field(db_field_name); + (*plog) << " field, you should set FT::is_foreign_key or FT::is_foreign_key_in_child flag for a model child object" << pt::Log::logend; + } + } + } + + if( !is_empty_field(flat_field_name) ) + { + if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_GENERATING_FLAT_STRING ) + { + // calling field_model.table() is not needed in generating strings (at least for json/space formats) + field_model_generate_flat_string(flat_field_name, field_model, field_type); + } + } + + if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_CLEARING_VALUE ) + { + field_model_clear_values(field_model); + } + + field_model.model_env = nullptr; + } +} + + +void Model::field_model_for_db(const wchar_t * db_field_name, Model & field_model, const FT & field_type) +{ + if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_SET_PARENT_ID ) + { + if( field_type.is_foreign_key_in_child() ) + { + field_model_set_parent_key(db_field_name, field_model); + } + } + + if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITH_FOREIGN_KEY ) + { + if( field_type.is_foreign_key() ) + { + field_model_iterate_through_childs(db_field_name, field_model, field_type); + } + } + + if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITHOUT_FOREIGN_KEY ) + { + if( field_type.is_foreign_key_in_child() ) + { + field_model_iterate_through_childs(db_field_name, field_model, field_type); + } + } + + if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_GENERATING_DB_SQL ) + { + field_model_generate_db_sql(db_field_name, field_model, field_type); + } + + + if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_READING_VALUE_FROM_DB_RESULTSET ) + { + field_model_read_values_from_queryresult(db_field_name, field_model, field_type); + } +} + + +void Model::set_parent_key_in_childs() +{ + if( model_env ) + { + model_env->model_work_mode = MORM_MODEL_WORK_MODE_SET_PARENT_ID; + fields(); + } +} + + + +bool Model::db_query(const char * raw_sql) +{ + bool status = false; + + if( model_connector ) + { + DbConnector * db_connector = model_connector->get_db_connector(); + + if( db_connector ) + { + status = db_connector->query(raw_sql); + } + } + + return status; +} + + +bool Model::db_query(const std::string & raw_sql) +{ + return db_query(raw_sql.c_str()); +} + + +bool Model::db_query(const pt::TextStream & raw_sql) +{ + bool status = false; + + if( model_connector ) + { + DbConnector * db_connector = model_connector->get_db_connector(); + + if( db_connector ) + { + status = db_connector->query(raw_sql); + } + } + + return status; +} + + + } // namespace diff --git a/src/model.h b/src/model.h index 5da8e56..c7596b9 100644 --- a/src/model.h +++ b/src/model.h @@ -42,10 +42,12 @@ #include #include "textstream/textstream.h" +#include "space/space.h" #include "modelconnector.h" #include "dbexpression.h" #include "flatexpression.h" #include "modelenv.h" +#include "ft.h" namespace morm @@ -67,6 +69,9 @@ public: virtual void set_save_mode(SaveMode save_mode); virtual SaveMode get_save_mode(); + virtual void set_has_primary_key_set(bool has_primary_key); + virtual bool get_has_primary_key_set(); + virtual void mark_to_delete(); virtual void mark_to_remove(); @@ -81,26 +86,13 @@ public: void set_connector(ModelConnector * connector); ModelConnector * get_connector(); - /* - * map fields to names - * - * - */ - virtual void map_fields() = 0; + virtual void get_table_name(pt::WTextStream & stream, bool with_schema_name = true, ModelData * model_data = nullptr, bool clear_stream = true); + virtual void get_table_name(std::wstring & str, bool with_schema_name = true, ModelData * model_data = nullptr, bool clear_string = true); + virtual void get_table_name(std::string & str, bool with_schema_name = true, ModelData * model_data = nullptr, bool clear_string = true); - - - /* - * - * we can use the object for a different purpose than database (e.g. json) - * so let the table_name be non pure-virtual - * - */ - virtual void table_name(PT::TextStream & stream); - - virtual void to_text(PT::TextStream & stream, ModelData * model_data, bool clear_stream = true, bool dump_mode = false); - virtual void to_text(PT::TextStream & stream, ModelData & model_data, bool clear_stream = true, bool dump_mode = false); - virtual void to_text(PT::TextStream & stream, bool clear_stream = true, bool dump_mode = false); + virtual void to_text(pt::TextStream & stream, ModelData * model_data, bool clear_stream = true, bool dump_mode = false); + virtual void to_text(pt::TextStream & stream, ModelData & model_data, bool clear_stream = true, bool dump_mode = false); + virtual void to_text(pt::TextStream & stream, bool clear_stream = true, bool dump_mode = false); virtual void to_text(std::string & str, ModelData * model_data, bool clear_string = true, bool dump_mode = false); virtual void to_text(std::string & str, ModelData & model_data, bool clear_string = true, bool dump_mode = false); @@ -109,17 +101,17 @@ public: virtual std::string to_text(); virtual std::string to_string(); - virtual void generate_insert_query(PT::TextStream & stream, ModelData * model_data = nullptr); + virtual void generate_insert_query(pt::TextStream & stream, ModelData * model_data = nullptr); virtual bool insert(ModelData * model_data, bool insert_whole_tree = true); virtual bool insert(ModelData & model_data, bool insert_whole_tree = true); virtual bool insert(bool insert_whole_tree = true); - virtual void generate_update_query(PT::TextStream & stream, ModelData * model_data = nullptr); + virtual void generate_update_query(pt::TextStream & stream, ModelData * model_data = nullptr); virtual bool update(ModelData * model_data, bool update_whole_tree = true); virtual bool update(ModelData & model_data, bool update_whole_tree = true); virtual bool update(bool update_whole_tree = true); - virtual void generate_remove_query(PT::TextStream & stream, ModelData * model_data = nullptr); + virtual void generate_remove_query(pt::TextStream & stream, ModelData * model_data = nullptr); virtual bool remove(ModelData * model_data, bool remove_whole_tree = true); virtual bool remove(ModelData & model_data, bool remove_whole_tree = true); virtual bool remove(bool remove_whole_tree = true); @@ -129,11 +121,14 @@ public: virtual bool save(bool save_whole_tree = true); - virtual void generate_select_columns(PT::TextStream & stream); + virtual void generate_select_columns(pt::TextStream & stream); // set object to default values virtual void clear(); + virtual bool do_migration(int & current_table_version); + + // IMPROVE ME this will be protected // add set_field_value() functions for each POD type template @@ -143,6 +138,7 @@ public: model_env = &model_env_local; model_env->model_work_mode = MORM_MODEL_WORK_MODE_SET_FIELD_VALUE; model_env->field_index = 0; + table(); // CHECK ME it is needed to set table name? FieldValueHelper field_value_helper; field_value_helper.db_field_name = db_field_name; @@ -154,17 +150,17 @@ public: helper_tab.push_back(field_value_helper); model_env->field_value_helper_tab = &helper_tab; - map_fields(); + fields(); if( !helper_tab.back().found && model_connector ) { - PT::Log * plog = model_connector->get_logger(); + pt::Log * plog = model_connector->get_logger(); if( plog ) { - (*plog) << "Morm: I cannot find such a property: "; + (*plog) << pt::Log::log1 << "Morm: I cannot find such a property: "; put_fields_to_log(*plog, db_field_name, flat_field_name); - (*plog) << PT::Log::logend; + (*plog) << pt::Log::logend; } } @@ -176,8 +172,9 @@ public: protected: ModelConnector * model_connector; - SaveMode save_mode; ModelEnv * model_env; + SaveMode save_mode; + bool has_primary_key_set; @@ -185,6 +182,15 @@ protected: Model(const Model & m); virtual ~Model(); + /* + * the main method of mapping between fields and database resultsets + */ + virtual void fields() = 0; + + virtual void table(); + virtual void table_name(const wchar_t * table_name); + virtual void table_name(const wchar_t * schema_name, const wchar_t * table_name); + virtual void before_select(); virtual void before_insert(); virtual void before_update(); @@ -211,253 +217,248 @@ protected: virtual void map_values_from_query(); + virtual bool db_query(const char * raw_sql); + virtual bool db_query(const std::string & raw_sql); + virtual bool db_query(const pt::TextStream & raw_sql); ///////////////////////////////// /* * IMPLEMENT ME - * field methods for such field_values: signed char, wchar_t, char16_t, char32_t, std::u16string, std::u32string + * field methods for such field_values: signed char, char16_t, char32_t, std::u16string, std::u32string * */ - - void field(const wchar_t * field_name, char & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, char & field_value, const FT & field_type = FT::default_type) { - field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); + field_generic(field_name, field_name, field_value, field_type); } - void field(const wchar_t * field_name, unsigned char & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, unsigned char & field_value, const FT & field_type = FT::default_type) { - field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); + field_generic(field_name, field_name, field_value, field_type); } - void field(const wchar_t * field_name, std::wstring & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, wchar_t & field_value, const FT & field_type = FT::default_type) { - field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); + field_generic(field_name, field_name, field_value, field_type); } -// void field(const wchar_t * field_name, wchar_t * field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) -// { -// field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); -// } - - void field(const wchar_t * field_name, std::string & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, std::wstring & field_value, const FT & field_type = FT::default_type) { - field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); + field_generic(field_name, field_name, field_value, field_type); } -// void field(const wchar_t * field_name, char * field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) -// { -// field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); -// } - - void field(const wchar_t * field_name, bool & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, std::string & field_value, const FT & field_type = FT::default_type) { - field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); + field_generic(field_name, field_name, field_value, field_type); } - void field(const wchar_t * field_name, short & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, bool & field_value, const FT & field_type = FT::default_type) { - field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); + field_generic(field_name, field_name, field_value, field_type); } - void field(const wchar_t * field_name, unsigned short & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, short & field_value, const FT & field_type = FT::default_type) { - field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); + field_generic(field_name, field_name, field_value, field_type); } - void field(const wchar_t * field_name, int & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, unsigned short & field_value, const FT & field_type = FT::default_type) { - field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); + field_generic(field_name, field_name, field_value, field_type); } - void field(const wchar_t * field_name, unsigned int & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, int & field_value, const FT & field_type = FT::default_type) { - field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); + field_generic(field_name, field_name, field_value, field_type); } - void field(const wchar_t * field_name, long & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, unsigned int & field_value, const FT & field_type = FT::default_type) { - field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); + field_generic(field_name, field_name, field_value, field_type); } - void field(const wchar_t * field_name, unsigned long & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, long & field_value, const FT & field_type = FT::default_type) { - field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); + field_generic(field_name, field_name, field_value, field_type); } - void field(const wchar_t * field_name, long long & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, unsigned long & field_value, const FT & field_type = FT::default_type) { - field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); + field_generic(field_name, field_name, field_value, field_type); } - void field(const wchar_t * field_name, unsigned long long & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, long long & field_value, const FT & field_type = FT::default_type) { - field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); + field_generic(field_name, field_name, field_value, field_type); } - void field(const wchar_t * field_name, float & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, unsigned long long & field_value, const FT & field_type = FT::default_type) { - field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); + field_generic(field_name, field_name, field_value, field_type); } - void field(const wchar_t * field_name, double & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, float & field_value, const FT & field_type = FT::default_type) { - field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); + field_generic(field_name, field_name, field_value, field_type); } - void field(const wchar_t * field_name, long double & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, double & field_value, const FT & field_type = FT::default_type) { - field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); + field_generic(field_name, field_name, field_value, field_type); } -// void field(const wchar_t * field_name, void * field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) -// { -// field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); -// } - - void field(const wchar_t * field_name, PT::Date & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) + void field(const wchar_t * field_name, long double & field_value, const FT & field_type = FT::default_type) { - field_generic(field_name, field_name, field_value, insertable, updatable, is_primary_key); + field_generic(field_name, field_name, field_value, field_type); } - void field(const wchar_t * field_name, Model & field_value, bool insertable = true, bool updatable = true, bool has_foreign_key = true) + void field(const wchar_t * field_name, pt::Date & field_value, const FT & field_type = FT::default_type) { - field_model(field_name, field_name, field_value, insertable, updatable, has_foreign_key); + field_generic(field_name, field_name, field_value, field_type); + } + + void field(const wchar_t * field_name, pt::Space & field_value, const FT & field_type = FT::default_type) + { + field_generic(field_name, field_name, field_value, field_type); + } + + void field(const wchar_t * field_name, Model & field_value, const FT & field_type = FT::default_type) + { + field_model(field_name, field_name, field_value, field_type); } template - void field(const wchar_t * field_name, std::list & field_value, bool insertable = true, bool updatable = true) + void field(const wchar_t * field_name, std::list & field_value, const FT & field_type = FT::default_type) { ModelClass * list_model_null_pointer = nullptr; - field_list(field_name, field_name, field_value, list_model_null_pointer, insertable, updatable); + field_list(field_name, field_name, field_value, list_model_null_pointer, field_type); } template - void field(const wchar_t * field_name, std::vector & field_value, bool insertable = true, bool updatable = true) + void field(const wchar_t * field_name, std::vector & field_value, const FT & field_type = FT::default_type) { ModelClass * list_model_null_pointer = nullptr; - field_list(field_name, field_name, field_value, list_model_null_pointer, insertable, updatable); - } - -////////////////////// - - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, char & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) - { - field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); - } - - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned char & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) - { - field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); - } - - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::wstring & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) - { - field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); - } - -// void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, wchar_t * field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) -// { -// field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); -// } - - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::string & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) - { - field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); - } - -// void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, char * field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) -// { -// field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); -// } - - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, bool & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) - { - field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); - } - - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, short & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) - { - field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); - } - - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned short & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) - { - field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); - } - - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, int & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) - { - field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); - } - - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned int & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) - { - field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); - } - - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, long & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) - { - field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); - } - - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned long & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) - { - field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); - } - - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, long long & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) - { - field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); - } - - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned long long & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) - { - field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); - } - - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, float & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) - { - field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); - } - - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, double & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) - { - field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); - } - - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, long double & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) - { - field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); - } - -// void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, void * field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) -// { -// field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); -// } - - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, PT::Date & field_value, bool insertable = true, bool updatable = true, bool is_primary_key = false) - { - field_generic(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); + field_list(field_name, field_name, field_value, list_model_null_pointer, field_type); } - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_value, bool insertable = true, bool updatable = true, bool has_foreign_key = true) + /* + * field methods which take two names: db_field_name and flat_field_name + */ + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, char & field_value, const FT & field_type = FT::default_type) { - field_model(db_field_name, flat_field_name, field_value, insertable, updatable, has_foreign_key); + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned char & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, wchar_t & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::wstring & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::string & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, bool & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, short & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned short & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, int & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned int & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, long & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned long & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, long long & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, unsigned long long & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, float & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, double & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, long double & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, pt::Date & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, pt::Space & field_value, const FT & field_type = FT::default_type) + { + field_generic(db_field_name, flat_field_name, field_value, field_type); + } + + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_value, const FT & field_type = FT::default_type) + { + // has_foreign_key was here + field_model(db_field_name, flat_field_name, field_value, field_type); } template - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::list & field_value, bool insertable = true, bool updatable = true) + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::list & field_value, const FT & field_type = FT::default_type) { ModelClass * list_model_null_pointer = nullptr; - field_list(db_field_name, flat_field_name, field_value, list_model_null_pointer, insertable, updatable); + field_list(db_field_name, flat_field_name, field_value, list_model_null_pointer, field_type); } template - void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::vector & field_value, bool insertable = true, bool updatable = true) + void field(const wchar_t * db_field_name, const wchar_t * flat_field_name, std::vector & field_value, const FT & field_type = FT::default_type) { ModelClass * list_model_null_pointer = nullptr; - field_list(db_field_name, flat_field_name, field_value, list_model_null_pointer, insertable, updatable); + field_list(db_field_name, flat_field_name, field_value, list_model_null_pointer, field_type); } @@ -466,14 +467,14 @@ protected: template - void field_generic_set_field_value(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key) + void field_generic_set_field_value(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value) { if( model_env->field_value_helper_tab ) { if( model_env->field_index >= 0 && (size_t)model_env->field_index < model_env->field_value_helper_tab->size() ) { FieldValueHelper & helper = (*model_env->field_value_helper_tab)[model_env->field_index]; - PT::Log * log = model_connector->get_logger(); + pt::Log * log = model_connector->get_logger(); if( (!helper.compare_db_field_name || is_the_same_field(db_field_name, helper.db_field_name)) && (!helper.compare_flat_field_name || is_the_same_field(flat_field_name, helper.flat_field_name)) ) @@ -486,14 +487,14 @@ protected: } else { - table_name(model_env->table_name); - if( log ) { - (*log) << PT::Log::log1 << "Morm: incorrect type of a field in " << model_env->table_name << ", "; + (*log) << pt::Log::log1 << "Morm: incorrect type of a field in "; + log_table_name(); + (*log) << ", "; put_fields_to_log(*log, db_field_name, flat_field_name); (*log) << ", type expected " << typeid(field_value).name() - << " got " << helper.value_type_info->name() << PT::Log::logend; + << " got " << helper.value_type_info->name() << pt::Log::logend; } } } @@ -505,10 +506,11 @@ protected: } } + template - void field_generic_iterate_primary_key_values(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key) + void field_generic_iterate_primary_key_values(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, const FT & field_type) { - if( is_primary_key ) + if( field_type.is_primary_key() ) { if( model_env->field_value_helper_tab ) { @@ -524,8 +526,9 @@ protected: } } + template - void field_generic_generate_flat_string(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key) + void field_generic_generate_flat_string(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, const FT & field_type) { FlatConnector * flat_connector = model_connector->get_flat_connector(); @@ -535,14 +538,14 @@ protected: if( flat_expression && !is_empty_field(flat_field_name) ) { - // insertable, updatable and is_primary_key are ignored here - flat_expression->field(flat_field_name, field_value, insertable, updatable, is_primary_key, model_env); + flat_expression->field(flat_field_name, field_value, field_type, model_env); } } } + template - void field_generic_generate_db_sql(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key) + void field_generic_generate_db_sql(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, const FT & field_type) { DbConnector * db_connector = model_connector->get_db_connector(); @@ -552,13 +555,14 @@ protected: if( db_expression && !is_empty_field(db_field_name) ) { - db_expression->field(db_field_name, field_value, insertable, updatable, is_primary_key, model_env); + db_expression->field(db_field_name, field_value, field_type, model_env); } } } + template - void field_generic_read_value_from_db_resultset(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key) + void field_generic_read_value_from_db_resultset(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, const FT & field_type) { DbConnector * db_connector = model_connector->get_db_connector(); @@ -568,19 +572,20 @@ protected: { if( model_env->cursor_helper && model_env->cursor_helper->has_autogenerated_select ) { - get_value_by_field_index(model_env->cursor_helper->current_column, field_value); + get_value_by_field_index(model_env->cursor_helper->current_column, field_value, field_type); model_env->cursor_helper->current_column += 1; } else { - get_value_by_field_name(db_field_name, field_value); + get_value_by_field_name(db_field_name, field_value, field_type); } } } } + template - void field_generic_clear_value(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key) + void field_generic_clear_value(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, const FT & field_type) { Clearer * clearer = model_connector->get_clearer(); @@ -592,432 +597,59 @@ protected: template - void field_generic(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, bool insertable, bool updatable, bool is_primary_key) + void field_generic(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value, const FT & field_type) { if( model_connector && model_env ) { + if( field_type.is_primary_key() ) + { + model_env->was_primary_key_read = true; + } + if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_SET_FIELD_VALUE ) { - field_generic_set_field_value(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); + field_generic_set_field_value(db_field_name, flat_field_name, field_value); } if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_ITERATE_PRIMARY_KEY_VALUES ) { - field_generic_iterate_primary_key_values(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); + field_generic_iterate_primary_key_values(db_field_name, flat_field_name, field_value, field_type); } if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_GENERATING_FLAT_STRING ) { - field_generic_generate_flat_string(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); + field_generic_generate_flat_string(db_field_name, flat_field_name, field_value, field_type); } if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_GENERATING_DB_SQL ) { - field_generic_generate_db_sql(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); + field_generic_generate_db_sql(db_field_name, flat_field_name, field_value, field_type); } if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_READING_VALUE_FROM_DB_RESULTSET ) { - field_generic_read_value_from_db_resultset(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); + field_generic_read_value_from_db_resultset(db_field_name, flat_field_name, field_value, field_type); } if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_CLEARING_VALUE ) { - field_generic_clear_value(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key); + field_generic_clear_value(db_field_name, flat_field_name, field_value, field_type); } } } - /* - * IMPROVE ME there can be more rows in the result set when there are more items on the left hand side of the join - * this is only in a case when has_foreign_key is false, may it can be ignored? we can use unique index in such a case - * - */ - void field_model_left_join(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model, bool insertable, bool updatable, bool has_foreign_key, DbExpression * db_expression) - { - if( model_env && field_model.model_env && model_env->finder_helper ) - { - model_env->finder_helper->foreign_keys.clear(); - PT::TextStream & join_tables_str = model_env->finder_helper->join_tables_str; - field_model.model_env->table_index = model_env->finder_helper->add_join_table(field_model.model_env->table_name_short); - - join_tables_str << "LEFT JOIN " << field_model.model_env->table_name << " AS "; - field_model.put_table_name_with_index(join_tables_str); - - int expr_work_mode = db_expression->get_work_mode(); - int expr_output_type = db_expression->get_output_type(); - bool expr_allow_prefix = db_expression->get_allow_to_use_prefix(); - - db_expression->set_work_mode(MORM_WORK_MODE_MODEL_SAVE_FIELDS); - db_expression->set_output_type(MORM_OUTPUT_TYPE_JOIN_TABLES); - db_expression->allow_to_use_prefix(false); - - if( has_foreign_key ) - { - field_model.map_fields(); - - join_tables_str << " ON "; - put_table_name_with_index(join_tables_str); - join_tables_str << '.' << db_field_name << " = "; - field_model.put_table_name_with_index(join_tables_str); - join_tables_str << '.'; - - // IMPROVE ME at the moment support only for foreign keys consisting of only one column - if( model_env->finder_helper->foreign_keys.size() == 1 ) - { - join_tables_str << model_env->finder_helper->foreign_keys.front(); - } - } - else - { - ModelEnv * old_model_env = field_model.model_env; - map_fields(); // map_fields() will set field_model.model_env to null - field_model.model_env = old_model_env; - - join_tables_str << " ON "; - put_table_name_with_index(join_tables_str); - join_tables_str << '.'; - - // IMPROVE ME at the moment support only for foreign keys consisting of only one column - if( model_env->finder_helper->foreign_keys.size() == 1 ) - { - join_tables_str << model_env->finder_helper->foreign_keys.front(); - } - - join_tables_str << " = "; - field_model.put_table_name_with_index(join_tables_str); - join_tables_str << '.' << db_field_name; - } - - join_tables_str << ' '; - - db_expression->set_work_mode(expr_work_mode); - db_expression->set_output_type(expr_output_type); - db_expression->allow_to_use_prefix(expr_allow_prefix); - } - } - - - /* - * first we iterate through fields and save primary key values to helper_tab - */ - void field_model_save_key(const wchar_t * db_field_name) - { - DbConnector * db_connector = model_connector->get_db_connector(); - PT::Log * plog = model_connector->get_logger(); - - if( db_connector ) - { - DbExpression * db_expression = db_connector->get_expression(); - - if( db_expression && !is_empty_field(db_field_name) && model_env->field_value_helper_tab ) - { - int old_work_mode = model_env->model_work_mode; - model_env->model_work_mode = MORM_MODEL_WORK_MODE_ITERATE_PRIMARY_KEY_VALUES; - model_env->field_index = 0; - map_fields(); - model_env->model_work_mode = old_work_mode; - - if( model_env->field_value_helper_tab->empty() && plog ) - { - (*plog) << "Morm: I cannot find a primary key in " << model_env->table_name << PT::Log::logend; - } - } - } - } - - - /* - * now we iterate through fields in field_model and save primary key values from *this object to the specified fields in field_model - */ - void field_model_set_parent_key_in_child(const wchar_t * db_field_name, Model & field_model) - { - DbConnector * db_connector = model_connector->get_db_connector(); - PT::Log * log = model_connector->get_logger(); - - if( db_connector ) - { - DbExpression * db_expression = db_connector->get_expression(); - - if( db_expression && !is_empty_field(db_field_name) && model_env->field_value_helper_tab ) - { - std::vector & helper_tab = *model_env->field_value_helper_tab; - - if( (size_t)model_env->field_index == helper_tab.size() ) - { - ModelEnv model_env_local; - model_env_local.copy_global_objects(*model_env); - model_env_local.model_work_mode = MORM_MODEL_WORK_MODE_SET_FIELD_VALUE; - model_env_local.field_value_helper_tab = &helper_tab; - model_env_local.field_index = 0; - field_model.model_env = &model_env_local; - - field_model.map_fields(); - - if( (size_t)field_model.model_env->field_index != helper_tab.size() && log ) - { - if( model_env->table_name.empty() ) - table_name(model_env->table_name); - - if( field_model.model_env->table_name.empty() ) - field_model.table_name(field_model.model_env->table_name); - - (*log) << PT::Log::log1 << "Morm: primary key in " << model_env->table_name << " consists of " << model_env->field_index << " column(s)" - << " but in " << field_model.model_env->table_name << " there are only " - << field_model.model_env->field_index << " matching column(s)" << PT::Log::logend; - } - - field_model.model_env = nullptr; - } - else - if( log ) - { - table_name(model_env->table_name); - - (*log) << PT::Log::log1 << "Morm: primary key in " << model_env->table_name << " consists of incorrect number of columns" - << ", expected " << helper_tab.size() << " column(s) but got " << model_env->field_index << PT::Log::logend; - } - } - } - } - - - void field_model_set_parent_key(const wchar_t * db_field_name, Model & field_model) - { - FieldValueHelper helper; - helper.db_field_name = db_field_name; - helper.flat_field_name = nullptr; - helper.compare_flat_field_name = false; - - std::vector helper_tab; - helper_tab.push_back(helper); - // only one column at the moment, in the future we can have a primary key from more than one column - - model_env->field_value_helper_tab = &helper_tab; - - field_model_save_key(db_field_name); - field_model_set_parent_key_in_child(db_field_name, field_model); - - model_env->field_value_helper_tab = nullptr; - } - - - void field_model_iterate_through_childs(const wchar_t * db_field_name, Model & field_model) - { - if( !is_empty_field(db_field_name) ) - { - if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_INSERT ) - { - field_model.insert_tree(true); - } - - if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_UPDATE ) - { - field_model.update_tree(true); - } - - if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_REMOVE ) - { - field_model.remove_tree(true); - } - - if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_SAVE ) - { - field_model.save_tree(true); - } - } - } - - - - void field_model_generate_flat_string(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model, bool insertable, bool updatable) - { - FlatConnector * flat_connector = model_connector->get_flat_connector(); - - if( flat_connector ) - { - FlatExpression * flat_expression = flat_connector->get_expression(); - - if( flat_expression && !is_empty_field(flat_field_name) ) - { - if( model_env->dump_mode || field_model.save_mode == DO_INSERT_ON_SAVE || field_model.save_mode == DO_UPDATE_ON_SAVE ) - { - field_model.model_env->model_work_mode = MORM_MODEL_WORK_MODE_GENERATING_FLAT_STRING; - flat_expression->field_model(flat_field_name, field_model, insertable, updatable, false, model_env); - } - } - } - } - - - void field_model_generate_db_sql(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model, bool insertable, bool updatable, bool has_foreign_key) - { - DbConnector * db_connector = model_connector->get_db_connector(); - - if( db_connector ) - { - DbExpression * db_expression = db_connector->get_expression(); - - if( db_expression && !is_empty_field(db_field_name) ) - { - field_model.model_env->model_work_mode = MORM_MODEL_WORK_MODE_GENERATING_DB_SQL; - - field_model.table_name(field_model.model_env->table_name); - db_expression->prepare_short_table_name(field_model.model_env->table_name, field_model.model_env->table_name_short); - - if( db_expression->get_output_type() == MORM_OUTPUT_TYPE_SELECT_COLUMNS ) - { - field_model_left_join(db_field_name, flat_field_name, field_model, insertable, updatable, has_foreign_key, db_expression); - } - - if( has_foreign_key ) - { - if( db_expression->get_work_mode() == MORM_WORK_MODE_MODEL_FIELDS && db_expression->get_output_type() == MORM_OUTPUT_TYPE_DB_INSERT ) - { - int not_used_object = 0; - db_expression->field(db_field_name, not_used_object, insertable, updatable, false, model_env); - } - - if( db_expression->get_work_mode() == MORM_WORK_MODE_MODEL_VALUES && db_expression->get_output_type() == MORM_OUTPUT_TYPE_DB_INSERT ) - { - db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_INSERT_PRIMARY_KEY); - field_model.map_fields(); - db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_INSERT); - } - - if( db_expression->get_work_mode() == MORM_WORK_MODE_MODEL_FIELDS_VALUES && db_expression->get_output_type() == MORM_OUTPUT_TYPE_DB_UPDATE ) - { - std::vector key_fields; - key_fields.push_back(db_field_name); // at the moment only one key - - db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_UPDATE_PRIMARY_KEY); - field_model.model_env->field_index = 0; - field_model.model_env->set_field_name_helper = &key_fields; - field_model.map_fields(); - db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_UPDATE); - - if( (size_t)field_model.model_env->field_index != key_fields.size() ) - { - // number of keys are different - // put error log here - } - } - } - - if( db_expression->get_output_type() != MORM_OUTPUT_TYPE_JOIN_TABLES && - db_expression->get_output_type() != MORM_OUTPUT_TYPE_DB_PRIMARY_KEY && - db_expression->get_output_type() != MORM_OUTPUT_TYPE_DB_INSERT && - db_expression->get_output_type() != MORM_OUTPUT_TYPE_DB_UPDATE ) - { - field_model.map_fields(); - } - - field_model.model_env->model_work_mode = MORM_MODEL_WORK_MODE_NONE; - } - } - } - - - void field_model_clear_values(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model, bool insertable, bool updatable, bool has_foreign_key) - { - Clearer * clearer = model_connector->get_clearer(); - - if( clearer ) - { - clearer->clear_model(field_model); - } - } - - - void field_model_read_values_from_queryresult(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model, bool insertable, bool updatable, bool has_foreign_key) - { - DbConnector * db_connector = model_connector->get_db_connector(); - - if( db_connector ) - { - if( !is_empty_field(db_field_name) ) - { - DbExpression * db_expression = db_connector->get_expression(); - - if( db_expression ) - { - if( model_env->cursor_helper && - !model_env->cursor_helper->has_autogenerated_select && - model_env->cursor_helper->use_table_prefix_for_fetching_values ) - { - field_model.prepare_table_names(); - } - - field_model.before_select(); - field_model.map_values_from_query(); - - if( field_model.found() ) - { - field_model.after_select(); - } - } - } - } - } - - void field_model(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model, bool insertable, bool updatable, bool has_foreign_key) - { - if( model_connector && model_env ) - { - ModelEnv model_env_local; - model_env_local.copy_global_objects(*model_env); - - field_model.model_env = &model_env_local; - field_model.set_connector(model_connector); - - if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_SET_PARENT_ID ) - { - if( !has_foreign_key ) - { - field_model_set_parent_key(db_field_name, field_model); - } - } - - if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITH_FOREIGN_KEY ) - { - if( has_foreign_key ) - { - field_model_iterate_through_childs(db_field_name, field_model); - } - } - - if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITHOUT_FOREIGN_KEY ) - { - if( !has_foreign_key ) - { - field_model_iterate_through_childs(db_field_name, field_model); - } - } - - if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_GENERATING_FLAT_STRING ) - { - field_model_generate_flat_string(db_field_name, flat_field_name, field_model, insertable, updatable); - } - - if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_GENERATING_DB_SQL ) - { - field_model_generate_db_sql(db_field_name, flat_field_name, field_model, insertable, updatable, has_foreign_key); - } - - if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_CLEARING_VALUE ) - { - field_model_clear_values(db_field_name, flat_field_name, field_model, insertable, updatable, has_foreign_key); - } - - if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_READING_VALUE_FROM_DB_RESULTSET ) - { - field_model_read_values_from_queryresult(db_field_name, flat_field_name, field_model, insertable, updatable, has_foreign_key); - } - - field_model.model_env = nullptr; - } - } + void field_model_left_join(const wchar_t * db_field_name, Model & field_model, const FT & field_type, DbExpression * db_expression); + void field_model_save_key(const wchar_t * db_field_name); + void field_model_set_parent_key_in_child(const wchar_t * db_field_name, Model & field_model); + void field_model_set_parent_key(const wchar_t * db_field_name, Model & field_model); + void field_model_iterate_through_childs(const wchar_t * db_field_name, Model & field_model, const FT & field_type); + void field_model_generate_flat_string(const wchar_t * flat_field_name, Model & field_model, const FT & field_type); + void field_model_generate_db_sql(const wchar_t * db_field_name, Model & field_model, const FT & field_type); + void field_model_clear_values(Model & field_model); + void field_model_read_values_from_queryresult(const wchar_t * db_field_name, Model & field_model, const FT & field_type); + void field_model(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model & field_model, const FT & field_type); + void field_model_for_db(const wchar_t * db_field_name, Model & field_model, const FT & field_type); template @@ -1048,45 +680,43 @@ protected: template void field_list_iterate_through_childs(const wchar_t * db_field_name, ModelContainer & field_container, ModelContainerType * model_container_type) { - if( !is_empty_field(db_field_name) ) + for(ModelContainerType & child_model : field_container) { - for(ModelContainerType & child_model : field_container) + ModelEnv model_env_local; + model_env_local.copy_global_objects(*model_env); + + child_model.model_env = &model_env_local; + child_model.model_env->has_primary_key_set = child_model.has_primary_key_set; + child_model.set_connector(model_connector); + child_model.table(); + + if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_INSERT ) { - ModelEnv model_env_local; - model_env_local.copy_global_objects(*model_env); - - child_model.model_env = &model_env_local; - child_model.set_connector(model_connector); - - if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_INSERT ) - { - child_model.insert_tree(true); - } - - if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_UPDATE ) - { - child_model.update_tree(true); - } - - if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_REMOVE ) - { - child_model.remove_tree(true); - } - - if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_SAVE ) - { - child_model.save_tree(true); - } - - child_model.model_env = nullptr; + child_model.insert_tree(true); } - } + if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_UPDATE ) + { + child_model.update_tree(true); + } + + if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_REMOVE ) + { + child_model.remove_tree(true); + } + + if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_SAVE ) + { + child_model.save_tree(true); + } + + child_model.model_env = nullptr; + } } template - void field_list_generate_flat_string(const wchar_t * flat_field_name, ModelContainer & field_container, bool insertable, bool updatable) + void field_list_generate_flat_string(const wchar_t * flat_field_name, ModelContainer & field_container, const FT & field_type) { FlatConnector * flat_connector = model_connector->get_flat_connector(); @@ -1094,10 +724,9 @@ protected: { FlatExpression * flat_expression = flat_connector->get_expression(); - if( flat_expression && !is_empty_field(flat_field_name) ) + if( flat_expression ) { - // insertable and updatable will be ignored there - flat_expression->field_list(flat_field_name, field_container, insertable, updatable, false, model_connector, model_env); + flat_expression->field_list(flat_field_name, field_container, field_type, model_connector, model_env); } } } @@ -1116,38 +745,69 @@ protected: template - void field_list(const wchar_t * db_field_name, const wchar_t * flat_field_name, ModelContainer & field_container, ModelContainerType * model_container_type, bool insertable, bool updatable) + void field_list(const wchar_t * db_field_name, const wchar_t * flat_field_name, ModelContainer & field_container, ModelContainerType * model_container_type, const FT & field_type) { if( model_connector && model_env ) { + pt::Log * plog = model_connector->get_logger(); + if( !is_empty_field(db_field_name) ) { - if constexpr (std::is_base_of()) + /* + * IMPROVEME + * field_type.is_foreign_key() is not implemented for lists yet + * (in such a case parent will point only to one object (or none) so the list will consists of only one object (or none)) + */ + if( field_type.is_foreign_key() ) { - if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_SET_PARENT_ID ) + if( plog ) { - field_list_set_parent_key(db_field_name, field_container, model_container_type); + (*plog) << pt::Log::log1 << "Morm: error: FT::is_foreign_key is not implemented for a list/vector yet" << pt::Log::logend; + return; } + } - if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITHOUT_FOREIGN_KEY ) + if( field_type.is_foreign_key() || field_type.is_foreign_key_in_child() ) + { + if constexpr (std::is_base_of()) { - field_list_iterate_through_childs(db_field_name, field_container, model_container_type); + if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_SET_PARENT_ID ) + { + field_list_set_parent_key(db_field_name, field_container, model_container_type); + } + + if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITHOUT_FOREIGN_KEY ) + { + field_list_iterate_through_childs(db_field_name, field_container, model_container_type); + } + } + else + { + if( plog ) + { + (*plog) << pt::Log::log1 << "Morm: ignoring "; + log_table_name_with_field(db_field_name); + (*plog) << " as this is not a container with Model objects" << pt::Log::logend; + } } } else { - PT::Log * plog = model_connector->get_logger(); - if( plog ) { - (*plog) << "Morm: ignoring " << db_field_name << " as this is not a container with Model objects" << PT::Log::logend; + (*plog) << pt::Log::log1 << "Morm: error in "; + log_table_name_with_field(db_field_name); + (*plog) << " field, you should set FT::is_foreign_key or FT::is_foreign_key_in_child flag for a list of child objects" << pt::Log::logend; } } } - if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_GENERATING_FLAT_STRING ) + if( !is_empty_field(flat_field_name) ) { - field_list_generate_flat_string(flat_field_name, field_container, insertable, updatable); + if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_GENERATING_FLAT_STRING ) + { + field_list_generate_flat_string(flat_field_name, field_container, field_type); + } } if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_CLEARING_VALUE ) @@ -1159,7 +819,7 @@ protected: template - void get_value_by_field_index(int field_index, FieldValue & field_value) + void get_value_by_field_index(int field_index, FieldValue & field_value, const FT & field_type) { DbConnector * db_connector = model_connector->get_db_connector(); @@ -1167,12 +827,18 @@ protected: { if( !model_env->cursor_helper->query_result->is_null(field_index) ) { - model_env->all_fields_are_null = false; const char * val_str = model_env->cursor_helper->query_result->get_field_string_value(field_index); if( val_str ) { - db_connector->get_value(val_str, field_value); + db_connector->get_value(val_str, field_value, field_type); + } + } + else + { + if( field_type.is_primary_key() ) + { + model_env->has_primary_key_set = false; } } } @@ -1180,7 +846,7 @@ protected: template - void get_value_by_field_name(const wchar_t * field_name, FieldValue & field_value) + void get_value_by_field_name(const wchar_t * field_name, FieldValue & field_value, const FT & field_type) { DbConnector * db_connector = model_connector->get_db_connector(); @@ -1190,16 +856,18 @@ protected: if( model_env->cursor_helper->use_table_prefix_for_fetching_values && model_env->finder_helper ) { - // CHECK what about escaping field names here? + DbExpression * db_expression = db_connector->get_expression(); - std::wstring table_field_name; - PT::TextStream table_field_name_str; + if( db_expression ) + { + std::wstring table_field_name; + pt::TextStream table_field_name_str; - put_table_name_with_index(table_field_name_str); - table_field_name_str << '.'; - table_field_name_str << field_name; - table_field_name_str.to_string(table_field_name); - column_index = model_env->cursor_helper->query_result->get_column_index(table_field_name.c_str()); + // CHECK ME not tested yet after changing to db_expression->table_with_index_and_field_to_stream() + db_expression->table_with_index_and_field_to_stream(table_field_name_str, model_env->table_name, model_env->table_index, field_name, field_type); + table_field_name_str.to_string(table_field_name); + column_index = model_env->cursor_helper->query_result->get_column_index(table_field_name.c_str()); + } } else { @@ -1208,33 +876,31 @@ protected: if( column_index != -1 && !model_env->cursor_helper->query_result->is_null(column_index) ) { - model_env->all_fields_are_null = false; const char * val_str = model_env->cursor_helper->query_result->get_field_string_value(column_index); if( val_str ) { - db_connector->get_value(val_str, field_value); + db_connector->get_value(val_str, field_value, field_type); + } + } + else + { + if( field_type.is_primary_key() ) + { + model_env->has_primary_key_set = false; } } } } - virtual void set_parent_key_in_childs() - { - if( model_env ) - { - model_env->model_work_mode = MORM_MODEL_WORK_MODE_SET_PARENT_ID; - map_fields(); - } - } - + virtual void set_parent_key_in_childs(); public: template - void get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value) + bool get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value) { if( model_connector ) { @@ -1242,15 +908,27 @@ public: if( db_connector && !is_empty_field(sequence_table_name) ) { - db_connector->get_last_sequence(sequence_table_name, field_value); + return db_connector->get_last_sequence(sequence_table_name, field_value); } } + + return false; + } + + + template + bool get_last_sequence_for_primary_key(const wchar_t * sequence_table_name, FieldValue & field_value) + { + has_primary_key_set = get_last_sequence(sequence_table_name, field_value); + return has_primary_key_set; } template void add_field_for_select(const wchar_t * new_column_expression, const wchar_t * new_column_name, const wchar_t * flat_field_name, FieldValue & field_value) { + FT field_type = FT::no_insertable | FT::no_updatable | FT::raw_field_name; + if( model_connector && model_env ) { if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_GENERATING_DB_SQL ) @@ -1263,24 +941,24 @@ public: if( db_expression && !is_empty_field(new_column_expression) ) { - db_expression->add_field_for_select(new_column_expression, new_column_name, field_value); + db_expression->add_field_for_select(new_column_expression, new_column_name, field_value, field_type, model_env); } } } else if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_GENERATING_FLAT_STRING ) { - field_generic(L"", flat_field_name, field_value, false, false, false); + field_generic(L"", flat_field_name, field_value, field_type); } else if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_READING_VALUE_FROM_DB_RESULTSET ) { - field_generic(new_column_name, L"", field_value, false, false, false); + field_generic(new_column_name, L"", field_value, field_type); } else if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_CLEARING_VALUE ) { - field_generic(L"", L"", field_value, false, false, false); // the names don't matter here + field_generic(L"", L"", field_value, field_type); // the names don't matter here } } } @@ -1293,23 +971,48 @@ public: } - protected: virtual bool is_empty_field(const wchar_t * value); virtual bool is_the_same_field(const wchar_t * field1, const wchar_t * field2); - virtual void prepare_table_names(bool prepare_table_index = true); - virtual void put_table_name_with_index(PT::TextStream & str); + + virtual void put_to_log(const wchar_t * str); + virtual void put_fields_to_log(pt::Log & log, const wchar_t * db_field_name, const wchar_t * flat_field_name); + + virtual void log_table_name(bool put_schema_name = true); + virtual void log_table_name_with_field(const wchar_t * db_field_name = nullptr, bool put_schema_name = true); + + template + bool do_migration(int & current_table_version, int destination_table_version, ModelObject * model_object, bool (ModelObject::*migration_function)()) + { + bool status = true; + + if( current_table_version < destination_table_version ) + { + if( (model_object->*migration_function)() ) + { + current_table_version = destination_table_version; + } + else + { + status = false; + } + } + + return status; + } - virtual void put_fields_to_log(PT::Log & log, const wchar_t * db_field_name, const wchar_t * flat_field_name); template friend class Finder; template friend class Cursor; friend class BaseExpression; + friend class DbConnector; }; + + } // namespace #endif diff --git a/src/modelconnector.cpp b/src/modelconnector.cpp index 51a6c06..9c7a2fa 100644 --- a/src/modelconnector.cpp +++ b/src/modelconnector.cpp @@ -60,17 +60,17 @@ ModelConnector::~ModelConnector() } -void ModelConnector::set_logger(PT::Log * log) +void ModelConnector::set_logger(pt::Log * log) { this->log = log; } -void ModelConnector::set_logger(PT::Log & log) +void ModelConnector::set_logger(pt::Log & log) { this->log = &log; } -PT::Log * ModelConnector::get_logger() +pt::Log * ModelConnector::get_logger() { return log; } @@ -91,7 +91,7 @@ void ModelConnector::deallocate_stream() void ModelConnector::allocate_default_stream() { deallocate_stream(); - out_stream = new PT::TextStream(); + out_stream = new pt::TextStream(); out_stream_allocated = true; } @@ -133,14 +133,14 @@ void ModelConnector::allocate_default_clearer_if_needed() } -void ModelConnector::set_stream(PT::TextStream & stream) +void ModelConnector::set_stream(pt::TextStream & stream) { deallocate_stream(); this->out_stream = &stream; } -PT::TextStream * ModelConnector::get_stream() +pt::TextStream * ModelConnector::get_stream() { allocate_default_stream_if_needed(); return out_stream; diff --git a/src/modelconnector.h b/src/modelconnector.h index f28dfc3..9e20547 100644 --- a/src/modelconnector.h +++ b/src/modelconnector.h @@ -59,13 +59,13 @@ public: ModelConnector(const ModelConnector &) = delete; virtual ~ModelConnector(); - virtual void set_logger(PT::Log * log); - virtual void set_logger(PT::Log & log); + virtual void set_logger(pt::Log * log); + virtual void set_logger(pt::Log & log); - virtual PT::Log * get_logger(); + virtual pt::Log * get_logger(); - virtual void set_stream(PT::TextStream & stream); - virtual PT::TextStream * get_stream(); + virtual void set_stream(pt::TextStream & stream); + virtual pt::TextStream * get_stream(); virtual void set_flat_connector(FlatConnector & flat_connector); virtual FlatConnector * get_flat_connector(); @@ -80,12 +80,12 @@ public: protected: - PT::Log * log; + pt::Log * log; FlatConnector * flat_connector; DbConnector * db_connector; - PT::TextStream * out_stream; // IMPROVE ME give here an interface to the base stream (implement him) + pt::TextStream * out_stream; // IMPROVE ME give here an interface to the base stream (implement him) bool out_stream_allocated; Clearer * clearer; diff --git a/src/modelenv.h b/src/modelenv.h index be29b45..7b72405 100644 --- a/src/modelenv.h +++ b/src/modelenv.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2019, Tomasz Sowa + * Copyright (c) 2019-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -46,6 +46,8 @@ namespace morm { + + class ModelEnv { public: @@ -59,11 +61,22 @@ public: int model_work_submode; bool dump_mode; - PT::TextStream table_name; // CHECK ME may it should be PT::WTextStream? - PT::TextStream table_name_short; + pt::WTextStream schema_name; + pt::WTextStream table_name; int table_index; + + /* + * optional additional table name + * used in eq(), neq(), ... methods in Finder + */ + const wchar_t * table2_name; + int table2_index; + + int field_index; - bool all_fields_are_null; + bool was_primary_key_read; + bool has_primary_key_set; + std::vector * set_field_name_helper; std::vector * field_value_helper_tab; @@ -74,7 +87,6 @@ public: clear(); } - ~ModelEnv() { } @@ -82,19 +94,18 @@ public: ModelEnv(const ModelEnv & e) { - model_data = e.model_data; - finder_helper = e.finder_helper; - cursor_helper = e.cursor_helper; - model_work_mode = e.model_work_mode; - model_work_submode = e.model_work_submode; - dump_mode = e.dump_mode; + copy_global_objects(e); + table_index = e.table_index; + table2_index = e.table2_index; set_field_name_helper = e.set_field_name_helper; field_value_helper_tab = e.field_value_helper_tab; field_index = e.field_index; - all_fields_are_null = e.all_fields_are_null; + was_primary_key_read = e.was_primary_key_read; + has_primary_key_set = e.has_primary_key_set; - // table_name and table_name_short don't have to bo copied + // schema_name and table_name don't have to be copied + table2_name = nullptr; } @@ -118,16 +129,31 @@ public: model_work_mode = MORM_MODEL_WORK_MODE_NONE; model_work_submode = MORM_MODEL_WORK_SUBMODE_NONE; dump_mode = false; + schema_name.clear(); table_name.clear(); - table_name_short.clear(); + table2_name = nullptr; table_index = 0; + table2_index = 0; set_field_name_helper = nullptr; field_value_helper_tab = nullptr; field_index = 0; - all_fields_are_null = false; + was_primary_key_read = false; + has_primary_key_set = false; } + void add_table_name_to_finder_helper() + { + if( finder_helper ) + { + table_index = finder_helper->add_join_table(table_name); + } + else + { + table_index = 0; + } + } + }; } diff --git a/src/postgresqlconnector.cpp b/src/postgresqlconnector.cpp index bad375d..a9fec7d 100644 --- a/src/postgresqlconnector.cpp +++ b/src/postgresqlconnector.cpp @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2018-2019, Tomasz Sowa + * Copyright (c) 2018-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -92,7 +92,7 @@ bool PostgreSQLConnector::do_query(const char * query_str, PostgreSQLQueryResult if( log_queries && log ) { - (*log) << PT::Log::log3 << "Morm: query: " << query_str << PT::Log::logend; + (*log) << pt::Log::log3 << "Morm: query: " << query_str << pt::Log::logend; } psql_result->psql_result = PQexec(pg_conn, query_str); @@ -119,15 +119,15 @@ bool PostgreSQLConnector::do_query(const char * query_str, PostgreSQLQueryResult if( err_msg ) { - PT::UTF8ToWide(err_msg, psql_result->error_msg); + pt::utf8_to_wide(err_msg, psql_result->error_msg); } if( log ) { - (*log) << PT::Log::log1 << "Morm: Problem with this query: \"" << query_str << '\"' << PT::Log::logend; + (*log) << pt::Log::log1 << "Morm: Problem with this query: \"" << query_str << '\"' << pt::Log::logend; if( err_msg ) - (*log) << PT::Log::log1 << "Morm: " << err_msg << PT::Log::logend; + (*log) << pt::Log::log1 << "Morm: " << err_msg << pt::Log::logend; } } else @@ -171,8 +171,8 @@ const char * PostgreSQLConnector::query_last_sequence(const wchar_t * sequence_t { if( log ) { - (*log) << PT::Log::log1 << "Morm: expected only one row in sequence result, has: " << psql_result.result_rows - << PT::Log::logend; + (*log) << pt::Log::log1 << "Morm: expected only one row in sequence result, has: " << psql_result.result_rows + << pt::Log::logend; } } } @@ -180,8 +180,8 @@ const char * PostgreSQLConnector::query_last_sequence(const wchar_t * sequence_t { if( pg_conn && log ) { - (*log) << PT::Log::log1 << "Morm: error (currval) for table: " << sequence_table_name << ", " - << PQerrorMessage(pg_conn) << PT::Log::logend; + (*log) << pt::Log::log1 << "Morm: error (currval) for table: " << sequence_table_name << ", " + << PQerrorMessage(pg_conn) << pt::Log::logend; } } } @@ -191,7 +191,7 @@ const char * PostgreSQLConnector::query_last_sequence(const wchar_t * sequence_t -bool PostgreSQLConnector::query(const PT::TextStream & stream, QueryResult & query_result) +bool PostgreSQLConnector::query(const pt::TextStream & stream, QueryResult & query_result) { stream.to_string(query_str); return query(query_str.c_str(), query_result); @@ -264,25 +264,25 @@ bool PostgreSQLConnector::query_remove(const char * query_str, QueryResult & que } -bool PostgreSQLConnector::query_select(const PT::TextStream & stream, QueryResult & query_result) +bool PostgreSQLConnector::query_select(const pt::TextStream & stream, QueryResult & query_result) { stream.to_string(query_str); return query_select(query_str.c_str(), query_result); } -bool PostgreSQLConnector::query_update(const PT::TextStream & stream, QueryResult & query_result) +bool PostgreSQLConnector::query_update(const pt::TextStream & stream, QueryResult & query_result) { stream.to_string(query_str); return query_update(query_str.c_str(), query_result); } -bool PostgreSQLConnector::query_insert(const PT::TextStream & stream, QueryResult & query_result) +bool PostgreSQLConnector::query_insert(const pt::TextStream & stream, QueryResult & query_result) { stream.to_string(query_str); return query_insert(query_str.c_str(), query_result); } -bool PostgreSQLConnector::query_remove(const PT::TextStream & stream, QueryResult & query_result) +bool PostgreSQLConnector::query_remove(const pt::TextStream & stream, QueryResult & query_result) { stream.to_string(query_str); return query_remove(query_str.c_str(), query_result); @@ -392,128 +392,6 @@ bool PostgreSQLConnector::query_remove(const PT::TextStream & stream, QueryResul - - - -/* - converting from a bytea - the old way (escape format) -*/ -/* -int PostgreSQLConnector::CharToInt(char c) -{ - return (int)(unsigned char)(c-'0'); -} - -bool PostgreSQLConnector::IsCorrectOctalDigit(char c) -{ - return c>='0' && c<='7'; -} - -// moves 'i' at least once -// return -1 if there is en error -int PostgreSQLConnector::UnescapeBin(const char * str, size_t & i, size_t len) -{ - if( str[i] != '\\' ) - return str[i++]; - - i += 1; - - if( i >= len ) - return -1; - - if( str[i] == '\\' ) - return str[i++]; - - if( i+2 >= len ) - { - i = len; - return -1; - } - - if( !IsCorrectOctalDigit(str[i]) || - !IsCorrectOctalDigit(str[i+1]) || - !IsCorrectOctalDigit(str[i+2]) ) - { - i += 3; - return -1; - } - - int c = 8*8*CharToInt(str[i]) + 8*CharToInt(str[i+1]) + CharToInt(str[i+2]); - - i += 3; - - if( c<0 || c>255 ) - return -1; - -return c; -} - -void PostgreSQLConnector::UnescapeBin(const char * str, size_t len, std::string & out, bool clear_out) -{ -int c; -size_t i = 0; - - if( clear_out ) - out.clear(); - - while( i < len ) - { - c = UnescapeBin(str, i, len); - - if( c != -1 ) - out += c; - } -} -*/ - - - - - -/* - converting from a bytea - the new way (hex format) -*/ - - -//char PostgreSQLConnector::UnescapeBinHexToDigit(char hex) -//{ -// if( hex>='0' && hex<='9' ) -// return hex - '0'; -// -// if( hex>='a' && hex<='z' ) -// return hex - 'a' + 10; -// -// if( hex>='A' && hex<='Z' ) -// return hex - 'A' + 10; -// -//return 0; -//} -// -// -//void PostgreSQLConnector::UnescapeBin(const char * str, size_t len, std::string & out, bool clear_out) -//{ -// if( clear_out ) -// out.clear(); -// -// if( len < 2 || str[0]!='\\' || str[1]!='x' ) -// { -// log << log1 << "Morm: unsupported binary format (skipping)" << logend; -// return; -// } -// -// for(size_t i=2 ; i + 1 < len ; i+=2 ) -// { -// int c1 = UnescapeBinHexToDigit(str[i]); -// int c2 = UnescapeBinHexToDigit(str[i+1]); -// -// out += ((c1 << 4) | c2); -// } -//} - - - void PostgreSQLConnector::set_conn_param(const std::wstring & database_name, const std::wstring & user, const std::wstring & pass) { db_database = database_name; @@ -522,9 +400,9 @@ void PostgreSQLConnector::set_conn_param(const std::wstring & database_name, con } -void PostgreSQLConnector::overwrite(PT::TextStream & stream) +void PostgreSQLConnector::overwrite(pt::TextStream & stream) { - PT::TextStream::iterator i = stream.begin(); + pt::TextStream::iterator i = stream.begin(); for( ; i != stream.end() ; ++i) { @@ -577,9 +455,9 @@ void PostgreSQLConnector::log_connection_socket() { if( pg_conn && log ) { - (*log) << PT::Log::log2 << "Morm: connection to the database works fine" << PT::Log::logend; - (*log) << PT::Log::log3 << "Morm: connection socket: " << PQsocket(pg_conn) << PT::Log::logend; - (*log) << PT::Log::logsave; + (*log) << pt::Log::log2 << "Morm: connection to the database works fine" << pt::Log::logend; + (*log) << pt::Log::log3 << "Morm: connection socket: " << PQsocket(pg_conn) << pt::Log::logend; + (*log) << pt::Log::logsave; } } @@ -589,7 +467,7 @@ void PostgreSQLConnector::wait_for_connection() { if( log ) { - (*log) << PT::Log::log3 << "Morm: waiting for the db to be ready...." << PT::Log::logend << PT::Log::logsave; + (*log) << pt::Log::log3 << "Morm: waiting for the db to be ready...." << pt::Log::logend << pt::Log::logsave; } while( !assert_connection(false) ) @@ -620,7 +498,7 @@ bool was_connection = true; { if( put_log && log ) { - (*log) << PT::Log::log2 << "Morm: connection to the database is lost, trying to recover" << PT::Log::logend << PT::Log::logsave; + (*log) << pt::Log::log2 << "Morm: connection to the database is lost, trying to recover" << pt::Log::logend << pt::Log::logsave; } was_connection = false; @@ -644,7 +522,7 @@ bool was_connection = true; { if( put_log && log ) { - (*log) << PT::Log::log1 << "Morm: connection to db server cannot be established" << PT::Log::logend << PT::Log::logsave; + (*log) << pt::Log::log1 << "Morm: connection to db server cannot be established" << pt::Log::logend << pt::Log::logsave; } // if( throw_if_no_connection ) @@ -665,15 +543,62 @@ void PostgreSQLConnector::set_db_parameters() { if( log ) { - (*log) << PT::Log::log1 << "Morm: Can't set the proper client encoding" << PT::Log::logend << PT::Log::logsave; + (*log) << pt::Log::log1 << "Morm: Can't set the proper client encoding" << pt::Log::logend << pt::Log::logsave; } } } } +void PostgreSQLConnector::log_unsupported_bin_format() +{ + if( log ) + { + (*log) << pt::Log::log1 << "Morm: unsupported binary format (skipping)" << pt::Log::logend; + } +} +size_t PostgreSQLConnector::unescape_bin_char(const char * str, wchar_t & field_value, const FT & field_type) +{ + if( str[0]!='\\' || str[1]!='x' ) + { + log_unsupported_bin_format(); + return 0; + } + else + { + return unescape_hex_char(str + 2, field_value, field_type); + } +} + + + +void PostgreSQLConnector::unescape_bin_string(const char * str, std::string & out) +{ + if( str[0]!='\\' || str[1]!='x' ) + { + log_unsupported_bin_format(); + } + else + { + unescape_hex_string(str + 2, out); + } +} + + +void PostgreSQLConnector::unescape_bin_string(const char * str, std::wstring & out, const FT & field_type) +{ + if( str[0]!='\\' || str[1]!='x' ) + { + log_unsupported_bin_format(); + } + else + { + unescape_hex_string(str + 2, out, field_type); + } +} + } diff --git a/src/postgresqlconnector.h b/src/postgresqlconnector.h index 27e4f1a..9f21165 100644 --- a/src/postgresqlconnector.h +++ b/src/postgresqlconnector.h @@ -5,7 +5,7 @@ */ /* - * Copyright (c) 2018-2019, Tomasz Sowa + * Copyright (c) 2018-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -55,7 +55,7 @@ public: virtual ~PostgreSQLConnector(); - bool query(const PT::TextStream & stream, QueryResult & query_result); + bool query(const pt::TextStream & stream, QueryResult & query_result); bool query(const char * query_str, QueryResult & query_result); bool query(const std::string & query_str, QueryResult & query_result); @@ -64,10 +64,10 @@ public: bool query_insert(const char * query_str, QueryResult & query_result); bool query_remove(const char * query_str, QueryResult & query_result); - bool query_select(const PT::TextStream & stream, QueryResult & query_result); - bool query_update(const PT::TextStream & stream, QueryResult & query_result); - bool query_insert(const PT::TextStream & stream, QueryResult & query_result); - bool query_remove(const PT::TextStream & stream, QueryResult & query_result); + bool query_select(const pt::TextStream & stream, QueryResult & query_result); + bool query_update(const pt::TextStream & stream, QueryResult & query_result); + bool query_insert(const pt::TextStream & stream, QueryResult & query_result); + bool query_remove(const pt::TextStream & stream, QueryResult & query_result); virtual void set_conn_param(const std::wstring & database, const std::wstring & user, const std::wstring & pass); @@ -85,7 +85,7 @@ public: protected: PGconn * pg_conn; - PT::TextStream stream; + pt::TextStream stream; std::string query_str; std::wstring db_database; @@ -94,10 +94,15 @@ protected: virtual bool do_query(const char * query_str, PostgreSQLQueryResult * psql_result); virtual void allocate_default_expression(); - virtual void overwrite(PT::TextStream & stream); + virtual void overwrite(pt::TextStream & stream); virtual const char * query_last_sequence(const wchar_t * sequence_table_name); virtual QueryResult * create_query_result(); + void log_unsupported_bin_format(); + + size_t unescape_bin_char(const char * str, wchar_t & field_value, const FT & field_type); + void unescape_bin_string(const char * str, std::string & out); + void unescape_bin_string(const char * str, std::wstring & out, const FT & field_type); }; diff --git a/src/postgresqlexpression.cpp b/src/postgresqlexpression.cpp index 4235383..c9b4ccd 100644 --- a/src/postgresqlexpression.cpp +++ b/src/postgresqlexpression.cpp @@ -39,120 +39,60 @@ namespace morm { -void PostgreSQLExpression::before_short_field_name() + +void PostgreSQLExpression::before_field_value_string(const FT & field_type) { - (*out_stream) << '"'; -} - -void PostgreSQLExpression::after_short_field_name() -{ - (*out_stream) << '"'; -} - - - -void PostgreSQLExpression::before_first_part_long_field_name() -{ -} - - -void PostgreSQLExpression::after_first_part_long_field_name() -{ -} - - -void PostgreSQLExpression::before_second_part_long_field_name() -{ - before_short_field_name(); -} - - -void PostgreSQLExpression::after_second_part_long_field_name() -{ - after_short_field_name(); -} - - - - -void PostgreSQLExpression::before_field_value_string() -{ -// if( output_type == MORM_OUTPUT_TYPE_DB_INSERT || -// output_type == MORM_OUTPUT_TYPE_DB_UPDATE || -// output_type == MORM_OUTPUT_TYPE_DB_PRIMARY_KEY ) + if( field_type.is_binary() ) + { + (*out_stream) << "'\\x"; + } + else + if( field_type.is_hexadecimal() ) + { + (*out_stream) << "'"; + } + else { (*out_stream) << "E'"; } } -void PostgreSQLExpression::after_field_value_string() +void PostgreSQLExpression::after_field_value_string(const FT & field_type) { -// if( output_type == MORM_OUTPUT_TYPE_DB_INSERT || -// output_type == MORM_OUTPUT_TYPE_DB_UPDATE || -// output_type == MORM_OUTPUT_TYPE_DB_PRIMARY_KEY ) + (*out_stream) << "'"; +} + + + +void PostgreSQLExpression::esc(char val, pt::TextStream & stream, const FT & field_type) +{ + if( field_type.is_hexadecimal() || field_type.is_binary() ) { - (*out_stream) << "'"; + char_to_hex(val, stream); } -} - - -void PostgreSQLExpression::before_field_value(const std::wstring &) -{ - before_field_value_string(); -} - -void PostgreSQLExpression::after_field_value(const std::wstring &) -{ - after_field_value_string(); -} - -void PostgreSQLExpression::before_field_value(const std::string &) -{ - before_field_value_string(); -} - -void PostgreSQLExpression::after_field_value(const std::string &) -{ - after_field_value_string(); -} - -void PostgreSQLExpression::before_field_value(const wchar_t *) -{ - before_field_value_string(); -} - -void PostgreSQLExpression::after_field_value(const wchar_t *) -{ - after_field_value_string(); -} - -void PostgreSQLExpression::before_field_value(const char *) -{ - before_field_value_string(); -} - -void PostgreSQLExpression::after_field_value(const char *) -{ - after_field_value_string(); -} - - -void PostgreSQLExpression::esc(char val, PT::TextStream & stream) -{ - switch( val ) + else { - case '\\': stream << "\\\\"; break; - case '\'': stream << "\\\'"; break; // don't use "''" because we use the method for PQconnectdb too - default: - if( val != 0 ) + switch( val ) { - stream << val; + case '\\': stream << "\\\\"; break; + case '\'': stream << "\\\'"; break; // don't use "''" because we use the method for PQconnectdb too + default: + if( val != 0 ) + { + stream << val; + } } } } -DbExpression & PostgreSQLExpression::page(PT::TextStream & stream, size_t page_number, size_t page_size) +void PostgreSQLExpression::esc(const pt::Date & date, pt::TextStream & stream, const FT & field_type) +{ + stream << date << "+00"; +} + + +DbExpression & PostgreSQLExpression::page(pt::TextStream & stream, size_t page_number, size_t page_size) { stream << " offset " << page_number << " limit " << page_size << " "; return *this; diff --git a/src/postgresqlexpression.h b/src/postgresqlexpression.h index b26605b..d3c8346 100644 --- a/src/postgresqlexpression.h +++ b/src/postgresqlexpression.h @@ -45,38 +45,21 @@ class PostgreSQLExpression : public DbExpression { public: - void esc(char val, PT::TextStream & stream); - DbExpression & page(PT::TextStream & stream, size_t page_number, size_t page_size); + void esc(char val, pt::TextStream & stream, const FT & field_type); + void esc(const pt::Date & date, pt::TextStream & stream, const FT & field_type); + + DbExpression & page(pt::TextStream & stream, size_t page_number, size_t page_size); protected: - virtual void before_short_field_name(); - virtual void after_short_field_name(); - virtual void before_first_part_long_field_name(); - virtual void after_first_part_long_field_name(); - virtual void before_second_part_long_field_name(); - virtual void after_second_part_long_field_name(); - void before_field_value(const std::wstring &); - void after_field_value(const std::wstring &); - - void before_field_value(const std::string &); - void after_field_value(const std::string &); - - void before_field_value(const wchar_t *); - void after_field_value(const wchar_t *); - - void before_field_value(const char *); - void after_field_value(const char *); private: - void before_field_value_string(); - void after_field_value_string(); - - + void before_field_value_string(const FT & field_type); + void after_field_value_string(const FT & field_type); }; diff --git a/src/postgresqlqueryresult.cpp b/src/postgresqlqueryresult.cpp index 61c3209..22eeb5f 100644 --- a/src/postgresqlqueryresult.cpp +++ b/src/postgresqlqueryresult.cpp @@ -184,7 +184,7 @@ bool PostgreSQLQueryResult::is_null(int row, int col) } -void PostgreSQLQueryResult::dump_column_names(PT::Log & log) +void PostgreSQLQueryResult::dump_column_names(pt::Log & log) { if( psql_result ) { @@ -192,7 +192,7 @@ void PostgreSQLQueryResult::dump_column_names(PT::Log & log) for(int i = 0 ; i < cols ; ++i) { - log << i << ' ' << PQfname(psql_result, i) << PT::Log::logend; + log << i << ' ' << PQfname(psql_result, i) << pt::Log::logend; } } } @@ -255,20 +255,20 @@ void PostgreSQLQueryResult::dump_column_names(PT::Log & log) //} -//bool PostgreSQLConnector::AssertValueSpace(PGresult * r, int row, int col, PT::Space & space) +//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); +// pt::SpaceParser::Status status = conf_parser.ParseString(res); // -// if( status != PT::SpaceParser::ok ) +// if( status != pt::SpaceParser::ok ) // { -// log << log1 << "Morm: a problem with parsing a PT::Space"; +// log << log1 << "Morm: a problem with parsing a pt::Space"; // -// if( status == PT::SpaceParser::syntax_error ) +// if( status == pt::SpaceParser::syntax_error ) // log << ", syntax error at line: " << conf_parser.line; // // log << logend; diff --git a/src/postgresqlqueryresult.h b/src/postgresqlqueryresult.h index ca80482..fcc5758 100644 --- a/src/postgresqlqueryresult.h +++ b/src/postgresqlqueryresult.h @@ -68,7 +68,7 @@ struct PostgreSQLQueryResult : public QueryResult bool is_null(int row, int col); - void dump_column_names(PT::Log & log); + void dump_column_names(pt::Log & log); }; diff --git a/src/queryresult.cpp b/src/queryresult.cpp index cdac798..ff276ef 100644 --- a/src/queryresult.cpp +++ b/src/queryresult.cpp @@ -85,7 +85,7 @@ const char * QueryResult::get_field_string_value(const char * column_name) const char * QueryResult::get_field_string_value(const wchar_t * column_name) { - PT::WideToUTF8(column_name, temp_column_name); + pt::wide_to_utf8(column_name, temp_column_name); return get_field_string_value(temp_column_name.c_str()); } @@ -98,7 +98,7 @@ int QueryResult::get_column_index(const char * column_name) int QueryResult::get_column_index(const wchar_t * column_name) { - PT::WideToUTF8(column_name, temp_column_name); + pt::wide_to_utf8(column_name, temp_column_name); return get_column_index(temp_column_name.c_str()); } @@ -125,7 +125,7 @@ bool QueryResult::is_null(int row, int col) } -void QueryResult::dump_column_names(PT::Log & log) +void QueryResult::dump_column_names(pt::Log & log) { } diff --git a/src/queryresult.h b/src/queryresult.h index f18e032..fdabfb5 100644 --- a/src/queryresult.h +++ b/src/queryresult.h @@ -76,7 +76,7 @@ struct QueryResult virtual int get_value_length(int row, int col); virtual bool is_null(int row, int col); - virtual void dump_column_names(PT::Log & log); + virtual void dump_column_names(pt::Log & log); };