고도화: 전 모듈 dbio 25→40 · batch 17→22 세분화 (+432본, 전부 고유)

- 11개 모듈 각 dbio +15(→40), batch +5(→22) 새 고유 ECPG 프로그램 + 카피북 헤더
  (window/HAVING/JOIN/FILTER/NOT EXISTS/upsert/correlated/INSERT..SELECT 등 구조 다양)
- 전 코퍼스 .pgc 1004/1004 정규화-고유 (dup 그룹 0)
- 통합 검증: 12서버 runok, 333 서비스, 242 배치 바이너리, 매입체인 XA 커밋, 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 14:37:10 +00:00
parent 05ad8a3064
commit fc16ea64c8
422 changed files with 8717 additions and 0 deletions

View file

@ -0,0 +1,60 @@
/*
* ac_amountband_batch.pgc - ac 매입 금액대 분포 배치 (CASE 버킷 + XA).
*
* ATMI client: one global transaction; a single CASE-bucketed aggregate splits
* the day's purchases into three amount bands. The C helper mirrors the band
* thresholds for reporting. tpcommit drives XA 2PC.
* Usage: ac_amountband_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "ac_amountband_batch.h"
/* 금액을 3구간으로 분류. */
int acb_band_classify(long amount)
{
if (amount < 50000L) return 0;
if (amount < 500000L) return 1;
return 2;
}
int main(int argc, char **argv)
{
ac_band_ctx_t ctx;
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_lo = 0, h_mid = 0, h_hi = 0;
EXEC SQL END DECLARE SECTION;
memset(&ctx, 0, sizeof(ctx));
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
strncpy(ctx.biz_date, bizdate, sizeof(ctx.biz_date)-1);
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(*) FILTER (WHERE amount < 50000),
count(*) FILTER (WHERE amount >= 50000 AND amount < 500000),
count(*) FILTER (WHERE amount >= 500000)
INTO :h_lo, :h_mid, :h_hi
FROM purchase WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) { fprintf(stderr, "ac_amountband_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
ctx.band_lo = h_lo;
ctx.band_mid = h_mid;
ctx.band_hi = h_hi;
(void)acb_band_classify(ctx.band_hi);
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> ac_amountband_batch COMMIT: bizdate=%s lo=%ld mid=%ld hi=%ld\n",
ctx.biz_date, ctx.band_lo, ctx.band_mid, ctx.band_hi);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,58 @@
/*
* ac_concentration_batch.pgc - ac 상위매입 집중도 배치 (window + XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction, a windowed subquery ranks purchases and a scalar sums the top-3
* against the daily total; tpcommit drives XA 2PC.
* Usage: ac_concentration_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "ac_concentration_batch.h"
/* 집중도(bps) = top_sum / total * 10000. total<=0 이면 0. */
long acb_conc_ratio_bps(long top_sum, long total)
{
if (total <= 0) return 0;
return (top_sum * 10000L) / total;
}
int main(int argc, char **argv)
{
ac_conc_ctx_t ctx;
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_top = 0, h_total = 0;
EXEC SQL END DECLARE SECTION;
memset(&ctx, 0, sizeof(ctx));
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
strncpy(ctx.biz_date, bizdate, sizeof(ctx.biz_date)-1);
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_top FROM (
SELECT amount, row_number() OVER (ORDER BY amount DESC) AS rn
FROM purchase WHERE biz_date = :h_bizdate) t WHERE t.rn <= 3;
if (sqlca.sqlcode < 0) { fprintf(stderr, "ac_concentration_batch TOP FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
EXEC SQL SELECT coalesce(sum(amount),0) INTO :h_total FROM purchase WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) { fprintf(stderr, "ac_concentration_batch TOT FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
ctx.top_sum = h_top;
ctx.total = h_total;
ctx.ratio_bps = acb_conc_ratio_bps(ctx.top_sum, ctx.total);
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> ac_concentration_batch COMMIT: bizdate=%s top3=%ld total=%ld ratio_bps=%ld\n",
ctx.biz_date, ctx.top_sum, ctx.total, ctx.ratio_bps);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,53 @@
/*
* ac_fxweight_batch.pgc - ac 해외매입 가중 평균 환율 배치 (XA).
*
* ATMI client: one global transaction; sums rate_bps weighted by krw_amount and
* the weight itself, then a C helper computes the weighted average bps.
* tpcommit drives XA 2PC. Usage: ac_fxweight_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "ac_fxweight_batch.h"
/* 가중합/가중치 나눗셈 (0 보호). */
long acb_fxw_divide(long num, long den)
{
if (den <= 0) return 0;
return num / den;
}
int main(int argc, char **argv)
{
ac_fxw_ctx_t ctx;
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_num = 0, h_den = 0;
EXEC SQL END DECLARE SECTION;
memset(&ctx, 0, sizeof(ctx));
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
strncpy(ctx.biz_date, bizdate, sizeof(ctx.biz_date)-1);
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(rate_bps * krw_amount),0), coalesce(sum(krw_amount),0)
INTO :h_num, :h_den FROM ac_fx WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) { fprintf(stderr, "ac_fxweight_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
ctx.num = h_num;
ctx.den = h_den;
ctx.avg_bps = acb_fxw_divide(ctx.num, ctx.den);
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> ac_fxweight_batch COMMIT: bizdate=%s weight=%ld avg_bps=%ld\n",
ctx.biz_date, ctx.den, ctx.avg_bps);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,63 @@
/*
* ac_summaryrebuild_batch.pgc - ac 가맹점 일집계 재구축 배치 (INSERT..SELECT + upsert + XA).
*
* ATMI client: one global transaction; an INSERT..SELECT..GROUP BY re-aggregates
* purchase into merchant_summary via ON CONFLICT DO UPDATE, then reads back the
* rebuilt gross. tpcommit drives XA 2PC. Usage: ac_summaryrebuild_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "ac_summaryrebuild_batch.h"
/* 반영 행수가 음수가 아니면 그대로 반환. */
long acb_rebuild_ok(long affected)
{
return (affected < 0) ? 0 : affected;
}
int main(int argc, char **argv)
{
ac_rebuild_ctx_t ctx;
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_gross = 0;
EXEC SQL END DECLARE SECTION;
memset(&ctx, 0, sizeof(ctx));
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
strncpy(ctx.biz_date, bizdate, sizeof(ctx.biz_date)-1);
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 merchant_summary
(merchant_id, biz_date, txn_count, gross_amount, fee_amount, net_amount)
SELECT merchant_id, biz_date, count(*), coalesce(sum(amount),0),
coalesce(sum(fee),0), coalesce(sum(net),0)
FROM purchase WHERE biz_date = :h_bizdate
GROUP BY merchant_id, biz_date
ON CONFLICT (merchant_id, biz_date) DO UPDATE
SET txn_count = EXCLUDED.txn_count,
gross_amount = EXCLUDED.gross_amount,
fee_amount = EXCLUDED.fee_amount,
net_amount = EXCLUDED.net_amount,
updated_at = now();
if (sqlca.sqlcode < 0) { fprintf(stderr, "ac_summaryrebuild_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
ctx.rows_affected = acb_rebuild_ok(sqlca.sqlerrd[2]);
EXEC SQL SELECT coalesce(sum(gross_amount),0) INTO :h_gross FROM merchant_summary WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) { fprintf(stderr, "ac_summaryrebuild_batch READ FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
ctx.total_gross = h_gross;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> ac_summaryrebuild_batch COMMIT: bizdate=%s rows=%ld gross=%ld\n",
ctx.biz_date, ctx.rows_affected, ctx.total_gross);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,49 @@
/*
* ac_unmatchpurge_batch.pgc - ac 미매입 로그 정리 배치 (구간 DELETE + XA).
*
* ATMI client: one global transaction; a range DELETE removes ac_unmatch rows
* older than the cutoff. The deleted count comes from sqlca.sqlerrd[2].
* tpcommit drives XA 2PC. Usage: ac_unmatchpurge_batch [cutoff-YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "ac_unmatchpurge_batch.h"
/* 배치 인자를 cutoff 문자열로 복사 (그대로 사용). */
void acb_purge_cutoff(const char *bizdate, char *out, int outsz)
{
strncpy(out, bizdate, outsz - 1);
out[outsz - 1] = 0;
}
int main(int argc, char **argv)
{
ac_purge_ctx_t ctx;
const char *cutoff = (argc > 1) ? argv[1] : "2026-07-01";
EXEC SQL BEGIN DECLARE SECTION;
char h_cut[16];
long h_deleted = 0;
EXEC SQL END DECLARE SECTION;
memset(&ctx, 0, sizeof(ctx));
acb_purge_cutoff(cutoff, ctx.cutoff, (int)sizeof(ctx.cutoff));
strncpy(h_cut, ctx.cutoff, sizeof(h_cut)-1); h_cut[sizeof(h_cut)-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 ac_unmatch WHERE biz_date < :h_cut;
if (sqlca.sqlcode < 0) { fprintf(stderr, "ac_unmatchpurge_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
h_deleted = sqlca.sqlerrd[2];
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
ctx.deleted = h_deleted;
printf(">>> ac_unmatchpurge_batch COMMIT: cutoff=%s deleted=%ld\n", ctx.cutoff, ctx.deleted);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,17 @@
/*
* ac_amountband_batch.h - copybook for ac_amountband_batch (XA client).
* CASE + . Kept in dbio/ for -I resolution.
*/
#ifndef AC_AMOUNTBAND_BATCH_H
#define AC_AMOUNTBAND_BATCH_H
typedef struct {
char biz_date[16];
long band_lo; /* < 5만 */
long band_mid; /* 5만~50만 */
long band_hi; /* >= 50만 */
} ac_band_ctx_t;
int acb_band_classify(long amount); /* 0=lo, 1=mid, 2=hi */
#endif /* AC_AMOUNTBAND_BATCH_H */

View file

@ -0,0 +1,14 @@
/*
* ac_cancel_casebucket_dbio.h - ac DB copybook (ac_cancel_casebucket_dbio, part of libacdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: CASE .
*/
#ifndef AC_CANCEL_CASEBUCKET_DBIO_H
#define AC_CANCEL_CASEBUCKET_DBIO_H
typedef struct { long small; long mid; long large; } ac_cancel_bucket_rec_t;
int acdb_cancel_buckets(const char *bizdate, ac_cancel_bucket_rec_t *out);
#endif /* AC_CANCEL_CASEBUCKET_DBIO_H */

View file

@ -0,0 +1,32 @@
/*
* ac_cancel_casebucket_dbio.pgc - ac 모듈 DB 접근 함수 세트 (ac_cancel_casebucket_dbio), archived into libacdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: CASE WHEN 금액 구간별 건수를 한 번의 집계로 산출.
*/
#include <string.h>
#include <userlog.h>
#include "ac_cancel_casebucket_dbio.h"
/* 취소 금액을 소액(<1만)/중액(<10만)/고액 3구간으로 CASE 버킷팅하여 out 에 채움. */
int acdb_cancel_buckets(const char *bizdate, ac_cancel_bucket_rec_t *out)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_sm = 0, h_md = 0, h_lg = 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(*) FILTER (WHERE amount < 10000),
count(*) FILTER (WHERE amount >= 10000 AND amount < 100000),
count(*) FILTER (WHERE amount >= 100000)
INTO :h_sm, :h_md, :h_lg
FROM ac_cancel WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) {
userlog("acdb_cancel_buckets FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return -1;
}
out->small = h_sm;
out->mid = h_md;
out->large = h_lg;
return 0;
}

View file

@ -0,0 +1,18 @@
/*
* ac_concentration_batch.h - copybook for ac_concentration_batch (XA client).
* Struct + helper prototype #include'd by the batch; kept in dbio/ so both ecpg
* (-I dbio) and gcc (CFLAGS -I dbio) resolve it. The helper is defined in the batch TU.
*/
#ifndef AC_CONCENTRATION_BATCH_H
#define AC_CONCENTRATION_BATCH_H
typedef struct {
char biz_date[16];
long top_sum; /* 상위 N 매입 금액 합 */
long total; /* 당일 총 매입 금액 */
long ratio_bps; /* 집중도 = top_sum/total (bps) */
} ac_conc_ctx_t;
long acb_conc_ratio_bps(long top_sum, long total);
#endif /* AC_CONCENTRATION_BATCH_H */

View file

@ -0,0 +1,14 @@
/*
* ac_edi_intoledger_dbio.h - ac DB copybook (ac_edi_intoledger_dbio, part of libacdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: INSERT INTO ledger SELECT ... FROM ac_edi.
*/
#ifndef AC_EDI_INTOLEDGER_DBIO_H
#define AC_EDI_INTOLEDGER_DBIO_H
typedef struct { long inserted; long total_amount; } ac_edi_post_rec_t;
long acdb_edi_post_to_ledger(const char *bizdate);
#endif /* AC_EDI_INTOLEDGER_DBIO_H */

View file

@ -0,0 +1,27 @@
/*
* ac_edi_intoledger_dbio.pgc - ac 모듈 DB 접근 함수 세트 (ac_edi_intoledger_dbio), archived into libacdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: INSERT INTO ledger SELECT (set-based 전기), 삽입 건수 반환.
*/
#include <string.h>
#include <userlog.h>
#include "ac_edi_intoledger_dbio.h"
/* 당일 EDI 문서를 RECON 원장 엔트리로 set-based 전기하고 삽입 건수를 반환. */
long acdb_edi_post_to_ledger(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long inserted = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL INSERT INTO ledger (ledger_id, purchase_id, entry_type, amount, biz_date)
SELECT nextval('ledger_seq'), 0, 'RECON', e.amount, e.biz_date
FROM ac_edi e WHERE e.biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) {
userlog("acdb_edi_post_to_ledger FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return -1;
}
inserted = sqlca.sqlerrd[2];
return inserted;
}

View file

@ -0,0 +1,14 @@
/*
* ac_feeadj_repeat_dbio.h - ac DB copybook (ac_feeadj_repeat_dbio, part of libacdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: GROUP BY purchase_id HAVING count(*) > 1 ( ).
*/
#ifndef AC_FEEADJ_REPEAT_DBIO_H
#define AC_FEEADJ_REPEAT_DBIO_H
typedef struct { long purchase_id; long adj_count; long delta_sum; } ac_feeadj_repeat_rec_t;
long acdb_feeadj_repeat_purchases(const char *bizdate, long *delta_out);
#endif /* AC_FEEADJ_REPEAT_DBIO_H */

View file

@ -0,0 +1,34 @@
/*
* ac_feeadj_repeat_dbio.pgc - ac 모듈 DB 접근 함수 세트 (ac_feeadj_repeat_dbio), archived into libacdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: GROUP BY purchase_id HAVING count(*) > 1 커서로 반복조정 매입 수 + delta 합.
*/
#include <string.h>
#include <userlog.h>
#include "ac_feeadj_repeat_dbio.h"
/* 수수료조정이 2회 이상 발생한 매입 수를 세고, delta 총합을 delta_out 에 반환. */
long acdb_feeadj_repeat_purchases(const char *bizdate, long *delta_out)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_pid, h_cnt, h_delta, purchases = 0, delta_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 frc CURSOR FOR
SELECT purchase_id, count(*), coalesce(sum(delta),0) FROM ac_fee_adj
WHERE biz_date = :h_bizdate
GROUP BY purchase_id HAVING count(*) > 1;
EXEC SQL OPEN frc;
if (sqlca.sqlcode < 0) return -1;
for (;;) {
EXEC SQL FETCH frc INTO :h_pid, :h_cnt, :h_delta;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE frc; return -1; }
purchases++;
delta_total += h_delta;
}
EXEC SQL CLOSE frc;
*delta_out = delta_total;
return purchases;
}

View file

@ -0,0 +1,14 @@
/*
* ac_fx_weightavg_dbio.h - ac DB copybook (ac_fx_weightavg_dbio, part of libacdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: KRW (bps).
*/
#ifndef AC_FX_WEIGHTAVG_DBIO_H
#define AC_FX_WEIGHTAVG_DBIO_H
typedef struct { long weighted_num; long weight; long avg_bps; } ac_fx_weight_rec_t;
long acdb_fx_weighted_rate(const char *bizdate);
#endif /* AC_FX_WEIGHTAVG_DBIO_H */

View file

@ -0,0 +1,25 @@
/*
* ac_fx_weightavg_dbio.pgc - ac 모듈 DB 접근 함수 세트 (ac_fx_weightavg_dbio), archived into libacdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: KRW 금액 가중 평균 환율 = sum(rate_bps*krw_amount)/sum(krw_amount).
*/
#include <string.h>
#include <userlog.h>
#include "ac_fx_weightavg_dbio.h"
/* 원화 환산액을 가중치로 하는 평균 환율(bps). 가중치 0 이면 0 반환. */
long acdb_fx_weighted_rate(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_num = 0, h_den = 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(rate_bps * krw_amount), 0),
coalesce(sum(krw_amount), 0)
INTO :h_num, :h_den FROM ac_fx WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) return -1;
if (h_den <= 0) return 0;
return h_num / h_den;
}

View file

@ -0,0 +1,17 @@
/*
* ac_fxweight_batch.h - copybook for ac_fxweight_batch (XA client).
* KRW + . Kept in dbio/ for -I resolution.
*/
#ifndef AC_FXWEIGHT_BATCH_H
#define AC_FXWEIGHT_BATCH_H
typedef struct {
char biz_date[16];
long num; /* sum(rate_bps*krw) */
long den; /* sum(krw) */
long avg_bps; /* 가중 평균 */
} ac_fxw_ctx_t;
long acb_fxw_divide(long num, long den);
#endif /* AC_FXWEIGHT_BATCH_H */

View file

@ -0,0 +1,14 @@
/*
* ac_install_corr_dbio.h - ac DB copybook (ac_install_corr_dbio, part of libacdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: - .
*/
#ifndef AC_INSTALL_CORR_DBIO_H
#define AC_INSTALL_CORR_DBIO_H
typedef struct { long install_id; long month_amount; } ac_install_corr_rec_t;
long acdb_install_above_own_avg(const char *bizdate);
#endif /* AC_INSTALL_CORR_DBIO_H */

View file

@ -0,0 +1,24 @@
/*
* ac_install_corr_dbio.pgc - ac 모듈 DB 접근 함수 세트 (ac_install_corr_dbio), archived into libacdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: 상관(correlated) 서브쿼리 - 동일 매입의 평균 월납입액을 초과한 회차 수.
*/
#include <string.h>
#include <userlog.h>
#include "ac_install_corr_dbio.h"
/* 같은 purchase_id 의 평균 month_amount 를 초과하는 할부 회차 건수. */
long acdb_install_above_own_avg(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(*) INTO :h_v FROM ac_install i
WHERE i.biz_date = :h_bizdate
AND i.month_amount > (SELECT avg(j.month_amount) FROM ac_install j
WHERE j.purchase_id = i.purchase_id);
if (sqlca.sqlcode < 0) return -1;
return h_v;
}

View file

@ -0,0 +1,14 @@
/*
* ac_merchant_bigday_dbio.h - ac DB copybook (ac_merchant_bigday_dbio, part of libacdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: GROUP BY merchant_id HAVING sum(amount) >= .
*/
#ifndef AC_MERCHANT_BIGDAY_DBIO_H
#define AC_MERCHANT_BIGDAY_DBIO_H
typedef struct { char merchant_id[64]; long gross; } ac_bigday_rec_t;
long acdb_bigday_merchant_count(const char *bizdate, long threshold);
#endif /* AC_MERCHANT_BIGDAY_DBIO_H */

View file

@ -0,0 +1,34 @@
/*
* ac_merchant_bigday_dbio.pgc - ac 모듈 DB 접근 함수 세트 (ac_merchant_bigday_dbio), archived into libacdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: GROUP BY ... HAVING sum(amount) >= 임계, 커서로 가맹점 계수 + 최대 group 합.
*/
#include <string.h>
#include <userlog.h>
#include "ac_merchant_bigday_dbio.h"
/* 당일 매입합이 threshold 이상인 가맹점 수를 세고, 최대 group 합은 peak 로 보고. */
long acdb_bigday_merchant_count(const char *bizdate, long threshold)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16], h_merch[64];
long h_gross, h_thr = threshold, cnt = 0, peak = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL DECLARE bdc CURSOR FOR
SELECT merchant_id, sum(amount) FROM purchase
WHERE biz_date = :h_bizdate
GROUP BY merchant_id HAVING sum(amount) >= :h_thr;
EXEC SQL OPEN bdc;
if (sqlca.sqlcode < 0) return -1;
for (;;) {
EXEC SQL FETCH bdc INTO :h_merch, :h_gross;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE bdc; return -1; }
cnt++;
if (h_gross > peak) peak = h_gross;
}
EXEC SQL CLOSE bdc;
if (peak < 0) return -1;
return cnt;
}

View file

@ -0,0 +1,15 @@
/*
* ac_purchase_incancel_dbio.h - ac DB copybook (ac_purchase_incancel_dbio, part of libacdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: WHERE purchase_id IN (SELECT ... FROM ac_cancel).
*/
#ifndef AC_PURCHASE_INCANCEL_DBIO_H
#define AC_PURCHASE_INCANCEL_DBIO_H
typedef struct { long cancelled_cnt; long cancelled_amount; } ac_incancel_rec_t;
long acdb_cancelled_purchase_count(const char *bizdate);
long acdb_cancelled_purchase_amount(const char *bizdate);
#endif /* AC_PURCHASE_INCANCEL_DBIO_H */

View file

@ -0,0 +1,38 @@
/*
* ac_purchase_incancel_dbio.pgc - ac 모듈 DB 접근 함수 세트 (ac_purchase_incancel_dbio), archived into libacdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: IN 서브셀렉트 - 취소 이력이 있는 매입 집계.
*/
#include <string.h>
#include <userlog.h>
#include "ac_purchase_incancel_dbio.h"
/* 취소 테이블에 존재하는 purchase_id 를 가진 매입 건수. */
long acdb_cancelled_purchase_count(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(*) INTO :h_v FROM purchase
WHERE biz_date = :h_bizdate
AND purchase_id IN (SELECT purchase_id FROM ac_cancel);
if (sqlca.sqlcode < 0) return -1;
return h_v;
}
/* 취소 이력이 있는 매입들의 원매입 금액 합계. */
long acdb_cancelled_purchase_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(amount),0) INTO :h_v FROM purchase
WHERE biz_date = :h_bizdate
AND purchase_id IN (SELECT purchase_id FROM ac_cancel);
if (sqlca.sqlcode < 0) return -1;
return h_v;
}

View file

@ -0,0 +1,14 @@
/*
* ac_purchase_rankpid_dbio.h - ac DB copybook (ac_purchase_rankpid_dbio, part of libacdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: window rank() .
*/
#ifndef AC_PURCHASE_RANKPID_DBIO_H
#define AC_PURCHASE_RANKPID_DBIO_H
typedef struct { long rk; long purchase_id; long amount; } ac_rankpid_rec_t;
long acdb_purchase_rank_of(const char *bizdate, long pid);
#endif /* AC_PURCHASE_RANKPID_DBIO_H */

View file

@ -0,0 +1,31 @@
/*
* ac_purchase_rankpid_dbio.pgc - ac 모듈 DB 접근 함수 세트 (ac_purchase_rankpid_dbio), archived into libacdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: rank() OVER (ORDER BY amount DESC) 커서 스캔 후 대상 pid 의 순위 반환.
*/
#include <string.h>
#include <userlog.h>
#include "ac_purchase_rankpid_dbio.h"
/* 금액 순위표에서 지정 매입(pid)의 rank 를 찾아 반환. 미발견 시 0. */
long acdb_purchase_rank_of(const char *bizdate, long pid)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_rk, h_pid, h_amt, target = pid, found = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL DECLARE rkc CURSOR FOR
SELECT rank() OVER (ORDER BY amount DESC) AS rk, purchase_id, amount
FROM purchase WHERE biz_date = :h_bizdate;
EXEC SQL OPEN rkc;
if (sqlca.sqlcode < 0) return -1;
for (;;) {
EXEC SQL FETCH rkc INTO :h_rk, :h_pid, :h_amt;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE rkc; return -1; }
if (h_pid == target) { found = h_rk; break; }
}
EXEC SQL CLOSE rkc;
return found;
}

