2018-11-14 18:14:26 +01:00
|
|
|
/*
|
|
|
|
* This file is a part of morm
|
|
|
|
* and is distributed under the 2-Clause BSD licence.
|
|
|
|
* Author: Tomasz Sowa <t.sowa@ttmath.org>
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2019-09-17 19:55:39 +02:00
|
|
|
* Copyright (c) 2018-2019, Tomasz Sowa
|
2018-11-14 18:14:26 +01:00
|
|
|
* 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()
|
|
|
|
{
|
2018-11-15 09:50:10 +01:00
|
|
|
psql_result = nullptr;
|
|
|
|
psql_status = PGRES_EMPTY_QUERY;
|
2018-11-14 18:14:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void PostgreSQLQueryResult::clear()
|
|
|
|
{
|
2018-11-15 09:50:10 +01:00
|
|
|
if( psql_result )
|
2018-11-14 18:14:26 +01:00
|
|
|
{
|
2018-11-15 09:50:10 +01:00
|
|
|
PQclear(psql_result);
|
2018-11-14 18:14:26 +01:00
|
|
|
}
|
|
|
|
|
2018-11-15 09:50:10 +01:00
|
|
|
psql_result = nullptr;
|
|
|
|
psql_status = PGRES_EMPTY_QUERY;
|
2018-11-14 18:14:26 +01:00
|
|
|
|
|
|
|
QueryResult::clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool PostgreSQLQueryResult::has_db_result()
|
|
|
|
{
|
2018-11-15 09:50:10 +01:00
|
|
|
return psql_result != nullptr;
|
2018-11-14 18:14:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-13 05:12:31 +02:00
|
|
|
const char * PostgreSQLQueryResult::get_field_string_value(int column_index)
|
|
|
|
{
|
|
|
|
const char * value_str = nullptr;
|
|
|
|
|
2019-09-18 14:29:20 +02:00
|
|
|
if( psql_result && column_index >= 0 && (size_t)column_index < result_cols )
|
2019-05-13 05:12:31 +02:00
|
|
|
{
|
|
|
|
if( cur_row < result_rows )
|
|
|
|
{
|
|
|
|
value_str = PQgetvalue(psql_result, cur_row, column_index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return value_str;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-11-14 18:14:26 +01:00
|
|
|
const char * PostgreSQLQueryResult::get_field_string_value(const char * column_name)
|
|
|
|
{
|
|
|
|
const char * value_str = nullptr;
|
|
|
|
|
2018-11-15 09:50:10 +01:00
|
|
|
if( psql_result )
|
2018-11-14 18:14:26 +01:00
|
|
|
{
|
2018-11-15 09:50:10 +01:00
|
|
|
int col_index = PQfnumber(psql_result, column_name);
|
2018-11-14 18:14:26 +01:00
|
|
|
|
|
|
|
if( col_index != -1 )
|
|
|
|
{
|
|
|
|
if( cur_row < result_rows )
|
|
|
|
{
|
2018-11-15 09:50:10 +01:00
|
|
|
value_str = PQgetvalue(psql_result, cur_row, col_index);
|
2018-11-14 18:14:26 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return value_str;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int PostgreSQLQueryResult::get_column_index(const char * column_name)
|
|
|
|
{
|
|
|
|
int col_index = -1;
|
|
|
|
|
2018-11-15 09:50:10 +01:00
|
|
|
if( psql_result )
|
2018-11-14 18:14:26 +01:00
|
|
|
{
|
2018-11-15 09:50:10 +01:00
|
|
|
col_index = PQfnumber(psql_result, column_name);
|
2018-11-14 18:14:26 +01:00
|
|
|
// returns -1 if there is no such a column
|
|
|
|
}
|
|
|
|
|
|
|
|
return col_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-18 14:29:20 +02:00
|
|
|
bool PostgreSQLQueryResult::is_null(int column_index)
|
|
|
|
{
|
|
|
|
bool res = false;
|
|
|
|
|
|
|
|
if( column_index >= 0 && (size_t)column_index < result_cols )
|
|
|
|
{
|
|
|
|
if( cur_row < result_rows )
|
|
|
|
{
|
|
|
|
res = is_null(cur_row, column_index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-11-22 14:40:30 +01:00
|
|
|
/*
|
|
|
|
* in the future we can use single row mode:
|
|
|
|
* https://www.postgresql.org/docs/10/libpq-single-row-mode.html
|
|
|
|
*
|
|
|
|
* or just cursors from database:
|
|
|
|
* https://www.postgresql.org/docs/current/sql-fetch.html
|
|
|
|
*
|
|
|
|
*/
|
2018-11-14 18:14:26 +01:00
|
|
|
const char * PostgreSQLQueryResult::get_value_from_result(int row, int col)
|
|
|
|
{
|
|
|
|
const char * value_str = nullptr;
|
|
|
|
|
2018-11-15 09:50:10 +01:00
|
|
|
if( psql_result )
|
2018-11-14 18:14:26 +01:00
|
|
|
{
|
2018-11-15 09:50:10 +01:00
|
|
|
value_str = PQgetvalue(psql_result, row, col);
|
|
|
|
// can return a null pointer if there is no such an item in the last psql_result
|
2018-11-14 18:14:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return value_str;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int PostgreSQLQueryResult::get_value_length(int row, int col)
|
|
|
|
{
|
|
|
|
int len = 0;
|
|
|
|
|
2018-11-15 09:50:10 +01:00
|
|
|
if( psql_result )
|
2018-11-14 18:14:26 +01:00
|
|
|
{
|
2018-11-15 09:50:10 +01:00
|
|
|
len = PQgetlength(psql_result, row, col);
|
2018-11-14 18:14:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool PostgreSQLQueryResult::is_null(int row, int col)
|
|
|
|
{
|
|
|
|
bool is_null = false;
|
|
|
|
|
2018-11-15 09:50:10 +01:00
|
|
|
if( psql_result )
|
2018-11-14 18:14:26 +01:00
|
|
|
{
|
2018-11-15 09:50:10 +01:00
|
|
|
is_null = (PQgetisnull(psql_result, row, col) == 1);
|
2018-11-14 18:14:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return is_null;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2021-05-20 16:25:01 +02:00
|
|
|
void PostgreSQLQueryResult::dump_column_names(pt::Log & log)
|
2019-09-17 19:55:39 +02:00
|
|
|
{
|
|
|
|
if( psql_result )
|
|
|
|
{
|
|
|
|
int cols = PQnfields(psql_result);
|
|
|
|
|
|
|
|
for(int i = 0 ; i < cols ; ++i)
|
|
|
|
{
|
2021-05-20 16:25:01 +02:00
|
|
|
log << i << ' ' << PQfname(psql_result, i) << pt::Log::logend;
|
2019-09-17 19:55:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-14 18:14:26 +01:00
|
|
|
//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);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
2021-05-20 16:25:01 +02:00
|
|
|
//bool PostgreSQLConnector::AssertValueSpace(PGresult * r, int row, int col, pt::Space & space)
|
2018-11-14 18:14:26 +01:00
|
|
|
//{
|
|
|
|
// const char * res = AssertValue(r, row, col);
|
|
|
|
//
|
|
|
|
// conf_parser.SetSpace(space);
|
|
|
|
// space.Clear();
|
|
|
|
//
|
2021-05-20 16:25:01 +02:00
|
|
|
// pt::SpaceParser::Status status = conf_parser.ParseString(res);
|
2018-11-14 18:14:26 +01:00
|
|
|
//
|
2021-05-20 16:25:01 +02:00
|
|
|
// if( status != pt::SpaceParser::ok )
|
2018-11-14 18:14:26 +01:00
|
|
|
// {
|
2021-05-20 16:25:01 +02:00
|
|
|
// log << log1 << "Morm: a problem with parsing a pt::Space";
|
2018-11-14 18:14:26 +01:00
|
|
|
//
|
2021-05-20 16:25:01 +02:00
|
|
|
// if( status == pt::SpaceParser::syntax_error )
|
2018-11-14 18:14:26 +01:00
|
|
|
// log << ", syntax error at line: " << conf_parser.line;
|
|
|
|
//
|
|
|
|
// log << logend;
|
|
|
|
//
|
|
|
|
// space.Clear();
|
|
|
|
// return false;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
//return true;
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|