Skip to content

judge가 로컬 MySQL 템플릿 형식의 init SQL을 받아들이도록 수정 - #53

Merged
pwh9882 merged 1 commit into
devfrom
fix/judge-init-schema-template
Sep 2, 2026
Merged

judge가 로컬 MySQL 템플릿 형식의 init SQL을 받아들이도록 수정#53
pwh9882 merged 1 commit into
devfrom
fix/judge-init-schema-template

Conversation

@pwh9882

@pwh9882 pwh9882 commented Sep 2, 2026

Copy link
Copy Markdown

목적

PR #52를 dev에 병합하고 sql-dev.ddps.cloud에 배포한 뒤, 지난 학기 문제 61개를 scripts/regrade-challenges로 전수 재채점했더니 58개가 init 단계에서 Error 1044 Access denied for user 'ct_…'@'%' to database 'kbo'로 실패했습니다. 옛 go-mysql-server judge는 61개 모두 통과했습니다.

원인

문제 init SQL 대부분이 MySQL Workbench·mysqldump 템플릿을 그대로 쓰고 있습니다.

SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';
DROP SCHEMA IF EXISTS kbo;
CREATE SCHEMA kbo;
USE kbo;
CREATE TABLE PLAYER (...);

새 judge는 실행마다 ctfd_tmp_<hex> 하나에만 권한을 주므로 DROP/CREATE SCHEMA kboUSE kbo가 거부됩니다. 옛 엔진은 프로세스 안의 인메모리 DB라 아무 이름이나 만들 수 있었습니다. 또한 옛 엔진과 로컬 MySQL에서는 init과 채점 문장이 같은 세션이라 init의 SET SQL_MODE='TRADITIONAL'(ONLY_FULL_GROUP_BY 없음)이 정답 쿼리에도 적용됐는데, 새 judge는 init 계정과 채점 계정의 세션이 분리되어 서버 기본 sql_mode로 실행했습니다.

변경

  • init 문장 중 CREATE DATABASE|SCHEMA, DROP DATABASE|SCHEMA, USE는 실행하지 않고 그 스키마 이름을 임시 DB의 별칭으로 기억합니다. 앞선 주석(--, /* */)은 건너뛰고 판별하며, /*! */ 버전 주석은 그대로 실행합니다.
  • 별칭으로 한정된 이름(kbo.PLAYER)은 init 문장과 채점 문장 모두에서 임시 DB 이름으로 바꿉니다.
  • init 세션이 끝난 뒤 @@SESSION.sql_mode를 읽어 채점 세션에 같은 값을 적용합니다. init이 없으면 서버 기본값 그대로입니다.
  • init 연결을 한 커넥션에 고정해 스크립트의 SET 문이 끝까지 유지되게 했습니다.

검증

  • 단위 테스트: 스키마 문장 판별(주석 선행, IF EXISTS, 백틱), 비대상 문장(CREATE TABLE kbo, 문자열 안의 USE), 별칭 치환.
  • 통합 테스트: 템플릿 그대로의 init → kbo.PLAYER에 대한 GROUP BY 비집계 SELECT가 TRADITIONAL 모드로 성공, 실제 kbo 스키마는 생성되지 않음, init 없는 실행은 여전히 ONLY_FULL_GROUP_BY 적용.
  • 지난 학기 문제 61개 전수 재채점 결과는 아래 댓글에 기록합니다.

전수 재채점 결과 (로컬, 수정된 judge vs dev@72b1775d의 옛 judge)

항목 결과
새 judge 성공 60 / 61
옛 judge 성공 61 / 61
결과 행 완전 일치 35
숫자 표현만 다름 (183.0901 vs 183.0900900900901, 8510700.00 vs 8510700, 4017733 vs 4.017733e+06) 17
행 순서 다름 (ORDER BY 없음 또는 동률 tie-break 없음) 6 (#22, #23, #27, #30, #36, #57)
DATE 표현 (2024-03-23 vs 옛 2024-03-23 00:00:00 +0000 UTC) 2 (#24, #34)
새 judge 오류 1 (#32: GROUP BY TEAM_ID가 두 테이블에 모두 있어 MySQL이 ambiguous로 거부. 로컬 MySQL에서도 같은 오류)

행 순서 차이는 두 엔진 중 어느 쪽이 맞다고 할 수 없는 문제 정의 이슈이며 지난 학기 DDPS-791에서 반복 지적된 tie-break 항목입니다. 숫자·DATE 표현 차이는 정답과 제출이 같은 엔진에서 실행되므로 채점에는 영향이 없고, 지문의 예시 출력만 갱신하면 됩니다. #33(팀별 최장신, 상관 서브쿼리 안의 GROUP BY)은 로컬에서 1.2초로 가장 느려 t4g.small에서 실행당 2.5초 예산을 확인해야 합니다.

문제 SQL 자체는 저장소에 넣지 않았습니다.

Re-grading last semester's 61 challenges on the MySQL judge failed 58 of
them at init: the scripts are MySQL Workbench and mysqldump exports that
manage their own schema and session.

- Skip CREATE/DROP DATABASE|SCHEMA and USE statements and map that
  schema name onto the execution's temporary database, including
  mysqldump's /*!... */ wrapped forms and schema-qualified names such
  as kbo.PLAYER in init and graded statements.
- Drop leading comment lines from each statement; MySQL rejects
  "-----" separators and empty comment-only chunks.
- Carry the init session's sql_mode (for example TRADITIONAL) into the
  graded statement's session, as one local MySQL session would.
- Start MySQL with lower_case_table_names=1 so Salaries and salaries
  match, as on Windows and macOS where the challenges were written.

The re-grade tool now treats float-precision differences as formatting.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-02T05:02:26.514008Z 5a91915 PR opened
🔒 Security Review Completed 2026-09-02T05:05:32.824236Z 5a91915 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@pwh9882
pwh9882 merged commit 65f890c into dev Sep 2, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5a9191511b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +640 to +641
pattern := regexp.MustCompile("(?i)(^|[^A-Za-z0-9_$.`])`?" + regexp.QuoteMeta(alias) + "`?\\s*\\.\\s*(`?[A-Za-z0-9_$]+`?)")
statement = pattern.ReplaceAllString(statement, "${1}"+quoteIdentifier(database)+".${2}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep schema alias rewriting out of SQL literals

When an init script declares an alias such as company, this regex also rewrites occurrences like 'company.com' inside string literals. Because the solution and submission are evaluated in separately named temporary databases, an init row containing that value becomes a different random string in each evaluation, so even identical queries that return the row are marked as mismatches. Rewrite only parsed schema-qualified identifiers, not raw SQL text.

Useful? React with 👍 / 👎.

// with their own schema name. These statements are mapped onto the
// temporary database instead of being executed.
schemaStatementPattern = regexp.MustCompile("(?is)^(?:CREATE\\s+(?:DATABASE|SCHEMA)(?:\\s+IF\\s+NOT\\s+EXISTS)?|DROP\\s+(?:DATABASE|SCHEMA)(?:\\s+IF\\s+EXISTS)?|USE)\\s+`?([A-Za-z0-9_$]+)`?(?:\\s|$)")
sqlModePattern = regexp.MustCompile(`^[A-Za-z0-9_,]*$`)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Accept valid quoted schema identifiers

For valid exported schemas whose quoted name contains a hyphen, space, Unicode character, or another character outside [A-Za-z0-9_$]—for example USE kbo-data``—this pattern does not recognize the statement. It is consequently executed rather than mapped to the temporary database and fails with the same access-denied error this change is intended to eliminate.

Useful? React with 👍 / 👎.

"""Equal as numbers, allowing for DECIMAL vs float text precision (72220.1111 vs 72220.11111111111)."""
try:
return float(left) == float(right)
return math.isclose(float(left), float(right), rel_tol=1e-6, abs_tol=1e-9)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not classify materially different numbers as formatting

With rel_tol=1e-6, distinct integral results such as 1000000 and 1000001 satisfy math.isclose and are classified as numeric_format; summarize then treats that comparison as successful and exits zero. This can hide real judge regressions during the full regrade rather than merely tolerating DECIMAL-versus-float textual precision differences.

Useful? React with 👍 / 👎.

@pwh9882

pwh9882 commented Sep 2, 2026

Copy link
Copy Markdown
Author

dev 배포 결과 (2026-09-02)

dev@65f890ca를 release dev-65f890cae7b0-20260902T050048Z(AMI ami-0bbb1474ddbc824b2)로 빌드해 sql-dev.ddps.cloud에 instance refresh로 반영했습니다. 새 인스턴스 부팅 후 MySQL 초기화 약 25초, CTFd 기동까지 약 2분이며 .env.judge 0600, CTFd에서 MySQL 비접근, event_scheduler=DISABLED, utf8mb4_0900_ai_ci, OOM 0을 확인했습니다.

지난 학기 문제 61개를 scripts/regrade-challenges로 t4g.small의 judge에 직접 돌린 결과:

항목
성공 60 / 61 (#32는 정답 SQL의 ambiguous GROUP BY TEAM_ID, 문제 수정 필요)
요청 지연 p50 / p90 / 최대 694ms / 843ms / 2,429ms (#33)
실행당 2.5초 초과 없음
judge 정리 실패, 잔여 임시 DB·계정 0, 0
MySQL RSS (재채점 후) 306MiB / 768MiB

같은 인스턴스의 부하 실측(PR #52 병합 직후 release 기준)은 5테이블×100행 init에서 동시 16에 7.2 req/s·p95 2.5초, 동시 32에서 26/96이 busy 응답, 5테이블×1000행 init은 동시 16에 3.9 req/s·p95 4.7초였습니다.

CTFd 웹 경로(setup → 관리자 로그인 → SQL 문제 생성 → Test 5종 → Submit 2종)도 dev에서 정상 동작했습니다.

@pwh9882

pwh9882 commented Sep 2, 2026

Copy link
Copy Markdown
Author

Codex 지적 3건은 #59(문자열 리터럴 안 alias 치환 방지, 백틱 스키마 이름 인식)와 #60(재채점 숫자 비교를 표시 정밀도 기준으로 변경)에서 반영했습니다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant