1454 lines
27 KiB
C++
Executable File
1454 lines
27 KiB
C++
Executable File
/*
|
|
* This file is a part of CMSLU -- Content Management System like Unix
|
|
* and is not publicly distributed
|
|
*
|
|
* Copyright (c) 2008-2009, Tomasz Sowa
|
|
* All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#include "db.h"
|
|
#include "log.h"
|
|
#include "misc.h"
|
|
|
|
|
|
Db::Db(bool close_at_end_)
|
|
{
|
|
pg_conn = 0;
|
|
close_at_end = close_at_end_;
|
|
}
|
|
|
|
|
|
Db::~Db()
|
|
{
|
|
if( close_at_end )
|
|
Close();
|
|
}
|
|
|
|
|
|
PGconn * Db::GetPGconn()
|
|
{
|
|
return pg_conn;
|
|
}
|
|
|
|
|
|
void Db::Init(const std::string & d, const std::string & u, const std::string & p)
|
|
{
|
|
db_database = d;
|
|
db_user = u;
|
|
db_pass = p;
|
|
|
|
Connect();
|
|
}
|
|
|
|
|
|
void Db::Connect()
|
|
{
|
|
Close();
|
|
|
|
std::ostringstream buf;
|
|
buf << "dbname=" << db_database << " user=" << db_user << " password=" << db_pass;
|
|
|
|
pg_conn = PQconnectdb(buf.str().c_str());
|
|
|
|
if( pg_conn )
|
|
log << log3 << "Db: Socket: " << PQsocket(pg_conn) << logend;
|
|
|
|
// warning! pg_conn can be not null but there cannnot be a connection established
|
|
// use PQstatus(pg_conn) to check whether the connection works fine
|
|
}
|
|
|
|
|
|
|
|
void Db::SetDbParameters()
|
|
{
|
|
if( PQsetClientEncoding(pg_conn, "LATIN2") == -1 )
|
|
log << log1 << "Db: Can't set the proper client encoding" << logend;
|
|
}
|
|
|
|
|
|
|
|
|
|
void Db::Close()
|
|
{
|
|
if( pg_conn )
|
|
{
|
|
PQfinish(pg_conn);
|
|
pg_conn = 0;
|
|
}
|
|
}
|
|
|
|
|
|
void Db::AssertConnection()
|
|
{
|
|
bool was_connection = true;
|
|
|
|
|
|
if( !pg_conn )
|
|
{
|
|
was_connection = false;
|
|
Connect();
|
|
}
|
|
else
|
|
if( PQstatus(pg_conn) != CONNECTION_OK )
|
|
{
|
|
log << log2 << "Db: connection to the database is lost, trying to recover" << logend;
|
|
was_connection = false;
|
|
PQreset(pg_conn);
|
|
}
|
|
|
|
|
|
if( pg_conn && PQstatus(pg_conn) == CONNECTION_OK )
|
|
{
|
|
if( was_connection == false )
|
|
log << log2 << "Db: Connection to the database works fine" << logend;
|
|
|
|
SetDbParameters();
|
|
}
|
|
else
|
|
{
|
|
log << log1 << "Db: Connection to db server cannot be established" << logend;
|
|
throw Error(Error::db_fatal_error_during_connecting);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
std::string Db::Escape(const std::string & s)
|
|
{
|
|
std::string result;
|
|
|
|
result.resize(s.length() * 2 + 1);
|
|
|
|
size_t len = PQescapeStringConn(pg_conn, const_cast<char*>( result.c_str() ), s.c_str(), s.length(), 0);
|
|
result.resize(len);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
std::string Db::Escape(const char * s)
|
|
{
|
|
std::string result;
|
|
int len;
|
|
|
|
for(len=0 ; s[len] != 0 ; ++len);
|
|
|
|
result.resize(len * 2 + 1);
|
|
|
|
size_t len_new = PQescapeStringConn(pg_conn, const_cast<char*>( result.c_str() ), s, len, 0);
|
|
result.resize(len_new);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
// ------------------
|
|
|
|
|
|
|
|
PGresult * Db::AssertQuery(const std::string & q)
|
|
{
|
|
PGresult * r = PQexec(pg_conn, q.c_str());
|
|
|
|
if( !r )
|
|
{
|
|
log << log1 << "Db: Problem with query: \"" << q << '\"' << logend;
|
|
log << log1 << "Db: " << PQerrorMessage(pg_conn) << logend;
|
|
|
|
throw Error(Error::db_incorrect_query);
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
|
|
|
|
void Db::AssertResultStatus(PGresult * r, ExecStatusType t)
|
|
{
|
|
if( PQresultStatus(r) != t )
|
|
{
|
|
log << "Db: Incorrect result status: " << PQerrorMessage(pg_conn) << logend;
|
|
|
|
throw Error(Error::db_incorrent_result_status);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
int Db::AssertColumn(PGresult * r, const char * column_name)
|
|
{
|
|
int c = PQfnumber(r, column_name);
|
|
|
|
if( c == -1 )
|
|
{
|
|
log << log1 << "Db: there is no column: " << column_name << logend;
|
|
|
|
throw Error(Error::db_no_column);
|
|
}
|
|
|
|
return c;
|
|
}
|
|
|
|
|
|
const char * Db::AssertValue(PGresult * r, int row, int col)
|
|
{
|
|
const char * res = PQgetvalue(r, row, col);
|
|
|
|
if( !res )
|
|
{
|
|
log << log1 << "Db: there is no such an item in the result, row:" << row << ", col:" << col << logend;
|
|
|
|
throw Error(Error::db_no_item);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
void Db::ClearResult(PGresult * r)
|
|
{
|
|
if( r )
|
|
PQclear(r);
|
|
}
|
|
|
|
|
|
bool Db::CheckUser(std::string & login, std::string & password, long & user_id)
|
|
{
|
|
PGresult * r = 0;
|
|
bool user_ok = false;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
|
|
std::ostringstream query;
|
|
query << "select id from core.user where login='" << Escape(login) << "' and password='" << Escape(password) << "';";
|
|
|
|
r = AssertQuery( query.str() );
|
|
|
|
AssertResultStatus(r, PGRES_TUPLES_OK);
|
|
|
|
int rows = PQntuples(r);
|
|
|
|
if( rows == 0 )
|
|
throw Error(Error::db_incorrect_login);
|
|
|
|
if( rows > 1 )
|
|
{
|
|
log << log1 << "Db: there is more than one user: " << login << " (with the same password)" << logend;
|
|
throw Error(Error::db_more_than_one_login);
|
|
}
|
|
|
|
int cuser_id = AssertColumn(r, "id");
|
|
const char * fuser_id = AssertValue(r, 0, cuser_id);
|
|
user_id = atol( fuser_id );
|
|
|
|
user_ok = true;
|
|
}
|
|
catch(const Error &)
|
|
{
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
|
|
return user_ok;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool Db::AddItemCreateUrlSubject(Item & item)
|
|
{
|
|
bool is_that_url;
|
|
PGresult * r = 0;
|
|
int index = 1;
|
|
const int max_index = 100;
|
|
char appendix[20];
|
|
appendix[0] = 0;
|
|
|
|
|
|
try
|
|
{
|
|
do
|
|
{
|
|
std::ostringstream query;
|
|
|
|
// this Escape can be put at the beginning (performance)
|
|
query << "select id from core.item where url='" << Escape(item.url) << appendix << "' and parent_id='" << item.parent_id << "';";
|
|
r = AssertQuery(query.str());
|
|
AssertResultStatus(r, PGRES_TUPLES_OK);
|
|
|
|
if( PQntuples(r) != 0 )
|
|
{
|
|
sprintf(appendix, "_(%d)", ++index);
|
|
is_that_url = true;
|
|
}
|
|
else
|
|
{
|
|
item.url += appendix;
|
|
is_that_url = false;
|
|
}
|
|
|
|
ClearResult(r);
|
|
r = 0;
|
|
}
|
|
while( is_that_url && index <= max_index );
|
|
}
|
|
catch(const Error &)
|
|
{
|
|
is_that_url = true; // for return false
|
|
}
|
|
|
|
|
|
ClearResult(r);
|
|
|
|
|
|
return !is_that_url;
|
|
}
|
|
|
|
|
|
// for testing consistency
|
|
void Db::CheckAllUrlSubjectModifyItem(Item & item)
|
|
{
|
|
PGresult * r = 0;
|
|
|
|
try
|
|
{
|
|
std::ostringstream query;
|
|
query << "update core.item set url=";
|
|
|
|
// url
|
|
if( AddItemCreateUrlSubject(item) )
|
|
query << '\'' << Escape(item.url) << '\'';
|
|
else
|
|
{
|
|
query << '\'' << item.id << '\'';
|
|
item.url.clear();
|
|
}
|
|
|
|
query << " where id='" << item.id << "';";
|
|
|
|
r = AssertQuery(query.str());
|
|
AssertResultStatus(r, PGRES_COMMAND_OK);
|
|
}
|
|
catch(const Error &)
|
|
{
|
|
}
|
|
|
|
ClearResult(r);
|
|
}
|
|
|
|
|
|
|
|
// for checking consistency
|
|
void Db::CheckAllUrlSubject()
|
|
{
|
|
PGresult * r = 0;
|
|
Item item;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
std::ostringstream query, query2;
|
|
query << "select item.id, subject from core.item left join core.content on item.content_id = content.id where url is null or url=''";
|
|
|
|
r = AssertQuery(query.str());
|
|
AssertResultStatus(r, PGRES_TUPLES_OK);
|
|
|
|
int rows = PQntuples(r);
|
|
int cid = AssertColumn(r, "id");
|
|
int csubject = AssertColumn(r, "subject");
|
|
|
|
for(int i = 0 ; i<rows ; ++i)
|
|
{
|
|
item.id = atol( AssertValue(r, i, cid) );
|
|
item.subject = AssertValue(r, i, csubject);
|
|
|
|
CheckAllUrlSubjectModifyItem(item);
|
|
}
|
|
}
|
|
catch(const Error &)
|
|
{
|
|
}
|
|
|
|
ClearResult(r);
|
|
}
|
|
|
|
|
|
|
|
long Db::AssertCurrval(const char * table)
|
|
{
|
|
PGresult * r;
|
|
std::ostringstream query;
|
|
|
|
query << "select currval('" << table << "');";
|
|
|
|
r = AssertQuery(query.str());
|
|
AssertResultStatus(r, PGRES_TUPLES_OK);
|
|
|
|
if( PQntuples(r) != 1 )
|
|
{
|
|
log << log1 << "Db: error (currval) for table: " << table << ", " << PQerrorMessage(pg_conn) << logend;
|
|
throw Error(Error::db_err_currval);
|
|
}
|
|
|
|
long res = strtol( AssertValue(r, 0, 0), 0, 10 );
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
Error Db::AddItemIntoItem(Item & item)
|
|
{
|
|
PGresult * r = 0;
|
|
Error result = Error::ok;
|
|
bool url_without_id = false;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
std::ostringstream query;
|
|
query << "insert into core.item (user_id, group_id, privileges, date_creation, date_modification, type, parent_id, content_id, default_item, url) values (";
|
|
query << '\'' << item.user_id << "', ";
|
|
query << '\'' << item.group_id << "', ";
|
|
query << '\'' << item.privileges << "', ";
|
|
query << '\'' << ConvertTime(item.date_creation) << "', ";
|
|
query << '\'' << ConvertTime(item.date_modification) << "', ";
|
|
query << '\'' << static_cast<int>(item.type) << "', ";
|
|
query << '\'' << item.parent_id << "', ";
|
|
query << '\'' << item.content_id << "', ";
|
|
query << '\'' << item.default_item << "', ";
|
|
|
|
url_without_id = AddItemCreateUrlSubject(item);
|
|
|
|
if( url_without_id )
|
|
query << '\'' << Escape(item.url) << "');";
|
|
else
|
|
query << "currval('core.item_id_seq')" << ");";
|
|
|
|
|
|
r = AssertQuery(query.str());
|
|
AssertResultStatus(r, PGRES_COMMAND_OK);
|
|
|
|
item.id = AssertCurrval("core.item_id_seq");
|
|
|
|
if( !url_without_id )
|
|
ToString(item.url, item.id);
|
|
|
|
}
|
|
catch(const Error & e)
|
|
{
|
|
result = e;
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
Error Db::AddItemIntoContent(Item & item)
|
|
{
|
|
PGresult * r = 0;
|
|
Error result = Error::ok;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
std::ostringstream query;
|
|
query << "insert into core.content (subject, content, content_type) values (";
|
|
query << '\'' << Escape(item.subject) << "', ";
|
|
query << '\'' << Escape(item.content) << "', ";
|
|
query << '\'' << item.content_type << "');";
|
|
|
|
r = AssertQuery(query.str());
|
|
AssertResultStatus(r, PGRES_COMMAND_OK);
|
|
|
|
item.content_id = AssertCurrval("core.content_id_seq");
|
|
}
|
|
catch(const Error & e)
|
|
{
|
|
result = e;
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
|
|
Error Db::AddItem(Item & item)
|
|
{
|
|
Error result = Error::ok;
|
|
|
|
if( item.type == Item::file )
|
|
result = AddItemIntoContent(item);
|
|
else
|
|
item.content_id = -1;
|
|
|
|
if( result == Error::ok )
|
|
result = AddItemIntoItem(item);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// !! with_subject zamienic na with_url
|
|
Error Db::EditItemInItem(Item & item, bool with_subject)
|
|
{
|
|
PGresult * r = 0;
|
|
Error result = Error::ok;
|
|
bool url_without_id = false;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
std::ostringstream query;
|
|
query << "update core.item set (user_id, group_id, privileges, date_creation, date_modification, type, default_item, parent_id";
|
|
|
|
if( with_subject )
|
|
query << ", url";
|
|
|
|
query << ") = (";
|
|
query << '\'' << item.user_id << "', ";
|
|
query << '\'' << item.group_id << "', ";
|
|
query << '\'' << item.privileges << "', ";
|
|
query << '\'' << ConvertTime(item.date_creation) << "', ";
|
|
query << '\'' << ConvertTime(item.date_modification) << "', ";
|
|
query << '\'' << static_cast<int>(item.type) << "', ";
|
|
query << '\'' << item.default_item << "', ";
|
|
query << '\'' << item.parent_id << "' ";
|
|
|
|
if( with_subject )
|
|
{
|
|
url_without_id = AddItemCreateUrlSubject(item);
|
|
|
|
if( url_without_id )
|
|
query << ", '" << Escape(item.url) << "'";
|
|
else
|
|
query << ", '" << item.id << "'";
|
|
}
|
|
|
|
query << ") where id='" << item.id << "';";
|
|
|
|
r = AssertQuery(query.str());
|
|
AssertResultStatus(r, PGRES_COMMAND_OK);
|
|
|
|
if( with_subject && !url_without_id )
|
|
ToString(item.url, item.id);
|
|
}
|
|
catch(const Error & e)
|
|
{
|
|
result = e;
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
Error Db::EditItemInContent(Item & item)
|
|
{
|
|
PGresult * r = 0;
|
|
Error result = Error::ok;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
std::ostringstream query;
|
|
query << "update core.content set (subject, content, content_type) = (";
|
|
|
|
query << '\'' << Escape(item.subject) << "', ";
|
|
query << '\'' << Escape(item.content) << "', ";
|
|
query << '\'' << item.content_type << "' ";
|
|
|
|
query << ") where id='" << item.content_id << "';";
|
|
|
|
r = AssertQuery(query.str());
|
|
AssertResultStatus(r, PGRES_COMMAND_OK);
|
|
}
|
|
catch(const Error & e)
|
|
{
|
|
result = e;
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
Error Db::EditItemGetId(Item & item)
|
|
{
|
|
PGresult * r = 0;
|
|
Error result = Error::ok;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
std::ostringstream query;
|
|
query << "select item.id, content.id from core.item left join core.content on item.content_id = content.id where item.parent_id='";
|
|
query << item.parent_id << "' and item.url='" << Escape(item.url) << "';";
|
|
|
|
r = AssertQuery(query.str());
|
|
AssertResultStatus(r, PGRES_TUPLES_OK);
|
|
|
|
if( PQntuples(r) != 1 || PQnfields(r) != 2 )
|
|
throw Error(Error::db_no_item);
|
|
|
|
// we cannot use AssertColumn() with a name because both columns are called 'id'
|
|
item.id = atol( AssertValue(r, 0, 0) );
|
|
item.content_id = atol( AssertValue(r, 0, 1) );
|
|
}
|
|
catch(const Error & e)
|
|
{
|
|
result = e;
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
Error Db::EditItemGetContentId(Item & item)
|
|
{
|
|
PGresult * r = 0;
|
|
Error result = Error::ok;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
std::ostringstream query;
|
|
// !! tutaj chyba nie ma potrzeby robic left join z core.content (nie uzywamy nic z tamtej tabeli)
|
|
query << "select content_id from core.item left join core.content on item.content_id = content.id where item.id='";
|
|
query << item.id << "';";
|
|
|
|
r = AssertQuery(query.str());
|
|
AssertResultStatus(r, PGRES_TUPLES_OK);
|
|
|
|
if( PQntuples(r) != 1 || PQnfields(r) != 1 )
|
|
throw Error(Error::db_no_item);
|
|
|
|
item.content_id = atol( AssertValue(r, 0, 0) );
|
|
}
|
|
catch(const Error & e)
|
|
{
|
|
result = e;
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
// item.id must be set
|
|
// !! with_subject zamienic na with_url
|
|
// !! moze nazwa poprostu EditItem (nie trzeba tego ById) ? (sprawdzic czy nie koliduje z inna nazwa)
|
|
Error Db::EditItemById(Item & item, bool with_subject)
|
|
{
|
|
Error result = Error::ok;
|
|
|
|
// !! dla katalogow nie testowane jeszcze
|
|
|
|
if( item.type == Item::file )
|
|
result = EditItemGetContentId(item);
|
|
|
|
if( result == Error::ok )
|
|
{
|
|
if( item.type == Item::file )
|
|
result = EditItemInContent(item);
|
|
|
|
if( result == Error::ok )
|
|
result = EditItemInItem(item, with_subject);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
// item.url and item.parent_id must be set
|
|
// doesn't work with directiories
|
|
Error Db::EditItemByUrl(Item & item, bool with_subject)
|
|
{
|
|
Error result = EditItemGetId(item);
|
|
|
|
if( result == Error::ok )
|
|
{
|
|
result = EditItemInContent(item);
|
|
|
|
if( result == Error::ok )
|
|
result = EditItemInItem(item, with_subject);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
Error Db::EditDefaultItem(long id, long new_default_item)
|
|
{
|
|
PGresult * r = 0;
|
|
Error result = Error::ok;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
std::ostringstream query;
|
|
query << "update core.item set (default_item) = ('" << new_default_item << "') where id='" << id << "';";
|
|
|
|
r = AssertQuery(query.str());
|
|
AssertResultStatus(r, PGRES_COMMAND_OK);
|
|
|
|
char * rows_str = PQcmdTuples(r);
|
|
long rows = 0;
|
|
|
|
if( rows_str )
|
|
rows = atol(rows_str);
|
|
|
|
if( rows == 0 )
|
|
{
|
|
result = Error::db_no_item;
|
|
log << log1 << "Db: EditDefaultItem: no such item, id: " << id << logend;
|
|
}
|
|
}
|
|
catch(const Error & e)
|
|
{
|
|
result = e;
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
|
|
PGresult * Db::GetItemsQuery(Item & item_ref, bool asc)
|
|
{
|
|
std::ostringstream query;
|
|
query << "select * from core.item left join core.content on item.content_id = content.id where type!='0' and parent_id='" << item_ref.parent_id << "'";
|
|
|
|
if( item_ref.id != -1 )
|
|
query << " and item.id='" << item_ref.id << "'";
|
|
|
|
if( !item_ref.url.empty() )
|
|
query << " and url='" << Escape(item_ref.url) << "'";
|
|
|
|
query << " order by item.date_modification";
|
|
|
|
if( asc )
|
|
query << " asc";
|
|
else
|
|
query << " desc";
|
|
|
|
query << ';';
|
|
|
|
|
|
return AssertQuery(query.str());
|
|
}
|
|
|
|
|
|
|
|
void Db::GetItems(std::vector<Item> & item_table, Item & item_ref, bool asc)
|
|
{
|
|
item_table.clear();
|
|
PGresult * r = 0;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
|
|
r = GetItemsQuery(item_ref, asc);
|
|
AssertResultStatus(r, PGRES_TUPLES_OK);
|
|
|
|
Item item;
|
|
int rows = PQntuples(r);
|
|
|
|
ItemColumns col;
|
|
col.SetColumns(r);
|
|
|
|
for(int i = 0 ; i<rows ; ++i)
|
|
{
|
|
col.SetItem(r, i, item);
|
|
item_table.push_back(item);
|
|
}
|
|
}
|
|
catch(const Error &)
|
|
{
|
|
}
|
|
|
|
ClearResult(r);
|
|
}
|
|
|
|
|
|
|
|
void Db::GetItem(std::vector<Item> & item_table, long id)
|
|
{
|
|
PGresult * r = 0;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
|
|
std::ostringstream query;
|
|
query << "select * from core.item left join core.content on item.content_id = content.id where type='1' and item.id='" << id << "';";
|
|
|
|
r = AssertQuery( query.str() );
|
|
AssertResultStatus(r, PGRES_TUPLES_OK);
|
|
|
|
Item item;
|
|
int rows = PQntuples(r);
|
|
|
|
if( rows > 1 )
|
|
log << log1 << "Db: we have more than one item with id: " << id << logend;
|
|
|
|
ItemColumns col;
|
|
col.SetColumns(r);
|
|
|
|
for(int i = 0 ; i<rows ; ++i)
|
|
{
|
|
col.SetItem(r, i, item);
|
|
item_table.push_back(item);
|
|
}
|
|
}
|
|
catch(const Error &)
|
|
{
|
|
}
|
|
|
|
ClearResult(r);
|
|
}
|
|
|
|
|
|
|
|
// !! nowy interfejs
|
|
Error Db::GetItem(long parent_id, const std::string & url, Item & item)
|
|
{
|
|
PGresult * r = 0;
|
|
Error result = Error::ok;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
|
|
std::ostringstream query;
|
|
query << "select * from core.item left join core.content on item.content_id = content.id where type='1' and item.parent_id='";
|
|
query << parent_id << "' and item.url='" << Escape(url) << "';";
|
|
|
|
r = AssertQuery( query.str() );
|
|
AssertResultStatus(r, PGRES_TUPLES_OK);
|
|
|
|
int rows = PQntuples(r);
|
|
|
|
if( rows == 0 )
|
|
throw Error(Error::db_no_item);
|
|
|
|
ItemColumns col;
|
|
col.SetColumns(r);
|
|
col.SetItem(r, 0, item);
|
|
}
|
|
catch(const Error & e)
|
|
{
|
|
result = e;
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
long Db::GetItemId(long parent_id, const std::string & url, Item::Type type)
|
|
{
|
|
PGresult * r = 0;
|
|
long result = -1;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
|
|
std::ostringstream query;
|
|
query << "select id from core.item where type='" << static_cast<int>(type) << "' and item.parent_id='";
|
|
query << parent_id << "' and item.url='" << Escape(url) << "';";
|
|
|
|
r = AssertQuery( query.str() );
|
|
AssertResultStatus(r, PGRES_TUPLES_OK);
|
|
|
|
int rows = PQntuples(r);
|
|
|
|
if( rows == 1 )
|
|
result = atol( AssertValue(r, 0, 0) );
|
|
}
|
|
catch(const Error & e)
|
|
{
|
|
result = e;
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
long Db::GetFileId(long parent_id, const std::string & url)
|
|
{
|
|
return GetItemId(parent_id, url, Item::file);
|
|
}
|
|
|
|
|
|
long Db::GetDirId(long parent_id, const std::string & url)
|
|
{
|
|
return GetItemId(parent_id, url, Item::dir);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool Db::GetPriv(Item & item, long id)
|
|
{
|
|
bool result = false;
|
|
|
|
PGresult * r = 0;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
|
|
std::ostringstream query;
|
|
query << "select user_id, group_id, privileges, subject, content from core.item left join core.content on item.content_id = content.id where item.id='" << id << "';"; // !! tymczasowo odczytujemy z content i subject
|
|
|
|
r = AssertQuery( query.str() );
|
|
AssertResultStatus(r, PGRES_TUPLES_OK);
|
|
|
|
int rows = PQntuples(r);
|
|
|
|
if( rows != 1 )
|
|
throw Error();
|
|
|
|
ItemColumns col;
|
|
col.SetColumns(r);
|
|
col.SetItem(r, 0, item);
|
|
|
|
result = true;
|
|
}
|
|
catch(const Error &)
|
|
{
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
// !! to jest nowy interfejs, z jawnym podaniem id
|
|
Error Db::EditPrivById(Item & item, long id)
|
|
{
|
|
PGresult * r = 0;
|
|
Error result = Error::ok;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
std::ostringstream query;
|
|
query << "update core.item set (user_id, group_id, privileges) = (";
|
|
query << '\'' << item.user_id << "', ";
|
|
query << '\'' << item.group_id << "', ";
|
|
query << '\'' << item.privileges << "' ";
|
|
|
|
query << ") where id='" << id << "';";
|
|
|
|
r = AssertQuery(query.str());
|
|
AssertResultStatus(r, PGRES_COMMAND_OK);
|
|
}
|
|
catch(const Error & e)
|
|
{
|
|
result = e;
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
Error Db::DelDirById(long id)
|
|
{
|
|
Error result = Error::ok;
|
|
PGresult * r = 0;
|
|
const char * crows;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
std::ostringstream query, query2;
|
|
|
|
query << "delete from core.content where content.id in (select content_id from core.item where parent_id='" << id << "');";
|
|
r = AssertQuery( query.str() );
|
|
AssertResultStatus(r, PGRES_COMMAND_OK);
|
|
|
|
crows = PQcmdTuples(r);
|
|
if( crows )
|
|
log << log2 << "Db: deleted " << atol(crows) << " rows from core.content" << logend;
|
|
|
|
query2 << "delete from core.item where id='" << id << "' or parent_id='" << id << "';";
|
|
r = AssertQuery( query2.str() );
|
|
AssertResultStatus(r, PGRES_COMMAND_OK);
|
|
|
|
crows = PQcmdTuples(r);
|
|
if( crows )
|
|
log << log1 << "Db: deleted dir: " << id << " (deleted: " << atol(crows) << " rows)" << logend;
|
|
}
|
|
catch(const Error & e)
|
|
{
|
|
result = e;
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
|
|
bool Db::DelItemDelItem(const Item & item)
|
|
{
|
|
long rows = 0;
|
|
PGresult * r = 0;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
|
|
std::ostringstream query;
|
|
query << "delete from core.item where id='" << item.id << "';";
|
|
|
|
r = AssertQuery( query.str() );
|
|
AssertResultStatus(r, PGRES_COMMAND_OK);
|
|
|
|
const char * crows = PQcmdTuples(r);
|
|
if( crows )
|
|
{
|
|
rows = atol(crows);
|
|
|
|
if( rows > 1 )
|
|
log << log1 << "Db: more than one item were deleted" << logend;
|
|
else
|
|
if( rows == 0 )
|
|
log << log1 << "Db: no item has been deleted" << logend;
|
|
}
|
|
}
|
|
catch(const Error &)
|
|
{
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
return rows != 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
void Db::DelItemDelContent(const Item & item)
|
|
{
|
|
PGresult * r = 0;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
|
|
std::ostringstream query;
|
|
query << "delete from core.content where id='" << item.content_id << "';";
|
|
|
|
r = AssertQuery( query.str() );
|
|
AssertResultStatus(r, PGRES_COMMAND_OK);
|
|
|
|
const char * crows = PQcmdTuples(r);
|
|
if( crows )
|
|
{
|
|
long rows = atol(crows);
|
|
|
|
if( rows > 1 )
|
|
log << log1 << "Db: more than one content were deleted" << logend;
|
|
else
|
|
if( rows == 0 )
|
|
log << log1 << "Db: no content has been deleted" << logend;
|
|
|
|
}
|
|
}
|
|
catch(const Error &)
|
|
{
|
|
}
|
|
|
|
ClearResult(r);
|
|
}
|
|
|
|
|
|
|
|
|
|
Error Db::DelItemCountContents(const Item & item, long & contents)
|
|
{
|
|
Error result = Error::ok;
|
|
PGresult * r = 0;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
|
|
std::ostringstream query;
|
|
query << "select count('id') from core.item where content_id='" << item.content_id << "';";
|
|
|
|
r = AssertQuery( query.str() );
|
|
AssertResultStatus(r, PGRES_TUPLES_OK);
|
|
|
|
contents = atol( AssertValue(r, 0, 0) );
|
|
|
|
log << log1 << "counters: " << contents << logend; // !!
|
|
}
|
|
catch(const Error & e)
|
|
{
|
|
result = e;
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
bool Db::DelItem(const Item & item)
|
|
{
|
|
long contents;
|
|
|
|
Error result = DelItemCountContents(item, contents);
|
|
|
|
if( result == Error::ok && contents == 1 )
|
|
DelItemDelContent(item);
|
|
|
|
return DelItemDelItem(item);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void Db::GetDirs(DirContainer & dir_table)
|
|
{
|
|
PGresult * r = 0;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
|
|
std::ostringstream query;
|
|
query << "select * from core.item where type='0';";
|
|
|
|
r = AssertQuery( query.str() );
|
|
AssertResultStatus(r, PGRES_TUPLES_OK);
|
|
|
|
Item item;
|
|
int rows = PQntuples(r);
|
|
|
|
ItemColumns col;
|
|
col.SetColumns(r);
|
|
|
|
for(int i = 0 ; i<rows ; ++i)
|
|
{
|
|
col.SetItem(r, i, item);
|
|
dir_table.PushBack( item );
|
|
}
|
|
}
|
|
catch(const Error &)
|
|
{
|
|
}
|
|
|
|
ClearResult(r);
|
|
}
|
|
|
|
|
|
|
|
void Db::GetUsers(UGContainer<User> & user_table)
|
|
{
|
|
PGresult * r = 0;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
|
|
std::ostringstream query;
|
|
query << "select id, login, super_user, group_id from core.user left outer join core.group_mem on core.user.id = core.group_mem.user_id order by id asc;";
|
|
|
|
r = AssertQuery( query.str() );
|
|
AssertResultStatus(r, PGRES_TUPLES_OK);
|
|
|
|
int rows = PQntuples(r);
|
|
|
|
int cid = AssertColumn(r, "id");
|
|
int cname = AssertColumn(r, "login");
|
|
int csuper_user = AssertColumn(r, "super_user");
|
|
int cgroup_id = AssertColumn(r, "group_id");
|
|
|
|
User u;
|
|
long last_id = -1;
|
|
UGContainer<User>::Iterator iter;
|
|
|
|
for(int i = 0 ; i<rows ; ++i)
|
|
{
|
|
u.id = atol( AssertValue(r, i, cid) );
|
|
|
|
if( u.id != last_id )
|
|
{
|
|
u.name = AssertValue(r, i, cname);
|
|
u.super_user = static_cast<bool>( atoi( AssertValue(r, i, csuper_user) ) );
|
|
log << log1 << "Db: get user: id:" << u.id << ", name:" << u.name << ", super_user:" << u.super_user << logend;
|
|
|
|
iter = user_table.PushBack( u );
|
|
last_id = u.id;
|
|
}
|
|
|
|
long group_id = atol( AssertValue(r, i, cgroup_id) );
|
|
|
|
if( !PQgetisnull(r, i, cgroup_id) && group_id!=-1 && !user_table.Empty() )
|
|
{
|
|
iter->groups.push_back(group_id);
|
|
log << log3 << "Db: user:" << iter->name << " is a member of group_id:" << group_id << logend;
|
|
}
|
|
}
|
|
}
|
|
catch(const Error &)
|
|
{
|
|
}
|
|
|
|
ClearResult(r);
|
|
}
|
|
|
|
|
|
|
|
void Db::GetGroups(UGContainer<Group> & group_table)
|
|
{
|
|
PGresult * r = 0;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
|
|
std::ostringstream query;
|
|
query << "select id, core.group.group, user_id from core.group left outer join core.group_mem on core.group.id = core.group_mem.group_id order by id asc;";
|
|
|
|
r = AssertQuery( query.str() );
|
|
AssertResultStatus(r, PGRES_TUPLES_OK);
|
|
|
|
int rows = PQntuples(r);
|
|
|
|
int cid = AssertColumn(r, "id");
|
|
int cname = AssertColumn(r, "group");
|
|
int cuser_id = AssertColumn(r, "user_id");
|
|
|
|
Group g;
|
|
long last_id = -1;
|
|
UGContainer<Group>::Iterator iter;
|
|
|
|
for(int i = 0 ; i<rows ; ++i)
|
|
{
|
|
g.id = atol( AssertValue(r, i, cid) );
|
|
|
|
if( g.id != last_id )
|
|
{
|
|
g.name = AssertValue(r, i, cname);
|
|
log << log3 << "Db: get group, id:" << g.id << ", group:" << g.name << logend;
|
|
|
|
iter = group_table.PushBack( g );
|
|
last_id = g.id;
|
|
}
|
|
|
|
long user_id = atol( AssertValue(r, i, cuser_id) );
|
|
|
|
if( !PQgetisnull(r, i, cuser_id) && user_id!=-1 && !group_table.Empty() )
|
|
{
|
|
iter->members.push_back(user_id);
|
|
log << log3 << "Db: get group member: user_id:" << user_id << logend;
|
|
}
|
|
}
|
|
}
|
|
catch(const Error &)
|
|
{
|
|
}
|
|
|
|
ClearResult(r);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tm Db::ConvertTime(const char * str)
|
|
{
|
|
tm t;
|
|
|
|
memset(&t, 0, sizeof(t));
|
|
|
|
if( !str )
|
|
return t;
|
|
|
|
size_t len = strlen(str);
|
|
|
|
if( len != 19 )
|
|
{
|
|
// unknown format
|
|
// the format must be like this: 2008-12-31 22:30:00
|
|
return t;
|
|
}
|
|
|
|
|
|
t.tm_year = atoi(str + 0) - 1900; /* year - 1900 */
|
|
t.tm_mon = atoi(str + 5) - 1; /* month of year (0 - 11) */
|
|
t.tm_mday = atoi(str + 8); /* day of month (1 - 31) */
|
|
t.tm_hour = atoi(str + 11); /* hours (0 - 23) */
|
|
t.tm_min = atoi(str + 14); /* minutes (0 - 59) */
|
|
t.tm_sec = atoi(str + 17); /* seconds (0 - 60) */
|
|
|
|
|
|
// t.tm_wday = 0; /* day of week (Sunday = 0) */
|
|
// t.tm_yday = 0; /* day of year (0 - 365) */
|
|
// t.tm_isdst = 0; /* is summer time in effect? */
|
|
// t.tm_zone = 0; // const_cast<char*>(""); /* abbreviation of timezone name */
|
|
|
|
|
|
//return mktime(&t);
|
|
return t;
|
|
}
|
|
|
|
|
|
const char * Db::ConvertTime(const tm & t)
|
|
{
|
|
// not thread safe
|
|
static char buffer[100];
|
|
|
|
sprintf(buffer, "%04d-%02d-%02d %02d:%02d:%02d", t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Error Db::GetThreadByDirId(long dir_id, Thread & thread)
|
|
{
|
|
PGresult * r = 0;
|
|
Error status = Error::ok;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
|
|
std::ostringstream query;
|
|
query << "select id, dir_id, subject, closed from core.thread where thread.dir_id = " << dir_id << ";";
|
|
|
|
r = AssertQuery( query.str() );
|
|
AssertResultStatus(r, PGRES_TUPLES_OK);
|
|
|
|
int rows = PQntuples(r);
|
|
|
|
if( rows > 1 )
|
|
log << log1 << "Db: there is more than one thread with dir_id: " << dir_id << logend;
|
|
else
|
|
if( rows == 0 )
|
|
{
|
|
log << log1 << "Db: there is no a thread with dir_id: " << dir_id << logend;
|
|
throw Error(Error::no_thread);
|
|
}
|
|
|
|
int cid = AssertColumn(r, "id");
|
|
int cdir_id = AssertColumn(r, "dir_id");
|
|
int csubject = AssertColumn(r, "subject");
|
|
int cclosed = AssertColumn(r, "closed");
|
|
|
|
thread.id = atol( AssertValue(r, 0, cid) );
|
|
thread.dir_id = atol( AssertValue(r, 0, cdir_id) );
|
|
thread.subject = AssertValue(r, 0, csubject);
|
|
thread.closed = atol( AssertValue(r, 0, cclosed) ) == 0 ? false : true;
|
|
}
|
|
catch(const Error & e)
|
|
{
|
|
status = e;
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
|
|
Error Db::AddThread(Thread & thread)
|
|
{
|
|
PGresult * r = 0;
|
|
Error status = Error::ok;
|
|
|
|
try
|
|
{
|
|
AssertConnection();
|
|
std::ostringstream query;
|
|
query << "insert into core.thread (dir_id, subject, closed) values (";
|
|
query << '\'' << thread.dir_id << "', ";
|
|
query << '\'' << Escape(thread.subject) << "', ";
|
|
query << '\'' << (thread.closed ? 1 : 0 ) << "'); ";
|
|
|
|
r = AssertQuery(query.str());
|
|
AssertResultStatus(r, PGRES_COMMAND_OK);
|
|
|
|
thread.id = AssertCurrval("core.thread_id_seq");
|
|
}
|
|
catch(const Error & e)
|
|
{
|
|
status = e;
|
|
}
|
|
|
|
ClearResult(r);
|
|
|
|
|
|
return status;
|
|
}
|
|
|
|
|