Phase 2c: 전 11모듈 per-service 레거시 구조 분해·확장 (실동작 유지)

- 10개 모듈(au py rc st lg cl mm vl mg cm)을 ac 템플릿대로 분해:
  svc/ 30 서비스 .pgc + 카피북 .h, 얇은 <mod>_svr 디스패처
  dbio/ ~25 .pgc(+.h), batch/ ~17 .pgc, run/ ~17 .sh (모듈마다)
- 파일: svc 330 + dbio 276 + batch 187 + run 187, 총 소스 1602본
- 서비스별 고유 실로직(정규화 md5), build.sh 자동발견(inline/split 양립)
- 통합 검증: build DONE modules=11 servers=11 batches=187, 12서버 runok,
  333 서비스 AVAIL, 매입체인 XA 커밋(status=S), prepared_xacts=0

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
forge-bot 2026-07-19 11:58:44 +00:00
parent c3b99a8b75
commit fd8b418c6e
1404 changed files with 30322 additions and 5994 deletions

View file

@ -0,0 +1,37 @@
/*
* mg_amount_batch.pgc - mg 모듈 건수+금액 단건 집계 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction; 건수+금액 단건 집계; then tpcommit drives XA 2PC.
* Usage: mg_amount_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mg_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_cnt = 0, h_sum = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT count(*), coalesce(sum(amount),0) INTO :h_cnt, :h_sum
FROM mg_msg_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mg_amount_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mg_amount_batch COMMIT: bizdate=%s rows=%ld sum=%ld\n", bizdate, h_cnt, h_sum);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,46 @@
/*
* mg_chanacc_batch.pgc - mg 모듈 커서 누적 합계 (행별 DML 없음) 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction; 커서 누적 합계 (행별 DML 없음); then tpcommit drives XA 2PC.
* Usage: mg_chanacc_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mg_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16], h_key[32];
long h_amt = 0, total = 0, rows = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL DECLARE bc CURSOR FOR
SELECT channel, coalesce(sum(amount),0) FROM mg_msg_log
WHERE biz_date = :h_bizdate GROUP BY channel;
EXEC SQL OPEN bc;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH bc INTO :h_key, :h_amt;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bc; tpabort(0); return 1; }
total += h_amt; rows++;
}
EXEC SQL CLOSE bc;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mg_chanacc_batch COMMIT: bizdate=%s groups=%ld total=%ld\n", bizdate, rows, total);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,49 @@
/*
* mg_chansnap_batch.pgc - mg 모듈 커서 순회 후 대상 테이블 행별 INSERT 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction; 커서 순회 후 대상 테이블 행별 INSERT; then tpcommit drives XA 2PC.
* Usage: mg_chansnap_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mg_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16], h_key[32];
long h_amt = 0, rows = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL DECLARE bc CURSOR FOR
SELECT channel, coalesce(sum(amount),0) FROM mg_msg_log
WHERE biz_date = :h_bizdate GROUP BY channel;
EXEC SQL OPEN bc;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH bc INTO :h_key, :h_amt;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bc; tpabort(0); return 1; }
EXEC SQL INSERT INTO mg_chan_snap (channel, biz_date, amt)
VALUES (:h_key, :h_bizdate, :h_amt);
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bc; tpabort(0); return 1; }
rows++;
}
EXEC SQL CLOSE bc;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mg_chansnap_batch COMMIT: bizdate=%s inserted=%ld\n", bizdate, rows);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,43 @@
/*
* mg_confirm_batch.pgc - mg 모듈 건수 확인 후 조건부 업데이트 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction; 건수 확인 후 조건부 업데이트; then tpcommit drives XA 2PC.
* Usage: mg_confirm_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mg_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_cnt = 0, h_upd = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT count(*) INTO :h_cnt FROM mg_queue
WHERE biz_date = :h_bizdate AND status = 'S';
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
if (h_cnt > 0) {
EXEC SQL UPDATE mg_queue SET status = 'C', updated_at = now()
WHERE biz_date = :h_bizdate AND status = 'S';
if (sqlca.sqlcode < 0) { fprintf(stderr, "mg_confirm_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
h_upd = sqlca.sqlerrd[2];
}
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mg_confirm_batch COMMIT: bizdate=%s pending=%ld updated=%ld\n", bizdate, h_cnt, h_upd);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,40 @@
/*
* mg_dirstat_batch.pgc - mg 모듈 3분류 CASE 집계 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction; 3분류 CASE 집계; then tpcommit drives XA 2PC.
* Usage: mg_dirstat_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mg_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_a = 0, h_b = 0, h_c = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT
coalesce(sum(CASE WHEN direction = 'IN' THEN 1 ELSE 0 END),0),
coalesce(sum(CASE WHEN direction = 'OUT' THEN 1 ELSE 0 END),0),
coalesce(sum(CASE WHEN direction = 'IN' THEN 1 ELSE 0 END),0)
INTO :h_a, :h_b, :h_c FROM mg_msg_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mg_dirstat_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mg_dirstat_batch COMMIT: bizdate=%s a=%ld b=%ld c=%ld\n", bizdate, h_a, h_b, h_c);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,36 @@
/*
* mg_distinct_batch.pgc - mg 모듈 고유값(distinct) 집계 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction; 고유값(distinct) 집계; then tpcommit drives XA 2PC.
* Usage: mg_distinct_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mg_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_d = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT count(DISTINCT channel) INTO :h_d FROM mg_msg_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mg_distinct_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mg_distinct_batch COMMIT: bizdate=%s distinct=%ld\n", bizdate, h_d);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,40 @@
/*
* mg_errbps_batch.pgc - mg 모듈 두 SELECT 비율(bps) 산출 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction; 두 SELECT 비율(bps) 산출; then tpcommit drives XA 2PC.
* Usage: mg_errbps_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mg_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_a = 0, h_b = 0, h_bps = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT count(*) INTO :h_a FROM mg_msg_log
WHERE biz_date = :h_bizdate AND status = 'N';
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
EXEC SQL SELECT count(*) INTO :h_b FROM mg_msg_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
h_bps = (h_b > 0) ? h_a * 10000 / h_b : 0;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mg_errbps_batch COMMIT: bizdate=%s hit=%ld total=%ld bps=%ld\n", bizdate, h_a, h_b, h_bps);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,38 @@
/*
* mg_join_batch.pgc - mg 모듈 조인 집계 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction; 조인 집계; then tpcommit drives XA 2PC.
* Usage: mg_join_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mg_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_v = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT coalesce(sum(a.amount),0) INTO :h_v
FROM mg_msg_log a JOIN mg_route b ON a.channel = b.channel
WHERE a.biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mg_join_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mg_join_batch COMMIT: bizdate=%s joined_sum=%ld\n", bizdate, h_v);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,40 @@
/*
* mg_marker_batch.pgc - mg 모듈 시퀀스 채번 + 마커 행 INSERT 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction; 시퀀스 채번 + 마커 행 INSERT; then tpcommit drives XA 2PC.
* Usage: mg_marker_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mg_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_id = 0, h_cnt = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT count(*) INTO :h_cnt FROM mg_msg_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
EXEC SQL SELECT nextval('mg_msg_seq') INTO :h_id;
if (sqlca.sqlcode < 0) { tpabort(0); return 1; }
EXEC SQL INSERT INTO mg_eod_mark (mark_id, biz_date, cnt) VALUES (:h_id, :h_bizdate, :h_cnt);
if (sqlca.sqlcode < 0) { fprintf(stderr, "mg_marker_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mg_marker_batch COMMIT: bizdate=%s mark_id=%ld cnt=%ld\n", bizdate, h_id, h_cnt);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,38 @@
/*
* mg_promote_batch.pgc - mg 모듈 상태 일괄 전이 업데이트 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction; 상태 일괄 전이 업데이트; then tpcommit drives XA 2PC.
* Usage: mg_promote_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mg_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_upd = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL UPDATE mg_queue SET status = 'Q', updated_at = now()
WHERE biz_date = :h_bizdate AND status = 'F';
if (sqlca.sqlcode < 0) { fprintf(stderr, "mg_promote_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
h_upd = sqlca.sqlerrd[2];
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mg_promote_batch COMMIT: bizdate=%s updated=%ld\n", bizdate, h_upd);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,38 @@
/*
* mg_prunequeue_batch.pgc - mg 모듈 서브셀렉트 IN 조건 삭제 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction; 서브셀렉트 IN 조건 삭제; then tpcommit drives XA 2PC.
* Usage: mg_prunequeue_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mg_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_del = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL DELETE FROM mg_queue
WHERE stan IN (SELECT stan FROM mg_msg_log WHERE biz_date = :h_bizdate AND status = 'N');
if (sqlca.sqlcode < 0) { fprintf(stderr, "mg_prunequeue_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
h_del = sqlca.sqlerrd[2];
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mg_prunequeue_batch COMMIT: bizdate=%s deleted=%ld\n", bizdate, h_del);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,37 @@
/*
* mg_purge_batch.pgc - mg 모듈 상태 조건 삭제 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction; 상태 조건 삭제; then tpcommit drives XA 2PC.
* Usage: mg_purge_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mg_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_del = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL DELETE FROM mg_queue WHERE biz_date = :h_bizdate AND status = 'S';
if (sqlca.sqlcode < 0) { fprintf(stderr, "mg_purge_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
h_del = sqlca.sqlerrd[2];
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mg_purge_batch COMMIT: bizdate=%s deleted=%ld\n", bizdate, h_del);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,39 @@
/*
* mg_rollup_batch.pgc - mg 모듈 INSERT ... SELECT 그룹 롤업 적재 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction; INSERT ... SELECT 그룹 롤업 적재; then tpcommit drives XA 2PC.
* Usage: mg_rollup_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mg_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_rows = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL INSERT INTO mg_chan_rollup (channel, biz_date, cnt, amt)
SELECT channel, biz_date, count(*), coalesce(sum(amount),0)
FROM mg_msg_log WHERE biz_date = :h_bizdate GROUP BY channel, biz_date;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mg_rollup_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
h_rows = sqlca.sqlerrd[2];
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mg_rollup_batch COMMIT: bizdate=%s rolled=%ld\n", bizdate, h_rows);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,36 @@
/*
* mg_scalar_batch.pgc - mg 모듈 스칼라 합계 집계 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction; 스칼라 합계 집계; then tpcommit drives XA 2PC.
* Usage: mg_scalar_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mg_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_v = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT coalesce(sum(amount),0) INTO :h_v FROM mg_msg_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mg_scalar_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mg_scalar_batch COMMIT: bizdate=%s total=%ld\n", bizdate, h_v);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,38 @@
/*
* mg_spread_batch.pgc - mg 모듈 최대-최소 스프레드 집계 배치 (XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction; 최대-최소 스프레드 집계; then tpcommit drives XA 2PC.
* Usage: mg_spread_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "mg_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_max = 0, h_min = 0, h_spread = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT coalesce(max(amount),0), coalesce(min(amount),0)
INTO :h_max, :h_min FROM mg_msg_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) { fprintf(stderr, "mg_spread_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
h_spread = h_max - h_min;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> mg_spread_batch COMMIT: bizdate=%s max=%ld min=%ld spread=%ld\n", bizdate, h_max, h_min, h_spread);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,12 @@
/*
* mg_amount_spread_dbio.h - mg DB copybook (mg_amount_spread_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_AMOUNT_SPREAD_DBIO_H
#define MG_AMOUNT_SPREAD_DBIO_H
/* 전문 금액 최대-최소 스프레드. */
long mgdb_msg_amount_spread(const char *bizdate);
#endif /* MG_AMOUNT_SPREAD_DBIO_H */

