added Cursor class

git-svn-id: svn://ttmath.org/publicrep/morm/trunk@1140 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2018-11-14 17:14:26 +00:00
parent 011d8f96e8
commit 1f9e4ee70a
16 changed files with 1108 additions and 802 deletions

View File

@ -12,8 +12,9 @@ baseexpression.o: ../../pikotools/convert/misc.h
baseexpression.o: ../../pikotools/membuffer/membuffer.h
baseexpression.o: ../../pikotools/textstream/types.h morm_types.h model.h
baseexpression.o: modelconnector.h clearer.h dbconnector.h
baseexpression.o: ../../pikotools/logger/logger.h flatconnector.h
baseexpression.o: dbexpression.h flatexpression.h ../../pikotools/utf8/utf8.h
baseexpression.o: ../../pikotools/logger/logger.h queryresult.h
baseexpression.o: flatconnector.h dbexpression.h flatexpression.h
baseexpression.o: ../../pikotools/utf8/utf8.h
clearer.o: clearer.h ../../pikotools/date/date.h
clearer.o: ../../pikotools/convert/convert.h
clearer.o: ../../pikotools/convert/inttostr.h
@ -23,8 +24,8 @@ clearer.o: ../../pikotools/textstream/textstream.h
clearer.o: ../../pikotools/space/space.h ../../pikotools/textstream/types.h
clearer.o: ../../pikotools/membuffer/membuffer.h
clearer.o: ../../pikotools/textstream/types.h modelconnector.h dbconnector.h
clearer.o: ../../pikotools/logger/logger.h flatconnector.h dbexpression.h
clearer.o: baseexpression.h morm_types.h flatexpression.h
clearer.o: ../../pikotools/logger/logger.h queryresult.h flatconnector.h
clearer.o: dbexpression.h baseexpression.h morm_types.h flatexpression.h
dbconnector.o: dbconnector.h ../../pikotools/textstream/textstream.h
dbconnector.o: ../../pikotools/space/space.h
dbconnector.o: ../../pikotools/textstream/types.h ../../pikotools/date/date.h
@ -34,7 +35,7 @@ dbconnector.o: ../../pikotools/convert/strtoint.h
dbconnector.o: ../../pikotools/convert/text.h ../../pikotools/convert/misc.h
dbconnector.o: ../../pikotools/membuffer/membuffer.h
dbconnector.o: ../../pikotools/textstream/types.h
dbconnector.o: ../../pikotools/logger/logger.h dbexpression.h
dbconnector.o: ../../pikotools/logger/logger.h queryresult.h dbexpression.h
dbconnector.o: baseexpression.h morm_types.h model.h modelconnector.h
dbconnector.o: clearer.h flatconnector.h flatexpression.h
dbconnector.o: ../../pikotools/utf8/utf8.h
@ -86,7 +87,7 @@ flatconnector.o: ../../pikotools/membuffer/membuffer.h
flatconnector.o: ../../pikotools/textstream/types.h flatexpression.h
flatconnector.o: baseexpression.h morm_types.h model.h modelconnector.h
flatconnector.o: clearer.h dbconnector.h ../../pikotools/logger/logger.h
flatconnector.o: dbexpression.h
flatconnector.o: queryresult.h dbexpression.h
flatexpression.o: flatexpression.h baseexpression.h
flatexpression.o: ../../pikotools/textstream/textstream.h
flatexpression.o: ../../pikotools/space/space.h
@ -131,8 +132,9 @@ model.o: ../../pikotools/convert/inttostr.h
model.o: ../../pikotools/convert/strtoint.h ../../pikotools/convert/text.h
model.o: ../../pikotools/convert/misc.h ../../pikotools/membuffer/membuffer.h
model.o: ../../pikotools/textstream/types.h modelconnector.h clearer.h
model.o: dbconnector.h ../../pikotools/logger/logger.h flatconnector.h
model.o: dbexpression.h baseexpression.h morm_types.h flatexpression.h
model.o: dbconnector.h ../../pikotools/logger/logger.h queryresult.h
model.o: flatconnector.h dbexpression.h baseexpression.h morm_types.h
model.o: flatexpression.h
modelconnector.o: modelconnector.h clearer.h ../../pikotools/date/date.h
modelconnector.o: ../../pikotools/convert/convert.h
modelconnector.o: ../../pikotools/convert/inttostr.h
@ -144,7 +146,8 @@ modelconnector.o: ../../pikotools/space/space.h
modelconnector.o: ../../pikotools/textstream/types.h
modelconnector.o: ../../pikotools/membuffer/membuffer.h
modelconnector.o: ../../pikotools/textstream/types.h
modelconnector.o: ../../pikotools/logger/logger.h flatconnector.h
modelconnector.o: ../../pikotools/logger/logger.h queryresult.h
modelconnector.o: flatconnector.h
postgresqlconnector.o: postgresqlconnector.h dbconnector.h
postgresqlconnector.o: ../../pikotools/textstream/textstream.h
postgresqlconnector.o: ../../pikotools/space/space.h
@ -157,10 +160,10 @@ postgresqlconnector.o: ../../pikotools/convert/text.h
postgresqlconnector.o: ../../pikotools/convert/misc.h
postgresqlconnector.o: ../../pikotools/membuffer/membuffer.h
postgresqlconnector.o: ../../pikotools/textstream/types.h
postgresqlconnector.o: ../../pikotools/logger/logger.h
postgresqlconnector.o: ../../pikotools/utf8/utf8.h postgresqlexpression.h
postgresqlconnector.o: dbexpression.h baseexpression.h morm_types.h
postgresqlconnector.o: ../../pikotools/convert/strtoint.h
postgresqlconnector.o: ../../pikotools/logger/logger.h queryresult.h
postgresqlconnector.o: postgresqlqueryresult.h ../../pikotools/utf8/utf8.h
postgresqlconnector.o: postgresqlexpression.h dbexpression.h baseexpression.h
postgresqlconnector.o: morm_types.h ../../pikotools/convert/strtoint.h
postgresqlexpression.o: postgresqlexpression.h dbexpression.h
postgresqlexpression.o: baseexpression.h
postgresqlexpression.o: ../../pikotools/textstream/textstream.h
@ -174,3 +177,5 @@ postgresqlexpression.o: ../../pikotools/convert/text.h
postgresqlexpression.o: ../../pikotools/convert/misc.h
postgresqlexpression.o: ../../pikotools/membuffer/membuffer.h
postgresqlexpression.o: ../../pikotools/textstream/types.h morm_types.h
postgresqlqueryresult.o: postgresqlqueryresult.h queryresult.h
queryresult.o: queryresult.h ../../pikotools/utf8/utf8.h

