Compare commits

...

54 Commits

Author SHA1 Message Date
Tomasz Sowa e026af9994
add QT Creator files to .gitignore 2023-10-22 23:37:44 +02:00
Tomasz Sowa 92d9d2c01b
add Finder::esc_like(...) methods 2023-10-10 19:43:02 +02:00
Tomasz Sowa 8200092524
add Finder::raw(pt::Date&,...) and esc(pt::Date &,...) methods 2023-07-17 03:42:14 +02:00
Tomasz Sowa 21f12a8a98
add support for declared cursors
Declare a cursor with the Finder::declare_cursor() method and next get the cursor with get_cursor():
morm::Cursor<MyObject> cursor = finder.
  declare_cursor("mycursorname").
  select().
  raw("ORDER BY column_name ASC").
  get_cursor();

The cursor now can be used with fetch.*() methods and then get() or get_list():
MyObject myobject = cursor.fetch_next().get();
std::list<MyObject> myobjects = cursor.fetch_forward_count(10).get_list();
2023-07-16 04:03:03 +02:00
Tomasz Sowa 6619f3ecb5
fix: correctly use a table name when using Finder::use_table_prefix(true)
We cannot use aliases in the form of "tablename"."fieldname" - now it was
changed to "tablename.fieldname".

Sample how to get the id field, assuming the table name is 'mymodel'.
mymodel = finder2.
          select(morm::Select::no_auto_generated_columns).
          use_table_prefix(true).
          raw("SELECT id AS \"mymodel.id\"").
          raw("FROM mymodel").
          raw("WHERE id = 25").
          get();

In addition, there was an error that the table name was not correctly set
for the first object in the hierarchy - it was empty, e.g. ""."field_name"
2023-07-15 03:08:02 +02:00
Tomasz Sowa e7c62e35dc
add Finder::is_null() and is_not_null() methods 2023-07-08 23:26:54 +02:00
Tomasz Sowa 25a91168ac
fix: correctly use a table name when a Select::no_auto_generated_columns flag is used 2023-05-08 10:26:31 +02:00
Tomasz Sowa 86177889af
add a CSVConnector/CSVExpression classes to serialize to csv format
Current limitation: list/vectors are not serialized.

while here:
- move the output_type flag from the DbExpression to BaseExpression class
- add Model::to_text(...) methods with an Export parameter
2023-04-12 17:20:29 +02:00
Tomasz Sowa d61fc31b5c
allow to set a custom name for the auto generated rows counter column 2023-02-28 09:51:05 +01:00
Tomasz Sowa c56bae57ca
fix: propagate the model_data in the cursor
model_data can be used in Model::fields() method
2023-02-28 09:48:44 +01:00
Tomasz Sowa 1821c562f7
add a Select::distinct flag 2023-02-28 03:37:20 +01:00
Tomasz Sowa dee48ea2b5
use an <item> field when serializing a table to xml 2023-02-27 00:29:51 +01:00
Tomasz Sowa cf377204a9
improve the xml serializer
while here:
- do some refactoring in BaseExpression
2023-02-26 22:19:46 +01:00
Tomasz Sowa 0fbd988eda
serialize a model to flat string even when a DO_NOTHING_ON_SAVE flag is set
while here:
- add FT::serialize_to_null_if_null and FT::do_not_serialize_if_null flags
2023-02-26 18:28:16 +01:00
Tomasz Sowa d1c86c84cf fix: allow to use a minus sign in strings with FT::numeric flag 2023-01-11 23:06:27 +01:00
Tomasz Sowa 794051fa15 add basic support for serializing objects to xml 2022-12-16 02:48:07 +01:00
Tomasz Sowa a3c337355d fix: correctly read a date from a database if a date_only flag is set 2022-12-15 17:33:46 +01:00
Tomasz Sowa a4a1acebeb add Finder::like(...) and ilike(...) methods 2022-12-05 06:36:13 +01:00
Tomasz Sowa dfc631dd06 add more Finder::esc(...) and raw(...) methods 2022-12-02 13:26:30 +01:00
Tomasz Sowa 2ac8769d3a add Finder::esc(...) methods 2022-12-02 11:45:19 +01:00
Tomasz Sowa 7f4deaf847 update to the new pikotools api: change converting functions to the snake case 2022-11-14 03:38:27 +01:00
Tomasz Sowa 0ce05850b3 add FT::date_only, FT::time_only and FT::no_time_zone flags 2022-10-22 16:29:40 +02:00
Tomasz Sowa 38e790c2ac fix: correctly delete child objects - use the original value from save_mode 2022-08-17 07:43:58 +02:00
Tomasz Sowa bc92654be9 let Finder::page() takes a page number and not an offset 2022-08-04 14:54:04 +02:00
Tomasz Sowa c54a5bed05 add Model::get_logger() 2022-08-01 03:58:07 +02:00
Tomasz Sowa 8373f9e9d8 make depend 2022-07-30 03:32:33 +02:00
Tomasz Sowa 43dfbd5d5a add possibility of calculating how many rows there were before LIMIT was applied
The Finder has get_rows_counter() method which returns how many rows there were
before LIMIT clause was applied. The select(...) method should be called with
Select::with_rows_counter flag in such a case.

while here:
- change the semantic of Finder, now the select(...) method takes a morm::Select flags,
  and we have such flags:
  - Select::no_auto_generated_columns - do not generate columns from models
  - with_rows_counter - add an additional column for the rows counter
- remove Finder::prepare_to_select() - now use select(...) with no_auto_generated_columns flag
2022-07-11 17:48:13 +02:00
Tomasz Sowa 4e8f3af8fc (finder): take pt::TextStream by const ref in raw(...) method 2022-07-08 22:02:02 +02:00
Tomasz Sowa 128f43482a make depend 2022-07-05 19:48:17 +02:00
Tomasz Sowa 3ddeb78c97 add LICENSE file 2022-07-03 11:01:14 +02:00
Tomasz Sowa ea6f9fd13e remove empty src/outstream.h file 2022-06-30 13:30:06 +02:00
Tomasz Sowa 1ad3d89d52 change headerfile_morm_* macros to headerfile_morm_src_* 2022-06-30 13:28:38 +02:00
Tomasz Sowa 576d537177 add src/version.h with macros: MORM_VERSION_MAJOR, MORM_VERSION_MINOR, MORM_VERSION_PATCH
Let the version be 0.7.0.
2022-06-30 13:19:55 +02:00
Tomasz Sowa c89d4f76bc add global Makefile
src/Makefile uses now 'find' for looking for *.cpp files
and we don't need Makefile.o.dep anymore
2022-06-26 06:15:19 +02:00
Tomasz Sowa fc50c8ca5e fixed: in Finder::select(PT::TextStream & out_stream, ModelConnector & model_connector)
and Finder::select(PT::TextStream & out_stream, ModelConnector * model_connector)
       there was 'out_stream' parameter ignored

merged from 0890f27fe5
2022-06-25 18:30:53 +02:00
Tomasz Sowa 1ace47266d fix: correctly escape output stream buffer for models getters 2022-05-31 01:45:27 +02:00
Tomasz Sowa 21117e24c0 do Transaction::commit/rollback only on the same group for which a begin was called 2022-05-27 00:06:56 +02:00
Tomasz Sowa dd04ee84b7 capitalize INSERT/UPDATE/DELETE sql statements 2022-05-26 20:19:05 +02:00
Tomasz Sowa 1d4de8abe2 add support for nested transactions
while here:
- don't allow to copy/move DbConnector
2022-05-26 20:14:14 +02:00
Tomasz Sowa 907f10671d do not allow to copy/move transactions objects 2022-05-26 00:45:49 +02:00
Tomasz Sowa c5cf4a2672 add Transaction class as a wrapper for transactions 2022-05-26 00:34:17 +02:00
Tomasz Sowa b32917afe7 use pikotools Log::put_multiline() method when printing PostgreSQL error messages 2022-05-25 19:58:13 +02:00
Tomasz Sowa 0ce7578de3 fix: the way how we test if there is a connection issue
If there is a connection issue then PQexec returns a resultset now
- older versions of PostgreSQL returned null pointer.
2022-05-25 19:11:42 +02:00
Tomasz Sowa 12232bf722 propagate status from childs in Model::insert, Model::update, Model::remove and Model::save 2022-05-24 23:27:07 +02:00
Tomasz Sowa 1ad4cb4fbd trim white lines after PostgreSQL error message 2022-05-24 20:06:06 +02:00
Tomasz Sowa 56cbebad4f add FT::numeric to be applied on string types 2022-05-16 13:42:51 +02:00
Tomasz Sowa 3bde64e033 add possibility to set save status for the whole tree
add method:
void Model::set_save_mode2(SaveMode save_mode, bool update_whole_tree = true)
in the future it may be renamed to set_save_mode()
2022-05-12 00:21:42 +02:00
Tomasz Sowa df44296c04 fix: only insert primary keys from the first descendant childs 2022-05-11 23:18:25 +02:00
Tomasz Sowa 469294502e allow specify how many times we can try to connect to the database 2022-04-29 05:56:02 +02:00
Tomasz Sowa d384929e75 allow to use host connection parameter 2022-04-28 06:03:40 +02:00
Tomasz Sowa ac77abb8fd allow to use hostaddr, port or conn_string to connect to PostgreSQL 2022-04-20 18:36:06 +02:00
Tomasz Sowa 0bdabfc7b4 fix: put 'char' type directly to the output stream
Char type was converted to wchar_t and then was serialized as utf-8 stream.
Let char type will always be one char, of course it need to be a valid utf-8 sequence.

Let FT::dont_use_utf8 apply only to wchar_t and std::wstring
but ignore it if FT::hexadecimal or FT::binary are defined.

Now we have bool BaseExpression::esc_char(wchar_t val, pt::TextStream & stream) method
which (in most cases) will be used in derived classes.

Let wchar_t (and std::wstring) will be stored as 8 hex digits when using FT::hexadecimal
or FT::binary (and ignore FT::dont_use_utf8 in such a case).
2022-02-08 12:47:34 +01:00
Tomasz Sowa 48d515ea64 if pt::Space has FT::json type then let JSONExpression serialize it as json and not string 2022-02-03 11:18:01 +01:00
Tomasz Sowa c25a5d2215 - code from JSONExpression::esc(char val, ...) moved to Pikotools (convert/misc.h)
- added ModelContainerWrapper::set_iterator_at_first_model() method
2021-10-12 19:59:19 +02:00
61 changed files with 5580 additions and 1261 deletions

9
.gitignore vendored
View File

@ -6,3 +6,12 @@
log.txt
samples/log.txt
samples/mormsample
.clangd
.qtc_clangd/
morm.cflags
morm.config
morm.creator
morm.creator.user
morm.cxxflags
morm.files
morm.includes

24
LICENSE Normal file
View File

@ -0,0 +1,24 @@
Copyright (c) 2018-2022, 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.

42
Makefile Normal file
View File

@ -0,0 +1,42 @@
export CXX
export CXXFLAGS
export AR
all: src
src: FORCE
$(MAKE) -C src
samples: FORCE
$(MAKE) -C src
$(MAKE) -C samples
samples-gcc11: FORCE
env CXX=g++11 CXXFLAGS="-Wl,-rpath=/usr/local/lib/gcc11/ -Wall -pedantic -O0 -g -std=c++20 -fmax-errors=1 -I../src -I../../pikotools/src -I/usr/local/include" $(MAKE) -C src
env CXX=g++11 CXXFLAGS="-Wl,-rpath=/usr/local/lib/gcc11/ -Wall -pedantic -O0 -g -std=c++20 -fmax-errors=1 -I../src -I../../pikotools/src -I/usr/local/include" $(MAKE) -C samples
clean: FORCE
$(MAKE) -C src clean
$(MAKE) -C samples clean
cleanall: clean
$(MAKE) -C ../pikotools clean
depend: FORCE
$(MAKE) -C src depend
$(MAKE) -C samples depend
FORCE:

View File

@ -1,68 +1,57 @@
include Makefile.o.dep
sourcefiles:=$(shell find . -name "*.cpp")
objfiles:=$(patsubst %.cpp,%.o,$(sourcefiles))
name=mormsample
ifndef GLOBAL_WORKING_DIR
GLOBAL_WORKING_DIR := $(shell pwd)/../..
ifndef CXX
CXX = g++
endif
ifndef CXXFLAGS
CXXFLAGS = -Wall -pedantic -O2 -std=c++20 -I../src -I../../pikotools/src -I/usr/local/include
endif
ifndef LDFLAGS
LDFLAGS = -L/usr/local/lib
endif
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/gcc10 -Wfatal-errors -fPIC -Wall -pedantic -O0 -g3 -pthread -std=c++20 -I/usr/local/include -I$(GLOBAL_WORKING_DIR)/pikotools/src -I$(GLOBAL_WORKING_DIR)/morm/src
LDFLAGS = -L/usr/local/lib
name = mormsample
export CXX
export CXXFLAGS
export LDFLAGS
export GLOBAL_WORKING_DIR
all: $(name)
current_path := $(shell pwd)
global_relative_working_dir := $(shell relative_path $(current_path) $(GLOBAL_WORKING_DIR))
$(name): morm pikotools $(objfiles)
$(CXX) -o $(name) $(CXXFLAGS) $(LDFLAGS) $(objfiles) ../src/morm.a ../../pikotools/src/pikotools.a $(LDFLAGS) -lpq -lpthread
# IMPROVE ME
# add dependency to pikotools
all: morm $(name)
morm: FORCE
@cd ../src ; $(MAKE) -e
$(name): morm pikotools $(o)
$(CXX) -o $(name) $(CXXFLAGS) $(LDFLAGS) $(o) $(GLOBAL_WORKING_DIR)/morm/src/morm.a $(GLOBAL_WORKING_DIR)/pikotools/src/pikotools.a $(LDFLAGS) -lpq -lpthread
.PHONY: morm
morm:
@cd $(GLOBAL_WORKING_DIR)/morm/src ; $(MAKE) -e
pikotools:
@cd $(GLOBAL_WORKING_DIR)/pikotools/src ; $(MAKE) -e
pikotools: FORCE
@cd ../../pikotools/src ; $(MAKE) -e
%.o: %.cpp
$(CXX) -c $(CXXFLAGS) $<
depend:
makedepend -Y. -I$(global_relative_working_dir)/pikotools/src -I$(global_relative_working_dir)/morm/src -f- *.cpp > Makefile.dep
echo -n "o = " > Makefile.o.dep
ls -1 *.cpp | xargs -I foo echo -n foo " " | sed -E "s/([^\.]*)\.cpp[ ]/\1\.o/g" >> Makefile.o.dep
$(CXX) -c $(CXXFLAGS) -o $@ $<
clean:
@cd $(GLOBAL_WORKING_DIR)/morm/src ; $(MAKE) -e clean
rm -f *.o
rm -f $(objfiles)
rm -f $(name)
depend:
makedepend -Y. -I../src -I../../pikotools/src -f- $(sourcefiles) > Makefile.dep
include Makefile.dep
FORCE:
-include Makefile.dep

View File

@ -1,17 +1,30 @@
# DO NOT DELETE
main.o: sample01.h basesample.h ../../morm/src/morm.h
main.o: ../../morm/src/morm_types.h ../../morm/src/model.h
main.o: ../../morm/src/modelconnector.h ../../morm/src/clearer.h
main.o: ../../morm/src/dbconnector.h ../../morm/src/queryresult.h
main.o: ../../morm/src/ft.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/modelwrapper.h ../../morm/src/finder.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/postgresqlqueryresult.h person.h language.h
main.o: attachment.h type.h attachment2.h
./main.o: ../../pikotools/src/mainoptions/mainoptionsparser.h
./main.o: ../../pikotools/src/space/space.h
./main.o: ../../pikotools/src/textstream/types.h
./main.o: ../../pikotools/src/convert/inttostr.h
./main.o: ../../pikotools/src/utf8/utf8.h
./main.o: ../../pikotools/src/textstream/stream.h
./main.o: ../../pikotools/src/utf8/utf8_templates.h
./main.o: ../../pikotools/src/utf8/utf8_private.h sample01.h basesample.h
./main.o: ../src/morm.h ../src/version.h ../src/morm_types.h ../src/model.h
./main.o: ../../pikotools/src/textstream/textstream.h
./main.o: ../../pikotools/src/textstream/stream.h
./main.o: ../../pikotools/src/date/date.h
./main.o: ../../pikotools/src/membuffer/membuffer.h
./main.o: ../../pikotools/src/textstream/types.h ../src/modelconnector.h
./main.o: ../src/clearer.h ../src/ft.h ../src/dbconnector.h
./main.o: ../../pikotools/src/log/log.h ../../pikotools/src/log/filelog.h
./main.o: ../src/queryresult.h ../src/flatconnector.h ../src/export.h
./main.o: ../src/dbexpression.h ../src/baseexpression.h ../src/modelenv.h
./main.o: ../src/modeldata.h ../src/cursorhelper.h ../src/finderhelper.h
./main.o: ../src/fieldvaluehelper.h ../src/wrapper.h ../src/spacewrapper.h
./main.o: ../src/baseobjectwrapper.h ../src/modelcontainerwrapper.h
./main.o: ../src/select.h ../../pikotools/src/convert/text.h
./main.o: ../src/flatexpression.h ../src/finder.h ../src/cursor.h
./main.o: ../src/jsonexpression.h ../src/postgresqlexpression.h
./main.o: ../src/xmlexpression.h ../src/jsonconnector.h
./main.o: ../src/postgresqlconnector.h ../src/postgresqlqueryresult.h
./main.o: ../src/xmlconnector.h ../src/transaction.h person.h language.h
./main.o: attachment.h type.h attachment2.h

View File

@ -1 +0,0 @@
o = main.o

View File

@ -1,36 +1,45 @@
include Makefile.o.dep
sourcefiles:=$(shell find . -name "*.cpp")
objfiles:=$(patsubst %.cpp,%.o,$(sourcefiles))
libname=morm.a
ifndef GLOBAL_WORKING_DIR
GLOBAL_WORKING_DIR := $(shell pwd)/../..
ifndef CXX
CXX = g++
endif
current_path := $(shell pwd)
global_relative_working_dir := $(shell relative_path $(current_path) $(GLOBAL_WORKING_DIR))
ifndef CXXFLAGS
CXXFLAGS = -Wall -pedantic -O2 -std=c++20 -I../../pikotools/src -I/usr/local/include
endif
ifndef AR
AR = ar
endif
libname = morm.a
all: $(libname)
$(libname): $(o)
$(AR) rcs $(libname) $(o)
$(libname): $(objfiles)
$(AR) rcs $(libname) $(objfiles)
%.o: %.cpp
$(CXX) -c $(CXXFLAGS) -I$(GLOBAL_WORKING_DIR)/pikotools $<
depend:
makedepend -Y. -I$(global_relative_working_dir)/pikotools -f- *.cpp > Makefile.dep
echo -n "o = " > Makefile.o.dep
ls -1 *.cpp | xargs -I foo echo -n foo " " | sed -E "s/([^\.]*)\.cpp[ ]/\1\.o/g" >> Makefile.o.dep
$(CXX) -c $(CXXFLAGS) -o $@ $<
clean:
rm -f *.o
rm -f $(objfiles)
rm -f $(libname)
include Makefile.dep
depend:
makedepend -Y. -I../../pikotools/src -f- $(sourcefiles) > Makefile.dep
-include Makefile.dep

View File