View file

@ -0,0 +1,21 @@
/*
* mg_amount_spread_dbio.pgc - mg 모듈 DB 접근 함수 (mg_amount_spread_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 전문 금액 최대-최소 스프레드.
*/
#include <string.h>
#include <userlog.h>
#include "mg_amount_spread_dbio.h"
long mgdb_msg_amount_spread(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_max = 0, h_min = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL SELECT coalesce(max(amount),0), coalesce(min(amount),0)
INTO :h_max, :h_min FROM mg_msg_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) return -1;
return h_max - h_min;
}

View file

@ -0,0 +1,12 @@
/*
* mg_avg_amount_dbio.h - mg DB copybook (mg_avg_amount_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_AVG_AMOUNT_DBIO_H
#define MG_AVG_AMOUNT_DBIO_H
/* 전문 건당 평균 금액. */
long mgdb_msg_avg_amount(const char *bizdate);
#endif /* MG_AVG_AMOUNT_DBIO_H */

View file

@ -0,0 +1,22 @@
/*
* mg_avg_amount_dbio.pgc - mg 모듈 DB 접근 함수 (mg_avg_amount_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 전문 건당 평균 금액.
*/
#include <string.h>
#include <userlog.h>
#include "mg_avg_amount_dbio.h"
long mgdb_msg_avg_amount(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_sum = 0, h_cnt = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL SELECT coalesce(sum(amount),0), count(*) INTO :h_sum, :h_cnt
FROM mg_msg_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) return -1;
if (h_cnt <= 0) return 0;
return h_sum / h_cnt;
}

View file

@ -0,0 +1,12 @@
/*
* mg_big_pct_dbio.h - mg DB copybook (mg_big_pct_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_BIG_PCT_DBIO_H
#define MG_BIG_PCT_DBIO_H
/* 고액 전문 비율(%). */
long mgdb_msg_big_pct(const char *bizdate);
#endif /* MG_BIG_PCT_DBIO_H */

View file

@ -0,0 +1,22 @@
/*
* mg_big_pct_dbio.pgc - mg 모듈 DB 접근 함수 (mg_big_pct_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 고액 전문 비율(%).
*/
#include <string.h>
#include <userlog.h>
#include "mg_big_pct_dbio.h"
long mgdb_msg_big_pct(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_hi = 0, h_all = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL SELECT coalesce(sum(CASE WHEN amount > 1000000 THEN 1 ELSE 0 END),0), count(*)
INTO :h_hi, :h_all FROM mg_msg_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) return -1;
if (h_all <= 0) return 0;
return h_hi * 100 / h_all;
}

View file

@ -0,0 +1,12 @@
/*
* mg_bump_stan_dbio.h - mg DB copybook (mg_bump_stan_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_BUMP_STAN_DBIO_H
#define MG_BUMP_STAN_DBIO_H
/* 활동 채널 last_stan 증가. */
long mgdb_channel_bump_stan(const char *bizdate);
#endif /* MG_BUMP_STAN_DBIO_H */

View file

@ -0,0 +1,20 @@
/*
* 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"
long mgdb_channel_bump_stan(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL UPDATE mg_channel SET last_stan = last_stan + 1
WHERE channel IN (SELECT channel 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; }
return sqlca.sqlerrd[2];
}

View file

@ -0,0 +1,12 @@
/*
* mg_chan_sum_dbio.h - mg DB copybook (mg_chan_sum_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_CHAN_SUM_DBIO_H
#define MG_CHAN_SUM_DBIO_H
/* 채널 그룹 금액 커서 누적. */
long mgdb_msg_chan_sum(const char *bizdate);
#endif /* MG_CHAN_SUM_DBIO_H */

View file

@ -0,0 +1,30 @@
/*
* mg_chan_sum_dbio.pgc - mg 모듈 DB 접근 함수 (mg_chan_sum_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 채널 그룹 금액 커서 누적.
*/
#include <string.h>
#include <userlog.h>
#include "mg_chan_sum_dbio.h"
long mgdb_msg_chan_sum(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16], h_key[32];
long h_amt = 0, total = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL DECLARE qc CURSOR FOR
SELECT channel, coalesce(sum(amount),0) FROM mg_msg_log
WHERE biz_date = :h_bizdate GROUP BY channel;
EXEC SQL OPEN qc;
if (sqlca.sqlcode < 0) { userlog("mgdb_msg_chan_sum OPEN [%d]", sqlca.sqlcode); return -1; }
for (;;) {
EXEC SQL FETCH qc INTO :h_key, :h_amt;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE qc; return -1; }
total += h_amt;
}
EXEC SQL CLOSE qc;
return total;
}

View file

@ -0,0 +1,12 @@
/*
* mg_channel_up_dbio.h - mg DB copybook (mg_channel_up_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_CHANNEL_UP_DBIO_H
#define MG_CHANNEL_UP_DBIO_H
/* 채널 UP 상태 여부. */
int mgdb_channel_is_up(const char *key);
#endif /* MG_CHANNEL_UP_DBIO_H */

View file

@ -0,0 +1,21 @@
/*
* mg_channel_up_dbio.pgc - mg 모듈 DB 접근 함수 (mg_channel_up_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 채널 UP 상태 여부.
*/
#include <string.h>
#include <userlog.h>
#include "mg_channel_up_dbio.h"
int mgdb_channel_is_up(const char *key)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_key[32], h_st[16];
EXEC SQL END DECLARE SECTION;
strncpy(h_key, key, sizeof(h_key)-1); h_key[sizeof(h_key)-1] = 0;
EXEC SQL SELECT status INTO :h_st FROM mg_channel WHERE channel = :h_key;
if (sqlca.sqlcode == 100) return -1;
if (sqlca.sqlcode < 0) return -1;
if (strcmp(h_st, "UP") == 0) return 1;
return 0;
}

View file

@ -38,4 +38,30 @@ int mgdb_enqueue(long queue_id, long stan, const char *channel, const char *mti
const char *payload, const char *bizdate);
int mgdb_set_queue_status(long queue_id, const char *status);
/* ----- expanded query/analytics dbio (each in its own mg_*_dbio.pgc) ----- */
long mgdb_msg_amount_sum(const char *bizdate); /* 당일 전문 금액 합계. */
long mgdb_queue_backlog(const char *status); /* 상태별 큐 적체 건수. */
long mgdb_msg_amount_spread(const char *bizdate); /* 전문 금액 최대-최소 스프레드. */
long mgdb_msg_err_ratio(const char *bizdate); /* 오류 전문 비율(bps). */
long mgdb_msg_chan_sum(const char *bizdate); /* 채널 그룹 금액 커서 누적. */
long mgdb_msg_avg_amount(const char *bizdate); /* 전문 건당 평균 금액. */
long mgdb_msg_inbound_amount(const char *bizdate); /* 수신(IN) 전문 금액 합계. */
long mgdb_queue_purge_sent(const char *bizdate); /* 송신완료(S) 큐 정리 삭제. */
long mgdb_queue_mark_stale(const char *bizdate); /* 대기(Q) 오래된 큐 실패(F) 전이. */
int mgdb_route_channel_exists(const char *key); /* 채널 라우팅 존재 여부. */
int mgdb_queue_payload(long id, char *out); /* 큐 ID 페이로드 조회. */
long mgdb_queue_weighted(const char *bizdate); /* STAN x 재시도수 가중 합. */
long mgdb_msg_peak_count(const char *bizdate); /* 최고 금액 전문 건수. */
long mgdb_msg_pan_like(const char *pat); /* PAN 접두 패턴 전문 건수. */
long mgdb_msg_distinct_chan(const char *bizdate); /* 당일 고유 채널 수. */
long mgdb_msg_routed_amount(const char *bizdate); /* 라우팅 매칭 전문 금액(조인). */
long mgdb_msg_min_amount(const char *bizdate); /* 당일 최소 전문 금액. */
long mgdb_msg_big_pct(const char *bizdate); /* 고액 전문 비율(%). */
int mgdb_channel_is_up(const char *key); /* 채널 UP 상태 여부. */
long mgdb_channel_bump_stan(const char *bizdate); /* 활동 채널 last_stan 증가. */
long mgdb_msg_insert_marker(const char *bizdate, long amount); /* 마커 전문 채번 후 적재. */
long mgdb_queue_load(const char *bizdate); /* 큐 STAN+재시도 합산 부하지표. */
long mgdb_msg_positive_count(const char *bizdate); /* 금액>0 전문 건수(커서). */
#endif /* MG_DBIO_H */

View file

@ -0,0 +1,12 @@
/*
* mg_distinct_chan_dbio.h - mg DB copybook (mg_distinct_chan_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_DISTINCT_CHAN_DBIO_H
#define MG_DISTINCT_CHAN_DBIO_H
/* 당일 고유 채널 수. */
long mgdb_msg_distinct_chan(const char *bizdate);
#endif /* MG_DISTINCT_CHAN_DBIO_H */

View file

@ -0,0 +1,20 @@
/*
* mg_distinct_chan_dbio.pgc - mg 모듈 DB 접근 함수 (mg_distinct_chan_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 당일 고유 채널 수.
*/
#include <string.h>
#include <userlog.h>
#include "mg_distinct_chan_dbio.h"
long mgdb_msg_distinct_chan(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_v = 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_v FROM mg_msg_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) return -1;
return h_v;
}

View file

@ -0,0 +1,12 @@
/*
* mg_err_ratio_dbio.h - mg DB copybook (mg_err_ratio_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_ERR_RATIO_DBIO_H
#define MG_ERR_RATIO_DBIO_H
/* 오류 전문 비율(bps). */
long mgdb_msg_err_ratio(const char *bizdate);
#endif /* MG_ERR_RATIO_DBIO_H */