View File

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

312
src/cursor.h Normal file
View File

@ -0,0 +1,312 @@
/*
* 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) 2018, 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_cursor
#define headerfile_morm_cursor
#include "queryresult.h"
#include "modelconnector.h"
namespace morm
{
template<typename ModelClass>
class Cursor
{
public:
Cursor()
{
set_default_values();
}
Cursor(const Cursor & c)
{
model_connector = c.model_connector;
model_data = c.model_data;
query_result = c.query_result;
select_status = c.select_status;
if( query_result )
{
query_result->references_count += 1;
}
}
Cursor & operator=(const Cursor & c) = delete;
virtual ~Cursor()
{
if( query_result && query_result->references_count > 0 )
{
query_result->references_count -= 1;
}
clear();
}
virtual void clear()
{
if( query_result && query_result->references_count == 0 )
{
query_result->clear();
delete query_result;
}
set_default_values();
}
virtual void set_model_connector(ModelConnector * model_connector)
{
this->model_connector = model_connector;
}
virtual void set_model_data(Model::ModelData * model_data)
{
this->model_data = model_data;
}
virtual void set_query_result(QueryResult * query_result)
{
this->query_result = query_result;
}
virtual void set_select_status(bool select_status)
{
this->select_status = select_status;
}
virtual QueryResult * get_query_result()
{
return query_result;
}
virtual bool has_next()
{
bool has = false;
if( model_connector && query_result && query_result->has_db_result() && select_status )
{
has = query_result->cur_row < query_result->result_rows;
}
return has;
}
virtual bool get(ModelClass & result)
{
bool res = false;
result.set_connector(model_connector);
result.clear();
if( model_connector && query_result && query_result->has_db_result() )
{
DbConnector * db_connector = model_connector->get_db_connector();
if( db_connector )
{
try
{
result.model_data = model_data;
result.before_select();
res = select_status;
if( res )
{
if( query_result->cur_row < query_result->result_rows )
{
result.set_save_mode(Model::DO_UPDATE_ON_SAVE); // IMPROVE ME check if there is a primary key
result.map_values_from_query(query_result);
result.after_select();
query_result->cur_row += 1;
}
else
{
res = false;
// log some error or throw an exception?
}
}
else
{
result.after_select_failure();
}
}
catch(...)
{
res = false;
// throw something?
}
result.model_data = nullptr;
}
}
return res;
}
virtual ModelClass get()
{
ModelClass model;
get(model);
return std::move(model);
}
virtual bool get_list(std::list<ModelClass> & result, bool clear_list = true)
{
bool res = false;
if( clear_list )
{
result.clear();
}
if( model_connector && query_result && query_result->has_db_result() )
{
DbConnector * db_connector = model_connector->get_db_connector();
if( db_connector )
{
res = select_status;
try
{
if( res )
{
res = add_models_to_list(result);
}
else
{
// add log
// if there was a failure we do not call after_select_failure()
// because there are no any objects in the list
}
}
catch(...)
{
res = false;
// throw or something?
}
}
}
return res;
}
virtual std::list<ModelClass> get_list()
{
std::list<ModelClass> result;
get_list(result, false);
return std::move(result);
}
protected:
ModelConnector * model_connector;
Model::ModelData * model_data;
QueryResult * query_result;
bool select_status;
virtual void set_default_values()
{
model_connector = nullptr;
model_data = nullptr;
query_result = nullptr;
select_status = false;
}
template<typename ContainerType>
bool add_models_to_list(ContainerType & result)
{
bool res = true;
for(query_result->cur_row = 0 ; query_result->cur_row < query_result->result_rows ; query_result->cur_row += 1)
{
result.emplace_back(); // it returns a reference from c++17
ModelClass & added_model = result.back();
try
{
added_model.set_connector(model_connector);
added_model.clear();
added_model.set_save_mode(Model::DO_UPDATE_ON_SAVE); // IMPROVE ME check if there is a primary key
added_model.model_data = model_data;
added_model.before_select();
added_model.map_values_from_query(query_result);
added_model.after_select();
}
catch(...)
{
res = false;
// throw or something?
}
added_model.model_data = nullptr;
}
return res;
}
};
} // namespace
#endif

View File

@ -33,6 +33,7 @@
*/
#include <cstdlib>
#include <memory>
#include "dbconnector.h"
#include "dbexpression.h"
#include "model.h"
@ -75,36 +76,22 @@ void DbConnector::set_logger(PT::Logger & logger)
void DbConnector::clear_last_query_result()
bool DbConnector::query(const PT::TextStream & stream, QueryResult & query_result)
{
std::string query_str;
stream.to_string(query_str);
return query(query_str, query_result);
}
bool DbConnector::query(const PT::TextStream & stream)
bool DbConnector::query(const std::string & query_str, QueryResult & query_result)
{
return false;
return query(query_str.c_str(), query_result);
}
//bool DbConnector::query(const std::wstring & query)
//{
// return false;
//}
bool DbConnector::query(const std::string & query_str)
{
return false;
}
//bool DbConnector::query(const wchar_t * query)
//{
// return false;
//}
bool DbConnector::query(const char * query_str)
bool DbConnector::query(const char * query_str, QueryResult & query_result)
{
// do query
return false;
@ -112,55 +99,48 @@ bool DbConnector::query(const char * query_str)
bool DbConnector::query_select(const PT::TextStream & stream)
bool DbConnector::query_select(const char * query_str, QueryResult & query_result)
{
return false;
return query(query_str, query_result);
}
bool DbConnector::query_update(const PT::TextStream & stream)
bool DbConnector::query_update(const char * query_str, QueryResult & query_result)
{
return false;
return query(query_str, query_result);
}
bool DbConnector::query_insert(const PT::TextStream & stream)
bool DbConnector::query_insert(const char * query_str, QueryResult & query_result)
{
return false;
return query(query_str, query_result);
}
bool DbConnector::query_remove(const PT::TextStream & stream)
bool DbConnector::query_remove(const char * query_str, QueryResult & query_result)
{
return false;
}
size_t DbConnector::last_select_size()
{
return 0;
}
std::wstring DbConnector::get_last_query_error_msg()
{
return std::wstring();
}
bool DbConnector::was_error_in_last_query()
{
return false;
return query(query_str, query_result);
}
void DbConnector::set_current_row_at_beginning()
bool DbConnector::query_select(const PT::TextStream & stream, QueryResult & query_result)
{
return query(stream, query_result);
}
void DbConnector::advance_current_row()
bool DbConnector::query_update(const PT::TextStream & stream, QueryResult & query_result)
{
return query(stream, query_result);
}
bool DbConnector::query_insert(const PT::TextStream & stream, QueryResult & query_result)
{
return query(stream, query_result);
}
bool DbConnector::query_remove(const PT::TextStream & stream, QueryResult & query_result)
{
return query(stream, query_result);
}
//void DbConnector::map_values_from_query(Model & model)
//{
// model.clear();
//}
DbExpression * DbConnector::get_expression()
@ -249,22 +229,28 @@ void DbConnector::generate_remove_query(PT::TextStream & stream, Model & model)
bool DbConnector::insert(PT::TextStream & stream, Model & model)
{
std::unique_ptr<QueryResult> query_result_ptr(create_query_result());
generate_insert_query(stream, model);
return query_insert(stream);
return query_insert(stream, *query_result_ptr);
}
bool DbConnector::update(PT::TextStream & stream, Model & model)
{
std::unique_ptr<QueryResult> query_result_ptr(create_query_result());
generate_update_query(stream, model);
return query_update(stream);
return query_update(stream, *query_result_ptr);
}
bool DbConnector::remove(PT::TextStream & stream, Model & model)
{
std::unique_ptr<QueryResult> query_result_ptr(create_query_result());
generate_remove_query(stream, model);
return query_remove(stream);
return query_remove(stream, *query_result_ptr);
}
@ -288,15 +274,6 @@ void DbConnector::allocate_default_expression_if_needed()
}
}
const char * DbConnector::get_field_string_value(const char * field_name)
{
return nullptr;
}
const char * DbConnector::get_field_string_value(const wchar_t * field_name)
{
return nullptr;
}

