/* * This file is a part of morm * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2018-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. * */ #include "baseexpression.h" #include "morm_types.h" #include "model.h" #include "utf8/utf8.h" namespace morm { BaseExpression::BaseExpression() { clear(); } BaseExpression::~BaseExpression() { } void BaseExpression::clear() { out_stream = nullptr; is_first_field = false; work_mode = 0; use_prefix = false; } void BaseExpression::set_work_mode(int work_mode) { this->work_mode = work_mode; } int BaseExpression::get_work_mode() { return work_mode; } pt::TextStream * BaseExpression::get_text_stream() { return out_stream; } void BaseExpression::set_text_stream(pt::TextStream * out_stream) { this->out_stream = out_stream; } pt::TextStream * BaseExpression::get_current_stream() { return out_stream; } void BaseExpression::allow_to_use_prefix(bool use_prefix) { this->use_prefix = use_prefix; } bool BaseExpression::get_allow_to_use_prefix() { return use_prefix; } void BaseExpression::generate_from_model(pt::TextStream & stream, Model & model) { this->out_stream = &stream; generate_from_model(model); this->out_stream = nullptr; } void BaseExpression::generate_from_model(Model & model) { if( out_stream ) { before_generate_from_model(); dump_additional_info(model); model.fields(); after_generate_from_model(); } } void BaseExpression::dump_additional_info(Model & model) { if( model.model_env && model.model_env->dump_mode ) { field(L"model_save_mode", model.save_mode, FT::no_insertable | FT::no_updatable | FT::no_fetchable, model.model_env); field(L"has_primary_key_set", model.has_primary_key_set, FT::no_insertable | FT::no_updatable | FT::no_fetchable, model.model_env); } } void BaseExpression::before_generate_from_model() { is_first_field = true; } void BaseExpression::after_generate_from_model() { } bool BaseExpression::can_field_be_generated(const FT &) { return true; } void BaseExpression::field_before() { if( !is_first_field ) { // put a separator between fields } } void BaseExpression::field_after() { is_first_field = false; } void BaseExpression::put_field_name_and_table_if_needed(const wchar_t * field_name, const FT & field_type, ModelEnv * model_env) { if( !field_type.is_raw_field_name() && use_prefix && model_env ) { if( !is_empty_field(model_env->table2_name) ) { put_table_with_index_and_field(model_env->table2_name, model_env->table2_index, field_name, field_type); } else { put_table_with_index_and_field(model_env->table_name, model_env->table_index, field_name, field_type); } } else { put_field_name(field_name, field_type, model_env); } } void BaseExpression::put_field_name(const wchar_t * field_name, const FT & field_type, ModelEnv * model_env) { if( field_type.is_raw_field_name() ) { (*out_stream) << field_name; } else { before_field_name(); esc(field_name, *out_stream); after_field_name(); } } void BaseExpression::save_foreign_key(const wchar_t * field_name, const FT & field_type, ModelEnv * model_env) { pt::TextStream str; pt::TextStream * old_out_stream = out_stream; out_stream = &str; put_field_name(field_name, field_type, model_env); out_stream = old_out_stream; if( model_env && model_env->finder_helper ) { model_env->finder_helper->foreign_keys.emplace_back(); std::string & key_str = model_env->finder_helper->foreign_keys.back(); str.to_str(key_str, false); } } void BaseExpression::schema_table_separator() { } void BaseExpression::table_field_separator() { } void BaseExpression::before_schema_name() { } void BaseExpression::after_schema_name() { } void BaseExpression::before_table_name() { } void BaseExpression::after_table_name() { } void BaseExpression::before_field_name() { } void BaseExpression::after_field_name() { } void BaseExpression::before_field_value(const std::wstring &, const FT & field_type) { before_field_value_string(field_type); } void BaseExpression::before_field_value(const std::string &, const FT & field_type) { before_field_value_string(field_type); } void BaseExpression::after_field_value(const std::wstring &, const FT & field_type) { after_field_value_string(field_type); } void BaseExpression::after_field_value(const std::string &, const FT & field_type) { after_field_value_string(field_type); } void BaseExpression::before_field_value(const wchar_t *, const FT & field_type) { before_field_value_string(field_type); } void BaseExpression::after_field_value(const wchar_t *, const FT & field_type) { after_field_value_string(field_type); } void BaseExpression::before_field_value(const char *, const FT & field_type) { before_field_value_string(field_type); } void BaseExpression::after_field_value(const char *, const FT & field_type) { after_field_value_string(field_type); } void BaseExpression::before_field_value(wchar_t, const FT & field_type) { before_field_value_string(field_type); } void BaseExpression::after_field_value(wchar_t, const FT & field_type) { after_field_value_string(field_type); } void BaseExpression::before_field_value(char, const FT & field_type) { before_field_value_string(field_type); } void BaseExpression::after_field_value(char, const FT & field_type) { after_field_value_string(field_type); } void BaseExpression::before_field_value(const pt::Date &, const FT & field_type) { before_field_value_string(field_type); } void BaseExpression::after_field_value(const pt::Date &, const FT & field_type) { after_field_value_string(field_type); } void BaseExpression::before_field_value(const pt::Space &, const FT & field_type) { before_field_value_string(field_type); } void BaseExpression::after_field_value(const pt::Space &, const FT & field_type) { after_field_value_string(field_type); } void BaseExpression::put_name_value_separator() { (*out_stream) << ','; } char BaseExpression::char_to_hex_part(char c) { if( c < 10 ) return c + '0'; return c - 10 + 'A'; } void BaseExpression::char_to_hex(char c, pt::TextStream & stream) { stream << char_to_hex_part(((unsigned char)c) >> 4); stream << char_to_hex_part(((unsigned char)c) & 0x0f); } void BaseExpression::esc(char val, pt::TextStream & stream, const FT & field_type) { if( field_type.is_binary() || field_type.is_hexadecimal() ) { char_to_hex(val, stream); } else { stream << val; } } void BaseExpression::esc(unsigned char val, pt::TextStream & stream, const FT & field_type) { esc(static_cast(val), stream, field_type); } void BaseExpression::esc(wchar_t val, pt::TextStream & stream, const FT & field_type) { if( field_type.use_utf8() ) { 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); } } else { esc(static_cast(val), stream, field_type); } } void BaseExpression::esc(const wchar_t * val, bool has_known_length, size_t len, pt::TextStream & stream, const FT & field_type) { if( field_type.use_utf8() ) { char utf8_buf[10]; for(size_t i = 0 ; has_known_length ? (i < len) : val[i] != 0 ; ++i) { // 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) { esc(utf8_buf[a], stream, field_type); } } } else { for(size_t i = 0 ; has_known_length ? (i < len) : val[i] != 0 ; ++i) { esc(static_cast(val[i]), stream, field_type); } } } void BaseExpression::esc(const std::wstring & val, pt::TextStream & stream, const FT & field_type) { 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) { esc(val[i], stream, field_type); } } void BaseExpression::esc(const char * val, pt::TextStream & stream, const FT & field_type) { for(size_t i = 0 ; val[i] != 0 ; ++i) { esc(val[i], stream, field_type); } } void BaseExpression::esc(bool val, pt::TextStream & stream, const FT & field_type) { if( val ) stream << "true"; else stream << "false"; } void BaseExpression::esc(short val, pt::TextStream & stream, const FT & field_type) { stream << val; } void BaseExpression::esc(unsigned short val, pt::TextStream & stream, const FT & field_type) { stream << val; } void BaseExpression::esc(int val, pt::TextStream & stream, const FT & field_type) { stream << val; } void BaseExpression::esc(unsigned int val, pt::TextStream & stream, const FT & field_type) { stream << val; } void BaseExpression::esc(long val, pt::TextStream & stream, const FT & field_type) { stream << val; } void BaseExpression::esc(unsigned long val, pt::TextStream & stream, const FT & field_type) { stream << val; } void BaseExpression::esc(long long val, pt::TextStream & stream, const FT & field_type) { stream << val; } void BaseExpression::esc(unsigned long long val, pt::TextStream & stream, const FT & field_type) { stream << val; } void BaseExpression::esc(float val, pt::TextStream & stream, const FT & field_type) { stream << val; } void BaseExpression::esc(double val, pt::TextStream & stream, const FT & field_type) { stream << val; } void BaseExpression::esc(long double val, pt::TextStream & stream, const FT & field_type) { stream << val; } void BaseExpression::esc(const pt::Date & date, pt::TextStream & stream, const FT & field_type) { stream << date; } void BaseExpression::esc(const pt::TextStream & val, pt::TextStream & stream, const FT & field_type) { pt::TextStream::const_iterator i = val.begin(); for(; i != val.end() ; ++i) { esc(*i, stream, field_type); } } void BaseExpression::esc(const pt::WTextStream & val, pt::TextStream & stream, const FT & field_type) { pt::WTextStream::const_iterator i = val.begin(); for(; i != val.end() ; ++i) { esc(*i, stream, field_type); } } void BaseExpression::esc(const pt::Space & space, pt::TextStream & stream, const FT & field_type) { pt::WTextStream tmp_stream; space.serialize_to_space_stream(tmp_stream, true); esc(tmp_stream, stream, field_type); } //void BaseExpression::put_type(char val, pt::TextStream & stream) //{ // stream << "char"; //} // //void BaseExpression::put_type(unsigned char val, pt::TextStream & stream) //{ // stream << "unsigned char"; //} // // //void BaseExpression::put_type(const std::wstring & val, pt::TextStream & stream) //{ // stream << "text"; //} // //void BaseExpression::put_type(const wchar_t * val, pt::TextStream & stream) //{ // stream << "text"; //} // // //void BaseExpression::put_type(const std::string & val, pt::TextStream & stream) //{ // stream << "text"; //} // //void BaseExpression::put_type(const char * val, pt::TextStream & stream) //{ // stream << "text"; //} // // //void BaseExpression::put_type(bool val, pt::TextStream & stream) //{ // stream << "boolean"; //} // //void BaseExpression::put_type(short val, pt::TextStream & stream) //{ // stream << "short integer"; //} // //void BaseExpression::put_type(unsigned short val, pt::TextStream & stream) //{ // stream << "unsigned short integer"; //} // //void BaseExpression::put_type(int val, pt::TextStream & stream) //{ // stream << "integer"; //} // //void BaseExpression::put_type(unsigned int val, pt::TextStream & stream) //{ // stream << "unsigned integer"; //} // //void BaseExpression::put_type(long val, pt::TextStream & stream) //{ // stream << "long integer"; //} // //void BaseExpression::put_type(unsigned long val, pt::TextStream & stream) //{ // stream << "unsigned long integer"; //} // //void BaseExpression::put_type(long long val, pt::TextStream & stream) //{ // stream << "very long integer"; //} // //void BaseExpression::put_type(unsigned long long val, pt::TextStream & stream) //{ // stream << "unsigned very long integer"; //} // //void BaseExpression::put_type(float val, pt::TextStream & stream) //{ // stream << "float"; //} // //void BaseExpression::put_type(double val, pt::TextStream & stream) //{ // stream << "double"; //} // //void BaseExpression::put_type(long double val, pt::TextStream & stream) //{ // stream << "long double"; //} // ////void BaseExpression::put_type(void* val, pt::TextStream & stream) ////{ ////} // // //void BaseExpression::put_type(const pt::Date & date, pt::TextStream & stream) //{ // stream << "date"; //} // //void BaseExpression::put_type(const Model & model, pt::TextStream & stream) //{ // stream << "object"; //} void BaseExpression::before_field_value_string(const FT & field_type) { } void BaseExpression::after_field_value_string(const FT & field_type) { } /* * schema_name can be a null pointer or just pointing to an empty string * in such a case we do not put the schema name */ void BaseExpression::put_schema_table(const wchar_t * schema_name, const wchar_t * table_name) { if( out_stream ) { bool has_schema = false; if( !is_empty_field(schema_name) ) { has_schema = true; before_schema_name(); esc(schema_name, *out_stream); after_schema_name(); } if( !is_empty_field(table_name) ) { if( has_schema ) schema_table_separator(); before_table_name(); esc(table_name, *out_stream); after_table_name(); } } } /* * schema_name can be empty - in such a case we do not put the schema name */ void BaseExpression::put_schema_table(const pt::WTextStream & schema_name, const pt::WTextStream & table_name) { if( out_stream ) { bool has_schema = false; if( !schema_name.empty() ) { has_schema = true; before_schema_name(); esc(schema_name, *out_stream); after_schema_name(); } if( !table_name.empty() ) { if( has_schema ) schema_table_separator(); before_table_name(); esc(table_name, *out_stream); after_table_name(); } } } void BaseExpression::put_table(const wchar_t * table_name) { if( out_stream ) { before_table_name(); esc(table_name, *out_stream); after_table_name(); } } void BaseExpression::put_table(const pt::WTextStream & table_name) { if( out_stream ) { before_table_name(); esc(table_name, *out_stream); after_table_name(); } } void BaseExpression::put_table_with_index(const wchar_t * table_name, int index) { if( out_stream ) { before_table_name(); esc(table_name, *out_stream); if( index > 1 ) { (*out_stream) << index; } after_table_name(); } } void BaseExpression::put_table_with_index(const pt::WTextStream & table_name, int index) { if( out_stream ) { before_table_name(); esc(table_name, *out_stream); if( index > 1 ) { (*out_stream) << index; } after_table_name(); } } void BaseExpression::put_table_with_index_and_field(const wchar_t * table_name, int index, const wchar_t * field_name, const FT & field_type) { if( out_stream ) { put_table_with_index(table_name, index); table_field_separator(); put_field_name(field_name, field_type, nullptr); } } void BaseExpression::put_table_with_index_and_field(const pt::WTextStream & table_name, int index, const wchar_t * field_name, const FT & field_type) { if( out_stream ) { put_table_with_index(table_name, index); table_field_separator(); put_field_name(field_name, field_type, nullptr); } } void BaseExpression::put_table_and_field(const wchar_t * table_name, const wchar_t * field_name, const FT & field_type) { if( out_stream ) { put_table(table_name); table_field_separator(); put_field_name(field_name, field_type, nullptr); } } void BaseExpression::put_table_and_field(const pt::WTextStream & table_name, const wchar_t * field_name, const FT & field_type) { if( out_stream ) { put_table(table_name); table_field_separator(); put_field_name(field_name, field_type, nullptr); } } void BaseExpression::schema_table_to_stream(pt::TextStream & stream, const wchar_t * schema_name, const wchar_t * table_name) { this->out_stream = &stream; put_schema_table(schema_name, table_name); this->out_stream = nullptr; } void BaseExpression::schema_table_to_stream(pt::TextStream & stream, const pt::WTextStream & schema_name, const pt::WTextStream & table_name) { this->out_stream = &stream; put_schema_table(schema_name, table_name); this->out_stream = nullptr; } void BaseExpression::table_to_stream(pt::TextStream & stream, const wchar_t * table_name) { this->out_stream = &stream; put_table(table_name); this->out_stream = nullptr; } void BaseExpression::table_to_stream(pt::TextStream & stream, const pt::WTextStream & table_name) { this->out_stream = &stream; put_table(table_name); this->out_stream = nullptr; } void BaseExpression::table_with_index_to_stream(pt::TextStream & stream, const wchar_t * table_name, int index) { this->out_stream = &stream; put_table_with_index(table_name, index); this->out_stream = nullptr; } void BaseExpression::table_with_index_to_stream(pt::TextStream & stream, const pt::WTextStream & table_name, int index) { this->out_stream = &stream; put_table_with_index(table_name, index); this->out_stream = nullptr; } void BaseExpression::table_with_index_and_field_to_stream(pt::TextStream & stream, const wchar_t * table_name, int index, const wchar_t * field_name, const FT & field_type) { this->out_stream = &stream; put_table_with_index_and_field(table_name, index, field_name, field_type); this->out_stream = nullptr; } void BaseExpression::table_with_index_and_field_to_stream(pt::TextStream & stream, const pt::WTextStream & table_name, int index, const wchar_t * field_name, const FT & field_type) { this->out_stream = &stream; put_table_with_index_and_field(table_name, index, field_name, field_type); this->out_stream = nullptr; } void BaseExpression::table_and_field_to_stream(pt::TextStream & stream, const wchar_t * table_name, const wchar_t * field_name, const FT & field_type) { this->out_stream = &stream; put_table_and_field(table_name, field_name, field_type); this->out_stream = nullptr; } void BaseExpression::table_and_field_to_stream(pt::TextStream & stream, const pt::WTextStream & table_name, const wchar_t * field_name, const FT & field_type) { this->out_stream = &stream; put_table_and_field(table_name, field_name, field_type); this->out_stream = nullptr; } bool BaseExpression::is_empty_field(const wchar_t * value) { return (!value || *value == '\0'); } }