고도화: 전 모듈 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
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 */
|
||||
Loading…
Add table
Add a link
Reference in a new issue