View file

@ -0,0 +1,23 @@
/*
* mg_err_ratio_dbio.pgc - mg 모듈 DB 접근 함수 (mg_err_ratio_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 오류 전문 비율(bps).
*/
#include <string.h>
#include <userlog.h>
#include "mg_err_ratio_dbio.h"
long mgdb_msg_err_ratio(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_a = 0, h_b = 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(*) INTO :h_a FROM mg_msg_log WHERE biz_date = :h_bizdate AND status = 'N';
if (sqlca.sqlcode < 0) return -1;
EXEC SQL SELECT count(*) INTO :h_b FROM mg_msg_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) return -1;
if (h_b <= 0) return 0;
return h_a * 10000 / h_b;
}

View file

@ -0,0 +1,12 @@
/*
* mg_inbound_amt_dbio.h - mg DB copybook (mg_inbound_amt_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_INBOUND_AMT_DBIO_H
#define MG_INBOUND_AMT_DBIO_H
/* 수신(IN) 전문 금액 합계. */
long mgdb_msg_inbound_amount(const char *bizdate);
#endif /* MG_INBOUND_AMT_DBIO_H */

View file

@ -0,0 +1,21 @@
/*
* mg_inbound_amt_dbio.pgc - mg 모듈 DB 접근 함수 (mg_inbound_amt_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 수신(IN) 전문 금액 합계.
*/
#include <string.h>
#include <userlog.h>
#include "mg_inbound_amt_dbio.h"
long mgdb_msg_inbound_amount(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_v = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL SELECT coalesce(sum(CASE WHEN direction = 'IN' THEN amount ELSE 0 END),0)
INTO :h_v FROM mg_msg_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) return -1;
return h_v;
}

View file

@ -0,0 +1,12 @@
/*
* mg_insert_mark_dbio.h - mg DB copybook (mg_insert_mark_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_INSERT_MARK_DBIO_H
#define MG_INSERT_MARK_DBIO_H
/* 마커 전문 채번 후 적재. */
long mgdb_msg_insert_marker(const char *bizdate, long amount);
#endif /* MG_INSERT_MARK_DBIO_H */

View file

@ -0,0 +1,23 @@
/*
* mg_insert_mark_dbio.pgc - mg 모듈 DB 접근 함수 (mg_insert_mark_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 마커 전문 채번 후 적재.
*/
#include <string.h>
#include <userlog.h>
#include "mg_insert_mark_dbio.h"
long mgdb_msg_insert_marker(const char *bizdate, long amount)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_id = 0, h_amt = amount;
char h_bizdate[16];
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL SELECT nextval('mg_msg_seq') INTO :h_id;
if (sqlca.sqlcode < 0) return -1;
EXEC SQL INSERT INTO mg_msg_log (msg_id, amount, biz_date)
VALUES (:h_id, :h_amt, :h_bizdate);
if (sqlca.sqlcode < 0) { userlog("mgdb_msg_insert_marker FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); return -1; }
return h_id;
}

View file

@ -0,0 +1,12 @@
/*
* mg_min_amount_dbio.h - mg DB copybook (mg_min_amount_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_MIN_AMOUNT_DBIO_H
#define MG_MIN_AMOUNT_DBIO_H
/* 당일 최소 전문 금액. */
long mgdb_msg_min_amount(const char *bizdate);
#endif /* MG_MIN_AMOUNT_DBIO_H */

View file

@ -0,0 +1,21 @@
/*
* mg_min_amount_dbio.pgc - mg 모듈 DB 접근 함수 (mg_min_amount_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 당일 최소 전문 금액.
*/
#include <string.h>
#include <userlog.h>
#include "mg_min_amount_dbio.h"
long mgdb_msg_min_amount(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_v = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL SELECT min(amount) INTO :h_v FROM mg_msg_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode == 100) return 0;
if (sqlca.sqlcode < 0) { userlog("mgdb_msg_min_amount FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); return -1; }
return h_v;
}

View file

@ -0,0 +1,12 @@
/*
* mg_msg_amount_dbio.h - mg DB copybook (mg_msg_amount_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_MSG_AMOUNT_DBIO_H
#define MG_MSG_AMOUNT_DBIO_H
/* 당일 전문 금액 합계. */
long mgdb_msg_amount_sum(const char *bizdate);
#endif /* MG_MSG_AMOUNT_DBIO_H */

View file

@ -0,0 +1,20 @@
/*
* mg_msg_amount_dbio.pgc - mg 모듈 DB 접근 함수 (mg_msg_amount_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 당일 전문 금액 합계.
*/
#include <string.h>
#include <userlog.h>
#include "mg_msg_amount_dbio.h"
long mgdb_msg_amount_sum(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_v = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL SELECT coalesce(sum(amount),0) INTO :h_v FROM mg_msg_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) { userlog("mgdb_msg_amount_sum FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); return -1; }
return h_v;
}

View file

@ -0,0 +1,12 @@
/*
* mg_pan_like_dbio.h - mg DB copybook (mg_pan_like_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_PAN_LIKE_DBIO_H
#define MG_PAN_LIKE_DBIO_H
/* PAN 접두 패턴 전문 건수. */
long mgdb_msg_pan_like(const char *pat);
#endif /* MG_PAN_LIKE_DBIO_H */

View file

@ -0,0 +1,20 @@
/*
* mg_pan_like_dbio.pgc - mg 모듈 DB 접근 함수 (mg_pan_like_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* PAN 접두 패턴 전문 건수.
*/
#include <string.h>
#include <userlog.h>
#include "mg_pan_like_dbio.h"
long mgdb_msg_pan_like(const char *pat)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_pat[64];
long h_v = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_pat, pat, sizeof(h_pat)-1); h_pat[sizeof(h_pat)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_v FROM mg_msg_log WHERE pan LIKE :h_pat;
if (sqlca.sqlcode < 0) return -1;
return h_v;
}

View file

@ -0,0 +1,12 @@
/*
* mg_peak_count_dbio.h - mg DB copybook (mg_peak_count_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_PEAK_COUNT_DBIO_H
#define MG_PEAK_COUNT_DBIO_H
/* 최고 금액 전문 건수. */
long mgdb_msg_peak_count(const char *bizdate);
#endif /* MG_PEAK_COUNT_DBIO_H */

View file

@ -0,0 +1,23 @@
/*
* mg_peak_count_dbio.pgc - mg 모듈 DB 접근 함수 (mg_peak_count_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 최고 금액 전문 건수.
*/
#include <string.h>
#include <userlog.h>
#include "mg_peak_count_dbio.h"
long mgdb_msg_peak_count(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_peak = 0, h_cnt = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL SELECT coalesce(max(amount),0) INTO :h_peak FROM mg_msg_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) return -1;
EXEC SQL SELECT count(*) INTO :h_cnt FROM mg_msg_log
WHERE biz_date = :h_bizdate AND amount = :h_peak;
if (sqlca.sqlcode < 0) return -1;
return h_cnt;
}

View file

@ -0,0 +1,12 @@
/*
* mg_pos_count_dbio.h - mg DB copybook (mg_pos_count_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_POS_COUNT_DBIO_H
#define MG_POS_COUNT_DBIO_H
/* 금액>0 전문 건수(커서). */
long mgdb_msg_positive_count(const char *bizdate);
#endif /* MG_POS_COUNT_DBIO_H */

View file

@ -0,0 +1,29 @@
/*
* mg_pos_count_dbio.pgc - mg 모듈 DB 접근 함수 (mg_pos_count_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 금액>0 전문 건수(커서).
*/
#include <string.h>
#include <userlog.h>
#include "mg_pos_count_dbio.h"
long mgdb_msg_positive_count(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_x = 0, k = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL DECLARE qc CURSOR FOR
SELECT amount FROM mg_msg_log WHERE biz_date = :h_bizdate;
EXEC SQL OPEN qc;
if (sqlca.sqlcode < 0) return -1;
for (;;) {
EXEC SQL FETCH qc INTO :h_x;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE qc; return -1; }
if (h_x > 0) k++;
}
EXEC SQL CLOSE qc;
return k;
}

View file

@ -0,0 +1,12 @@
/*
* mg_queue_backlog_dbio.h - mg DB copybook (mg_queue_backlog_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_QUEUE_BACKLOG_DBIO_H
#define MG_QUEUE_BACKLOG_DBIO_H
/* 상태별 큐 적체 건수. */
long mgdb_queue_backlog(const char *status);
#endif /* MG_QUEUE_BACKLOG_DBIO_H */

View file

