# include "ReposLog.hpp"
# include "LogCache.hpp"
# include "svnqt/info_entry.hpp"
# include "svnqt/svnqttypes.hpp"
# include "svnqt/client.hpp"
# include "svnqt/context_listener.hpp"
# include "svnqt/cache/DatabaseException.hpp"
# include <tqsqldatabase.h>
/*!
\ fn svn : : cache : : ReposLog : : ReposLog ( svn : : Client * aClient , const TQString & )
*/
svn : : cache : : ReposLog : : ReposLog ( svn : : Client * aClient , const TQString & aRepository )
: m_Client ( ) ,
m_Database ( 0 ) ,
m_ReposRoot ( aRepository ) , m_latestHead ( svn : : Revision : : UNDEFINED )
{
m_Client = aClient ;
ContextP ctx = m_Client - > getContext ( ) ;
if ( ! aRepository . isEmpty ( ) ) {
m_Database = LogCache : : self ( ) - > reposDb ( aRepository ) ;
}
}
/*!
\ fn svn : : cache : : ReposLog : : latestHeadRev ( )
*/
svn : : Revision svn : : cache : : ReposLog : : latestHeadRev ( )
{
if ( ! m_Client | | m_ReposRoot . isEmpty ( ) ) {
return svn : : Revision : : UNDEFINED ;
}
if ( ! m_Database ) {
m_Database = LogCache : : self ( ) - > reposDb ( m_ReposRoot ) ;
if ( ! m_Database ) {
return svn : : Revision : : UNDEFINED ;
}
}
/// no catch - exception has go trough...
tqDebug ( " Getting headrev " ) ;
svn : : InfoEntries e = m_Client - > info ( m_ReposRoot , svn : : DepthEmpty , svn : : Revision : : HEAD , svn : : Revision : : HEAD ) ;
if ( e . count ( ) < 1 | | e [ 0 ] . reposRoot ( ) . isEmpty ( ) ) {
return svn : : Revision : : UNDEFINED ;
}
tqDebug ( " Getting headrev done " ) ;
return e [ 0 ] . revision ( ) ;
}
/*!
\ fn svn : : cache : : ReposLog : : latestCachedRev ( )
*/
svn : : Revision svn : : cache : : ReposLog : : latestCachedRev ( )
{
if ( m_ReposRoot . isEmpty ( ) ) {
return svn : : Revision : : UNDEFINED ;
}
if ( ! m_Database ) {
m_Database = LogCache : : self ( ) - > reposDb ( m_ReposRoot ) ;
if ( ! m_Database ) {
return svn : : Revision : : UNDEFINED ;
}
}
TQString q ( " select revision from 'logentries' order by revision DESC limit 1 " ) ;
TQSqlQuery _q ( TQString ( ) , m_Database ) ;
if ( ! _q . exec ( q ) ) {
tqDebug ( " %s " , _q . lastError ( ) . text ( ) . TOUTF8 ( ) . data ( ) ) ;
return svn : : Revision : : UNDEFINED ;
}
int _r ;
if ( _q . isActive ( ) & & _q . next ( ) ) {
//tqDebug("Sel result: %s",_q.value(0).toString().TOUTF8().data());
_r = _q . value ( 0 ) . toInt ( ) ;
} else {
tqDebug ( " %s " , _q . lastError ( ) . text ( ) . TOUTF8 ( ) . data ( ) ) ;
return svn : : Revision : : UNDEFINED ;
}
return _r ;
}
bool svn : : cache : : ReposLog : : checkFill ( svn : : Revision & start , svn : : Revision & end , bool checkHead )
{
if ( ! m_Database ) {
m_Database = LogCache : : self ( ) - > reposDb ( m_ReposRoot ) ;
if ( ! m_Database ) {
return false ;
}
}
ContextP cp = m_Client - > getContext ( ) ;
long long icount = 0 ;
svn : : Revision _latest = latestCachedRev ( ) ;
// tqDebug("Latest cached rev: %i",_latest.revnum());
// tqDebug("End revision is: %s",end.toString().TOUTF8().data());
if ( checkHead & & _latest . revnum ( ) > = latestHeadRev ( ) . revnum ( ) ) {
return true ;
}
start = date2numberRev ( start ) ;
end = date2numberRev ( end ) ;
// both should now one of START, HEAD or NUMBER
if ( start = = svn : : Revision : : HEAD | | ( end = = svn : : Revision : : NUMBER & & start = = svn : : Revision : : NUMBER & & start . revnum ( ) > end . revnum ( ) ) ) {
svn : : Revision tmp = start ;
start = end ;
end = tmp ;
}
svn : : Revision _rstart = _latest . revnum ( ) + 1 ;
svn : : Revision _rend = end ;
if ( _rend = = svn : : Revision : : UNDEFINED ) {
// tqDebug("Setting end to Head");
_rend = svn : : Revision : : HEAD ;
}
// no catch - exception should go outside.
if ( _rstart = = 0 ) {
_rstart = 1 ;
}
// tqDebug("Getting log %s -> %s",_rstart.toString().TOUTF8().data(),_rend.toString().TOUTF8().data());
if ( _rend = = svn : : Revision : : HEAD ) {
_rend = latestHeadRev ( ) ;
}
if ( _rend = = svn : : Revision : : HEAD | | _rend . revnum ( ) > _latest . revnum ( ) ) {
LogEntriesMap _internal ;
// tqDebug("Retrieving from network.");
if ( ! m_Client - > log ( m_ReposRoot , _rstart , _rend , _internal , svn : : Revision : : UNDEFINED , true , false ) ) {
return false ;
}
LogEntriesMap : : ConstIterator it = _internal . begin ( ) ;
for ( ; it ! = _internal . end ( ) ; + + it ) {
_insertLogEntry ( ( * it ) ) ;
if ( cp & & cp - > getListener ( ) ) {
//cp->getListener()->contextProgress(++icount,_internal.size());
if ( cp - > getListener ( ) - > contextCancel ( ) ) {
throw DatabaseException ( TQString ( " Could not retrieve values: User cancel. " ) ) ;
}
}
}
}
return true ;
}
bool svn : : cache : : ReposLog : : fillCache ( const svn : : Revision & _end )
{
svn : : Revision end = _end ;
svn : : Revision start = latestCachedRev ( ) . revnum ( ) + 1 ;
return checkFill ( start , end , false ) ;
}
/*!
\ fn svn : : cache : : ReposLog : : simpleLog ( const svn : : Revision & start , const svn : : Revision & end , LogEntriesMap & target )
*/
bool svn : : cache : : ReposLog : : simpleLog ( LogEntriesMap & target , const svn : : Revision & _start , const svn : : Revision & _end , bool noNetwork )
{
if ( ! m_Client | | m_ReposRoot . isEmpty ( ) ) {
return false ;
}
target . clear ( ) ;
ContextP cp = m_Client - > getContext ( ) ;
svn : : Revision end = _end ;
svn : : Revision start = _start ;
if ( ! noNetwork ) {
if ( ! checkFill ( start , end , true ) ) {
return false ;
}
} else {
end = date2numberRev ( end , noNetwork ) ;
start = date2numberRev ( start , noNetwork ) ;
}
if ( end = = svn : : Revision : : HEAD ) {
end = latestCachedRev ( ) ;
}
if ( start = = svn : : Revision : : HEAD ) {
start = latestCachedRev ( ) ;
}
static TQString sCount ( " select count(*) from logentries where revision < = ? and revision > = ? " ) ;
static TQString sEntry ( " select revision,author,date,message from logentries where revision<=? and revision>=? " ) ;
static TQString sItems ( " select changeditem,action,copyfrom,copyfromrev from changeditems where revision=? " ) ;
TQSqlQuery bcount ( TQString ( ) , m_Database ) ;
bcount . prepare ( sCount ) ;
TQSqlQuery bcur ( TQString ( ) , m_Database ) ;
bcur . prepare ( sEntry ) ;
TQSqlQuery cur ( TQString ( ) , m_Database ) ;
cur . prepare ( sItems ) ;
bcount . bindValue ( 0 , TQ_LLONG ( end . revnum ( ) ) ) ;
bcount . bindValue ( 1 , TQ_LLONG ( start . revnum ( ) ) ) ;
if ( ! bcount . exec ( ) ) {
tqDebug ( " %s " , bcount . lastError ( ) . text ( ) . TOUTF8 ( ) . data ( ) ) ;
throw svn : : cache : : DatabaseException ( TQString ( " Could not retrieve count: " ) + bcount . lastError ( ) . text ( ) ) ;
return false ;
}
bcount . next ( ) ;
if ( bcount . value ( 0 ) . toLongLong ( ) < 1 ) {
// we didn't found logs with this parameters
return false ;
}
bcur . bindValue ( 0 , TQ_LLONG ( end . revnum ( ) ) ) ;
bcur . bindValue ( 1 , TQ_LLONG ( start . revnum ( ) ) ) ;
if ( ! bcur . exec ( ) ) {
tqDebug ( " %s " , bcur . lastError ( ) . text ( ) . TOUTF8 ( ) . data ( ) ) ;
throw svn : : cache : : DatabaseException ( TQString ( " Could not retrieve values: " ) + bcur . lastError ( ) . text ( ) ) ;
return false ;
}
TQ_LLONG revision ;
while ( bcur . next ( ) ) {
revision = bcur . value ( 0 ) . toLongLong ( ) ;
cur . bindValue ( 0 , revision ) ;
if ( ! cur . exec ( ) ) {
tqDebug ( " %s " , cur . lastError ( ) . text ( ) . TOUTF8 ( ) . data ( ) ) ;
throw svn : : cache : : DatabaseException ( TQString ( " Could not retrieve values: " ) + cur . lastError ( ) . text ( )
, cur . lastError ( ) . number ( ) ) ;
return false ;
}
target [ revision ] . revision = revision ;
target [ revision ] . author = bcur . value ( 1 ) . toString ( ) ;
target [ revision ] . date = bcur . value ( 2 ) . toLongLong ( ) ;
target [ revision ] . message = bcur . value ( 3 ) . toString ( ) ;
while ( cur . next ( ) ) {
LogChangePathEntry lcp ;
TQString ac = cur . value ( 1 ) . toString ( ) ;
lcp . action = ac [ 0 ] . latin1 ( ) ;
lcp . copyFromPath = cur . value ( 2 ) . toString ( ) ;
lcp . path = cur . value ( 0 ) . toString ( ) ;
lcp . copyFromRevision = cur . value ( 3 ) . toLongLong ( ) ;
target [ revision ] . changedPaths . push_back ( lcp ) ;
}
if ( cp & & cp - > getListener ( ) ) {
if ( cp - > getListener ( ) - > contextCancel ( ) ) {
throw svn : : cache : : DatabaseException ( TQString ( " Could not retrieve values: User cancel. " ) ) ;
return false ;
}
}
}
return true ;
}
/*!
\ fn svn : : cache : : ReposLog : : date2numberRev ( const svn : : Revision & )
*/
svn : : Revision svn : : cache : : ReposLog : : date2numberRev ( const svn : : Revision & aRev , bool noNetwork )
{
if ( aRev ! = svn : : Revision : : DATE ) {
return aRev ;
}
if ( ! m_Database ) {
return svn : : Revision : : UNDEFINED ;
}
static TQString _q ( " select revision from logentries where date<? order by revision desc " ) ;
TQSqlQuery query ( " select revision,date from logentries order by revision desc limit 1 " , m_Database ) ;
if ( query . lastError ( ) . type ( ) ! = TQSqlError : : None ) {
tqDebug ( " %s " , query . lastError ( ) . text ( ) . TOUTF8 ( ) . data ( ) ) ;
}
bool must_remote = ! noNetwork ;
if ( query . next ( ) ) {
if ( query . value ( 1 ) . toLongLong ( ) > = aRev . date ( ) ) {
must_remote = false ;
}
}
if ( must_remote ) {
svn : : InfoEntries e = ( m_Client - > info ( m_ReposRoot , svn : : DepthEmpty , aRev , aRev ) ) ; ;
if ( e . count ( ) < 1 | | e [ 0 ] . reposRoot ( ) . isEmpty ( ) ) {
return aRev ;
}
return e [ 0 ] . revision ( ) ;
}
query . prepare ( _q ) ;
query . bindValue ( 0 , TQ_LLONG ( aRev . date ( ) ) ) ;
query . exec ( ) ;
if ( query . lastError ( ) . type ( ) ! = TQSqlError : : None ) {
tqDebug ( " %s " , query . lastError ( ) . text ( ) . TOUTF8 ( ) . data ( ) ) ;
}
if ( query . next ( ) ) {
return query . value ( 0 ) . toInt ( ) ;
}
// not found...
if ( noNetwork ) {
return svn : : Revision : : UNDEFINED ;
}
svn : : InfoEntries e = ( m_Client - > info ( m_ReposRoot , svn : : DepthEmpty , svn : : Revision : : HEAD , svn : : Revision : : HEAD ) ) ; ;
if ( e . count ( ) < 1 | | e [ 0 ] . reposRoot ( ) . isEmpty ( ) ) {
return svn : : Revision : : UNDEFINED ;
}
return e [ 0 ] . revision ( ) ;
}
/*!
\ fn svn : : cache : : ReposLog : : insertLogEntry ( const svn : : LogEntry & )
*/
bool svn : : cache : : ReposLog : : _insertLogEntry ( const svn : : LogEntry & aEntry )
{
TQSqlRecord * buffer ;
m_Database - > transaction ( ) ;
TQ_LLONG j = aEntry . revision ;
static TQString qEntry ( " insert into logentries (revision,date,author,message) values ( ? , ? , ? , ? ) " ) ;
static TQString qPathes ( " insert into changeditems (revision,changeditem,action,copyfrom,copyfromrev) values ( ? , ? , ? , ? , ? ) " ) ;
TQSqlQuery _q ( TQString ( ) , m_Database ) ;
_q . prepare ( qEntry ) ;
_q . bindValue ( 0 , j ) ;
_q . bindValue ( 1 , aEntry . date ) ;
_q . bindValue ( 2 , aEntry . author ) ;
_q . bindValue ( 3 , aEntry . message ) ;
if ( ! _q . exec ( ) ) {
m_Database - > rollback ( ) ;
tqDebug ( " Could not insert values: %s " , _q . lastError ( ) . text ( ) . TOUTF8 ( ) . data ( ) ) ;
tqDebug ( " %s " , _q . lastQuery ( ) . TOUTF8 ( ) . data ( ) ) ;
throw svn : : cache : : DatabaseException ( TQString ( " Could not insert values: " ) + _q . lastError ( ) . text ( ) , _q . lastError ( ) . number ( ) ) ;
}
_q . prepare ( qPathes ) ;
svn : : LogChangePathEntries : : ConstIterator cpit = aEntry . changedPaths . begin ( ) ;
for ( ; cpit ! = aEntry . changedPaths . end ( ) ; + + cpit ) {
_q . bindValue ( 0 , j ) ;
_q . bindValue ( 1 , ( * cpit ) . path ) ;
_q . bindValue ( 2 , TQString ( TQChar ( ( * cpit ) . action ) ) ) ;
_q . bindValue ( 3 , ( * cpit ) . copyFromPath ) ;
_q . bindValue ( 4 , TQ_LLONG ( ( * cpit ) . copyFromRevision ) ) ;
if ( ! _q . exec ( ) ) {
m_Database - > rollback ( ) ;
tqDebug ( " Could not insert values: %s " , _q . lastError ( ) . text ( ) . TOUTF8 ( ) . data ( ) ) ;
tqDebug ( " %s " , _q . lastQuery ( ) . TOUTF8 ( ) . data ( ) ) ;
throw svn : : cache : : DatabaseException ( TQString ( " Could not insert values: " ) + _q . lastError ( ) . text ( ) , _q . lastError ( ) . number ( ) ) ;
}
}
m_Database - > commit ( ) ;
return true ;
}
bool svn : : cache : : ReposLog : : insertLogEntry ( const svn : : LogEntry & aEntry )
{
return _insertLogEntry ( aEntry ) ;
}
/*!
\ fn svn : : cache : : ReposLog : : log ( const svn : : Path & , const svn : : Revision & start , const svn : : Revision & end , const svn : : Revision & peg , svn : : LogEntriesMap & target , bool strictNodeHistory , int limit ) )
*/
bool svn : : cache : : ReposLog : : log ( const svn : : Path & what , const svn : : Revision & _start , const svn : : Revision & _end , const svn : : Revision & _peg , svn : : LogEntriesMap & target , bool strictNodeHistory , int limit )
{
static TQString s_q ( " select logentries.revision,logentries.author,logentries.date,logentries.message from logentries where logentries.revision in (select changeditems.revision from changeditems where (changeditems.changeditem='%1' or changeditems.changeditem GLOB '%2/*') % 3 GROUP BY changeditems . revision ) ORDER BY logentries . revision DESC " ) ;
static TQString s_e ( " select changeditem,action,copyfrom,copyfromrev from changeditems where changeditems.revision='%1' " ) ;
svn : : Revision peg = date2numberRev ( _peg , true ) ;
svn : : Revision end = date2numberRev ( _end , true ) ;
svn : : Revision start = date2numberRev ( _start , true ) ;
TQString query_string = TQString ( s_q ) . arg ( what . native ( ) ) . arg ( what . native ( ) ) . arg ( ( peg = = svn : : Revision : : UNDEFINED ? " " : TQString ( " AND revision<=%1 " ) . arg ( peg . revnum ( ) ) ) ) ;
if ( peg = = svn : : Revision : : UNDEFINED ) {
peg = latestCachedRev ( ) ;
}
if ( ! itemExists ( peg , what ) ) {
throw svn : : cache : : DatabaseException ( TQString ( " Entry '%1' does not exists at revision %2 " ) . arg ( what . native ( ) ) . arg ( peg . toString ( ) ) ) ;
}
if ( limit > 0 ) {
query_string + = TQString ( " LIMIT %1 " ) . arg ( limit ) ;
}
TQSqlQuery _q ( TQString ( ) , m_Database ) ;
TQSqlQuery _q2 ( TQString ( ) , m_Database ) ;
_q . prepare ( query_string ) ;
if ( ! _q . exec ( ) ) {
tqDebug ( " Could not select values: %s " , _q . lastError ( ) . text ( ) . TOUTF8 ( ) . data ( ) ) ;
tqDebug ( " %s " , _q . lastQuery ( ) . TOUTF8 ( ) . data ( ) ) ;
throw svn : : cache : : DatabaseException ( TQString ( " Could not select values: " ) + _q . lastError ( ) . text ( ) , _q . lastError ( ) . number ( ) ) ;
}
while ( _q . next ( ) ) {
TQ_LLONG revision = _q . value ( 0 ) . toLongLong ( ) ;
target [ revision ] . revision = revision ;
target [ revision ] . author = _q . value ( 1 ) . toString ( ) ;
target [ revision ] . date = _q . value ( 2 ) . toLongLong ( ) ;
target [ revision ] . message = _q . value ( 3 ) . toString ( ) ;
query_string = s_e . arg ( revision ) ;
_q2 . prepare ( query_string ) ;
if ( ! _q2 . exec ( ) ) {
tqDebug ( " Could not select values: %s " , _q2 . lastError ( ) . text ( ) . TOUTF8 ( ) . data ( ) ) ;
} else {
while ( _q2 . next ( ) ) {
target [ revision ] . changedPaths . push_back (
LogChangePathEntry ( _q2 . value ( 0 ) . toString ( ) ,
_q2 . value ( 1 ) . toString ( ) [ 0 ] ,
_q2 . value ( 2 ) . toString ( ) ,
_q2 . value ( 3 ) . toLongLong ( )
)
) ;
}
}
}
return true ;
}
/*!
\ fn svn : : cache : : ReposLog : : itemExists ( const svn : : Revision & , const TQString & )
*/
bool svn : : cache : : ReposLog : : itemExists ( const svn : : Revision & peg , const svn : : Path & path )
{
/// @todo this moment I have no idea how to check real with all moves and deletes of parent folders without a hell of sql statements so we make it quite simple: it exists if we found it.
#if 0
static TQString _s1 ( " select revision from changeditems where changeditem='%1' and action='A' and revision<=%2 order by revision desc limit 1 " ) ;
TQSqlQuery _q ( TQString ( ) , m_Database ) ;
TQString query_string = TQString ( _s1 ) . arg ( path . native ( ) ) . arg ( peg . revnum ( ) ) ;
if ( ! _q . exec ( query_string ) ) {
tqDebug ( " Could not select values: %s " , _q . lastError ( ) . text ( ) . TOUTF8 ( ) . data ( ) ) ;
tqDebug ( _q . lastQuery ( ) . TOUTF8 ( ) . data ( ) ) ;
throw svn : : cache : : DatabaseException ( TQString ( " Could not select values: " ) + _q . lastError ( ) . text ( ) , _q . lastError ( ) . number ( ) ) ;
}
tqDebug ( _q . lastQuery ( ) . TOUTF8 ( ) . data ( ) ) ;
svn : : Path _p = path ;
static TQString _s2 ( " select revision from changeditem where changeditem in (%1) and action = ' D ' and revision > % 2 and revision < = % 3 order by revision desc limit 1 " ) ;
TQStringList p_list ;
while ( _p . length ( ) > 0 ) {
p_list . append ( TQString ( " '%1' " ) . arg ( _p . native ( ) ) ) ;
_p . removeLast ( ) ;
}
query_string = TQString ( _s2 ) . arg ( p_list . join ( " , " ) ) . arg ( ) ;
# endif
return true ;
}
bool svn : : cache : : ReposLog : : isValid ( ) const
{
if ( ! m_Database ) {
m_Database = LogCache : : self ( ) - > reposDb ( m_ReposRoot ) ;
if ( ! m_Database ) {
return false ;
}
}
return true ;
}