/* -*- 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 #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