View File

@ -37,6 +37,7 @@
#include "textstream/textstream.h"
#include "logger/logger.h"
#include "queryresult.h"
namespace morm
@ -58,7 +59,7 @@ public:
DbExpression * get_expression();
virtual void clear_last_query_result();
//virtual void clear_last_query_result();
virtual void generate_select_columns(PT::TextStream & stream, Model & model, const std::wstring & column_prefix);
virtual void generate_insert_query(PT::TextStream & stream, Model & model);
@ -71,27 +72,21 @@ public:
//void ModelConnector::get_values_from_db(Model & model)
virtual QueryResult * create_query_result() = 0;
virtual bool query(const PT::TextStream & stream);
//virtual bool query(const std::wstring & query);
virtual bool query(const std::string & query_str);
//virtual bool query(const wchar_t * query);
virtual bool query(const char * query_str);
virtual bool query(const PT::TextStream & stream, QueryResult & query_result);
virtual bool query(const std::string & query_str, QueryResult & query_result);
virtual bool query(const char * query_str, QueryResult & query_result);
virtual bool query_select(const PT::TextStream & stream);
virtual bool query_update(const PT::TextStream & stream);
virtual bool query_insert(const PT::TextStream & stream);
virtual bool query_remove(const PT::TextStream & stream);
virtual bool query_select(const char * query_str, QueryResult & query_result);
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 size_t last_select_size();
virtual std::wstring get_last_query_error_msg();
virtual bool was_error_in_last_query();
// give me a better name
virtual void set_current_row_at_beginning();
virtual void advance_current_row();
//virtual void map_values_from_query(Model & model);
virtual bool query_select(const PT::TextStream & stream, QueryResult & query_result);
virtual bool query_update(const PT::TextStream & stream, QueryResult & query_result);
virtual bool query_insert(const PT::TextStream & stream, QueryResult & query_result);
virtual bool query_remove(const PT::TextStream & stream, QueryResult & query_result);
virtual void get_value(const char * value_str, char & field_value);
virtual void get_value(const char * value_str, unsigned char & field_value);
@ -112,18 +107,6 @@ public:
virtual void get_value(const char * value_str, PT::Date & field_value);
template<typename FieldValue>
void get_value_by_field_name(const wchar_t * field_name, FieldValue & field_value)
{
const char * val_str = get_field_string_value(field_name);
if( val_str )
{
get_value(val_str, field_value);
}
}
template<typename FieldValue>
void get_last_sequence(const wchar_t * sequence_table_name, FieldValue & field_value)
{
@ -140,7 +123,6 @@ protected:
DbExpression * db_expression;
bool expression_allocated;
std::wstring last_query_error_msg;
PT::Logger * logger;
@ -148,9 +130,6 @@ protected:
virtual void allocate_default_expression_if_needed();
virtual void deallocate_expression();
virtual const char * get_field_string_value(const char * field_name);
virtual const char * get_field_string_value(const wchar_t * field_name);
virtual const char * query_last_sequence(const wchar_t * sequence_table_name);

View File

@ -42,6 +42,7 @@
#include "textstream/textstream.h"
#include "dbconnector.h"
#include "modelconnector.h"
#include "cursor.h"
namespace morm
@ -431,61 +432,42 @@ public:
}
bool get(ModelClass & result)
Cursor<ModelClass> get_cursor()
{
bool res = false;
result.set_connector(model_connector);
result.clear();
Cursor<ModelClass> cursor;
cursor.set_model_data(model_data);
if( model_connector && out_stream )
{
cursor.set_model_connector(model_connector);
DbConnector * db_connector = model_connector->get_db_connector();
if( db_connector )
{
try
{
result.model_data = model_data;
result.before_select();
res = db_connector->query_select(*out_stream);
QueryResult * query_result = db_connector->create_query_result();
cursor.set_query_result(query_result);
query_result->references_count = 1;
if( res )
{
if( db_connector->last_select_size() == 1 )
{
result.set_save_mode(Model::DO_UPDATE_ON_SAVE); // IMPROVE ME check if there is a primary key
result.map_values_from_query();
result.after_select();
}
else
{
res = false;
// log some error or throw an exception if there are more items than one?
}
}
else
{
result.after_select_failure();
}
}
catch(...)
{
res = false;
// throw something?
// if yes then make sure to call db_connector->clear_last_query_result();
}
result.model_data = nullptr;
db_connector->clear_last_query_result();
bool status = db_connector->query_select(*out_stream, *query_result);
cursor.set_select_status(status);
}
}
return res;
return cursor;
}
bool get(ModelClass & result)
{
Cursor<ModelClass> cursor = get_cursor();
return cursor.get(result);
}
ModelClass get()
{
ModelClass model;
get(model);
return model;
}
@ -493,84 +475,22 @@ public:
bool get_list(std::list<ModelClass> & result, bool clear_list = true)
{
bool res = false;
if( clear_list )
{
result.clear();
}
if( model_connector && out_stream )
{
DbConnector * db_connector = model_connector->get_db_connector();
if( db_connector )
{
res = db_connector->query_select(*out_stream);
try
{
if( res )
{
size_t len = db_connector->last_select_size();
db_connector->set_current_row_at_beginning();
for(size_t i = 0 ; i < len ; ++i)
{
result.emplace_back(); // it returns a reference from c++17
ModelClass & added_model = result.back();
try
{
added_model.set_connector(model_connector);
added_model.clear();
added_model.set_save_mode(Model::DO_UPDATE_ON_SAVE); // IMPROVE ME check if there is a primary key
added_model.model_data = model_data;
added_model.before_select();
added_model.map_values_from_query();
added_model.after_select();
}
catch(...)
{
res = false;
// throw or something?
// make sure to call db_connector->clear_last_query_result()
}
added_model.model_data = nullptr;
db_connector->advance_current_row();
}
// if there was a failure we do not call after_select_failure()
// because there are no any objects in the list
}
else
{
// log
}
}
catch(...)
{
res = false;
// throw or something?
// make sure to call db_connector->clear_last_query_result()
}
db_connector->clear_last_query_result();
}
}
return res;
Cursor<ModelClass> cursor = get_cursor();
return cursor.get_list(result, clear_list);
}
std::list<ModelClass> get_list()
{
std::list<ModelClass> result;
get_list(result, false);
return std::move(result);
}
private:

