/* * This file is a part of morm * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2018-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 "dbexpression.h" #include "model.h" namespace morm { DbExpression::DbExpression() { } DbExpression::~DbExpression() { } bool DbExpression::can_field_be_generated(const FT & field_type) { if( output_type == MORM_OUTPUT_TYPE_DB_INSERT ) { return field_type.is_insertable(); } else if( output_type == MORM_OUTPUT_TYPE_DB_UPDATE ) { return field_type.is_updatable(); } else if( output_type == MORM_OUTPUT_TYPE_DB_PRIMARY_KEY || output_type == MORM_OUTPUT_TYPE_JOIN_TABLES || output_type == MORM_OUTPUT_TYPE_DB_INSERT_PRIMARY_KEY || output_type == MORM_OUTPUT_TYPE_DB_UPDATE_PRIMARY_KEY ) { return field_type.is_primary_key(); } else { return true; } } void DbExpression::field_before() { BaseExpression::field_before(); if( !is_first_field ) { if( output_type == MORM_OUTPUT_TYPE_DB_INSERT || output_type == MORM_OUTPUT_TYPE_DB_UPDATE || output_type == MORM_OUTPUT_TYPE_SELECT_COLUMNS ) { (*out_stream) << ", "; } else if( output_type == MORM_OUTPUT_TYPE_DB_PRIMARY_KEY ) { (*out_stream) << " AND "; } else if( output_type == MORM_OUTPUT_TYPE_DB_INSERT_PRIMARY_KEY || output_type == MORM_OUTPUT_TYPE_DB_UPDATE_PRIMARY_KEY ) { (*out_stream) << ", "; } else if( output_type == MORM_OUTPUT_TYPE_WHERE_EQ || output_type == MORM_OUTPUT_TYPE_WHERE_GE || output_type == MORM_OUTPUT_TYPE_WHERE_GT || 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_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; if( !conjunctions.empty() ) { conjunction = conjunctions.back(); } if( conjunction == MORM_CONJUNCTION_AND ) { (*out_stream) << " AND "; } else if( conjunction == MORM_CONJUNCTION_OR ) { (*out_stream) << " OR "; } } } } void DbExpression::put_name_value_separator() { if( output_type == MORM_OUTPUT_TYPE_DB_PRIMARY_KEY || output_type == MORM_OUTPUT_TYPE_WHERE_EQ || output_type == MORM_OUTPUT_TYPE_DB_UPDATE || output_type == MORM_OUTPUT_TYPE_DB_INSERT_PRIMARY_KEY || output_type == MORM_OUTPUT_TYPE_DB_UPDATE_PRIMARY_KEY ) { (*out_stream) << "="; } else if( output_type == MORM_OUTPUT_TYPE_WHERE_NOT_EQ ) { (*out_stream) << "<>"; } else if( output_type == MORM_OUTPUT_TYPE_WHERE_LT ) { (*out_stream) << "<"; } else if( output_type == MORM_OUTPUT_TYPE_WHERE_GT ) { (*out_stream) << ">"; } else if( output_type == MORM_OUTPUT_TYPE_WHERE_LE ) { (*out_stream) << "<="; } else if( output_type == MORM_OUTPUT_TYPE_WHERE_GE ) { (*out_stream) << ">="; } else if( output_type == MORM_OUTPUT_TYPE_WHERE_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 "; } } void DbExpression::schema_table_separator() { (*out_stream) << '.'; } void DbExpression::table_field_separator() { (*out_stream) << '.'; } void DbExpression::alias_names_separator() { (*out_stream) << '.'; } void DbExpression::before_schema_name() { (*out_stream) << '"'; } void DbExpression::after_schema_name() { (*out_stream) << '"'; } void DbExpression::before_table_name() { (*out_stream) << '"'; } void DbExpression::after_table_name() { (*out_stream) << '"'; } void DbExpression::before_field_name() { (*out_stream) << '"'; } void DbExpression::after_field_name() { (*out_stream) << '"'; } void DbExpression::before_alias_name() { (*out_stream) << '"'; } 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) << "'"; } void DbExpression::prepare_to_where_clause() { work_mode = MORM_WORK_MODE_MODEL_FIELDS_VALUES; conjunctions.clear(); is_first_field = true; } DbExpression & DbExpression::group_or(pt::TextStream & stream) { out_stream = &stream; field_before(); (*out_stream) << "("; is_first_field = true; conjunctions.push_back(MORM_CONJUNCTION_OR); out_stream = nullptr; return *this; } DbExpression & DbExpression::group_and(pt::TextStream & stream) { out_stream = &stream; field_before(); (*out_stream) << "("; is_first_field = true; conjunctions.push_back(MORM_CONJUNCTION_AND); out_stream = nullptr; return *this; } DbExpression & DbExpression::group_end(pt::TextStream & stream) { out_stream = &stream; if( !conjunctions.empty() ) { conjunctions.pop_back(); (*out_stream) << ")"; field_after(); } out_stream = nullptr; return *this; } DbExpression & DbExpression::page(pt::TextStream & stream, size_t page_number, size_t 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; } }