Skip to content
isdnetworks
Go back

반복을 넘어 살아남은 변수

(수정됨)

한 셀에 여러 종류의 문자가 섞여 있는 자료에서 원하는 종류만 골라내는 plpgsql 함수 extract_chars() 를 쓰고 있었다. FOR i IN 1..length(s) 로 문자열을 한 글자씩 돌면서 조건에 맞는 것만 이어 붙이는 방식이었다.

Table of contents

Open Table of contents

증상 — 첫 글자에서만 틀린 결과

대체로 잘 나왔는데 결과를 검수하다가 몇 건이 이상했다. 이상한 건들을 모아 보니 공통점이 있었고 전부 첫 글자에서만 어긋났다.

특정 위치에서만 틀린다는 것은 그 위치를 특별하게 만드는 무언가가 있다는 뜻이다. 첫 글자는 앞에 아무것도 없다는 점이 다른 위치와 달랐다.

원인 — 조건부 갱신과 직전 값

함수 안을 보니 각 글자의 종류를 담는 변수 ch_type 이 있었는데 그것을 IF 조건에 맞을 때만 갱신하고 있었다. 조건에 안 맞으면 값을 안 넣으니 이전 반복의 값이 그대로 남는다.

LOOP 안에서 썼다고 매 반복마다 초기화되는 것이 아니었다. 갱신하지 않으면 지워지는 것이 아니라 직전 값을 물려받는다.

조치 — 값 없음을 명시적으로 넣는다

조건을 옮기는 것 대신 값 없음을 명시적으로 넣는 쪽을 골랐다. 이유는 조건을 옮기면 다른 자리에서 같은 문제가 나고, 근본은 조건에 안 맞을 때 값을 안 넣는다는 점이라서다.

그래서 조건에 안 맞으면 ch_type := NULL 이 명시적으로 들어가도록 손봤다. 그러면 직전 값이 남을 자리가 없어지고 문제가 위치와 무관해진다.

교훈 — 경계에서만 틀리는 결함

이런 결함은 첫 번째나 마지막에서만 드러나므로 대부분의 입력에서는 안 보인다. 그래서 오래 살아남고 검수하다가 우연히 걸린다.

이후로 반복문을 볼 때 그 안의 변수가 매번 초기화되는지를 확인하게 됐다. 조건부로만 갱신되는 변수가 보이면 그 자리는 한 번 더 본다.

주의 — 같은 함수에서 더 보인 것들

같은 함수를 읽다가 다른 것도 몇 개 보였는데 인자만으로 결과가 정해지는데도 VOLATILE 선언이 붙어 있었다. PostgreSQL 11 공식 문서의 함수 휘발성 절대로 VOLATILE 은 기본값이고 최적화기가 아무 가정도 안 해 행마다 다시 계산한다. 인자만으로 정해지는 함수는 IMMUTABLE 이 맞는 자리였다.

bool::int 처럼 참과 거짓의 내부 표현에 기대서 계산하는 자리도 있었는데 그것은 동작은 해도 의도를 가린다. ascii() 코드 범위 같은 상수에는 왜 그 값인지를 주석으로 남겼다.

정리


Share this post on:

Previous Post
이수 기준이 둘 필요한 분류
Next Post
프로젝트별 배포 대상 표