View file

@ -0,0 +1,14 @@
/*
* ac_purchase_topn_dbio.h - ac DB copybook (ac_purchase_topn_dbio, part of libacdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: window row_number() N .
*/
#ifndef AC_PURCHASE_TOPN_DBIO_H
#define AC_PURCHASE_TOPN_DBIO_H
typedef struct { long rn; long purchase_id; long amount; } ac_topn_rec_t;
long acdb_topn_amount_sum(const char *bizdate, long topn);
#endif /* AC_PURCHASE_TOPN_DBIO_H */

View file

@ -0,0 +1,31 @@
/*
* ac_purchase_topn_dbio.pgc - ac 모듈 DB 접근 함수 세트 (ac_purchase_topn_dbio), archived into libacdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: window row_number() OVER (ORDER BY amount DESC) 상위 N 매입 금액 누적.
*/
#include <string.h>
#include <userlog.h>
#include "ac_purchase_topn_dbio.h"
/* 금액 내림차순 상위 topn 매입의 amount 합계를 커서 누적으로 반환. */
long acdb_topn_amount_sum(const char *bizdate, long topn)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_rn, h_amt, 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 tnc CURSOR FOR
SELECT row_number() OVER (ORDER BY amount DESC) AS rn, amount
FROM purchase WHERE biz_date = :h_bizdate;
EXEC SQL OPEN tnc;
if (sqlca.sqlcode < 0) return -1;
for (;;) {
EXEC SQL FETCH tnc INTO :h_rn, :h_amt;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE tnc; return -1; }
if (h_rn <= topn) acc += h_amt;
}
EXEC SQL CLOSE tnc;
return acc;
}