View File

@ -45,8 +45,22 @@ Model::Model()
doc_field_pointer = nullptr;
save_mode = DO_INSERT_ON_SAVE;
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
query_result = nullptr;
}
Model::Model(const Model & m)
{
model_connector = m.model_connector;
save_mode = m.save_mode;
model_data = nullptr;
doc_field_pointer = nullptr; // does it need to be copied?
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
query_result = nullptr;
}
Model::~Model()
{
}
@ -85,28 +99,6 @@ void Model::mark_to_update()
}
bool Model::was_db_error()
{
if( model_connector )
{
return model_connector->was_db_error();
}
return false;
}
std::wstring Model::get_db_error()
{
if( model_connector )
{
return model_connector->get_db_error();
}
return std::wstring();
}
void Model::table_name(PT::TextStream & stream)
{
@ -472,11 +464,15 @@ void Model::generate_doc_for_db(PT::TextStream & stream, bool clear_stream)
}
void Model::map_values_from_query()
void Model::map_values_from_query(QueryResult * query_result)
{
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_READING_VALUE_FROM_DB_RESULTSET;
this->query_result = query_result;
map_fields();
model_connector_mode = MORM_MODEL_CONNECTOR_MODE_NONE;
this->query_result = nullptr;
}

View File

@ -41,6 +41,7 @@
#include "modelconnector.h"
#include "dbexpression.h"
#include "flatexpression.h"
#include "queryresult.h"
@ -92,10 +93,6 @@ public:
virtual bool found();
virtual bool was_db_error();
virtual std::wstring get_db_error();
void set_connector(ModelConnector & connector);
void set_connector(ModelConnector * connector);
@ -155,8 +152,11 @@ protected:
ModelData * model_data;
const void * doc_field_pointer;
int model_connector_mode;
QueryResult * query_result;
Model();
Model(const Model & m);
virtual ~Model();
virtual void before_select();
@ -176,8 +176,8 @@ protected:
virtual int get_connector_mode();
// used by Finder
virtual void map_values_from_query();
// used by Cursor
virtual void map_values_from_query(QueryResult * query_result);
/////////////////////////////////
@ -684,7 +684,7 @@ protected:
if( db_connector )
{
if( !is_empty_field(db_field_name) )
db_connector->get_value_by_field_name(db_field_name, field_value);
get_value_by_field_name(db_field_name, field_value);
}
}
@ -825,6 +825,27 @@ protected:
}
}
template<typename FieldValue>
void get_value_by_field_name(const wchar_t * field_name, FieldValue & field_value)
{
if( query_result )
{
const char * val_str = query_result->get_field_string_value(field_name);
if( val_str )
{
DbConnector * db_connector = model_connector->get_db_connector();
if( db_connector )
{
db_connector->get_value(val_str, field_value);
}
}
}
}
////
template<typename FieldValue>
void doc_field_generic(const wchar_t * db_field_name, const wchar_t * flat_field_name, FieldValue & field_value)
@ -966,7 +987,8 @@ protected:
virtual bool is_empty_field(const wchar_t * value);
template<typename ModelClass> friend class Finder;
// template<typename ModelClass> friend class Finder;
template<typename ModelClass> friend class Cursor;
friend class BaseExpression;
};

View File

@ -197,28 +197,5 @@ Clearer * ModelConnector::get_clearer()
bool ModelConnector::was_db_error()
{
if( db_connector )
{
return db_connector->was_error_in_last_query();
}
return false;
}
std::wstring ModelConnector::get_db_error()
{
if( db_connector )
{
return db_connector->get_last_query_error_msg();
}
return std::wstring();
}
}

View File

@ -56,17 +56,12 @@ class ModelConnector
public:
ModelConnector();
ModelConnector(const ModelConnector &) = delete;
virtual ~ModelConnector();
virtual void set_logger(PT::Logger * logger);
virtual void set_logger(PT::Logger & logger);
// FIX ME
// add c-copy ctr (allocate a new stream and expression)
virtual bool was_db_error();
virtual std::wstring get_db_error();
virtual void set_stream(PT::TextStream & stream);
virtual PT::TextStream * get_stream();

View File

