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

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

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

View file

@ -0,0 +1,34 @@
/*
* py_account_batch.pgc - py 계좌 현황 집계 (dbio 전용 배치, XA).
*
* Uses only the dbio layer (no direct EXEC SQL here) to read the active-account
* balance total and count under ONE XA transaction. Usage: py_account_batch
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "py_dbio.h"
#include "py_account_agg_dbio.h"
int main(int argc, char **argv)
{
long total, cnt;
(void)argc; (void)argv;
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; }
total = pydb_account_active_balance();
if (total < 0) { fprintf(stderr, "py_account_batch balance FAIL\n"); tpabort(0); return 1; }
cnt = pydb_account_active_count();
if (cnt < 0) { fprintf(stderr, "py_account_batch count FAIL\n"); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> py_account_batch COMMIT: active_accounts=%ld total_balance=%ld\n", cnt, total);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,50 @@
/*
* py_adjust_apply_batch.pgc - py 조정 반영 (커서 + inline UPDATE, XA).
*
* Cursors the day's adjustments and applies each delta to the linked payout's
* net with an inline UPDATE, under ONE XA transaction.
* Usage: py_adjust_apply_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "py_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
long rows = 0;
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_pay, h_delta;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL DECLARE pyaac CURSOR FOR
SELECT payout_id, delta FROM py_adjust WHERE biz_date = :h_bizdate ORDER BY adj_id;
EXEC SQL OPEN pyaac;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH pyaac INTO :h_pay, :h_delta;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE pyaac; tpabort(0); return 1; }
EXEC SQL UPDATE py_payout SET net = net + :h_delta, updated_at = now() WHERE payout_id = :h_pay;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE pyaac; tpabort(0); return 1; }
rows++;
}
EXEC SQL CLOSE pyaac;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> py_adjust_apply_batch COMMIT: bizdate=%s applied=%ld\n", bizdate, rows);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,38 @@
/*
* py_close_batch.pgc - py 일마감 (단건 UPDATE 배치, XA).
*
* Flips the day's paid(P) payouts to closed(X) with ONE guarded UPDATE and
* reports the affected count via sqlca.sqlerrd[2], all under ONE XA transaction.
* Usage: py_close_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "py_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_aff;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL UPDATE py_payout SET status = 'X' WHERE biz_date = :h_bizdate AND status = 'P';
if (sqlca.sqlcode < 0) { fprintf(stderr, "py_close_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
h_aff = sqlca.sqlerrd[2];
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> py_close_batch COMMIT: bizdate=%s closed(P->X)=%ld\n", bizdate, h_aff);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,37 @@
/*
* py_daily_batch.pgc - py 일일 지급 총계 (단건 집계 배치, XA).
*
* ATMI client: tpinit/tpopen open the ECPG XA RM, tpbegin starts ONE global
* transaction, an EXEC SQL aggregate runs on the biz_date, then tpcommit drives
* XA 2PC. Usage: py_daily_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "py_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_cnt, h_gross, h_fee, h_net;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT count(*), coalesce(sum(amount),0), coalesce(sum(fee),0), coalesce(sum(net),0) INTO :h_cnt, :h_gross, :h_fee, :h_net FROM py_payout WHERE biz_date = :h_bizdate;
if (sqlca.sqlcode < 0) { fprintf(stderr, "py_daily_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> py_daily_batch COMMIT: bizdate=%s payouts=%ld gross=%ld fee=%ld net=%ld\n", bizdate, h_cnt, h_gross, h_fee, h_net);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,55 @@
/*
* py_fee_recalc_batch.pgc - py 수수료 재계산 (커서 + 계산 + inline UPDATE, XA).
*
* Cursors the day's requested(R) payouts, recomputes fee (30bps) and net in C,
* and writes them back with an inline UPDATE, under ONE XA transaction.
* Usage: py_fee_recalc_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "py_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
long rows = 0, fee, net;
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_pay, h_amt, h_fee, h_net;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL DECLARE pyfrc CURSOR FOR
SELECT payout_id, amount FROM py_payout
WHERE biz_date = :h_bizdate AND status = 'R'
ORDER BY payout_id;
EXEC SQL OPEN pyfrc;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH pyfrc INTO :h_pay, :h_amt;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE pyfrc; tpabort(0); return 1; }
fee = h_amt * 30 / 10000;
net = h_amt - fee;
h_fee = fee; h_net = net;
EXEC SQL UPDATE py_payout SET fee = :h_fee, net = :h_net, updated_at = now() WHERE payout_id = :h_pay;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE pyfrc; tpabort(0); return 1; }
rows++;
}
EXEC SQL CLOSE pyfrc;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> py_fee_recalc_batch COMMIT: bizdate=%s recalced=%ld\n", bizdate, rows);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,39 @@
/*
* py_file_confirm_batch.pgc - py 지급파일 확정 (조회 후 UPDATE 배치, XA).
*
* Counts the day's generated(G) files, then flips them to confirmed(C) stamping
* confirmed_at, under ONE XA transaction. Usage: py_file_confirm_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "py_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_cnt, h_aff;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT count(*) INTO :h_cnt FROM py_file WHERE biz_date = :h_bizdate AND status = 'G';
if (sqlca.sqlcode < 0) { fprintf(stderr, "COUNT FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
EXEC SQL UPDATE py_file SET status = 'C', confirmed_at = now() WHERE biz_date = :h_bizdate AND status = 'G';
if (sqlca.sqlcode < 0) { fprintf(stderr, "py_file_confirm_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
h_aff = sqlca.sqlerrd[2];
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> py_file_confirm_batch COMMIT: bizdate=%s generated=%ld confirmed=%ld\n", bizdate, h_cnt, h_aff);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,39 @@
/*
* py_ledger_batch.pgc - py 지급 원장 생성 (INSERT..SELECT 배치, XA).
*
* Bulk-inserts one XFER ledger row per paid(P) payout of the biz_date using a
* single INSERT ... SELECT, under ONE XA transaction. Usage: py_ledger_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "py_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_rows;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL INSERT INTO py_ledger (ledger_id, payout_id, entry_type, amount, biz_date)
SELECT nextval('py_ledger_seq'), payout_id, 'XFER', net, biz_date
FROM py_payout WHERE biz_date = :h_bizdate AND status = 'P';
if (sqlca.sqlcode < 0) { fprintf(stderr, "py_ledger_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
h_rows = sqlca.sqlerrd[2];
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> py_ledger_batch COMMIT: bizdate=%s xfer_rows=%ld\n", bizdate, h_rows);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,50 @@
/*
* py_merchsum_batch.pgc - py 가맹점 지급 집계 (커서 + dbio upsert 배치, XA).
*
* Cursors the day's paid(P) payouts and rolls a per-merchant summary via the
* dbio upsert, under ONE XA transaction. Usage: py_merchsum_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "py_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
long rows = 0;
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16], h_merch[64];
long h_pay, h_net;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL DECLARE pymsc CURSOR FOR
SELECT payout_id, merchant_id, net FROM py_payout
WHERE biz_date = :h_bizdate AND status = 'P'
ORDER BY payout_id;
EXEC SQL OPEN pymsc;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH pymsc INTO :h_pay, :h_merch, :h_net;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE pymsc; tpabort(0); return 1; }
if (pydb_upsert_summary(h_merch, bizdate, 1, h_net) < 0) { EXEC SQL CLOSE pymsc; tpabort(0); return 1; }
rows++;
}
EXEC SQL CLOSE pymsc;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> py_merchsum_batch COMMIT: bizdate=%s rolled=%ld\n", bizdate, rows);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,40 @@
/*
* py_netoff_batch.pgc - py 일괄 상계 (단건 산술 UPDATE 배치, XA).
*
* Applies a flat offset amount to the net of every requested(R) payout of the
* biz_date with a single arithmetic UPDATE, under ONE XA transaction.
* Usage: py_netoff_batch [YYYY-MM-DD] [OFFSET]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "py_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_off, h_aff;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
h_off = (argc > 2) ? atol(argv[2]) : 100;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL UPDATE py_payout SET net = net - :h_off, updated_at = now()
WHERE biz_date = :h_bizdate AND status = 'R';
if (sqlca.sqlcode < 0) { fprintf(stderr, "py_netoff_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
h_aff = sqlca.sqlerrd[2];
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> py_netoff_batch COMMIT: bizdate=%s offset=%ld affected=%ld\n", bizdate, h_off, h_aff);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,50 @@
/*
* py_reject_report_batch.pgc - py 반려 현황 리포트 (읽기 전용 커서 누적 배치, XA).
*
* Cursors the day's rejected(J) payouts, accumulating count and amount in C
* (no writes), under ONE XA transaction. Usage: py_reject_report_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "py_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
long rows = 0, total = 0;
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_pay, h_amt;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL DECLARE pyjrc CURSOR FOR
SELECT payout_id, amount FROM py_payout
WHERE biz_date = :h_bizdate AND status = 'J'
ORDER BY payout_id;
EXEC SQL OPEN pyjrc;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH pyjrc INTO :h_pay, :h_amt;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE pyjrc; tpabort(0); return 1; }
total += h_amt;
rows++;
}
EXEC SQL CLOSE pyjrc;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> py_reject_report_batch COMMIT: bizdate=%s rejects=%ld amount=%ld\n", bizdate, rows, total);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,39 @@
/*
* py_retry_batch.pgc - py 실패 지급 재시도 (단건 UPDATE 배치, XA).
*
* One guarded UPDATE flips the day's failed/held(J,H) payouts back to requested(R)
* and bumps retry_count, reporting the affected count via sqlca.sqlerrd[2].
* Usage: py_retry_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "py_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_aff;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL UPDATE py_payout SET status = 'R', retry_count = retry_count + 1, updated_at = now()
WHERE biz_date = :h_bizdate AND status IN ('J', 'H');
if (sqlca.sqlcode < 0) { fprintf(stderr, "py_retry_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
h_aff = sqlca.sqlerrd[2];
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> py_retry_batch COMMIT: bizdate=%s requeued=%ld\n", bizdate, h_aff);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,53 @@
/*
* py_schedule_run_batch.pgc - py 예약 지급 실행 (커서 + dbio + inline UPDATE, XA).
*
* Cursors the day's pending(S) schedules; per row it flips the linked payout to
* requested(R) via dbio and marks the schedule done(D) inline, under ONE XA
* transaction. Usage: py_schedule_run_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "py_dbio.h"
int main(int argc, char **argv)
{
const char *rundate = (argc > 1) ? argv[1] : "2026-07-19";
long rows = 0;
EXEC SQL BEGIN DECLARE SECTION;
char h_rundate[16];
long h_sched, h_pay;
EXEC SQL END DECLARE SECTION;
strncpy(h_rundate, rundate, sizeof(h_rundate)-1); h_rundate[sizeof(h_rundate)-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 pyrsc CURSOR FOR
SELECT schedule_id, payout_id FROM py_schedule
WHERE run_date = :h_rundate AND status = 'S'
ORDER BY schedule_id;
EXEC SQL OPEN pyrsc;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH pyrsc INTO :h_sched, :h_pay;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE pyrsc; tpabort(0); return 1; }
if (pydb_update_status(h_pay, "R") < 0) { EXEC SQL CLOSE pyrsc; tpabort(0); return 1; }
EXEC SQL UPDATE py_schedule SET status = 'D' WHERE schedule_id = :h_sched;
if (sqlca.sqlcode < 0) { EXEC SQL CLOSE pyrsc; tpabort(0); return 1; }
rows++;
}
EXEC SQL CLOSE pyrsc;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> py_schedule_run_batch COMMIT: rundate=%s executed=%ld\n", rundate, rows);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,37 @@
/*
* py_settle_batch.pgc - py 지급완료 정산 집계 (단건 집계 배치, XA).
*
* ATMI client: opens the ECPG XA RM, starts ONE global transaction, aggregates
* paid(P) payouts for the biz_date, then tpcommit drives XA 2PC.
* Usage: py_settle_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "py_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_cnt, h_net;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT count(*), coalesce(sum(net),0) INTO :h_cnt, :h_net FROM py_payout WHERE biz_date = :h_bizdate AND status = 'P';
if (sqlca.sqlcode < 0) { fprintf(stderr, "py_settle_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> py_settle_batch COMMIT: bizdate=%s paid=%ld net=%ld\n", bizdate, h_cnt, h_net);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,40 @@
/*
* py_stat_batch.pgc - py 집중 가맹점 통계 (GROUP BY HAVING 서브쿼리 배치, XA).
*
* Counts merchants whose daily payout amount clears a threshold using a single
* GROUP BY ... HAVING subquery, under ONE XA transaction.
* Usage: py_stat_batch [YYYY-MM-DD] [THRESHOLD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "py_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16];
long h_thr, h_merchants;
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
h_thr = (argc > 2) ? atol(argv[2]) : 1000000;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL SELECT count(*) INTO :h_merchants FROM (
SELECT merchant_id FROM py_payout WHERE biz_date = :h_bizdate
GROUP BY merchant_id HAVING coalesce(sum(net),0) >= :h_thr) t;
if (sqlca.sqlcode < 0) { fprintf(stderr, "py_stat_batch FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> py_stat_batch COMMIT: bizdate=%s threshold=%ld top_merchants=%ld\n", bizdate, h_thr, h_merchants);
tpclose(); tpterm();
return 0;
}

View file

@ -0,0 +1,49 @@
/*
* py_summary_reset_batch.pgc - py 집계 리셋 (커서 DISTINCT + dbio upsert, XA).
*
* Cursors the DISTINCT merchants that traded on the biz_date and zeroes each
* merchant's daily summary via the dbio ON CONFLICT reset, under ONE XA
* transaction. Usage: py_summary_reset_batch [YYYY-MM-DD]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atmi.h>
#include "py_dbio.h"
#include "py_summary_upsert_dbio.h"
int main(int argc, char **argv)
{
const char *bizdate = (argc > 1) ? argv[1] : "2026-07-19";
long rows = 0;
EXEC SQL BEGIN DECLARE SECTION;
char h_bizdate[16], h_merch[64];
EXEC SQL END DECLARE SECTION;
strncpy(h_bizdate, bizdate, sizeof(h_bizdate)-1); h_bizdate[sizeof(h_bizdate)-1] = 0;
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpopen() < 0) { fprintf(stderr, "tpopen FAIL: %s\n", tpstrerror(tperrno)); return 1; }
if (tpbegin(60, 0) < 0) { fprintf(stderr, "tpbegin FAIL: %s\n", tpstrerror(tperrno)); return 1; }
EXEC SQL DECLARE pysrc CURSOR FOR
SELECT DISTINCT merchant_id FROM py_payout WHERE biz_date = :h_bizdate;
EXEC SQL OPEN pysrc;
if (sqlca.sqlcode < 0) { fprintf(stderr, "OPEN FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); tpabort(0); return 1; }
for (;;) {
EXEC SQL FETCH pysrc INTO :h_merch;
if (sqlca.sqlcode == 100) break;
if (sqlca.sqlcode < 0) { fprintf(stderr, "FETCH FAIL [%d] %s\n", sqlca.sqlcode, sqlca.sqlerrm.sqlerrmc); EXEC SQL CLOSE pysrc; tpabort(0); return 1; }
if (pydb_summary_reset(h_merch, bizdate) < 0) { EXEC SQL CLOSE pysrc; tpabort(0); return 1; }
rows++;
}
EXEC SQL CLOSE pysrc;
if (tpcommit(0) < 0) { fprintf(stderr, "tpcommit FAIL: %s\n", tpstrerror(tperrno)); tpabort(0); return 1; }
printf(">>> py_summary_reset_batch COMMIT: bizdate=%s merchants=%ld\n", bizdate, rows);
tpclose(); tpterm();
return 0;
}