/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*
Copyright (c) 2013 D. Richard Hipp
This program is free software; you can redistribute it and/or
modify it under the terms of the Simplified BSD License (also
known as the "2-Clause License" or "FreeBSD License".)
This program is distributed in the hope that it will be useful,
but without any warranty; without even the implied warranty of
merchantability or fitness for a particular purpose.
Author contact information:
drh@hwaci.com
http://www.hwaci.com/drh/
*****************************************************************************
This file houses some of the "leaf"-related APIs.
*/
#include <assert.h>
#include "fossil-scm/fossil-internal.h"
/* Only for debugging */
#define MARKER(pfexp) \
do{ printf("MARKER: %s:%d:%s():\t",__FILE__,__LINE__,__func__); \
printf pfexp; \
} while(0)
int fsl_repo_leaves_rebuild(fsl_cx * f){
fsl_db * db = f ? fsl_cx_db_repo(f) : NULL;
return !db ? FSL_RC_MISUSE : fsl_db_exec_multi(db,
"DELETE FROM leaf;"
"INSERT OR IGNORE INTO leaf"
" SELECT cid FROM plink"
" EXCEPT"
" SELECT pid FROM plink"
" WHERE coalesce((SELECT value FROM tagxref"
" WHERE tagid=%d AND rid=plink.pid),'trunk')"
" == coalesce((SELECT value FROM tagxref"
" WHERE tagid=%d AND rid=plink.cid),'trunk')",
FSL_TAGID_BRANCH, FSL_TAGID_BRANCH
);
}
fsl_int_t fsl_count_nonbranch_children(fsl_cx * f, fsl_id_t rid){
fsl_int32_t rv = 0;
int rc;
fsl_db * db = f ? fsl_cx_db_repo(f) : NULL;
if(!db || !db->dbh || (rid<=0)) return -1;
rc = fsl_db_get_int32(db, &rv,
"SELECT count(*) FROM plink "
"WHERE pid=%"FSL_ID_T_PFMT" "
"AND isprim "
"AND coalesce((SELECT value FROM tagxref "
"WHERE tagid=%d AND rid=plink.pid), 'trunk')"
"=coalesce((SELECT value FROM tagxref "
"WHERE tagid=%d AND rid=plink.cid), 'trunk')",
rid, FSL_TAGID_BRANCH, FSL_TAGID_BRANCH);
return rc ? -2 : rv;
}
/*
Return >0 if the check-in with RID=rid is a leaf, 0
if it is not, negative value on error.
A leaf has no children in the same branch.
*/
char fsl_rid_is_leaf(fsl_cx * f, fsl_id_t rid){
fsl_int32_t rv = -1;
int rc;
fsl_db * db = f ? fsl_cx_db_repo(f) : NULL;
fsl_stmt * st = NULL;
if(!db || !db->dbh || (rid<=0)) return 0;
rc = fsl_db_prepare_cached(db, &st,
"SELECT 1 FROM plink "
"WHERE pid=? "
"AND coalesce((SELECT value FROM tagxref "
"WHERE tagid=%d "
"AND rid=plink.pid), 'trunk')"
"=coalesce((SELECT value FROM tagxref "
"WHERE tagid=%d "
"AND rid=plink.cid), 'trunk')",
FSL_TAGID_BRANCH, FSL_TAGID_BRANCH);
if(!rc){
rc = fsl_stmt_bind_id(st, 1, rid);
if(!rc){
rc = fsl_stmt_step(st);
if(FSL_RC_STEP_ROW==rc){
rv = 1;
}else if(FSL_RC_STEP_DONE==rc) rc = 0;
}
fsl_stmt_cached_yield(st);
}
return rc ? 0 : (rv==-1);
}
int fsl_repo_leaf_check(fsl_cx * f, fsl_id_t rid){
fsl_db * db = f ? fsl_cx_db_repo(f) : NULL;
if(!db || !db->dbh) return FSL_RC_MISUSE;
else if(rid<=0) return FSL_RC_RANGE;
else {
char isLeaf;
int rc = 0;
fsl_stmt * st = NULL;
isLeaf = fsl_rid_is_leaf(f, rid);
if( isLeaf ){
rc = fsl_db_prepare_cached(db, &st,
"DELETE FROM leaf WHERE rid=?");
}else{
rc = fsl_db_prepare_cached(db, &st,
"INSERT OR IGNORE INTO leaf VALUES"
"(?)");
}
if(!rc && st){
rc = fsl_stmt_bind_id(st, 1, rid);
if(!rc) rc = fsl_stmt_step(st);
fsl_stmt_cached_yield(st);
if(FSL_RC_STEP_DONE==rc) rc = 0;
}
return rc;
}
}
int fsl_repo_leaf_eventually_check( fsl_cx * f, fsl_id_t rid){
fsl_db * db = f ? fsl_cx_db_repo(f) : NULL;
if(!f) return FSL_RC_MISUSE;
else if(rid<=0) return FSL_RC_RANGE;
else if(!db) return FSL_RC_NOT_A_REPO;
else {
fsl_stmt * parentsOf = NULL;
int rc = fsl_db_prepare_cached(db, &parentsOf,
"SELECT pid FROM plink WHERE "
"cid=? AND pid>0");
if(rc) return rc;
rc = fsl_stmt_bind_id(parentsOf, 1, rid);
if(!rc){
rc = fsl_id_bag_insert(&f->cache.leafCheck, rid);
while( !rc && (FSL_RC_STEP_ROW==fsl_stmt_step(parentsOf)) ){
rc = fsl_id_bag_insert(&f->cache.leafCheck,
fsl_stmt_g_id(parentsOf, 0));
}
}
fsl_stmt_cached_yield(parentsOf);
return rc;
}
}
int fsl_repo_leaf_do_pending_checks(fsl_cx *f){
fsl_id_t rid;
int rc = 0;
for(rid=fsl_id_bag_first(&f->cache.leafCheck);
!rc && rid; rid=fsl_id_bag_next(&f->cache.leafCheck,rid)){
rc = fsl_repo_leaf_check(f, rid);
}
fsl_id_bag_clear(&f->cache.leafCheck);
return rc;
}
#undef MARKER