View file

@ -0,0 +1,15 @@
/*
* ac_settle_join_dbio.h - ac DB copybook (ac_settle_join_dbio, part of libacdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: purchase JOIN settlement .
*/
#ifndef AC_SETTLE_JOIN_DBIO_H
#define AC_SETTLE_JOIN_DBIO_H
typedef struct { char merchant_id[64]; long settled_net; long matched; } ac_settle_join_rec_t;
long acdb_settled_net_by_merchant(const char *merch, const char *bizdate);
long acdb_settled_match_count(const char *bizdate);
#endif /* AC_SETTLE_JOIN_DBIO_H */

View file

@ -0,0 +1,39 @@
/*
* ac_settle_join_dbio.pgc - ac 모듈 DB 접근 함수 세트 (ac_settle_join_dbio), archived into libacdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: purchase p JOIN settlement s ON p.purchase_id=s.purchase_id 집계.
*/
#include <string.h>
#include <userlog.h>
#include "ac_settle_join_dbio.h"
/* 특정 가맹점의 정산 완료된 매입 net 합계 (조인 기준 매입측 net). */
long acdb_settled_net_by_merchant(const char *merch, const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_merch[64], h_bizdate[16];
long h_v = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_merch, merch, sizeof(h_merch)-1); h_merch[sizeof(h_merch)-1] = 0;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL SELECT coalesce(sum(p.net),0) INTO :h_v
FROM purchase p JOIN settlement s ON p.purchase_id = s.purchase_id
WHERE p.merchant_id = :h_merch AND s.biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) return -1;
return h_v;
}
/* 당일 정산행과 매입행이 조인 매칭된 건수. */
long acdb_settled_match_count(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(*) INTO :h_v
FROM settlement s JOIN purchase p ON s.purchase_id = p.purchase_id
WHERE s.biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) return -1;
return h_v;
}

View file

@ -0,0 +1,14 @@
/*
* ac_settle_notexists_dbio.h - ac DB copybook (ac_settle_notexists_dbio, part of libacdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: NOT EXISTS .
*/
#ifndef AC_SETTLE_NOTEXISTS_DBIO_H
#define AC_SETTLE_NOTEXISTS_DBIO_H
typedef struct { long purchase_id; long net; } ac_settle_gap_rec_t;
long acdb_unsettled_count(const char *bizdate);
#endif /* AC_SETTLE_NOTEXISTS_DBIO_H */

View file

@ -0,0 +1,23 @@
/*
* ac_settle_notexists_dbio.pgc - ac 모듈 DB 접근 함수 세트 (ac_settle_notexists_dbio), archived into libacdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: NOT EXISTS 상관 서브쿼리 - 대사완료(M) 이나 정산행이 없는 매입.
*/
#include <string.h>
#include <userlog.h>
#include "ac_settle_notexists_dbio.h"
/* 상태가 대사완료(M) 이지만 settlement 에 대응행이 없는 매입 건수. */
long acdb_unsettled_count(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(*) INTO :h_v FROM purchase p
WHERE p.biz_date = :h_bizdate AND p.status = 'M'
AND NOT EXISTS (SELECT 1 FROM settlement s WHERE s.purchase_id = p.purchase_id);
if (sqlca.sqlcode < 0) return -1;
return h_v;
}

View file

@ -0,0 +1,14 @@
/*
* ac_summary_rebuild_dbio.h - ac DB copybook (ac_summary_rebuild_dbio, part of libacdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: INSERT INTO ... SELECT ... GROUP BY ... ON CONFLICT DO UPDATE ( upsert).
*/
#ifndef AC_SUMMARY_REBUILD_DBIO_H
#define AC_SUMMARY_REBUILD_DBIO_H
typedef struct { char biz_date[16]; long merchants; } ac_summary_rebuild_rec_t;
long acdb_summary_rebuild_from_purchase(const char *bizdate);
#endif /* AC_SUMMARY_REBUILD_DBIO_H */

View file

@ -0,0 +1,36 @@
/*
* ac_summary_rebuild_dbio.pgc - ac 모듈 DB 접근 함수 세트 (ac_summary_rebuild_dbio), archived into libacdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: INSERT INTO merchant_summary SELECT ... GROUP BY ... ON CONFLICT DO UPDATE (재집계 upsert).
*/
#include <string.h>
#include <userlog.h>
#include "ac_summary_rebuild_dbio.h"
/* 당일 purchase 를 가맹점별로 재집계하여 merchant_summary 에 upsert. 반영 행수 반환. */
long acdb_summary_rebuild_from_purchase(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long affected = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL INSERT INTO merchant_summary
(merchant_id, biz_date, txn_count, gross_amount, fee_amount, net_amount)
SELECT merchant_id, biz_date, count(*), coalesce(sum(amount),0),
coalesce(sum(fee),0), coalesce(sum(net),0)
FROM purchase WHERE biz_date = :h_bizdate
GROUP BY merchant_id, biz_date
ON CONFLICT (merchant_id, biz_date) DO UPDATE
SET txn_count = EXCLUDED.txn_count,
gross_amount = EXCLUDED.gross_amount,
fee_amount = EXCLUDED.fee_amount,
net_amount = EXCLUDED.net_amount,
updated_at = now();
if (sqlca.sqlcode < 0) {
userlog("acdb_summary_rebuild_from_purchase FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return -1;
}
affected = sqlca.sqlerrd[2];
return affected;
}

View file

@ -0,0 +1,16 @@
/*
* ac_summaryrebuild_batch.h - copybook for ac_summaryrebuild_batch (XA client).
* merchant_summary + . Kept in dbio/ for -I resolution.
*/
#ifndef AC_SUMMARYREBUILD_BATCH_H
#define AC_SUMMARYREBUILD_BATCH_H
typedef struct {
char biz_date[16];
long rows_affected;
long total_gross;
} ac_rebuild_ctx_t;
long acb_rebuild_ok(long affected);
#endif /* AC_SUMMARYREBUILD_BATCH_H */

View file

@ -0,0 +1,15 @@
/*
* ac_taxinv_spread_dbio.h - ac DB copybook (ac_taxinv_spread_dbio, part of libacdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: max(vat)-min(vat) .
*/
#ifndef AC_TAXINV_SPREAD_DBIO_H
#define AC_TAXINV_SPREAD_DBIO_H
typedef struct { long vat_max; long vat_min; long spread; } ac_taxinv_spread_rec_t;
long acdb_taxinv_vat_spread(const char *bizdate);
long acdb_taxinv_count(const char *bizdate);
#endif /* AC_TAXINV_SPREAD_DBIO_H */

View file

@ -0,0 +1,35 @@
/*
* ac_taxinv_spread_dbio.pgc - ac 모듈 DB 접근 함수 세트 (ac_taxinv_spread_dbio), archived into libacdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: 세금계산서 VAT 최대-최소 스프레드 및 건수.
*/
#include <string.h>
#include <userlog.h>
#include "ac_taxinv_spread_dbio.h"
/* 당일 세금계산서 VAT 의 max-min 스프레드. 데이터 없으면 0. */
long acdb_taxinv_vat_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(vat),0), coalesce(min(vat),0)
INTO :h_max, :h_min FROM ac_tax_invoice WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) return -1;
return h_max - h_min;
}
/* 당일 발행된 세금계산서 건수. */
long acdb_taxinv_count(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(*) INTO :h_v FROM ac_tax_invoice WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) return -1;
return h_v;
}

View file