@ -1,63 +1,380 @@
# DO NOT DELETE
baseexpression.o: baseexpression.h morm_types.h modelenv.h modeldata.h
baseexpression.o: cursorhelper.h queryresult.h finderhelper.h
baseexpression.o: fieldvaluehelper.h wrapper.h spacewrapper.h
baseexpression.o: baseobjectwrapper.h modelcontainerwrapper.h ft.h model.h
baseexpression.o: modelconnector.h clearer.h dbconnector.h flatconnector.h
baseexpression.o: dbexpression.h 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 wrapper.h spacewrapper.h baseobjectwrapper.h
clearer.o: modelcontainerwrapper.h flatexpression.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 wrapper.h
dbconnector.o: spacewrapper.h baseobjectwrapper.h modelcontainerwrapper.h
dbconnector.o: model.h modelconnector.h clearer.h flatconnector.h
dbconnector.o: flatexpression.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 wrapper.h spacewrapper.h
dbexpression.o: baseobjectwrapper.h modelcontainerwrapper.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 wrapper.h
flatconnector.o: spacewrapper.h baseobjectwrapper.h modelcontainerwrapper.h
flatconnector.o: ft.h model.h modelconnector.h clearer.h dbconnector.h
flatconnector.o: 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 wrapper.h spacewrapper.h
flatexpression.o: baseobjectwrapper.h modelcontainerwrapper.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 finderhelper.h
jsonconnector.o: fieldvaluehelper.h wrapper.h spacewrapper.h
jsonconnector.o: baseobjectwrapper.h modelcontainerwrapper.h ft.h
jsonexpression.o: jsonexpression.h flatexpression.h baseexpression.h
jsonexpression.o: morm_types.h modelenv.h modeldata.h cursorhelper.h
jsonexpression.o: queryresult.h finderhelper.h fieldvaluehelper.h wrapper.h
jsonexpression.o: spacewrapper.h baseobjectwrapper.h modelcontainerwrapper.h
jsonexpression.o: 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 wrapper.h spacewrapper.h baseobjectwrapper.h
model.o: modelcontainerwrapper.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 wrapper.h spacewrapper.h
postgresqlconnector.o: baseobjectwrapper.h modelcontainerwrapper.h
postgresqlexpression.o: postgresqlexpression.h dbexpression.h
postgresqlexpression.o: baseexpression.h morm_types.h modelenv.h modeldata.h
postgresqlexpression.o: cursorhelper.h queryresult.h finderhelper.h
postgresqlexpression.o: fieldvaluehelper.h wrapper.h spacewrapper.h
postgresqlexpression.o: baseobjectwrapper.h modelcontainerwrapper.h ft.h
postgresqlqueryresult.o: postgresqlqueryresult.h queryresult.h
queryresult.o: queryresult.h
./baseexpression.o: baseexpression.h
./baseexpression.o: ../../pikotools/src/textstream/textstream.h
./baseexpression.o: ../../pikotools/src/textstream/stream.h
./baseexpression.o: ../../pikotools/src/space/space.h
./baseexpression.o: ../../pikotools/src/textstream/types.h
./baseexpression.o: ../../pikotools/src/convert/inttostr.h
./baseexpression.o: ../../pikotools/src/utf8/utf8.h
./baseexpression.o: ../../pikotools/src/textstream/stream.h
./baseexpression.o: ../../pikotools/src/utf8/utf8_templates.h
./baseexpression.o: ../../pikotools/src/utf8/utf8_private.h
./baseexpression.o: ../../pikotools/src/date/date.h
./baseexpression.o: ../../pikotools/src/membuffer/membuffer.h
./baseexpression.o: ../../pikotools/src/textstream/types.h morm_types.h
./baseexpression.o: modelenv.h modeldata.h cursorhelper.h queryresult.h
./baseexpression.o: ../../pikotools/src/log/log.h
./baseexpression.o: ../../pikotools/src/log/filelog.h finderhelper.h
./baseexpression.o: fieldvaluehelper.h wrapper.h spacewrapper.h
./baseexpression.o: baseobjectwrapper.h modelcontainerwrapper.h select.h ft.h
./baseexpression.o: export.h ../../pikotools/src/convert/text.h model.h
./baseexpression.o: modelconnector.h clearer.h dbconnector.h flatconnector.h
./baseexpression.o: dbexpression.h flatexpression.h
./clearer.o: clearer.h ../../pikotools/src/date/date.h
./clearer.o: ../../pikotools/src/convert/inttostr.h
./clearer.o: ../../pikotools/src/space/space.h
./clearer.o: ../../pikotools/src/textstream/types.h
./clearer.o: ../../pikotools/src/utf8/utf8.h
./clearer.o: ../../pikotools/src/textstream/stream.h
./clearer.o: ../../pikotools/src/utf8/utf8_templates.h
./clearer.o: ../../pikotools/src/utf8/utf8_private.h ft.h model.h
./clearer.o: ../../pikotools/src/textstream/textstream.h
./clearer.o: ../../pikotools/src/textstream/stream.h
./clearer.o: ../../pikotools/src/membuffer/membuffer.h
./clearer.o: ../../pikotools/src/textstream/types.h modelconnector.h
./clearer.o: dbconnector.h ../../pikotools/src/log/log.h
./clearer.o: ../../pikotools/src/log/filelog.h queryresult.h flatconnector.h
./clearer.o: export.h dbexpression.h baseexpression.h morm_types.h modelenv.h
./clearer.o: modeldata.h cursorhelper.h finderhelper.h fieldvaluehelper.h
./clearer.o: wrapper.h spacewrapper.h baseobjectwrapper.h
./clearer.o: modelcontainerwrapper.h select.h
./clearer.o: ../../pikotools/src/convert/text.h flatexpression.h
./dbconnector.o: ../../pikotools/src/space/spaceparser.h
./dbconnector.o: ../../pikotools/src/space/space.h
./dbconnector.o: ../../pikotools/src/textstream/types.h
./dbconnector.o: ../../pikotools/src/convert/inttostr.h
./dbconnector.o: ../../pikotools/src/utf8/utf8.h
./dbconnector.o: ../../pikotools/src/textstream/stream.h
./dbconnector.o: ../../pikotools/src/utf8/utf8_templates.h
./dbconnector.o: ../../pikotools/src/utf8/utf8_private.h
./dbconnector.o: ../../pikotools/src/convert/baseparser.h
./dbconnector.o: ../../pikotools/src/textstream/textstream.h
./dbconnector.o: ../../pikotools/src/textstream/stream.h
./dbconnector.o: ../../pikotools/src/space/space.h
./dbconnector.o: ../../pikotools/src/date/date.h
./dbconnector.o: ../../pikotools/src/membuffer/membuffer.h
./dbconnector.o: ../../pikotools/src/textstream/types.h dbconnector.h
./dbconnector.o: ../../pikotools/src/log/log.h
./dbconnector.o: ../../pikotools/src/log/filelog.h queryresult.h ft.h
./dbconnector.o: dbexpression.h baseexpression.h morm_types.h modelenv.h
./dbconnector.o: modeldata.h cursorhelper.h finderhelper.h fieldvaluehelper.h
./dbconnector.o: wrapper.h spacewrapper.h baseobjectwrapper.h
./dbconnector.o: modelcontainerwrapper.h select.h export.h
./dbconnector.o: ../../pikotools/src/convert/text.h model.h modelconnector.h
./dbconnector.o: clearer.h flatconnector.h flatexpression.h
./dbconnector.o: ../../pikotools/src/convert/convert.h
./dbconnector.o: ../../pikotools/src/convert/inttostr.h
./dbconnector.o: ../../pikotools/src/convert/patternreplacer.h
./dbconnector.o: ../../pikotools/src/convert/strtoint.h
./dbconnector.o: ../../pikotools/src/convert/text.h
./dbconnector.o: ../../pikotools/src/convert/misc.h
./dbconnector.o: ../../pikotools/src/convert/double.h
./dbexpression.o: dbexpression.h baseexpression.h
./dbexpression.o: ../../pikotools/src/textstream/textstream.h
./dbexpression.o: ../../pikotools/src/textstream/stream.h
./dbexpression.o: ../../pikotools/src/space/space.h
./dbexpression.o: ../../pikotools/src/textstream/types.h
./dbexpression.o: ../../pikotools/src/convert/inttostr.h
./dbexpression.o: ../../pikotools/src/utf8/utf8.h
./dbexpression.o: ../../pikotools/src/textstream/stream.h
./dbexpression.o: ../../pikotools/src/utf8/utf8_templates.h
./dbexpression.o: ../../pikotools/src/utf8/utf8_private.h
./dbexpression.o: ../../pikotools/src/date/date.h
./dbexpression.o: ../../pikotools/src/membuffer/membuffer.h
./dbexpression.o: ../../pikotools/src/textstream/types.h morm_types.h
./dbexpression.o: modelenv.h modeldata.h cursorhelper.h queryresult.h
./dbexpression.o: ../../pikotools/src/log/log.h
./dbexpression.o: ../../pikotools/src/log/filelog.h finderhelper.h
./dbexpression.o: fieldvaluehelper.h wrapper.h spacewrapper.h
./dbexpression.o: baseobjectwrapper.h modelcontainerwrapper.h select.h ft.h
./dbexpression.o: export.h ../../pikotools/src/convert/text.h model.h
./dbexpression.o: modelconnector.h clearer.h dbconnector.h flatconnector.h
./dbexpression.o: flatexpression.h
./flatconnector.o: flatconnector.h
./flatconnector.o: ../../pikotools/src/textstream/textstream.h
./flatconnector.o: ../../pikotools/src/textstream/stream.h
./flatconnector.o: ../../pikotools/src/space/space.h
./flatconnector.o: ../../pikotools/src/textstream/types.h
./flatconnector.o: ../../pikotools/src/convert/inttostr.h
./flatconnector.o: ../../pikotools/src/utf8/utf8.h
./flatconnector.o: ../../pikotools/src/textstream/stream.h
./flatconnector.o: ../../pikotools/src/utf8/utf8_templates.h
./flatconnector.o: ../../pikotools/src/utf8/utf8_private.h
./flatconnector.o: ../../pikotools/src/date/date.h
./flatconnector.o: ../../pikotools/src/membuffer/membuffer.h
./flatconnector.o: ../../pikotools/src/textstream/types.h export.h
./flatconnector.o: flatexpression.h baseexpression.h morm_types.h modelenv.h
./flatconnector.o: modeldata.h cursorhelper.h queryresult.h
./flatconnector.o: ../../pikotools/src/log/log.h
./flatconnector.o: ../../pikotools/src/log/filelog.h finderhelper.h
./flatconnector.o: fieldvaluehelper.h wrapper.h spacewrapper.h
./flatconnector.o: baseobjectwrapper.h modelcontainerwrapper.h select.h ft.h
./flatconnector.o: ../../pikotools/src/convert/text.h model.h
./flatconnector.o: modelconnector.h clearer.h dbconnector.h dbexpression.h
./flatexpression.o: flatexpression.h baseexpression.h
./flatexpression.o: ../../pikotools/src/textstream/textstream.h
./flatexpression.o: ../../pikotools/src/textstream/stream.h
./flatexpression.o: ../../pikotools/src/space/space.h
./flatexpression.o: ../../pikotools/src/textstream/types.h
./flatexpression.o: ../../pikotools/src/convert/inttostr.h
./flatexpression.o: ../../pikotools/src/utf8/utf8.h
./flatexpression.o: ../../pikotools/src/textstream/stream.h
./flatexpression.o: ../../pikotools/src/utf8/utf8_templates.h
./flatexpression.o: ../../pikotools/src/utf8/utf8_private.h
./flatexpression.o: ../../pikotools/src/date/date.h
./flatexpression.o: ../../pikotools/src/membuffer/membuffer.h
./flatexpression.o: ../../pikotools/src/textstream/types.h morm_types.h
./flatexpression.o: modelenv.h modeldata.h cursorhelper.h queryresult.h
./flatexpression.o: ../../pikotools/src/log/log.h
./flatexpression.o: ../../pikotools/src/log/filelog.h finderhelper.h
./flatexpression.o: fieldvaluehelper.h wrapper.h spacewrapper.h
./flatexpression.o: baseobjectwrapper.h modelcontainerwrapper.h select.h ft.h
./flatexpression.o: export.h ../../pikotools/src/convert/text.h
./jsonconnector.o: jsonconnector.h flatconnector.h
./jsonconnector.o: ../../pikotools/src/textstream/textstream.h
./jsonconnector.o: ../../pikotools/src/textstream/stream.h
./jsonconnector.o: ../../pikotools/src/space/space.h
./jsonconnector.o: ../../pikotools/src/textstream/types.h
./jsonconnector.o: ../../pikotools/src/convert/inttostr.h
./jsonconnector.o: ../../pikotools/src/utf8/utf8.h
./jsonconnector.o: ../../pikotools/src/textstream/stream.h
./jsonconnector.o: ../../pikotools/src/utf8/utf8_templates.h
./jsonconnector.o: ../../pikotools/src/utf8/utf8_private.h
./jsonconnector.o: ../../pikotools/src/date/date.h
./jsonconnector.o: ../../pikotools/src/membuffer/membuffer.h
./jsonconnector.o: ../../pikotools/src/textstream/types.h export.h
./jsonconnector.o: jsonexpression.h flatexpression.h baseexpression.h
./jsonconnector.o: morm_types.h modelenv.h modeldata.h cursorhelper.h
./jsonconnector.o: queryresult.h ../../pikotools/src/log/log.h
./jsonconnector.o: ../../pikotools/src/log/filelog.h finderhelper.h
./jsonconnector.o: fieldvaluehelper.h wrapper.h spacewrapper.h
./jsonconnector.o: baseobjectwrapper.h modelcontainerwrapper.h select.h ft.h
./jsonconnector.o: ../../pikotools/src/convert/text.h
./jsonexpression.o: jsonexpression.h flatexpression.h baseexpression.h
./jsonexpression.o: ../../pikotools/src/textstream/textstream.h
./jsonexpression.o: ../../pikotools/src/textstream/stream.h
./jsonexpression.o: ../../pikotools/src/space/space.h
./jsonexpression.o: ../../pikotools/src/textstream/types.h
./jsonexpression.o: ../../pikotools/src/convert/inttostr.h
./jsonexpression.o: ../../pikotools/src/utf8/utf8.h
./jsonexpression.o: ../../pikotools/src/textstream/stream.h
./jsonexpression.o: ../../pikotools/src/utf8/utf8_templates.h
./jsonexpression.o: ../../pikotools/src/utf8/utf8_private.h
./jsonexpression.o: ../../pikotools/src/date/date.h
./jsonexpression.o: ../../pikotools/src/membuffer/membuffer.h
./jsonexpression.o: ../../pikotools/src/textstream/types.h morm_types.h
./jsonexpression.o: modelenv.h modeldata.h cursorhelper.h queryresult.h
./jsonexpression.o: ../../pikotools/src/log/log.h
./jsonexpression.o: ../../pikotools/src/log/filelog.h finderhelper.h
./jsonexpression.o: fieldvaluehelper.h wrapper.h spacewrapper.h
./jsonexpression.o: baseobjectwrapper.h modelcontainerwrapper.h select.h ft.h
./jsonexpression.o: export.h ../../pikotools/src/convert/text.h
./jsonexpression.o: ../../pikotools/src/convert/misc.h
./jsonexpression.o: ../../pikotools/src/convert/text.h
./model.o: model.h ../../pikotools/src/textstream/textstream.h
./model.o: ../../pikotools/src/textstream/stream.h
./model.o: ../../pikotools/src/space/space.h
./model.o: ../../pikotools/src/textstream/types.h
./model.o: ../../pikotools/src/convert/inttostr.h
./model.o: ../../pikotools/src/utf8/utf8.h
./model.o: ../../pikotools/src/textstream/stream.h
./model.o: ../../pikotools/src/utf8/utf8_templates.h
./model.o: ../../pikotools/src/utf8/utf8_private.h
./model.o: ../../pikotools/src/date/date.h
./model.o: ../../pikotools/src/membuffer/membuffer.h
./model.o: ../../pikotools/src/textstream/types.h modelconnector.h clearer.h
./model.o: ft.h dbconnector.h ../../pikotools/src/log/log.h
./model.o: ../../pikotools/src/log/filelog.h queryresult.h flatconnector.h
./model.o: export.h dbexpression.h baseexpression.h morm_types.h modelenv.h
./model.o: modeldata.h cursorhelper.h finderhelper.h fieldvaluehelper.h
./model.o: wrapper.h spacewrapper.h baseobjectwrapper.h
./model.o: modelcontainerwrapper.h select.h
./model.o: ../../pikotools/src/convert/text.h flatexpression.h
./modelconnector.o: modelconnector.h clearer.h
./modelconnector.o: ../../pikotools/src/date/date.h
./modelconnector.o: ../../pikotools/src/convert/inttostr.h
./modelconnector.o: ../../pikotools/src/space/space.h
./modelconnector.o: ../../pikotools/src/textstream/types.h
./modelconnector.o: ../../pikotools/src/utf8/utf8.h
./modelconnector.o: ../../pikotools/src/textstream/stream.h
./modelconnector.o: ../../pikotools/src/utf8/utf8_templates.h
./modelconnector.o: ../../pikotools/src/utf8/utf8_private.h ft.h
./modelconnector.o: dbconnector.h ../../pikotools/src/textstream/textstream.h
./modelconnector.o: ../../pikotools/src/textstream/stream.h
./modelconnector.o: ../../pikotools/src/membuffer/membuffer.h
./modelconnector.o: ../../pikotools/src/textstream/types.h
./modelconnector.o: ../../pikotools/src/log/log.h
./modelconnector.o: ../../pikotools/src/log/filelog.h queryresult.h
./modelconnector.o: flatconnector.h export.h
./postgresqlconnector.o: postgresqlconnector.h dbconnector.h
./postgresqlconnector.o: ../../pikotools/src/textstream/textstream.h
./postgresqlconnector.o: ../../pikotools/src/textstream/stream.h
./postgresqlconnector.o: ../../pikotools/src/space/space.h
./postgresqlconnector.o: ../../pikotools/src/textstream/types.h
./postgresqlconnector.o: ../../pikotools/src/convert/inttostr.h
./postgresqlconnector.o: ../../pikotools/src/utf8/utf8.h
./postgresqlconnector.o: ../../pikotools/src/textstream/stream.h
./postgresqlconnector.o: ../../pikotools/src/utf8/utf8_templates.h
./postgresqlconnector.o: ../../pikotools/src/utf8/utf8_private.h
./postgresqlconnector.o: ../../pikotools/src/date/date.h
./postgresqlconnector.o: ../../pikotools/src/membuffer/membuffer.h
./postgresqlconnector.o: ../../pikotools/src/textstream/types.h
./postgresqlconnector.o: ../../pikotools/src/log/log.h
./postgresqlconnector.o: ../../pikotools/src/log/filelog.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 wrapper.h spacewrapper.h
./postgresqlconnector.o: baseobjectwrapper.h modelcontainerwrapper.h select.h
./postgresqlconnector.o: export.h ../../pikotools/src/convert/text.h
./postgresqlconnector.o: ../../pikotools/src/convert/strtoint.h
./postgresqlconnector.o: ../../pikotools/src/convert/text.h
./postgresqlconnector.o: ../../pikotools/src/convert/misc.h
./postgresqlexpression.o: postgresqlexpression.h dbexpression.h
./postgresqlexpression.o: baseexpression.h
./postgresqlexpression.o: ../../pikotools/src/textstream/textstream.h
./postgresqlexpression.o: ../../pikotools/src/textstream/stream.h
./postgresqlexpression.o: ../../pikotools/src/space/space.h
./postgresqlexpression.o: ../../pikotools/src/textstream/types.h
./postgresqlexpression.o: ../../pikotools/src/convert/inttostr.h
./postgresqlexpression.o: ../../pikotools/src/utf8/utf8.h
./postgresqlexpression.o: ../../pikotools/src/textstream/stream.h
./postgresqlexpression.o: ../../pikotools/src/utf8/utf8_templates.h
./postgresqlexpression.o: ../../pikotools/src/utf8/utf8_private.h
./postgresqlexpression.o: ../../pikotools/src/date/date.h
./postgresqlexpression.o: ../../pikotools/src/membuffer/membuffer.h
./postgresqlexpression.o: ../../pikotools/src/textstream/types.h morm_types.h
./postgresqlexpression.o: modelenv.h modeldata.h cursorhelper.h queryresult.h
./postgresqlexpression.o: ../../pikotools/src/log/log.h
./postgresqlexpression.o: ../../pikotools/src/log/filelog.h finderhelper.h
./postgresqlexpression.o: fieldvaluehelper.h wrapper.h spacewrapper.h
./postgresqlexpression.o: baseobjectwrapper.h modelcontainerwrapper.h
./postgresqlexpression.o: select.h ft.h export.h
./postgresqlexpression.o: ../../pikotools/src/convert/text.h
./postgresqlqueryresult.o: postgresqlqueryresult.h queryresult.h
./postgresqlqueryresult.o: ../../pikotools/src/log/log.h
./postgresqlqueryresult.o: ../../pikotools/src/textstream/textstream.h
./postgresqlqueryresult.o: ../../pikotools/src/textstream/stream.h
./postgresqlqueryresult.o: ../../pikotools/src/space/space.h
./postgresqlqueryresult.o: ../../pikotools/src/textstream/types.h
./postgresqlqueryresult.o: ../../pikotools/src/convert/inttostr.h
./postgresqlqueryresult.o: ../../pikotools/src/utf8/utf8.h
./postgresqlqueryresult.o: ../../pikotools/src/textstream/stream.h
./postgresqlqueryresult.o: ../../pikotools/src/utf8/utf8_templates.h
./postgresqlqueryresult.o: ../../pikotools/src/utf8/utf8_private.h
./postgresqlqueryresult.o: ../../pikotools/src/date/date.h
./postgresqlqueryresult.o: ../../pikotools/src/membuffer/membuffer.h
./postgresqlqueryresult.o: ../../pikotools/src/textstream/types.h
./postgresqlqueryresult.o: ../../pikotools/src/log/filelog.h
./queryresult.o: queryresult.h ../../pikotools/src/log/log.h
./queryresult.o: ../../pikotools/src/textstream/textstream.h
./queryresult.o: ../../pikotools/src/textstream/stream.h
./queryresult.o: ../../pikotools/src/space/space.h
./queryresult.o: ../../pikotools/src/textstream/types.h
./queryresult.o: ../../pikotools/src/convert/inttostr.h
./queryresult.o: ../../pikotools/src/utf8/utf8.h
./queryresult.o: ../../pikotools/src/textstream/stream.h
./queryresult.o: ../../pikotools/src/utf8/utf8_templates.h
./queryresult.o: ../../pikotools/src/utf8/utf8_private.h
./queryresult.o: ../../pikotools/src/date/date.h
./queryresult.o: ../../pikotools/src/membuffer/membuffer.h
./queryresult.o: ../../pikotools/src/textstream/types.h
./queryresult.o: ../../pikotools/src/log/filelog.h
./transaction.o: transaction.h ../../pikotools/src/log/log.h
./transaction.o: ../../pikotools/src/textstream/textstream.h
./transaction.o: ../../pikotools/src/textstream/stream.h
./transaction.o: ../../pikotools/src/space/space.h
./transaction.o: ../../pikotools/src/textstream/types.h
./transaction.o: ../../pikotools/src/convert/inttostr.h
./transaction.o: ../../pikotools/src/utf8/utf8.h
./transaction.o: ../../pikotools/src/textstream/stream.h
./transaction.o: ../../pikotools/src/utf8/utf8_templates.h
./transaction.o: ../../pikotools/src/utf8/utf8_private.h
./transaction.o: ../../pikotools/src/date/date.h
./transaction.o: ../../pikotools/src/membuffer/membuffer.h
./transaction.o: ../../pikotools/src/textstream/types.h
./transaction.o: ../../pikotools/src/log/filelog.h modelconnector.h clearer.h
./transaction.o: ft.h dbconnector.h queryresult.h flatconnector.h export.h
./xmlconnector.o: xmlconnector.h flatconnector.h
./xmlconnector.o: ../../pikotools/src/textstream/textstream.h
./xmlconnector.o: ../../pikotools/src/textstream/stream.h
./xmlconnector.o: ../../pikotools/src/space/space.h
./xmlconnector.o: ../../pikotools/src/textstream/types.h
./xmlconnector.o: ../../pikotools/src/convert/inttostr.h
./xmlconnector.o: ../../pikotools/src/utf8/utf8.h
./xmlconnector.o: ../../pikotools/src/textstream/stream.h
./xmlconnector.o: ../../pikotools/src/utf8/utf8_templates.h
./xmlconnector.o: ../../pikotools/src/utf8/utf8_private.h
./xmlconnector.o: ../../pikotools/src/date/date.h
./xmlconnector.o: ../../pikotools/src/membuffer/membuffer.h
./xmlconnector.o: ../../pikotools/src/textstream/types.h export.h
./xmlconnector.o: xmlexpression.h flatexpression.h baseexpression.h
./xmlconnector.o: morm_types.h modelenv.h modeldata.h cursorhelper.h
./xmlconnector.o: queryresult.h ../../pikotools/src/log/log.h
./xmlconnector.o: ../../pikotools/src/log/filelog.h finderhelper.h
./xmlconnector.o: fieldvaluehelper.h wrapper.h spacewrapper.h
./xmlconnector.o: baseobjectwrapper.h modelcontainerwrapper.h select.h ft.h
./xmlconnector.o: ../../pikotools/src/convert/text.h
./xmlexpression.o: xmlexpression.h flatexpression.h baseexpression.h
./xmlexpression.o: ../../pikotools/src/textstream/textstream.h
./xmlexpression.o: ../../pikotools/src/textstream/stream.h
./xmlexpression.o: ../../pikotools/src/space/space.h
./xmlexpression.o: ../../pikotools/src/textstream/types.h
./xmlexpression.o: ../../pikotools/src/convert/inttostr.h
./xmlexpression.o: ../../pikotools/src/utf8/utf8.h
./xmlexpression.o: ../../pikotools/src/textstream/stream.h
./xmlexpression.o: ../../pikotools/src/utf8/utf8_templates.h
./xmlexpression.o: ../../pikotools/src/utf8/utf8_private.h
./xmlexpression.o: ../../pikotools/src/date/date.h
./xmlexpression.o: ../../pikotools/src/membuffer/membuffer.h
./xmlexpression.o: ../../pikotools/src/textstream/types.h morm_types.h
./xmlexpression.o: modelenv.h modeldata.h cursorhelper.h queryresult.h
./xmlexpression.o: ../../pikotools/src/log/log.h
./xmlexpression.o: ../../pikotools/src/log/filelog.h finderhelper.h
./xmlexpression.o: fieldvaluehelper.h wrapper.h spacewrapper.h
./xmlexpression.o: baseobjectwrapper.h modelcontainerwrapper.h select.h ft.h
./xmlexpression.o: export.h ../../pikotools/src/convert/text.h
./xmlexpression.o: ../../pikotools/src/convert/misc.h
./xmlexpression.o: ../../pikotools/src/convert/text.h
./csvexpression.o: csvexpression.h flatexpression.h baseexpression.h
./csvexpression.o: ../../pikotools/src/textstream/textstream.h
./csvexpression.o: ../../pikotools/src/textstream/stream.h
./csvexpression.o: ../../pikotools/src/space/space.h
./csvexpression.o: ../../pikotools/src/textstream/types.h
./csvexpression.o: ../../pikotools/src/convert/inttostr.h
./csvexpression.o: ../../pikotools/src/utf8/utf8.h
./csvexpression.o: ../../pikotools/src/textstream/stream.h
./csvexpression.o: ../../pikotools/src/utf8/utf8_templates.h
./csvexpression.o: ../../pikotools/src/utf8/utf8_private.h
./csvexpression.o: ../../pikotools/src/date/date.h
./csvexpression.o: ../../pikotools/src/membuffer/membuffer.h
./csvexpression.o: ../../pikotools/src/textstream/types.h morm_types.h
./csvexpression.o: modelenv.h modeldata.h cursorhelper.h queryresult.h
./csvexpression.o: ../../pikotools/src/log/log.h
./csvexpression.o: ../../pikotools/src/log/filelog.h finderhelper.h
./csvexpression.o: fieldvaluehelper.h wrapper.h spacewrapper.h
./csvexpression.o: baseobjectwrapper.h modelcontainerwrapper.h select.h ft.h
./csvexpression.o: export.h ../../pikotools/src/convert/text.h
./csvexpression.o: ../../pikotools/src/convert/misc.h
./csvexpression.o: ../../pikotools/src/convert/text.h
./csvconnector.o: csvconnector.h flatconnector.h
./csvconnector.o: ../../pikotools/src/textstream/textstream.h
./csvconnector.o: ../../pikotools/src/textstream/stream.h
./csvconnector.o: ../../pikotools/src/space/space.h
./csvconnector.o: ../../pikotools/src/textstream/types.h
./csvconnector.o: ../../pikotools/src/convert/inttostr.h
./csvconnector.o: ../../pikotools/src/utf8/utf8.h
./csvconnector.o: ../../pikotools/src/textstream/stream.h
./csvconnector.o: ../../pikotools/src/utf8/utf8_templates.h
./csvconnector.o: ../../pikotools/src/utf8/utf8_private.h
./csvconnector.o: ../../pikotools/src/date/date.h
./csvconnector.o: ../../pikotools/src/membuffer/membuffer.h
./csvconnector.o: ../../pikotools/src/textstream/types.h export.h
./csvconnector.o: csvexpression.h flatexpression.h baseexpression.h
./csvconnector.o: morm_types.h modelenv.h modeldata.h cursorhelper.h
./csvconnector.o: queryresult.h ../../pikotools/src/log/log.h
./csvconnector.o: ../../pikotools/src/log/filelog.h finderhelper.h
./csvconnector.o: fieldvaluehelper.h wrapper.h spacewrapper.h
./csvconnector.o: baseobjectwrapper.h modelcontainerwrapper.h select.h ft.h
./csvconnector.o: ../../pikotools/src/convert/text.h

View File