@ -0,0 +1,20 @@
/*
* mg_queue_backlog_dbio.pgc - mg 모듈 DB 접근 함수 (mg_queue_backlog_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 상태별 큐 적체 건수.
*/
#include <string.h>
#include <userlog.h>
#include "mg_queue_backlog_dbio.h"
long mgdb_queue_backlog(const char *status)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_st[16];
long h_v = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_st, status, sizeof(h_st)-1); h_st[sizeof(h_st)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_v FROM mg_queue WHERE status = :h_st;
if (sqlca.sqlcode < 0) { userlog("mgdb_queue_backlog FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); return -1; }
return h_v;
}

View file

@ -0,0 +1,12 @@
/*
* mg_queue_load_dbio.h - mg DB copybook (mg_queue_load_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_QUEUE_LOAD_DBIO_H
#define MG_QUEUE_LOAD_DBIO_H
/* 큐 STAN+재시도 합산 부하지표. */
long mgdb_queue_load(const char *bizdate);
#endif /* MG_QUEUE_LOAD_DBIO_H */

View file

@ -0,0 +1,21 @@
/*
* mg_queue_load_dbio.pgc - mg 모듈 DB 접근 함수 (mg_queue_load_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 큐 STAN+재시도 합산 부하지표.
*/
#include <string.h>
#include <userlog.h>
#include "mg_queue_load_dbio.h"
long mgdb_queue_load(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_v = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL SELECT coalesce(sum(stan),0) + coalesce(sum(retry_cnt),0) INTO :h_v
FROM mg_queue WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) return -1;
return h_v;
}

View file

@ -0,0 +1,12 @@
/*
* mg_queue_payload_dbio.h - mg DB copybook (mg_queue_payload_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_QUEUE_PAYLOAD_DBIO_H
#define MG_QUEUE_PAYLOAD_DBIO_H
/* 큐 ID 페이로드 조회. */
int mgdb_queue_payload(long id, char *out);
#endif /* MG_QUEUE_PAYLOAD_DBIO_H */

View file

@ -0,0 +1,21 @@
/*
* mg_queue_payload_dbio.pgc - mg 모듈 DB 접근 함수 (mg_queue_payload_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 큐 ID 페이로드 조회.
*/
#include <string.h>
#include <userlog.h>
#include "mg_queue_payload_dbio.h"
int mgdb_queue_payload(long id, char *out)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_id = id;
char h_s[64];
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT payload INTO :h_s FROM mg_queue WHERE queue_id = :h_id;
if (sqlca.sqlcode == 100) { out[0] = 0; return -1; }
if (sqlca.sqlcode < 0) { userlog("mgdb_queue_payload FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); return -1; }
strncpy(out, h_s, 63); out[63] = 0;
return 0;
}

View file

@ -0,0 +1,12 @@
/*
* mg_queue_purge_dbio.h - mg DB copybook (mg_queue_purge_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_QUEUE_PURGE_DBIO_H
#define MG_QUEUE_PURGE_DBIO_H
/* 송신완료(S) 큐 정리 삭제. */
long mgdb_queue_purge_sent(const char *bizdate);
#endif /* MG_QUEUE_PURGE_DBIO_H */

View file

@ -0,0 +1,19 @@
/*
* mg_queue_purge_dbio.pgc - mg 모듈 DB 접근 함수 (mg_queue_purge_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 송신완료(S) 큐 정리 삭제.
*/
#include <string.h>
#include <userlog.h>
#include "mg_queue_purge_dbio.h"
long mgdb_queue_purge_sent(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL DELETE FROM mg_queue WHERE biz_date = :h_bizdate AND status = 'S';
if (sqlca.sqlcode < 0) { userlog("mgdb_queue_purge_sent FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); return -1; }
return sqlca.sqlerrd[2];
}

View file

@ -0,0 +1,12 @@
/*
* mg_queue_stale_dbio.h - mg DB copybook (mg_queue_stale_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_QUEUE_STALE_DBIO_H
#define MG_QUEUE_STALE_DBIO_H
/* 대기(Q) 오래된 큐 실패(F) 전이. */
long mgdb_queue_mark_stale(const char *bizdate);
#endif /* MG_QUEUE_STALE_DBIO_H */

View file

@ -0,0 +1,20 @@
/*
* mg_queue_stale_dbio.pgc - mg 모듈 DB 접근 함수 (mg_queue_stale_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 대기(Q) 오래된 큐 실패(F) 전이.
*/
#include <string.h>
#include <userlog.h>
#include "mg_queue_stale_dbio.h"
long mgdb_queue_mark_stale(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL UPDATE mg_queue SET status = 'F', updated_at = now()
WHERE biz_date = :h_bizdate AND status = 'Q';
if (sqlca.sqlcode < 0) { userlog("mgdb_queue_mark_stale FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); return -1; }
return sqlca.sqlerrd[2];
}

View file

@ -0,0 +1,12 @@
/*
* mg_queue_weight_dbio.h - mg DB copybook (mg_queue_weight_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_QUEUE_WEIGHT_DBIO_H
#define MG_QUEUE_WEIGHT_DBIO_H
/* STAN x 재시도수 가중 합. */
long mgdb_queue_weighted(const char *bizdate);
#endif /* MG_QUEUE_WEIGHT_DBIO_H */

View file

@ -0,0 +1,29 @@
/*
* mg_queue_weight_dbio.pgc - mg 모듈 DB 접근 함수 (mg_queue_weight_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* STAN x 재시도수 가중 합.
*/
#include <string.h>
#include <userlog.h>
#include "mg_queue_weight_dbio.h"
long mgdb_queue_weighted(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_a = 0, h_b = 0, acc = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL DECLARE qc CURSOR FOR
SELECT stan, retry_cnt FROM mg_queue WHERE biz_date = :h_bizdate;
EXEC SQL OPEN qc;
if (sqlca.sqlcode < 0) return -1;
for (;;) {
EXEC SQL FETCH qc INTO :h_a, :h_b;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE qc; return -1; }
acc += h_a * h_b;
}
EXEC SQL CLOSE qc;
return acc;
}

View file

@ -0,0 +1,12 @@
/*
* mg_route_exists_dbio.h - mg DB copybook (mg_route_exists_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_ROUTE_EXISTS_DBIO_H
#define MG_ROUTE_EXISTS_DBIO_H
/* 채널 라우팅 존재 여부. */
int mgdb_route_channel_exists(const char *key);
#endif /* MG_ROUTE_EXISTS_DBIO_H */

View file

@ -0,0 +1,20 @@
/*
* mg_route_exists_dbio.pgc - mg 모듈 DB 접근 함수 (mg_route_exists_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 채널 라우팅 존재 여부.
*/
#include <string.h>
#include <userlog.h>
#include "mg_route_exists_dbio.h"
int mgdb_route_channel_exists(const char *key)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_key[64];
long h_v = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_key, key, sizeof(h_key)-1); h_key[sizeof(h_key)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_v FROM mg_route WHERE channel = :h_key;
if (sqlca.sqlcode < 0) return -1;
return h_v > 0 ? 1 : 0;
}

View file

@ -0,0 +1,12 @@
/*
* mg_routed_amt_dbio.h - mg DB copybook (mg_routed_amt_dbio, part of libmgdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef MG_ROUTED_AMT_DBIO_H
#define MG_ROUTED_AMT_DBIO_H
/* 라우팅 매칭 전문 금액(조인). */
long mgdb_msg_routed_amount(const char *bizdate);
#endif /* MG_ROUTED_AMT_DBIO_H */

View file

@ -0,0 +1,22 @@
/*
* mg_routed_amt_dbio.pgc - mg 모듈 DB 접근 함수 (mg_routed_amt_dbio), archived into libmgdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* 라우팅 매칭 전문 금액(조인).
*/
#include <string.h>
#include <userlog.h>
#include "mg_routed_amt_dbio.h"
long mgdb_msg_routed_amount(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_v = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL SELECT coalesce(sum(a.amount),0) INTO :h_v
FROM mg_msg_log a JOIN mg_route b ON a.channel = b.channel
WHERE a.biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) return -1;
return h_v;
}

View file

@ -1,70 +1,72 @@
/*
* mg_svr.pgc - mg (전문게이트웨이 / message gateway) MODULE SERVER.
* mg_svr.pgc - mg (전문게이트웨이 / message gateway) MODULE SERVER (thin dispatcher).
*
* ONE binary that tpadvertise()s ALL ~30 online mg services (the real Tuxedo
* "one module server, many services" pattern). Every service is a distinct 전문
* (ISO8583) gateway operation with genuine EXEC SQL (directly, or via the linked
* libmgdbio.a dbio layer) plus 고정길이/비트맵 pack/unpack idioms and STAN 채번
* via a Postgres sequence.
* The legacy "one module server, many services" pattern: this binary owns NO
* business logic. Each of mg's 30 online services now lives in its own file
* (app/src/mg/svc/<SVCNAME>.pgc) with its own copybook header
* (app/src/mg/svc/<SVCNAME>.h); those objects are archived into libmgsvc.a
* and linked into this server. Here we only:
* - include every service copybook (for the extern prototypes),
* - tpopen() the ECPG XA RM,
* - tpadvertise() all 30 services from a {name, fn} table,
* - tpclose() at shutdown.
*
* XA: the connection is opened once by tpopen() (ECPG XA switch libndrxxaecpg.so);
* there is NO EXEC SQL CONNECT. Each tpcall runs on this process's XA branch.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include <ubf.h>
#include <userlog.h>
#include <ndebug.h>
#include "acq.fd.h"
#include "mg_dbio.h"
#include "acq_common.h"
/* ----- small UBF helpers ------------------------------------------------- */
static long getl(UBFH *b, BFLDID f) { long v = 0; Bget(b, f, 0, (char *)&v, 0L); return v; }
static void gets_(UBFH *b, BFLDID f, char *out, int cap)
{ BFLDLEN l = cap; out[0] = 0; Bget(b, f, 0, out, &l); }
static void setl(UBFH *b, BFLDID f, long v) { Bchg(b, f, 0, (char *)&v, 0L); }
static void sets_(UBFH *b, BFLDID f, const char *s) { Bchg(b, f, 0, (char *)s, 0L); }
/* every mg service's copybook header (declares its prototype) */
#include "MG_RECV.h"
#include "MG_SEND.h"
#include "MG_ISO8583.h"
#include "MG_BITMAP.h"
#include "MG_STAN.h"
#include "MG_ROUTE.h"
#include "MG_RESEND.h"
#include "MG_CONVERT.h"
#include "MG_ERRMSG.h"
#include "MG_LOG.h"
#include "MG_CHANAUTH.h"
#include "MG_SESSION.h"
#include "MG_ACK.h"
#include "MG_NACK.h"
#include "MG_ECHO.h"
#include "MG_HEALTH.h"
#include "MG_SIGNON.h"
#include "MG_SIGNOFF.h"
#include "MG_KEYEXCH.h"
#include "MG_MAC.h"
#include "MG_PARSE.h"
#include "MG_PACK.h"
#include "MG_UNPACK.h"
#include "MG_QUEUE.h"
#include "MG_DEQUEUE.h"
#include "MG_RETRY.h"
#include "MG_STATS.h"
#include "MG_CHANSTAT.h"
#include "MG_STATUS.h"
#include "MG_CONFIRM.h"
#define FAIL(b) do { tpreturn(TPFAIL, 0, (char *)(b), 0L, 0L); return; } while (0)
#define OK(b) do { tpreturn(TPSUCCESS, 0, (char *)(b), 0L, 0L); return; } while (0)
/* ----- service prototypes ------------------------------------------------ */
void MG_RECV(TPSVCINFO *p); void MG_SEND(TPSVCINFO *p);
void MG_ISO8583(TPSVCINFO *p); void MG_BITMAP(TPSVCINFO *p);
void MG_STAN(TPSVCINFO *p); void MG_ROUTE(TPSVCINFO *p);
void MG_RESEND(TPSVCINFO *p); void MG_CONVERT(TPSVCINFO *p);
void MG_ERRMSG(TPSVCINFO *p); void MG_LOG(TPSVCINFO *p);
void MG_CHANAUTH(TPSVCINFO *p); void MG_SESSION(TPSVCINFO *p);
void MG_ACK(TPSVCINFO *p); void MG_NACK(TPSVCINFO *p);
void MG_ECHO(TPSVCINFO *p); void MG_HEALTH(TPSVCINFO *p);
void MG_SIGNON(TPSVCINFO *p); void MG_SIGNOFF(TPSVCINFO *p);
void MG_KEYEXCH(TPSVCINFO *p); void MG_MAC(TPSVCINFO *p);
void MG_PARSE(TPSVCINFO *p); void MG_PACK(TPSVCINFO *p);
void MG_UNPACK(TPSVCINFO *p); void MG_QUEUE(TPSVCINFO *p);
void MG_DEQUEUE(TPSVCINFO *p); void MG_RETRY(TPSVCINFO *p);
void MG_STATS(TPSVCINFO *p); void MG_CHANSTAT(TPSVCINFO *p);
void MG_STATUS(TPSVCINFO *p); void MG_CONFIRM(TPSVCINFO *p);
/* ----- advertise table (this is what "scales to 30" cleanly) ------------- */
/* ----- advertise table: {service name, function} (fn is extern from its file) */
static struct { const char *name; void (*fn)(TPSVCINFO *); } SVCS[] = {
{"MG_RECV", MG_RECV}, {"MG_SEND", MG_SEND},
{"MG_ISO8583", MG_ISO8583}, {"MG_BITMAP", MG_BITMAP},
{"MG_STAN", MG_STAN}, {"MG_ROUTE", MG_ROUTE},
{"MG_RESEND", MG_RESEND}, {"MG_CONVERT", MG_CONVERT},
{"MG_ERRMSG", MG_ERRMSG}, {"MG_LOG", MG_LOG},
{"MG_CHANAUTH", MG_CHANAUTH}, {"MG_SESSION", MG_SESSION},
{"MG_ACK", MG_ACK}, {"MG_NACK", MG_NACK},
{"MG_ECHO", MG_ECHO}, {"MG_HEALTH", MG_HEALTH},
{"MG_SIGNON", MG_SIGNON}, {"MG_SIGNOFF", MG_SIGNOFF},
{"MG_KEYEXCH", MG_KEYEXCH}, {"MG_MAC", MG_MAC},
{"MG_PARSE", MG_PARSE}, {"MG_PACK", MG_PACK},
{"MG_UNPACK", MG_UNPACK}, {"MG_QUEUE", MG_QUEUE},
{"MG_DEQUEUE", MG_DEQUEUE}, {"MG_RETRY", MG_RETRY},
{"MG_STATS", MG_STATS}, {"MG_CHANSTAT", MG_CHANSTAT},
{"MG_STATUS", MG_STATUS}, {"MG_CONFIRM", MG_CONFIRM},
{"MG_RECV", MG_RECV}, {"MG_SEND", MG_SEND},
{"MG_ISO8583", MG_ISO8583}, {"MG_BITMAP", MG_BITMAP},
{"MG_STAN", MG_STAN}, {"MG_ROUTE", MG_ROUTE},
{"MG_RESEND", MG_RESEND}, {"MG_CONVERT", MG_CONVERT},
{"MG_ERRMSG", MG_ERRMSG}, {"MG_LOG", MG_LOG},
{"MG_CHANAUTH", MG_CHANAUTH}, {"MG_SESSION", MG_SESSION},
{"MG_ACK", MG_ACK}, {"MG_NACK", MG_NACK},
{"MG_ECHO", MG_ECHO}, {"MG_HEALTH", MG_HEALTH},
{"MG_SIGNON", MG_SIGNON}, {"MG_SIGNOFF", MG_SIGNOFF},
{"MG_KEYEXCH", MG_KEYEXCH}, {"MG_MAC", MG_MAC},
{"MG_PARSE", MG_PARSE}, {"MG_PACK", MG_PACK},
{"MG_UNPACK", MG_UNPACK}, {"MG_QUEUE", MG_QUEUE},
{"MG_DEQUEUE", MG_DEQUEUE}, {"MG_RETRY", MG_RETRY},
{"MG_STATS", MG_STATS}, {"MG_CHANSTAT", MG_CHANSTAT},
{"MG_STATUS", MG_STATUS}, {"MG_CONFIRM", MG_CONFIRM},
{NULL, NULL}
};
@ -91,559 +93,4 @@ void tpsvrdone(void)
userlog("mg_svr: tpsvrdone");
}
/* ----- module-local pure helpers (고정길이/비트맵/체크섬) ----------------- */
/* 16-hex primary bitmap from a 64-bit field-present mask. */
static void mg_bitmap_hex(unsigned long mask, char *out /* >= 17 */)
{
sprintf(out, "%016lX", mask);
}
/* simple additive 4-hex MAC/checksum over a buffer (전문 무결성 데모). */
static void mg_checksum(const char *s, char *out /* >= 5 */)
{
unsigned int sum = 0; int i;
for (i = 0; s[i]; i++) sum = (sum + (unsigned char)s[i] * 31u) & 0xFFFF;
sprintf(out, "%04X", sum);
}
/* ========================================================================= */
/* 1. MG_RECV - 전문 수신 접수 (direction=IN). STAN 채번 후 로그 적재. */
/* ========================================================================= */
void MG_RECV(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], mti[8], raw[512], bizdate[16], pan[24];
long stan, msg_id, amount;
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
gets_(b, T_STR1, mti, sizeof(mti)); if (mti[0] == 0) strcpy(mti, "0200");
gets_(b, T_STR3, raw, sizeof(raw));
gets_(b, T_STR5, pan, sizeof(pan));
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
amount = getl(b, T_AMOUNT);
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
if (mgdb_insert_msg(msg_id, stan, mti, chan, "IN", "000000", "", amount,
pan, "00", raw, "R", bizdate) < 0) FAIL(b);
setl(b, T_ARG1, stan);
setl(b, T_ID1, msg_id);
userlog("MG_RECV 수신 stan=%ld msg_id=%ld chan=%s mti=%s amt=%ld", stan, msg_id, chan, mti, amount);
OK(b);
}
/* 2. MG_SEND - 전문 송신 (direction=OUT). */
void MG_SEND(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], mti[8], raw[512], bizdate[16];
long stan, msg_id, amount;
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
gets_(b, T_STR1, mti, sizeof(mti)); if (mti[0] == 0) strcpy(mti, "0210");
gets_(b, T_STR3, raw, sizeof(raw));
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
amount = getl(b, T_AMOUNT);
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
if (mgdb_insert_msg(msg_id, stan, mti, chan, "OUT", "000000", "", amount,
"", "00", raw, "S", bizdate) < 0) FAIL(b);
setl(b, T_ARG1, stan);
setl(b, T_ID1, msg_id);
OK(b);
}
/* 3. MG_ISO8583 - ISO8583 전문 파싱 후 로그 (mti=전문 앞 4자리). */
void MG_ISO8583(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], raw[512], bizdate[16], mti[8], proc[8];
long stan, msg_id, amount, n;
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
gets_(b, T_STR3, raw, sizeof(raw));
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
n = (long)strlen(raw);
/* 고정길이 전문: [0..3]=MTI, [4..9]=처리코드, [10..21]=금액(12자리) */
memset(mti, 0, sizeof(mti)); memset(proc, 0, sizeof(proc));
if (n >= 4) strncpy(mti, raw, 4);
else strcpy(mti, "0200");
if (n >= 10) strncpy(proc, raw + 4, 6);
else strcpy(proc, "000000");
amount = (n >= 22) ? atol(raw + 10) : getl(b, T_AMOUNT);
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
if (mgdb_insert_msg(msg_id, stan, mti, chan, "IN", proc, "", amount,
"", "00", raw, "R", bizdate) < 0) FAIL(b);
sets_(b, T_STR1, mti);
sets_(b, T_STR4, proc);
setl(b, T_AMOUNT, amount);
setl(b, T_ID1, msg_id);
OK(b);
}
/* 4. MG_BITMAP - 비트맵 계산 후 해당 전문(msg_id)에 반영. */
void MG_BITMAP(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char hex[24];
unsigned long mask = (unsigned long)getl(b, T_ARG1); /* 필드 존재 마스크 */
EXEC SQL BEGIN DECLARE SECTION;
long h_id;
char h_bitmap[40];
EXEC SQL END DECLARE SECTION;
mg_bitmap_hex(mask, hex);
sets_(b, T_STR6, hex);
h_id = getl(b, T_ID1);
if (h_id > 0) {
strncpy(h_bitmap, hex, sizeof(h_bitmap)-1); h_bitmap[sizeof(h_bitmap)-1] = 0;
EXEC SQL UPDATE mg_msg_log SET bitmap = :h_bitmap WHERE msg_id = :h_id;
if (sqlca.sqlcode < 0) { userlog("MG_BITMAP UPDATE FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
}
OK(b);
}
/* 5. MG_STAN - STAN 채번 (Postgres sequence). */
void MG_STAN(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
long stan = mgdb_next_stan();
if (stan < 0) FAIL(b);
setl(b, T_ARG1, stan);
OK(b);
}
/* 6. MG_ROUTE - 채널+전문유형 -> 목적지 라우팅 조회. */
void MG_ROUTE(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], mti[8], dest[64];
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
gets_(b, T_STR1, mti, sizeof(mti)); if (mti[0] == 0) strcpy(mti, "0200");
if (mgdb_lookup_route(chan, mti, dest) < 0) {
userlog("MG_ROUTE 라우팅 없음 chan=%s mti=%s", chan, mti);
setl(b, T_RC, 1);
FAIL(b);
}
sets_(b, T_STR3, dest);
setl(b, T_RC, 0);
OK(b);
}
/* 7. MG_RESEND - 전문 재전송: STAN 으로 원전문 찾아 큐에 적재. */
void MG_RESEND(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], mti[8], raw[512], bizdate[16];
long stan, msg_id, qid;
stan = getl(b, T_ARG1);
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
gets_(b, T_STR1, mti, sizeof(mti)); if (mti[0] == 0) strcpy(mti, "0200");
gets_(b, T_STR3, raw, sizeof(raw));
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
msg_id = mgdb_find_msg_by_stan(stan);
if (msg_id < 0) { userlog("MG_RESEND 원전문 없음 stan=%ld", stan); FAIL(b); }
qid = mgdb_next_queue_id(); if (qid < 0) FAIL(b);
if (mgdb_enqueue(qid, stan, chan, mti, raw, bizdate) < 0) FAIL(b);
setl(b, T_ID2, qid);
userlog("MG_RESEND 재전송 큐적재 stan=%ld qid=%ld", stan, qid);
OK(b);
}
/* 8. MG_CONVERT - 요청전문 -> 응답전문 변환 (MTI +0x10) 후 송신 로그. */
void MG_CONVERT(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], mti[8], rmti[8], raw[512], bizdate[16];
long stan, msg_id, amount, mnum;
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
gets_(b, T_STR1, mti, sizeof(mti)); if (mti[0] == 0) strcpy(mti, "0200");
gets_(b, T_STR3, raw, sizeof(raw));
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
amount = getl(b, T_AMOUNT);
mnum = atol(mti) + 10; /* 0200 -> 0210 응답 */
sprintf(rmti, "%04ld", mnum);
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
if (mgdb_insert_msg(msg_id, stan, rmti, chan, "OUT", "000000", "", amount,
"", "00", raw, "S", bizdate) < 0) FAIL(b);
sets_(b, T_STR1, rmti);
setl(b, T_ID1, msg_id);
OK(b);
}
/* 9. MG_ERRMSG - 오류 전문 기록 (status=N, rc=입력). */
void MG_ERRMSG(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], mti[8], raw[512], bizdate[16], rc[4];
long stan, msg_id, rcnum;
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
gets_(b, T_STR1, mti, sizeof(mti)); if (mti[0] == 0) strcpy(mti, "0210");
gets_(b, T_STR3, raw, sizeof(raw));
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
rcnum = getl(b, T_RC); if (rcnum <= 0) rcnum = 96;
sprintf(rc, "%02ld", rcnum % 100);
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
if (mgdb_insert_msg(msg_id, stan, mti, chan, "OUT", "000000", "", 0,
"", rc, raw, "N", bizdate) < 0) FAIL(b);
setl(b, T_ID1, msg_id);
OK(b);
}
/* 10. MG_LOG - 채널 당일 전문 로그 건수 조회. */
void MG_LOG(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], bizdate[16];
EXEC SQL BEGIN DECLARE SECTION;
long h_cnt;
char h_chan[16], h_bizdate[16];
EXEC SQL END DECLARE SECTION;
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
strncpy(h_chan, chan, sizeof(h_chan)-1); h_chan[sizeof(h_chan)-1] = 0;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL SELECT count(*) INTO :h_cnt FROM mg_msg_log
WHERE channel = :h_chan AND biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_COUNT, h_cnt);
OK(b);
}
/* 11. MG_CHANAUTH - 채널 인증: UP/SIGNON 상태만 통과. */
void MG_CHANAUTH(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], st[16];
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
if (mgdb_get_channel_status(chan, st) < 0) { setl(b, T_RC, 2); FAIL(b); }
if (strcmp(st, "UP") == 0 || strcmp(st, "SIGNON") == 0) {
setl(b, T_RC, 0);
sets_(b, T_STATUS, st);
OK(b);
}
userlog("MG_CHANAUTH 거부 chan=%s status=%s", chan, st);
setl(b, T_RC, 1);
sets_(b, T_STATUS, st);
FAIL(b);
}
/* 12. MG_SESSION - 세션 시퀀스 채번 (mg_seq SESSION). */
void MG_SESSION(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
long v = mgdb_seq_bump("SESSION");
if (v < 0) FAIL(b);
setl(b, T_ARG2, v);
OK(b);
}
/* 13. MG_ACK - 응답 확인 (status=A, rc=00). */
void MG_ACK(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
long msg_id = getl(b, T_ID1);
if (mgdb_update_msg_rc(msg_id, "00", "A") < 0) FAIL(b);
sets_(b, T_STATUS, "A");
OK(b);
}
/* 14. MG_NACK - 부정 응답 (status=N, rc=입력). */
void MG_NACK(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char rc[4];
long msg_id = getl(b, T_ID1), rcnum = getl(b, T_RC);
if (rcnum <= 0) rcnum = 91;
sprintf(rc, "%02ld", rcnum % 100);
if (mgdb_update_msg_rc(msg_id, rc, "N") < 0) FAIL(b);
sets_(b, T_STATUS, "N");
OK(b);
}
/* 15. MG_ECHO - 에코 전문(0800) 처리 + 채널 UP 표시. */
void MG_ECHO(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], bizdate[16];
long stan, msg_id;
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
if (mgdb_insert_msg(msg_id, stan, "0800", chan, "IN", "990000", "", 0,
"", "00", "ECHO-TEST", "A", bizdate) < 0) FAIL(b);
if (mgdb_set_channel_status(chan, "UP") < 0) FAIL(b);
setl(b, T_ID1, msg_id);
sets_(b, T_STATUS, "UP");
OK(b);
}
/* 16. MG_HEALTH - 게이트웨이 헬스: 활성 채널 수 조회. */
void MG_HEALTH(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
EXEC SQL BEGIN DECLARE SECTION;
long h_up;
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT count(*) INTO :h_up FROM mg_channel WHERE status IN ('UP','SIGNON');
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_COUNT, h_up);
setl(b, T_RC, 0);
OK(b);
}
/* 17. MG_SIGNON - 채널 사인온 + 세션키 설정. */
void MG_SIGNON(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], key[64];
long stan;
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
gets_(b, T_KEY1, key, sizeof(key)); if (key[0] == 0) strcpy(key, "SESSION-KEY-DFLT");
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
if (mgdb_set_channel_session(chan, key, stan) < 0) FAIL(b);
sets_(b, T_STATUS, "SIGNON");
userlog("MG_SIGNON chan=%s stan=%ld", chan, stan);
OK(b);
}
/* 18. MG_SIGNOFF - 채널 사인오프 (status=DOWN). */
void MG_SIGNOFF(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16];
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
if (mgdb_set_channel_status(chan, "DOWN") < 0) FAIL(b);
sets_(b, T_STATUS, "DOWN");
OK(b);
}
/* 19. MG_KEYEXCH - 키 교환: 키버전 채번 + 세션키 갱신. */
void MG_KEYEXCH(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], key[64];
long ver, stan;
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
gets_(b, T_KEY1, key, sizeof(key)); if (key[0] == 0) strcpy(key, "NEW-KEY");
ver = mgdb_seq_bump("KEYVER"); if (ver < 0) FAIL(b);
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
if (mgdb_set_channel_session(chan, key, stan) < 0) FAIL(b);
setl(b, T_ARG2, ver);
userlog("MG_KEYEXCH chan=%s keyver=%ld", chan, ver);
OK(b);
}
/* 20. MG_MAC - 전문 MAC 계산 후 해당 전문에 반영 (무결성). */
void MG_MAC(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char raw[512], mac[8];
EXEC SQL BEGIN DECLARE SECTION;
long h_id;
char h_mac[8];
EXEC SQL END DECLARE SECTION;
gets_(b, T_STR3, raw, sizeof(raw));
mg_checksum(raw, mac);
sets_(b, T_KEY1, mac);
h_id = getl(b, T_ID1);
if (h_id > 0) {
strncpy(h_mac, mac, sizeof(h_mac)-1); h_mac[sizeof(h_mac)-1] = 0;
EXEC SQL UPDATE mg_msg_log SET mac = :h_mac WHERE msg_id = :h_id;
if (sqlca.sqlcode < 0) { userlog("MG_MAC UPDATE FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
}
OK(b);
}
/* 21. MG_PARSE - 고정길이 전문에서 처리코드 필드 추출 (순수 계산). */
void MG_PARSE(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char raw[512], mti[8], proc[8];
long n;
gets_(b, T_STR3, raw, sizeof(raw));
n = (long)strlen(raw);
memset(mti, 0, sizeof(mti)); memset(proc, 0, sizeof(proc));
if (n >= 4) strncpy(mti, raw, 4); else strcpy(mti, "0000");
if (n >= 10) strncpy(proc, raw + 4, 6); else strcpy(proc, "000000");
sets_(b, T_STR1, mti);
sets_(b, T_STR4, proc);
setl(b, T_COUNT, n);
OK(b);
}
/* 22. MG_PACK - 고정길이 전문 조립 (순수 계산): MTI(4)+처리코드(6)+금액(12). */
void MG_PACK(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char mti[8], proc[8], raw[64];
long amount;
gets_(b, T_STR1, mti, sizeof(mti)); if (mti[0] == 0) strcpy(mti, "0200");
gets_(b, T_STR4, proc, sizeof(proc)); if (proc[0] == 0) strcpy(proc, "000000");
amount = getl(b, T_AMOUNT);
sprintf(raw, "%.4s%.6s%012ld", mti, proc, amount);
sets_(b, T_STR3, raw);
setl(b, T_COUNT, (long)strlen(raw));
OK(b);
}
/* 23. MG_UNPACK - 고정길이 전문 해체 (순수 계산). */
void MG_UNPACK(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char raw[512], mti[8], proc[8];
long amount, n;
gets_(b, T_STR3, raw, sizeof(raw));
n = (long)strlen(raw);
memset(mti, 0, sizeof(mti)); memset(proc, 0, sizeof(proc));
if (n >= 4) strncpy(mti, raw, 4); else strcpy(mti, "0000");
if (n >= 10) strncpy(proc, raw + 4, 6); else strcpy(proc, "000000");
amount = (n >= 22) ? atol(raw + 10) : 0;
sets_(b, T_STR1, mti);
sets_(b, T_STR4, proc);
setl(b, T_AMOUNT, amount);
OK(b);
}
/* 24. MG_QUEUE - 송신 큐 적재. */
void MG_QUEUE(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], mti[8], raw[512], bizdate[16];
long stan, qid;
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
gets_(b, T_STR1, mti, sizeof(mti)); if (mti[0] == 0) strcpy(mti, "0200");
gets_(b, T_STR3, raw, sizeof(raw));
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
stan = getl(b, T_ARG1);
if (stan <= 0) { stan = mgdb_next_stan(); if (stan < 0) FAIL(b); }
qid = mgdb_next_queue_id(); if (qid < 0) FAIL(b);
if (mgdb_enqueue(qid, stan, chan, mti, raw, bizdate) < 0) FAIL(b);
setl(b, T_ID2, qid);
setl(b, T_ARG1, stan);
OK(b);
}
/* 25. MG_DEQUEUE - 대기(Q) 전문 1건 인출 후 송신중(S) 전이. */
void MG_DEQUEUE(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
EXEC SQL BEGIN DECLARE SECTION;
long h_qid, h_stan;
char h_payload[512], h_chan[16];
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT queue_id, stan, channel, payload INTO :h_qid, :h_stan, :h_chan, :h_payload
FROM mg_queue WHERE status = 'Q' ORDER BY queue_id ASC LIMIT 1;
if (sqlca.sqlcode == 100) { setl(b, T_COUNT, 0); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
EXEC SQL UPDATE mg_queue SET status = 'S', updated_at = now() WHERE queue_id = :h_qid;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
setl(b, T_ID2, h_qid);
setl(b, T_ARG1, h_stan);
sets_(b, T_CHANNEL, h_chan);
sets_(b, T_STR3, h_payload);
setl(b, T_COUNT, 1);
OK(b);
}
/* 26. MG_RETRY - 큐 재시도: retry_cnt +1, status=Q. */
void MG_RETRY(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
EXEC SQL BEGIN DECLARE SECTION;
long h_qid, h_retry;
EXEC SQL END DECLARE SECTION;
h_qid = getl(b, T_ID2);
EXEC SQL UPDATE mg_queue SET retry_cnt = retry_cnt + 1, status = 'Q', updated_at = now()
WHERE queue_id = :h_qid;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
EXEC SQL SELECT retry_cnt INTO :h_retry FROM mg_queue WHERE queue_id = :h_qid;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
setl(b, T_COUNT, h_retry);
OK(b);
}
/* 27. MG_STATS - 채널 당일 통계: 수신/송신/오류 건수. */
void MG_STATS(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], bizdate[16];
EXEC SQL BEGIN DECLARE SECTION;
long h_in, h_out, h_err, h_sum;
char h_chan[16], h_bizdate[16];
EXEC SQL END DECLARE SECTION;
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
strncpy(h_chan, chan, sizeof(h_chan)-1); h_chan[sizeof(h_chan)-1] = 0;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL SELECT
coalesce(sum(CASE WHEN direction='IN' THEN 1 ELSE 0 END),0),
coalesce(sum(CASE WHEN direction='OUT' THEN 1 ELSE 0 END),0),
coalesce(sum(CASE WHEN rc<>'00' THEN 1 ELSE 0 END),0),
coalesce(sum(amount),0)
INTO :h_in, :h_out, :h_err, :h_sum
FROM mg_msg_log WHERE channel = :h_chan AND biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_ARG1, h_in);
setl(b, T_ARG2, h_out);
setl(b, T_ARG3, h_err);
setl(b, T_GROSS, h_sum);
OK(b);
}
/* 28. MG_CHANSTAT - 채널 상태 조회. */
void MG_CHANSTAT(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], st[16];
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
if (mgdb_get_channel_status(chan, st) < 0) FAIL(b);
sets_(b, T_STATUS, st);
OK(b);
}
/* 29. MG_STATUS - 전문 처리 상태 조회 (msg_id). */
void MG_STATUS(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
long msg_id = getl(b, T_ID1);
char st[4];
if (mgdb_get_msg_status(msg_id, st) < 0) FAIL(b);
sets_(b, T_STATUS, st);
OK(b);
}
/* 30. MG_CONFIRM - 전문 확정 (status=C). */
void MG_CONFIRM(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
long msg_id = getl(b, T_ID1);
if (mgdb_update_msg_rc(msg_id, "00", "C") < 0) FAIL(b);
sets_(b, T_STATUS, "C");
OK(b);
}
/* vim: set ts=4 sw=4 et smartindent: */