@ -0,0 +1,14 @@
/*
* ac_unmatch_purge_dbio.h - ac DB copybook (ac_unmatch_purge_dbio, part of libacdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: DELETE ... WHERE biz_date < ( ).
*/
#ifndef AC_UNMATCH_PURGE_DBIO_H
#define AC_UNMATCH_PURGE_DBIO_H
typedef struct { char cutoff[16]; long deleted; } ac_unmatch_purge_rec_t;
long acdb_unmatch_purge_before(const char *cutoff);
#endif /* AC_UNMATCH_PURGE_DBIO_H */

View file

@ -0,0 +1,25 @@
/*
* ac_unmatch_purge_dbio.pgc - ac 모듈 DB 접근 함수 세트 (ac_unmatch_purge_dbio), archived into libacdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: DELETE 구간 삭제 - 기준일 이전 미매입 로그 정리, 삭제 건수 반환.
*/
#include <string.h>
#include <userlog.h>
#include "ac_unmatch_purge_dbio.h"
/* cutoff(YYYY-MM-DD) 이전의 ac_unmatch 로그를 삭제하고 삭제 건수를 반환. */
long acdb_unmatch_purge_before(const char *cutoff)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_cut[16];
long deleted = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_cut, cutoff, sizeof(h_cut)-1); h_cut[sizeof(h_cut)-1] = 0;
EXEC SQL DELETE FROM ac_unmatch WHERE biz_date < :h_cut;
if (sqlca.sqlcode < 0) {
userlog("acdb_unmatch_purge_before FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return -1;
}
deleted = sqlca.sqlerrd[2];
return deleted;
}

View file

@ -0,0 +1,15 @@
/*
* ac_unmatchpurge_batch.h - copybook for ac_unmatchpurge_batch (XA client).
* + . Kept in dbio/ for -I resolution.
*/
#ifndef AC_UNMATCHPURGE_BATCH_H
#define AC_UNMATCHPURGE_BATCH_H
typedef struct {
char cutoff[16];
long deleted;
} ac_purge_ctx_t;
void acb_purge_cutoff(const char *bizdate, char *out, int outsz);
#endif /* AC_UNMATCHPURGE_BATCH_H */

View file

@ -0,0 +1,14 @@
/*
* ac_wht_distinct_dbio.h - ac DB copybook (ac_wht_distinct_dbio, part of libacdbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: count(DISTINCT purchase_id) + sum(tax_amount).
*/
#ifndef AC_WHT_DISTINCT_DBIO_H
#define AC_WHT_DISTINCT_DBIO_H
typedef struct { long distinct_purchases; long total_tax; } ac_wht_distinct_rec_t;
int acdb_wht_distinct_summary(const char *bizdate, ac_wht_distinct_rec_t *out);
#endif /* AC_WHT_DISTINCT_DBIO_H */

View file

@ -0,0 +1,27 @@
/*
* ac_wht_distinct_dbio.pgc - ac 모듈 DB 접근 함수 세트 (ac_wht_distinct_dbio), archived into libacdbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: count(DISTINCT purchase_id) 와 sum(tax_amount) 를 한 번에 산출하여 구조체로 반환.
*/
#include <string.h>
#include <userlog.h>
#include "ac_wht_distinct_dbio.h"
/* 원천징수가 걸린 서로 다른 매입 수와 총 원천세액을 out 에 채운다. */
int acdb_wht_distinct_summary(const char *bizdate, ac_wht_distinct_rec_t *out)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_dp = 0, h_tax = 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 purchase_id), coalesce(sum(tax_amount),0)
INTO :h_dp, :h_tax FROM ac_wht WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) {
userlog("acdb_wht_distinct_summary FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return -1;
}
out->distinct_purchases = h_dp;
out->total_tax = h_tax;
return 0;
}

View file

@ -0,0 +1,53 @@
/*
* au_approverate_batch.pgc - au 일일 승인율 배치 (FILTER 집계 + XA).
*
* ATMI client: one global transaction; a FILTER aggregate counts approved vs.
* total authorizations, then a C helper computes the approval rate in bps.
* tpcommit drives XA 2PC. Usage: au_approverate_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "au_approverate_batch.h"
/* 승인율(bps) = approved/total * 10000. total<=0 이면 0. */
long aub_rate_bps(long approved, long total)
{
if (total <= 0) return 0;
return (approved * 10000L) / total;
}
int main(int argc, char **argv)
{
au_rate_ctx_t ctx;
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_appr = 0, h_total = 0;
EXEC SQL END DECLARE SECTION;
memset(&ctx, 0, sizeof(ctx));
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
strncpy(ctx.biz_date, bizdate, sizeof(ctx.biz_date)-1);
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(*) FILTER (WHERE status = 'A'), count(*)
INTO :h_appr, :h_total FROM au_authorization WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) { fprintf(stderr, "au_approverate_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
ctx.approved = h_appr;
ctx.total = h_total;
ctx.rate_bps = aub_rate_bps(ctx.approved, ctx.total);
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> au_approverate_batch COMMIT: bizdate=%s approved=%ld total=%ld rate_bps=%ld\n",
ctx.biz_date, ctx.approved, ctx.total, ctx.rate_bps);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,52 @@
/*
* au_fraudpurge_batch.pgc - au 저점수 부정로그 정리 배치 (복합조건 DELETE + XA).
*
* ATMI client: one global transaction; a range DELETE removes fraud-log rows that
* are both older than the cutoff and below the score floor. Deleted count comes
* from sqlca.sqlerrd[2]. Usage: au_fraudpurge_batch [cutoff] [min_score]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "au_fraudpurge_batch.h"
/* 최소 점수 하한 (음수 방지). */
long aub_fpurge_floor(long score)
{
return (score < 0) ? 0 : score;
}
int main(int argc, char **argv)
{
au_fpurge_ctx_t ctx;
const char *cutoff = (argc > 1) ? argv[1] : "2026-07-01";
long min_score = (argc > 2) ? atol(argv[2]) : 50;
EXEC SQL BEGIN DECLARE SECTION;
char h_cut[16];
long h_min, h_deleted = 0;
EXEC SQL END DECLARE SECTION;
memset(&ctx, 0, sizeof(ctx));
strncpy(ctx.cutoff, cutoff, sizeof(ctx.cutoff)-1);
ctx.min_score = aub_fpurge_floor(min_score);
strncpy(h_cut, ctx.cutoff, sizeof(h_cut)-1); h_cut[sizeof(h_cut)-1] = 0;
h_min = ctx.min_score;
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 au_fraud_log WHERE biz_date < :h_cut AND score < :h_min;
if (sqlca.sqlcode < 0) { fprintf(stderr, "au_fraudpurge_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
h_deleted = sqlca.sqlerrd[2];
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
ctx.deleted = h_deleted;
printf(">>> au_fraudpurge_batch COMMIT: cutoff=%s min_score=%ld deleted=%ld\n",
ctx.cutoff, ctx.min_score, ctx.deleted);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,58 @@
/*
* au_scorebucket_batch.pgc - au 부정거래 점수대 분포 배치 (CASE + XA).
*
* ATMI client: one global transaction; a CASE-summed aggregate splits fraud-log
* scores into three bands. The C helper maps a score to a label. tpcommit drives
* XA 2PC. Usage: au_scorebucket_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "au_scorebucket_batch.h"
/* 점수 → 라벨. */
const char *aub_score_label(long score)
{
if (score < 50) return "LOW";
if (score < 80) return "MID";
return "HIGH";
}
int main(int argc, char **argv)
{
au_score_ctx_t ctx;
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_low = 0, h_mid = 0, h_high = 0;
EXEC SQL END DECLARE SECTION;
memset(&ctx, 0, sizeof(ctx));
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
strncpy(ctx.biz_date, bizdate, sizeof(ctx.biz_date)-1);
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 score < 50 THEN 1 ELSE 0 END),0),
coalesce(sum(CASE WHEN score >= 50 AND score < 80 THEN 1 ELSE 0 END),0),
coalesce(sum(CASE WHEN score >= 80 THEN 1 ELSE 0 END),0)
INTO :h_low, :h_mid, :h_high
FROM au_fraud_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) { fprintf(stderr, "au_scorebucket_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
ctx.low = h_low;
ctx.mid = h_mid;
ctx.high = h_high;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> au_scorebucket_batch COMMIT: bizdate=%s low=%ld mid=%ld high=%ld peak=%s\n",
ctx.biz_date, ctx.low, ctx.mid, ctx.high, aub_score_label(ctx.high > 0 ? 80 : 0));
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,65 @@
/*
* au_summaryrebuild_batch.pgc - au 가맹점 일집계 재구축 배치 (INSERT..SELECT FILTER upsert + XA).
*
* ATMI client: one global transaction; an INSERT..SELECT with FILTER re-aggregates
* au_authorization into au_summary via ON CONFLICT DO UPDATE, then reads back the
* approve total. tpcommit drives XA 2PC. Usage: au_summaryrebuild_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "au_summaryrebuild_batch.h"
/* 음수 반영행수는 0 으로 클립. */
long aub_rebuild_clip(long affected)
{
return (affected < 0) ? 0 : affected;
}
int main(int argc, char **argv)
{
au_rebuild_ctx_t ctx;
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_appr = 0;
EXEC SQL END DECLARE SECTION;
memset(&ctx, 0, sizeof(ctx));
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
strncpy(ctx.biz_date, bizdate, sizeof(ctx.biz_date)-1);
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 au_summary
(merchant_id, biz_date, auth_count, approve_count, decline_count, auth_amount)
SELECT merchant_id, biz_date, count(*),
count(*) FILTER (WHERE status = 'A'),
count(*) FILTER (WHERE status = 'D'),
coalesce(sum(amount),0)
FROM au_authorization WHERE biz_date = :h_bizdate
GROUP BY merchant_id, biz_date
ON CONFLICT (merchant_id, biz_date) DO UPDATE
SET auth_count = EXCLUDED.auth_count,
approve_count = EXCLUDED.approve_count,
decline_count = EXCLUDED.decline_count,
auth_amount = EXCLUDED.auth_amount,
updated_at = now();
if (sqlca.sqlcode < 0) { fprintf(stderr, "au_summaryrebuild_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
ctx.rows_affected = aub_rebuild_clip(sqlca.sqlerrd[2]);
EXEC SQL SELECT coalesce(sum(approve_count),0) INTO :h_appr FROM au_summary WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) { fprintf(stderr, "au_summaryrebuild_batch READ FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
ctx.total_approved = h_appr;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> au_summaryrebuild_batch COMMIT: bizdate=%s rows=%ld approved=%ld\n",
ctx.biz_date, ctx.rows_affected, ctx.total_approved);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,62 @@
/*
* au_topcard_batch.pgc - au 최고 지출 카드 배치 (window + XA).
*
* ATMI client: one global transaction; a windowed subquery ranks card spend and
* picks the rn=1 card. tpcommit drives XA 2PC. Usage: au_topcard_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "au_topcard_batch.h"
/* 지출액이 양수면 유효한 결과로 간주. */
int aub_topcard_valid(long spend)
{
return (spend > 0) ? 1 : 0;
}
int main(int argc, char **argv)
{
au_topcard_ctx_t ctx;
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16], h_card[24];
long h_spend = 0;
EXEC SQL END DECLARE SECTION;
memset(&ctx, 0, sizeof(ctx));
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
strncpy(h_card, "NONE", sizeof(h_card)-1); h_card[sizeof(h_card)-1] = 0;
strncpy(ctx.biz_date, bizdate, sizeof(ctx.biz_date)-1);
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 card_no, spend FROM (
SELECT card_no, sum(amount) AS spend,
row_number() OVER (ORDER BY sum(amount) DESC) AS rn
FROM au_authorization WHERE biz_date = :h_bizdate
GROUP BY card_no) t WHERE t.rn = 1;
if (sqlca.sqlcode < 0) { fprintf(stderr, "au_topcard_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (sqlca.sqlcode != 100) {
EXEC SQL SELECT card_no, spend INTO :h_card, :h_spend FROM (
SELECT card_no, sum(amount) AS spend,
row_number() OVER (ORDER BY sum(amount) DESC) AS rn
FROM au_authorization WHERE biz_date = :h_bizdate
GROUP BY card_no) t WHERE t.rn = 1;
if (sqlca.sqlcode < 0) { fprintf(stderr, "au_topcard_batch FETCH FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
}
strncpy(ctx.top_card, h_card, sizeof(ctx.top_card)-1);
ctx.top_spend = h_spend;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> au_topcard_batch COMMIT: bizdate=%s top_card=%s spend=%ld valid=%d\n",
ctx.biz_date, ctx.top_card, ctx.top_spend, aub_topcard_valid(ctx.top_spend));
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,17 @@
/*
* au_approverate_batch.h - copybook for au_approverate_batch (XA client).
* + . Kept in dbio/ for -I resolution.
*/
#ifndef AU_APPROVERATE_BATCH_H
#define AU_APPROVERATE_BATCH_H
typedef struct {
char biz_date[16];
long approved;
long total;
long rate_bps; /* approved/total (bps) */
} au_rate_ctx_t;
long aub_rate_bps(long approved, long total);
#endif /* AU_APPROVERATE_BATCH_H */

View file

@ -0,0 +1,14 @@
/*
* au_auth_distinctcard_dbio.h - au DB copybook (au_auth_distinctcard_dbio, part of libaudbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: count(DISTINCT card_no) + count(DISTINCT merchant_id).
*/
#ifndef AU_AUTH_DISTINCTCARD_DBIO_H
#define AU_AUTH_DISTINCTCARD_DBIO_H
typedef struct { long distinct_cards; long distinct_merchants; } au_distinct_rec_t;
int audb_auth_distinct_counts(const char *bizdate, au_distinct_rec_t *out);
#endif /* AU_AUTH_DISTINCTCARD_DBIO_H */

View file

@ -0,0 +1,28 @@
/*
* au_auth_distinctcard_dbio.pgc - au 모듈 DB 접근 함수 세트 (au_auth_distinctcard_dbio), archived into libaudbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: 승인건에서 서로 다른 카드/가맹점 수를 count(DISTINCT) 로 동시 산출.
*/
#include <string.h>
#include <userlog.h>
#include "au_auth_distinctcard_dbio.h"
/* 당일 승인(A) 건에서 사용된 서로 다른 카드/가맹점 수를 out 에 채운다. */
int audb_auth_distinct_counts(const char *bizdate, au_distinct_rec_t *out)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_cards = 0, h_merch = 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 card_no), count(DISTINCT merchant_id)
INTO :h_cards, :h_merch FROM au_authorization
WHERE biz_date = :h_bizdate AND status = 'A';
if (sqlca.sqlcode < 0) {
userlog("audb_auth_distinct_counts FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return -1;
}
out->distinct_cards = h_cards;
out->distinct_merchants = h_merch;
return 0;
}

View file

@ -0,0 +1,14 @@
/*
* au_auth_incancel_dbio.h - au DB copybook (au_auth_incancel_dbio, part of libaudbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: WHERE auth_id IN (SELECT auth_id FROM au_cancel WHERE ...).
*/
#ifndef AU_AUTH_INCANCEL_DBIO_H
#define AU_AUTH_INCANCEL_DBIO_H
typedef struct { long auth_id; long amount; } au_incancel_rec_t;
long audb_fullcancelled_auth_amount(const char *bizdate);
#endif /* AU_AUTH_INCANCEL_DBIO_H */

View file

@ -0,0 +1,23 @@
/*
* au_auth_incancel_dbio.pgc - au 모듈 DB 접근 함수 세트 (au_auth_incancel_dbio), archived into libaudbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: IN 서브셀렉트(내부 WHERE 조건 포함) - 전액취소된 승인 금액 합.
*/
#include <string.h>
#include <userlog.h>
#include "au_auth_incancel_dbio.h"
/* 전액취소(FULL) 이력이 있는 승인들의 원승인 금액 합계. */
long audb_fullcancelled_auth_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(amount),0) INTO :h_v FROM au_authorization
WHERE biz_date = :h_bizdate
AND auth_id IN (SELECT auth_id FROM au_cancel WHERE cancel_type = 'FULL');
if (sqlca.sqlcode < 0) return -1;
return h_v;
}

View file

@ -0,0 +1,14 @@
/*
* au_auth_rankcard_dbio.h - au DB copybook (au_auth_rankcard_dbio, part of libaudbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: window rank() N위 .
*/
#ifndef AU_AUTH_RANKCARD_DBIO_H
#define AU_AUTH_RANKCARD_DBIO_H
typedef struct { long rk; long auth_id; long amount; } au_rankcard_rec_t;
long audb_auth_amount_at_rank(const char *bizdate, long target_rank);
#endif /* AU_AUTH_RANKCARD_DBIO_H */

View file

@ -0,0 +1,31 @@
/*
* au_auth_rankcard_dbio.pgc - au 모듈 DB 접근 함수 세트 (au_auth_rankcard_dbio), archived into libaudbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: rank() OVER (ORDER BY amount DESC) 커서에서 목표 순위의 금액 반환.
*/
#include <string.h>
#include <userlog.h>
#include "au_auth_rankcard_dbio.h"
/* 금액 순위표에서 target_rank 위에 해당하는 승인 금액을 반환. 없으면 0. */
long audb_auth_amount_at_rank(const char *bizdate, long target_rank)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_rk, h_aid, h_amt, tr = target_rank, hit = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL DECLARE arc CURSOR FOR
SELECT rank() OVER (ORDER BY amount DESC) AS rk, auth_id, amount
FROM au_authorization WHERE biz_date = :h_bizdate AND status = 'A';
EXEC SQL OPEN arc;
if (sqlca.sqlcode < 0) return -1;
for (;;) {
EXEC SQL FETCH arc INTO :h_rk, :h_aid, :h_amt;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE arc; return -1; }
if (h_rk == tr) { hit = h_amt; break; }
}
EXEC SQL CLOSE arc;
return hit;
}

View file

@ -0,0 +1,14 @@
/*
* au_auth_topcard_dbio.h - au DB copybook (au_auth_topcard_dbio, part of libaudbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: window row_number() PARTITION BY card_no ( ).
*/
#ifndef AU_AUTH_TOPCARD_DBIO_H
#define AU_AUTH_TOPCARD_DBIO_H
typedef struct { long rn; char card_no[24]; long amount; } au_topcard_rec_t;
long audb_topcard_distinct(const char *bizdate, long *peak_out);
#endif /* AU_AUTH_TOPCARD_DBIO_H */

View file

@ -0,0 +1,35 @@
/*
* au_auth_topcard_dbio.pgc - au 모듈 DB 접근 함수 세트 (au_auth_topcard_dbio), archived into libaudbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: row_number() OVER (PARTITION BY card_no ORDER BY amount DESC) 커서 스캔.
*/
#include <string.h>
#include <userlog.h>
#include "au_auth_topcard_dbio.h"
/* 카드별 최고 승인행(rn=1)만 세어 서로 다른 카드 수를 반환하고 최고 금액은 peak_out. */
long audb_topcard_distinct(const char *bizdate, long *peak_out)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16], h_card[24];
long h_rn, h_amt, cards = 0, peak = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL DECLARE tcc CURSOR FOR
SELECT row_number() OVER (PARTITION BY card_no ORDER BY amount DESC) AS rn, card_no, amount
FROM au_authorization WHERE biz_date = :h_bizdate;
EXEC SQL OPEN tcc;
if (sqlca.sqlcode < 0) return -1;
for (;;) {
EXEC SQL FETCH tcc INTO :h_rn, :h_card, :h_amt;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE tcc; return -1; }
if (h_rn == 1) {
cards++;
if (h_amt > peak) peak = h_amt;
}
}
EXEC SQL CLOSE tcc;
*peak_out = peak;
return cards;
}

View file

@ -0,0 +1,14 @@
/*
* au_cancel_corr_dbio.h - au DB copybook (au_cancel_corr_dbio, part of libaudbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: - .
*/
#ifndef AU_CANCEL_CORR_DBIO_H
#define AU_CANCEL_CORR_DBIO_H
typedef struct { long cancel_id; long amount; } au_cancel_corr_rec_t;
long audb_cancel_over_peer_max(const char *bizdate);
#endif /* AU_CANCEL_CORR_DBIO_H */

View file

@ -0,0 +1,23 @@
/*
* au_cancel_corr_dbio.pgc - au 모듈 DB 접근 함수 세트 (au_cancel_corr_dbio), archived into libaudbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: 상관(correlated) 서브쿼리 + 부가조건 - 동일 승인 부분취소 평균 초과 건수.
*/
#include <string.h>
#include <userlog.h>
#include "au_cancel_corr_dbio.h"
/* 부분취소(PARTIAL) 중, 같은 auth_id 의 평균 취소액을 초과하는 건수. */
long audb_cancel_over_peer_max(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(*) INTO :h_v FROM au_cancel c
WHERE c.biz_date = :h_bizdate AND c.cancel_type = 'PARTIAL'
AND c.amount > (SELECT avg(d.amount) FROM au_cancel d WHERE d.auth_id = c.auth_id);
if (sqlca.sqlcode < 0) return -1;
return h_v;
}

View file

@ -0,0 +1,14 @@
/*
* au_capture_join_dbio.h - au DB copybook (au_capture_join_dbio, part of libaudbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: au_authorization JOIN au_cancel .
*/
#ifndef AU_CAPTURE_JOIN_DBIO_H
#define AU_CAPTURE_JOIN_DBIO_H
typedef struct { long auth_id; long cancel_amount; } au_capture_join_rec_t;
long audb_cancelled_capture_amount(const char *bizdate);
#endif /* AU_CAPTURE_JOIN_DBIO_H */

View file

@ -0,0 +1,23 @@
/*
* au_capture_join_dbio.pgc - au 모듈 DB 접근 함수 세트 (au_capture_join_dbio), archived into libaudbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: au_authorization a JOIN au_cancel c ON a.auth_id=c.auth_id 집계 (매입확정 취소액).
*/
#include <string.h>
#include <userlog.h>
#include "au_capture_join_dbio.h"
/* 매입확정(M)/정산반영(S) 승인에 대한 취소 금액 합계 (조인 기준 취소측 amount). */
long audb_cancelled_capture_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(c.amount),0) INTO :h_v
FROM au_authorization a JOIN au_cancel c ON a.auth_id = c.auth_id
WHERE c.biz_date = :h_bizdate AND a.status IN ('M', 'S');
if (sqlca.sqlcode < 0) return -1;
return h_v;
}

View file

