/*
 * mg_bump_stan_dbio.pgc - mg 모듈 DB 접근 함수 (mg_bump_stan_dbio), archived into libmgdbio.a.
 * ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
 * 활동 채널 last_stan 증가.
 */
#include <string.h>
#include <userlog.h>
#include "mg_bump_stan_dbio.h"

/*
 * 해당 영업일에 전문이 오간 활동 채널 수를 세고, STAN 은 시퀀스에서 채번한다.
 *
 * 과거 구현은 mg_channel 을 다중행 UPDATE(last_stan = last_stan + 1) 했었다.
 * 그 방식은 크로스브랜치 핫로우 교착의 원인이다: 한 글로벌 트랜잭션 안에서
 * 형제 XA 브랜치 둘이 같은 채널 행을 잠그면 같은 트랜잭션이라 락이 풀리지 않아
 * 트랜잭션 타임아웃까지 그대로 멈춘다(AUTH→LIMIT_DEC/FRAUD_DETECT→MG_LOG 사례).
 * 다중행 UPDATE 라 활동 채널 전체를 한 번에 잠가 파급도 가장 넓었다.
 *
 * 실제 전문 스위치도 STAN 을 채널 상태행이 아니라 카운터에서 뽑는다.
 * 시퀀스 채번은 행락을 잡지 않아 형제 브랜치끼리 충돌하지 않는다.
 * mg_channel 쓰기는 채널 생애주기 소유자(MG_CHANOPEN/CLOSE/SWITCH/FAILOVER/
 * RESET/SIGNON/SIGNOFF)에게만 남긴다.
 *
 * 반환: 해당 영업일 활동 채널 수 (실패 시 -1).
 */
long mgdb_channel_bump_stan(const char *bizdate)
{
    EXEC SQL BEGIN DECLARE SECTION;
    char h_bizdate[16];
    long h_chan_cnt = 0;
    long h_stan = 0;
    EXEC SQL END DECLARE SECTION;
    strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;

    EXEC SQL SELECT count(DISTINCT channel) INTO :h_chan_cnt
        FROM mg_msg_log WHERE biz_date = :h_bizdate;
    if (sqlca.sqlcode < 0) {
        userlog("mgdb_channel_bump_stan 활동채널 집계 FAIL [%d] %s",
                sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        return -1;
    }

    EXEC SQL SELECT nextval('mg_stan_seq') INTO :h_stan;
    if (sqlca.sqlcode < 0) {
        userlog("mgdb_channel_bump_stan STAN 채번 FAIL [%d] %s",
                sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        return -1;
    }

    userlog("mgdb_channel_bump_stan 영업일=%s 활동채널=%ld STAN=%ld",
            h_bizdate, h_chan_cnt, h_stan);
    return h_chan_cnt;
}