13
app/src/mg/run/run_chanacc.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
##
## run_chanacc.sh - 채널 누적 집계
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 배치/서비스를 실행.
## Usage: run_chanacc.sh [BIZDATE]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
echo "[run_chanacc.sh] BIZDATE=$BIZDATE"
exec /app/bin/mg_chanacc_batch "$BIZDATE"

13
app/src/mg/run/run_chansnap.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
##
## run_chansnap.sh - 채널 스냅샷 적재
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 배치/서비스를 실행.
## Usage: run_chansnap.sh [BIZDATE]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
echo "[run_chansnap.sh] BIZDATE=$BIZDATE"
exec /app/bin/mg_chansnap_batch "$BIZDATE"

13
app/src/mg/run/run_confirm.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
##
## run_confirm.sh - 송신 큐 확정 처리
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 배치/서비스를 실행.
## Usage: run_confirm.sh [BIZDATE]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
echo "[run_confirm.sh] BIZDATE=$BIZDATE"
exec /app/bin/mg_confirm_batch "$BIZDATE"

13
app/src/mg/run/run_dirstat.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
##
## run_dirstat.sh - 방향별 통계 집계
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 배치/서비스를 실행.
## Usage: run_dirstat.sh [BIZDATE]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
echo "[run_dirstat.sh] BIZDATE=$BIZDATE"
exec /app/bin/mg_dirstat_batch "$BIZDATE"

13
app/src/mg/run/run_distinct.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
##
## run_distinct.sh - 고유 채널 집계
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 배치/서비스를 실행.
## Usage: run_distinct.sh [BIZDATE]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
echo "[run_distinct.sh] BIZDATE=$BIZDATE"
exec /app/bin/mg_distinct_batch "$BIZDATE"

16
app/src/mg/run/run_eod.sh Executable file
View file

@ -0,0 +1,16 @@
#!/bin/bash
##
## run_eod.sh - mg 일마감 배치 일괄 실행
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 배치/서비스를 실행.
## Usage: run_eod.sh [BIZDATE]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
echo "[run_eod.sh] BIZDATE=$BIZDATE"
for b in mg_amount_batch mg_rollup_batch mg_chanacc_batch mg_spread_batch mg_stat_batch \
mg_errbps_batch mg_dirstat_batch mg_marker_batch mg_purge_batch; do
echo "--- $b $BIZDATE ---"; "/app/bin/$b" "$BIZDATE" || exit 1
done

13
app/src/mg/run/run_errbps.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
##
## run_errbps.sh - 오류율(bps) 집계
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 배치/서비스를 실행.
## Usage: run_errbps.sh [BIZDATE]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
echo "[run_errbps.sh] BIZDATE=$BIZDATE"
exec /app/bin/mg_errbps_batch "$BIZDATE"

13
app/src/mg/run/run_join.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
##
## run_join.sh - 라우팅 조인 집계
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 배치/서비스를 실행.
## Usage: run_join.sh [BIZDATE]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
echo "[run_join.sh] BIZDATE=$BIZDATE"
exec /app/bin/mg_join_batch "$BIZDATE"

13
app/src/mg/run/run_marker.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
##
## run_marker.sh - EOD 마커 채번 적재
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 배치/서비스를 실행.
## Usage: run_marker.sh [BIZDATE]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
echo "[run_marker.sh] BIZDATE=$BIZDATE"
exec /app/bin/mg_marker_batch "$BIZDATE"

13
app/src/mg/run/run_promote.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
##
## run_promote.sh - 실패 큐 재대기 승격
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 배치/서비스를 실행.
## Usage: run_promote.sh [BIZDATE]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
echo "[run_promote.sh] BIZDATE=$BIZDATE"
exec /app/bin/mg_promote_batch "$BIZDATE"

13
app/src/mg/run/run_prune.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
##
## run_prune.sh - 오류 전문 큐 삭제
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 배치/서비스를 실행.
## Usage: run_prune.sh [BIZDATE]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
echo "[run_prune.sh] BIZDATE=$BIZDATE"
exec /app/bin/mg_prunequeue_batch "$BIZDATE"

13
app/src/mg/run/run_purge.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
##
## run_purge.sh - 송신완료 큐 정리
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 배치/서비스를 실행.
## Usage: run_purge.sh [BIZDATE]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
echo "[run_purge.sh] BIZDATE=$BIZDATE"
exec /app/bin/mg_purge_batch "$BIZDATE"

13
app/src/mg/run/run_recv.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
##
## run_recv.sh - 전문 수신 처리
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 배치/서비스를 실행.
## Usage: run_recv.sh [BIZDATE]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
echo "[run_recv.sh] BIZDATE=$BIZDATE"
exec /app/bin/mg_amount_batch "$BIZDATE"

13
app/src/mg/run/run_resend.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
##
## run_resend.sh - 실패 전문 재전송
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 배치/서비스를 실행.
## Usage: run_resend.sh [BIZDATE]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
echo "[run_resend.sh] BIZDATE=$BIZDATE"
exec /app/bin/mg_resend_batch "$BIZDATE"

13
app/src/mg/run/run_rollup.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
##
## run_rollup.sh - 채널 롤업 집계
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 배치/서비스를 실행.
## Usage: run_rollup.sh [BIZDATE]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
echo "[run_rollup.sh] BIZDATE=$BIZDATE"
exec /app/bin/mg_rollup_batch "$BIZDATE"

13
app/src/mg/run/run_send.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
##
## run_send.sh - 전문 송신 처리
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 배치/서비스를 실행.
## Usage: run_send.sh [BIZDATE]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
echo "[run_send.sh] BIZDATE=$BIZDATE"
exec /app/bin/mg_scalar_batch "$BIZDATE"

13
app/src/mg/run/run_spread.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
##
## run_spread.sh - 금액 스프레드 집계
## 운영 스크립트: Enduro/X + ECPG/XA 런타임 환경을 설정하고 배치/서비스를 실행.
## Usage: run_spread.sh [BIZDATE]
##
set -e
. /app/conf/setapp.sh
BIZDATE="${1:-2026-07-19}"
echo "[run_spread.sh] BIZDATE=$BIZDATE"
exec /app/bin/mg_spread_batch "$BIZDATE"

12
app/src/mg/svc/MG_ACK.h Normal file
View file

@ -0,0 +1,12 @@
/*
* MG_ACK.h - mg () MG_ACK (copybook / record header).
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
*/
#ifndef MG_ACK_H
#define MG_ACK_H
#include "mg_svc.h"
void MG_ACK(TPSVCINFO *p);
#endif /* MG_ACK_H */

16
app/src/mg/svc/MG_ACK.pgc Normal file
View file

@ -0,0 +1,16 @@
/*
* MG_ACK.pgc - mg 모듈 서비스 MG_ACK (one service = one file).
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
*/
#include "MG_ACK.h"
/* 13. MG_ACK - 응답 확인 (status=A, rc=00). */
void MG_ACK(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
long msg_id = getl(b, T_ID1);
if (mgdb_update_msg_rc(msg_id, "00", "A") < 0) FAIL(b);
sets_(b, T_STATUS, "A");
OK(b);
}

View file

@ -0,0 +1,12 @@
/*
* MG_BITMAP.h - mg () MG_BITMAP (copybook / record header).
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
*/
#ifndef MG_BITMAP_H
#define MG_BITMAP_H
#include "mg_svc.h"
void MG_BITMAP(TPSVCINFO *p);
#endif /* MG_BITMAP_H */

View file

@ -0,0 +1,37 @@
/*
* MG_BITMAP.pgc - mg 모듈 서비스 MG_BITMAP (one service = one file).
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
*/
#include "MG_BITMAP.h"
/* ----- service-local pure helper(s) ----- */
/* 16-hex primary bitmap from a 64-bit field-present mask. */
static void mg_bitmap_hex(unsigned long mask, char *out /* >= 17 */)
{
sprintf(out, "%016lX", mask);
}
/* 4. MG_BITMAP - 비트맵 계산 후 해당 전문(msg_id)에 반영. */
void MG_BITMAP(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char hex[24];
unsigned long mask = (unsigned long)getl(b, T_ARG1); /* 필드 존재 마스크 */
EXEC SQL BEGIN DECLARE SECTION;
long h_id;
char h_bitmap[40];
EXEC SQL END DECLARE SECTION;
mg_bitmap_hex(mask, hex);
sets_(b, T_STR6, hex);
h_id = getl(b, T_ID1);
if (h_id > 0) {
strncpy(h_bitmap, hex, sizeof(h_bitmap)-1); h_bitmap[sizeof(h_bitmap)-1] = 0;
EXEC SQL UPDATE mg_msg_log SET bitmap = :h_bitmap WHERE msg_id = :h_id;
if (sqlca.sqlcode < 0) { userlog("MG_BITMAP UPDATE FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); FAIL(b); }
}
OK(b);
}

View file

@ -0,0 +1,12 @@
/*
* MG_CHANAUTH.h - mg () MG_CHANAUTH (copybook / record header).
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
*/
#ifndef MG_CHANAUTH_H
#define MG_CHANAUTH_H
#include "mg_svc.h"
void MG_CHANAUTH(TPSVCINFO *p);
#endif /* MG_CHANAUTH_H */

View file

@ -0,0 +1,24 @@
/*
* MG_CHANAUTH.pgc - mg 모듈 서비스 MG_CHANAUTH (one service = one file).
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
*/
#include "MG_CHANAUTH.h"
/* 11. MG_CHANAUTH - 채널 인증: UP/SIGNON 상태만 통과. */
void MG_CHANAUTH(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], st[16];
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
if (mgdb_get_channel_status(chan, st) < 0) { setl(b, T_RC, 2); FAIL(b); }
if (strcmp(st, "UP") == 0 || strcmp(st, "SIGNON") == 0) {
setl(b, T_RC, 0);
sets_(b, T_STATUS, st);
OK(b);
}
userlog("MG_CHANAUTH 거부 chan=%s status=%s", chan, st);
setl(b, T_RC, 1);
sets_(b, T_STATUS, st);
FAIL(b);
}

View file

@ -0,0 +1,12 @@
/*
* MG_CHANSTAT.h - mg () MG_CHANSTAT (copybook / record header).
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
*/
#ifndef MG_CHANSTAT_H
#define MG_CHANSTAT_H
#include "mg_svc.h"
void MG_CHANSTAT(TPSVCINFO *p);
#endif /* MG_CHANSTAT_H */

View file

@ -0,0 +1,17 @@
/*
* MG_CHANSTAT.pgc - mg 모듈 서비스 MG_CHANSTAT (one service = one file).
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
*/
#include "MG_CHANSTAT.h"
/* 28. MG_CHANSTAT - 채널 상태 조회. */
void MG_CHANSTAT(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], st[16];
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
if (mgdb_get_channel_status(chan, st) < 0) FAIL(b);
sets_(b, T_STATUS, st);
OK(b);
}

View file

@ -0,0 +1,12 @@
/*
* MG_CONFIRM.h - mg () MG_CONFIRM (copybook / record header).
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
*/
#ifndef MG_CONFIRM_H
#define MG_CONFIRM_H
#include "mg_svc.h"
void MG_CONFIRM(TPSVCINFO *p);
#endif /* MG_CONFIRM_H */

View file

@ -0,0 +1,16 @@
/*
* MG_CONFIRM.pgc - mg 모듈 서비스 MG_CONFIRM (one service = one file).
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
*/
#include "MG_CONFIRM.h"
/* 30. MG_CONFIRM - 전문 확정 (status=C). */
void MG_CONFIRM(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
long msg_id = getl(b, T_ID1);
if (mgdb_update_msg_rc(msg_id, "00", "C") < 0) FAIL(b);
sets_(b, T_STATUS, "C");
OK(b);
}

View file

@ -0,0 +1,12 @@
/*
* MG_CONVERT.h - mg () MG_CONVERT (copybook / record header).
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
*/
#ifndef MG_CONVERT_H
#define MG_CONVERT_H
#include "mg_svc.h"
void MG_CONVERT(TPSVCINFO *p);
#endif /* MG_CONVERT_H */

View file

@ -0,0 +1,31 @@
/*
* MG_CONVERT.pgc - mg 모듈 서비스 MG_CONVERT (one service = one file).
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
*/
#include "MG_CONVERT.h"
/* 8. MG_CONVERT - 요청전문 -> 응답전문 변환 (MTI +0x10) 후 송신 로그. */
void MG_CONVERT(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], mti[8], rmti[8], raw[512], bizdate[16];
long stan, msg_id, amount, mnum;
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
gets_(b, T_STR1, mti, sizeof(mti)); if (mti[0] == 0) strcpy(mti, "0200");
gets_(b, T_STR3, raw, sizeof(raw));
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
amount = getl(b, T_AMOUNT);
mnum = atol(mti) + 10; /* 0200 -> 0210 응답 */
sprintf(rmti, "%04ld", mnum);
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
if (mgdb_insert_msg(msg_id, stan, rmti, chan, "OUT", "000000", "", amount,
"", "00", raw, "S", bizdate) < 0) FAIL(b);
sets_(b, T_STR1, rmti);
setl(b, T_ID1, msg_id);
OK(b);
}

View file

@ -0,0 +1,12 @@
/*
* MG_DEQUEUE.h - mg () MG_DEQUEUE (copybook / record header).
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
*/
#ifndef MG_DEQUEUE_H
#define MG_DEQUEUE_H
#include "mg_svc.h"
void MG_DEQUEUE(TPSVCINFO *p);
#endif /* MG_DEQUEUE_H */

View file

@ -0,0 +1,31 @@
/*
* MG_DEQUEUE.pgc - mg 모듈 서비스 MG_DEQUEUE (one service = one file).
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
*/
#include "MG_DEQUEUE.h"
/* 25. MG_DEQUEUE - 대기(Q) 전문 1건 인출 후 송신중(S) 전이. */
void MG_DEQUEUE(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
EXEC SQL BEGIN DECLARE SECTION;
long h_qid, h_stan;
char h_payload[512], h_chan[16];
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT queue_id, stan, channel, payload INTO :h_qid, :h_stan, :h_chan, :h_payload
FROM mg_queue WHERE status = 'Q' ORDER BY queue_id ASC LIMIT 1;
if (sqlca.sqlcode == 100) { setl(b, T_COUNT, 0); OK(b); }
if (sqlca.sqlcode < 0) FAIL(b);
EXEC SQL UPDATE mg_queue SET status = 'S', updated_at = now() WHERE queue_id = :h_qid;
if (sqlca.sqlcode < 0 || sqlca.sqlcode == 100) FAIL(b);
setl(b, T_ID2, h_qid);
setl(b, T_ARG1, h_stan);
sets_(b, T_CHANNEL, h_chan);
sets_(b, T_STR3, h_payload);
setl(b, T_COUNT, 1);
OK(b);
}

12
app/src/mg/svc/MG_ECHO.h Normal file
View file

@ -0,0 +1,12 @@
/*
* MG_ECHO.h - mg () MG_ECHO (copybook / record header).
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
*/
#ifndef MG_ECHO_H
#define MG_ECHO_H
#include "mg_svc.h"
void MG_ECHO(TPSVCINFO *p);
#endif /* MG_ECHO_H */

View file

@ -0,0 +1,25 @@
/*
* MG_ECHO.pgc - mg 모듈 서비스 MG_ECHO (one service = one file).
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
*/
#include "MG_ECHO.h"
/* 15. MG_ECHO - 에코 전문(0800) 처리 + 채널 UP 표시. */
void MG_ECHO(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], bizdate[16];
long stan, msg_id;
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
if (mgdb_insert_msg(msg_id, stan, "0800", chan, "IN", "990000", "", 0,
"", "00", "ECHO-TEST", "A", bizdate) < 0) FAIL(b);
if (mgdb_set_channel_status(chan, "UP") < 0) FAIL(b);
setl(b, T_ID1, msg_id);
sets_(b, T_STATUS, "UP");
OK(b);
}

View file

@ -0,0 +1,12 @@
/*
* MG_ERRMSG.h - mg () MG_ERRMSG (copybook / record header).
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
*/
#ifndef MG_ERRMSG_H
#define MG_ERRMSG_H
#include "mg_svc.h"
void MG_ERRMSG(TPSVCINFO *p);
#endif /* MG_ERRMSG_H */

View file

@ -0,0 +1,28 @@
/*
* MG_ERRMSG.pgc - mg 모듈 서비스 MG_ERRMSG (one service = one file).
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
*/
#include "MG_ERRMSG.h"
/* 9. MG_ERRMSG - 오류 전문 기록 (status=N, rc=입력). */
void MG_ERRMSG(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
char chan[16], mti[8], raw[512], bizdate[16], rc[4];
long stan, msg_id, rcnum;
gets_(b, T_CHANNEL, chan, sizeof(chan)); if (chan[0] == 0) strcpy(chan, "CH01");
gets_(b, T_STR1, mti, sizeof(mti)); if (mti[0] == 0) strcpy(mti, "0210");
gets_(b, T_STR3, raw, sizeof(raw));
gets_(b, T_BIZDATE, bizdate, sizeof(bizdate));
rcnum = getl(b, T_RC); if (rcnum <= 0) rcnum = 96;
sprintf(rc, "%02ld", rcnum % 100);
stan = mgdb_next_stan(); if (stan < 0) FAIL(b);
msg_id = mgdb_next_msg_id(); if (msg_id < 0) FAIL(b);
if (mgdb_insert_msg(msg_id, stan, mti, chan, "OUT", "000000", "", 0,
"", rc, raw, "N", bizdate) < 0) FAIL(b);
setl(b, T_ID1, msg_id);
OK(b);
}

View file

@ -0,0 +1,12 @@
/*
* MG_HEALTH.h - mg () MG_HEALTH (copybook / record header).
* Split out of the former inline mg_svr.pgc; advertised by mg_svr.
*/
#ifndef MG_HEALTH_H
#define MG_HEALTH_H
#include "mg_svc.h"
void MG_HEALTH(TPSVCINFO *p);
#endif /* MG_HEALTH_H */

View file

@ -0,0 +1,20 @@
/*
* MG_HEALTH.pgc - mg 모듈 서비스 MG_HEALTH (one service = one file).
* Split out of the former inline mg_svr.pgc; runs on the caller's XA
* branch (no EXEC SQL CONNECT). Advertised by mg_svr at tpsvrinit.
*/
#include "MG_HEALTH.h"
/* 16. MG_HEALTH - 게이트웨이 헬스: 활성 채널 수 조회. */
void MG_HEALTH(TPSVCINFO *p)
{
UBFH *b = (UBFH *)p->data;
EXEC SQL BEGIN DECLARE SECTION;
long h_up;
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT count(*) INTO :h_up FROM mg_channel WHERE status IN ('UP','SIGNON');
if (sqlca.sqlcode < 0) FAIL(b);
setl(b, T_COUNT, h_up);
setl(b, T_RC, 0);
OK(b);
}

Some files were not shown because too many files have changed in this diff Show more