/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=2 et sw=2 tw=80: */ /* Copyright 2013-2021 The Libfossil Authors, see LICENSES/BSD-2-Clause.txt SPDX-License-Identifier: BSD-2-Clause-FreeBSD SPDX-FileCopyrightText: 2021 The Libfossil Authors SPDX-ArtifactOfProjectName: Libfossil SPDX-FileType: Code Heavily indebted to the Fossil SCM project (https://fossil-scm.org). */ /************************************************************************* This file implements ticket-related parts of the library. */ #include "fossil-scm/fossil-internal.h" #include #include /* memcmp() */ int fsl__cx_ticket_create_table(fsl_cx * const f){ fsl_db * const db = fsl_needs_repo(f); int rc; if(!db) return FSL_RC_NOT_A_REPO; rc = fsl_cx_exec_multi(f, "DROP TABLE IF EXISTS ticket;" "DROP TABLE IF EXISTS ticketchng;" ); if(!rc){ fsl_buffer * const buf = &f->cache.fileContent; fsl_buffer_reuse(buf); rc = fsl_cx_schema_ticket(f, buf); if(!rc) rc = fsl_cx_exec_multi(f, "%b", buf); } return rc; } static int fsl_tkt_field_id(fsl_list const * jli, const char *zFieldName){ int i; fsl_card_J const * jc; for(i=0; i<(int)jli->used; ++i){ jc = (fsl_card_J const *)jli->list[i]; if( !fsl_strcmp(zFieldName, jc->field) ) return i; } return -1; } int fsl__cx_ticket_load_fields(fsl_cx * const f, bool forceReload){ fsl_stmt q = fsl_stmt_empty; int i, rc = 0; fsl_list * const li = &f->ticket.customFields; fsl_card_J * jc; if( !fsl_needs_repo(f) ){ return FSL_RC_NOT_A_REPO; }else if(li->used){ if(!forceReload) return 0; fsl__card_J_list_free(li, false); /* Fall through and reload ... */ } rc = fsl_cx_prepare(f, &q, "PRAGMA table_info(ticket)"); if(!rc) while( FSL_RC_STEP_ROW==fsl_stmt_step(&q) ){ char const * zFieldName = fsl_stmt_g_text(&q, 1, NULL); f->ticket.hasTicket = 1; if( 0==memcmp(zFieldName,"tkt_", 4)){ if( 0==fsl_strcmp(zFieldName,"tkt_ctime")) f->ticket.hasCTime = 1; continue; } jc = fsl_card_J_malloc(0, zFieldName, NULL); if(!jc){ rc = FSL_RC_OOM; break; } jc->flags = FSL_CARD_J_TICKET; rc = fsl_list_append(li, jc); if(rc){ fsl_card_J_free(jc); break; } } fsl_stmt_finalize(&q); if(rc) goto end; rc = fsl_cx_prepare(f, &q, "PRAGMA table_info(ticketchng)"); if(!rc) while( FSL_RC_STEP_ROW==fsl_stmt_step(&q) ){ char const * zFieldName = fsl_stmt_g_text(&q, 1, NULL); f->ticket.hasChng = 1; if( 0==memcmp(zFieldName,"tkt_", 4)){ if( 0==fsl_strcmp(zFieldName,"tkt_rid")) f->ticket.hasChngRid = 1; continue; } if( (i=fsl_tkt_field_id(li, zFieldName)) >= 0){ jc = (fsl_card_J*)li->list[i]; jc->flags |= FSL_CARD_J_CHNG; continue; } jc = fsl_card_J_malloc(0, zFieldName, NULL); if(!jc){ rc = FSL_RC_OOM; break; } jc->flags = FSL_CARD_J_CHNG; rc = fsl_list_append(li, jc); if(rc){ fsl_card_J_free(jc); break; } } fsl_stmt_finalize(&q); end: if(!rc){ fsl_list_sort(li, fsl__qsort_cmp_J_cards); } return rc; } int fsl__ticket_rebuild(fsl_cx * const f, char const * zTktKCard){ int rc; fsl_id_t tktRid; fsl_id_t tagId; fsl_db * const db = fsl_needs_repo(f); fsl_stmt q = fsl_stmt_empty; if(!db) return FSL_RC_NOT_A_REPO; assert(!f->cache.isCrosslinking); rc = fsl__cx_ticket_load_fields(f, false); if(rc) goto end; else if(!f->ticket.hasTicket) return 0; if(f->flags & FSL_CX_F_SKIP_UNKNOWN_CROSSLINKS){ return 0; }else{ char * const zTag = fsl_mprintf("tkt-%s", zTktKCard); if(!zTag){ rc = FSL_RC_OOM; goto end; } tagId = fsl_tag_id(f, zTag, true); fsl_free(zTag); } if(tagId<0){ rc = f->error.code; assert(0!=rc); goto end; } tktRid = fsl_db_g_id(db, 0, "SELECT tkt_id FROM ticket " "WHERE tkt_uuid=%Q", zTktKCard); if(tktRid>0){ if(f->ticket.hasChng){ rc = fsl_cx_exec(f, "DELETE FROM ticketchng " "WHERE tkt_id=%" FSL_ID_T_PFMT, tktRid); } if(!rc) rc = fsl_cx_exec(f, "DELETE FROM ticket " "WHERE tkt_id=%" FSL_ID_T_PFMT, tktRid); if(rc) goto end; } tktRid = 0; rc = fsl_cx_prepare(f, &q, "SELECT rid FROM tagxref " "WHERE tagid=%" FSL_ID_T_PFMT " ORDER BY mtime", tagId); while(0==rc && FSL_RC_STEP_ROW==fsl_stmt_step(&q)){ fsl_deck deck = fsl_deck_empty; fsl_id_t const rid = fsl_stmt_g_id(&q, 0); rc = fsl_deck_load_rid(f, &deck, rid, FSL_SATYPE_TICKET); if(0==rc){ #if 0 /* TODOs... */ assert(deck.rid==rid); rc = fsl__ticket_insert(f, &deck, rid, tktRid, &tgtRid) /* See fossil(1) tkt.c:ticket_insert() */; if(rc) goto outro; rc = fsl__deck_ticket_event(&deck, createFlag, tagId) /* See fossil(1) manifest.c:mainfest_ticket_event() */; #else rc = fsl_cx_err_set(f, FSL_RC_NYI, "MISSING: a huge block of TICKET stuff from/via " "manifest_crosslink(). It requires infrastructure " "libfossil does not yet have."); #endif } //outro: fsl_deck_finalize(&deck); } end: fsl_stmt_finalize(&q); return rc; }