/* ** Repopulate the ticket table */ void ticket_rebuild(void){ Stmt q; ticket_create_table(1); db_begin_transaction(); db_prepare(&q,"SELECT tagname FROM tag WHERE tagname GLOB 'tkt-*'"); while( db_step(&q)==SQLITE_ROW ){ const char *zName = db_column_text(&q, 0); int len; zName += 4; len = strlen(zName); if( len<20 || !validate16(zName, len) ) continue; ticket_rebuild_entry(zName); } db_finalize(&q); db_end_transaction(0); }
/* ** Core function to rebuild the information in the derived tables of a ** fossil repository from the blobs. This function is shared between ** 'rebuild_database' ('rebuild') and 'reconstruct_cmd' ** ('reconstruct'), both of which have to regenerate this information ** from scratch. ** ** If the randomize parameter is true, then the BLOBs are deliberately ** extracted in a random order. This feature is used to test the ** ability of fossil to accept records in any order and still ** construct a sane repository. */ int rebuild_db(int randomize, int doOut, int doClustering){ Stmt s; int errCnt = 0; char *zTable; int incrSize; bag_init(&bagDone); ttyOutput = doOut; processCnt = 0; if (ttyOutput && !g.fQuiet) { percent_complete(0); } rebuild_update_schema(); for(;;){ zTable = db_text(0, "SELECT name FROM sqlite_master /*scan*/" " WHERE type='table'" " AND name NOT IN ('blob','delta','rcvfrom','user'," "'config','shun','private','reportfmt'," "'concealed','accesslog','modreq')" " AND name NOT GLOB 'sqlite_*'" " AND name NOT GLOB 'fx_*'" ); if( zTable==0 ) break; db_multi_exec("DROP TABLE %Q", zTable); free(zTable); } db_multi_exec(zRepositorySchema2); ticket_create_table(0); shun_artifacts(); db_multi_exec( "INSERT INTO unclustered" " SELECT rid FROM blob EXCEPT SELECT rid FROM private" ); db_multi_exec( "DELETE FROM unclustered" " WHERE rid IN (SELECT rid FROM shun JOIN blob USING(uuid))" ); db_multi_exec( "DELETE FROM config WHERE name IN ('remote-code', 'remote-maxid')" ); /* The following should be count(*) instead of max(rid). max(rid) is ** an adequate approximation, however, and is much faster for large ** repositories. */ totalSize = db_int(0, "SELECT max(rid) FROM blob"); incrSize = totalSize/100; totalSize += incrSize*2; db_prepare(&s, "SELECT rid, size FROM blob /*scan*/" " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)" " AND NOT EXISTS(SELECT 1 FROM delta WHERE rid=blob.rid)" ); manifest_crosslink_begin(); while( db_step(&s)==SQLITE_ROW ){ int rid = db_column_int(&s, 0); int size = db_column_int(&s, 1); if( size>=0 ){ Blob content; content_get(rid, &content); rebuild_step(rid, size, &content); } } db_finalize(&s); db_prepare(&s, "SELECT rid, size FROM blob" " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)" ); while( db_step(&s)==SQLITE_ROW ){ int rid = db_column_int(&s, 0); int size = db_column_int(&s, 1); if( size>=0 ){ if( !bag_find(&bagDone, rid) ){ Blob content; content_get(rid, &content); rebuild_step(rid, size, &content); } }else{ db_multi_exec("INSERT OR IGNORE INTO phantom VALUES(%d)", rid); rebuild_step_done(rid); } } db_finalize(&s); manifest_crosslink_end(MC_NONE); rebuild_tag_trunk(); if( ttyOutput && !g.fQuiet && totalSize>0 ){ processCnt += incrSize; percent_complete((processCnt*1000)/totalSize); } if( doClustering ) create_cluster(); if( ttyOutput && !g.fQuiet && totalSize>0 ){ processCnt += incrSize; percent_complete((processCnt*1000)/totalSize); } if(!g.fQuiet && ttyOutput ){ percent_complete(1000); fossil_print("\n"); } return errCnt; }