2008-12-10 05:42:49 +01:00
/*
* This file is a part of CMSLU - - Content Management System like Unix
* and is not publicly distributed
*
2009-04-21 22:50:55 +02:00
* Copyright ( c ) 2008 - 2009 , Tomasz Sowa
2008-12-10 05:42:49 +01:00
* All rights reserved .
*
*/
# include "db.h"
2009-04-21 22:50:55 +02:00
# include "log.h"
# include "misc.h"
2008-12-10 05:42:49 +01:00
2009-01-26 21:49:28 +01:00
Db : : Db ( bool close_at_end_ )
2008-12-10 05:42:49 +01:00
{
2009-01-26 21:49:28 +01:00
pg_conn = 0 ;
close_at_end = close_at_end_ ;
2008-12-10 05:42:49 +01:00
}
Db : : ~ Db ( )
{
2009-01-26 21:49:28 +01:00
if ( close_at_end )
Close ( ) ;
2008-12-10 05:42:49 +01:00
}
2009-01-26 21:49:28 +01:00
PGconn * Db : : GetPGconn ( )
{
return pg_conn ;
}
2008-12-10 05:42:49 +01:00
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 ( )
{
2008-12-11 03:46:16 +01:00
Close ( ) ;
2008-12-10 05:42:49 +01:00
std : : ostringstream buf ;
buf < < " dbname= " < < db_database < < " user= " < < db_user < < " password= " < < db_pass ;
pg_conn = PQconnectdb ( buf . str ( ) . c_str ( ) ) ;
2009-01-27 19:43:44 +01:00
if ( pg_conn )
log < < log3 < < " Db: Socket: " < < PQsocket ( pg_conn ) < < logend ;
2008-12-10 05:42:49 +01:00
2009-01-27 19:43:44 +01:00
// 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
}
2008-12-10 05:42:49 +01:00
2009-01-27 19:43:44 +01:00
void Db : : SetDbParameters ( )
{
2008-12-10 05:42:49 +01:00
if ( PQsetClientEncoding ( pg_conn , " LATIN2 " ) = = - 1 )
log < < log1 < < " Db: Can't set the proper client encoding " < < logend ;
}
2009-01-27 19:43:44 +01:00
2008-12-10 05:42:49 +01:00
void Db : : Close ( )
{
if ( pg_conn )
{
PQfinish ( pg_conn ) ;
pg_conn = 0 ;
}
}
void Db : : AssertConnection ( )
{
2009-01-27 19:43:44 +01:00
bool was_connection = true ;
2008-12-10 05:42:49 +01:00
if ( ! pg_conn )
{
2009-01-27 19:43:44 +01:00
was_connection = false ;
2008-12-10 05:42:49 +01:00
Connect ( ) ;
}
2009-01-27 19:43:44 +01:00
else
2008-12-10 05:42:49 +01:00
if ( PQstatus ( pg_conn ) ! = CONNECTION_OK )
{
2009-01-27 19:43:44 +01:00
log < < log2 < < " Db: connection to the database is lost, trying to recover " < < logend ;
was_connection = false ;
2008-12-10 05:42:49 +01:00
PQreset ( pg_conn ) ;
2009-01-27 19:43:44 +01:00
}
if ( pg_conn & & PQstatus ( pg_conn ) = = CONNECTION_OK )
{
if ( was_connection = = false )
log < < log2 < < " Db: Connection to the database works fine " < < logend ;
2008-12-10 05:42:49 +01:00
2009-01-27 19:43:44 +01:00
SetDbParameters ( ) ;
}
else
{
log < < log1 < < " Db: Connection to db server cannot be established " < < logend ;
throw Error ( Error : : db_fatal_error_during_connecting ) ;
2008-12-10 05:42:49 +01:00
}
}
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 )
{
2009-01-26 21:49:28 +01:00
log < < log1 < < " Db: Problem with query: \" " < < q < < ' \" ' < < logend ;
log < < log1 < < " Db: " < < PQerrorMessage ( pg_conn ) < < logend ;
2008-12-10 05:42:49 +01:00
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 ;
}
2008-12-14 06:28:28 +01:00
2008-12-10 05:42:49 +01:00
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)
2008-12-14 06:28:28 +01:00
query < < " select id from core.item where url=' " < < Escape ( item . url ) < < appendix < < " ' and parent_id=' " < < item . parent_id < < " '; " ;
2008-12-10 05:42:49 +01:00
r = AssertQuery ( query . str ( ) ) ;
AssertResultStatus ( r , PGRES_TUPLES_OK ) ;
if ( PQntuples ( r ) ! = 0 )
{
sprintf ( appendix , " _(%d) " , + + index ) ;
is_that_url = true ;
}
else
{
2008-12-14 06:28:28 +01:00
item . url + = appendix ;
2008-12-10 05:42:49 +01:00
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 ;
2008-12-14 06:28:28 +01:00
query < < " update core.item set url= " ;
2008-12-10 05:42:49 +01:00
2008-12-14 06:28:28 +01:00
// url
2008-12-10 05:42:49 +01:00
if ( AddItemCreateUrlSubject ( item ) )
2008-12-14 06:28:28 +01:00
query < < ' \' ' < < Escape ( item . url ) < < ' \' ' ;
2008-12-10 05:42:49 +01:00
else
{
query < < ' \' ' < < item . id < < ' \' ' ;
2008-12-14 06:28:28 +01:00
item . url . clear ( ) ;
2008-12-10 05:42:49 +01:00
}
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 ;
2009-06-05 22:29:06 +02:00
// !! subject zostal wrzucony do tabeli item
2008-12-14 06:28:28 +01:00
query < < " select item.id, subject from core.item left join core.content on item.content_id = content.id where url is null or url='' " ;
2008-12-10 05:42:49 +01:00
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 )
{
2008-12-14 06:28:28 +01:00
item . id = atol ( AssertValue ( r , i , cid ) ) ;
2008-12-10 05:42:49 +01:00
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 ;
}
2008-12-14 06:28:28 +01:00
Error Db : : AddItemIntoItem ( Item & item )
2008-12-10 05:42:49 +01:00
{
PGresult * r = 0 ;
Error result = Error : : ok ;
bool url_without_id = false ;
try
{
AssertConnection ( ) ;
std : : ostringstream query ;
2009-06-05 22:29:06 +02:00
query < < " insert into core.item (user_id, group_id, privileges, date_creation, date_modification, type, parent_id, content_id, default_item, subject, url) values ( " ;
query < < ' \' ' < < item . user_id < < " ', " ;
query < < ' \' ' < < item . group_id < < " ', " ;
query < < ' \' ' < < item . privileges < < " ', " ;
query < < ' \' ' < < ConvertTime ( item . date_creation ) < < " ', " ;
2009-03-23 00:54:15 +01:00
query < < ' \' ' < < ConvertTime ( item . date_modification ) < < " ', " ;
2009-06-05 22:29:06 +02:00
query < < ' \' ' < < static_cast < int > ( item . type ) < < " ', " ;
query < < ' \' ' < < item . parent_id < < " ', " ;
query < < ' \' ' < < item . content_id < < " ', " ;
query < < ' \' ' < < item . default_item < < " ', " ;
query < < ' \' ' < < Escape ( item . subject ) < < " ', " ;
2008-12-10 05:42:49 +01:00
url_without_id = AddItemCreateUrlSubject ( item ) ;
if ( url_without_id )
2008-12-14 06:28:28 +01:00
query < < ' \' ' < < Escape ( item . url ) < < " '); " ;
2008-12-10 05:42:49 +01:00
else
2008-12-14 06:28:28 +01:00
query < < " currval('core.item_id_seq') " < < " ); " ;
2008-12-10 05:42:49 +01:00
r = AssertQuery ( query . str ( ) ) ;
AssertResultStatus ( r , PGRES_COMMAND_OK ) ;
item . id = AssertCurrval ( " core.item_id_seq " ) ;
if ( ! url_without_id )
2008-12-14 06:28:28 +01:00
ToString ( item . url , item . id ) ;
2008-12-10 05:42:49 +01:00
}
catch ( const Error & e )
{
result = e ;
}
ClearResult ( r ) ;
return result ;
}
2008-12-14 06:28:28 +01:00
Error Db : : AddItemIntoContent ( Item & item )
{
PGresult * r = 0 ;
Error result = Error : : ok ;
try
{
AssertConnection ( ) ;
std : : ostringstream query ;
2009-06-05 22:29:06 +02:00
query < < " insert into core.content (content, content_type) values ( " ;
query < < ' \' ' < < Escape ( item . content ) < < " ', " ;
query < < ' \' ' < < item . content_type < < " '); " ;
2008-12-14 06:28:28 +01:00
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 )
{
2008-12-31 14:36:46 +01:00
Error result = Error : : ok ;
2008-12-14 06:28:28 +01:00
2008-12-31 14:36:46 +01:00
if ( item . type = = Item : : file )
result = AddItemIntoContent ( item ) ;
else
item . content_id = - 1 ;
2008-12-14 06:28:28 +01:00
if ( result = = Error : : ok )
result = AddItemIntoItem ( item ) ;
return result ;
}
2009-06-05 22:29:06 +02:00
Error Db : : EditItemInItem ( Item & item , bool with_url )
2008-12-10 05:42:49 +01:00
{
PGresult * r = 0 ;
Error result = Error : : ok ;
bool url_without_id = false ;
try
{
AssertConnection ( ) ;
std : : ostringstream query ;
2009-06-05 22:29:06 +02:00
query < < " update core.item set (user_id, group_id, privileges, date_creation, date_modification, type, default_item, parent_id, subject " ;
2008-12-10 05:42:49 +01:00
2009-06-05 22:29:06 +02:00
if ( with_url )
2008-12-21 22:17:09 +01:00
query < < " , url " ;
2008-12-10 05:42:49 +01:00
2008-12-14 06:28:28 +01:00
query < < " ) = ( " ;
2009-06-05 22:29:06 +02:00
query < < ' \' ' < < item . user_id < < " ', " ;
query < < ' \' ' < < item . group_id < < " ', " ;
query < < ' \' ' < < item . privileges < < " ', " ;
query < < ' \' ' < < ConvertTime ( item . date_creation ) < < " ', " ;
2009-03-23 00:54:15 +01:00
query < < ' \' ' < < ConvertTime ( item . date_modification ) < < " ', " ;
2009-06-05 22:29:06 +02:00
query < < ' \' ' < < static_cast < int > ( item . type ) < < " ', " ;
query < < ' \' ' < < item . default_item < < " ', " ;
query < < ' \' ' < < item . parent_id < < " ', " ;
query < < ' \' ' < < Escape ( item . subject ) < < " ' " ;
2008-12-10 05:42:49 +01:00
2009-06-05 22:29:06 +02:00
if ( with_url )
2008-12-10 05:42:49 +01:00
{
url_without_id = AddItemCreateUrlSubject ( item ) ;
if ( url_without_id )
2008-12-14 06:28:28 +01:00
query < < " , ' " < < Escape ( item . url ) < < " ' " ;
2008-12-10 05:42:49 +01:00
else
2008-12-14 06:28:28 +01:00
query < < " , ' " < < item . id < < " ' " ;
2008-12-10 05:42:49 +01:00
}
query < < " ) where id=' " < < item . id < < " '; " ;
r = AssertQuery ( query . str ( ) ) ;
AssertResultStatus ( r , PGRES_COMMAND_OK ) ;
2009-06-05 22:29:06 +02:00
if ( with_url & & ! url_without_id )
2008-12-14 06:28:28 +01:00
ToString ( item . url , item . id ) ;
2008-12-10 05:42:49 +01:00
}
catch ( const Error & e )
{
result = e ;
}
ClearResult ( r ) ;
return result ;
}
2008-12-14 06:28:28 +01:00
Error Db : : EditItemInContent ( Item & item )
{
PGresult * r = 0 ;
Error result = Error : : ok ;
try
{
AssertConnection ( ) ;
std : : ostringstream query ;
2009-06-05 22:29:06 +02:00
query < < " update core.content set (content, content_type) = ( " ;
2008-12-14 06:28:28 +01:00
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 ;
}
2008-12-21 22:17:09 +01:00
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 ;
}
2008-12-14 06:28:28 +01:00
2008-12-21 22:17:09 +01:00
Error Db : : EditItemGetContentId ( Item & item )
2008-12-14 06:28:28 +01:00
{
2008-12-21 22:17:09 +01:00
PGresult * r = 0 ;
Error result = Error : : ok ;
try
{
AssertConnection ( ) ;
std : : ostringstream query ;
2008-12-31 19:28:12 +01:00
// !! tutaj chyba nie ma potrzeby robic left join z core.content (nie uzywamy nic z tamtej tabeli)
2008-12-21 22:17:09 +01:00
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 ) ;
2008-12-14 06:28:28 +01:00
2008-12-21 22:17:09 +01:00
item . content_id = atol ( AssertValue ( r , 0 , 0 ) ) ;
}
catch ( const Error & e )
{
result = e ;
}
ClearResult ( r ) ;
return result ;
}
// item.id must be set
2008-12-30 02:05:03 +01:00
// !! moze nazwa poprostu EditItem (nie trzeba tego ById) ? (sprawdzic czy nie koliduje z inna nazwa)
2009-06-05 22:29:06 +02:00
Error Db : : EditItemById ( Item & item , bool with_url )
2008-12-21 22:17:09 +01:00
{
2008-12-31 19:28:12 +01:00
Error result = Error : : ok ;
// !! dla katalogow nie testowane jeszcze
if ( item . type = = Item : : file )
result = EditItemGetContentId ( item ) ;
2008-12-21 22:17:09 +01:00
2008-12-14 06:28:28 +01:00
if ( result = = Error : : ok )
2008-12-21 22:17:09 +01:00
{
2008-12-31 19:28:12 +01:00
if ( item . type = = Item : : file )
result = EditItemInContent ( item ) ;
2008-12-14 06:28:28 +01:00
2008-12-21 22:17:09 +01:00
if ( result = = Error : : ok )
2009-06-05 22:29:06 +02:00
result = EditItemInItem ( item , with_url ) ;
2008-12-21 22:17:09 +01:00
}
return result ;
}
// item.url and item.parent_id must be set
2008-12-31 19:28:12 +01:00
// doesn't work with directiories
2009-06-05 22:29:06 +02:00
Error Db : : EditItemByUrl ( Item & item , bool with_url )
2008-12-21 22:17:09 +01:00
{
Error result = EditItemGetId ( item ) ;
if ( result = = Error : : ok )
{
result = EditItemInContent ( item ) ;
if ( result = = Error : : ok )
2009-06-05 22:29:06 +02:00
result = EditItemInItem ( item , with_url ) ;
2008-12-21 22:17:09 +01:00
}
2008-12-14 06:28:28 +01:00
return result ;
}
2008-12-31 19:28:12 +01:00
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 ;
}
2008-12-14 06:28:28 +01:00
2008-12-21 22:17:09 +01:00
2009-06-05 22:29:06 +02:00
PGresult * Db : : GetItemsQuery ( long parent_id , Item : : Type type , bool with_subject , bool with_content , bool sort_asc )
2008-12-10 05:42:49 +01:00
{
std : : ostringstream query ;
2009-06-05 22:29:06 +02:00
query < < " select item.id, user_id, group_id, privileges, date_creation, date_modification, url, type, parent_id, content_id, default_item " ;
2008-12-10 05:42:49 +01:00
2009-06-05 22:29:06 +02:00
if ( type ! = Item : : dir )
{
if ( with_subject )
query < < " , subject " ;
if ( with_content )
query < < " , content, content_type " ;
}
query < < " from core.item " ;
2008-12-10 05:42:49 +01:00
2009-06-05 22:29:06 +02:00
if ( type ! = Item : : dir & & with_content )
query < < " left join core.content on item.content_id = content.id " ;
query < < " where parent_id=' " < < parent_id < < " ' " ;
2008-12-10 05:42:49 +01:00
2009-06-05 22:29:06 +02:00
if ( type = = Item : : dir )
query < < " and type='0' " ;
if ( type = = Item : : file )
query < < " and type='1' " ;
query < < " order by item.date_creation " ;
2009-04-21 01:49:28 +02:00
2009-06-05 22:29:06 +02:00
if ( sort_asc )
2009-04-21 01:49:28 +02:00
query < < " asc " ;
else
query < < " desc " ;
2008-12-10 05:42:49 +01:00
query < < ' ; ' ;
return AssertQuery ( query . str ( ) ) ;
}
2009-06-05 22:29:06 +02:00
void Db : : GetItems ( std : : vector < Item > & item_table , long parent_id , Item : : Type type , bool with_subject , bool with_content , bool sort_asc )
2008-12-10 05:42:49 +01:00
{
item_table . clear ( ) ;
PGresult * r = 0 ;
try
{
AssertConnection ( ) ;
2009-06-05 22:29:06 +02:00
r = GetItemsQuery ( parent_id , type , with_subject , with_content , sort_asc ) ;
2008-12-10 05:42:49 +01:00
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 ;
2008-12-14 06:28:28 +01:00
query < < " select * from core.item left join core.content on item.content_id = content.id where type='1' and item.id=' " < < id < < " '; " ;
2008-12-10 05:42:49 +01:00
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 ) ;
}
2008-12-14 06:28:28 +01:00
2008-12-30 02:05:03 +01:00
// !! 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 ;
}
2008-12-31 19:28:12 +01:00
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 ) ;
}
2009-06-05 22:29:06 +02:00
// !! w tej metodzie odczytujemy tylko uprawnienia?
// bo w tej chwili jest caly item odczytywany
2008-12-21 22:17:09 +01:00
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 ;
}
2008-12-30 02:05:03 +01:00
// !! 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 ;
}
2008-12-21 22:17:09 +01:00
2009-02-06 14:12:03 +01:00
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 ;
}
2008-12-14 06:28:28 +01:00
bool Db : : DelItemDelItem ( const Item & item )
2008-12-10 05:42:49 +01:00
{
2008-12-14 06:28:28 +01:00
long rows = 0 ;
2008-12-10 05:42:49 +01:00
PGresult * r = 0 ;
try
{
AssertConnection ( ) ;
std : : ostringstream query ;
2008-12-14 06:28:28 +01:00
query < < " delete from core.item where id=' " < < item . id < < " '; " ;
2008-12-10 05:42:49 +01:00
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 ;
2008-12-14 06:28:28 +01:00
else
if ( rows = = 0 )
log < < log1 < < " Db: no item has been deleted " < < logend ;
2008-12-10 05:42:49 +01:00
}
}
catch ( const Error & )
{
}
ClearResult ( r ) ;
return rows ! = 0 ;
}
2008-12-14 06:28:28 +01:00
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 ) ;
}
2008-12-10 05:42:49 +01:00
void Db : : GetDirs ( DirContainer & dir_table )
{
PGresult * r = 0 ;
try
{
AssertConnection ( ) ;
std : : ostringstream query ;
2008-12-22 17:03:03 +01:00
query < < " select * from core.item where type='0'; " ;
2008-12-10 05:42:49 +01:00
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 ) ;
}
2008-12-21 22:17:09 +01:00
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 ) ;
}
2008-12-10 05:42:49 +01:00
2009-01-26 21:49:28 +01:00
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 ;
}
2008-12-10 05:42:49 +01:00
2009-03-23 00:54:15 +01:00
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 ;
}
2008-12-10 05:42:49 +01:00
2009-04-21 01:49:28 +02:00
Error Db : : GetThreadByDirId ( long dir_id , Thread & thread )
{
PGresult * r = 0 ;
Error status = Error : : ok ;
try
{
AssertConnection ( ) ;
std : : ostringstream query ;
2009-06-05 22:29:06 +02:00
query < < " select thread.id, thread.parent_id, thread.dir_id, thread.closed, thread.items, thread.last_item, item.date_modification, item.user_id from core.thread left join core.item on thread.last_item = item.id where thread.dir_id = ' " < < dir_id < < " '; " ;
2009-04-21 01:49:28 +02:00
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 )
throw Error ( Error : : no_thread ) ;
2009-06-05 22:29:06 +02:00
int cid = AssertColumn ( r , " id " ) ;
int cparent_id = AssertColumn ( r , " parent_id " ) ;
int cdir_id = AssertColumn ( r , " dir_id " ) ;
int cclosed = AssertColumn ( r , " closed " ) ;
int citems = AssertColumn ( r , " items " ) ;
int clast_item = AssertColumn ( r , " last_item " ) ;
int cdate_modification = PQfnumber ( r , " date_modification " ) ;
int cuser_id = PQfnumber ( r , " user_id " ) ;
thread . id = atol ( AssertValue ( r , 0 , cid ) ) ;
thread . parent_id = atol ( AssertValue ( r , 0 , cparent_id ) ) ;
thread . dir_id = atol ( AssertValue ( r , 0 , cdir_id ) ) ;
thread . closed = atol ( AssertValue ( r , 0 , cclosed ) ) = = 0 ? false : true ;
thread . items = atol ( AssertValue ( r , 0 , citems ) ) ;
thread . last_item . id = atol ( AssertValue ( r , 0 , clast_item ) ) ;
thread . last_item . date_modification = ConvertTime ( Db : : AssertValue ( r , 0 , cdate_modification ) ) ;
thread . last_item . user_id = atol ( Db : : AssertValue ( r , 0 , cuser_id ) ) ;
}
catch ( const Error & e )
{
status = e ;
}
ClearResult ( r ) ;
return status ;
}
Error Db : : GetThreads ( long parent_id , std : : vector < Thread > & thread_tab )
{
PGresult * r = 0 ;
Error status = Error : : ok ;
try
{
AssertConnection ( ) ;
std : : ostringstream query ;
query < < " select thread.id, thread.parent_id, thread.dir_id, thread.closed, thread.items, thread.last_item, item.date_modification, item.user_id "
" from core.thread left join core.item on thread.last_item = item.id "
" where thread.parent_id = ' " < < parent_id < < " ' order by date_modification asc; " ;
r = AssertQuery ( query . str ( ) ) ;
AssertResultStatus ( r , PGRES_TUPLES_OK ) ;
2009-04-21 01:49:28 +02:00
2009-06-05 22:29:06 +02:00
int rows = PQntuples ( r ) ;
Thread thread ;
int cid = AssertColumn ( r , " id " ) ;
int cparent_id = AssertColumn ( r , " parent_id " ) ;
int cdir_id = AssertColumn ( r , " dir_id " ) ;
int cclosed = AssertColumn ( r , " closed " ) ;
int citems = AssertColumn ( r , " items " ) ;
int clast_item = AssertColumn ( r , " last_item " ) ;
int cdate_modification = PQfnumber ( r , " date_modification " ) ;
int cuser_id = PQfnumber ( r , " user_id " ) ;
for ( int i = 0 ; i < rows ; + + i )
{
thread . id = atol ( AssertValue ( r , i , cid ) ) ;
thread . parent_id = atol ( AssertValue ( r , i , cparent_id ) ) ;
thread . dir_id = atol ( AssertValue ( r , i , cdir_id ) ) ;
thread . closed = atol ( AssertValue ( r , i , cclosed ) ) = = 0 ? false : true ;
thread . items = atol ( AssertValue ( r , i , citems ) ) ;
thread . last_item . id = atol ( AssertValue ( r , i , clast_item ) ) ;
thread . last_item . date_modification = ConvertTime ( Db : : AssertValue ( r , i , cdate_modification ) ) ;
thread . last_item . user_id = atol ( Db : : AssertValue ( r , i , cuser_id ) ) ;
thread_tab . push_back ( thread ) ;
}
2009-04-21 01:49:28 +02:00
}
catch ( const Error & e )
{
status = e ;
}
ClearResult ( r ) ;
return status ;
}
2009-06-05 22:29:06 +02:00
2009-04-21 01:49:28 +02:00
Error Db : : AddThread ( Thread & thread )
{
PGresult * r = 0 ;
Error status = Error : : ok ;
try
{
AssertConnection ( ) ;
std : : ostringstream query ;
2009-06-05 22:29:06 +02:00
query < < " insert into core.thread (parent_id, dir_id, closed, items, last_item) values ( " ;
query < < ' \' ' < < thread . parent_id < < " ', " ;
2009-04-21 01:49:28 +02:00
query < < ' \' ' < < thread . dir_id < < " ', " ;
2009-06-05 22:29:06 +02:00
query < < ' \' ' < < ( thread . closed ? 1 : 0 ) < < " ', " ;
query < < ' \' ' < < thread . items < < " ', " ;
query < < ' \' ' < < thread . last_item . id < < " '); " ;
2009-04-21 01:49:28 +02:00
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 ;
}
2009-06-05 22:29:06 +02:00
Error Db : : EditThreadAddItem ( long dir_id , long item_id )
{
PGresult * r = 0 ;
Error status = Error : : ok ;
try
{
AssertConnection ( ) ;
std : : ostringstream query ;
query < < " update core.thread set (last_item, items) = (' " < < item_id < < " ', items+1) where dir_id=' " < < dir_id < < " '; " ;
r = AssertQuery ( query . str ( ) ) ;
AssertResultStatus ( r , PGRES_COMMAND_OK ) ;
}
catch ( const Error & e )
{
status = e ;
}
ClearResult ( r ) ;
return status ;
}