@ -0,0 +1,14 @@
/*
* au_fraud_casescore_dbio.h - au DB copybook (au_fraud_casescore_dbio, part of libaudbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: CASE WHEN score sum ( ).
*/
#ifndef AU_FRAUD_CASESCORE_DBIO_H
#define AU_FRAUD_CASESCORE_DBIO_H
typedef struct { long weighted; long high; } au_casescore_rec_t;
long audb_fraud_high_weight(const char *bizdate);
#endif /* AU_FRAUD_CASESCORE_DBIO_H */

View file

@ -0,0 +1,25 @@
/*
* au_fraud_casescore_dbio.pgc - au 모듈 DB 접근 함수 세트 (au_fraud_casescore_dbio), archived into libaudbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: CASE WHEN 으로 점수 구간별 가중치를 합산하여 위험 점수 총합 반환.
*/
#include <string.h>
#include <userlog.h>
#include "au_fraud_casescore_dbio.h"
/* score 구간에 3/2/1 가중치를 부여한 CASE 합계(위험 가중 점수)를 반환. */
long audb_fraud_high_weight(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 score >= 80 THEN 3
WHEN score >= 50 THEN 2
ELSE 1 END), 0)
INTO :h_v FROM au_fraud_log WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) return -1;
return h_v;
}

View file

@ -0,0 +1,14 @@
/*
* au_fraud_intolog_dbio.h - au DB copybook (au_fraud_intolog_dbio, part of libaudbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: INSERT INTO au_fraud_log SELECT ... FROM au_authorization.
*/
#ifndef AU_FRAUD_INTOLOG_DBIO_H
#define AU_FRAUD_INTOLOG_DBIO_H
typedef struct { long flagged; long threshold; } au_autoflag_rec_t;
long audb_autoflag_high_amount(const char *bizdate, long threshold);
#endif /* AU_FRAUD_INTOLOG_DBIO_H */

View file

@ -0,0 +1,28 @@
/*
* au_fraud_intolog_dbio.pgc - au 모듈 DB 접근 함수 세트 (au_fraud_intolog_dbio), archived into libaudbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: INSERT INTO au_fraud_log SELECT (고액 승인 자동 플래그), 삽입 건수 반환.
*/
#include <string.h>
#include <userlog.h>
#include "au_fraud_intolog_dbio.h"
/* threshold 초과 고액 승인을 부정거래 로그에 자동 등록(set-based)하고 건수 반환. */
long audb_autoflag_high_amount(const char *bizdate, long threshold)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_thr = threshold, flagged = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL INSERT INTO au_fraud_log (fraud_id, auth_id, card_no, score, reason, biz_date)
SELECT nextval('au_fraud_seq'), a.auth_id, a.card_no, 90, 'AUTOFLAG_HIGH', a.biz_date
FROM au_authorization a
WHERE a.biz_date = :h_bizdate AND a.amount > :h_thr;
if (sqlca.sqlcode < 0) {
userlog("audb_autoflag_high_amount FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return -1;
}
flagged = sqlca.sqlerrd[2];
return flagged;
}

View file

@ -0,0 +1,14 @@
/*
* au_fraud_purge_dbio.h - au DB copybook (au_fraud_purge_dbio, part of libaudbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: DELETE ... WHERE biz_date < AND score < ( ).
*/
#ifndef AU_FRAUD_PURGE_DBIO_H
#define AU_FRAUD_PURGE_DBIO_H
typedef struct { char cutoff[16]; long min_score; long deleted; } au_fraud_purge_rec_t;
long audb_fraud_purge_lowscore(const char *cutoff, long min_score);
#endif /* AU_FRAUD_PURGE_DBIO_H */

View file

@ -0,0 +1,25 @@
/*
* au_fraud_purge_dbio.pgc - au 모듈 DB 접근 함수 세트 (au_fraud_purge_dbio), archived into libaudbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: DELETE 복합조건 구간 삭제 - 기준일 이전 저점수 부정로그 정리.
*/
#include <string.h>
#include <userlog.h>
#include "au_fraud_purge_dbio.h"
/* cutoff 이전이면서 점수가 min_score 미만인 부정로그를 삭제하고 삭제 건수를 반환. */
long audb_fraud_purge_lowscore(const char *cutoff, long min_score)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_cut[16];
long h_min = min_score, deleted = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_cut, cutoff, sizeof(h_cut)-1); h_cut[sizeof(h_cut)-1] = 0;
EXEC SQL DELETE FROM au_fraud_log WHERE biz_date < :h_cut AND score < :h_min;
if (sqlca.sqlcode < 0) {
userlog("audb_fraud_purge_lowscore FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return -1;
}
deleted = sqlca.sqlerrd[2];
return deleted;
}

View file

@ -0,0 +1,16 @@
/*
* au_fraudpurge_batch.h - copybook for au_fraudpurge_batch (XA client).
* + . Kept in dbio/ for -I resolution.
*/
#ifndef AU_FRAUDPURGE_BATCH_H
#define AU_FRAUDPURGE_BATCH_H
typedef struct {
char cutoff[16];
long min_score;
long deleted;
} au_fpurge_ctx_t;
long aub_fpurge_floor(long score);
#endif /* AU_FRAUDPURGE_BATCH_H */

View file

@ -0,0 +1,14 @@
/*
* au_limit_spread_dbio.h - au DB copybook (au_limit_spread_dbio, part of libaudbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: max/min/avg 3 .
*/
#ifndef AU_LIMIT_SPREAD_DBIO_H
#define AU_LIMIT_SPREAD_DBIO_H
typedef struct { long lim_max; long lim_min; long used_avg; } au_limit_spread_rec_t;
long audb_limit_spread(long *used_avg_out);
#endif /* AU_LIMIT_SPREAD_DBIO_H */

View file

@ -0,0 +1,22 @@
/*
* au_limit_spread_dbio.pgc - au 모듈 DB 접근 함수 세트 (au_limit_spread_dbio), archived into libaudbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: 한 번의 SELECT 로 max/min/avg 3중 집계 - 한도 스프레드 + 평균 사용액.
*/
#include <string.h>
#include <userlog.h>
#include "au_limit_spread_dbio.h"
/* 활성 카드 한도의 max-min 스프레드를 반환하고 평균 사용액을 used_avg_out 에 채운다. */
long audb_limit_spread(long *used_avg_out)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_max = 0, h_min = 0, h_avg = 0;
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT coalesce(max(daily_limit),0), coalesce(min(daily_limit),0),
coalesce(avg(used_amount),0)::bigint
INTO :h_max, :h_min, :h_avg FROM card_limit WHERE status = 'ACTIVE';
if (sqlca.sqlcode < 0) return -1;
*used_avg_out = h_avg;
return h_max - h_min;
}

View file

@ -0,0 +1,14 @@
/*
* au_merchant_active_dbio.h - au DB copybook (au_merchant_active_dbio, part of libaudbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: GROUP BY merchant_id HAVING count(*) >= .
*/
#ifndef AU_MERCHANT_ACTIVE_DBIO_H
#define AU_MERCHANT_ACTIVE_DBIO_H
typedef struct { char merchant_id[64]; long auths; } au_active_rec_t;
long audb_active_merchant_count(const char *bizdate, long min_auths);
#endif /* AU_MERCHANT_ACTIVE_DBIO_H */

View file

@ -0,0 +1,32 @@
/*
* au_merchant_active_dbio.pgc - au 모듈 DB 접근 함수 세트 (au_merchant_active_dbio), archived into libaudbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: GROUP BY merchant_id HAVING count(*) >= 최소건수, 커서로 활성 가맹점 계수.
*/
#include <string.h>
#include <userlog.h>
#include "au_merchant_active_dbio.h"
/* 당일 승인 건수가 min_auths 이상인 가맹점 수. */
long audb_active_merchant_count(const char *bizdate, long min_auths)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16], h_merch[64];
long h_cnt, h_min = min_auths, active = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL DECLARE amc CURSOR FOR
SELECT merchant_id, count(*) FROM au_authorization
WHERE biz_date = :h_bizdate
GROUP BY merchant_id HAVING count(*) >= :h_min;
EXEC SQL OPEN amc;
if (sqlca.sqlcode < 0) return -1;
for (;;) {
EXEC SQL FETCH amc INTO :h_merch, :h_cnt;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE amc; return -1; }
active++;
}
EXEC SQL CLOSE amc;
return active;
}

View file

@ -0,0 +1,14 @@
/*
* au_preauth_notexists_dbio.h - au DB copybook (au_preauth_notexists_dbio, part of libaudbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: NOT EXISTS .
*/
#ifndef AU_PREAUTH_NOTEXISTS_DBIO_H
#define AU_PREAUTH_NOTEXISTS_DBIO_H
typedef struct { long preauth_id; long amount; } au_preauth_gap_rec_t;
long audb_preauth_unconfirmed(const char *bizdate);
#endif /* AU_PREAUTH_NOTEXISTS_DBIO_H */

View file

@ -0,0 +1,24 @@
/*
* au_preauth_notexists_dbio.pgc - au 모듈 DB 접근 함수 세트 (au_preauth_notexists_dbio), archived into libaudbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: NOT EXISTS 상관 서브쿼리(복합조건) - 대응 승인이 없는 미확정 예비승인.
*/
#include <string.h>
#include <userlog.h>
#include "au_preauth_notexists_dbio.h"
/* 상태 P(예비) 이면서 같은 카드/금액의 승인행이 없는 예비승인 건수. */
long audb_preauth_unconfirmed(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(*) INTO :h_v FROM au_preauth p
WHERE p.biz_date = :h_bizdate AND p.status = 'P'
AND NOT EXISTS (SELECT 1 FROM au_authorization a
WHERE a.card_no = p.card_no AND a.amount = p.amount);
if (sqlca.sqlcode < 0) return -1;
return h_v;
}

View file

@ -0,0 +1,17 @@
/*
* au_scorebucket_batch.h - copybook for au_scorebucket_batch (XA client).
* CASE + . Kept in dbio/ for -I resolution.
*/
#ifndef AU_SCOREBUCKET_BATCH_H
#define AU_SCOREBUCKET_BATCH_H
typedef struct {
char biz_date[16];
long low; /* < 50 */
long mid; /* 50~79 */
long high; /* >= 80 */
} au_score_ctx_t;
const char *aub_score_label(long score);
#endif /* AU_SCOREBUCKET_BATCH_H */

View file

@ -0,0 +1,14 @@
/*
* au_summary_rebuild_dbio.h - au DB copybook (au_summary_rebuild_dbio, part of libaudbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: INSERT INTO au_summary SELECT ... FILTER ... GROUP BY ... ON CONFLICT DO UPDATE.
*/
#ifndef AU_SUMMARY_REBUILD_DBIO_H
#define AU_SUMMARY_REBUILD_DBIO_H
typedef struct { char biz_date[16]; long merchants; } au_summary_rebuild_rec_t;
long audb_summary_rebuild_from_auth(const char *bizdate);
#endif /* AU_SUMMARY_REBUILD_DBIO_H */

View file

@ -0,0 +1,38 @@
/*
* au_summary_rebuild_dbio.pgc - au 모듈 DB 접근 함수 세트 (au_summary_rebuild_dbio), archived into libaudbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: INSERT INTO au_summary SELECT count(*) FILTER (...) GROUP BY ... ON CONFLICT DO UPDATE.
*/
#include <string.h>
#include <userlog.h>
#include "au_summary_rebuild_dbio.h"
/* 당일 au_authorization 을 가맹점별 승인/거절/금액으로 재집계하여 au_summary 에 upsert. */
long audb_summary_rebuild_from_auth(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long affected = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL INSERT INTO au_summary
(merchant_id, biz_date, auth_count, approve_count, decline_count, auth_amount)
SELECT merchant_id, biz_date, count(*),
count(*) FILTER (WHERE status = 'A'),
count(*) FILTER (WHERE status = 'D'),
coalesce(sum(amount),0)
FROM au_authorization WHERE biz_date = :h_bizdate
GROUP BY merchant_id, biz_date
ON CONFLICT (merchant_id, biz_date) DO UPDATE
SET auth_count = EXCLUDED.auth_count,
approve_count = EXCLUDED.approve_count,
decline_count = EXCLUDED.decline_count,
auth_amount = EXCLUDED.auth_amount,
updated_at = now();
if (sqlca.sqlcode < 0) {
userlog("audb_summary_rebuild_from_auth FAIL [%d] %s", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc);
return -1;
}
affected = sqlca.sqlerrd[2];
return affected;
}

View file

@ -0,0 +1,14 @@
/*
* au_summary_riskmerch_dbio.h - au DB copybook (au_summary_riskmerch_dbio, part of libaudbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: GROUP BY merchant_id HAVING sum(decline) > sum(approve).
*/
#ifndef AU_SUMMARY_RISKMERCH_DBIO_H
#define AU_SUMMARY_RISKMERCH_DBIO_H
typedef struct { char merchant_id[64]; long declines; long approves; } au_riskmerch_rec_t;
long audb_decline_heavy_merchants(const char *bizdate);
#endif /* AU_SUMMARY_RISKMERCH_DBIO_H */

View file

@ -0,0 +1,32 @@
/*
* au_summary_riskmerch_dbio.pgc - au 모듈 DB 접근 함수 세트 (au_summary_riskmerch_dbio), archived into libaudbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: GROUP BY merchant_id HAVING sum(decline_count) > sum(approve_count) 커서 계수.
*/
#include <string.h>
#include <userlog.h>
#include "au_summary_riskmerch_dbio.h"
/* 거절 건수가 승인 건수보다 많은(위험) 가맹점 수를 GROUP BY/HAVING 커서로 계수. */
long audb_decline_heavy_merchants(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16], h_merch[64];
long h_dec, h_app, risky = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL DECLARE rmc CURSOR FOR
SELECT merchant_id, sum(decline_count), sum(approve_count) FROM au_summary
WHERE biz_date = :h_bizdate
GROUP BY merchant_id HAVING sum(decline_count) > sum(approve_count);
EXEC SQL OPEN rmc;
if (sqlca.sqlcode < 0) return -1;
for (;;) {
EXEC SQL FETCH rmc INTO :h_merch, :h_dec, :h_app;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE rmc; return -1; }
risky++;
}
EXEC SQL CLOSE rmc;
return risky;
}

View file

@ -0,0 +1,14 @@
/*
* au_summary_weightavg_dbio.h - au DB copybook (au_summary_weightavg_dbio, part of libaudbio.a).
* ECPG functions; run on the caller's XA branch (no EXEC SQL CONNECT).
* Return convention: >=0 ok, -1 = SQL error.
* Shape: .
*/
#ifndef AU_SUMMARY_WEIGHTAVG_DBIO_H
#define AU_SUMMARY_WEIGHTAVG_DBIO_H
typedef struct { char merchant_id[64]; long auth_count; long auth_amount; } au_weight_rec_t;
long audb_summary_weighted_ticket(const char *bizdate);
#endif /* AU_SUMMARY_WEIGHTAVG_DBIO_H */

View file

@ -0,0 +1,33 @@
/*
* au_summary_weightavg_dbio.pgc - au 모듈 DB 접근 함수 세트 (au_summary_weightavg_dbio), archived into libaudbio.a.
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
* Shape: 커서로 가맹점별 행을 순회하며 건수 가중 평균 티켓을 C 측에서 누산/산출.
*/
#include <string.h>
#include <userlog.h>
#include "au_summary_weightavg_dbio.h"
/* 건수(auth_count)를 가중치로 하는 평균 승인 티켓을 커서 누산으로 계산. */
long audb_summary_weighted_ticket(const char *bizdate)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16], h_merch[64];
long h_cnt, h_amt;
EXEC SQL END DECLARE SECTION;
long num = 0, den = 0;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
EXEC SQL DECLARE swc CURSOR FOR
SELECT merchant_id, auth_count, auth_amount FROM au_summary WHERE biz_date = :h_bizdate;
EXEC SQL OPEN swc;
if (sqlca.sqlcode < 0) return -1;
for (;;) {
EXEC SQL FETCH swc INTO :h_merch, :h_cnt, :h_amt;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE swc; return -1; }
num += h_amt;
den += h_cnt;
}
EXEC SQL CLOSE swc;
if (den <= 0) return 0;
return num / den;
}

View file

@ -0,0 +1,16 @@
/*
* au_summaryrebuild_batch.h - copybook for au_summaryrebuild_batch (XA client).
* au_summary + . Kept in dbio/ for -I resolution.
*/
#ifndef AU_SUMMARYREBUILD_BATCH_H
#define AU_SUMMARYREBUILD_BATCH_H
typedef struct {
char biz_date[16];
long rows_affected;
long total_approved;
} au_rebuild_ctx_t;
long aub_rebuild_clip(long affected);
#endif /* AU_SUMMARYREBUILD_BATCH_H */

View file

@ -0,0 +1,16 @@
/*
* au_topcard_batch.h - copybook for au_topcard_batch (XA client).
* + . Kept in dbio/ for -I resolution.
*/
#ifndef AU_TOPCARD_BATCH_H
#define AU_TOPCARD_BATCH_H
typedef struct {
char biz_date[16];
char top_card[24];
long top_spend;
} au_topcard_ctx_t;
int aub_topcard_valid(long spend);
#endif /* AU_TOPCARD_BATCH_H */

View file

@ -0,0 +1,50 @@
/*
* cl_gap_batch.pgc - cl 일마감 저장건수 vs 실매입 대사 배치 (커서 + XA).
*
* period_key 프리픽스의 DAILY 마감을 커서로 훑어, 각 마감의 저장 txn_count 와
* 실제 purchase 건수를 비교하여 불일치 마감 수를 집계한다. 전 구간 ONE global XA.
* host 변수는 전용 카피북 cl_gap_cpy.h 를 EXEC SQL INCLUDE 로 가져온다.
* Usage: cl_gap_batch [YYYY-MM]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
const char *prefix = (argc > 1) ? argv[1] : "2026-07";
long checked = 0, mismatch = 0;
EXEC SQL INCLUDE cl_gap_cpy;
strncpy(g_prefix, prefix, sizeof(g_prefix)-1); g_prefix[sizeof(g_prefix)-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 cgap CURSOR FOR
SELECT close_id, to_char(biz_date,'YYYY-MM-DD'), txn_count FROM cl_close_log
WHERE close_type = 'DAILY' AND period_key LIKE :g_prefix || '%' AND status <> 'X'
ORDER BY biz_date;
EXEC SQL OPEN cgap;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH cgap INTO :g_cid, :g_bizdate, :g_stored;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE cgap; tpabort(0); return 1; }
EXEC SQL SELECT count(*) INTO :g_actual FROM purchase WHERE biz_date = :g_bizdate;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE cgap; tpabort(0); return 1; }
checked++;
if (g_stored != g_actual) mismatch++;
}
EXEC SQL CLOSE cgap;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> cl_gap_batch COMMIT: prefix=%s 검증=%ld 불일치=%ld\n", prefix, checked, mismatch);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,8 @@
/* cl_gap_cpy.h - cl_gap_batch 전용 카피북 (host 변수 선언, EXEC SQL INCLUDE 대상). */
EXEC SQL BEGIN DECLARE SECTION;
char g_prefix[16];
char g_bizdate[16];
long g_cid;
long g_stored;
long g_actual;
EXEC SQL END DECLARE SECTION;

View file

@ -0,0 +1,35 @@
/*
* cl_purgeold_batch.pgc - cl 오래된 마감 스냅샷 정리 배치 (DELETE range + XA).
*
* cutoff 이전(biz_date < cutoff) 마감 스냅샷을 한 문장으로 삭제하고 삭제행수를
* sqlca.sqlerrd[2] 로 확인한다. ONE global XA transaction 하에서 수행.
* host 변수는 전용 카피북 cl_purgeold_cpy.h 를 EXEC SQL INCLUDE.
* Usage: cl_purgeold_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
const char *cutoff = (argc > 1) ? argv[1] : "2026-01-01";
EXEC SQL INCLUDE cl_purgeold_cpy;
strncpy(p_cutoff, cutoff, sizeof(p_cutoff)-1); p_cutoff[sizeof(p_cutoff)-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 cl_snapshot WHERE biz_date < :p_cutoff;
if (sqlca.sqlcode < 0) { fprintf(stderr, "DELETE FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
p_deleted = (long) sqlca.sqlerrd[2];
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> cl_purgeold_batch COMMIT: cutoff=%s 삭제=%ld건\n", cutoff, p_deleted);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,5 @@
/* cl_purgeold_cpy.h - cl_purgeold_batch 전용 카피북 (host 변수 선언). */
EXEC SQL BEGIN DECLARE SECTION;
char p_cutoff[16];
long p_deleted;
EXEC SQL END DECLARE SECTION;

View file

@ -0,0 +1,47 @@
/*
* cl_relock_batch.pgc - cl 완료 기간 일괄 잠금 배치 (커서 + upsert + XA).
*
* status='C' 로 마감된 고유 period_key 를 커서로 훑어 cl_period_lock 에
* upsert(ON CONFLICT) 하여 기간을 잠근다. 전 구간 ONE global XA transaction.
* host 변수는 전용 카피북 cl_relock_cpy.h 를 EXEC SQL INCLUDE.
* Usage: cl_relock_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
long locked = 0;
(void) argc; (void) argv;
EXEC SQL INCLUDE cl_relock_cpy;
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 crel CURSOR FOR
SELECT DISTINCT period_key FROM cl_close_log WHERE status = 'C'
ORDER BY period_key;
EXEC SQL OPEN crel;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH crel INTO :r_period;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE crel; tpabort(0); return 1; }
EXEC SQL INSERT INTO cl_period_lock (period_key, locked) VALUES (:r_period, true)
ON CONFLICT (period_key) DO UPDATE SET locked = true, locked_at = now();
if (sqlca.sqlcode < 0) { fprintf(stderr, "UPSERT FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE crel; tpabort(0); return 1; }
locked++;
}
EXEC SQL CLOSE crel;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> cl_relock_batch COMMIT: 잠금기간=%ld\n", locked);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,4 @@
/* cl_relock_cpy.h - cl_relock_batch 전용 카피북 (host 변수 선언). */
EXEC SQL BEGIN DECLARE SECTION;
char r_period[16];
EXEC SQL END DECLARE SECTION;

View file