@ -61,149 +61,12 @@ void PostgreSQLConnector::close()
{
if( pg_conn )
{
clear_all_query_results();
PQfinish(pg_conn);
pg_conn = nullptr;
}
}
void PostgreSQLConnector::clear_all_query_results()
{
while( !query_results.empty() )
{
clear_last_query_result();
}
}
void PostgreSQLConnector::clear_last_query_result()
{
if( !query_results.empty() )
{
QueryResult & res = query_results.back();
if( res.result )
{
PQclear(res.result);
}
res.result = nullptr;
res.result_rows = 0;
res.status = PGRES_EMPTY_QUERY;
res.cur_row = 0;
res.error_msg.clear(); // may overwrite it first?
res.was_error = false;
query_results.pop_back();
}
}
// to nie tylko dla selectow moze byc uzywane
size_t PostgreSQLConnector::last_select_size()
{
if( !query_results.empty() )
{
return query_results.back().result_rows;
}
return 0;
}
ExecStatusType PostgreSQLConnector::last_query_status()
{
if( !query_results.empty() )
{
return query_results.back().status;
}
return PGRES_EMPTY_QUERY;
}
bool PostgreSQLConnector::is_last_result(ExecStatusType t)
{
if( !query_results.empty() )
{
QueryResult & res = query_results.back();
return (res.result && PQresultStatus(res.result) == t);
}
return false;
}
std::wstring PostgreSQLConnector::get_last_query_error_msg()
{
if( !query_results.empty() )
{
return query_results.back().error_msg;
}
return std::wstring();
}
void PostgreSQLConnector::set_last_query_error_msg()
{
if( pg_conn )
{
set_last_query_error_msg(PQerrorMessage(pg_conn));
}
}
void PostgreSQLConnector::set_last_query_error_msg(const char * error_msg)
{
if( !query_results.empty() )
{
if( error_msg )
{
PT::UTF8ToWide(error_msg, query_results.back().error_msg);
}
else
{
query_results.back().error_msg.clear();
}
}
}
void PostgreSQLConnector::set_last_query_error_msg(const wchar_t * error_msg)
{
if( !query_results.empty() )
{
if( error_msg )
{
query_results.back().error_msg = error_msg;
}
else
{
query_results.back().error_msg.clear();
}
}
}
bool PostgreSQLConnector::was_error_in_last_query()
{
if( !query_results.empty() )
{
return query_results.back().was_error;
}
return false;
}
void PostgreSQLConnector::set_was_error_in_last_query(bool was_error)
{
if( !query_results.empty() )
{
query_results.back().was_error = was_error;
}
}
void PostgreSQLConnector::allocate_default_expression()
{
@ -220,76 +83,106 @@ void PostgreSQLConnector::set_log_queries(bool log_queries)
}
bool PostgreSQLConnector::query(const char * query_str)
QueryResult * PostgreSQLConnector::create_query_result()
{
if( pg_conn )
return new PostgreSQLQueryResult();
}
bool PostgreSQLConnector::do_query(const char * query_str, PostgreSQLQueryResult * psql_result)
{
if( pg_conn && psql_result )
{
if( log_queries && logger )
{
(*logger) << PT::Logger::log1 << "Db: executing query: " << query_str << PT::Logger::logend << PT::Logger::logsave;
}
query_results.push_back(QueryResult());
QueryResult & last_res = query_results.back();
psql_result->result = PQexec(pg_conn, query_str);
last_res.result = PQexec(pg_conn, query_str);
if( !last_res.result )
if( !psql_result->result )
{
if( PQstatus(pg_conn) != CONNECTION_OK )
{
assert_connection();
last_res.result = PQexec(pg_conn, query_str);
psql_result->result = PQexec(pg_conn, query_str);
}
}
if( last_res.result )
if( psql_result->result )
{
last_res.status = PQresultStatus(last_res.result);
last_res.result_rows = static_cast<size_t>(PQntuples(last_res.result));
psql_result->status = PQresultStatus(psql_result->result);
psql_result->result_rows = static_cast<size_t>(PQntuples(psql_result->result));
}
if( !last_res.result || last_res.status == PGRES_FATAL_ERROR )
if( !psql_result->result || psql_result->status == PGRES_FATAL_ERROR )
{
psql_result->was_error = true;
const char * err_msg = PQerrorMessage(pg_conn);
if( err_msg )
{
PT::UTF8ToWide(err_msg, psql_result->error_msg);
}
if( logger )
{
(*logger) << PT::Logger::log1 << "Db: Problem with this query: \"" << query_str << '\"' << PT::Logger::logend << PT::Logger::logsave;
(*logger) << PT::Logger::log1 << "Db: " << PQerrorMessage(pg_conn) << PT::Logger::logend << PT::Logger::logsave;
if( err_msg )
(*logger) << PT::Logger::log1 << "Db: " << err_msg << PT::Logger::logend << PT::Logger::logsave;
}
}
}
return (!query_results.empty() && query_results.back().result != nullptr);
return (psql_result && psql_result->result != nullptr);
}
bool PostgreSQLConnector::query(const char * query_str, QueryResult & query_result)
{
PostgreSQLQueryResult * psql_result = dynamic_cast<PostgreSQLQueryResult*>(&query_result);
return do_query(query_str, psql_result);
}
const char * PostgreSQLConnector::query_last_sequence(const wchar_t * sequence_table_name)
{
allocate_default_expression_if_needed();
if( db_expression )
{
PostgreSQLQueryResult psql_result;
stream.clear();
stream << "select currval(E'";
db_expression->esc(sequence_table_name, stream);
stream << "');";
if( query_select(stream) )
if( query_select(stream, psql_result) )
{
if( last_select_size() == 1 )
if( psql_result.result_rows == 1 )
{
return get_value_from_result(0, 0);
return psql_result.get_value_from_result(0, 0);
}
else
{
if( pg_conn && logger )
if( logger )
{
(*logger) << PT::Logger::log1 << "Db: error (currval) for table: " << sequence_table_name << ", "
<< PQerrorMessage(pg_conn) << PT::Logger::logend << PT::Logger::logsave;
(*logger) << PT::Logger::log1 << "Db: expected only one row in sequence result, has: " << psql_result.result_rows
<< PT::Logger::logend << PT::Logger::logsave;
}
}
}
else
{
if( pg_conn && logger )
{
(*logger) << PT::Logger::log1 << "Db: error (currval) for table: " << sequence_table_name << ", "
<< PQerrorMessage(pg_conn) << PT::Logger::logend << PT::Logger::logsave;
}
}
}
return nullptr;
@ -297,323 +190,108 @@ const char * PostgreSQLConnector::query_last_sequence(const wchar_t * sequence_t
bool PostgreSQLConnector::query(const PT::TextStream & stream)
bool PostgreSQLConnector::query(const PT::TextStream & stream, QueryResult & query_result)
{
stream.to_string(query_str);
return query(query_str.c_str());
return query(query_str.c_str(), query_result);
}
bool PostgreSQLConnector::query(const std::string & query_str)
bool PostgreSQLConnector::query(const std::string & query_str, QueryResult & query_result)
{
return query(query_str.c_str());
return query(query_str.c_str(), query_result);
}
bool PostgreSQLConnector::query_select(const char * query_str)
bool PostgreSQLConnector::query_select(const char * query_str, QueryResult & query_result)
{
bool result = (query(query_str) && last_query_status() == PGRES_TUPLES_OK);
PostgreSQLQueryResult * psql_result = dynamic_cast<PostgreSQLQueryResult*>(&query_result);
bool result = false;
if( !result )
if( psql_result )
{
set_was_error_in_last_query(true);
set_last_query_error_msg();
}
return result;
}
bool PostgreSQLConnector::query_update(const char * query_str)
{
bool result = (query(query_str) && last_query_status() == PGRES_COMMAND_OK);
if( !result )
{
set_was_error_in_last_query(true);
set_last_query_error_msg();
}
return result;
}
bool PostgreSQLConnector::query_insert(const char * query_str)
{
bool result = (query(query_str) && last_query_status() == PGRES_COMMAND_OK);
if( !result )
{
set_was_error_in_last_query(true);
set_last_query_error_msg();
}
return result;
}
bool PostgreSQLConnector::query_remove(const char * query_str)
{
bool result = (query(query_str) && last_query_status() == PGRES_COMMAND_OK);
if( !result )
{
set_was_error_in_last_query(true);
set_last_query_error_msg();
result = (do_query(query_str, psql_result) && psql_result->status == PGRES_TUPLES_OK);
}
return result;
}
bool PostgreSQLConnector::query_select(const PT::TextStream & stream)
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->status == PGRES_COMMAND_OK);
}
return result;
}
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->status == PGRES_COMMAND_OK);
}
return result;
}
bool PostgreSQLConnector::query_remove(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->status == PGRES_COMMAND_OK);
}
return result;
}
bool PostgreSQLConnector::query_select(const PT::TextStream & stream, QueryResult & query_result)
{
stream.to_string(query_str);
return query_select(query_str.c_str());
return query_select(query_str.c_str(), query_result);
}
bool PostgreSQLConnector::query_update(const PT::TextStream & stream)
bool PostgreSQLConnector::query_update(const PT::TextStream & stream, QueryResult & query_result)
{
stream.to_string(query_str);
return query_update(query_str.c_str());
return query_update(query_str.c_str(), query_result);
}
bool PostgreSQLConnector::query_insert(const PT::TextStream & stream)
bool PostgreSQLConnector::query_insert(const PT::TextStream & stream, QueryResult & query_result)
{
stream.to_string(query_str);
return query_insert(query_str.c_str());
return query_insert(query_str.c_str(), query_result);
}
bool PostgreSQLConnector::query_remove(const PT::TextStream & stream)
bool PostgreSQLConnector::query_remove(const PT::TextStream & stream, QueryResult & query_result)
{
stream.to_string(query_str);
return query_remove(query_str.c_str());
return query_remove(query_str.c_str(), query_result);
}
//int PostgreSQLConnector::Rows(PGresult * r)
//{
// // PQntuples - Returns the number of rows (tuples) in the query result. Because it returns
// // an integer result, large result sets might overflow the return value on 32-bit operating systems.
// return PQntuples(r);
//}
//int PostgreSQLConnector::Cols(PGresult * r)
//{
// // PQnfields - Returns the number of columns (fields) in each row of the query result.
// return PQnfields(r);
//}
//long PostgreSQLConnector::AffectedRows(PGresult * r)
//{
// // PQcmdTuples - This function returns a string containing the number of rows affected by the SQL
// // statement that generated the PGresult. This function can only be used following the execution
// // of an INSERT, UPDATE, DELETE, MOVE, FETCH, or COPY statement, or [...]
// char * rows_str = PQcmdTuples(r); // can be an empty string
// long rows = 0;
//
// if( rows_str )
// {
// rows = strtol(rows_str, 0, 10);
// // strtol - If an overflow or underflow occurs, errno is set to ERANGE
// // and the function return value is clamped according to the following table:
// // Function underflow overflow
// // strtol() LONG_MIN LONG_MAX
//
// if( rows < 0 )
// rows = 0;
// }
//
//return rows;
//}
void PostgreSQLConnector::set_current_row_at_beginning()
{
if( !query_results.empty() )
{
query_results.back().cur_row = 0;
}
}
void PostgreSQLConnector::advance_current_row()
{
if( !query_results.empty() )
{
query_results.back().cur_row += 1;
}
}
int PostgreSQLConnector::get_column_index(const char * column_name)
{
int col_index = -1;
if( !query_results.empty() )
{
QueryResult & res = query_results.back();
if( res.result )
{
col_index = PQfnumber(res.result, column_name);
// returns -1 if there is no such a column
}
}
return col_index;
}
int PostgreSQLConnector::get_column_index(const wchar_t * column_name)
{
PT::WideToUTF8(column_name, temp_column_name);
return get_column_index(temp_column_name.c_str());
}
//const char * PostgreSQLConnector::get_field_string_value(const wchar_t * field_name)
const char * PostgreSQLConnector::get_field_string_value(const char * column_name)
{
const char * value_str = nullptr;
if( !query_results.empty() )
{
QueryResult & res = query_results.back();
if( res.result )
{
int col_index = PQfnumber(res.result, column_name);
if( col_index != -1 )
{
if( res.cur_row < res.result_rows )
{
value_str = PQgetvalue(res.result, res.cur_row, col_index);
}
}
}
}
return value_str;
}
const char * PostgreSQLConnector::get_field_string_value(const wchar_t * column_name)
{
PT::WideToUTF8(column_name, temp_column_name);
return get_field_string_value(temp_column_name.c_str());
}
const char * PostgreSQLConnector::get_value_from_result(int row, int col)
{
const char * value_str = nullptr;
if( !query_results.empty() )
{
QueryResult & res = query_results.back();
if( res.result )
{
value_str = PQgetvalue(res.result, row, col);
// can return a null pointer if there is no such an item in the last result
}
}
return value_str;
}
int PostgreSQLConnector::get_value_length(int row, int col)
{
int len = 0;
if( !query_results.empty() )
{
QueryResult & res = query_results.back();
if( res.result )
{
len = PQgetlength(res.result, row, col);
}
}
return len;
}
//void PostgreSQLConnector::get_value_bin(int row, int col, std::string & result, bool clear_string)
//{
// if( clear_string )
// result.clear();
//
// const char * raw_result = get_value(row, col);
//
// if( raw_result )
// {
// int len = PQgetlength(last_result, row, col);
//
// if( len > 0 )
// {
// unescape_bin(raw_result, len, result);
// }
// }
//}
//bool PostgreSQLConnector::AssertValueSpace(PGresult * r, int row, int col, PT::Space & space)
//{
// const char * res = AssertValue(r, row, col);
//
// conf_parser.SetSpace(space);
// space.Clear();
//
// PT::SpaceParser::Status status = conf_parser.ParseString(res);
//
// if( status != PT::SpaceParser::ok )
// {
// log << log1 << "Db: a problem with parsing a PT::Space";
//
// if( status == PT::SpaceParser::syntax_error )
// log << ", syntax error at line: " << conf_parser.line;
//
// log << logend;
//
// space.Clear();
// return false;
// }
//
//return true;
//}
bool PostgreSQLConnector::is_null(int row, int col)
{
bool is_null = false;
if( !query_results.empty() )
{
QueryResult & res = query_results.back();
if( res.result )
{
is_null = (PQgetisnull(res.result, row, col) == 1);
}
}
return is_null;
}

View File

@ -35,9 +35,10 @@
#ifndef headerfile_morm_postgresqlconnector
#define headerfile_morm_postgresqlconnector
#include "dbconnector.h"
#include <libpq-fe.h>
#include <string>
#include "dbconnector.h"
#include "postgresqlqueryresult.h"
@ -49,85 +50,42 @@ class PostgreSQLConnector : public DbConnector
public:
PostgreSQLConnector();
PostgreSQLConnector(const PostgreSQLConnector &) = delete;
virtual ~PostgreSQLConnector();
void clear_all_query_results();
void clear_last_query_result();
virtual void set_log_queries(bool log_queries);
// give me a better names
virtual size_t last_select_size();
virtual ExecStatusType last_query_status();
virtual bool is_last_result(ExecStatusType t); // was: is_last_result
bool query(const PT::TextStream & stream, QueryResult & query_result);
bool query(const char * query_str, QueryResult & query_result);
bool query(const std::string & query_str, QueryResult & query_result);
virtual std::wstring get_last_query_error_msg();
virtual void set_last_query_error_msg(const char * error_msg);
virtual void set_last_query_error_msg(const wchar_t * error_msg);
bool query_select(const char * query_str, QueryResult & query_result);
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);
virtual bool was_error_in_last_query();
virtual void set_was_error_in_last_query(bool was_error);
void set_log_queries(bool log_queries);
bool query(const PT::TextStream & stream);
bool query(const char * query_str);
bool query(const std::string & query_str);
bool query_select(const char * query_str);
bool query_update(const char * query_str);
bool query_insert(const char * query_str);
bool query_remove(const char * query_str);
bool query_select(const PT::TextStream & stream);
bool query_update(const PT::TextStream & stream);
bool query_insert(const PT::TextStream & stream);
bool query_remove(const PT::TextStream & stream);
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);
// give me a better name
virtual void set_current_row_at_beginning();
virtual void advance_current_row();
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();
/*
* get column index from the last query (select)
* returns -1 if there is no such a column
*
*/
int get_column_index(const char * column_name);
int get_column_index(const wchar_t * column_name);
bool is_null(int row, int col);
/*
* return an item from the last query
* can return a null pointer if there is no such an item in the last result
*
*/
const char * get_value_from_result(int row, int col);
int get_value_length(int row, int col);
void set_conn_param(const std::wstring & database, const std::wstring & user, const std::wstring & pass);
void connect();
void wait_for_connection();
void close();
//bool assert_connection(bool put_log = true, bool throw_if_no_connection = true);
bool assert_connection(bool put_log = true);
void set_db_parameters();
void log_connection_socket();
//PGconn * GetPgConn();
protected:
PGconn * pg_conn;
// PGresult * last_result; // can be null
// size_t last_result_rows; // how many rows in the last result query
// ExecStatusType last_status;
bool log_queries;
PT::TextStream stream;
std::string query_str;
@ -137,35 +95,13 @@ protected:
std::wstring db_user;
std::wstring db_pass;
struct QueryResult
{
PGresult * result; // can be null
size_t result_rows; // how many rows in the result query
ExecStatusType status;
size_t cur_row; // used for reading
bool was_error;
std::wstring error_msg;
QueryResult()
{
result = nullptr;
result_rows = 0;
status = PGRES_EMPTY_QUERY;
cur_row = 0;
was_error = false;
}
};
std::vector<QueryResult> query_results;
virtual bool do_query(const char * query_str, PostgreSQLQueryResult * psql_result);
virtual void allocate_default_expression();
virtual void overwrite(PT::TextStream & stream);
virtual const char * query_last_sequence(const wchar_t * sequence_table_name);
virtual QueryResult * create_query_result();
void allocate_default_expression();
void overwrite(PT::TextStream & stream);
virtual const char * get_field_string_value(const char * column_name);
virtual const char * get_field_string_value(const wchar_t * field_name);
virtual void set_last_query_error_msg();
const char * query_last_sequence(const wchar_t * sequence_table_name);
};
}

View File

@ -0,0 +1,234 @@
/*
* 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) 2018, 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 "postgresqlqueryresult.h"
namespace morm
{
PostgreSQLQueryResult::PostgreSQLQueryResult()
{
result = nullptr;
status = PGRES_EMPTY_QUERY;
}
void PostgreSQLQueryResult::clear()
{
if( result )
{
PQclear(result);
}
result = nullptr;
status = PGRES_EMPTY_QUERY;
QueryResult::clear();
}
bool PostgreSQLQueryResult::has_db_result()
{
return result != nullptr;
}
const char * PostgreSQLQueryResult::get_field_string_value(const char * column_name)
{
const char * value_str = nullptr;
if( result )
{
int col_index = PQfnumber(result, column_name);
if( col_index != -1 )
{
if( cur_row < result_rows )
{
value_str = PQgetvalue(result, cur_row, col_index);
}
}
}
return value_str;
}
int PostgreSQLQueryResult::get_column_index(const char * column_name)
{
int col_index = -1;
if( result )
{
col_index = PQfnumber(result, column_name);
// returns -1 if there is no such a column
}
return col_index;
}
const char * PostgreSQLQueryResult::get_value_from_result(int row, int col)
{
const char * value_str = nullptr;
if( result )
{
value_str = PQgetvalue(result, row, col);
// can return a null pointer if there is no such an item in the last result
}
return value_str;
}
int PostgreSQLQueryResult::get_value_length(int row, int col)
{
int len = 0;
if( result )
{
len = PQgetlength(result, row, col);
}
return len;
}
bool PostgreSQLQueryResult::is_null(int row, int col)
{
bool is_null = false;
if( result )
{
is_null = (PQgetisnull(result, row, col) == 1);
}
return is_null;
}
//int PostgreSQLQueryResult::Rows(PGresult * r)
//{
// // PQntuples - Returns the number of rows (tuples) in the query result. Because it returns
// // an integer result, large result sets might overflow the return value on 32-bit operating systems.
// return PQntuples(r);
//}
//int PostgreSQLQueryResult::Cols(PGresult * r)
//{
// // PQnfields - Returns the number of columns (fields) in each row of the query result.
// return PQnfields(r);
//}
//long PostgreSQLQueryResult::AffectedRows(PGresult * r)
//{
// // PQcmdTuples - This function returns a string containing the number of rows affected by the SQL
// // statement that generated the PGresult. This function can only be used following the execution
// // of an INSERT, UPDATE, DELETE, MOVE, FETCH, or COPY statement, or [...]
// char * rows_str = PQcmdTuples(r); // can be an empty string
// long rows = 0;
//
// if( rows_str )
// {
// rows = strtol(rows_str, 0, 10);
// // strtol - If an overflow or underflow occurs, errno is set to ERANGE
// // and the function return value is clamped according to the following table:
// // Function underflow overflow
// // strtol() LONG_MIN LONG_MAX
//
// if( rows < 0 )
// rows = 0;
// }
//
//return rows;
//}
//void PostgreSQLConnector::get_value_bin(int row, int col, std::string & result, bool clear_string)
//{
// if( clear_string )
// result.clear();
//
// const char * raw_result = get_value(row, col);
//
// if( raw_result )
// {
// int len = PQgetlength(last_result, row, col);
//
// if( len > 0 )
// {
// unescape_bin(raw_result, len, result);
// }
// }
//}
//bool PostgreSQLConnector::AssertValueSpace(PGresult * r, int row, int col, PT::Space & space)
//{
// const char * res = AssertValue(r, row, col);
//
// conf_parser.SetSpace(space);
// space.Clear();
//
// PT::SpaceParser::Status status = conf_parser.ParseString(res);
//
// if( status != PT::SpaceParser::ok )
// {
// log << log1 << "Db: a problem with parsing a PT::Space";
//
// if( status == PT::SpaceParser::syntax_error )
// log << ", syntax error at line: " << conf_parser.line;
//
// log << logend;
//
// space.Clear();
// return false;
// }
//
//return true;
//}
} // namespace

View File

@ -0,0 +1,74 @@
/*
* 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) 2018, 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_postgresqlqueryresult
#define headerfile_morm_postgresqlqueryresult
#include "queryresult.h"
#include <libpq-fe.h>
namespace morm
{
struct PostgreSQLQueryResult : public QueryResult
{
PGresult * result; // can be null
ExecStatusType status;
PostgreSQLQueryResult();
virtual void clear();
virtual bool has_db_result();
const char * get_field_string_value(const char * column_name);
int get_column_index(const char * column_name);
const char * get_value_from_result(int row, int col);
int get_value_length(int row, int col);
bool is_null(int row, int col);
};
} // namespace
#endif

120
src/queryresult.cpp Normal file
View File

@ -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) 2018, 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 "queryresult.h"
#include "utf8/utf8.h"
namespace morm
{
QueryResult::QueryResult()
{
clear();
references_count = 0;
}
QueryResult::~QueryResult()
{
clear();
}
void QueryResult::clear()
{
result_rows = 0;
cur_row = 0;
was_error = false;
error_msg.clear();
temp_column_name.clear();
}
bool QueryResult::has_db_result()
{
return false;
}
const char * QueryResult::get_field_string_value(const char * column_name)
{
return nullptr;
}
const char * QueryResult::get_field_string_value(const wchar_t * column_name)
{
PT::WideToUTF8(column_name, temp_column_name);
return get_field_string_value(temp_column_name.c_str());
}
int QueryResult::get_column_index(const char * column_name)
{
return -1;
}
int QueryResult::get_column_index(const wchar_t * column_name)
{
PT::WideToUTF8(column_name, temp_column_name);
return get_column_index(temp_column_name.c_str());
}
const char * QueryResult::get_value_from_result(int row, int col)
{
return nullptr;
}
int QueryResult::get_value_length(int row, int col)
{
return 0;
}
bool QueryResult::is_null(int row, int col)
{
return true;
}
} // namespace

81
src/queryresult.h 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) 2018, 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_queryresult
#define headerfile_morm_queryresult
#include <string>
namespace morm
{
struct QueryResult
{
size_t result_rows; // how many rows in the result query
size_t cur_row; // used for reading
bool was_error;
std::wstring error_msg;
std::string temp_column_name;
size_t references_count;
QueryResult();
virtual ~QueryResult();
virtual void clear();
virtual bool has_db_result();
virtual const char * get_field_string_value(const char * column_name);
virtual const char * get_field_string_value(const wchar_t * field_name);
/*
* returns -1 if there is no such a column
*
*/
virtual int get_column_index(const char * column_name);
virtual int get_column_index(const wchar_t * column_name);
// may it should be changed to size_t?
virtual const char * get_value_from_result(int row, int col);
virtual int get_value_length(int row, int col);
virtual bool is_null(int row, int col);
};
} // namespace
#endif