@ -1 +0,0 @@
o = baseexpression.o clearer.o dbconnector.o dbexpression.o flatconnector.o flatexpression.o jsonconnector.o jsonexpression.o model.o modelconnector.o postgresqlconnector.o postgresqlexpression.o postgresqlqueryresult.o queryresult.o

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -44,9 +44,14 @@ namespace morm
BaseExpression::BaseExpression()
{
/*
* may it would be better for the ModelConnector/JSONConnector/PostgreSQLConnector to provide one scratch buffer?
*/
scratch_buffer = &scratch_buffer_local;
clear();
}
BaseExpression::~BaseExpression()
{
}
@ -57,6 +62,7 @@ void BaseExpression::clear()
out_stream = nullptr;
is_first_field = false;
work_mode = 0;
output_type = 0;
use_prefix = false;
}
@ -73,6 +79,18 @@ int BaseExpression::get_work_mode()
}
void BaseExpression::set_output_type(int output_type)
{
this->output_type = output_type;
}
int BaseExpression::get_output_type()
{
return output_type;
}
pt::TextStream * BaseExpression::get_text_stream()
{
@ -108,21 +126,36 @@ bool BaseExpression::get_allow_to_use_prefix()
void BaseExpression::generate_from_model(pt::TextStream & stream, Model & model)
{
FT field_type = FT::default_type;
generate_from_model(stream, model, field_type);
}
void BaseExpression::generate_from_model(pt::TextStream & stream, Model & model, const FT & field_type)
{
this->out_stream = &stream;
generate_from_model(model);
generate_from_model(model, field_type);
this->out_stream = nullptr;
}
void BaseExpression::generate_from_model(Model & model)
void BaseExpression::generate_from_model(Model & model, const FT & field_type)
{
if( out_stream )
{
before_generate_from_model();
dump_additional_info(model);
model.fields();
after_generate_from_model();
if( should_field_model_be_generated_as_null(model.get_has_primary_key_set(), field_type) )
{
put_null_value();
}
else
{
before_generate_from_model();
dump_additional_info(model);
model.fields();
add_additional_columns(model);
after_generate_from_model();
}
}
}
@ -137,6 +170,11 @@ void BaseExpression::dump_additional_info(Model & model)
}
void BaseExpression::add_additional_columns(Model & model)
{
}
void BaseExpression::before_generate_from_model()
{
is_first_field = true;
@ -154,6 +192,24 @@ bool BaseExpression::can_field_be_generated(const FT &)
}
bool BaseExpression::can_field_model_be_generated(bool has_model_primary_key, const FT & field_type)
{
return true;
}
bool BaseExpression::can_field_list_be_generated(const FT &)
{
return true;
}
bool BaseExpression::should_field_model_be_generated_as_null(bool has_model_primary_key, const FT & field_type)
{
return false;
}
void BaseExpression::field_before()
{
if( !is_first_field )
@ -200,12 +256,27 @@ void BaseExpression::put_field_name(const wchar_t * field_name, const FT & field
else
{
before_field_name();
esc(field_name, *out_stream);
esc(field_name, *out_stream, FT::default_type, nullptr); /* do not use provided field_type here - it would use e.g. binary mode if it was set, similar don't use model_env */
after_field_name();
}
}
void BaseExpression::put_field_closing_name(const wchar_t * field_name, const FT & field_type, ModelEnv * model_env)
{
put_field_name(field_name, field_type, model_env);
}
void BaseExpression::put_value_list_opening_index(size_t index, const FT & field_type)
{
}
void BaseExpression::put_value_list_closing_index(size_t index, const FT & field_type)
{
}
void BaseExpression::save_foreign_key(const wchar_t * field_name, const FT & field_type, ModelEnv * model_env)
{
@ -236,6 +307,10 @@ void BaseExpression::table_field_separator()
}
void BaseExpression::alias_names_separator()
{
}
void BaseExpression::before_schema_name()
{
@ -267,95 +342,105 @@ void BaseExpression::after_field_name()
}
void BaseExpression::before_field_value(const std::wstring &, const FT & field_type)
void BaseExpression::before_alias_name()
{
before_field_value_string(field_type);
}
void BaseExpression::before_field_value(const std::string &, const FT & field_type)
void BaseExpression::after_alias_name()
{
before_field_value_string(field_type);
}
void BaseExpression::after_field_value(const std::wstring &, const FT & field_type)
void BaseExpression::before_field_value(const std::wstring &, const FT & field_type, ModelEnv * model_env)
{
after_field_value_string(field_type);
before_field_value_string(field_type, model_env);
}
void BaseExpression::after_field_value(const std::string &, const FT & field_type)
void BaseExpression::before_field_value(const std::string &, const FT & field_type, ModelEnv * model_env)
{
after_field_value_string(field_type);
before_field_value_string(field_type, model_env);
}
void BaseExpression::before_field_value(const wchar_t *, const FT & field_type)
void BaseExpression::after_field_value(const std::wstring &, const FT & field_type, ModelEnv * model_env)
{
before_field_value_string(field_type);
after_field_value_string(field_type, model_env);
}
void BaseExpression::after_field_value(const wchar_t *, const FT & field_type)
void BaseExpression::after_field_value(const std::string &, const FT & field_type, ModelEnv * model_env)
{
after_field_value_string(field_type);
after_field_value_string(field_type, model_env);
}
void BaseExpression::before_field_value(const char *, const FT & field_type)
void BaseExpression::before_field_value(const wchar_t *, const FT & field_type, ModelEnv * model_env)
{
before_field_value_string(field_type);
before_field_value_string(field_type, model_env);
}
void BaseExpression::after_field_value(const char *, const FT & field_type)
void BaseExpression::after_field_value(const wchar_t *, const FT & field_type, ModelEnv * model_env)
{
after_field_value_string(field_type);
after_field_value_string(field_type, model_env);
}
void BaseExpression::before_field_value(wchar_t, const FT & field_type)
void BaseExpression::before_field_value(const char *, const FT & field_type, ModelEnv * model_env)
{
before_field_value_string(field_type);
before_field_value_string(field_type, model_env);
}
void BaseExpression::after_field_value(wchar_t, const FT & field_type)
void BaseExpression::after_field_value(const char *, const FT & field_type, ModelEnv * model_env)
{
after_field_value_string(field_type);
after_field_value_string(field_type, model_env);
}
void BaseExpression::before_field_value(char, const FT & field_type)
void BaseExpression::before_field_value(wchar_t, const FT & field_type, ModelEnv * model_env)
{
before_field_value_string(field_type);
before_field_value_string(field_type, model_env);
}
void BaseExpression::after_field_value(char, const FT & field_type)
void BaseExpression::after_field_value(wchar_t, const FT & field_type, ModelEnv * model_env)
{
after_field_value_string(field_type);
after_field_value_string(field_type, model_env);
}
void BaseExpression::before_field_value(const pt::Date &, const FT & field_type)
void BaseExpression::before_field_value(char, const FT & field_type, ModelEnv * model_env)
{
before_field_value_string(field_type);
before_field_value_string(field_type, model_env);
}
void BaseExpression::after_field_value(const pt::Date &, const FT & field_type)
void BaseExpression::after_field_value(char, const FT & field_type, ModelEnv * model_env)
{
after_field_value_string(field_type);
after_field_value_string(field_type, model_env);
}
void BaseExpression::before_field_value(const pt::Space &, const FT & field_type)
void BaseExpression::before_field_value(const pt::Date &, const FT & field_type, ModelEnv * model_env)
{
before_field_value_string(field_type);
before_field_value_string(field_type, model_env);
}
void BaseExpression::after_field_value(const pt::Space &, const FT & field_type)
void BaseExpression::after_field_value(const pt::Date &, const FT & field_type, ModelEnv * model_env)
{
after_field_value_string(field_type);
after_field_value_string(field_type, model_env);
}
void BaseExpression::before_field_value(const pt::Space &, const FT & field_type, ModelEnv * model_env)
{
before_field_value_string(field_type, model_env);
}
void BaseExpression::after_field_value(const pt::Space &, const FT & field_type, ModelEnv * model_env)
{
after_field_value_string(field_type, model_env);
}
@ -381,9 +466,41 @@ void BaseExpression::char_to_hex(char c, pt::TextStream & stream)
}
void BaseExpression::char_to_hex(wchar_t c, pt::TextStream & stream)
{
unsigned int z = static_cast<unsigned int>(c);
char_to_hex((char)(unsigned char)(z >> 24), stream);
char_to_hex((char)(unsigned char)(z >> 16), stream);
char_to_hex((char)(unsigned char)(z >> 8), stream);
char_to_hex((char)(unsigned char)(z), stream);
}
void BaseExpression::esc(char val, pt::TextStream & stream, const FT & field_type)
/*
* return true if the val character was escaped and put (or ignored) to the stream
*
*/
bool BaseExpression::esc_char(char val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
return esc_char((wchar_t)(unsigned char)val, stream, field_type, model_env);
}
/*
* return true if the val character was escaped and put (or ignored) to the stream
*
* in most caces you have to provide your own esc_char(wchar_t val, pt::TextStream & stream) method
*
*/
bool BaseExpression::esc_char(wchar_t val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
return false;
}
void BaseExpression::esc(char val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
if( field_type.is_binary() || field_type.is_hexadecimal() )
{
@ -391,96 +508,99 @@ void BaseExpression::esc(char val, pt::TextStream & stream, const FT & field_typ
}
else
{
stream << val;
if( !esc_char(val, stream, field_type, model_env) )
{
stream << val;
}
}
}
void BaseExpression::esc(unsigned char val, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(unsigned char val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
esc(static_cast<char>(val), stream, field_type);
esc(static_cast<char>(val), stream, field_type, model_env);
}
void BaseExpression::esc(wchar_t val, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(wchar_t val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
if( field_type.use_utf8() )
if( field_type.is_binary() || field_type.is_hexadecimal() )
{
char utf8_buf[10];
// FIXME surrogate pairs are not used
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, field_type);
}
char_to_hex(val, stream);
}
else
{
esc(static_cast<char>(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)
if( field_type.use_utf8() )
{
// FIXME surrogate pairs are not used
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)
if( !esc_char(val, stream, field_type, model_env) )
{
esc(utf8_buf[a], stream, field_type);
stream << val;
}
}
else
{
char val_char = (char)(unsigned char)val;
if( !esc_char(val_char, stream, field_type, model_env) )
{
stream << val_char;
}
}
}
}
void BaseExpression::esc(const wchar_t * val, bool has_known_length, size_t len, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
if( field_type.is_numeric() )
{
esc_numeric_string(val, has_known_length, len, stream, field_type, model_env);
}
else
{
for(size_t i = 0 ; has_known_length ? (i < len) : val[i] != 0 ; ++i)
{
esc(static_cast<char>(val[i]), stream, field_type);
}
esc_normal_string(val, has_known_length, len, stream, field_type, model_env);
}
}
void BaseExpression::esc(const std::wstring & val, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(const char * val, bool has_known_length, size_t len, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
esc(val.c_str(), true, val.size(), stream, field_type);
}
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)
if( field_type.is_numeric() )
{
esc(val[i], stream, field_type);
esc_numeric_string(val, has_known_length, len, stream, field_type, model_env);
}
}
void BaseExpression::esc(const char * val, pt::TextStream & stream, const FT & field_type)
{
for(size_t i = 0 ; val[i] != 0 ; ++i)
else
{
esc(val[i], stream, field_type);
esc_normal_string(val, has_known_length, len, stream, field_type, model_env);
}
}
void BaseExpression::esc(bool val, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(const std::wstring & val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
esc(val.c_str(), true, val.size(), stream, field_type, model_env);
}
void BaseExpression::esc(const wchar_t * val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
esc(val, false, 0, stream, field_type, model_env);
}
void BaseExpression::esc(const std::string & val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
esc(val.c_str(), true, val.size(), stream, field_type, model_env);
}
void BaseExpression::esc(const char * val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
esc(val, false, 0, stream, field_type, model_env);
}
void BaseExpression::esc(bool val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
if( val )
stream << "true";
@ -489,101 +609,120 @@ void BaseExpression::esc(bool val, pt::TextStream & stream, const FT & field_typ
}
void BaseExpression::esc(short val, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(short val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
stream << val;
}
void BaseExpression::esc(unsigned short val, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(unsigned short val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
stream << val;
}
void BaseExpression::esc(int val, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(int val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
stream << val;
}
void BaseExpression::esc(unsigned int val, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(unsigned int val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
stream << val;
}
void BaseExpression::esc(long val, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(long val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
stream << val;
}
void BaseExpression::esc(unsigned long val, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(unsigned long val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
stream << val;
}
void BaseExpression::esc(long long val, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(long long val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
stream << val;
}
void BaseExpression::esc(unsigned long long val, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(unsigned long long val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
stream << val;
}
void BaseExpression::esc(float val, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(float val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
stream << val;
}
void BaseExpression::esc(double val, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(double val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
stream << val;
}
void BaseExpression::esc(long double val, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(long double val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
stream << val;
}
void BaseExpression::esc(const pt::Date & date, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(const pt::Date & date, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
stream << date;
if( field_type.is_date_only() )
{
date.SerializeYearMonthDay(stream, false);
}
else
if( field_type.is_time_only() )
{
date.SerializeHourMinSec(stream);
}
else
{
if( field_type.is_no_time_zone() )
{
date.Serialize(stream);
}
else
{
date.SerializeISO(stream);
}
}
}
void BaseExpression::esc(const pt::TextStream & val, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(const pt::TextStream & val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
pt::TextStream::const_iterator i = val.begin();
for(; i != val.end() ; ++i)
{
esc(*i, stream, field_type);
esc(*i, stream, field_type, model_env);
}
}
void BaseExpression::esc(const pt::WTextStream & val, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(const pt::WTextStream & val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
pt::WTextStream::const_iterator i = val.begin();
for(; i != val.end() ; ++i)
{
esc(*i, stream, field_type);
esc(*i, stream, field_type, model_env);
}
}
void BaseExpression::esc(const pt::Space & space, pt::TextStream & stream, const FT & field_type)
void BaseExpression::esc(const pt::Space & space, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
pt::WTextStream tmp_stream;
bool pretty_print = field_type.is_pretty_print();
@ -593,7 +732,7 @@ void BaseExpression::esc(const pt::Space & space, pt::TextStream & stream, const
else
space.serialize_to_json_stream(tmp_stream, pretty_print);
esc(tmp_stream, stream, field_type);
esc(tmp_stream, stream, field_type, model_env);
}
@ -706,11 +845,11 @@ void BaseExpression::esc(const pt::Space & space, pt::TextStream & stream, const
//}
void BaseExpression::before_field_value_string(const FT & field_type)
void BaseExpression::before_field_value_string(const FT & field_type, ModelEnv * model_env)
{
}
void BaseExpression::after_field_value_string(const FT & field_type)
void BaseExpression::after_field_value_string(const FT & field_type, ModelEnv * model_env)
{
}
@ -863,6 +1002,7 @@ void BaseExpression::put_table_and_field(const wchar_t * table_name, const wchar
}
}
void BaseExpression::put_table_and_field(const pt::WTextStream & table_name, const wchar_t * field_name, const FT & field_type)
{
if( out_stream )
@ -874,6 +1014,79 @@ void BaseExpression::put_table_and_field(const pt::WTextStream & table_name, con
}
void BaseExpression::put_alias(const pt::WTextStream & alias_name, int index)
{
if( out_stream )
{
before_alias_name();
esc(alias_name, *out_stream);
if( index > 1 )
{
(*out_stream) << index;
}
after_alias_name();
}
}
void BaseExpression::put_alias(const pt::WTextStream & alias_name_prefix, int index, const wchar_t * alias_name_postfix)
{
if( out_stream )
{
before_alias_name();
esc(alias_name_prefix, *out_stream);
if( index > 1 )
{
(*out_stream) << index;
}
alias_names_separator();
esc(alias_name_postfix, *out_stream);
after_alias_name();
}
}
void BaseExpression::put_string(const char * str, const FT & field_type, bool add_quotes, ModelEnv * model_env)
{
put_string_generic(str, field_type, add_quotes, model_env);
}
void BaseExpression::put_string(const wchar_t * str, const FT & field_type, bool add_quotes, ModelEnv * model_env)
{
put_string_generic(str, field_type, add_quotes, model_env);
}
void BaseExpression::put_string(const std::string & str, const FT & field_type, bool add_quotes, ModelEnv * model_env)
{
put_string_generic(str, field_type, add_quotes, model_env);
}
void BaseExpression::put_string(const std::wstring & str, const FT & field_type, bool add_quotes, ModelEnv * model_env)
{
put_string_generic(str, field_type, add_quotes, model_env);
}
void BaseExpression::put_stream(const pt::TextStream & str, const FT & field_type, bool add_quotes, ModelEnv * model_env)
{
put_string_generic(str, field_type, add_quotes, model_env);
}
void BaseExpression::put_stream(const pt::WTextStream & str, const FT & field_type, bool add_quotes, ModelEnv * model_env)
{
put_string_generic(str, field_type, add_quotes, model_env);
}
void BaseExpression::schema_table_to_stream(pt::TextStream & stream, const wchar_t * schema_name, const wchar_t * table_name)
{
@ -955,6 +1168,73 @@ void BaseExpression::table_and_field_to_stream(pt::TextStream & stream, const pt
}
void BaseExpression::alias_to_stream(pt::TextStream & stream, const pt::WTextStream & alias_name, int index)
{
this->out_stream = &stream;
put_alias(alias_name, index);
this->out_stream = nullptr;
}
void BaseExpression::alias_to_stream(pt::TextStream & stream, const pt::WTextStream & alias_name_prefix, int index, const wchar_t * alias_name_postfix)
{
this->out_stream = &stream;
put_alias(alias_name_prefix, index, alias_name_postfix);
this->out_stream = nullptr;
}
void BaseExpression::string_to_stream(pt::TextStream & stream, const char * str, const FT & field_type, bool add_quotes, ModelEnv * model_env)
{
this->out_stream = &stream;
put_string(str, field_type, add_quotes, model_env);
this->out_stream = nullptr;
}
void BaseExpression::string_to_stream(pt::TextStream & stream, const wchar_t * str, const FT & field_type, bool add_quotes, ModelEnv * model_env)
{
this->out_stream = &stream;
put_string(str, field_type, add_quotes, model_env);
this->out_stream = nullptr;
}
void BaseExpression::string_to_stream(pt::TextStream & stream, const std::string & str, const FT & field_type, bool add_quotes, ModelEnv * model_env)
{
this->out_stream = &stream;
put_string(str, field_type, add_quotes, model_env);
this->out_stream = nullptr;
}
void BaseExpression::string_to_stream(pt::TextStream & stream, const std::wstring & str, const FT & field_type, bool add_quotes, ModelEnv * model_env)
{
this->out_stream = &stream;
put_string(str, field_type, add_quotes, model_env);
this->out_stream = nullptr;
}
void BaseExpression::stream_to_stream(pt::TextStream & stream_out, const pt::TextStream & stream_in, const FT & field_type, bool add_quotes, ModelEnv * model_env)
{
this->out_stream = &stream_out;
put_stream(stream_in, field_type, add_quotes, model_env);
this->out_stream = nullptr;
}
void BaseExpression::stream_to_stream(pt::TextStream & stream_out, const pt::WTextStream & stream_in, const FT & field_type, bool add_quotes, ModelEnv * model_env)
{
this->out_stream = &stream_out;
put_stream(stream_in, field_type, add_quotes, model_env);
this->out_stream = nullptr;
}
bool BaseExpression::is_empty_field(const wchar_t * value)
{

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,16 +32,18 @@
*
*/
#ifndef headerfile_morm_baseexpression
#define headerfile_morm_baseexpression
#ifndef headerfile_morm_src_baseexpression
#define headerfile_morm_src_baseexpression
#include <list>
#include <set>
#include <type_traits>
#include "textstream/textstream.h"
#include "date/date.h"
#include "morm_types.h"
#include "modelenv.h"
#include "ft.h"
#include "export.h"
#include "convert/text.h"
#ifdef MORM_HAS_EZC_LIBRARY
@ -62,15 +64,22 @@ public:
BaseExpression();
virtual ~BaseExpression();
BaseExpression(const BaseExpression &) = delete;
BaseExpression(BaseExpression &&) = delete;
virtual void set_work_mode(int work_mode);
virtual int get_work_mode();
virtual void set_output_type(int output_type);
virtual int get_output_type();
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, const FT & field_type);
virtual pt::TextStream * get_current_stream();
@ -117,23 +126,12 @@ public:
else
if( work_mode == MORM_WORK_MODE_MODEL_FIELDS_VALUES )
{
if( model_env && model_env->set_field_name_helper )
{
if( (size_t)model_env->field_index < model_env->set_field_name_helper->size() )
{
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_or_null(field_value, getter_method, field_type, model_env);
}
model_env->field_index += 1;
}
else
{
put_field_name_and_table_if_needed(field_name, field_type, model_env);
put_name_value_separator();
put_field_value_or_null(field_value, getter_method, field_type, model_env);
}
put_field_name_and_value(field_name, field_value, getter_method, field_type, model_env);
}
else
if( work_mode == MORM_WORK_MODE_MODEL_FIELDS_VALUES_FIELDS )
{
put_field_name_and_value_and_closing_name(field_name, field_value, getter_method, field_type, model_env);
}
field_after();
@ -141,30 +139,6 @@ public:
}
template<typename FieldValue>
void put_field_value_or_null(const FieldValue & field_value, void (Model::*getter_method)(pt::Stream &), const FT & field_type, ModelEnv * model_env)
{
if( getter_method )
{
put_field_value(getter_method, field_type, model_env);
}
else
{
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<typename FieldValue>
void field_in(pt::TextStream & stream, const wchar_t * field_name, const std::set<FieldValue> & container, ModelEnv * model_env)
{
@ -190,7 +164,7 @@ public:
void field_list(const wchar_t * field_name, ModelContainer & field_value, ModelContainerType * model_container_type,
const FT & field_type, ModelConnector * model_connector, ModelEnv * model_env, IsContainerByValueRenameMe * foo)
{
if( out_stream && can_field_be_generated(field_type) )
if( out_stream && can_field_be_generated(field_type) && can_field_list_be_generated(field_type) )
{
field_before();
@ -201,9 +175,12 @@ public:
// else
if( work_mode == MORM_WORK_MODE_MODEL_FIELDS_VALUES )
{
put_field_name_and_table_if_needed(field_name, field_type, model_env);
put_name_value_separator();
put_field_value_list(field_value, model_container_type, model_connector, model_env, foo);
put_field_name_and_value_list(field_name, field_value, model_container_type, field_type, model_connector, model_env, foo);
}
else
if( work_mode == MORM_WORK_MODE_MODEL_FIELDS_VALUES_FIELDS )
{
put_field_name_and_value_list_and_closing_name(field_name, field_value, model_container_type, field_type, model_connector, model_env, foo);
}
field_after();
@ -213,31 +190,38 @@ public:
template<typename ModelClass>
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(field_type) )
if( out_stream && can_field_be_generated(field_type) && can_field_model_be_generated(field_model.get_has_primary_key_set(), field_type) )
{
field_before();
if( work_mode == MORM_WORK_MODE_MODEL_FIELDS )
{
put_field_name_and_table_if_needed(field_name, field_type, model_env);
if( output_type == MORM_OUTPUT_TYPE_FIELDS_RECURSIVE )
generate_from_model(field_model, field_type);
else
put_field_name_and_table_if_needed(field_name, field_type, model_env);
}
else
if( work_mode == MORM_WORK_MODE_MODEL_VALUES )
{
generate_from_model(field_model); // is it ok as a value?
generate_from_model(field_model, field_type);
}
else
if( work_mode == MORM_WORK_MODE_MODEL_FIELDS_VALUES )
{
put_field_name_and_table_if_needed(field_name, field_type, model_env);
put_name_value_separator();
generate_from_model(field_model);
put_field_name_and_value_model(field_name, field_model, field_type, model_env);
}
else
if( work_mode == MORM_WORK_MODE_MODEL_FIELDS_VALUES_FIELDS )
{
put_field_name_and_value_model_and_closing_name(field_name, field_model, field_type, model_env);
}
field_after();
}
}
template<typename FieldValue>
void field_to_stream(pt::TextStream & stream, const wchar_t * field_name, const FieldValue & field_value, const FT & field_type, ModelEnv * model_env)
{
@ -247,6 +231,15 @@ public:
}
template<typename FieldValue>
void value_to_stream(pt::TextStream & stream, const FieldValue & field_value, const FT & field_type, ModelEnv * model_env = nullptr)
{
this->out_stream = &stream;
put_field_value(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);
@ -257,6 +250,15 @@ public:
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 put_alias(const pt::WTextStream & alias_name, int index);
virtual void put_alias(const pt::WTextStream & alias_name_prefix, int index, const wchar_t * alias_name_postfix);
virtual void put_string(const char * str, const FT & field_type, bool add_quotes = false, ModelEnv * model_env = nullptr);
virtual void put_string(const wchar_t * str, const FT & field_type, bool add_quotes = false, ModelEnv * model_env = nullptr);
virtual void put_string(const std::string & str, const FT & field_type, bool add_quotes = false, ModelEnv * model_env = nullptr);
virtual void put_string(const std::wstring & str, const FT & field_type, bool add_quotes = false, ModelEnv * model_env = nullptr);
virtual void put_stream(const pt::TextStream & str, const FT & field_type, bool add_quotes = false, ModelEnv * model_env = nullptr);
virtual void put_stream(const pt::WTextStream & str, const FT & field_type, bool add_quotes = false, ModelEnv * model_env = nullptr);
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);
@ -268,86 +270,153 @@ public:
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);
virtual void alias_to_stream(pt::TextStream & stream, const pt::WTextStream & alias_name, int index);
virtual void alias_to_stream(pt::TextStream & stream, const pt::WTextStream & alias_name_prefix, int index, const wchar_t * alias_name_postfix);
virtual void string_to_stream(pt::TextStream & stream, const char * str, const FT & field_type, bool add_quotes = false, ModelEnv * model_env = nullptr);
virtual void string_to_stream(pt::TextStream & stream, const wchar_t * str, const FT & field_type, bool add_quotes = false, ModelEnv * model_env = nullptr);
virtual void string_to_stream(pt::TextStream & stream, const std::string & str, const FT & field_type, bool add_quotes = false, ModelEnv * model_env = nullptr);
virtual void string_to_stream(pt::TextStream & stream, const std::wstring & str, const FT & field_type, bool add_quotes = false, ModelEnv * model_env = nullptr);
virtual void stream_to_stream(pt::TextStream & stream_out, const pt::TextStream & stream_in, const FT & field_type, bool add_quotes = false, ModelEnv * model_env = nullptr);
virtual void stream_to_stream(pt::TextStream & stream_out, const pt::WTextStream & stream_in, const FT & field_type, bool add_quotes = false, ModelEnv * model_env = nullptr);
template<typename StringType>
void put_string_generic(const StringType * str, const FT & field_type, bool add_quotes, ModelEnv * model_env = nullptr)
{
if( out_stream )
{
if( add_quotes )
{
before_field_value_string(field_type, model_env);
}
esc(str, *out_stream, field_type, model_env);
if( add_quotes )
{
after_field_value_string(field_type, model_env);
}
}
}
template<typename StringOrStreamType>
void put_string_generic(const StringOrStreamType & str, const FT & field_type, bool add_quotes, ModelEnv * model_env = nullptr)
{
if( out_stream )
{
if( add_quotes )
{
before_field_value_string(field_type, model_env);
}
esc(str, *out_stream, field_type, model_env);
if( add_quotes )
{
after_field_value_string(field_type, model_env);
}
}
}
/*
* IMPLEMENT ME
* esc for: signed char, wchar_t, char16_t, char32_t
*
*/
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 bool esc_char(char val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual bool esc_char(wchar_t val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(wchar_t val, pt::TextStream & stream, const FT & field_type = FT::default_type);
virtual void esc(char val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(unsigned char val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(wchar_t val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
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::wstring & val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(const wchar_t * val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
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(const std::string & val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(const char * val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
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(bool val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(short val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(unsigned short val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(int val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(unsigned int val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(long val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(unsigned long val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(long long val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(unsigned long long val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(float val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(double val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(long double val, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
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);
virtual void esc(const pt::Date & date, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(const pt::TextStream & val,pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(const pt::WTextStream & val,pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
virtual void esc(const pt::Space & space, pt::TextStream & stream, const FT & field_type = FT::default_type, ModelEnv * model_env = nullptr);
protected:
int work_mode; /* what to do: generating fields list, values list or fields-values list */
int output_type;
bool is_first_field;
pt::TextStream * out_stream;
bool use_prefix;
pt::TextStream scratch_buffer_local;
pt::TextStream * scratch_buffer;
virtual void generate_from_model(Model & model);
virtual void generate_from_model(Model & model, const FT & field_type);
virtual void before_generate_from_model();
virtual void after_generate_from_model();
virtual bool can_field_be_generated(const FT &);
virtual bool can_field_model_be_generated(bool has_model_primary_key, const FT & field_type);
virtual bool can_field_list_be_generated(const FT &);
virtual bool should_field_model_be_generated_as_null(bool has_model_primary_key, const FT & field_type);
virtual void field_before();
virtual void field_after();
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 put_field_closing_name(const wchar_t * field_name, const FT & field_type, ModelEnv * model_env);
virtual void put_value_list_opening_index(size_t index, const FT & field_type);
virtual void put_value_list_closing_index(size_t index, const FT & field_type);
virtual void save_foreign_key(const wchar_t * field_name, const FT & field_type, ModelEnv * model_env);
virtual void dump_additional_info(Model & model);
virtual void add_additional_columns(Model & model);
template<typename FieldValue>
void put_field_value(const FieldValue & field_value, const FT & field_type)
void put_field_value(const FieldValue & field_value, const FT & field_type, ModelEnv * model_env = nullptr)
{
if( out_stream )
{
before_field_value(field_value, field_type);
esc(field_value, *out_stream, field_type);
after_field_value(field_value, field_type);
before_field_value(field_value, field_type, model_env);
esc(field_value, *out_stream, field_type, model_env);
after_field_value(field_value, field_type, model_env);
}
}
void put_field_value(void (Model::*getter_method)(pt::Stream &), const FT & field_type, ModelEnv * model_env)
void put_field_value(void (Model::*getter_method)(pt::Stream &), const FT & field_type, ModelEnv * model_env = nullptr)
{
if( out_stream && model_env && model_env->model && getter_method )
{
before_field_value_string(field_type);
(model_env->model->*getter_method)(*out_stream);
after_field_value_string(field_type);
before_field_value_string(field_type, model_env);
if( scratch_buffer )
{
scratch_buffer->clear();
(model_env->model->*getter_method)(*scratch_buffer);
esc(*scratch_buffer, *out_stream, field_type, model_env);
scratch_buffer->clear();
}
after_field_value_string(field_type, model_env);
}
}
@ -384,45 +453,50 @@ protected:
template<typename ModelContainer, typename ModelContainerType, typename IsContainerByValueRenameMe>
void put_field_value_list(ModelContainer & field_value, ModelContainerType * model_container_type, ModelConnector * model_connector,
ModelEnv * model_env, IsContainerByValueRenameMe * foo)
void put_field_value_list(ModelContainer & field_value, ModelContainerType * model_container_type, const FT & field_type,
ModelConnector * model_connector, ModelEnv * model_env, IsContainerByValueRenameMe * foo)
{
if constexpr (std::is_base_of<Model, ModelContainerType>())
{
if constexpr (std::is_base_of<Model, IsContainerByValueRenameMe>())
{
put_field_value_list_model_by_value(field_value, model_container_type, model_connector, model_env);
put_field_value_list_model_by_value(field_value, model_container_type, field_type, model_connector, model_env);
}
else
{
put_field_value_list_model_by_pointer(field_value, model_container_type, model_connector, model_env);
put_field_value_list_model_by_pointer(field_value, model_container_type, field_type, model_connector, model_env);
}
}
else
{
put_field_value_list_non_model(field_value, model_connector);
put_field_value_list_non_model(field_value, model_connector, field_type);
}
}
template<typename ModelContainer, typename ModelContainerType>
void put_field_value_list_model_by_value(ModelContainer & field_value, ModelContainerType * model_container_type, ModelConnector * model_connector,
ModelEnv * model_env)
void put_field_value_list_model_by_value(ModelContainer & field_value, ModelContainerType * model_container_type, const FT & field_type,
ModelConnector * model_connector, ModelEnv * model_env)
{
if( model_connector && model_env && out_stream )
{
bool is_first = true;
before_field_value_list();
size_t index = 0;
for(auto & child_model_item : field_value)
{
if( !is_first )
if( can_field_model_be_generated(child_model_item.get_has_primary_key_set(), field_type) )
{
field_value_list_separator();
}
if( index > 0 )
{
field_value_list_separator();
}
put_field_value_list_model(child_model_item, model_connector, model_env);
is_first = false;
put_value_list_opening_index(index, field_type);
put_field_value_list_model(child_model_item, model_connector, model_env);
put_value_list_closing_index(index, field_type);
index += 1;
}
}
after_field_value_list();
@ -431,23 +505,28 @@ protected:
template<typename ModelContainer, typename ModelContainerType>
void put_field_value_list_model_by_pointer(ModelContainer & field_value, ModelContainerType * model_container_type, ModelConnector * model_connector,
ModelEnv * model_env)
void put_field_value_list_model_by_pointer(ModelContainer & field_value, ModelContainerType * model_container_type, const FT & field_type,
ModelConnector * model_connector, ModelEnv * model_env)
{
if( model_connector && model_env && out_stream )
{
bool is_first = true;
before_field_value_list();
size_t index = 0;
for(auto * child_model_item : field_value)
{
if( !is_first )
if( can_field_model_be_generated(child_model_item->get_has_primary_key_set(), field_type) )
{
field_value_list_separator();
}
if( index > 0 )
{
field_value_list_separator();
}
put_field_value_list_model(*child_model_item, model_connector, model_env);
is_first = false;
put_value_list_opening_index(index, field_type);
put_field_value_list_model(*child_model_item, model_connector, model_env);
put_value_list_closing_index(index, field_type);
index += 1;
}
}
after_field_value_list();
@ -464,29 +543,32 @@ protected:
child_model.model_env->model = &child_model;
child_model.set_connector(model_connector);
generate_from_model(child_model);
FT field_type = FT::default_type;
generate_from_model(child_model, field_type);
child_model.model_env = nullptr;
}
template<typename ModelContainer>
void put_field_value_list_non_model(ModelContainer & field_value, ModelConnector * model_connector)
void put_field_value_list_non_model(ModelContainer & field_value, ModelConnector * model_connector, const FT & field_type)
{
if( model_connector && out_stream )
{
bool is_first = true;
before_field_value_list();
size_t index = 0;
for(const auto & m : field_value)
{
if( !is_first )
if( index > 0 )
{
field_value_list_separator();
}
put_value_list_opening_index(index, field_type);
put_field_value(m, FT::default_type);
is_first = false;
put_value_list_closing_index(index, field_type);
index += 1;
}
after_field_value_list();
@ -518,7 +600,7 @@ protected:
field_value_list_separator();
}
put_field_value(v, FT::default_type);
put_field_value(v, FT::default_type, model_env);
is_first = false;
}
@ -530,6 +612,7 @@ protected:
virtual void schema_table_separator();
virtual void table_field_separator();
virtual void alias_names_separator();
virtual void before_schema_name();
virtual void after_schema_name();
@ -540,38 +623,40 @@ protected:
virtual void before_field_name();
virtual void after_field_name();
virtual void before_alias_name();
virtual void after_alias_name();
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 std::wstring &, const FT & field_type, ModelEnv * model_env);
virtual void after_field_value(const std::wstring &, const FT & field_type, ModelEnv * model_env);
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 std::string &, const FT & field_type, ModelEnv * model_env);
virtual void after_field_value(const std::string &, const FT & field_type, ModelEnv * model_env);
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 wchar_t *, const FT & field_type, ModelEnv * model_env);
virtual void after_field_value(const wchar_t *, const FT & field_type, ModelEnv * model_env);
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(const char *, const FT & field_type, ModelEnv * model_env);
virtual void after_field_value(const char *, const FT & field_type, ModelEnv * model_env);
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(wchar_t, const FT & field_type, ModelEnv * model_env);
virtual void after_field_value(wchar_t, const FT & field_type, ModelEnv * model_env);
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(char, const FT & field_type, ModelEnv * model_env);
virtual void after_field_value(char, const FT & field_type, ModelEnv * model_env);
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::Date &, const FT & field_type, ModelEnv * model_env);
virtual void after_field_value(const pt::Date &, const FT & field_type, ModelEnv * model_env);
virtual void before_field_value(const pt::Space &, const FT & field_type);
virtual void after_field_value(const pt::Space &, const FT & field_type);
virtual void before_field_value(const pt::Space &, const FT & field_type, ModelEnv * model_env);
virtual void after_field_value(const pt::Space &, const FT & field_type, ModelEnv * model_env);
template<typename FieldValue>
void before_field_value(const FieldValue &, const FT & field_type)
void before_field_value(const FieldValue &, const FT & field_type, ModelEnv * model_env)
{
}
template<typename FieldValue>
void after_field_value(const FieldValue &, const FT & field_type)
void after_field_value(const FieldValue &, const FT & field_type, ModelEnv * model_env)
{
}
@ -623,15 +708,180 @@ protected:
virtual void before_field_value_string(const FT & field_type);
virtual void after_field_value_string(const FT & field_type);
virtual void before_field_value_string(const FT & field_type, ModelEnv * model_env);
virtual void after_field_value_string(const FT & field_type, ModelEnv * model_env);
char char_to_hex_part(char c);
void char_to_hex(char c, pt::TextStream & stream);
void char_to_hex(wchar_t c, pt::TextStream & stream);
void esc(const wchar_t * val, bool has_known_length, size_t len, pt::TextStream & stream, const FT & field_type = FT::default_type);
void esc(const wchar_t * val, bool has_known_length, size_t len, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env);
void esc(const char * val, bool has_known_length, size_t len, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env);
bool is_empty_field(const wchar_t * value);
template<typename CharType>
void esc_normal_string(CharType * val, bool has_known_length, size_t len, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
for(size_t i = 0 ; has_known_length ? (i < len) : val[i] != 0 ; ++i)
{
esc(val[i], stream, field_type, model_env);
}
}
template<typename CharType>
void esc_numeric_string(CharType * val, bool has_known_length, size_t len, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
bool was_comma = false;
bool was_something_printed = false;
bool was_digit_printed = false;
for(size_t i = 0 ; has_known_length ? (i < len) : val[i] != 0 ; ++i)
{
typename std::remove_const<CharType>::type c = val[i];
if( c == ',' )
c = '.';
if( (c=='.' && !was_comma) || (c>='0' && c<='9') || (c=='-' && !was_something_printed) )
{
if( c=='.' )
{
if( !was_digit_printed )
{
esc(static_cast<CharType>('0'), stream, field_type, model_env);
was_digit_printed = true;
}
was_comma = true;
}
esc(c, stream, field_type, model_env);
was_something_printed = true;
if( c>='0' && c<='9' )
{
was_digit_printed = true;
}
}
}
if( !was_digit_printed )
{
esc(static_cast<CharType>('0'), stream, field_type, model_env);
}
}
template<typename FieldValue>
void put_field_value_or_null(const FieldValue & field_value, void (Model::*getter_method)(pt::Stream &), const FT & field_type, ModelEnv * model_env)
{
if( getter_method )
{
put_field_value(getter_method, field_type, model_env);
}
else
{
if( field_type.is_primary_key() )
{
if( model_env && model_env->has_primary_key_set )
put_field_value(field_value, field_type, model_env);
else
put_null_value();
}
else
{
put_field_value(field_value, field_type, model_env);
}
}
}
template<typename FieldValue>
void put_field_name_and_value(const wchar_t * field_name, const FieldValue & field_value, void (Model::*getter_method)(pt::Stream &), const FT & field_type, ModelEnv * model_env)
{
bool allow_to_put_value = (get_output_type() != MORM_OUTPUT_TYPE_WHERE_IS_NULL && get_output_type() != MORM_OUTPUT_TYPE_WHERE_IS_NOT_NULL);
if( model_env && model_env->set_field_name_helper )
{
if( (size_t)model_env->field_index < model_env->set_field_name_helper->size() )
{
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();
if( allow_to_put_value )
put_field_value_or_null(field_value, getter_method, field_type, model_env);
}
model_env->field_index += 1;
}
else
{
put_field_name_and_table_if_needed(field_name, field_type, model_env);
put_name_value_separator();
if( allow_to_put_value )
put_field_value_or_null(field_value, getter_method, field_type, model_env);
}
}
template<typename ModelContainer, typename ModelContainerType, typename IsContainerByValueRenameMe>
void put_field_name_and_value_list(const wchar_t * field_name, ModelContainer & field_value, ModelContainerType * model_container_type,
const FT & field_type, ModelConnector * model_connector, ModelEnv * model_env, IsContainerByValueRenameMe * foo)
{
put_field_name_and_table_if_needed(field_name, field_type, model_env);
put_name_value_separator();
put_field_value_list(field_value, model_container_type, field_type, model_connector, model_env, foo);
}
template<typename ModelClass>
void put_field_name_and_value_model(const wchar_t * field_name, ModelClass & field_model, const FT & field_type, ModelEnv * model_env)
{
put_field_name_and_table_if_needed(field_name, field_type, model_env);
put_name_value_separator();
generate_from_model(field_model, field_type);
}
template<typename FieldValue>
void put_field_name_and_value_and_closing_name(const wchar_t * field_name, const FieldValue & field_value, void (Model::*getter_method)(pt::Stream &), const FT & field_type, ModelEnv * model_env)
{
put_field_name_and_table_if_needed(field_name, field_type, model_env);
put_name_value_separator();
put_field_value_or_null(field_value, getter_method, field_type, model_env);
put_name_value_separator();
put_field_closing_name(field_name, field_type, model_env);
}
template<typename ModelContainer, typename ModelContainerType, typename IsContainerByValueRenameMe>
void put_field_name_and_value_list_and_closing_name(const wchar_t * field_name, ModelContainer & field_value, ModelContainerType * model_container_type,
const FT & field_type, ModelConnector * model_connector, ModelEnv * model_env, IsContainerByValueRenameMe * foo)
{
put_field_name_and_table_if_needed(field_name, field_type, model_env);
put_name_value_separator();
put_field_value_list(field_value, model_container_type, field_type, model_connector, model_env, foo);
put_name_value_separator();
put_field_closing_name(field_name, field_type, model_env);
}
template<typename ModelClass>
void put_field_name_and_value_model_and_closing_name(const wchar_t * field_name, ModelClass & field_model, const FT & field_type, ModelEnv * model_env)
{
put_field_name_and_table_if_needed(field_name, field_type, model_env);
put_name_value_separator();
generate_from_model(field_model, field_type);
put_name_value_separator();
put_field_closing_name(field_name, field_type, model_env);
}
};
}

View File

@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_baseobjectwrapper
#define headerfile_morm_baseobjectwrapper
#ifndef headerfile_morm_src_baseobjectwrapper
#define headerfile_morm_src_baseobjectwrapper

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2022, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -50,105 +50,119 @@ Clearer::~Clearer()
}
void Clearer::clear_value(char & field_value)
void Clearer::clear_value(char & field_value, const FT & field_type)
{
field_value = 0;
}
void Clearer::clear_value(unsigned char & field_value)
void Clearer::clear_value(unsigned char & field_value, const FT & field_type)
{
field_value = 0;
}
void Clearer::clear_value(wchar_t & field_value)
void Clearer::clear_value(wchar_t & field_value, const FT & field_type)
{
field_value = 0;
}
void Clearer::clear_value(std::wstring & field_value)
void Clearer::clear_value(std::wstring & field_value, const FT & field_type)
{
field_value.clear();
if( field_type.is_numeric() )
{
field_value = L"0";
}
else
{
field_value.clear();
}
}
void Clearer::clear_value(std::string & field_value)
void Clearer::clear_value(std::string & field_value, const FT & field_type)
{
field_value.clear();
if( field_type.is_numeric() )
{
field_value = "0";
}
else
{
field_value.clear();
}
}
void Clearer::clear_value(bool & field_value)
void Clearer::clear_value(bool & field_value, const FT & field_type)
{
field_value = false;
}
void Clearer::clear_value(short & field_value)
void Clearer::clear_value(short & field_value, const FT & field_type)
{
field_value = 0;
}
void Clearer::clear_value(unsigned short & field_value)
void Clearer::clear_value(unsigned short & field_value, const FT & field_type)
{
field_value = 0;
}
void Clearer::clear_value(int & field_value)
void Clearer::clear_value(int & field_value, const FT & field_type)
{
field_value = 0;
}
void Clearer::clear_value(unsigned int & field_value)
void Clearer::clear_value(unsigned int & field_value, const FT & field_type)
{
field_value = 0;
}
void Clearer::clear_value(long & field_value)
void Clearer::clear_value(long & field_value, const FT & field_type)
{
field_value = 0;
}
void Clearer::clear_value(unsigned long & field_value)
void Clearer::clear_value(unsigned long & field_value, const FT & field_type)
{
field_value = 0;
}
void Clearer::clear_value(long long & field_value)
void Clearer::clear_value(long long & field_value, const FT & field_type)
{
field_value = 0;
}
void Clearer::clear_value(unsigned long long & field_value)
void Clearer::clear_value(unsigned long long & field_value, const FT & field_type)
{
field_value = 0;
}
void Clearer::clear_value(float & field_value)
void Clearer::clear_value(float & field_value, const FT & field_type)
{
field_value = 0.0f;
}
void Clearer::clear_value(double & field_value)
void Clearer::clear_value(double & field_value, const FT & field_type)
{
field_value = 0.0;
}
void Clearer::clear_value(long double & field_value)
void Clearer::clear_value(long double & field_value, const FT & field_type)
{
field_value = 0.0;
}
void Clearer::clear_value(pt::Date & field_value)
void Clearer::clear_value(pt::Date & field_value, const FT & field_type)
{
field_value.Clear();
}
void Clearer::clear_value(pt::Space & field_value)
void Clearer::clear_value(pt::Space & field_value, const FT & field_type)
{
field_value.clear();
}
void Clearer::clear_model(Model & field_value)
void Clearer::clear_model(Model & field_value, const FT & field_type)
{
field_value.clear();
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2022, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,12 +32,13 @@
*
*/
#ifndef headerfile_morm_clearer
#define headerfile_morm_clearer
#ifndef headerfile_morm_src_clearer
#define headerfile_morm_src_clearer
#include <string>
#include "date/date.h"
#include "space/space.h"
#include "ft.h"
namespace morm
@ -52,30 +53,30 @@ public:
Clearer();
virtual ~Clearer();
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);
virtual void clear_value(short & field_value);
virtual void clear_value(unsigned short & field_value);
virtual void clear_value(int & field_value);
virtual void clear_value(unsigned int & field_value);
virtual void clear_value(long & field_value);
virtual void clear_value(unsigned long & field_value);
virtual void clear_value(long long & field_value);
virtual void clear_value(unsigned long long & field_value);
virtual void clear_value(float & field_value);
virtual void clear_value(double & field_value);
virtual void clear_value(long double & field_value);
virtual void clear_value(pt::Date & field_value);
virtual void clear_value(pt::Space & field_value);
virtual void clear_value(char & field_value, const FT & field_type);
virtual void clear_value(unsigned char & field_value, const FT & field_type);
virtual void clear_value(wchar_t & field_value, const FT & field_type);
virtual void clear_value(std::wstring & field_value, const FT & field_type);
virtual void clear_value(std::string & field_value, const FT & field_type);
virtual void clear_value(bool & field_value, const FT & field_type);
virtual void clear_value(short & field_value, const FT & field_type);
virtual void clear_value(unsigned short & field_value, const FT & field_type);
virtual void clear_value(int & field_value, const FT & field_type);
virtual void clear_value(unsigned int & field_value, const FT & field_type);
virtual void clear_value(long & field_value, const FT & field_type);
virtual void clear_value(unsigned long & field_value, const FT & field_type);
virtual void clear_value(long long & field_value, const FT & field_type);
virtual void clear_value(unsigned long long & field_value, const FT & field_type);
virtual void clear_value(float & field_value, const FT & field_type);
virtual void clear_value(double & field_value, const FT & field_type);
virtual void clear_value(long double & field_value, const FT & field_type);
virtual void clear_value(pt::Date & field_value, const FT & field_type);
virtual void clear_value(pt::Space & field_value, const FT & field_type);
virtual void clear_model(Model & field_value);
virtual void clear_model(Model & field_value, const FT & field_type);
template<typename ModelContainer, typename ModelContainerType, typename IsContainerByValueRenameMe>
void clear_container(ModelContainer & container, ModelContainerType * model_container_type, IsContainerByValueRenameMe * foo)
void clear_container(ModelContainer & container, ModelContainerType * model_container_type, IsContainerByValueRenameMe * foo, const FT & field_type)
{
if constexpr (std::is_base_of<Model, ModelContainerType>())
{

81
src/csvconnector.cpp Normal file
View File

@ -0,0 +1,81 @@
/*
* This file is a part of morm
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2023, 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.
*
*/
#include "csvconnector.h"
#include "csvexpression.h"
namespace morm
{
CSVConnector::CSVConnector()
{
}
void CSVConnector::allocate_default_expression()
{
deallocate_expression();
flat_expression = new CSVExpression();
expression_allocated = true;
}
void CSVConnector::to_text(pt::TextStream & stream, Model & model, Export exp)
{
allocate_default_expression_if_needed();
if( flat_expression )
{
flat_expression->clear();
if( exp.is_export_headers() )
{
flat_expression->set_work_mode(MORM_WORK_MODE_MODEL_FIELDS);
flat_expression->set_output_type(MORM_OUTPUT_TYPE_FIELDS_RECURSIVE);
}
else
{
flat_expression->set_work_mode(MORM_WORK_MODE_MODEL_VALUES);
}
flat_expression->allow_to_use_prefix(false);
flat_expression->generate_from_model(stream, model);
}
}
}

63
src/csvconnector.h Normal file
View File

@ -0,0 +1,63 @@
/*
* This file is a part of morm
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2023, 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_src_csvconnector
#define headerfile_morm_src_csvconnector
#include "flatconnector.h"
namespace morm
{
class CSVConnector : public FlatConnector
{
public:
CSVConnector();
void to_text(pt::TextStream & stream, Model & model, Export exp);
protected:
void allocate_default_expression();
};
}
#endif

97
src/csvexpression.cpp Normal file
View File

@ -0,0 +1,97 @@
/*
* This file is a part of morm
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2023, 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.
*
*/
#include "csvexpression.h"
#include "morm_types.h"
#include "convert/misc.h"
namespace morm
{
bool CSVExpression::can_field_list_be_generated(const FT &)
{
return false;
}
void CSVExpression::field_before()
{
BaseExpression::field_before();
if( !is_first_field )
{
(*out_stream) << ",";
}
}
void CSVExpression::after_generate_from_model()
{
(*out_stream) << ",";
}
void CSVExpression::before_field_name()
{
(*out_stream) << '"';
}
void CSVExpression::after_field_name()
{
(*out_stream) << '"';
}
void CSVExpression::before_field_value_string(const FT & field_type, ModelEnv * model_env)
{
(*out_stream) << '"';
}
void CSVExpression::after_field_value_string(const FT & field_type, ModelEnv * model_env)
{
(*out_stream) << '"';
}
bool CSVExpression::esc_char(wchar_t val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
return pt::try_esc_to_csv(val, stream);
}
}

68
src/csvexpression.h Normal file
View File

@ -0,0 +1,68 @@
/*
* This file is a part of morm
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2023, 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_src_csvexpression
#define headerfile_morm_src_csvexpression
#include "flatexpression.h"
namespace morm
{
class CSVExpression : public FlatExpression
{
protected:
bool can_field_list_be_generated(const FT &);
void field_before();
void after_generate_from_model();
void before_field_name();
void after_field_name();
void before_field_value_string(const FT & field_type, ModelEnv * model_env);
void after_field_value_string(const FT & field_type, ModelEnv * model_env);
using BaseExpression::esc;
bool esc_char(wchar_t val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env);
};
}
#endif

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_cursor
#define headerfile_morm_cursor
#ifndef headerfile_morm_src_cursor
#define headerfile_morm_src_cursor
#include "queryresult.h"
#include "modelconnector.h"
@ -63,7 +63,11 @@ public:
has_autogenerated_select = c.has_autogenerated_select;
use_table_prefix_for_fetching = c.use_table_prefix_for_fetching;
query_result = c.query_result;
select_status = c.select_status;
last_query_status = c.last_query_status;
select_flags = c.select_flags;
rows_counter = c.rows_counter;
cursor_name = c.cursor_name;
scroll_cursor = c.scroll_cursor;
if( query_result )
{
@ -105,7 +109,11 @@ public:
cursor_helper.clear();
finder_helper.clear();
query_result = nullptr;
select_status = false;
last_query_status = false;
select_flags = Select::default_type;
rows_counter = 0;
cursor_name.clear();
scroll_cursor = false;
}
@ -127,9 +135,9 @@ public:
}
virtual void set_select_status(bool select_status)
virtual void set_last_query_status(bool status)
{
this->select_status = select_status;
this->last_query_status = status;
}
@ -145,6 +153,18 @@ public:
}
virtual void set_select_flags(const Select & select_flags)
{
this->select_flags = select_flags;
}
virtual void set_rows_counter_column_name(const std::wstring & column_name)
{
this->rows_counter_column_name = column_name;
}
virtual QueryResult * get_query_result()
{
return query_result;
@ -155,7 +175,7 @@ public:
{
bool has = false;
if( model_connector && query_result && query_result->has_db_result() && select_status )
if( model_connector && query_result && query_result->has_db_result() && last_query_status )
{
has = query_result->cur_row < query_result->result_rows;
}
@ -164,6 +184,24 @@ public:
}
virtual void prepare_model_env_for_new_object(ModelEnv & model_env)
{
model_env.cursor_helper = &cursor_helper;
model_env.finder_helper = &finder_helper;
model_env.select_flags = select_flags;
model_env.rows_counter = 0;
model_env.model_data = model_data;
if( model_env.select_flags.is_with_rows_counter() )
{
if( cursor_helper.current_row == 0 )
{
model_env.rows_counter_column_name = rows_counter_column_name;
}
}
}
virtual bool get(ModelClass & result)
{
bool res = false;
@ -177,34 +215,37 @@ public:
if( db_connector )
{
ModelEnv model_env_local;
result.model_env = &model_env_local;
result.model_env->cursor_helper = &cursor_helper;
result.model_env->finder_helper = &finder_helper;
result.model_env->model = &result;
try
{
ModelEnv model_env_local;
result.model_env = &model_env_local;
result.model_env->model = &result;
result.model_env->model_data = model_data;
finder_helper.clear(); // at the moment used only for calculating table prefixes (indices)
cursor_helper.clear();
cursor_helper.query_result = query_result;
cursor_helper.has_autogenerated_select = has_autogenerated_select;
cursor_helper.use_table_prefix_for_fetching_values = use_table_prefix_for_fetching;
result.model_env->model_data = model_data;
cursor_helper.current_row = 0;
prepare_model_env_for_new_object(model_env_local);
if( !cursor_helper.has_autogenerated_select && cursor_helper.use_table_prefix_for_fetching_values )
{
result.table();
result.model_env->add_table_name_to_finder_helper();
}
result.before_select();
res = select_status;
res = last_query_status;
if( res )
{
if( query_result->cur_row < query_result->result_rows )
{
result.map_values_from_query();
rows_counter = model_env_local.rows_counter;
if( result.found() )
{
@ -273,6 +314,7 @@ public:
return get_list_generic(result, clear_list);
}
virtual std::vector<ModelClass> get_vector()
{
std::vector<ModelClass> result;
@ -282,6 +324,142 @@ public:
}
virtual size_t get_rows_counter()
{
return rows_counter;
}
virtual void set_cursor_name(pt::TextStream & cursor_name)
{
this->cursor_name = cursor_name;
}
virtual void set_scroll_cursor(bool scroll_cursor)
{
this->scroll_cursor = scroll_cursor;
}
virtual Cursor & fetch(const char * fetch_str)
{
last_query_status = false;
rows_counter = 0;
if( query_result )
{
query_result->clear();
if( model_connector )
{
DbConnector * db_connector = model_connector->get_db_connector();
if( db_connector )
{
bool status = db_connector->query_select(fetch_str, *query_result);
last_query_status = status;
}
}
}
return *this;
}
virtual Cursor & fetch(pt::TextStream & str)
{
if( str.size() < 256 )
{
char str_buf[256];
if( str.to_str(str_buf, sizeof(str_buf) / sizeof(char)) )
{
fetch(str_buf);
}
}
else
{
put_cursor_fetch_query_too_long();
}
return *this;
}
virtual Cursor & fetch(pt::WTextStream & str)
{
if( str.size() < 256 )
{
char str_buf[256];
if( str.to_str(str_buf, sizeof(str_buf) / sizeof(char)) )
{
fetch(str_buf);
}
}
else
{
put_cursor_fetch_query_too_long();
}
return *this;
}
virtual Cursor & fetch_next()
{
return fetch(&DbExpression::prepare_fetch_next_query);
}
virtual Cursor & fetch_prior()
{
return fetch(&DbExpression::prepare_fetch_prior_query);
}
virtual Cursor & fetch_first()
{
return fetch(&DbExpression::prepare_fetch_first_query);
}
virtual Cursor & fetch_last()
{
return fetch(&DbExpression::prepare_fetch_last_query);
}
virtual Cursor & fetch_absolute(long position)
{
return fetch(&DbExpression::prepare_fetch_absotule_query, position);
}
virtual Cursor & fetch_relative(long position)
{
return fetch(&DbExpression::prepare_fetch_relative_query, position);
}
virtual Cursor & fetch_forward_count(size_t len)
{
return fetch(&DbExpression::prepare_fetch_forward_count_query, len);
}
virtual Cursor & fetch_backward_count(size_t len)
{
return fetch(&DbExpression::prepare_fetch_backward_count_query, len);
}
virtual Cursor & fetch_all()
{
return fetch(&DbExpression::prepare_fetch_all_query);
}
protected:
@ -292,8 +470,98 @@ protected:
CursorHelper cursor_helper;
FinderHelper finder_helper; // may CursorHelper and FinderHelper should be one class?
QueryResult * query_result;
bool select_status;
bool last_query_status;
Select select_flags;
size_t rows_counter;
std::wstring rows_counter_column_name;
pt::TextStream cursor_name;
bool scroll_cursor;
typedef void (DbExpression::*prepare_fetch_method_type)(const pt::TextStream & cursor_name, pt::TextStream & out_stream);
typedef void (DbExpression::*prepare_fetch_long_count_method_type)(const pt::TextStream & cursor_name, long count, pt::TextStream & out_stream);
typedef void (DbExpression::*prepare_fetch_size_count_method_type)(const pt::TextStream & cursor_name, size_t count, pt::TextStream & out_stream);
DbExpression * get_db_expression()
{
if( model_connector )
{
DbConnector * db_connector = model_connector->get_db_connector();
if( db_connector )
{
return db_connector->get_expression();
}
}
return nullptr;
}
virtual Cursor & fetch(prepare_fetch_method_type prepare_fetch_method)
{
if( !cursor_name.empty() )
{
DbExpression * db_expression = get_db_expression();
if( db_expression )
{
pt::TextStream str;
(db_expression->*prepare_fetch_method)(cursor_name, str);
fetch(str);
}
}
else
{
put_cursor_not_declared_log();
}
return *this;
}
virtual Cursor & fetch(prepare_fetch_long_count_method_type prepare_fetch_method, long count)
{
if( !cursor_name.empty() )
{
DbExpression * db_expression = get_db_expression();
if( db_expression )
{
pt::TextStream str;
(db_expression->*prepare_fetch_method)(cursor_name, count, str);
fetch(str);
}
}
else
{
put_cursor_not_declared_log();
}
return *this;
}
virtual Cursor & fetch(prepare_fetch_size_count_method_type prepare_fetch_method, size_t count)
{
if( !cursor_name.empty() )
{
DbExpression * db_expression = get_db_expression();
if( db_expression )
{
pt::TextStream str;
(db_expression->*prepare_fetch_method)(cursor_name, count, str);
fetch(str);
}
}
else
{
put_cursor_not_declared_log();
}
return *this;
}
template<typename ContainerType>
@ -312,7 +580,7 @@ protected:
if( db_connector )
{
res = select_status;
res = last_query_status;
try
{
@ -359,24 +627,30 @@ protected:
cursor_helper.query_result = query_result;
cursor_helper.has_autogenerated_select = has_autogenerated_select;
cursor_helper.use_table_prefix_for_fetching_values = use_table_prefix_for_fetching;
cursor_helper.current_row = query_result->cur_row;
added_model.set_connector(model_connector);
added_model.clear();
prepare_model_env_for_new_object(model_env_local);
added_model.model_env = &model_env_local;
added_model.model_env->cursor_helper = &cursor_helper;
added_model.model_env->finder_helper = &finder_helper;
added_model.model_env->model_data = model_data;
added_model.model_env->model = &added_model;
added_model.model_env->model_data = model_data;
if( !cursor_helper.has_autogenerated_select && cursor_helper.use_table_prefix_for_fetching_values )
{
added_model.table();
added_model.model_env->add_table_name_to_finder_helper();
}
added_model.before_select();
added_model.map_values_from_query();
if( model_env_local.select_flags.is_with_rows_counter() && query_result->cur_row == 0 )
{
rows_counter = model_env_local.rows_counter;
}
if( added_model.found() )
{
added_model.after_select();
@ -395,6 +669,38 @@ protected:
}
pt::Log * get_logger()
{
if( model_connector )
{
return model_connector->get_logger();
}
return nullptr;
}
void put_log(pt::Log::Manipulators level, const char * msg)
{
pt::Log * plog = get_logger();
if( plog )
{
(*plog) << level << msg << pt::Log::logend;
}
}
void put_cursor_fetch_query_too_long()
{
put_log(pt::Log::log2, "Morm: error: a fetch query should be less than 256 characters long");
}
void put_cursor_not_declared_log()
{
put_log(pt::Log::log2, "Morm: you cannot use fetch* methods, a cursor has not been declared, use Finder::declare_cursor(...) to declare a cursor");
}
};

View File

@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_cursorhelper
#define headerfile_morm_cursorhelper
#ifndef headerfile_morm_src_cursorhelper
#define headerfile_morm_src_cursorhelper
#include "queryresult.h"
@ -48,6 +48,7 @@ public:
bool has_autogenerated_select;
QueryResult * query_result;
int current_column;
size_t current_row;
// used if has_autogenerated_select is equal false
// if use_table_prefix_for_fetching_values is true we find a column in such a form: table.column_name instead of just column_name
@ -71,6 +72,7 @@ public:
has_autogenerated_select = false;
query_result = nullptr;
current_column = 0;
current_row = 0;
use_table_prefix_for_fetching_values = false;
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -51,16 +51,10 @@ DbConnector::DbConnector()
expression_allocated = false;
log = nullptr;
log_queries = false;
transaction_index = 0;
transaction_group = 0;
}
DbConnector::DbConnector(const DbConnector &)
{
db_expression = nullptr;
expression_allocated = false;
log = nullptr;
}
DbConnector::~DbConnector()
{
deallocate_expression();
@ -150,6 +144,11 @@ bool DbConnector::query_remove(const char * query_str, QueryResult & query_resul
return query(query_str, query_result);
}
bool DbConnector::query_declare_cursor(const char * query_str, QueryResult & query_result)
{
return query(query_str, query_result);
}
bool DbConnector::query_select(const pt::TextStream & stream, QueryResult & query_result)
@ -172,6 +171,221 @@ bool DbConnector::query_remove(const pt::TextStream & stream, QueryResult & quer
return query(stream, query_result);
}
bool DbConnector::query_declare_cursor(const pt::TextStream & stream, QueryResult & query_result)
{
return query(stream, query_result);
}
bool DbConnector::begin()
{
bool status = false;
if( transaction_index > 0 )
{
pt::TextStream str;
str << "SAVEPOINT savepoint_" << transaction_index;
status = DbConnector::query(str);
}
else
{
status = DbConnector::query("BEGIN");
}
if( status )
{
transaction_index += 1;
}
else
{
if( log )
{
(*log) << pt::Log::log1 << "Morm: I cannot start a transaction" << pt::Log::logend;
}
}
return status;
}
bool DbConnector::begin_if_needed()
{
bool status = true;
if( transaction_index == 0 )
{
status = begin();
}
return status;
}
bool DbConnector::rollback()
{
return rollback(transaction_index);
}
bool DbConnector::commit()
{
return commit(transaction_index);
}
bool DbConnector::rollback_one_transaction(size_t index)
{
bool status = false;
if( index > 1 )
{
pt::TextStream str;
str << "ROLLBACK TO SAVEPOINT savepoint_" << (index - 1);
status = DbConnector::query(str);
transaction_index = index - 1; // decrement it even if rollback failed
}
else
if( index == 1 )
{
status = DbConnector::query("ROLLBACK");
transaction_index = 0;
transaction_group += 1;
}
return status;
}
bool DbConnector::rollback(size_t index)
{
bool status = false;
if( index == 0 )
{
if( log )
{
(*log) << pt::Log::log1 << "Morm: there is no a transaction with zero index - skipping rollback";
}
}
else
if( index > transaction_index )
{
if( log )
{
(*log) << pt::Log::log1 << "Morm: transaction";
if( index > 1 )
(*log) << " for savepoint_" << (index-1);
(*log) << " does not exist - skipping rollback" << pt::Log::logend;
}
}
else
{
status = true;
for(size_t i = transaction_index ; i >= index ; --i)
{
if( !rollback_one_transaction(i) )
{
/*
* return false if at least one rollback failed
*/
status = false;
}
}
}
return status;
}
bool DbConnector::commit_one_transaction(size_t index)
{
bool status = false;
if( index > 1 )
{
pt::TextStream str;
str << "RELEASE SAVEPOINT savepoint_" << (index - 1);
status = DbConnector::query(str);
transaction_index = index - 1;
}
else
if( index == 1 )
{
status = DbConnector::query("COMMIT");
transaction_index = 0;
transaction_group += 1;
}
return status;
}
bool DbConnector::commit(size_t index)
{
bool status = false;
if( index == 0 )
{
if( log )
{
(*log) << pt::Log::log1 << "Morm: there is no a transaction with zero index - skipping commit";
}
}
else
if( index > transaction_index )
{
if( log )
{
(*log) << pt::Log::log1 << "Morm: transaction";
if( index > 1 )
(*log) << " for savepoint_" << (index-1);
(*log) << " does not exist - skipping commit" << pt::Log::logend;
}
}
else
{
status = true;
for(size_t i = transaction_index ; i >= index ; --i)
{
if( !commit_one_transaction(i) )
{
/*
* return false if at least one commit failed
*/
status = false;
}
}
}
return status;
}
size_t DbConnector::get_transaction_index()
{
return transaction_index;
}
size_t DbConnector::get_transaction_group()
{
return transaction_group;
}
DbExpression * DbConnector::get_expression()
@ -205,7 +419,7 @@ void DbConnector::generate_insert_query(pt::TextStream & stream, Model & model)
db_expression->clear();
db_expression->allow_to_use_prefix(false);
stream << "insert into ";
stream << "INSERT INTO ";
db_expression->schema_table_to_stream(stream, model.model_env->schema_name, model.model_env->table_name);
stream << " (";
@ -213,7 +427,7 @@ void DbConnector::generate_insert_query(pt::TextStream & stream, Model & model)
db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_INSERT);
db_expression->generate_from_model(stream, model);
stream << ") values (";
stream << ") VALUES (";
db_expression->set_work_mode(MORM_WORK_MODE_MODEL_VALUES);
db_expression->generate_from_model(stream, model);
stream << ")";
@ -230,15 +444,15 @@ void DbConnector::generate_update_query(pt::TextStream & stream, Model & model)
db_expression->clear();
db_expression->allow_to_use_prefix(false);
stream << "update ";
stream << "UPDATE ";
db_expression->schema_table_to_stream(stream, model.model_env->schema_name, model.model_env->table_name);
stream << " set ";
stream << " SET ";
db_expression->set_work_mode(MORM_WORK_MODE_MODEL_FIELDS_VALUES);
db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_UPDATE);
db_expression->generate_from_model(stream, model);
stream << " where ";
stream << " WHERE ";
db_expression->set_work_mode(MORM_WORK_MODE_MODEL_FIELDS_VALUES);
db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_PRIMARY_KEY);
db_expression->generate_from_model(stream, model);
@ -255,16 +469,17 @@ void DbConnector::generate_remove_query(pt::TextStream & stream, Model & model)
db_expression->clear();
db_expression->allow_to_use_prefix(false);
stream << "delete from ";
stream << "DELETE FROM ";
db_expression->schema_table_to_stream(stream, model.model_env->schema_name, model.model_env->table_name);
stream << " where ";
stream << " WHERE ";
db_expression->set_work_mode(MORM_WORK_MODE_MODEL_FIELDS_VALUES);
db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_PRIMARY_KEY);
db_expression->generate_from_model(stream, model);
}
}
bool DbConnector::insert(pt::TextStream & stream, Model & model)
{
std::unique_ptr<QueryResult> query_result_ptr(create_query_result());
@ -313,7 +528,7 @@ void DbConnector::allocate_default_expression_if_needed()
}
char DbConnector::unescape_hex_char_part(char hex)
unsigned int DbConnector::unescape_hex_char_part(char hex)
{
if( hex>='0' && hex<='9' )
{
@ -348,43 +563,79 @@ char DbConnector::unescape_hex_char_part(char hex)
}
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<char>(((c1 << 4) | c2));
const char * DbConnector::unescape_hex_char(const char * str, size_t len, unsigned int & res)
{
unsigned int c;
res = 0;
for(size_t i = 0 ; i < len ; ++i)
{
if( *str != 0 )
{
c = unescape_hex_char_part(*str);
str += 1;
}
else
{
c = 0;
}
res = (res << 4) | c;
}
return str;
}
void DbConnector::unescape_hex_char(const char * str, char & c)
{
unsigned int res = 0;
unescape_hex_char(str, sizeof(char) * 2, res);
c = (char)res;
}
void DbConnector::unescape_hex_char(const char * str, wchar_t & c)
{
unsigned int res = 0;
unescape_hex_char(str, sizeof(wchar_t) * 2, res);
c = (wchar_t)res;
}
void DbConnector::unescape_bin_char(const char * str, char & c)
{
unescape_hex_char(str, c);
}
void DbConnector::unescape_bin_char(const char * str, wchar_t & c)
{
unescape_hex_char(str, c);
}
void DbConnector::unescape_hex_string(const char * str, std::string & out)
{
for(size_t i=0 ; str[i] != 0 ; i+=2 )
unsigned int c = 0;
while( *str != 0 )
{
out += unescape_hex_char(str[i], str[i+1]);
str = unescape_hex_char(str, sizeof(char) * 2, c);
out += (char)c;
}
}
void DbConnector::unescape_hex_string(const char * str, std::wstring & out, const FT & field_type)
void DbConnector::unescape_hex_string(const char * str, std::wstring & out)
{
if( field_type.use_utf8() )
{
size_t len;
wchar_t c;
unsigned int c = 0;
while( *str != 0 && (len = unescape_hex_char(str, c, field_type)) > 0 )
{
out += c;
str += len;
}
}
else
while( *str != 0 )
{
for(size_t i=0 ; str[i] != 0 ; i+=2 )
{
out += static_cast<wchar_t>(static_cast<unsigned char>(unescape_hex_char(str[i], str[i+1])));
}
str = unescape_hex_char(str, sizeof(wchar_t) * 2, c);
out += (wchar_t)c;
}
}
@ -395,151 +646,53 @@ void DbConnector::unescape_bin_string(const char * str, std::string & out)
}
void DbConnector::unescape_bin_string(const char * str, std::wstring & out, const FT & field_type)
void DbConnector::unescape_bin_string(const char * str, std::wstring & out)
{
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<wchar_t>(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<wchar_t>(static_cast<unsigned char>(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);
unescape_hex_string(str, out);
}
// 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( field_type.is_hexadecimal() )
{
if( c <= 127 )
{
field_value = static_cast<char>(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;
}
}
unescape_hex_char(value_str, field_value);
}
else
if( field_type.is_binary() )
{
unescape_bin_char(value_str, field_value);
}
else
{
field_value = static_cast<char>(c);
field_value = *value_str;
}
}
// CHECKME need to be tested
void DbConnector::get_value(const char * value_str, unsigned char & field_value, const FT & field_type)
{
char tmp_char;
get_value(value_str, tmp_char, field_type);
field_value = static_cast<unsigned char>(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() )
{
unescape_bin_char(value_str, field_value, field_type);
}
else
if( field_type.is_hexadecimal() )
{
unescape_hex_char(value_str, field_value, field_type);
unescape_hex_char(value_str, field_value);
}
else
if( field_type.is_binary() )
{
unescape_bin_char(value_str, field_value);
}
else
{
@ -556,7 +709,7 @@ void DbConnector::get_value(const char * value_str, wchar_t & field_value, const
}
else
{
// report an error?
field_value = 0xFFFD; // U+FFFD "replacement character";
}
}
else
@ -568,48 +721,18 @@ void DbConnector::get_value(const char * value_str, wchar_t & field_value, const
// CHECKME need to be tested
void DbConnector::get_value(const char * value_str, std::wstring & field_value, const FT & field_type)
{
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<wchar_t>(value_str[i]);
}
}
}
}
// CHECKME need to be tested
void DbConnector::get_value(const char * value_str, std::string & field_value, const FT & field_type)
{
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
if( field_type.is_binary() )
{
unescape_bin_string(value_str, field_value);
}
else
{
field_value = value_str;
}
@ -622,6 +745,34 @@ void DbConnector::get_value(const char * value_str, std::string_view & field_val
}
void DbConnector::get_value(const char * value_str, std::wstring & field_value, const FT & field_type)
{
if( field_type.is_hexadecimal() )
{
unescape_hex_string(value_str, field_value);
}
else
if( field_type.is_binary() )
{
unescape_bin_string(value_str, field_value);
}
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<wchar_t>((unsigned char)value_str[i]);
}
}
}
}
void DbConnector::get_value(const char * value_str, bool & field_value, const FT & field_type)
{
// IMPROVE ME
@ -633,56 +784,56 @@ void DbConnector::get_value(const char * value_str, bool & field_value, const FT
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::to_i(value_str, 10);
}
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::to_ui(value_str, 10);
}
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::to_i(value_str, 10);
}
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::to_ui(value_str, 10);
}
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::to_l(value_str, 10);
}
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::to_ul(value_str, 10);
}
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::to_ll(value_str, 10);
}
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::to_ull(value_str, 10);
}
@ -710,7 +861,20 @@ void DbConnector::get_value(const char * value_str, long double & field_value, c
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);
if( field_type.is_date_only() )
{
field_value.ParseYearMonthDay(value_str);
}
else
if( field_type.is_time_only() )
{
field_value.ParseHourMinSec(value_str);
}
else
{
field_value.Parse(value_str, !field_type.is_no_time_zone());
}
}
@ -757,4 +921,6 @@ const char * DbConnector::query_last_sequence(const wchar_t * sequence_table_nam
return nullptr;
}
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_dbconnector
#define headerfile_morm_dbconnector
#ifndef headerfile_morm_src_dbconnector
#define headerfile_morm_src_dbconnector
#include "textstream/textstream.h"
#include "log/log.h"
@ -52,7 +52,8 @@ class DbConnector
public:
DbConnector();
DbConnector(const DbConnector &);
DbConnector(const DbConnector &) = delete;
DbConnector(DbConnector &&) = delete;
virtual ~DbConnector();
virtual void set_logger(pt::Log * log);
@ -85,32 +86,76 @@ public:
virtual bool query_update(const char * query_str, QueryResult & query_result);
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_declare_cursor(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_declare_cursor(const pt::TextStream & stream, QueryResult & query_result);
/*
* create a new transaction
* first transaction has index equal to one
*/
virtual bool begin();
/*
* create a new transaction if there is no a transaction started yet
*/
virtual bool begin_if_needed();
/*
* rollback or commit the last transaction
*/
virtual bool rollback();
virtual bool commit();
/*
* rollback or commit all transactions from the last one to the index
* (first transaction has index one, there is no a transaction with index zero)
*
*/
virtual bool rollback(size_t index);
virtual bool commit(size_t index);
/*
* return current transaction index (within a group)
* first transaction has index equal to one
* returns zero if there are no any transactions
*/
virtual size_t get_transaction_index();
/*
* return current transaction group index
* a group index is incremented when you commit or rollback a transaction
* (if you are closing a nested transaction then the group index is not incremented)
*
*/
virtual size_t get_transaction_group();
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, 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, std::string_view & 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, 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 & 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, 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);
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
@ -141,6 +186,8 @@ protected:
bool expression_allocated;
pt::Log * log;
bool log_queries;
size_t transaction_index;
size_t transaction_group;
virtual void allocate_default_expression() = 0;
@ -149,22 +196,25 @@ protected:
virtual const char * query_last_sequence(const wchar_t * sequence_table_name);
virtual void unescape_hex_char(const char * str, char & c);
virtual void unescape_hex_char(const char * str, wchar_t & c);
virtual void unescape_bin_char(const char * str, char & c);
virtual void unescape_bin_char(const char * str, wchar_t & c);
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_hex_string(const char * str, std::wstring & out);
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 void unescape_bin_string(const char * str, std::wstring & out);
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);
virtual bool rollback_one_transaction(size_t index);
virtual bool commit_one_transaction(size_t index);
private:
char unescape_hex_char_part(char hex);
char unescape_hex_char(char char1, char char2);
unsigned int unescape_hex_char_part(char hex);
const char * unescape_hex_char(const char * str, size_t len, unsigned int & res);

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -33,6 +33,7 @@
*/
#include "dbexpression.h"
#include "model.h"
namespace morm
@ -41,7 +42,6 @@ namespace morm
DbExpression::DbExpression()
{
output_type = 0;
}
@ -50,18 +50,6 @@ DbExpression::~DbExpression()
}
void DbExpression::set_output_type(int output_type)
{
this->output_type = output_type;
}
int DbExpression::get_output_type()
{
return output_type;
}
bool DbExpression::can_field_be_generated(const FT & field_type)
{
if( output_type == MORM_OUTPUT_TYPE_DB_INSERT )
@ -76,7 +64,8 @@ bool DbExpression::can_field_be_generated(const FT & field_type)
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 )
output_type == MORM_OUTPUT_TYPE_DB_INSERT_PRIMARY_KEY ||
output_type == MORM_OUTPUT_TYPE_DB_UPDATE_PRIMARY_KEY )
{
return field_type.is_primary_key();
}
@ -106,7 +95,8 @@ void DbExpression::field_before()
(*out_stream) << " AND ";
}
else
if( output_type == MORM_OUTPUT_TYPE_DB_INSERT_PRIMARY_KEY )
if( output_type == MORM_OUTPUT_TYPE_DB_INSERT_PRIMARY_KEY ||
output_type == MORM_OUTPUT_TYPE_DB_UPDATE_PRIMARY_KEY )
{
(*out_stream) << ", ";
}
@ -117,7 +107,11 @@ void DbExpression::field_before()
output_type == MORM_OUTPUT_TYPE_WHERE_LE ||
output_type == MORM_OUTPUT_TYPE_WHERE_LT ||
output_type == MORM_OUTPUT_TYPE_WHERE_NOT_EQ ||
output_type == MORM_OUTPUT_TYPE_WHERE_IN )
output_type == MORM_OUTPUT_TYPE_WHERE_IN ||
output_type == MORM_OUTPUT_TYPE_WHERE_LIKE ||
output_type == MORM_OUTPUT_TYPE_WHERE_ILIKE ||
output_type == MORM_OUTPUT_TYPE_WHERE_IS_NULL ||
output_type == MORM_OUTPUT_TYPE_WHERE_IS_NOT_NULL )
{
int conjunction = MORM_CONJUNCTION_AND;
@ -177,7 +171,27 @@ void DbExpression::put_name_value_separator()
else
if( output_type == MORM_OUTPUT_TYPE_WHERE_IN )
{
(*out_stream) << " in ";
(*out_stream) << " IN ";
}
else
if( output_type == MORM_OUTPUT_TYPE_WHERE_LIKE )
{
(*out_stream) << " LIKE ";
}
else
if( output_type == MORM_OUTPUT_TYPE_WHERE_ILIKE )
{
(*out_stream) << " ILIKE ";
}
else
if( output_type == MORM_OUTPUT_TYPE_WHERE_IS_NULL )
{
(*out_stream) << " IS NULL ";
}
else
if( output_type == MORM_OUTPUT_TYPE_WHERE_IS_NOT_NULL )
{
(*out_stream) << " IS NOT NULL ";
}
}
@ -194,6 +208,12 @@ void DbExpression::table_field_separator()
}
void DbExpression::alias_names_separator()
{
(*out_stream) << '.';
}
void DbExpression::before_schema_name()
{
(*out_stream) << '"';
@ -230,15 +250,34 @@ void DbExpression::after_field_name()
}
void DbExpression::before_field_value_string(const FT & field_type)
void DbExpression::before_alias_name()
{
(*out_stream) << "'";
(*out_stream) << '"';
}
void DbExpression::after_field_value_string(const FT & field_type)
void DbExpression::after_alias_name()
{
(*out_stream) << '"';
}
void DbExpression::before_field_value_string(const FT & field_type, ModelEnv * model_env)
{
(*out_stream) << "'";
if( model_env && model_env->use_escaping_for_like && model_env->add_prefix_percent )
(*out_stream) << '%';
}
void DbExpression::after_field_value_string(const FT & field_type, ModelEnv * model_env)
{
if( model_env && model_env->use_escaping_for_like && model_env->add_postfix_percent )
(*out_stream) << '%';
(*out_stream) << "'";
}
@ -293,11 +332,134 @@ DbExpression & DbExpression::group_end(pt::TextStream & stream)
DbExpression & DbExpression::page(pt::TextStream & stream, size_t page_number, size_t page_size)
{
stream << " limit " << page_number << "," << page_size << " ";
stream << " LIMIT " << (page_number*page_size) << "," << page_size << " ";
return *this;
}
void DbExpression::generate_rows_counter_column_name(ModelEnv & model_env, pt::TextStream & str)
{
str << model_env.table_name;
if( model_env.table_index > 1 )
{
str << model_env.table_index;
}
str << DbExpression::COLUMN_ROWS_COUNTER_POSTFIX;
}
void DbExpression::add_additional_columns(Model & model)
{
if( model.model_env )
{
if( model.model_env->select_flags.is_with_rows_counter() )
{
add_rows_counter_column(model);
}
}
}
void DbExpression::add_rows_counter_column(Model & model)
{
if( out_stream && model.model_env )
{
field_before();
(*out_stream) << "COUNT(*) OVER() AS ";
before_field_name();
if( model.model_env->rows_counter_column_name.empty() )
{
pt::TextStream str;
generate_rows_counter_column_name(*model.model_env, str);
esc(str, *out_stream);
/*
* for autogenerated selects we don't have to copy the rows_counter_column_name
* because a field() method will use an index instead of this name
*/
if( !model.model_env->has_autogenerated_select )
{
str.to_str(model.model_env->rows_counter_column_name);
}
}
else
{
esc(model.model_env->rows_counter_column_name, *out_stream);
}
after_field_name();
field_after();
}
}
void DbExpression::prepare_declare_cursor_query(const pt::TextStream & cursor_name, bool scroll_cursor, pt::TextStream & out_stream)
{
out_stream << "DECLARE " << cursor_name;
if( scroll_cursor )
out_stream << " SCROLL";
out_stream << " CURSOR FOR ";
}
void DbExpression::prepare_fetch_next_query(const pt::TextStream & cursor_name, pt::TextStream & out_stream)
{
out_stream << "FETCH NEXT FROM " << cursor_name;
}
void DbExpression::prepare_fetch_prior_query(const pt::TextStream & cursor_name, pt::TextStream & out_stream)
{
out_stream << "FETCH PRIOR FROM " << cursor_name;
}
void DbExpression::prepare_fetch_first_query(const pt::TextStream & cursor_name, pt::TextStream & out_stream)
{
out_stream << "FETCH FIRST FROM " << cursor_name;
}
void DbExpression::prepare_fetch_last_query(const pt::TextStream & cursor_name, pt::TextStream & out_stream)
{
out_stream << "FETCH LAST FROM " << cursor_name;
}
void DbExpression::prepare_fetch_absotule_query(const pt::TextStream & cursor_name, long position, pt::TextStream & out_stream)
{
out_stream << "FETCH ABSOLUTE " << position << " FROM " << cursor_name;
}
void DbExpression::prepare_fetch_relative_query(const pt::TextStream & cursor_name, long position, pt::TextStream & out_stream)
{
out_stream << "FETCH RELATIVE " << position << " FROM " << cursor_name;
}
void DbExpression::prepare_fetch_forward_count_query(const pt::TextStream & cursor_name, size_t len, pt::TextStream & out_stream)
{
out_stream << "FETCH FORWARD " << len << " FROM " << cursor_name;
}
void DbExpression::prepare_fetch_backward_count_query(const pt::TextStream & cursor_name, size_t len, pt::TextStream & out_stream)
{
out_stream << "FETCH BACKWARD " << len << " FROM " << cursor_name;
}
void DbExpression::prepare_fetch_all_query(const pt::TextStream & cursor_name, pt::TextStream & out_stream)
{
out_stream << "FETCH ALL FROM " << cursor_name;
}
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_dbexpression
#define headerfile_morm_dbexpression
#ifndef headerfile_morm_src_dbexpression
#define headerfile_morm_src_dbexpression
#include <vector>
#include "baseexpression.h"
@ -50,9 +50,8 @@ public:
DbExpression();
virtual ~DbExpression();
virtual void set_output_type(int output_type);
virtual int get_output_type();
constexpr static const char * COLUMN_ROWS_COUNTER_POSTFIX = "_autoadded_rows_counter";
virtual void prepare_to_where_clause();
@ -60,6 +59,9 @@ public:
virtual DbExpression & group_and(pt::TextStream & stream);
virtual DbExpression & group_end(pt::TextStream & stream);
/*
* page_number starts from zero (it's a number of a page, not an offset)
*/
virtual DbExpression & page(pt::TextStream & stream, size_t page_number, size_t page_size);
template<typename FieldValue>
@ -68,17 +70,29 @@ public:
std::wstring column_expression; // field() methods can be called recursively, so don't make it as class object
column_expression = new_column_expression;
column_expression += L" as ";
column_expression += L" AS ";
column_expression += new_column_name;
field(column_expression.c_str(), field_value, field_type, model_env);
}
virtual void generate_rows_counter_column_name(ModelEnv & model_env, pt::TextStream & str);
virtual void prepare_declare_cursor_query(const pt::TextStream & cursor_name, bool scroll_cursor, pt::TextStream & out_stream);
virtual void prepare_fetch_next_query(const pt::TextStream & cursor_name, pt::TextStream & out_stream);
virtual void prepare_fetch_prior_query(const pt::TextStream & cursor_name, pt::TextStream & out_stream);
virtual void prepare_fetch_first_query(const pt::TextStream & cursor_name, pt::TextStream & out_stream);
virtual void prepare_fetch_last_query(const pt::TextStream & cursor_name, pt::TextStream & out_stream);
virtual void prepare_fetch_absotule_query(const pt::TextStream & cursor_name, long position, pt::TextStream & out_stream);
virtual void prepare_fetch_relative_query(const pt::TextStream & cursor_name, long position, pt::TextStream & out_stream);
virtual void prepare_fetch_forward_count_query(const pt::TextStream & cursor_name, size_t len, pt::TextStream & out_stream);
virtual void prepare_fetch_backward_count_query(const pt::TextStream & cursor_name, size_t len, pt::TextStream & out_stream);
virtual void prepare_fetch_all_query(const pt::TextStream & cursor_name, pt::TextStream & out_stream);
protected:
int output_type;
std::vector<int> conjunctions;
bool can_field_be_generated(const FT & field_type);
@ -87,6 +101,7 @@ protected:
void schema_table_separator();
void table_field_separator();
void alias_names_separator();
void before_schema_name();
void after_schema_name();
@ -97,12 +112,15 @@ protected:
void before_field_name();
void after_field_name();
void before_alias_name();
void after_alias_name();
private:
void add_additional_columns(Model & model);
void before_field_value_string(const FT & field_type);
void after_field_value_string(const FT & field_type);
void before_field_value_string(const FT & field_type, ModelEnv * model_env);
void after_field_value_string(const FT & field_type, ModelEnv * model_env);
virtual void add_rows_counter_column(Model & model);
};

128
src/export.h Normal file
View File

@ -0,0 +1,128 @@
/*
* This file is a part of morm
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2023, 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 SOFTWAExportType, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef headerfile_morm_src_export
#define headerfile_morm_src_export
namespace morm
{
/*
* field types
*/
class Export
{
public:
enum ExportType
{
default_type = 0,
no_clear_stream = 1,
dump_mode = 2,
export_headers = 4,
};
/*
* type can be a superposition from ExportType values
*/
int type;
Export()
{
type = 0;
}
Export(const Export & field_type)
{
type = field_type.type;
}
Export(ExportType type)
{
this->type = static_cast<int>(type);
}
Export(int type)
{
this->type = type;
}
Export & operator=(const Export & field_type)
{
type = field_type.type;
return *this;
}
Export & operator=(ExportType type)
{
this->type = static_cast<int>(type);
return *this;
}
Export & operator=(int type)
{
this->type = type;
return *this;
}
bool is_flag_set(int flag_mask) const
{
return (type & flag_mask) != 0;
}
bool is_no_clear_stream() const
{
return is_flag_set(no_clear_stream);
}
bool is_dump_mode() const
{
return is_flag_set(dump_mode);
}
bool is_export_headers() const
{
return is_flag_set(export_headers);
}
};
}
#endif

View File

@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_fieldvaluehelper
#define headerfile_morm_fieldvaluehelper
#ifndef headerfile_morm_src_fieldvaluehelper
#define headerfile_morm_src_fieldvaluehelper
#include <vector>
#include <typeinfo>

File diff suppressed because it is too large Load Diff

View File

@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_finderhelper
#define headerfile_morm_finderhelper
#ifndef headerfile_morm_src_finderhelper
#define headerfile_morm_src_finderhelper
#include "queryresult.h"

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -67,8 +67,7 @@ FlatExpression * FlatConnector::get_expression()
}
void FlatConnector::to_text(pt::TextStream & stream, Model & model)
void FlatConnector::to_text(pt::TextStream & stream, Model & model, Export exp)
{
allocate_default_expression_if_needed();
@ -82,8 +81,6 @@ void FlatConnector::to_text(pt::TextStream & stream, Model & model)
}
void FlatConnector::deallocate_expression()
{
if( expression_allocated )

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,10 +32,11 @@
*
*/
#ifndef headerfile_morm_flatconnector
#define headerfile_morm_flatconnector
#ifndef headerfile_morm_src_flatconnector
#define headerfile_morm_src_flatconnector
#include "textstream/textstream.h"
#include "export.h"
namespace morm
@ -51,7 +52,7 @@ public:
FlatConnector();
virtual ~FlatConnector();
virtual void to_text(pt::TextStream & stream, Model & model);
virtual void to_text(pt::TextStream & stream, Model & model, Export exp);
virtual void set_expression(FlatExpression & expression);
virtual FlatExpression * get_expression();

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -39,9 +39,27 @@
namespace morm
{
void FlatExpression::esc(const pt::Date & date, pt::TextStream & stream, const FT & field_type)
FlatExpression::FlatExpression()
{
date.SerializeISO(stream);
}
FlatExpression::~FlatExpression()
{
}
bool FlatExpression::should_field_model_be_generated_as_null(bool has_model_primary_key, const FT & field_type)
{
return !has_model_primary_key && field_type.is_serialize_to_null_if_null();
}
bool FlatExpression::can_field_model_be_generated(bool has_model_primary_key, const FT & field_type)
{
return has_model_primary_key || !field_type.is_do_not_serialize_if_null();
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_flatexpression
#define headerfile_morm_flatexpression
#ifndef headerfile_morm_src_flatexpression
#define headerfile_morm_src_flatexpression
#include "baseexpression.h"
@ -45,9 +45,15 @@ class FlatExpression : public BaseExpression
{
public:
void esc(const pt::Date & date, pt::TextStream & stream, const FT & field_type);
FlatExpression();
virtual ~FlatExpression();
protected:
bool should_field_model_be_generated_as_null(bool has_model_primary_key, const FT & field_type);
bool can_field_model_be_generated(bool has_model_primary_key, const FT & field_type);
};

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2021, Tomasz Sowa
* Copyright (c) 2021-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_ft
#define headerfile_morm_ft
#ifndef headerfile_morm_src_ft
#define headerfile_morm_src_ft
namespace morm
{
@ -58,12 +58,25 @@ public:
no_fetchable = 32, /* not supported yet */
no_removable = 64,
raw_field_name = 128,
dont_use_utf8 = 256,
dont_use_utf8 = 256, /* used only with wchar_t and std::wstring, ignored if a binary or a hexadecimal flags are used */
hexadecimal = 512,
binary = 1024,
json = 2048,
space = 4096,
pretty_print = 8192,
numeric = 16384,
date_only = 32768, /* use only year, month and day from pt::Date, no_time_zone flag is not used here */
time_only = 65536, /* use only hour, min, sec from pt::Date, no_time_zone flag is not used here */
no_time_zone = 131072, /* no time zone, used only with pt::Date */
/*
* if this flag is set and a model does not have a primary key set
* then we print only 'null'
* (this is used only with flat strings)
*
*/
serialize_to_null_if_null = 262144,
do_not_serialize_if_null = 524288, /* null objects are completely skipped when serializing to a flat string (test only for Model objects, not lists/vectors with childs models */
};
/*
@ -99,6 +112,18 @@ public:
return *this;
}
FT & operator=(FieldType type)
{
this->type = static_cast<int>(type);
return *this;
}
FT & operator=(int type)
{
this->type = type;
return *this;
}
bool is_flag_set(int flag_mask) const
{
return (type & flag_mask) != 0;
@ -176,6 +201,36 @@ public:
return is_flag_set(pretty_print);
}
bool is_numeric() const
{
return is_flag_set(numeric);
}
bool is_date_only() const
{
return is_flag_set(date_only);
}
bool is_time_only() const
{
return is_flag_set(time_only);
}
bool is_no_time_zone() const
{
return is_flag_set(no_time_zone);
}
bool is_serialize_to_null_if_null() const
{
return is_flag_set(serialize_to_null_if_null);
}
bool is_do_not_serialize_if_null() const
{
return is_flag_set(do_not_serialize_if_null);
}
};
}

View File

@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_jsonconnector
#define headerfile_morm_jsonconnector
#ifndef headerfile_morm_src_jsonconnector
#define headerfile_morm_src_jsonconnector
#include "flatconnector.h"

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2022, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -34,7 +34,7 @@
#include "jsonexpression.h"
#include "morm_types.h"
#include "convert/misc.h"
namespace morm
@ -88,17 +88,35 @@ void JSONExpression::after_field_name()
void JSONExpression::before_field_value_string(const FT & field_type)
void JSONExpression::before_field_value_string(const FT & field_type, ModelEnv * model_env)
{
(*out_stream) << "\"";
}
void JSONExpression::after_field_value_string(const FT & field_type)
void JSONExpression::after_field_value_string(const FT & field_type, ModelEnv * model_env)
{
(*out_stream) << "\"";
}
void JSONExpression::before_field_value(const pt::Space &, const FT & field_type, ModelEnv * model_env)
{
if( field_type.is_space() )
{
before_field_value_string(field_type, model_env);
}
}
void JSONExpression::after_field_value(const pt::Space &, const FT & field_type, ModelEnv * model_env)
{
if( field_type.is_space() )
{
after_field_value_string(field_type, model_env);
}
}
void JSONExpression::put_name_value_separator()
{
(*out_stream) << ':';
@ -117,50 +135,28 @@ void JSONExpression::after_field_value_list()
}
void JSONExpression::esc(char val, pt::TextStream & stream, const FT & field_type)
bool JSONExpression::esc_char(wchar_t val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
if( field_type.is_hexadecimal() || field_type.is_binary() )
return pt::try_esc_to_json(val, stream);
}
void JSONExpression::esc(const pt::Space & space, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
bool pretty_print = field_type.is_pretty_print();
if( field_type.is_space() )
{
char_to_hex(val, stream);
pt::WTextStream tmp_stream;
space.serialize_to_space_stream(tmp_stream, pretty_print);
BaseExpression::esc(tmp_stream, stream, field_type, model_env);
}
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;
}
}
// when serializing as json put it directly without escaping
space.serialize_to_json_stream(stream, pretty_print);
}
}
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2022, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_jsonexpression
#define headerfile_morm_jsonexpression
#ifndef headerfile_morm_src_jsonexpression
#define headerfile_morm_src_jsonexpression
#include "flatexpression.h"
@ -62,17 +62,17 @@ protected:
void before_field_value_list();
void after_field_value_list();
// using FlatExpression::esc to suppress clang warning:
// 'morm::JSONExpression::esc' hides overloaded virtual function [-Woverloaded-virtual]
using FlatExpression::esc;
void esc(char val, pt::TextStream & stream, const FT & field_type);
bool esc_char(wchar_t val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env);
void esc(const pt::Space & space, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env);
private:
void before_field_value_string(const FT & field_type);
void after_field_value_string(const FT & field_type);
void before_field_value_string(const FT & field_type, ModelEnv * model_env);
void after_field_value_string(const FT & field_type, ModelEnv * model_env);
void before_field_value(const pt::Space &, const FT & field_type, ModelEnv * model_env);
void after_field_value(const pt::Space &, const FT & field_type, ModelEnv * model_env);
};

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -74,13 +74,28 @@ Model::SaveMode Model::get_save_mode()
}
void Model::set_save_mode2(SaveMode save_mode, bool update_whole_tree)
{
this->save_mode = save_mode;
if( update_whole_tree )
{
ModelEnv model_env_local;
model_env = &model_env_local;
model_env->model_work_mode = MORM_MODEL_WORK_MODE_PROPAGATE_SAVE_STATUS;
fields();
model_env = nullptr;
}
}
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()
bool Model::get_has_primary_key_set() const
{
return this->has_primary_key_set;
}
@ -332,10 +347,9 @@ bool Model::get_raw_value(const wchar_t * db_field_name, const wchar_t * flat_fi
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, Export exp)
{
if( clear_stream )
if( !exp.is_no_clear_stream() )
{
stream.clear();
}
@ -344,7 +358,7 @@ void Model::to_text(pt::TextStream & stream, ModelData * model_data, bool clear_
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->dump_mode = exp.is_dump_mode();
model_env->model_data = model_data;
model_env->model = this;
@ -357,7 +371,7 @@ void Model::to_text(pt::TextStream & stream, ModelData * model_data, bool clear_
try
{
// table(); at the moment flat strings (json/space) do not need a table name
flat_connector->to_text(stream, *this);
flat_connector->to_text(stream, *this, exp);
}
catch(...)
{
@ -371,6 +385,32 @@ void Model::to_text(pt::TextStream & stream, ModelData * model_data, bool clear_
}
void Model::to_text(pt::TextStream & stream, ModelData & model_data, Export exp)
{
to_text(stream, &model_data, exp);
}
void Model::to_text(pt::TextStream & stream, Export exp)
{
to_text(stream, nullptr, exp);
}
void Model::to_text(pt::TextStream & stream, ModelData * model_data, bool clear_stream, bool dump_mode)
{
Export exp = Export::default_type;
if( !clear_stream )
exp = exp.type | Export::no_clear_stream;
if( dump_mode )
exp = exp.type | Export::dump_mode;
to_text(stream, model_data, exp);
}
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);
@ -384,6 +424,7 @@ void Model::to_text(pt::TextStream & stream, bool clear_stream, bool dump_mode)
void Model::to_text(std::string & str, ModelData * model_data, bool clear_string, bool dump_mode)
{
if( model_connector )
@ -479,12 +520,11 @@ bool Model::insert(ModelData * model_data, bool insert_whole_tree)
model_env = &model_env_local;
model_env->model_data = model_data;
model_env->model = this;
bool status = false;
try
{
table();
status = insert_tree(insert_whole_tree);
insert_tree(insert_whole_tree);
}
catch(...)
{
@ -493,30 +533,27 @@ bool Model::insert(ModelData * model_data, bool insert_whole_tree)
}
model_env = nullptr;
return status;
return model_env_local.status;
}
// has ModelEnv set
// FIX ME we need to propagage the status from the whole tree, if there is an error somewhere then we should return error from the parent
bool Model::insert_tree(bool insert_whole_tree)
void Model::insert_tree(bool insert_whole_tree)
{
bool result = false;
model_env->has_primary_key_set = has_primary_key_set;
if( insert_whole_tree )
if( model_env->status && 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;
fields();
}
if( model_connector )
if( model_env->status && model_connector )
{
model_env->model_work_mode = MORM_MODEL_WORK_MODE_GENERATING_DB_SQL;
DbConnector * db_connector = model_connector->get_db_connector();
// CHECK ME what if the stream is being used by something other?
// CHECK ME what if the stream is being used by someone else?
pt::TextStream * out_stream = model_connector->get_stream();
if( db_connector && out_stream )
@ -524,9 +561,9 @@ bool Model::insert_tree(bool insert_whole_tree)
before_insert();
out_stream->clear();
result = db_connector->insert(*out_stream, *this);
model_env->status = db_connector->insert(*out_stream, *this);
if( result )
if( model_env->status )
{
/*
* after_insert() should read the new primary key and set has_primary_key_set flag if the key was read correctly
@ -549,16 +586,22 @@ bool Model::insert_tree(bool insert_whole_tree)
after_insert_failure();
}
}
else
{
model_env->status = false;
}
}
else
{
model_env->status = false;
}
if( insert_whole_tree )
if( model_env->status && 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;
fields();
}
return result;
}
@ -606,12 +649,11 @@ bool Model::update(ModelData * model_data, bool update_whole_tree)
model_env = &model_env_local;
model_env->model_data = model_data;
model_env->model = this;
bool status = false;
try
{
table();
status = update_tree(update_whole_tree);
update_tree(update_whole_tree);
}
catch(...)
{
@ -620,30 +662,28 @@ bool Model::update(ModelData * model_data, bool update_whole_tree)
}
model_env = nullptr;
return status;
return model_env_local.status;
}
// FIX ME we need to propagage the status from the whole tree, if there is an error somewhere then we should return error from the parent
bool Model::update_tree(bool update_whole_tree)
void 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;
model_env->status = false;
}
if( update_whole_tree )
if( model_env->status && 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;
fields();
}
if( model_connector )
if( model_env->status && model_connector )
{
model_env->model_work_mode = MORM_MODEL_WORK_MODE_GENERATING_DB_SQL;
DbConnector * db_connector = model_connector->get_db_connector();
@ -655,23 +695,29 @@ bool Model::update_tree(bool update_whole_tree)
{
before_update();
out_stream->clear();
result = db_connector->update(*out_stream, *this);
model_env->status = db_connector->update(*out_stream, *this);
if( result )
if( model_env->status )
after_update();
else
after_update_failure();
}
else
{
model_env->status = false;
}
}
else
{
model_env->status = false;
}
if( update_whole_tree )
if( model_env->status && 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;
fields();
}
return result;
}
@ -719,12 +765,11 @@ bool Model::remove(ModelData * model_data, bool remove_whole_tree)
model_env = &model_env_local;
model_env->model_data = model_data;
model_env->model = this;
bool status = false;
try
{
table();
status = remove_tree(remove_whole_tree);
remove_tree(remove_whole_tree);
}
catch(...)
{
@ -733,44 +778,42 @@ bool Model::remove(ModelData * model_data, bool remove_whole_tree)
}
model_env = nullptr;
return status;
return model_env_local.status;
}
// FIX ME we need to propagage the status from the whole tree, if there is an error somewhere then we should return error from the parent
bool Model::remove_tree(bool remove_whole_tree)
void 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;
model_env->status = false;
}
if( remove_whole_tree )
if( model_env->status && 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;
fields();
}
if( model_connector )
if( model_env->status && model_connector )
{
model_env->model_work_mode = MORM_MODEL_WORK_MODE_GENERATING_DB_SQL;
DbConnector * db_connector = model_connector->get_db_connector();
// CHECK ME what if the stream is being used by something other?
// CHECK ME what if the stream is being used by someone else?
pt::TextStream * out_stream = model_connector->get_stream();
if( db_connector && out_stream )
{
before_remove();
out_stream->clear();
result = db_connector->remove(*out_stream, *this);
model_env->status = db_connector->remove(*out_stream, *this);
if( result )
if( model_env->status )
{
save_mode = DO_NOTHING_ON_SAVE;
has_primary_key_set = false;
@ -782,16 +825,22 @@ bool Model::remove_tree(bool remove_whole_tree)
after_remove_failure();
}
}
else
{
model_env->status = false;
}
}
else
{
model_env->status = false;
}
if( remove_whole_tree )
if( model_env->status && 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;
fields();
}
return result;
}
@ -815,12 +864,11 @@ bool Model::save(ModelData * model_data, bool save_whole_tree)
model_env = &model_env_local;
model_env->model_data = model_data;
model_env->model = this;
bool status = false;
try
{
table();
status = save_tree(save_whole_tree);
save_tree(save_whole_tree);
}
catch(...)
{
@ -829,17 +877,16 @@ bool Model::save(ModelData * model_data, bool save_whole_tree)
}
model_env = nullptr;
return status;
return model_env_local.status;
}
// FIX ME we need to propagage the status from the whole tree, if there is an error somewhere then we should return error from the parent
bool Model::save_tree(bool save_whole_tree)
void Model::save_tree(bool save_whole_tree)
{
bool result = false;
model_env->has_primary_key_set = has_primary_key_set;
SaveMode origin_save_mode = save_mode;
if( save_whole_tree )
if( model_env->status && save_whole_tree )
{
if( save_mode == DO_DELETE_ON_SAVE )
model_env->model_work_mode = MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITHOUT_FOREIGN_KEY;
@ -850,32 +897,34 @@ bool Model::save_tree(bool save_whole_tree)
fields();
}
ModelEnv * old_model_env = model_env; // remove, insert or update will set model_env to nullptr
switch( save_mode )
if( model_env->status )
{
case DO_DELETE_ON_SAVE:
result = remove_tree(false);
break;
ModelEnv * old_model_env = model_env; // remove, insert or update will set model_env to nullptr
case DO_INSERT_ON_SAVE:
result = insert_tree(false);
break;
switch( save_mode )
{
case DO_DELETE_ON_SAVE:
remove_tree(false);
break;
case DO_UPDATE_ON_SAVE:
result = update_tree(false);
break;
case DO_INSERT_ON_SAVE:
insert_tree(false);
break;
case DO_NOTHING_ON_SAVE:
result = true;
break;
case DO_UPDATE_ON_SAVE:
update_tree(false);
break;
case DO_NOTHING_ON_SAVE:
break;
}
model_env = old_model_env;
}
model_env = old_model_env;
if( save_whole_tree )
if( model_env->status && save_whole_tree )
{
if( save_mode == DO_DELETE_ON_SAVE )
if( origin_save_mode == DO_DELETE_ON_SAVE )
model_env->model_work_mode = MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITH_FOREIGN_KEY;
else
model_env->model_work_mode = MORM_MODEL_WORK_MODE_ITERATE_THROUGH_CHILDS_WITHOUT_FOREIGN_KEY;
@ -883,8 +932,6 @@ bool Model::save_tree(bool save_whole_tree)
model_env->model_work_submode = MORM_MODEL_WORK_SUBMODE_SAVE;
fields();
}
return result;
}
@ -914,6 +961,7 @@ void Model::map_values_from_query()
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();
map_additional_columns_from_query();
model_env->model_work_mode = MORM_MODEL_WORK_MODE_NONE;
if( model_env->was_primary_key_read && model_env->has_primary_key_set )
@ -930,6 +978,40 @@ void Model::map_values_from_query()
}
void Model::map_additional_columns_from_query()
{
if( model_env )
{
if( model_env->select_flags.is_with_rows_counter() )
{
map_rows_counter_from_query();
}
}
}
void Model::map_rows_counter_from_query()
{
if( model_env && model_env->cursor_helper )
{
/*
* take the value only from the first row, the value should be the same on every row
*/
if( model_env->cursor_helper->current_row == 0 )
{
field(model_env->rows_counter_column_name.c_str(), L"", model_env->rows_counter);
}
else
{
if( model_env->cursor_helper && model_env->cursor_helper->has_autogenerated_select )
{
model_env->cursor_helper->current_column += 1;
}
}
}
}
void Model::clear()
{
@ -1108,16 +1190,24 @@ void Model::log_table_name_with_field(const wchar_t * db_field_name, bool put_sc
}
void Model::put_to_log(const wchar_t * str)
pt::Log * Model::get_logger()
{
if( model_connector )
{
pt::Log * log = model_connector->get_logger();
return model_connector->get_logger();
}
if( log )
{
(*log) << str << pt::Log::logend;
}
return nullptr;
}
void Model::put_to_log(const wchar_t * str)
{
pt::Log * log = get_logger();
if( log )
{
(*log) << str << pt::Log::logend;
}
}
@ -1171,7 +1261,7 @@ void Model::field_model_left_join(const wchar_t * db_field_name, Model & field_m
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->alias_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);
@ -1384,7 +1474,7 @@ void Model::field_model_generate_flat_string(const wchar_t * flat_field_name, Mo
if( flat_expression )
{
if( model_env->dump_mode || field_model.save_mode == DO_INSERT_ON_SAVE || field_model.save_mode == DO_UPDATE_ON_SAVE )
if( model_env->dump_mode || field_model.save_mode != DO_DELETE_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);
@ -1458,7 +1548,9 @@ void Model::field_model_generate_db_sql(const wchar_t * db_field_name, Model & f
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 )
db_expression->get_output_type() != MORM_OUTPUT_TYPE_DB_UPDATE &&
db_expression->get_output_type() != MORM_OUTPUT_TYPE_DB_INSERT_PRIMARY_KEY &&
db_expression->get_output_type() != MORM_OUTPUT_TYPE_DB_UPDATE_PRIMARY_KEY )
{
field_model.fields();
}
@ -1469,13 +1561,13 @@ void Model::field_model_generate_db_sql(const wchar_t * db_field_name, Model & f
}
void Model::field_model_clear_values(Model & field_model)
void Model::field_model_clear_values(Model & field_model, const FT & field_type)
{
Clearer * clearer = model_connector->get_clearer();
if( clearer )
{
clearer->clear_model(field_model);
clearer->clear_model(field_model, field_type);
}
}
@ -1554,7 +1646,7 @@ void Model::field_model(const wchar_t * db_field_name, const wchar_t * flat_fiel
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_CLEARING_VALUE )
{
field_model_clear_values(field_model);
field_model_clear_values(field_model, field_type);
}
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_GET_FIELD_MODEL )
@ -1576,7 +1668,15 @@ void Model::field_model(const wchar_t * db_field_name, const wchar_t * flat_fiel
}
}
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_PROPAGATE_SAVE_STATUS )
{
field_model.set_save_mode2(save_mode, true);
}
field_model.model_env = nullptr;
if( !model_env_local.status )
model_env->status = false;
}
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_model
#define headerfile_morm_model
#ifndef headerfile_morm_src_model
#define headerfile_morm_src_model
#include <string>
#include <list>
@ -153,8 +153,11 @@ public:
virtual void set_save_mode(SaveMode save_mode);
virtual SaveMode get_save_mode();
// set_save_mode() will be changed to set_save_mode2() in the future
virtual void set_save_mode2(SaveMode save_mode, bool update_whole_tree = true);
virtual void set_has_primary_key_set(bool has_primary_key);
virtual bool get_has_primary_key_set();
virtual bool get_has_primary_key_set() const;
virtual void mark_to_delete();
virtual void mark_to_remove();
@ -174,9 +177,13 @@ public:
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);
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, Export exp = Export::default_type);
virtual void to_text(pt::TextStream & stream, ModelData & model_data, Export exp = Export::default_type);
virtual void to_text(pt::TextStream & stream, Export exp = Export::default_type);
virtual void to_text(pt::TextStream & stream, ModelData * model_data, bool clear_stream, bool dump_mode);
virtual void to_text(pt::TextStream & stream, ModelData & model_data, bool clear_stream, bool dump_mode);
virtual void to_text(pt::TextStream & stream, bool clear_stream, bool dump_mode);
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);
@ -341,12 +348,14 @@ protected:
virtual ModelData * get_model_data();
virtual bool insert_tree(bool insert_whole_tree);
virtual bool update_tree(bool update_whole_tree);
virtual bool remove_tree(bool remove_whole_tree);
virtual bool save_tree(bool save_whole_tree);
virtual void insert_tree(bool insert_whole_tree);
virtual void update_tree(bool update_whole_tree);
virtual void remove_tree(bool remove_whole_tree);
virtual void save_tree(bool save_whole_tree);
virtual void map_values_from_query();
virtual void map_additional_columns_from_query();
virtual void map_rows_counter_from_query();
virtual bool db_query(const char * raw_sql);
virtual bool db_query(const std::string & raw_sql);
@ -751,7 +760,7 @@ protected:
if( clearer )
{
clearer->clear_value(field_value);
clearer->clear_value(field_value, field_type);
}
}
@ -1047,7 +1056,7 @@ protected:
void field_model_iterate_through_childs(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_clear_values(Model & field_model, const FT & field_type);
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(const wchar_t * db_field_name, const wchar_t * flat_field_name, Model * field_model, const FT & field_type);
@ -1143,18 +1152,24 @@ protected:
template<typename ModelContainerType>
void field_list_iterate_through_childs(ModelContainerType & child_model, const FT & field_type)
{
ModelEnv model_env_local;
model_env_local.copy_global_objects(*model_env);
model_env_local.model = &child_model;
if( model_env->status )
{
ModelEnv model_env_local;
model_env_local.copy_global_objects(*model_env);
model_env_local.model = &child_model;
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();
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();
field_model_iterate_through_childs(child_model, field_type);
field_model_iterate_through_childs(child_model, field_type);
child_model.model_env = nullptr;
if( !model_env_local.status )
model_env->status = false;
child_model.model_env = nullptr;
}
}
@ -1177,13 +1192,52 @@ protected:
template<typename ModelContainer, typename ModelContainerType, typename IsContainerByValueRenameMe>
void field_list_clearing_values(ModelContainer & field_container, ModelContainerType * model_container_type, IsContainerByValueRenameMe * foo)
void field_list_clearing_values(ModelContainer & field_container, ModelContainerType * model_container_type, IsContainerByValueRenameMe * foo, const FT & field_type)
{
Clearer * clearer = model_connector->get_clearer();
if( clearer )
{
clearer->clear_container(field_container, model_container_type, foo);
clearer->clear_container(field_container, model_container_type, foo, field_type);
}
}
template<typename ModelContainer, typename ModelContainerType, typename IsContainerByValueRenameMe>
void field_list_propagate_save_status(ModelContainer & field_container, ModelContainerType * model_container_type, IsContainerByValueRenameMe * foo)
{
if constexpr (std::is_base_of<Model, ModelContainerType>())
{
if constexpr (std::is_base_of<Model, IsContainerByValueRenameMe>())
{
field_list_propagate_save_status_in_container_by_value(field_container, model_container_type);
}
else
{
field_list_propagate_save_status_in_container_by_pointer(field_container, model_container_type);
}
}
}
template<typename ModelContainer, typename ModelContainerType>
void field_list_propagate_save_status_in_container_by_value(ModelContainer & field_container, ModelContainerType * model_container_type)
{
for(ModelContainerType & item : field_container)
{
item.set_connector(model_connector);
item.set_save_mode2(save_mode, true);
}
}
template<typename ModelContainer, typename ModelContainerType>
void field_list_propagate_save_status_in_container_by_pointer(ModelContainer & field_container, ModelContainerType * model_container_type)
{
for(ModelContainerType * item : field_container)
{
item->set_connector(model_connector);
item->set_save_mode2(save_mode, true);
}
}
@ -1370,7 +1424,12 @@ protected:
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_CLEARING_VALUE )
{
field_list_clearing_values(field_container, model_container_type, foo);
field_list_clearing_values(field_container, model_container_type, foo, field_type);
}
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_PROPAGATE_SAVE_STATUS )
{
field_list_propagate_save_status(field_container, model_container_type, foo);
}
}
}
@ -1418,13 +1477,18 @@ protected:
if( db_expression )
{
std::wstring table_field_name;
pt::TextStream table_field_name_str;
db_expression->alias_to_stream(table_field_name_str, model_env->table_name, model_env->table_index, field_name);
// 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_str(table_field_name);
column_index = model_env->cursor_helper->query_result->get_column_index(table_field_name.c_str());
if( table_field_name_str.size() < 256 )
{
wchar_t alias_name[256];
if( table_field_name_str.to_str(alias_name, sizeof(alias_name) / sizeof(wchar_t)) )
{
column_index = model_env->cursor_helper->query_result->get_column_index(alias_name);
}
}
}
}
else
@ -1534,6 +1598,7 @@ 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 pt::Log * get_logger();
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);
@ -1589,6 +1654,7 @@ protected:
template<typename ModelClass> friend class Finder;
template<typename ModelClass> friend class Cursor;
friend class BaseExpression;
friend class DbExpression;
friend class DbConnector;
friend class FlatConnector;

