Files
document-haness/docs/clean-architecture-backend-template/final/evidence/raw/a05-f018-sql.txt
T
DongHyeonkaandClaude Opus 5 b2963105a8 docs(keycloak-session-store): import the session-storage lab as a new project
The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.

Follows the import procedure in README.md.

  source/     the originating repository verbatim — 78 documents, 28 SVGs,
              8 manifests, plus .source-revision recording the commit
  final/      the SSOT
    document.md   729 lines written from the 29 experiment documents, not
                  concatenated: what was predicted, what was measured, and
                  where the measurement itself was wrong
    evidence/raw    125 outputs, flattened to <experiment>__<file> because
                    the originals collided (01-baseline.txt appeared three
                    times) and the audit only globs the top level
    evidence/meta   one per raw file; command and exitCode are null and the
                    README says why rather than inventing them
    evidence/browser  22 captures
    assets/       three diagrams through techviz
    .techviz/     their VizSpecs

A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.

Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.

verify-pipeline.py passes. audit-records.py reports no issues.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 22:51:59 +09:00

70 lines
4.3 KiB
Plaintext

# 검사기가 무엇을 하는지, 그리고 무엇을 위한 것인지
7:/**
8: * Prefixes each statement with the registered query name that issued it (design §37).
9: *
10: * <p>The comment travels with the SQL into {@code pg_stat_activity}, {@code auto_explain} output,
11: * and the slow-query log, which is the only place a DBA can connect a statement back to the use
12: * case that produced it. Without it, "which endpoint issues this query" is answered by grepping the
13: * codebase for fragments of SQL.
14: *
15: * <p>Only the registered name is emitted — never a parameter value, an id, or anything from the
16: * request. The name is already validated as bounded and low-cardinality, and this class
17: * additionally rejects the comment terminator so a name can never close the comment and continue as
18: * SQL.
20:public final class NamedStatementInspector implements StatementInspector {
21:
22: private static final long serialVersionUID = 1L;
23:
24: /**
25: * The comment terminator; a name containing it would end the comment and start statement text.
26: */
27: private static final String COMMENT_TERMINATOR = "*/";
28:
29: @Override
30: public String inspect(String sql) {
31: if (sql == null) {
32: return null;
33: }
34: Optional<QueryName> queryName = QueryNameContext.current();
35: if (queryName.isEmpty()) {
36: return sql;
37: }
38: String value = queryName.get().value();
39: if (value.contains(COMMENT_TERMINATOR)) {
40: return sql;
41: }
42: return "/* " + value + " */ " + sql;
43: }
# 이름 형식이 이미 * 와 / 를 막는다
16: private static final Pattern FORMAT = Pattern.compile("[a-z][a-z0-9.-]{2,95}");
# 하이버네이트가 이 구현을 설치하는 경로 — 저장소 루트, 확장자 무제한
# statement_inspector 설정 키: 0
# HibernatePropertiesCustomizer / SessionFactoryBuilder / ServiceRegistry / Integrator: 0
# persistence.xml: 0
# src 리소스와 자동설정 등록 파일의 FQCN: 0
# 그 클래스의 단위 테스트: 0
# 이름을 컨텍스트에 넣는 세 곳
adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/springdata/JpaStreamExecutor.java:63: return QueryNameContext.with(
adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/springdata/JpaKeysetQuerySupport.java:49: return QueryNameContext.with(
adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/springdata/JpaRepositoryFragmentSupport.java:72: return QueryNameContext.with(name, work);
# 그 컨텍스트를 읽는 곳: 1
# 이름을 SQL 로 옮기는 두 번째 경로
adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/api/query/QueryName.java:8: * <p>The name is what appears in metrics, traces, and the {@code org.hibernate.comment} hint, so it
adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/springdata/JpaRepositoryFragmentSupport.java:27: private static final String COMMENT_HINT = "org.hibernate.comment";
adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/querydsl/QuerydslJpaSupport.java:24: private static final String COMMENT_HINT = "org.hibernate.comment";
JpaRepositoryFragmentSupport.java:45: return entityManager.createQuery(jpql, resultType).setHint(COMMENT_HINT, name.value());
JpaRepositoryFragmentSupport.java:62: return entityManager.createNativeQuery(sql).setHint(COMMENT_HINT, name.value());
QuerydslJpaSupport.java:48: return query.offset(page.offset()).limit(page.size()).setHint(COMMENT_HINT, name.value());
# 그 힌트가 SQL 로 나오게 하는 use_sql_comments 를 켜는 곳: 0
# 이름을 넣는 세 클래스를 누가 쓰는가
# JpaStreamExecutor 그 타입을 쓰는 파일 전부: JpaStreamExecutorTest.java JpaStreamExecutor.java
# 상속(전체):
# JpaKeysetQuerySupport 그 타입을 쓰는 파일 전부: JpaKeysetQuerySupportTest.java JpaKeysetQuerySupport.java
# 상속(전체):
# JpaRepositoryFragmentSupport 그 타입을 쓰는 파일 전부: JpaRepositoryFragmentSupportTest.java JpaRepositoryFragmentSupport.java
# 상속(전체): JpaRepositoryFragmentSupportTest.java:74: private static final class Fragment extends JpaRepositoryFragmentSupport {