@ -0,0 +1,51 @@
/*
* cl_reweigh_batch.pgc - cl 마감 총액 스냅샷 재계산 배치 (커서 + UPDATE + XA).
*
* period_key 프리픽스 마감을 커서로 훑어, 각 마감의 스냅샷 net 합을 다시 계산하여
* cl_close_log.total_amount 를 갱신한다. 전 구간 ONE global XA transaction.
* host 변수는 전용 카피북 cl_reweigh_cpy.h 를 EXEC SQL INCLUDE.
* Usage: cl_reweigh_batch [YYYY-MM]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
const char *prefix = (argc > 1) ? argv[1] : "2026-07";
long updated = 0;
EXEC SQL INCLUDE cl_reweigh_cpy;
strncpy(w_prefix, prefix, sizeof(w_prefix)-1); w_prefix[sizeof(w_prefix)-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 crw CURSOR FOR
SELECT close_id FROM cl_close_log
WHERE period_key LIKE :w_prefix || '%' AND status <> 'X'
ORDER BY close_id;
EXEC SQL OPEN crw;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH crw INTO :w_cid;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE crw; tpabort(0); return 1; }
EXEC SQL SELECT coalesce(sum(net_amount),0) INTO :w_sum FROM cl_snapshot WHERE close_id = :w_cid;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE crw; tpabort(0); return 1; }
EXEC SQL UPDATE cl_close_log SET total_amount = :w_sum, updated_at = now() WHERE close_id = :w_cid;
if (sqlca.sqlcode < 0) { fprintf(stderr, "UPDATE FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE crw; tpabort(0); return 1; }
updated++;
}
EXEC SQL CLOSE crw;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> cl_reweigh_batch COMMIT: prefix=%s 재계산=%ld건\n", prefix, updated);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,6 @@
/* cl_reweigh_cpy.h - cl_reweigh_batch 전용 카피북 (host 변수 선언). */
EXEC SQL BEGIN DECLARE SECTION;
char w_prefix[16];
long w_cid;
long w_sum;
EXEC SQL END DECLARE SECTION;

View file

@ -0,0 +1,39 @@
/*
* cl_tierstat_batch.pgc - cl 마감 총액 구간 분포 배치 (CASE 집계 + XA).
*
* period_key 프리픽스 마감을 총액 소/중/대 구간으로 CASE 분류하여 각 구간 건수를
* 한 행으로 집계해 보고한다. ONE global XA transaction (read-committed).
* host 변수는 전용 카피북 cl_tierstat_cpy.h 를 EXEC SQL INCLUDE.
* Usage: cl_tierstat_batch [YYYY-MM]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
int main(int argc, char **argv)
{
const char *prefix = (argc > 1) ? argv[1] : "2026-07";
EXEC SQL INCLUDE cl_tierstat_cpy;
strncpy(t_prefix, prefix, sizeof(t_prefix)-1); t_prefix[sizeof(t_prefix)-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 total_amount < 1000000 THEN 1 ELSE 0 END),0),
coalesce(sum(CASE WHEN total_amount >= 1000000 AND total_amount < 100000000 THEN 1 ELSE 0 END),0),
coalesce(sum(CASE WHEN total_amount >= 100000000 THEN 1 ELSE 0 END),0)
INTO :t_lo, :t_mid, :t_hi FROM cl_close_log
WHERE period_key LIKE :t_prefix || '%' AND status <> 'X';
if (sqlca.sqlcode < 0) { fprintf(stderr, "AGG 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(">>> cl_tierstat_batch COMMIT: prefix=%s 소=%ld 중=%ld 대=%ld\n", prefix, t_lo, t_mid, t_hi);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,7 @@
/* cl_tierstat_cpy.h - cl_tierstat_batch 전용 카피북 (host 변수 선언). */
EXEC SQL BEGIN DECLARE SECTION;
char t_prefix[16];
long t_lo;
long t_mid;
long t_hi;
EXEC SQL END DECLARE SECTION;

View file

@ -0,0 +1,9 @@
/*
* cl_corr_sub_dbio.h - cl DB copybook (cl_corr_sub_dbio, part of libcldbio.a).
* (correlated subquery + cursor).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef CL_CORR_SUB_DBIO_H
#define CL_CORR_SUB_DBIO_H
long clqdb_corr_max_snap(const char *ctype);
#endif /* CL_CORR_SUB_DBIO_H */

View file

@ -0,0 +1,34 @@
/*
* cl_corr_sub_dbio.pgc - cl 모듈 DB 접근 함수 (cl_corr_sub_dbio), archived into libcldbio.a.
* 마감별 스냅샷 수 상관 서브쿼리 순회 최대치 (correlated subquery + cursor).
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "cl_corr_sub_dbio.h"
/* 각 마감의 스냅샷 수를 상관 서브쿼리로 뽑아 커서로 훑어 최대값 반환. */
long clqdb_corr_max_snap(const char *ctype)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_type[16];
long h_cid, h_snaps;
EXEC SQL END DECLARE SECTION;
long peak = 0;
strncpy(h_type, ctype, sizeof(h_type)-1); h_type[sizeof(h_type)-1] = 0;
EXEC SQL DECLARE ccs CURSOR FOR
SELECT c.close_id,
(SELECT count(*) FROM cl_snapshot s WHERE s.close_id = c.close_id)
FROM cl_close_log c WHERE c.close_type = :h_type AND c.status <> 'X'
ORDER BY c.close_id;
EXEC SQL OPEN ccs;
if (sqlca.sqlcode < 0) return -1;
for (;;) {
EXEC SQL FETCH ccs INTO :h_cid, :h_snaps;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE ccs; return -1; }
if (h_snaps > peak) peak = h_snaps;
}
EXEC SQL CLOSE ccs;
return peak;
}

View file

@ -0,0 +1,9 @@
/*
* cl_lock_upsert_dbio.h - cl DB copybook (cl_lock_upsert_dbio, part of libcldbio.a).
* upsert (ON CONFLICT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef CL_LOCK_UPSERT_DBIO_H
#define CL_LOCK_UPSERT_DBIO_H
int cldb_lock_upsert(const char *period, int locked);
#endif /* CL_LOCK_UPSERT_DBIO_H */

View file

@ -0,0 +1,24 @@
/*
* cl_lock_upsert_dbio.pgc - cl 모듈 DB 접근 함수 (cl_lock_upsert_dbio), archived into libcldbio.a.
* 기간잠금 upsert (ON CONFLICT).
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "cl_lock_upsert_dbio.h"
/* cl_period_lock 에 잠금 여부를 upsert. */
int cldb_lock_upsert(const char *period, int locked)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_period[16];
int h_locked = locked;
EXEC SQL END DECLARE SECTION;
strncpy(h_period, period, sizeof(h_period)-1); h_period[sizeof(h_period)-1] = 0;
EXEC SQL INSERT INTO cl_period_lock (period_key, locked)
VALUES (:h_period, :h_locked)
ON CONFLICT (period_key) DO UPDATE
SET locked = EXCLUDED.locked, locked_at = now();
if (sqlca.sqlcode < 0) { userlog("cldb_lock_upsert FAIL [%d]", sqlca.sqlcode); return -1; }
return 0;
}

View file

@ -0,0 +1,9 @@
/*
* cl_minmax_dbio.h - cl DB copybook (cl_minmax_dbio, part of libcldbio.a).
* / (min/max).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef CL_MINMAX_DBIO_H
#define CL_MINMAX_DBIO_H
int clqdb_minmax(const char *prefix, long *lo, long *hi);
#endif /* CL_MINMAX_DBIO_H */

View file

@ -0,0 +1,24 @@
/*
* cl_minmax_dbio.pgc - cl 모듈 DB 접근 함수 (cl_minmax_dbio), archived into libcldbio.a.
* 기간 프리픽스 마감 총액 최소/최대 (min/max).
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "cl_minmax_dbio.h"
/* period_key 프리픽스 마감의 total_amount 최소/최대를 반환. */
int clqdb_minmax(const char *prefix, long *lo, long *hi)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_prefix[16];
long h_lo = 0, h_hi = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_prefix, prefix, sizeof(h_prefix)-1); h_prefix[sizeof(h_prefix)-1] = 0;
EXEC SQL SELECT coalesce(min(total_amount),0), coalesce(max(total_amount),0)
INTO :h_lo, :h_hi FROM cl_close_log
WHERE period_key LIKE :h_prefix || '%' AND status <> 'X';
if (sqlca.sqlcode < 0) return -1;
*lo = h_lo; *hi = h_hi;
return 0;
}

View file

@ -0,0 +1,9 @@
/*
* cl_snap_distinct_dbio.h - cl DB copybook (cl_snap_distinct_dbio, part of libcldbio.a).
* (count DISTINCT).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef CL_SNAP_DISTINCT_DBIO_H
#define CL_SNAP_DISTINCT_DBIO_H
long clqdb_snap_distinct(long cid);
#endif /* CL_SNAP_DISTINCT_DBIO_H */

View file

@ -0,0 +1,20 @@
/*
* cl_snap_distinct_dbio.pgc - cl 모듈 DB 접근 함수 (cl_snap_distinct_dbio), archived into libcldbio.a.
* 마감 스냅샷 고유 가맹점 수 (count DISTINCT).
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "cl_snap_distinct_dbio.h"
/* close_id 스냅샷의 고유 가맹점 수. */
long clqdb_snap_distinct(long cid)
{
EXEC SQL BEGIN DECLARE SECTION;
long h_cid = cid, h_v = 0;
EXEC SQL END DECLARE SECTION;
EXEC SQL SELECT count(DISTINCT merchant_id) INTO :h_v FROM cl_snapshot
WHERE close_id = :h_cid;
if (sqlca.sqlcode < 0) return -1;
return h_v;
}

View file

@ -0,0 +1,9 @@
/*
* cl_snap_in_dbio.h - cl DB copybook (cl_snap_in_dbio, part of libcldbio.a).
* net (IN ).
* Return convention: >=0 ok, -1 = SQL error.
*/
#ifndef CL_SNAP_IN_DBIO_H
#define CL_SNAP_IN_DBIO_H
long clqdb_snap_in_net(const char *ctype);
#endif /* CL_SNAP_IN_DBIO_H */

View file

@ -0,0 +1,23 @@
/*
* cl_snap_in_dbio.pgc - cl 모듈 DB 접근 함수 (cl_snap_in_dbio), archived into libcldbio.a.
* 특정 마감유형에 속한 스냅샷 net 합 (IN 서브셀렉트).
* ECPG (EXEC SQL) functions; run on the caller's XA branch. No EXEC SQL CONNECT.
*/
#include <string.h>
#include <userlog.h>
#include "cl_snap_in_dbio.h"
/* close_type 에 해당하는 close_id 집합(IN)의 스냅샷 net 합계. */
long clqdb_snap_in_net(const char *ctype)
{
EXEC SQL BEGIN DECLARE SECTION;
char h_type[16];
long h_v = 0;
EXEC SQL END DECLARE SECTION;
strncpy(h_type, ctype, sizeof(h_type)-1); h_type[sizeof(h_type)-1] = 0;
EXEC SQL SELECT coalesce(sum(net_amount),0) INTO :h_v FROM cl_snapshot
WHERE close_id IN (SELECT close_id FROM cl_close_log
WHERE close_type = :h_type AND status <> 'X');
if (sqlca.sqlcode < 0) return -1;
return h_v;
}

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