View File

@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_modelconnector
#define headerfile_morm_modelconnector
#ifndef headerfile_morm_src_modelconnector
#define headerfile_morm_src_modelconnector
#include "clearer.h"
#include "dbconnector.h"

View File

@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_modelcontainerwrapper
#define headerfile_morm_modelcontainerwrapper
#ifndef headerfile_morm_src_modelcontainerwrapper
#define headerfile_morm_src_modelcontainerwrapper
#include <vector>
#include <list>
@ -69,6 +69,9 @@ public:
return false;
}
virtual void set_iterator_at_first_model()
{
}
};
@ -106,6 +109,10 @@ public:
return iterator != container->end();
}
void set_iterator_at_first_model()
{
iterator = container->begin();
}
protected:

View File

@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_modeldata
#define headerfile_morm_modeldata
#ifndef headerfile_morm_src_modeldata
#define headerfile_morm_src_modeldata

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2019-2021, Tomasz Sowa
* Copyright (c) 2019-2022, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_modelenv
#define headerfile_morm_modelenv
#ifndef headerfile_morm_src_modelenv
#define headerfile_morm_src_modelenv
#include "modeldata.h"
#include "cursorhelper.h"
@ -41,6 +41,7 @@
#include "fieldvaluehelper.h"
#include "morm_types.h"
#include "wrapper.h"
#include "select.h"
#ifdef MORM_HAS_EZC_LIBRARY
@ -105,6 +106,17 @@ public:
const std::type_info * ezc_fun_info_typeinfo;
#endif
bool status;
bool has_autogenerated_select;
Select select_flags;
size_t rows_counter;
std::wstring rows_counter_column_name;
bool use_escaping_for_like; // escaping % and _ characters for LIKE or ILIKE statements
bool add_prefix_percent; // add a percent sign before a string value (used mainly in LIKE or ILIKE)
bool add_postfix_percent; // add a percent sign after a string value (used mainly in LIKE or ILIKE)
ModelEnv()
{
clear();
@ -138,6 +150,14 @@ public:
stream = e.stream;
was_field_found = e.was_field_found;
wrapper = e.wrapper;
status = e.status;
has_autogenerated_select = e.has_autogenerated_select;
select_flags = e.select_flags;
rows_counter = e.rows_counter;
rows_counter_column_name = e.rows_counter_column_name;
use_escaping_for_like = e.use_escaping_for_like;
add_prefix_percent = e.add_prefix_percent;
add_postfix_percent = e.add_postfix_percent;
#ifdef MORM_HAS_EZC_LIBRARY
ezc_fun_info = e.ezc_fun_info;
@ -189,6 +209,14 @@ public:
stream = nullptr;
was_field_found = false;
wrapper.clear();
status = true;
has_autogenerated_select = false;
select_flags = Select::default_type;
rows_counter = 0;
rows_counter_column_name.clear();
use_escaping_for_like = false;
add_prefix_percent = false;
add_postfix_percent = false;
#ifdef MORM_HAS_EZC_LIBRARY
ezc_fun_info = nullptr;
@ -210,7 +238,6 @@ public:
}
}
};
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2019, Tomasz Sowa
* Copyright (c) 2018-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,23 +32,28 @@
*
*/
#ifndef headerfile_morm_morm
#define headerfile_morm_morm
#ifndef headerfile_morm_src_morm
#define headerfile_morm_src_morm
#include "version.h"
#include "morm_types.h"
#include "model.h"
#include "finder.h"
#include "jsonexpression.h"
#include "postgresqlexpression.h"
#include "xmlexpression.h"
#include "jsonconnector.h"
#include "postgresqlconnector.h"
#include "xmlconnector.h"
#include "modelconnector.h"
#include "clearer.h"
#include "transaction.h"
namespace morm

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_morm_types
#define headerfile_morm_morm_types
#ifndef headerfile_morm_src_morm_types
#define headerfile_morm_src_morm_types
#define MORM_MODEL_WORK_MODE_NONE 0
#define MORM_MODEL_WORK_MODE_GENERATING_DB_SQL 1
@ -48,7 +48,7 @@
#define MORM_MODEL_WORK_MODE_GET_FIELD_MODEL 10
#define MORM_MODEL_WORK_MODE_GET_MODEL_WRAPPER 11
#define MORM_MODEL_WORK_MODE_PUT_FIELD_RAW_VALUE_TO_STREAM 12
#define MORM_MODEL_WORK_MODE_PROPAGATE_SAVE_STATUS 13
// submodes used in some cases
@ -64,7 +64,8 @@
#define MORM_WORK_MODE_MODEL_FIELDS 1
#define MORM_WORK_MODE_MODEL_VALUES 2
#define MORM_WORK_MODE_MODEL_FIELDS_VALUES 3
#define MORM_WORK_MODE_MODEL_SAVE_FIELDS 4
#define MORM_WORK_MODE_MODEL_FIELDS_VALUES_FIELDS 4
#define MORM_WORK_MODE_MODEL_SAVE_FIELDS 5
@ -76,10 +77,12 @@
#define MORM_OUTPUT_TYPE_DB_UPDATE 3
// change to something like MORM_OUTPUT_TYPE_DB_WHERE_PRIMARY_KEY
// put a primary key
#define MORM_OUTPUT_TYPE_DB_PRIMARY_KEY 4
#define MORM_OUTPUT_TYPE_DB_INSERT_PRIMARY_KEY 5
#define MORM_OUTPUT_TYPE_DB_UPDATE_PRIMARY_KEY 5
#define MORM_OUTPUT_TYPE_DB_UPDATE_PRIMARY_KEY 6
//#define MORM_OUTPUT_TYPE_WHERE_CUSTOM 7
@ -96,7 +99,12 @@
#define MORM_OUTPUT_TYPE_WHERE_GE 24
#define MORM_OUTPUT_TYPE_WHERE_IN 25
#define MORM_OUTPUT_TYPE_WHERE_NOT_EQ 26
#define MORM_OUTPUT_TYPE_WHERE_LIKE 27
#define MORM_OUTPUT_TYPE_WHERE_ILIKE 28
#define MORM_OUTPUT_TYPE_WHERE_IS_NULL 29
#define MORM_OUTPUT_TYPE_WHERE_IS_NOT_NULL 30
#define MORM_OUTPUT_TYPE_FIELDS_RECURSIVE 31
#define MORM_CONJUNCTION_AND 1
#define MORM_CONJUNCTION_OR 2

