/*
 * cm_param_dbio.pgc - 공통 파라미터/채번/공통로그 DB 접근 (part of libcmdbio.a).
 */
#include <string.h>
#include <userlog.h>
#include "cm_dbio.h"

int cmdb_get_param(const char *key, char *out)
{
    EXEC SQL BEGIN DECLARE SECTION;
    char h_key[64], h_val[128];
    EXEC SQL END DECLARE SECTION;

    strncpy(h_key, key, sizeof(h_key)-1); h_key[sizeof(h_key)-1] = 0;

    EXEC SQL SELECT param_val INTO :h_val FROM cm_param WHERE param_key = :h_key;
    if (sqlca.sqlcode == 100) { out[0] = 0; return -1; }
    if (sqlca.sqlcode < 0) {
        userlog("cmdb_get_param FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        return -1;
    }
    /* 실제 값 길이만 복사한다.
     * 기존 strncpy(out, h_val, 127) 은 값이 짧아도 남는 자리를 NUL 로 '채워 쓰기'
     * 때문에 항상 128바이트를 기록했다. 호출자 대부분은 hz_bizdate[16] 같은 작은
     * ecpg 호스트변수를 넘기므로(BIZ_DATE 조회 133곳) 매번 112바이트가 호출자
     * 스택을 넘어 파손시켰고, 인접 호스트변수(예: ccy)가 깨지거나 서버 카피가
     * SIGSEGV 로 죽었다. 서버 카피가 죽으면 호출자는 응답을 못 받고 트랜잭션
     * 타임아웃(60초, TPETIME)까지 블록된다 — 이번 웨이브가 잡는 장기블록의
     * 또 다른 원인이다. */
    {
        size_t vn = strlen(h_val);
        if (vn > 127) vn = 127;
        memcpy(out, h_val, vn);
        out[vn] = 0;
    }
    return 0;
}

int cmdb_set_param(const char *key, const char *val)
{
    EXEC SQL BEGIN DECLARE SECTION;
    char h_key[64], h_val[128];
    EXEC SQL END DECLARE SECTION;

    strncpy(h_key, key, sizeof(h_key)-1); h_key[sizeof(h_key)-1] = 0;
    strncpy(h_val, val, sizeof(h_val)-1); h_val[sizeof(h_val)-1] = 0;

    EXEC SQL INSERT INTO cm_param (param_key, param_val) VALUES (:h_key, :h_val)
        ON CONFLICT (param_key) DO UPDATE
        SET param_val = EXCLUDED.param_val, updated_at = now();
    if (sqlca.sqlcode < 0) {
        userlog("cmdb_set_param FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        return -1;
    }
    return 0;
}

/* cm_seq 이름있는 카운터를 원자적으로 +1 하고 새 값을 돌려준다. */
long cmdb_next_seq(const char *name)
{
    EXEC SQL BEGIN DECLARE SECTION;
    long h_val;
    char h_name[32];
    EXEC SQL END DECLARE SECTION;

    strncpy(h_name, name, sizeof(h_name)-1); h_name[sizeof(h_name)-1] = 0;

    EXEC SQL UPDATE cm_seq SET seq_val = seq_val + 1, updated_at = now()
        WHERE seq_name = :h_name;
    if (sqlca.sqlcode < 0) {
        userlog("cmdb_next_seq UPDATE FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        return -1;
    }
    if (sqlca.sqlcode == 100) {   /* 최초 사용: 행 생성 */
        EXEC SQL INSERT INTO cm_seq (seq_name, seq_val) VALUES (:h_name, 1);
        if (sqlca.sqlcode < 0) return -1;
        return 1;
    }
    EXEC SQL SELECT seq_val INTO :h_val FROM cm_seq WHERE seq_name = :h_name;
    if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) return -1;
    return h_val;
}

long cmdb_log(const char *svc, const char *level, const char *msg, const char *bizdate)
{
    EXEC SQL BEGIN DECLARE SECTION;
    long h_id;
    char h_svc[64], h_level[4], h_msg[256], h_bizdate[16];
    EXEC SQL END DECLARE SECTION;

    strncpy(h_svc, svc, sizeof(h_svc)-1);       h_svc[sizeof(h_svc)-1] = 0;
    strncpy(h_level, level, sizeof(h_level)-1); h_level[sizeof(h_level)-1] = 0;
    strncpy(h_msg, msg, sizeof(h_msg)-1);       h_msg[sizeof(h_msg)-1] = 0;
    strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;

    EXEC SQL SELECT nextval('cm_log_seq') INTO :h_id;
    if (sqlca.sqlcode < 0) return -1;

    EXEC SQL INSERT INTO cm_log (log_id, svc_name, log_level, msg, biz_date)
        VALUES (:h_id, :h_svc, :h_level, :h_msg, :h_bizdate);
    if (sqlca.sqlcode < 0) {
        userlog("cmdb_log FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
        return -1;
    }
    return h_id;
}
