고도화: 전 모듈 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:
parent
05ad8a3064
commit
fc16ea64c8
422 changed files with 8717 additions and 0 deletions
60
app/src/ac/batch/ac_amountband_batch.pgc
Normal file
60
app/src/ac/batch/ac_amountband_batch.pgc
Normal 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;
|
||||
}
|
||||
58
app/src/ac/batch/ac_concentration_batch.pgc
Normal file
58
app/src/ac/batch/ac_concentration_batch.pgc
Normal 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;
|
||||
}
|
||||
53
app/src/ac/batch/ac_fxweight_batch.pgc
Normal file
53
app/src/ac/batch/ac_fxweight_batch.pgc
Normal 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;
|
||||
}
|
||||
63
app/src/ac/batch/ac_summaryrebuild_batch.pgc
Normal file
63
app/src/ac/batch/ac_summaryrebuild_batch.pgc
Normal 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;
|
||||
}
|
||||
49
app/src/ac/batch/ac_unmatchpurge_batch.pgc
Normal file
49
app/src/ac/batch/ac_unmatchpurge_batch.pgc
Normal 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;
|
||||
}
|
||||
17
app/src/ac/dbio/ac_amountband_batch.h
Normal file
17
app/src/ac/dbio/ac_amountband_batch.h
Normal 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 */
|
||||
14
app/src/ac/dbio/ac_cancel_casebucket_dbio.h
Normal file
14
app/src/ac/dbio/ac_cancel_casebucket_dbio.h
Normal 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 */
|
||||
32
app/src/ac/dbio/ac_cancel_casebucket_dbio.pgc
Normal file
32
app/src/ac/dbio/ac_cancel_casebucket_dbio.pgc
Normal 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;
|
||||
}
|
||||
18
app/src/ac/dbio/ac_concentration_batch.h
Normal file
18
app/src/ac/dbio/ac_concentration_batch.h
Normal 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 */
|
||||
14
app/src/ac/dbio/ac_edi_intoledger_dbio.h
Normal file
14
app/src/ac/dbio/ac_edi_intoledger_dbio.h
Normal 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 */
|
||||
27
app/src/ac/dbio/ac_edi_intoledger_dbio.pgc
Normal file
27
app/src/ac/dbio/ac_edi_intoledger_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/ac/dbio/ac_feeadj_repeat_dbio.h
Normal file
14
app/src/ac/dbio/ac_feeadj_repeat_dbio.h
Normal 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 */
|
||||
34
app/src/ac/dbio/ac_feeadj_repeat_dbio.pgc
Normal file
34
app/src/ac/dbio/ac_feeadj_repeat_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/ac/dbio/ac_fx_weightavg_dbio.h
Normal file
14
app/src/ac/dbio/ac_fx_weightavg_dbio.h
Normal 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 */
|
||||
25
app/src/ac/dbio/ac_fx_weightavg_dbio.pgc
Normal file
25
app/src/ac/dbio/ac_fx_weightavg_dbio.pgc
Normal 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;
|
||||
}
|
||||
17
app/src/ac/dbio/ac_fxweight_batch.h
Normal file
17
app/src/ac/dbio/ac_fxweight_batch.h
Normal 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 */
|
||||
14
app/src/ac/dbio/ac_install_corr_dbio.h
Normal file
14
app/src/ac/dbio/ac_install_corr_dbio.h
Normal 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 */
|
||||
24
app/src/ac/dbio/ac_install_corr_dbio.pgc
Normal file
24
app/src/ac/dbio/ac_install_corr_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/ac/dbio/ac_merchant_bigday_dbio.h
Normal file
14
app/src/ac/dbio/ac_merchant_bigday_dbio.h
Normal 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 */
|
||||
34
app/src/ac/dbio/ac_merchant_bigday_dbio.pgc
Normal file
34
app/src/ac/dbio/ac_merchant_bigday_dbio.pgc
Normal 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;
|
||||
}
|
||||
15
app/src/ac/dbio/ac_purchase_incancel_dbio.h
Normal file
15
app/src/ac/dbio/ac_purchase_incancel_dbio.h
Normal 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 */
|
||||
38
app/src/ac/dbio/ac_purchase_incancel_dbio.pgc
Normal file
38
app/src/ac/dbio/ac_purchase_incancel_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/ac/dbio/ac_purchase_rankpid_dbio.h
Normal file
14
app/src/ac/dbio/ac_purchase_rankpid_dbio.h
Normal 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 */
|
||||
31
app/src/ac/dbio/ac_purchase_rankpid_dbio.pgc
Normal file
31
app/src/ac/dbio/ac_purchase_rankpid_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/ac/dbio/ac_purchase_topn_dbio.h
Normal file
14
app/src/ac/dbio/ac_purchase_topn_dbio.h
Normal 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 */
|
||||
31
app/src/ac/dbio/ac_purchase_topn_dbio.pgc
Normal file
31
app/src/ac/dbio/ac_purchase_topn_dbio.pgc
Normal 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;
|
||||
}
|
||||
15
app/src/ac/dbio/ac_settle_join_dbio.h
Normal file
15
app/src/ac/dbio/ac_settle_join_dbio.h
Normal 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 */
|
||||
39
app/src/ac/dbio/ac_settle_join_dbio.pgc
Normal file
39
app/src/ac/dbio/ac_settle_join_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/ac/dbio/ac_settle_notexists_dbio.h
Normal file
14
app/src/ac/dbio/ac_settle_notexists_dbio.h
Normal 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 */
|
||||
23
app/src/ac/dbio/ac_settle_notexists_dbio.pgc
Normal file
23
app/src/ac/dbio/ac_settle_notexists_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/ac/dbio/ac_summary_rebuild_dbio.h
Normal file
14
app/src/ac/dbio/ac_summary_rebuild_dbio.h
Normal 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 */
|
||||
36
app/src/ac/dbio/ac_summary_rebuild_dbio.pgc
Normal file
36
app/src/ac/dbio/ac_summary_rebuild_dbio.pgc
Normal 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;
|
||||
}
|
||||
16
app/src/ac/dbio/ac_summaryrebuild_batch.h
Normal file
16
app/src/ac/dbio/ac_summaryrebuild_batch.h
Normal 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 */
|
||||
15
app/src/ac/dbio/ac_taxinv_spread_dbio.h
Normal file
15
app/src/ac/dbio/ac_taxinv_spread_dbio.h
Normal 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 */
|
||||
35
app/src/ac/dbio/ac_taxinv_spread_dbio.pgc
Normal file
35
app/src/ac/dbio/ac_taxinv_spread_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/ac/dbio/ac_unmatch_purge_dbio.h
Normal file
14
app/src/ac/dbio/ac_unmatch_purge_dbio.h
Normal 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 */
|
||||
25
app/src/ac/dbio/ac_unmatch_purge_dbio.pgc
Normal file
25
app/src/ac/dbio/ac_unmatch_purge_dbio.pgc
Normal 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;
|
||||
}
|
||||
15
app/src/ac/dbio/ac_unmatchpurge_batch.h
Normal file
15
app/src/ac/dbio/ac_unmatchpurge_batch.h
Normal 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 */
|
||||
14
app/src/ac/dbio/ac_wht_distinct_dbio.h
Normal file
14
app/src/ac/dbio/ac_wht_distinct_dbio.h
Normal 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 */
|
||||
27
app/src/ac/dbio/ac_wht_distinct_dbio.pgc
Normal file
27
app/src/ac/dbio/ac_wht_distinct_dbio.pgc
Normal 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;
|
||||
}
|
||||
53
app/src/au/batch/au_approverate_batch.pgc
Normal file
53
app/src/au/batch/au_approverate_batch.pgc
Normal 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;
|
||||
}
|
||||
52
app/src/au/batch/au_fraudpurge_batch.pgc
Normal file
52
app/src/au/batch/au_fraudpurge_batch.pgc
Normal 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;
|
||||
}
|
||||
58
app/src/au/batch/au_scorebucket_batch.pgc
Normal file
58
app/src/au/batch/au_scorebucket_batch.pgc
Normal 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;
|
||||
}
|
||||
65
app/src/au/batch/au_summaryrebuild_batch.pgc
Normal file
65
app/src/au/batch/au_summaryrebuild_batch.pgc
Normal 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;
|
||||
}
|
||||
62
app/src/au/batch/au_topcard_batch.pgc
Normal file
62
app/src/au/batch/au_topcard_batch.pgc
Normal 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;
|
||||
}
|
||||
17
app/src/au/dbio/au_approverate_batch.h
Normal file
17
app/src/au/dbio/au_approverate_batch.h
Normal 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 */
|
||||
14
app/src/au/dbio/au_auth_distinctcard_dbio.h
Normal file
14
app/src/au/dbio/au_auth_distinctcard_dbio.h
Normal 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 */
|
||||
28
app/src/au/dbio/au_auth_distinctcard_dbio.pgc
Normal file
28
app/src/au/dbio/au_auth_distinctcard_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/au/dbio/au_auth_incancel_dbio.h
Normal file
14
app/src/au/dbio/au_auth_incancel_dbio.h
Normal 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 */
|
||||
23
app/src/au/dbio/au_auth_incancel_dbio.pgc
Normal file
23
app/src/au/dbio/au_auth_incancel_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/au/dbio/au_auth_rankcard_dbio.h
Normal file
14
app/src/au/dbio/au_auth_rankcard_dbio.h
Normal 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 */
|
||||
31
app/src/au/dbio/au_auth_rankcard_dbio.pgc
Normal file
31
app/src/au/dbio/au_auth_rankcard_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/au/dbio/au_auth_topcard_dbio.h
Normal file
14
app/src/au/dbio/au_auth_topcard_dbio.h
Normal 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 */
|
||||
35
app/src/au/dbio/au_auth_topcard_dbio.pgc
Normal file
35
app/src/au/dbio/au_auth_topcard_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/au/dbio/au_cancel_corr_dbio.h
Normal file
14
app/src/au/dbio/au_cancel_corr_dbio.h
Normal 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 */
|
||||
23
app/src/au/dbio/au_cancel_corr_dbio.pgc
Normal file
23
app/src/au/dbio/au_cancel_corr_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/au/dbio/au_capture_join_dbio.h
Normal file
14
app/src/au/dbio/au_capture_join_dbio.h
Normal 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 */
|
||||
23
app/src/au/dbio/au_capture_join_dbio.pgc
Normal file
23
app/src/au/dbio/au_capture_join_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/au/dbio/au_fraud_casescore_dbio.h
Normal file
14
app/src/au/dbio/au_fraud_casescore_dbio.h
Normal 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 */
|
||||
25
app/src/au/dbio/au_fraud_casescore_dbio.pgc
Normal file
25
app/src/au/dbio/au_fraud_casescore_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/au/dbio/au_fraud_intolog_dbio.h
Normal file
14
app/src/au/dbio/au_fraud_intolog_dbio.h
Normal 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 */
|
||||
28
app/src/au/dbio/au_fraud_intolog_dbio.pgc
Normal file
28
app/src/au/dbio/au_fraud_intolog_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/au/dbio/au_fraud_purge_dbio.h
Normal file
14
app/src/au/dbio/au_fraud_purge_dbio.h
Normal 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 */
|
||||
25
app/src/au/dbio/au_fraud_purge_dbio.pgc
Normal file
25
app/src/au/dbio/au_fraud_purge_dbio.pgc
Normal 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;
|
||||
}
|
||||
16
app/src/au/dbio/au_fraudpurge_batch.h
Normal file
16
app/src/au/dbio/au_fraudpurge_batch.h
Normal 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 */
|
||||
14
app/src/au/dbio/au_limit_spread_dbio.h
Normal file
14
app/src/au/dbio/au_limit_spread_dbio.h
Normal 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 */
|
||||
22
app/src/au/dbio/au_limit_spread_dbio.pgc
Normal file
22
app/src/au/dbio/au_limit_spread_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/au/dbio/au_merchant_active_dbio.h
Normal file
14
app/src/au/dbio/au_merchant_active_dbio.h
Normal 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 */
|
||||
32
app/src/au/dbio/au_merchant_active_dbio.pgc
Normal file
32
app/src/au/dbio/au_merchant_active_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/au/dbio/au_preauth_notexists_dbio.h
Normal file
14
app/src/au/dbio/au_preauth_notexists_dbio.h
Normal 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 */
|
||||
24
app/src/au/dbio/au_preauth_notexists_dbio.pgc
Normal file
24
app/src/au/dbio/au_preauth_notexists_dbio.pgc
Normal 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;
|
||||
}
|
||||
17
app/src/au/dbio/au_scorebucket_batch.h
Normal file
17
app/src/au/dbio/au_scorebucket_batch.h
Normal 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 */
|
||||
14
app/src/au/dbio/au_summary_rebuild_dbio.h
Normal file
14
app/src/au/dbio/au_summary_rebuild_dbio.h
Normal 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 */
|
||||
38
app/src/au/dbio/au_summary_rebuild_dbio.pgc
Normal file
38
app/src/au/dbio/au_summary_rebuild_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/au/dbio/au_summary_riskmerch_dbio.h
Normal file
14
app/src/au/dbio/au_summary_riskmerch_dbio.h
Normal 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 */
|
||||
32
app/src/au/dbio/au_summary_riskmerch_dbio.pgc
Normal file
32
app/src/au/dbio/au_summary_riskmerch_dbio.pgc
Normal 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;
|
||||
}
|
||||
14
app/src/au/dbio/au_summary_weightavg_dbio.h
Normal file
14
app/src/au/dbio/au_summary_weightavg_dbio.h
Normal 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 */
|
||||
33
app/src/au/dbio/au_summary_weightavg_dbio.pgc
Normal file
33
app/src/au/dbio/au_summary_weightavg_dbio.pgc
Normal 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;
|
||||
}
|
||||
16
app/src/au/dbio/au_summaryrebuild_batch.h
Normal file
16
app/src/au/dbio/au_summaryrebuild_batch.h
Normal 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 */
|
||||
16
app/src/au/dbio/au_topcard_batch.h
Normal file
16
app/src/au/dbio/au_topcard_batch.h
Normal 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 */
|
||||
50
app/src/cl/batch/cl_gap_batch.pgc
Normal file
50
app/src/cl/batch/cl_gap_batch.pgc
Normal 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;
|
||||
}
|
||||
8
app/src/cl/batch/cl_gap_cpy.h
Normal file
8
app/src/cl/batch/cl_gap_cpy.h
Normal 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;
|
||||
35
app/src/cl/batch/cl_purgeold_batch.pgc
Normal file
35
app/src/cl/batch/cl_purgeold_batch.pgc
Normal 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;
|
||||
}
|
||||
5
app/src/cl/batch/cl_purgeold_cpy.h
Normal file
5
app/src/cl/batch/cl_purgeold_cpy.h
Normal 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;
|
||||
47
app/src/cl/batch/cl_relock_batch.pgc
Normal file
47
app/src/cl/batch/cl_relock_batch.pgc
Normal 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;
|
||||
}
|
||||
4
app/src/cl/batch/cl_relock_cpy.h
Normal file
4
app/src/cl/batch/cl_relock_cpy.h
Normal 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;
|
||||
51
app/src/cl/batch/cl_reweigh_batch.pgc
Normal file
51
app/src/cl/batch/cl_reweigh_batch.pgc
Normal 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;
|
||||
}
|
||||
6
app/src/cl/batch/cl_reweigh_cpy.h
Normal file
6
app/src/cl/batch/cl_reweigh_cpy.h
Normal 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;
|
||||
39
app/src/cl/batch/cl_tierstat_batch.pgc
Normal file
39
app/src/cl/batch/cl_tierstat_batch.pgc
Normal 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;
|
||||
}
|
||||
7
app/src/cl/batch/cl_tierstat_cpy.h
Normal file
7
app/src/cl/batch/cl_tierstat_cpy.h
Normal 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;
|
||||
9
app/src/cl/dbio/cl_corr_sub_dbio.h
Normal file
9
app/src/cl/dbio/cl_corr_sub_dbio.h
Normal 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 */
|
||||
34
app/src/cl/dbio/cl_corr_sub_dbio.pgc
Normal file
34
app/src/cl/dbio/cl_corr_sub_dbio.pgc
Normal 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;
|
||||
}
|
||||
9
app/src/cl/dbio/cl_lock_upsert_dbio.h
Normal file
9
app/src/cl/dbio/cl_lock_upsert_dbio.h
Normal 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 */
|
||||
24
app/src/cl/dbio/cl_lock_upsert_dbio.pgc
Normal file
24
app/src/cl/dbio/cl_lock_upsert_dbio.pgc
Normal 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;
|
||||
}
|
||||
9
app/src/cl/dbio/cl_minmax_dbio.h
Normal file
9
app/src/cl/dbio/cl_minmax_dbio.h
Normal 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 */
|
||||
24
app/src/cl/dbio/cl_minmax_dbio.pgc
Normal file
24
app/src/cl/dbio/cl_minmax_dbio.pgc
Normal 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;
|
||||
}
|
||||
9
app/src/cl/dbio/cl_snap_distinct_dbio.h
Normal file
9
app/src/cl/dbio/cl_snap_distinct_dbio.h
Normal 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 */
|
||||
20
app/src/cl/dbio/cl_snap_distinct_dbio.pgc
Normal file
20
app/src/cl/dbio/cl_snap_distinct_dbio.pgc
Normal 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;
|
||||
}
|
||||
9
app/src/cl/dbio/cl_snap_in_dbio.h
Normal file
9
app/src/cl/dbio/cl_snap_in_dbio.h
Normal 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 */
|
||||
23
app/src/cl/dbio/cl_snap_in_dbio.pgc
Normal file
23
app/src/cl/dbio/cl_snap_in_dbio.pgc
Normal 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
Loading…
Add table
Add a link
Reference in a new issue