View File

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -97,13 +97,15 @@ bool PostgreSQLConnector::do_query(const char * query_str, PostgreSQLQueryResult
psql_result->psql_result = PQexec(pg_conn, query_str);
if( !psql_result->psql_result )
/*
* in older versions of PostgreSQL when there was a connection issue then the psql_result pointer would be null
*
*/
if( !psql_result->psql_result || PQstatus(pg_conn) != CONNECTION_OK )
{
if( PQstatus(pg_conn) != CONNECTION_OK )
{
assert_connection();
psql_result->psql_result = PQexec(pg_conn, query_str);
}
psql_result->clear();
assert_connection_is_working();
psql_result->psql_result = PQexec(pg_conn, query_str);
}
if( psql_result->psql_result )
@ -115,19 +117,15 @@ bool PostgreSQLConnector::do_query(const char * query_str, PostgreSQLQueryResult
if( !psql_result->psql_result || psql_result->psql_status == PGRES_FATAL_ERROR )
{
const char * err_msg = PQerrorMessage(pg_conn);
if( err_msg )
{
pt::utf8_to_wide(err_msg, psql_result->error_msg);
}
if( log )
{
const char * err_msg = PQerrorMessage(pg_conn);
(*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->put_multiline("Morm: ", err_msg);
}
}
}
else
@ -172,7 +170,7 @@ 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;
<< pt::Log::logend;
}
}
}
@ -180,8 +178,13 @@ 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;
const char * err_msg = PQerrorMessage(pg_conn);
(*log) << pt::Log::log1 << "Morm: error (currval) for table: " << sequence_table_name << pt::Log::logend;
if( err_msg )
{
log->put_multiline("Morm: ", err_msg);
}
}
}
}
@ -204,14 +207,14 @@ bool PostgreSQLConnector::query(const std::string & query_str, QueryResult & que
}
bool PostgreSQLConnector::query_select(const char * query_str, QueryResult & query_result)
bool PostgreSQLConnector::query_command(const char * query_str, QueryResult & query_result, ExecStatusType expected_status)
{
PostgreSQLQueryResult * psql_result = dynamic_cast<PostgreSQLQueryResult*>(&query_result);
bool result = false;
if( psql_result )
{
result = (do_query(query_str, psql_result) && psql_result->psql_status == PGRES_TUPLES_OK);
result = (do_query(query_str, psql_result) && psql_result->psql_status == expected_status);
psql_result->status = result;
}
@ -219,48 +222,29 @@ bool PostgreSQLConnector::query_select(const char * query_str, QueryResult & que
}
bool PostgreSQLConnector::query_select(const char * query_str, QueryResult & query_result)
{
return query_command(query_str, query_result, PGRES_TUPLES_OK);
}
bool PostgreSQLConnector::query_update(const char * query_str, QueryResult & query_result)
{
PostgreSQLQueryResult * psql_result = dynamic_cast<PostgreSQLQueryResult*>(&query_result);
bool result = false;
if( psql_result )
{
result = (do_query(query_str, psql_result) && psql_result->psql_status == PGRES_COMMAND_OK);
psql_result->status = result;
}
return result;
return query_command(query_str, query_result, PGRES_COMMAND_OK);
}
bool PostgreSQLConnector::query_insert(const char * query_str, QueryResult & query_result)
{
PostgreSQLQueryResult * psql_result = dynamic_cast<PostgreSQLQueryResult*>(&query_result);
bool result = false;
if( psql_result )
{
result = (do_query(query_str, psql_result) && psql_result->psql_status == PGRES_COMMAND_OK);
psql_result->status = result;
}
return result;
return query_command(query_str, query_result, PGRES_COMMAND_OK);
}
bool PostgreSQLConnector::query_remove(const char * query_str, QueryResult & query_result)
{
PostgreSQLQueryResult * psql_result = dynamic_cast<PostgreSQLQueryResult*>(&query_result);
bool result = false;
return query_command(query_str, query_result, PGRES_COMMAND_OK);
}
if( psql_result )
{
result = (do_query(query_str, psql_result) && psql_result->psql_status == PGRES_COMMAND_OK);
psql_result->status = result;
}
return result;
bool PostgreSQLConnector::query_declare_cursor(const char * query_str, QueryResult & query_result)
{
return query_command(query_str, query_result, PGRES_COMMAND_OK);
}
@ -288,16 +272,11 @@ bool PostgreSQLConnector::query_remove(const pt::TextStream & stream, QueryResul
return query_remove(query_str.c_str(), query_result);
}
bool PostgreSQLConnector::query_declare_cursor(const pt::TextStream & stream, QueryResult & query_result)
{
stream.to_str(query_str);
return query_declare_cursor(query_str.c_str(), query_result);
}
@ -391,15 +370,48 @@ bool PostgreSQLConnector::query_remove(const pt::TextStream & stream, QueryResul
//}
void PostgreSQLConnector::set_conn_param(const std::wstring & database_name, const std::wstring & user, const std::wstring & pass)
void PostgreSQLConnector::set_conn_param(const std::wstring & database_conn_string)
{
db_conn_string = database_conn_string;
db_hostaddr.clear();
db_port.clear();
db_database.clear();
db_user.clear();
db_pass.clear();
}
void PostgreSQLConnector::set_conn_param(const std::wstring & database_host,
const std::wstring & database_hostaddr,
const std::wstring & database_port,
const std::wstring & database_name,
const std::wstring & user,
const std::wstring & pass)
{
db_conn_string.clear();
db_host = database_host;
db_hostaddr = database_hostaddr;
db_port = database_port;
db_database = database_name;
db_user = user;
db_pass = pass;
}
void PostgreSQLConnector::set_conn_param(const std::wstring & database_name, const std::wstring & user, const std::wstring & pass)
{
db_conn_string.clear();
db_host.clear();
db_hostaddr.clear();
db_port.clear();
db_database = database_name;
db_user = user;
db_pass = pass;
}
void PostgreSQLConnector::overwrite(pt::TextStream & stream)
{
pt::TextStream::iterator i = stream.begin();
@ -427,15 +439,44 @@ void PostgreSQLConnector::connect()
if( db_expression )
{
stream.clear();
stream << "dbname='";
db_expression->esc(db_database, stream);
stream << "' user='";
db_expression->esc(db_user, stream);
if( !db_conn_string.empty() )
{
stream << db_conn_string;
}
else
{
stream << "dbname='";
db_expression->esc(db_database, stream);
stream << "' password='";
db_expression->esc(db_pass, stream);
stream << "'";
stream << "' user='";
db_expression->esc(db_user, stream);
stream << "' password='";
db_expression->esc(db_pass, stream);
stream << "'";
if( !db_host.empty() )
{
stream << " host='";
db_expression->esc(db_host, stream);
stream << "'";
}
if( !db_hostaddr.empty() )
{
stream << " hostaddr='";
db_expression->esc(db_hostaddr, stream);
stream << "'";
}
if( !db_port.empty() )
{
stream << " port='";
db_expression->esc(db_port, stream);
stream << "'";
}
}
std::string str;
stream.to_str(str);
@ -451,6 +492,17 @@ void PostgreSQLConnector::connect()
//
//
void PostgreSQLConnector::log_no_connection(size_t attempts)
{
if( log )
{
(*log) << pt::Log::log2 << "Morm: connection to the database cannot be established";
(*log) << pt::Log::log3 << ", (" << attempts << " attempt(s))" << pt::Log::logend;
(*log) << pt::Log::logsave;
}
}
void PostgreSQLConnector::log_connection_socket()
{
if( pg_conn && log )
@ -461,8 +513,18 @@ void PostgreSQLConnector::log_connection_socket()
}
}
void PostgreSQLConnector::wait_for_connection()
bool PostgreSQLConnector::wait_for_connection(size_t attempts_max, size_t attempt_delay)
{
size_t attempts = 0;
bool attempts_exceeded = false;
if( attempt_delay == 0 )
attempt_delay = 1;
if( attempt_delay > 120 )
attempt_delay = 120;
if( !pg_conn || PQstatus(pg_conn) != CONNECTION_OK )
{
if( log )
@ -470,24 +532,41 @@ void PostgreSQLConnector::wait_for_connection()
(*log) << pt::Log::log3 << "Morm: waiting for the db to be ready...." << pt::Log::logend << pt::Log::logsave;
}
while( !assert_connection(false) )
while( !attempts_exceeded && !assert_connection_is_working(false) )
{
sleep(5);
}
if( attempts_max != 0 )
{
attempts += 1;
attempts_exceeded = (attempts >= attempts_max);
}
if( !attempts_exceeded )
{
sleep(attempt_delay);
}
}
}
if( attempts_exceeded )
{
log_no_connection(attempts);
}
else
{
log_connection_socket();
}
return !attempts_exceeded;
}
// IMPROVE ME what about the exception now?
bool PostgreSQLConnector::assert_connection(bool put_log)
bool PostgreSQLConnector::assert_connection_is_working(bool put_log)
{
bool was_connection = true;
if( !pg_conn )
{
was_connection = false;
@ -559,17 +638,28 @@ void PostgreSQLConnector::log_unsupported_bin_format()
}
size_t PostgreSQLConnector::unescape_bin_char(const char * str, wchar_t & field_value, const FT & field_type)
void PostgreSQLConnector::unescape_bin_char(const char * str, char & field_value)
{
if( str[0]!='\\' || str[1]!='x' )
{
log_unsupported_bin_format();
return 0;
}
else
{
return unescape_hex_char(str + 2, field_value, field_type);
DbConnector::unescape_bin_char(str + 2, field_value);
}
}
void PostgreSQLConnector::unescape_bin_char(const char * str, wchar_t & field_value)
{
if( str[0]!='\\' || str[1]!='x' )
{
log_unsupported_bin_format();
}
else
{
DbConnector::unescape_bin_char(str + 2, field_value);
}
}
@ -583,12 +673,12 @@ void PostgreSQLConnector::unescape_bin_string(const char * str, std::string & ou
}
else
{
unescape_hex_string(str + 2, out);
DbConnector::unescape_bin_string(str + 2, out);
}
}
void PostgreSQLConnector::unescape_bin_string(const char * str, std::wstring & out, const FT & field_type)
void PostgreSQLConnector::unescape_bin_string(const char * str, std::wstring & out)
{
if( str[0]!='\\' || str[1]!='x' )
{
@ -596,7 +686,7 @@ void PostgreSQLConnector::unescape_bin_string(const char * str, std::wstring & o
}
else
{
unescape_hex_string(str + 2, out, field_type);
DbConnector::unescape_bin_string(str + 2, out);
}
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2023, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_postgresqlconnector
#define headerfile_morm_postgresqlconnector
#ifndef headerfile_morm_src_postgresqlconnector
#define headerfile_morm_src_postgresqlconnector
#include <libpq-fe.h>
#include <string>
@ -63,23 +63,66 @@ public:
bool query_update(const char * query_str, QueryResult & query_result);
bool query_insert(const char * query_str, QueryResult & query_result);
bool query_remove(const char * query_str, QueryResult & query_result);
bool query_declare_cursor(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_declare_cursor(const pt::TextStream & stream, QueryResult & query_result);
/*
* https://www.postgresql.org/docs/14/libpq-connect.html#LIBPQ-CONNSTRING
*/
virtual void set_conn_param(const std::wstring & database_conn_string);
/*
*
* database_host - name of host to connect to (can be empty)
* database_hostaddr - numeric IP address of host to connect to (can be empty)
*
*
* meaning of this parameters is the same as described in
* https://www.postgresql.org/docs/14/libpq-connect.html#LIBPQ-CONNSTRING
*
* from above documentation:
* Using hostaddr allows the application to avoid a host name look-up, which might be important
* in applications with time constraints. However, a host name is required for GSSAPI or SSPI
* authentication methods, as well as for verify-full SSL certificate verification.
* The following rules are used:
*
* - If host is specified without hostaddr, a host name lookup occurs.
*
* - If hostaddr is specified without host, the value for hostaddr gives the server network address.
* The connection attempt will fail if the authentication method requires a host name.
*
* - If both host and hostaddr are specified, the value for hostaddr gives the server network address.
* The value for host is ignored unless the authentication method requires it, in which case it will
* be used as the host name.
*
*/
virtual void set_conn_param(const std::wstring & database_host, const std::wstring & database_hostaddr, const std::wstring & database_port,
const std::wstring & database, const std::wstring & user, const std::wstring & pass);
virtual void set_conn_param(const std::wstring & database, const std::wstring & user, const std::wstring & pass);
virtual void connect();
virtual void wait_for_connection();
virtual void close();
//virtual bool assert_connection(bool put_log = true, bool throw_if_no_connection = true);
virtual bool assert_connection(bool put_log = true);
virtual void set_db_parameters();
virtual void log_connection_socket();
/*
* waiting for a valid connection to the database
*
* attempts_max - how many connection attempts are allowed (0 - infinite)
* attempt_delay - delay between each attempt (in seconds)
*
*/
virtual bool wait_for_connection(size_t attempts_max = 0, size_t attempt_delay = 5);
/*
* close the connection with the database if it was open
*/
virtual void close();
protected:
@ -88,11 +131,22 @@ protected:
pt::TextStream stream;
std::string query_str;
std::wstring db_conn_string;
std::wstring db_host;
std::wstring db_hostaddr;
std::wstring db_port;
std::wstring db_database;
std::wstring db_user;
std::wstring db_pass;
virtual void set_db_parameters();
virtual void log_no_connection(size_t attempts);
virtual void log_connection_socket();
virtual bool assert_connection_is_working(bool put_log = true);
virtual void connect();
virtual bool do_query(const char * query_str, PostgreSQLQueryResult * psql_result);
virtual bool query_command(const char * query_str, QueryResult & query_result, ExecStatusType expected_status);
virtual void allocate_default_expression();
virtual void overwrite(pt::TextStream & stream);
virtual const char * query_last_sequence(const wchar_t * sequence_table_name);
@ -100,9 +154,12 @@ protected:
void log_unsupported_bin_format();
size_t unescape_bin_char(const char * str, wchar_t & field_value, const FT & field_type);
void unescape_bin_char(const char * str, char & field_value);
void unescape_bin_char(const char * str, wchar_t & field_value);
void unescape_bin_string(const char * str, std::string & out);
void unescape_bin_string(const char * str, std::wstring & out, const FT & field_type);
void unescape_bin_string(const char * str, std::wstring & out);
};

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2022, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -40,7 +40,7 @@ namespace morm
void PostgreSQLExpression::before_field_value_string(const FT & field_type)
void PostgreSQLExpression::before_field_value_string(const FT & field_type, ModelEnv * model_env)
{
if( field_type.is_binary() )
{
@ -52,49 +52,76 @@ void PostgreSQLExpression::before_field_value_string(const FT & field_type)
(*out_stream) << "'";
}
else
if( field_type.is_numeric() )
{
(*out_stream) << "'";
}
else
{
(*out_stream) << "E'";
if( model_env && model_env->add_prefix_percent )
(*out_stream) << '%';
}
}
void PostgreSQLExpression::after_field_value_string(const FT & field_type)
void PostgreSQLExpression::after_field_value_string(const FT & field_type, ModelEnv * model_env)
{
if( model_env && model_env->add_postfix_percent )
(*out_stream) << '%';
(*out_stream) << "'";
}
void PostgreSQLExpression::esc(char val, pt::TextStream & stream, const FT & field_type)
bool PostgreSQLExpression::esc_char(wchar_t val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
if( field_type.is_hexadecimal() || field_type.is_binary() )
if( model_env && model_env->use_escaping_for_like )
{
char_to_hex(val, stream);
}
else
{
switch( val )
if( val == '%' )
{
case '\\': stream << "\\\\"; break;
case '\'': stream << "\\\'"; break; // don't use "''" because we use the method for PQconnectdb too
default:
if( val != 0 )
{
stream << val;
}
stream << "\\\\%"; // gives: "\\%" (we are using a string form with E so we need to double backslashes here)
return true;
}
else
if( val == '_' )
{
stream << "\\\\_"; // gives: "\\_"
return true;
}
else
if( val == '\\' )
{
stream << "\\\\\\\\"; // gives: "\\\\"
return true;
}
}
}
if( val == '\\' )
{
stream << "\\\\";
return true;
}
else
if( val == '\'' )
{
stream << "\\\'"; // don't use "''" because we use the method for PQconnectdb too
return true;
}
else
if( val == 0 )
{
// may put the replacement character to the stream?
return true;
}
void PostgreSQLExpression::esc(const pt::Date & date, pt::TextStream & stream, const FT & field_type)
{
stream << date << "+00";
return false;
}
DbExpression & PostgreSQLExpression::page(pt::TextStream & stream, size_t page_number, size_t page_size)
{
stream << " offset " << page_number << " limit " << page_size << " ";
stream << " OFFSET " << (page_number*page_size) << " LIMIT " << page_size << " ";
return *this;
}

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2018-2021, Tomasz Sowa
* Copyright (c) 2018-2022, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_postgresqlexpression
#define headerfile_morm_postgresqlexpression
#ifndef headerfile_morm_src_postgresqlexpression
#define headerfile_morm_src_postgresqlexpression
#include "dbexpression.h"
@ -45,9 +45,6 @@ class PostgreSQLExpression : public DbExpression
{
public:
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);
@ -58,9 +55,10 @@ protected:
private:
void before_field_value_string(const FT & field_type);
void after_field_value_string(const FT & field_type);
void before_field_value_string(const FT & field_type, ModelEnv * model_env);
void after_field_value_string(const FT & field_type, ModelEnv * model_env);
bool esc_char(wchar_t val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env);
};

View File

@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_postgresqlqueryresult
#define headerfile_morm_postgresqlqueryresult
#ifndef headerfile_morm_src_postgresqlqueryresult
#define headerfile_morm_src_postgresqlqueryresult
#include "queryresult.h"
#include <libpq-fe.h>

View File

@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_queryresult
#define headerfile_morm_queryresult
#ifndef headerfile_morm_src_queryresult
#define headerfile_morm_src_queryresult
#include <log/log.h>
#include <string>

130
src/select.h Normal file
View File

@ -0,0 +1,130 @@
/*
* This file is a part of morm
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2022-2023, 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_src_select
#define headerfile_morm_src_select
namespace morm
{
/*
* additional arguments for Finder::select method
*/
class Select
{
public:
enum SelectType
{
default_type = 0,
no_auto_generated_columns = 1,
with_rows_counter = 2,
distinct = 4,
};
/*
* type can be a superposition from SelectType values
*/
int type;
Select()
{
type = 0;
}
Select(const Select & select_type)
{
this->type = select_type.type;
}
Select(SelectType select_type)
{
this->type = static_cast<int>(select_type);
}
Select(int type)
{
this->type = type;
}
Select & operator=(const Select & select_type)
{
type = select_type.type;
return *this;
}
Select & operator=(SelectType select_type)
{
this->type = static_cast<int>(select_type);
return *this;
}
Select & operator=(int type)
{
this->type = type;
return *this;
}
bool is_flag_set(int flag_mask) const
{
return (type & flag_mask) != 0;
}
bool is_with_rows_counter() const
{
return is_flag_set(with_rows_counter);
}
bool is_no_auto_generated_columns() const
{
return is_flag_set(no_auto_generated_columns);
}
bool is_distinct() const
{
return is_flag_set(distinct);
}
};
}
#endif

View File

@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_spacewrapper
#define headerfile_morm_spacewrapper
#ifndef headerfile_morm_src_spacewrapper
#define headerfile_morm_src_spacewrapper
#include <vector>
#include <limits>

285
src/transaction.cpp Normal file
View File

@ -0,0 +1,285 @@
/*
* This file is a part of morm
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2022, 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.
*
*/
#include "transaction.h"
#include "dbconnector.h"
namespace morm
{
Transaction::Transaction(ModelConnector * model_connector, bool auto_begin_transaction)
{
this->model_connector = model_connector;
is_transaction_started = false;
is_transaction_successful = true;
transaction_index = 0;
transaction_group = 0;
if( auto_begin_transaction )
{
begin();
}
}
Transaction::Transaction(const Transaction &)
{
// at the moment do not allow to copy transactions (make me private)
}
Transaction::Transaction(Transaction &&)
{
// at the moment do not allow to move transactions (make me private)
}
Transaction::~Transaction()
{
if( is_current_group() && is_transaction_started )
{
rollback();
}
}
bool Transaction::is_started()
{
return is_current_group() && is_transaction_started;
}
bool Transaction::is_successful()
{
return is_transaction_successful;
}
void Transaction::set_successful(bool is_successful)
{
is_transaction_successful = is_successful;
}
bool Transaction::begin()
{
bool status = false;
pt::Log * log = get_logger();
if( is_current_group() && is_transaction_started )
{
if( log )
{
(*log) << pt::Log::log2 << "Morm: a transaction is already started - rollbacking existing transaction before creating a new one" << pt::Log::logend;
}
rollback(); // what if there is an error here? skip it at the moment
}
if( model_connector )
{
DbConnector * db_connector = model_connector->get_db_connector();
if( db_connector )
{
status = db_connector->begin();
transaction_index = db_connector->get_transaction_index();
transaction_group = db_connector->get_transaction_group();
}
}
if( status )
{
is_transaction_started = true;
is_transaction_successful = true;
}
else
{
is_transaction_started = false;
is_transaction_successful = false;
}
return status;
}
bool Transaction::begin_if_needed()
{
bool status = true;
if( !is_transaction_started )
{
status = begin();
}
return status;
}
bool Transaction::rollback()
{
bool status = false;
pt::Log * log = get_logger();
if( is_current_group() )
{
if( is_transaction_started )
{
if( model_connector )
{
DbConnector * db_connector = model_connector->get_db_connector();
if( db_connector )
{
status = db_connector->rollback(transaction_index);
}
}
// set it to false even if rollback failed
is_transaction_started = false;
}
else
{
if( log )
{
(*log) << pt::Log::log1 << "Morm: not doing rollback, a transaction was not started - skipping" << pt::Log::logend;
}
}
}
else
{
if( log )
{
(*log) << pt::Log::log1 << "Morm: not doing rollback, this transaction has already been completed" << pt::Log::logend;
}
}
return status;
}
bool Transaction::commit()
{
bool status = false;
pt::Log * log = get_logger();
if( is_current_group() )
{
if( is_transaction_started )
{
if( model_connector )
{
DbConnector * db_connector = model_connector->get_db_connector();
if( db_connector )
{
status = db_connector->commit(transaction_index);
}
}
// set it to false even if commit failed
is_transaction_started = false;
}
else
{
if( log )
{
(*log) << pt::Log::log1 << "Morm: not doing commit, a transaction was not started - skipping" << pt::Log::logend;
}
}
}
else
{
if( log )
{
(*log) << pt::Log::log1 << "Morm: not doing commit, this transaction has already been completed" << pt::Log::logend;
}
}
return status;
}
bool Transaction::finish()
{
bool status = false;
if( is_transaction_successful )
status = commit();
else
status = rollback();
return status;
}
pt::Log * Transaction::get_logger()
{
pt::Log * logger = nullptr;
if( model_connector )
{
logger = model_connector->get_logger();
}
return logger;
}
bool Transaction::is_current_group()
{
if( model_connector )
{
DbConnector * db_connector = model_connector->get_db_connector();
if( db_connector )
{
return (db_connector->get_transaction_group() == transaction_group);
}
}
return false;
}
} // namespace

89
src/transaction.h Normal file
View File

@ -0,0 +1,89 @@
/*
* This file is a part of morm
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2022, 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_src_transaction
#define headerfile_morm_src_transaction
#include "log/log.h"
#include "modelconnector.h"
namespace morm
{
class Transaction
{
public:
Transaction(ModelConnector * model_connector, bool auto_begin_transaction = true);
virtual ~Transaction();
virtual bool is_started();
virtual bool is_successful();
virtual void set_successful(bool is_successful = true);
virtual bool begin();
virtual bool begin_if_needed();
virtual bool rollback();
virtual bool commit();
virtual bool finish();
virtual bool is_current_group();
protected:
ModelConnector * model_connector;
bool is_transaction_started;
bool is_transaction_successful;
size_t transaction_index;
size_t transaction_group;
virtual pt::Log * get_logger();
private:
Transaction(const Transaction &);
Transaction(Transaction &&);
};
} // namespace
#endif

44
src/version.h Normal file
View File

@ -0,0 +1,44 @@
/*
* This file is a part of morm
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2022, 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_src_version
#define headerfile_morm_src_version
#define MORM_VERSION_MAJOR 0
#define MORM_VERSION_MINOR 7
#define MORM_VERSION_PATCH 0
#endif

View File

@ -32,8 +32,8 @@
*
*/
#ifndef headerfile_morm_wrapper
#define headerfile_morm_wrapper
#ifndef headerfile_morm_src_wrapper
#define headerfile_morm_src_wrapper
#include "spacewrapper.h"
#include "date/date.h"

168
src/xmlconnector.cpp Normal file
View File

@ -0,0 +1,168 @@
/*
* This file is a part of morm
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2022-2023, 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.
*
*/
#include "xmlconnector.h"
#include "xmlexpression.h"
namespace morm
{
XMLConnector::XMLConnector()
{
put_doctype = true;
put_root_element = true;
}
void XMLConnector::set_putting_doctype(bool put_doctype)
{
this->put_doctype = put_doctype;
}
void XMLConnector::set_putting_root_element(bool put_root_element)
{
this->put_root_element = put_root_element;
}
bool XMLConnector::get_putting_doctype()
{
return put_doctype;
}
bool XMLConnector::get_putting_root_element()
{
return put_root_element;
}
void XMLConnector::set_root_element(const wchar_t * root_name)
{
root_element_name = root_name;
}
void XMLConnector::set_root_element(const std::wstring & root_name)
{
root_element_name = root_name;
}
std::wstring & XMLConnector::get_root_element()
{
return root_element_name;
}
void XMLConnector::allocate_default_expression()
{
deallocate_expression();
flat_expression = new XMLExpression();
expression_allocated = true;
}
void XMLConnector::to_text(pt::TextStream & stream, Model & model, Export exp)
{
allocate_default_expression_if_needed();
if( flat_expression )
{
flat_expression->clear();
flat_expression->set_work_mode(MORM_WORK_MODE_MODEL_FIELDS_VALUES_FIELDS);
flat_expression->allow_to_use_prefix(false);
put_doctype_definition(stream);
put_opening_root_element(stream);
flat_expression->generate_from_model(stream, model);
put_closing_root_element(stream);
}
}
void XMLConnector::put_doctype_definition(pt::TextStream & stream)
{
if( put_doctype )
{
stream << L"<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
}
}
void XMLConnector::put_opening_root_element(pt::TextStream & stream)
{
if( put_root_element )
{
stream << L"<";
put_root_element_name(stream);
stream << L">";
}
}
void XMLConnector::put_closing_root_element(pt::TextStream & stream)
{
if( put_root_element )
{
stream << L"</";
put_root_element_name(stream);
stream << L">";
}
}
void XMLConnector::put_root_element_name(pt::TextStream & stream)
{
if( root_element_name.empty() )
{
stream << L"xml";
}
else
{
if( flat_expression )
{
flat_expression->esc(root_element_name, stream, FT::default_type, nullptr);
}
}
}
}

80
src/xmlconnector.h Normal file
View File

@ -0,0 +1,80 @@
/*
* This file is a part of morm
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2022-2023, 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_src_xmlconnector
#define headerfile_morm_src_xmlconnector
#include "flatconnector.h"
namespace morm
{
class XMLConnector : public FlatConnector
{
public:
XMLConnector();
virtual void set_putting_doctype(bool put_doctype);
virtual void set_putting_root_element(bool put_root_element);
virtual bool get_putting_doctype();
virtual bool get_putting_root_element();
virtual void set_root_element(const wchar_t * root_name);
virtual void set_root_element(const std::wstring & root_name);
virtual std::wstring & get_root_element();
void to_text(pt::TextStream & stream, Model & model, Export exp);
protected:
bool put_doctype;
bool put_root_element;
std::wstring root_element_name;
void allocate_default_expression();
virtual void put_doctype_definition(pt::TextStream & stream);
virtual void put_opening_root_element(pt::TextStream & stream);
virtual void put_closing_root_element(pt::TextStream & stream);
virtual void put_root_element_name(pt::TextStream & stream);
};
}
#endif

143
src/xmlexpression.cpp Normal file
View File

@ -0,0 +1,143 @@
/*
* This file is a part of morm
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2022-2023, 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.
*
*/
#include "xmlexpression.h"
#include "morm_types.h"
#include "convert/misc.h"
namespace morm
{
void XMLExpression::before_field_name()
{
(*out_stream) << "<";
}
void XMLExpression::after_field_name()
{
(*out_stream) << ">";
}
void XMLExpression::before_field_value(const pt::Space &, const FT & field_type, ModelEnv * model_env)
{
if( field_type.is_space() )
{
//before_field_value_string(field_type, model_env);
}
}
void XMLExpression::after_field_value(const pt::Space &, const FT & field_type, ModelEnv * model_env)
{
if( field_type.is_space() )
{
//after_field_value_string(field_type, model_env);
}
}
void XMLExpression::put_field_closing_name(const wchar_t * field_name, const FT & field_type, ModelEnv * model_env)
{
if( field_type.is_raw_field_name() )
{
(*out_stream) << '/';
(*out_stream) << field_name;
}
else
{
before_field_name();
(*out_stream) << '/';
esc(field_name, *out_stream, FT::default_type, nullptr); /* do not use provided field_type here - it would use e.g. binary mode if it was set, similar don't use model_env */
after_field_name();
}
}
void XMLExpression::put_name_value_separator()
{
}
bool XMLExpression::esc_char(wchar_t val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
return pt::try_esc_to_xml(val, stream);
}
void XMLExpression::esc(const pt::Space & space, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env)
{
bool pretty_print = field_type.is_pretty_print();
if( field_type.is_space() )
{
pt::WTextStream tmp_stream;
space.serialize_to_space_stream(tmp_stream, pretty_print);
BaseExpression::esc(tmp_stream, stream, field_type, model_env);
}
else
{
/*
* IMPROVEME it would be better to serialize to xml
*
*/
pt::WTextStream tmp_stream;
space.serialize_to_json_stream(tmp_stream, pretty_print);
BaseExpression::esc(tmp_stream, stream, field_type, model_env);
}
}
void XMLExpression::put_value_list_opening_index(size_t index, const FT & field_type)
{
(*out_stream) << L"<item index=\"" << index << L"\">";
}
void XMLExpression::put_value_list_closing_index(size_t index, const FT & field_type)
{
(*out_stream) << L"</item>";
}
void XMLExpression::field_value_list_separator()
{
}
}

76
src/xmlexpression.h Normal file
View File

@ -0,0 +1,76 @@
/*
* This file is a part of morm
* and is distributed under the 2-Clause BSD licence.
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
* Copyright (c) 2022-2023, 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_src_xmlexpression
#define headerfile_morm_src_xmlexpression
#include "flatexpression.h"
namespace morm
{
class XMLExpression : public FlatExpression
{
protected:
void put_field_closing_name(const wchar_t * field_name, const FT & field_type, ModelEnv * model_env);
void before_field_name();
void after_field_name();
void put_name_value_separator();
using BaseExpression::esc;
bool esc_char(wchar_t val, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env);
void esc(const pt::Space & space, pt::TextStream & stream, const FT & field_type, ModelEnv * model_env);
private:
void before_field_value(const pt::Space &, const FT & field_type, ModelEnv * model_env);
void after_field_value(const pt::Space &, const FT & field_type, ModelEnv * model_env);
void put_value_list_opening_index(size_t index, const FT & field_type);
void put_value_list_closing_index(size_t index, const FT & field_type);
void field_value_list_separator();
};
}
#endif