winix_fullmorm #4
|
@ -3,3 +3,6 @@
|
|||
.settings/
|
||||
*.o
|
||||
*.a
|
||||
log.txt
|
||||
samples/log.txt
|
||||
samples/mormsample
|
||||
|
|
|
@ -7,13 +7,13 @@ GLOBAL_WORKING_DIR := $(shell pwd)/../..
|
|||
endif
|
||||
|
||||
|
||||
CXX = g++7
|
||||
CXX = g++10
|
||||
#CXX = clang++
|
||||
|
||||
# -fsanitize=address
|
||||
# -Wl,-rpath=/usr/local/lib/gcc5 or just compile with -static-libstdc++
|
||||
|
||||
CXXFLAGS = -Wl,-rpath=/usr/local/lib/gcc7 -Wfatal-errors -fPIC -Wall -pedantic -O0 -g3 -gdwarf-2 -pthread -std=c++17 -I/usr/local/include -I$(GLOBAL_WORKING_DIR)/pikotools -I$(GLOBAL_WORKING_DIR)/morm/src
|
||||
CXXFLAGS = -Wl,-rpath=/usr/local/lib/gcc10 -Wfatal-errors -fPIC -Wall -pedantic -O0 -g3 -gdwarf-2 -pthread -std=c++20 -I/usr/local/include -I$(GLOBAL_WORKING_DIR)/pikotools -I$(GLOBAL_WORKING_DIR)/morm/src
|
||||
LDFLAGS = -L/usr/local/lib
|
||||
|
||||
|
||||
|
|
|
@ -20,4 +20,4 @@ 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
|
||||
main.o: attachment.h type.h attachment2.h
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019, Tomasz Sowa
|
||||
* Copyright (c) 2019-2021, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -38,7 +38,7 @@
|
|||
#include <string>
|
||||
#include "morm.h"
|
||||
#include "type.h"
|
||||
|
||||
#include "language.h"
|
||||
|
||||
|
||||
namespace morm
|
||||
|
@ -54,7 +54,7 @@ CREATE TABLE public.attachment (
|
|||
content text,
|
||||
some_flags bool,
|
||||
created_date timestamp with time zone,
|
||||
bigint language_id,
|
||||
language_id bigint,
|
||||
|
||||
primary key(id)
|
||||
);
|
||||
|
@ -82,7 +82,6 @@ public:
|
|||
field(L"name", name);
|
||||
field(L"content", content);
|
||||
field(L"attachment_id", L"types", types);
|
||||
//field(L"types", types);
|
||||
field(L"some_flags", some_flags);
|
||||
field(L"created_date", created_date);
|
||||
field(L"language_id", L"language", language);
|
||||
|
@ -94,9 +93,18 @@ public:
|
|||
stream << "public.attachment";
|
||||
}
|
||||
|
||||
void after_select()
|
||||
{
|
||||
if( has_primary_key_set )
|
||||
{
|
||||
morm::Finder<Type> finder(model_connector);
|
||||
types = finder.select().where().eq(L"attachment_id", id).get_vector();
|
||||
}
|
||||
}
|
||||
|
||||
void after_insert()
|
||||
{
|
||||
get_last_sequence(L"public.attachment_id_seq", id);
|
||||
get_last_sequence_for_primary_key(L"public.attachment_id_seq", id);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* 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) 2021, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef headerfile_morm_samples_attachment2
|
||||
#define headerfile_morm_samples_attachment2
|
||||
|
||||
#include <string>
|
||||
#include "morm.h"
|
||||
#include "type.h"
|
||||
#include "language.h"
|
||||
|
||||
|
||||
namespace morm
|
||||
{
|
||||
namespace samples
|
||||
{
|
||||
|
||||
/*
|
||||
CREATE TABLE public.attachment2 (
|
||||
id bigserial,
|
||||
person_id bigint,
|
||||
name varchar(64),
|
||||
content text,
|
||||
some_flags bool,
|
||||
created_date timestamp with time zone,
|
||||
language_id bigint,
|
||||
|
||||
primary key(id)
|
||||
);
|
||||
*/
|
||||
|
||||
// copied from Attachment and changed the table name
|
||||
class Attachment2 : public morm::Model
|
||||
{
|
||||
public:
|
||||
|
||||
long id;
|
||||
long person_id;
|
||||
std::wstring name;
|
||||
std::string content;
|
||||
std::vector<Type> types;
|
||||
bool some_flags;
|
||||
PT::Date created_date;
|
||||
Language language;
|
||||
|
||||
|
||||
void map_fields()
|
||||
{
|
||||
field(L"id", id, false, false, true);
|
||||
field(L"person_id", person_id);
|
||||
field(L"name", name);
|
||||
field(L"content", content);
|
||||
field(L"attachment_id", L"types", types);
|
||||
field(L"some_flags", some_flags);
|
||||
field(L"created_date", created_date);
|
||||
field(L"language_id", L"language", language);
|
||||
}
|
||||
|
||||
void table_name(PT::TextStream & stream)
|
||||
{
|
||||
// schema.table_name or just table_name
|
||||
stream << "public.attachment2";
|
||||
}
|
||||
|
||||
void after_select()
|
||||
{
|
||||
if( has_primary_key_set )
|
||||
{
|
||||
morm::Finder<Type> finder(model_connector);
|
||||
types = finder.select().where().eq(L"attachment_id", id).get_vector();
|
||||
}
|
||||
}
|
||||
|
||||
void after_insert()
|
||||
{
|
||||
get_last_sequence_for_primary_key(L"public.attachment2_id_seq", id);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019, Tomasz Sowa
|
||||
* Copyright (c) 2019-2021, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -86,7 +86,7 @@ public:
|
|||
|
||||
void after_insert()
|
||||
{
|
||||
get_last_sequence(L"public.language_id_seq", id);
|
||||
get_last_sequence_for_primary_key(L"public.language_id_seq", id);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019, Tomasz Sowa
|
||||
* Copyright (c) 2019-2021, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -39,6 +39,7 @@
|
|||
#include "morm.h"
|
||||
#include "language.h"
|
||||
#include "attachment.h"
|
||||
#include "attachment2.h"
|
||||
|
||||
|
||||
|
||||
|
@ -64,29 +65,31 @@ class Person : public morm::Model
|
|||
public:
|
||||
|
||||
long id;
|
||||
|
||||
std::wstring first_name;
|
||||
std::wstring last_name;
|
||||
std::wstring email;
|
||||
Language language;
|
||||
|
||||
std::list<Attachment> attachments;
|
||||
Attachment attachment;
|
||||
Attachment2 attachment2;
|
||||
|
||||
|
||||
void map_fields()
|
||||
{
|
||||
field(L"id", id, false, false, true);
|
||||
//field(L"id", id, f::no_insertable | f::no_updatable | f::primary_key);
|
||||
field(L"language_id", L"language", language);
|
||||
|
||||
field(L"first_name", first_name);
|
||||
field(L"last_name", last_name);
|
||||
field(L"email", email);
|
||||
field(L"language_id", L"language", language);
|
||||
|
||||
field(L"person_id", L"attachments", attachments);
|
||||
|
||||
field(L"person_id", L"attachment", attachment, true, true, false);
|
||||
field(L"person_id", L"attachment2", attachment2, true, true, false);
|
||||
|
||||
|
||||
//field(L"id", id, f::no_insertable | f::no_updatable | f::primary_key);
|
||||
//field(L"person_id", attachment, f::insertable | f::updatable | f::foreign_key);
|
||||
//field(L"person_id", attachment, f::insertable, f::updatable, f::foreign_key);
|
||||
}
|
||||
|
@ -99,13 +102,19 @@ public:
|
|||
|
||||
void after_select()
|
||||
{
|
||||
morm::Finder<Attachment> finder(model_connector);
|
||||
attachments = finder.select().where().eq(L"person_id", id).get_list();
|
||||
if( has_primary_key_set )
|
||||
{
|
||||
morm::Finder<Attachment> finder(model_connector);
|
||||
attachments = finder.select().where().eq(L"person_id", id).get_list();
|
||||
|
||||
morm::Finder<Attachment2> finder2(model_connector);
|
||||
attachment2 = finder2.select().where().eq(L"person_id", id).get();
|
||||
}
|
||||
}
|
||||
|
||||
void after_insert()
|
||||
{
|
||||
get_last_sequence(L"public.person_id_seq", id);
|
||||
get_last_sequence_for_primary_key(L"public.person_id_seq", id);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019, Tomasz Sowa
|
||||
* Copyright (c) 2019-2021, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -51,23 +51,37 @@ public:
|
|||
|
||||
void make()
|
||||
{
|
||||
// delete all datas
|
||||
// delete from attachment; delete from attachment2; delete from language; delete from person; delete from types;
|
||||
|
||||
// select * from person; select * from attachment; select * from attachment2 ; select * from types; select * from language;
|
||||
|
||||
std::string str;
|
||||
|
||||
|
||||
person.set_connector(model_connector);
|
||||
load_defaults(person);
|
||||
|
||||
std::wstring sss = L"cosik wstawiony dynamicznie";
|
||||
person.set_field_value_generic(L"email", L"email", sss);
|
||||
//std::wstring sss = L"cosik wstawiony dynamicznie";
|
||||
//person.set_field_value_generic(L"email", L"email", sss);
|
||||
|
||||
|
||||
|
||||
//person.insert();
|
||||
//person.update();
|
||||
person.save();
|
||||
//person.save();
|
||||
//person.remove();
|
||||
//person.to_text(str, true, true);
|
||||
|
||||
|
||||
morm::Finder<Person> finder(model_connector);
|
||||
Person p = finder.select().where().eq(L"id", 191).get();
|
||||
p.to_text(str, true, true);
|
||||
|
||||
|
||||
|
||||
//std::list<Person> plist = finder.use_table_prefix(false).select().where().eq(L"id", 120).get_list();
|
||||
|
||||
//Person p = finder.use_table_prefix(false).select().where().eq(L"id", 120).get();
|
||||
|
||||
// Person p = finder.prepare_to_select().use_table_prefix(true).raw("select person.id as \"person.id\", person.first_name as \"person.first_name\", person.last_name as \"person.last_name\", person.email as \"person.email\", "
|
||||
// "language.id as \"language.id\", language.english_name as \"language.english_name\", language.local_name as \"language.local_name\", language.code_str as \"language.code_str\", language.code_int as \"language.code_int\", "
|
||||
|
@ -79,14 +93,13 @@ void make()
|
|||
// "LEFT JOIN public.language AS language2 ON attachment.language_id = language2.id "
|
||||
// "where person.id=120").get();
|
||||
|
||||
std::cout << "--------------------------------" << std::endl;
|
||||
//std::cout << "--------------------------------" << std::endl;
|
||||
//p.remove();
|
||||
//std::cout << "--------------------------------" << std::endl;
|
||||
|
||||
std::string str;
|
||||
//str += "--------\n";
|
||||
|
||||
person.to_text(str, true, true);
|
||||
|
||||
|
||||
// for(Person & person : plist)
|
||||
// {
|
||||
|
@ -112,6 +125,7 @@ private:
|
|||
person.first_name = L"MyFirstName";
|
||||
person.last_name = L"MyLastName";
|
||||
person.email = L"myemail@mydomain.ltd";
|
||||
//person.set_save_mode(Model::DO_NOTHING_ON_SAVE);
|
||||
person.set_save_mode(Model::DO_INSERT_ON_SAVE);
|
||||
//person.set_save_mode(Model::DO_UPDATE_ON_SAVE);
|
||||
|
||||
|
@ -120,29 +134,38 @@ private:
|
|||
person.language.local_name = L"polish";
|
||||
person.language.code_str = L"en";
|
||||
person.language.code_int = 200;
|
||||
//person.language.set_save_mode(Model::DO_NOTHING_ON_SAVE);
|
||||
person.language.set_save_mode(Model::DO_INSERT_ON_SAVE);
|
||||
//person.language.set_save_mode(Model::DO_UPDATE_ON_SAVE);
|
||||
|
||||
std::time_t t = std::time(0);
|
||||
|
||||
// person.attachment.id = 40;
|
||||
person.attachment.person_id = person.id;
|
||||
person.attachment.created_date.FromTime(t);
|
||||
person.attachment.name = L"attachment name";
|
||||
person.attachment.content = "long binary content";
|
||||
person.attachment.some_flags = true;
|
||||
person.attachment.set_save_mode(Model::DO_INSERT_ON_SAVE);
|
||||
// //person.attachment.set_save_mode(Model::DO_UPDATE_ON_SAVE);
|
||||
//
|
||||
person.attachment.language.id = 86;
|
||||
person.attachment.language.english_name = L"attachment language";
|
||||
person.attachment.language.local_name = L"attachment local name";
|
||||
person.attachment.language.code_str = L"loen";
|
||||
person.attachment.language.code_int = 300;
|
||||
// person.attachment.language.set_save_mode(Model::DO_UPDATE_ON_SAVE);
|
||||
|
||||
Type type;
|
||||
type.id = 0;
|
||||
type.set_save_mode(Model::DO_INSERT_ON_SAVE);
|
||||
|
||||
person.attachment2.id = 40;
|
||||
person.attachment2.person_id = person.id;
|
||||
person.attachment2.created_date.FromTime(t);
|
||||
person.attachment2.name = L"attachment name";
|
||||
person.attachment2.content = "long binary content";
|
||||
person.attachment2.some_flags = true;
|
||||
person.attachment2.set_save_mode(Model::DO_INSERT_ON_SAVE);
|
||||
// //person.attachment.set_save_mode(Model::DO_UPDATE_ON_SAVE);
|
||||
|
||||
person.attachment2.language.id = 86;
|
||||
person.attachment2.language.english_name = L"attachment language";
|
||||
person.attachment2.language.local_name = L"attachment local name";
|
||||
person.attachment2.language.code_str = L"loen";
|
||||
person.attachment2.language.code_int = 300;
|
||||
person.attachment2.language.set_save_mode(Model::DO_INSERT_ON_SAVE);
|
||||
person.attachment2.language.set_has_primary_key_set(true);
|
||||
|
||||
type.name = L"abcde - fghi";
|
||||
person.attachment2.types.push_back(type);
|
||||
|
||||
type.name = L"second type";
|
||||
person.attachment2.types.push_back(type);
|
||||
|
||||
Attachment attachment;
|
||||
attachment.id = 0;
|
||||
|
@ -186,7 +209,6 @@ private:
|
|||
type.name = L"Typ dla attachment 3 - 3";
|
||||
person.attachments.back().types.push_back(type);
|
||||
|
||||
|
||||
//type.name = L"Typik";
|
||||
//person.attachment.types.push_back(type);
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019, Tomasz Sowa
|
||||
* Copyright (c) 2019-2021, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -79,7 +79,7 @@ public:
|
|||
|
||||
void after_insert()
|
||||
{
|
||||
get_last_sequence(L"public.types_id_seq", id);
|
||||
get_last_sequence_for_primary_key(L"public.types_id_seq", id);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -118,6 +118,7 @@ void BaseExpression::dump_additional_info(Model & model)
|
|||
if( model.model_env && model.model_env->dump_mode )
|
||||
{
|
||||
field(L"model_save_mode", model.save_mode, false, false, false, model.model_env);
|
||||
field(L"has_primary_key_set", model.has_primary_key_set, false, false, false, model.model_env);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ public:
|
|||
else
|
||||
if( work_mode == MORM_WORK_MODE_MODEL_VALUES )
|
||||
{
|
||||
put_field_value(field_value);
|
||||
put_field_value_or_null(field_value, is_primary_key, model_env);
|
||||
}
|
||||
else
|
||||
if( work_mode == MORM_WORK_MODE_MODEL_FIELDS_VALUES )
|
||||
|
@ -102,7 +102,7 @@ public:
|
|||
{
|
||||
put_field_name((*model_env->set_field_name_helper)[model_env->field_index], model_env);
|
||||
put_name_value_separator();
|
||||
put_field_value(field_value);
|
||||
put_field_value_or_null(field_value, is_primary_key, model_env);
|
||||
}
|
||||
|
||||
model_env->field_index += 1;
|
||||
|
@ -111,7 +111,7 @@ public:
|
|||
{
|
||||
put_field_name(field_name, model_env);
|
||||
put_name_value_separator();
|
||||
put_field_value(field_value);
|
||||
put_field_value_or_null(field_value, is_primary_key, model_env);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -121,6 +121,22 @@ public:
|
|||
}
|
||||
|
||||
|
||||
template<typename FieldValue>
|
||||
void put_field_value_or_null(const FieldValue & field_value, bool is_primary_key, ModelEnv * model_env)
|
||||
{
|
||||
if( is_primary_key )
|
||||
{
|
||||
if( model_env && model_env->has_primary_key_set )
|
||||
put_field_value(field_value);
|
||||
else
|
||||
put_null_value();
|
||||
}
|
||||
else
|
||||
{
|
||||
put_field_value(field_value);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename FieldValue>
|
||||
void field_in(PT::TextStream & stream, const wchar_t * field_name, const std::set<FieldValue> & container, ModelEnv * model_env)
|
||||
{
|
||||
|
@ -282,6 +298,12 @@ protected:
|
|||
}
|
||||
|
||||
|
||||
virtual void put_null_value()
|
||||
{
|
||||
(*out_stream) << "null";
|
||||
}
|
||||
|
||||
|
||||
virtual void before_field_value_list()
|
||||
{
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ public:
|
|||
|
||||
|
||||
template<typename FieldValue>
|
||||
void get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value)
|
||||
bool get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value)
|
||||
{
|
||||
const char * val_str = query_last_sequence(sequence_table_name);
|
||||
|
||||
|
@ -122,7 +122,11 @@ public:
|
|||
{
|
||||
(*log) << PT::Log::log3 << "Morm: sequence value: " << field_value << PT::Log::logend;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -105,8 +105,6 @@ void JSONExpression::after_second_part_long_field_name()
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void JSONExpression::before_field_value_string()
|
||||
{
|
||||
(*out_stream) << "\"";
|
||||
|
|
178
src/model.cpp
178
src/model.cpp
|
@ -43,6 +43,7 @@ Model::Model()
|
|||
model_connector = nullptr;
|
||||
model_env = nullptr;
|
||||
save_mode = DO_INSERT_ON_SAVE;
|
||||
has_primary_key_set = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -50,7 +51,8 @@ Model::Model(const Model & m)
|
|||
{
|
||||
model_connector = m.model_connector;
|
||||
save_mode = m.save_mode;
|
||||
model_env = m.model_env; // or just set to null?
|
||||
model_env = nullptr;
|
||||
has_primary_key_set = m.has_primary_key_set;
|
||||
}
|
||||
|
||||
|
||||
|
@ -71,6 +73,19 @@ Model::SaveMode Model::get_save_mode()
|
|||
}
|
||||
|
||||
|
||||
void Model::set_has_primary_key_set(bool has_primary_key)
|
||||
{
|
||||
this->has_primary_key_set = has_primary_key;
|
||||
}
|
||||
|
||||
|
||||
bool Model::get_has_primary_key_set()
|
||||
{
|
||||
return this->has_primary_key_set;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Model::mark_to_delete()
|
||||
{
|
||||
save_mode = DO_DELETE_ON_SAVE;
|
||||
|
@ -140,8 +155,10 @@ void Model::to_text(PT::TextStream & stream, ModelData * model_data, bool clear_
|
|||
ModelEnv model_env_local;
|
||||
model_env = &model_env_local;
|
||||
|
||||
model_env->has_primary_key_set = has_primary_key_set;
|
||||
model_env->model_work_mode = MORM_MODEL_WORK_MODE_GENERATING_FLAT_STRING;
|
||||
model_env->dump_mode = dump_mode;
|
||||
model_env->model_data = model_data;
|
||||
|
||||
if( model_connector )
|
||||
{
|
||||
|
@ -149,13 +166,18 @@ void Model::to_text(PT::TextStream & stream, ModelData * model_data, bool clear_
|
|||
|
||||
if( flat_connector )
|
||||
{
|
||||
model_env->model_data = model_data;
|
||||
flat_connector->to_text(stream, *this);
|
||||
model_env->model_data = nullptr;
|
||||
try
|
||||
{
|
||||
flat_connector->to_text(stream, *this);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
model_env = nullptr;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// what about if an exception was thrown? this pointer will not be null
|
||||
model_env = nullptr;
|
||||
}
|
||||
|
||||
|
@ -221,6 +243,7 @@ void Model::generate_insert_query(PT::TextStream & stream, ModelData * model_dat
|
|||
{
|
||||
ModelEnv model_env_local;
|
||||
model_env = &model_env_local;
|
||||
model_env->has_primary_key_set = has_primary_key_set;
|
||||
model_env->model_data = model_data;
|
||||
model_env->model_work_mode = MORM_MODEL_WORK_MODE_GENERATING_DB_SQL;
|
||||
|
||||
|
@ -230,11 +253,18 @@ void Model::generate_insert_query(PT::TextStream & stream, ModelData * model_dat
|
|||
|
||||
if( db_connector )
|
||||
{
|
||||
db_connector->generate_insert_query(stream, *this);
|
||||
try
|
||||
{
|
||||
db_connector->generate_insert_query(stream, *this);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
model_env = nullptr;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// what about if an exception was thrown? this pointer will not be null
|
||||
model_env = nullptr;
|
||||
}
|
||||
|
||||
|
@ -257,11 +287,19 @@ bool Model::insert(ModelData * model_data, bool insert_whole_tree)
|
|||
model_env = &model_env_local;
|
||||
|
||||
model_env->model_data = model_data;
|
||||
bool status = insert_tree(insert_whole_tree);
|
||||
bool status = false;
|
||||
|
||||
try
|
||||
{
|
||||
status = insert_tree(insert_whole_tree);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
model_env = nullptr;
|
||||
throw;
|
||||
}
|
||||
|
||||
// what about if an exception was thrown? this pointer will not be null
|
||||
model_env = nullptr;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -271,6 +309,8 @@ bool Model::insert(ModelData * model_data, bool insert_whole_tree)
|
|||
bool Model::insert_tree(bool insert_whole_tree)
|
||||
{
|
||||
bool result = false;
|
||||
has_primary_key_set = false; // the key will be overwritten (the database will create a new key)
|
||||
model_env->has_primary_key_set = false;
|
||||
|
||||
if( insert_whole_tree )
|
||||
{
|
||||
|
@ -296,9 +336,21 @@ bool Model::insert_tree(bool insert_whole_tree)
|
|||
|
||||
if( result )
|
||||
{
|
||||
save_mode = DO_UPDATE_ON_SAVE; // IMPROVE ME check if there is a primary key
|
||||
/*
|
||||
* after_insert() should read the new primary key and set has_primary_key_set flag if the key was read correctly
|
||||
*/
|
||||
after_insert();
|
||||
set_parent_key_in_childs();
|
||||
model_env->has_primary_key_set = has_primary_key_set;
|
||||
|
||||
if( has_primary_key_set )
|
||||
{
|
||||
save_mode = DO_UPDATE_ON_SAVE;
|
||||
set_parent_key_in_childs(); // may it would be better to set it even if we do not have a primary key? set it to zero or something?
|
||||
}
|
||||
else
|
||||
{
|
||||
save_mode = DO_NOTHING_ON_SAVE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -323,6 +375,7 @@ void Model::generate_update_query(PT::TextStream & stream, ModelData * model_dat
|
|||
{
|
||||
ModelEnv model_env_local;
|
||||
model_env = &model_env_local;
|
||||
model_env->has_primary_key_set = has_primary_key_set;
|
||||
model_env->model_data = model_data;
|
||||
model_env->model_work_mode = MORM_MODEL_WORK_MODE_GENERATING_DB_SQL;
|
||||
|
||||
|
@ -359,11 +412,19 @@ bool Model::update(ModelData * model_data, bool update_whole_tree)
|
|||
model_env = &model_env_local;
|
||||
|
||||
model_env->model_data = model_data;
|
||||
bool status = update_tree(update_whole_tree);
|
||||
bool status = false;
|
||||
|
||||
try
|
||||
{
|
||||
status = update_tree(update_whole_tree);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
model_env = nullptr;
|
||||
throw;
|
||||
}
|
||||
|
||||
// what about if an exception was thrown? this pointer will not be null
|
||||
model_env = nullptr;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -372,6 +433,13 @@ bool Model::update(ModelData * model_data, bool update_whole_tree)
|
|||
bool Model::update_tree(bool update_whole_tree)
|
||||
{
|
||||
bool result = false;
|
||||
model_env->has_primary_key_set = has_primary_key_set;
|
||||
|
||||
if( !has_primary_key_set )
|
||||
{
|
||||
put_to_log(L"Morm: call update but model doesn't have a primary key set");
|
||||
return result;
|
||||
}
|
||||
|
||||
if( update_whole_tree )
|
||||
{
|
||||
|
@ -416,6 +484,7 @@ void Model::generate_remove_query(PT::TextStream & stream, ModelData * model_dat
|
|||
{
|
||||
ModelEnv model_env_local;
|
||||
model_env = &model_env_local;
|
||||
model_env->has_primary_key_set = has_primary_key_set;
|
||||
model_env->model_data = model_data;
|
||||
model_env->model_work_mode = MORM_MODEL_WORK_MODE_GENERATING_DB_SQL;
|
||||
|
||||
|
@ -453,11 +522,19 @@ bool Model::remove(ModelData * model_data, bool remove_whole_tree)
|
|||
model_env = &model_env_local;
|
||||
|
||||
model_env->model_data = model_data;
|
||||
bool status = remove_tree(remove_whole_tree);
|
||||
bool status = false;
|
||||
|
||||
try
|
||||
{
|
||||
status = remove_tree(remove_whole_tree);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
model_env = nullptr;
|
||||
throw;
|
||||
}
|
||||
|
||||
// what about if an exception was thrown? this pointer will not be null
|
||||
model_env = nullptr;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -466,6 +543,13 @@ bool Model::remove(ModelData * model_data, bool remove_whole_tree)
|
|||
bool Model::remove_tree(bool remove_whole_tree)
|
||||
{
|
||||
bool result = false;
|
||||
model_env->has_primary_key_set = has_primary_key_set;
|
||||
|
||||
if( !has_primary_key_set )
|
||||
{
|
||||
put_to_log(L"Morm: call remove but model doesn't have a primary key set");
|
||||
return result;
|
||||
}
|
||||
|
||||
if( remove_whole_tree )
|
||||
{
|
||||
|
@ -490,7 +574,9 @@ bool Model::remove_tree(bool remove_whole_tree)
|
|||
|
||||
if( result )
|
||||
{
|
||||
save_mode = DO_INSERT_ON_SAVE; // CHECKME may it would be better to set DO_NOTHING_ON_SAVE?
|
||||
save_mode = DO_NOTHING_ON_SAVE;
|
||||
has_primary_key_set = false;
|
||||
model_env->has_primary_key_set = false;
|
||||
after_remove();
|
||||
}
|
||||
else
|
||||
|
@ -531,11 +617,19 @@ bool Model::save(ModelData * model_data, bool save_whole_tree)
|
|||
model_env = &model_env_local;
|
||||
|
||||
model_env->model_data = model_data;
|
||||
bool status = save_tree(save_whole_tree);
|
||||
bool status = false;
|
||||
|
||||
try
|
||||
{
|
||||
status = save_tree(save_whole_tree);
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
model_env = nullptr;
|
||||
throw;
|
||||
}
|
||||
|
||||
// what about if an exception was thrown? this pointer will not be null
|
||||
model_env = nullptr;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -544,6 +638,7 @@ bool Model::save(ModelData * model_data, bool save_whole_tree)
|
|||
bool Model::save_tree(bool save_whole_tree)
|
||||
{
|
||||
bool result = false;
|
||||
model_env->has_primary_key_set = has_primary_key_set;
|
||||
|
||||
if( save_whole_tree )
|
||||
{
|
||||
|
@ -617,17 +712,20 @@ void Model::map_values_from_query()
|
|||
if( model_env )
|
||||
{
|
||||
model_env->model_work_mode = MORM_MODEL_WORK_MODE_READING_VALUE_FROM_DB_RESULTSET;
|
||||
model_env->all_fields_are_null = true;
|
||||
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
|
||||
map_fields();
|
||||
model_env->model_work_mode = MORM_MODEL_WORK_MODE_NONE;
|
||||
|
||||
if( model_env->all_fields_are_null )
|
||||
if( model_env->was_primary_key_read && model_env->has_primary_key_set )
|
||||
{
|
||||
save_mode = DO_NOTHING_ON_SAVE;
|
||||
has_primary_key_set = true;
|
||||
save_mode = DO_UPDATE_ON_SAVE;
|
||||
}
|
||||
else
|
||||
{
|
||||
save_mode = DO_UPDATE_ON_SAVE;
|
||||
has_primary_key_set = false;
|
||||
save_mode = DO_NOTHING_ON_SAVE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -640,10 +738,20 @@ void Model::clear()
|
|||
model_env = &model_env_local;
|
||||
|
||||
model_env->model_work_mode = MORM_MODEL_WORK_MODE_CLEARING_VALUE;
|
||||
map_fields();
|
||||
model_env = nullptr;
|
||||
|
||||
try
|
||||
{
|
||||
map_fields();
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
model_env = nullptr;
|
||||
throw;
|
||||
}
|
||||
|
||||
model_env = nullptr;
|
||||
save_mode = DO_INSERT_ON_SAVE;
|
||||
has_primary_key_set = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -794,6 +902,20 @@ void Model::put_table_name_with_index(PT::TextStream & str)
|
|||
}
|
||||
|
||||
|
||||
void Model::put_to_log(const wchar_t * str)
|
||||
{
|
||||
if( model_connector )
|
||||
{
|
||||
PT::Log * log = model_connector->get_logger();
|
||||
|
||||
if( log )
|
||||
{
|
||||
(*log) << str << PT::Log::logend;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Model::put_fields_to_log(PT::Log & log, const wchar_t * db_field_name, const wchar_t * flat_field_name)
|
||||
{
|
||||
bool was_db_field_put = false;
|
||||
|
|
97
src/model.h
97
src/model.h
|
@ -67,6 +67,9 @@ public:
|
|||
virtual void set_save_mode(SaveMode save_mode);
|
||||
virtual SaveMode get_save_mode();
|
||||
|
||||
virtual void set_has_primary_key_set(bool has_primary_key);
|
||||
virtual bool get_has_primary_key_set();
|
||||
|
||||
virtual void mark_to_delete();
|
||||
virtual void mark_to_remove();
|
||||
|
||||
|
@ -176,8 +179,9 @@ public:
|
|||
protected:
|
||||
|
||||
ModelConnector * model_connector;
|
||||
SaveMode save_mode;
|
||||
ModelEnv * model_env;
|
||||
SaveMode save_mode;
|
||||
bool has_primary_key_set;
|
||||
|
||||
|
||||
|
||||
|
@ -568,12 +572,12 @@ protected:
|
|||
{
|
||||
if( model_env->cursor_helper && model_env->cursor_helper->has_autogenerated_select )
|
||||
{
|
||||
get_value_by_field_index(model_env->cursor_helper->current_column, field_value);
|
||||
get_value_by_field_index(model_env->cursor_helper->current_column, field_value, is_primary_key);
|
||||
model_env->cursor_helper->current_column += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
get_value_by_field_name(db_field_name, field_value);
|
||||
get_value_by_field_name(db_field_name, field_value, is_primary_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -596,6 +600,11 @@ protected:
|
|||
{
|
||||
if( model_connector && model_env )
|
||||
{
|
||||
if( is_primary_key )
|
||||
{
|
||||
model_env->was_primary_key_read = true;
|
||||
}
|
||||
|
||||
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_SET_FIELD_VALUE )
|
||||
{
|
||||
field_generic_set_field_value(db_field_name, flat_field_name, field_value, insertable, updatable, is_primary_key);
|
||||
|
@ -748,6 +757,7 @@ protected:
|
|||
{
|
||||
ModelEnv model_env_local;
|
||||
model_env_local.copy_global_objects(*model_env);
|
||||
model_env_local.has_primary_key_set = field_model.has_primary_key_set;
|
||||
model_env_local.model_work_mode = MORM_MODEL_WORK_MODE_SET_FIELD_VALUE;
|
||||
model_env_local.field_value_helper_tab = &helper_tab;
|
||||
model_env_local.field_index = 0;
|
||||
|
@ -875,32 +885,42 @@ protected:
|
|||
{
|
||||
if( db_expression->get_work_mode() == MORM_WORK_MODE_MODEL_FIELDS && db_expression->get_output_type() == MORM_OUTPUT_TYPE_DB_INSERT )
|
||||
{
|
||||
int not_used_object = 0;
|
||||
db_expression->field(db_field_name, not_used_object, insertable, updatable, false, model_env);
|
||||
if( insertable )
|
||||
{
|
||||
int not_used_object = 0;
|
||||
db_expression->field(db_field_name, not_used_object, insertable, updatable, false, model_env);
|
||||
}
|
||||
}
|
||||
|
||||
if( db_expression->get_work_mode() == MORM_WORK_MODE_MODEL_VALUES && db_expression->get_output_type() == MORM_OUTPUT_TYPE_DB_INSERT )
|
||||
{
|
||||
db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_INSERT_PRIMARY_KEY);
|
||||
field_model.map_fields();
|
||||
db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_INSERT);
|
||||
if( insertable )
|
||||
{
|
||||
db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_INSERT_PRIMARY_KEY);
|
||||
field_model.map_fields();
|
||||
db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_INSERT);
|
||||
}
|
||||
}
|
||||
|
||||
if( db_expression->get_work_mode() == MORM_WORK_MODE_MODEL_FIELDS_VALUES && db_expression->get_output_type() == MORM_OUTPUT_TYPE_DB_UPDATE )
|
||||
{
|
||||
std::vector<const wchar_t *> key_fields;
|
||||
key_fields.push_back(db_field_name); // at the moment only one key
|
||||
|
||||
db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_UPDATE_PRIMARY_KEY);
|
||||
field_model.model_env->field_index = 0;
|
||||
field_model.model_env->set_field_name_helper = &key_fields;
|
||||
field_model.map_fields();
|
||||
db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_UPDATE);
|
||||
|
||||
if( (size_t)field_model.model_env->field_index != key_fields.size() )
|
||||
if( updatable )
|
||||
{
|
||||
// number of keys are different
|
||||
// put error log here
|
||||
std::vector<const wchar_t *> key_fields;
|
||||
key_fields.push_back(db_field_name); // at the moment only one key
|
||||
|
||||
db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_UPDATE_PRIMARY_KEY);
|
||||
field_model.model_env->field_index = 0;
|
||||
field_model.model_env->set_field_name_helper = &key_fields;
|
||||
field_model.map_fields();
|
||||
db_expression->set_output_type(MORM_OUTPUT_TYPE_DB_UPDATE);
|
||||
|
||||
if( (size_t)field_model.model_env->field_index != key_fields.size() )
|
||||
{
|
||||
// IMPROVEME
|
||||
// number of keys are different
|
||||
// put error log here
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -969,6 +989,7 @@ protected:
|
|||
model_env_local.copy_global_objects(*model_env);
|
||||
|
||||
field_model.model_env = &model_env_local;
|
||||
field_model.model_env->has_primary_key_set = field_model.has_primary_key_set;
|
||||
field_model.set_connector(model_connector);
|
||||
|
||||
if( model_env->model_work_mode == MORM_MODEL_WORK_MODE_SET_PARENT_ID )
|
||||
|
@ -1056,6 +1077,7 @@ protected:
|
|||
model_env_local.copy_global_objects(*model_env);
|
||||
|
||||
child_model.model_env = &model_env_local;
|
||||
child_model.model_env->has_primary_key_set = child_model.has_primary_key_set;
|
||||
child_model.set_connector(model_connector);
|
||||
|
||||
if( model_env->model_work_submode == MORM_MODEL_WORK_SUBMODE_INSERT )
|
||||
|
@ -1159,7 +1181,7 @@ protected:
|
|||
|
||||
|
||||
template<typename FieldValue>
|
||||
void get_value_by_field_index(int field_index, FieldValue & field_value)
|
||||
void get_value_by_field_index(int field_index, FieldValue & field_value, bool is_primary_key)
|
||||
{
|
||||
DbConnector * db_connector = model_connector->get_db_connector();
|
||||
|
||||
|
@ -1167,7 +1189,6 @@ protected:
|
|||
{
|
||||
if( !model_env->cursor_helper->query_result->is_null(field_index) )
|
||||
{
|
||||
model_env->all_fields_are_null = false;
|
||||
const char * val_str = model_env->cursor_helper->query_result->get_field_string_value(field_index);
|
||||
|
||||
if( val_str )
|
||||
|
@ -1175,12 +1196,19 @@ protected:
|
|||
db_connector->get_value(val_str, field_value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( is_primary_key )
|
||||
{
|
||||
model_env->has_primary_key_set = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename FieldValue>
|
||||
void get_value_by_field_name(const wchar_t * field_name, FieldValue & field_value)
|
||||
void get_value_by_field_name(const wchar_t * field_name, FieldValue & field_value, bool is_primary_key)
|
||||
{
|
||||
DbConnector * db_connector = model_connector->get_db_connector();
|
||||
|
||||
|
@ -1208,7 +1236,6 @@ protected:
|
|||
|
||||
if( column_index != -1 && !model_env->cursor_helper->query_result->is_null(column_index) )
|
||||
{
|
||||
model_env->all_fields_are_null = false;
|
||||
const char * val_str = model_env->cursor_helper->query_result->get_field_string_value(column_index);
|
||||
|
||||
if( val_str )
|
||||
|
@ -1216,6 +1243,13 @@ protected:
|
|||
db_connector->get_value(val_str, field_value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( is_primary_key )
|
||||
{
|
||||
model_env->has_primary_key_set = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1234,7 +1268,7 @@ public:
|
|||
|
||||
|
||||
template<typename FieldValue>
|
||||
void get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value)
|
||||
bool get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value)
|
||||
{
|
||||
if( model_connector )
|
||||
{
|
||||
|
@ -1242,9 +1276,19 @@ public:
|
|||
|
||||
if( db_connector && !is_empty_field(sequence_table_name) )
|
||||
{
|
||||
db_connector->get_last_sequence(sequence_table_name, field_value);
|
||||
return db_connector->get_last_sequence(sequence_table_name, field_value);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template<typename FieldValue>
|
||||
bool get_last_sequence_for_primary_key(const wchar_t * sequence_table_name, FieldValue & field_value)
|
||||
{
|
||||
has_primary_key_set = get_last_sequence(sequence_table_name, field_value);
|
||||
return has_primary_key_set;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1302,6 +1346,7 @@ protected:
|
|||
virtual void put_table_name_with_index(PT::TextStream & str);
|
||||
|
||||
|
||||
virtual void put_to_log(const wchar_t * str);
|
||||
virtual void put_fields_to_log(PT::Log & log, const wchar_t * db_field_name, const wchar_t * flat_field_name);
|
||||
|
||||
template<typename ModelClass> friend class Finder;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2019, Tomasz Sowa
|
||||
* Copyright (c) 2019-2021, Tomasz Sowa
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
|
@ -63,7 +63,8 @@ public:
|
|||
PT::TextStream table_name_short;
|
||||
int table_index;
|
||||
int field_index;
|
||||
bool all_fields_are_null;
|
||||
bool was_primary_key_read;
|
||||
bool has_primary_key_set;
|
||||
|
||||
std::vector<const wchar_t *> * set_field_name_helper;
|
||||
std::vector<FieldValueHelper> * field_value_helper_tab;
|
||||
|
@ -74,7 +75,6 @@ public:
|
|||
clear();
|
||||
}
|
||||
|
||||
|
||||
~ModelEnv()
|
||||
{
|
||||
}
|
||||
|
@ -92,7 +92,8 @@ public:
|
|||
set_field_name_helper = e.set_field_name_helper;
|
||||
field_value_helper_tab = e.field_value_helper_tab;
|
||||
field_index = e.field_index;
|
||||
all_fields_are_null = e.all_fields_are_null;
|
||||
was_primary_key_read = e.was_primary_key_read;
|
||||
has_primary_key_set = e.has_primary_key_set;
|
||||
|
||||
// table_name and table_name_short don't have to bo copied
|
||||
}
|
||||
|
@ -124,7 +125,8 @@ public:
|
|||
set_field_name_helper = nullptr;
|
||||
field_value_helper_tab = nullptr;
|
||||
field_index = 0;
|
||||
all_fields_are_null = false;
|
||||
was_primary_key_read = false;
|
||||
has_primary_key_set = false;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -152,6 +152,12 @@ void PostgreSQLExpression::esc(char val, PT::TextStream & stream)
|
|||
}
|
||||
|
||||
|
||||
void PostgreSQLExpression::esc(const PT::Date & date, PT::TextStream & stream)
|
||||
{
|
||||
stream << date << "+00";
|
||||
}
|
||||
|
||||
|
||||
DbExpression & PostgreSQLExpression::page(PT::TextStream & stream, size_t page_number, size_t page_size)
|
||||
{
|
||||
stream << " offset " << page_number << " limit " << page_size << " ";
|
||||
|
|
|
@ -46,6 +46,8 @@ class PostgreSQLExpression : public DbExpression
|
|||
public:
|
||||
|
||||
void esc(char val, PT::TextStream & stream);
|
||||
void esc(const PT::Date & date, PT::TextStream & stream);
|
||||
|
||||
DbExpression & page(PT::TextStream & stream, size_t page_number, size_t page_size);
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue