added: QueryResult stack to PostgreSQLConnector
this allowes us to call query() recursively (from after_select() callback) git-svn-id: svn://ttmath.org/publicrep/morm/trunk@1085 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
parent
7bae5224e5
commit
ffb7ac85a6
|
@ -60,6 +60,10 @@ DbConnector::~DbConnector()
|
|||
}
|
||||
|
||||
|
||||
void DbConnector::clear_last_query_result()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
bool DbConnector::query(const PT::TextStream & stream)
|
||||
{
|
||||
|
@ -229,6 +233,11 @@ 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;
|
||||
|
|
|
@ -55,6 +55,8 @@ public:
|
|||
|
||||
DbExpression * get_expression();
|
||||
|
||||
virtual void clear_last_query_result();
|
||||
|
||||
virtual void generate_select_columns(PT::TextStream & stream, Model & model);
|
||||
virtual void generate_insert_query(PT::TextStream & stream, Model & model);
|
||||
virtual void generate_update_query(PT::TextStream & stream, Model & model);
|
||||
|
@ -155,6 +157,8 @@ protected:
|
|||
virtual void allocate_default_expression() = 0;
|
||||
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);
|
||||
|
|
20
src/finder.h
20
src/finder.h
|
@ -277,6 +277,8 @@ public:
|
|||
{
|
||||
res = db_connector->query_select(*out_stream);
|
||||
|
||||
try
|
||||
{
|
||||
if( res )
|
||||
{
|
||||
result.set_object_exists(true);
|
||||
|
@ -291,6 +293,14 @@ public:
|
|||
// put some log here?
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
// throw something?
|
||||
// if yes then make sure to call db_connector->clear_last_query_result();
|
||||
}
|
||||
|
||||
db_connector->clear_last_query_result();
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -321,6 +331,8 @@ public:
|
|||
{
|
||||
res = db_connector->query_select(*out_stream);
|
||||
|
||||
try
|
||||
{
|
||||
if( res )
|
||||
{
|
||||
size_t len = db_connector->last_select_size();
|
||||
|
@ -344,6 +356,14 @@ public:
|
|||
// put some log here?
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
// throw or something?
|
||||
// make sure to call db_connector->clear_last_query_result()
|
||||
}
|
||||
|
||||
db_connector->clear_last_query_result();
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
|
|
|
@ -48,17 +48,92 @@ PostgreSQLConnector::PostgreSQLConnector()
|
|||
{
|
||||
pg_conn = nullptr;
|
||||
log_queries = false;
|
||||
last_status = PGRES_EMPTY_QUERY;
|
||||
last_result = nullptr;
|
||||
last_result_rows = 0;
|
||||
cur_row = 0;
|
||||
}
|
||||
|
||||
|
||||
PostgreSQLConnector::~PostgreSQLConnector()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void PostgreSQLConnector::allocate_default_expression()
|
||||
{
|
||||
deallocate_expression();
|
||||
|
@ -76,34 +151,40 @@ void PostgreSQLConnector::set_log_queries(bool log_queries)
|
|||
|
||||
bool PostgreSQLConnector::query(const char * query_str)
|
||||
{
|
||||
// if( pg_conn )
|
||||
{
|
||||
// if( log_queries )
|
||||
// {
|
||||
// log << log1 << "Db: executing query: " << q << logend;
|
||||
// }
|
||||
|
||||
last_status = PGRES_EMPTY_QUERY; // or something else?
|
||||
last_result_rows = 0;
|
||||
last_result = PQexec(pg_conn, query_str);
|
||||
query_results.push_back(QueryResult());
|
||||
QueryResult & last_res = query_results.back();
|
||||
|
||||
if( !last_result )
|
||||
last_res.result = PQexec(pg_conn, query_str);
|
||||
|
||||
if( !last_res.result )
|
||||
{
|
||||
if( PQstatus(pg_conn) != CONNECTION_OK )
|
||||
{
|
||||
assert_connection();
|
||||
last_result = PQexec(pg_conn, query_str);
|
||||
last_res.result = PQexec(pg_conn, query_str);
|
||||
}
|
||||
}
|
||||
|
||||
if( last_result )
|
||||
if( last_res.result )
|
||||
{
|
||||
last_status = PQresultStatus(last_result);
|
||||
last_result_rows = static_cast<size_t>(PQntuples(last_result));
|
||||
last_res.status = PQresultStatus(last_res.result);
|
||||
last_res.result_rows = static_cast<size_t>(PQntuples(last_res.result));
|
||||
}
|
||||
else
|
||||
{
|
||||
// log << log1 << "Db: Problem with this query: \"" << q << '\"' << logend;
|
||||
// log << log1 << "Db: " << PQerrorMessage(db_conn->GetPgConn()) << logend;
|
||||
// log << log1 << "Db: Problem with this query: \"" << q << '\"' << logend;
|
||||
// log << log1 << "Db: " << PQerrorMessage(pg_conn) << logend;
|
||||
}
|
||||
}
|
||||
|
||||
return last_result != nullptr;
|
||||
return (!query_results.empty() && query_results.back().result != nullptr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -121,7 +202,7 @@ const char * PostgreSQLConnector::query_last_sequence(const wchar_t * sequence_t
|
|||
|
||||
if( query_select(stream) )
|
||||
{
|
||||
if( last_result_rows == 1 )
|
||||
if( last_select_size() == 1 )
|
||||
{
|
||||
return get_value(0, 0);
|
||||
}
|
||||
|
@ -152,17 +233,17 @@ bool PostgreSQLConnector::query(const std::string & query_str)
|
|||
|
||||
bool PostgreSQLConnector::query_select(const char * query_str)
|
||||
{
|
||||
return (query(query_str) && last_status == PGRES_TUPLES_OK);
|
||||
return (query(query_str) && last_query_status() == PGRES_TUPLES_OK);
|
||||
}
|
||||
|
||||
bool PostgreSQLConnector::query_update(const char * query_str)
|
||||
{
|
||||
return (query(query_str) && last_status == PGRES_COMMAND_OK);
|
||||
return (query(query_str) && last_query_status() == PGRES_COMMAND_OK);
|
||||
}
|
||||
|
||||
bool PostgreSQLConnector::query_insert(const char * query_str)
|
||||
{
|
||||
return (query(query_str) && last_status == PGRES_COMMAND_OK);
|
||||
return (query(query_str) && last_query_status() == PGRES_COMMAND_OK);
|
||||
}
|
||||
|
||||
|
||||
|
@ -187,17 +268,8 @@ bool PostgreSQLConnector::query_insert(const PT::TextStream & stream)
|
|||
|
||||
|
||||
|
||||
bool PostgreSQLConnector::is_last_result(ExecStatusType t)
|
||||
{
|
||||
return (last_result && PQresultStatus(last_result) == t);
|
||||
}
|
||||
|
||||
|
||||
// to nie tylko dla selectow moze byc uzywane
|
||||
size_t PostgreSQLConnector::last_select_size()
|
||||
{
|
||||
return last_result_rows;
|
||||
}
|
||||
|
||||
//int PostgreSQLConnector::Rows(PGresult * r)
|
||||
//{
|
||||
|
@ -241,47 +313,118 @@ size_t PostgreSQLConnector::last_select_size()
|
|||
|
||||
void PostgreSQLConnector::set_current_row_at_beginning()
|
||||
{
|
||||
cur_row = 0;
|
||||
if( !query_results.empty() )
|
||||
{
|
||||
query_results.back().cur_row = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PostgreSQLConnector::advance_current_row()
|
||||
{
|
||||
cur_row += 1;
|
||||
if( !query_results.empty() )
|
||||
{
|
||||
query_results.back().cur_row += 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int PostgreSQLConnector::get_column_index(const char * column_name)
|
||||
{
|
||||
int c = PQfnumber(last_result, column_name);
|
||||
// returns -1 if there is no such a column
|
||||
int col_index = -1;
|
||||
|
||||
return c;
|
||||
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)
|
||||
{
|
||||
// temporary
|
||||
std::string s; // move me somewhere?
|
||||
PT::WideToUTF8(column_name, s);
|
||||
return get_column_index(s.c_str());
|
||||
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(int row, int col)
|
||||
{
|
||||
const char * res = PQgetvalue(last_result, row, col);
|
||||
// can return a null pointer if there is no such an item in the last result
|
||||
const char * value_str = nullptr;
|
||||
|
||||
return res;
|
||||
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 = PQgetlength(last_result, row, col);
|
||||
int len = 0;
|
||||
|
||||
if( !query_results.empty() )
|
||||
{
|
||||
QueryResult & res = query_results.back();
|
||||
|
||||
if( res.result )
|
||||
{
|
||||
len = PQgetlength(res.result, row, col);
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -333,25 +476,23 @@ int PostgreSQLConnector::get_value_length(int row, int col)
|
|||
|
||||
|
||||
|
||||
void PostgreSQLConnector::clear_result()
|
||||
{
|
||||
if( last_result )
|
||||
{
|
||||
PQclear(last_result);
|
||||
last_result = nullptr;
|
||||
last_result_rows = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PostgreSQLConnector::is_null(int row, int col)
|
||||
{
|
||||
if( last_result )
|
||||
bool is_null = false;
|
||||
|
||||
if( !query_results.empty() )
|
||||
{
|
||||
return PQgetisnull(last_result, row, col) == 1;
|
||||
QueryResult & res = query_results.back();
|
||||
|
||||
if( res.result )
|
||||
{
|
||||
is_null = (PQgetisnull(res.result, row, col) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return is_null;
|
||||
}
|
||||
|
||||
|
||||
|
@ -595,6 +736,9 @@ void PostgreSQLConnector::overwrite(PT::TextStream & stream)
|
|||
|
||||
void PostgreSQLConnector::connect()
|
||||
{
|
||||
// IMPROVEME
|
||||
// what about if reconnecting is made in the midle of queries?
|
||||
// e.g. in after_select? (the whole stack query_results will be cleared)
|
||||
close();
|
||||
|
||||
allocate_default_expression_if_needed();
|
||||
|
@ -645,7 +789,7 @@ void PostgreSQLConnector::wait_for_connection()
|
|||
//log << log3 << "Db: waiting for the db to be ready...." << logend << logsave;
|
||||
//std::cout << "Db: waiting for the db to be ready...." << std::endl;
|
||||
|
||||
while( !assert_connection(false, false) )
|
||||
while( !assert_connection(false) )
|
||||
{
|
||||
sleep(5);
|
||||
}
|
||||
|
@ -656,19 +800,9 @@ void PostgreSQLConnector::wait_for_connection()
|
|||
|
||||
|
||||
|
||||
void PostgreSQLConnector::close()
|
||||
{
|
||||
if( pg_conn )
|
||||
{
|
||||
PQfinish(pg_conn);
|
||||
pg_conn = nullptr;
|
||||
last_result = nullptr;
|
||||
last_result_rows = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool PostgreSQLConnector::assert_connection(bool put_log, bool throw_if_no_connection)
|
||||
// IMPROVE ME what about the exception now?
|
||||
bool PostgreSQLConnector::assert_connection(bool put_log)
|
||||
{
|
||||
bool was_connection = true;
|
||||
|
||||
|
@ -712,11 +846,11 @@ bool was_connection = true;
|
|||
//std::cout << "Db: connection to db server cannot be established" << std::endl;
|
||||
}
|
||||
|
||||
if( throw_if_no_connection )
|
||||
{
|
||||
//throw Error(WINIX_ERR_DB_FATAL_ERROR_DURING_CONNECTING);
|
||||
throw int(10);
|
||||
}
|
||||
// if( throw_if_no_connection )
|
||||
// {
|
||||
// //throw Error(WINIX_ERR_DB_FATAL_ERROR_DURING_CONNECTING);
|
||||
// throw int(10);
|
||||
// }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -732,21 +866,6 @@ void PostgreSQLConnector::set_db_parameters()
|
|||
}
|
||||
|
||||
|
||||
const char * PostgreSQLConnector::get_field_string_value(const wchar_t * field_name)
|
||||
{
|
||||
int c = get_column_index(field_name);
|
||||
|
||||
if( c != -1 )
|
||||
{
|
||||
if( cur_row < last_result_rows )
|
||||
{
|
||||
return get_value(cur_row, c);
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -50,6 +50,15 @@ public:
|
|||
PostgreSQLConnector();
|
||||
virtual ~PostgreSQLConnector();
|
||||
|
||||
void clear_all_query_results();
|
||||
void clear_last_query_result();
|
||||
|
||||
// give me a better names
|
||||
virtual size_t last_select_size(); // was: last_select_size
|
||||
virtual ExecStatusType last_query_status();
|
||||
virtual bool is_last_result(ExecStatusType t); // was: is_last_result
|
||||
|
||||
|
||||
void set_log_queries(bool log_queries);
|
||||
|
||||
bool query(const PT::TextStream & stream);
|
||||
|
@ -64,15 +73,12 @@ public:
|
|||
bool query_update(const PT::TextStream & stream);
|
||||
bool query_insert(const PT::TextStream & stream);
|
||||
|
||||
// give me a better name
|
||||
virtual size_t last_select_size();
|
||||
|
||||
// give me a better name
|
||||
virtual void set_current_row_at_beginning();
|
||||
virtual void advance_current_row();
|
||||
|
||||
|
||||
bool is_last_result(ExecStatusType t);
|
||||
|
||||
/*
|
||||
* get column index from the last query (select)
|
||||
|
@ -93,40 +99,61 @@ public:
|
|||
int get_value_length(int row, int col);
|
||||
|
||||
|
||||
void clear_result();
|
||||
|
||||
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, 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;
|
||||
// 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;
|
||||
size_t cur_row;
|
||||
std::string temp_column_name;
|
||||
|
||||
std::wstring db_database;
|
||||
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
|
||||
|
||||
QueryResult()
|
||||
{
|
||||
result = nullptr;
|
||||
result_rows = 0;
|
||||
status = PGRES_EMPTY_QUERY;
|
||||
cur_row = 0;
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<QueryResult> query_results;
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
const char * query_last_sequence(const wchar_t * sequence_table_name);
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue