Skip to content

[CBRD-26397] (Phase-3) Support for Floating-Point NUMERIC Type#6671

Open
jongmin-won wants to merge 47 commits intoCUBRID:feature/scale_range_fp_numericfrom
jongmin-won:CBRD-26397
Open

[CBRD-26397] (Phase-3) Support for Floating-Point NUMERIC Type#6671
jongmin-won wants to merge 47 commits intoCUBRID:feature/scale_range_fp_numericfrom
jongmin-won:CBRD-26397

Conversation

@jongmin-won
Copy link
Contributor

@jongmin-won jongmin-won commented Nov 27, 2025

http://jira.cubrid.org/browse/CBRD-26397

Purpose

  • 기존(develop)은 Fixed Numeric 타입만을 지원했으나, 이번 변경으로 Floating-Point Numeric(이하 Float Numeric) 타입을 추가 지원함.
  • Float Numeric 타입은 NUMERIC의 Default 타입으로 사용할 수 있음.
CREATE TABLE t1 (col1 numeric);
  • Float Numeric 타입은 NUMERIC의 전체 표현 범위만큼 read/write가 가능함.
1) 지수 표현
1.0 × 10^-252 <= |Value| < 1.0 * 10^254

2) Precision/ Scale
1 <= prec <= 40
-214 <= scale <= 252

Implementation

1. Literal 처리 범위 확장

  • Literal 길이 제한을 기존 254 -> 255로 확장함.
  • 제한을 초과하는 입력은 최대 허용 길이만큼 잘려(truncate) 전달됨.
  • 길이를 1 증가시킨 이유는, Numeric parsing 과정에서 scale 확인 기반의 overflow 판단 및 반올림 처리를 수행하기 위해서임.

2. Float Numeric 타입 해석 규칙 추가

  • TP_DOMAINDB_VALUE->domain의 precision 값이 DB_DEFAULT_NUMERIC_PRECISION(40)인 경우, 해당 값을 Float Numeric으로 해석하도록 분기 로직을 추가함.
  • Float Numeric은 domain의 precision/scale이 아닌, 데이터 header에 저장된 precision/scale을 사용하도록 수정함.

3. Float Numeric Overflow / Underflow 처리

  • Overflow
    • 입력 Literal 또는 연산 결과의 scale이 허용 최소값(DB_MIN_NUMERIC_SCALE=-214)을 벗어나는 경우 overflow로 처리함.
  • Underflow
    • 입력 Literal 또는 연산 결과의 scale이 허용 최대값(DB_MAX_NUMERIC_SCALE=252)을 초과하는 경우, 252 자리에서 반올림되어 0.000… 형태로 표시됨.
    • Underflow는 에러로 처리하지 않으며, 동작은 IEEE 754 Floating Point 표준 기준을 따릅니다.

4. tp_Numeric(DB_TYPE_NUMERIC) 저장 구조 변경

  • tp_Numeric(DB_TYPE_NUMERIC)의 저장 구조를 고정 길이(fixed) -> 가변 길이(variable) 방식으로 변경함.

  • Fixed Numeric

    • TP_DOMAIN의 precision 기준으로 데이터 크기를 계산하여 고정 크기로 저장함.
    • 가변으로 저장하면 **header(3B)**가 추가되고, 4B alignment 패딩까지 발생해 오히려 저장 크기가 커질 수 있어 fixed는 header 없이 유지함.
  • Float Numeric

    • 데이터에 3B header를 추가하여 (precision/scale 포함) 가변 길이로 저장함.
  • Float Numeric 3B Header 포맷

    • header[0] : 총 길이(header+data) + 부호(sign)
      • bit7: sign (1=negative)
      • bit06: total size (420 bytes)
    • header[1] : precision + scale 부호
      • bit7: scale sign (1=negative scale)
      • bit06: precision (140)
    • header[2] : scale 절댓값
      • 0252(양수 scale), 1214(음수 scale은 절댓값 저장 + 부호는 header[1] bit7)

5. AUTO_INCREMENT / SERIAL 동작 수정

  • AUTO_INCREMENT 컬럼이 NUMERIC default로 선언된 경우, NUMERIC(38,0)으로 생성되도록 수정함.
    • 예)
      • 기존 : (col1 NUMERIC (15,0) AUTO_INCREMENT)
      • 수정 : (col1 NUMERIC (38,0) AUTO_INCREMENT)

6. 산술 연산 및 비교 연산

  • Fixed Numeric으로 저장/읽힌 값이라도, 산술/비교 연산 및 내장 함수 등 가공 시점부터는 내부적으로 Float Numeric으로 변환하여 처리함.

7. 내장 함수 추가 수정

7-1) CAST()

  • double의 과학적 표기(예: 1.23e±N) 값을 Float Numeric으로 변환할 때, 기존 e±38 범위를 Float Numeric의 표현 범위(precision 1~40, scale -214~252) 까지 확장.
    7-2) MOD()
  • 매뉴얼 설명과 실제 동작이 달랐던 특정 케이스를 수정.
    7-3) ELT()
  • ELT() 수행 과정에서 불필요한 함수 호출을 줄이도록 개선

8. Hash Join 동작 변경

  • NUMERIC 타입 Hash Join에서 필요한 경우에만 Normalize를 수행하는 하이브리드 방식을 적용하였습니다.
    • Fixed <-> Fixed : 기존과 동일하게 공통 precision/scale 기준으로 CAST 후 처리
    • Fixed <-> Float : 공통 타입을 Float Numeric으로 결정하고, Hash key 생성 시 Normalize 수행
  • 다음 경우에는 Normalize 없이 해시 계산 :
    • Fixed Numeric 인 경우
    • Float Numeric 처리 시 Normalize 생략 조건을 다음과 같이 추가함
      • scale = 0
      • precision이 DB_MAX_NUMERIC_PRECISION(40)이고 scale이 음수인 경우
      • 단, scale > 0인 경우 precision = 40이어도 trailing zero 체크 필요.

9. PL/CSQL Numeric(BigDecimal) 처리 방식 변경

  • cub_server와 동일한 결과를 출력하도록 parsing 및 산술 연산을 Float Numeric 기반으로 변경
  • cub_server와 동일하게 Numeric Overflow/Underflow 처리(에러/표시)를 추가
  • FUNCTION의 RETURN 타입이 numeric이면 항상 Float Numeric으로 처리하도록 변경.
  • Procedure의 DBMS_OUTPUT.put_line()에서 NUMERIC 출력 시 Float Numeric 범위가 정상 출력되도록 수정

10. unload/load 유틸리티 수정

  • Float Numeric의 전체 범위를 지원하며, 해당 값들이 정상적으로 마이그레이션되도록 수정.

11. 시스템 파라미터 정리

  • compat_numeric_division_scale, stored_procedure_return_numeric_size를 HIDDEN/DEPRECATED로 전환.

12. scale 보정(normalize) 성능 최적화

  • mul_normalize / div_normalize를 10^1 반복 연산 대신, 최대 10^16 단위로 처리하는 base-256 곱/나눗셈 함수로 재작성하여 scale 보정 시 반복 횟수 감소.

Remarks

1. 8ec8de6 : domain 이중 포인터 원복

  • phase-1, phase-2 에서 numeric 결과를 검증하기 위해 임시로 적용했던 domain 이중 포인터 수정 부분을 원래대로 되돌립니다.

2. 60e2c0e : Float-Point Numeric 타입 지원, 묵시적 형변환 및 공통 타입 처리 수정

  • Float-Point Numeric 타입 지원
  • 묵시적 형변환 및 공통 타입 처리 방식 수정 (자세한 내용은 CBRD-26397 첨부 자료 참고)

3. 939ef35 : unload/load 유틸리티 수정

  • Float Numeric 범위의 값을 unload/load 할 수 있도록 유틸리티를 수정

4. a4c32cd, c079ead : AUTO_INCREMENT 및 SERIAL 수정

  • AUTO_INCREMENT 컬럼이 NUMERIC default로 선언된 경우, _db_serial 컬럼과의 일관성을 위해 NUMERIC(38,0) 으로 생성되도록 수정
    • c079ead : AUTO_INCREMENT 컬럼이 NUMERIC default 타입을 가질 때, 컬럼 선언 순서가 첫 번째가 아니면 NUMERIC(38,0)으로 변환되지 않는 문제를 수정합니다.
  • 사용자가 AUTO_INCREMENT 컬럼을 NUMERIC(1~28) 타입으로 생성한 경우 해당 값은 4 ~12 byte로 저장되지만, _db_serial.current_val 컬럼은 NUMERIC(38)으로 정의되어 항상 16 byte를 사용합니다.
    이로 인해 byte 크기가 서로 달라 값이 잘못 저장되거나 잘못 읽히는 문제가 발생하던 부분을 수정
  • SERIAL CACHE 생성 및 변경 시 발생하던 오류 해결.

5. ef2b46e, 8458a37 : scale 보정(mul_normalize) 곱셈 성능 최적화

  • 목적:
    • 연산 과정에서 두 값의 scale(소수점 위치)을 맞추기 위해, 내부 값(coefficient)의 10진 자릿수를 증가시키는 데 사용됩니다.
    • 저장 시 43자리(18byte) 제한으로 인해 축소된 유효한 값을, 연산 시 원래 자릿수로 다시 확장(rescale)하기 위해 사용됩니다.
  • 동작 :
    • 기존의 10^1 단위 반복 곱셈 대신, 최대 10^16 단위로 묶어 한 번에 곱하도록 개선함.
    • 남은 자릿수가 16 미만인 경우에는 10^1 ~ 10^15 범위의 값을 한 번에 곱함.
    • 10을 반복 곱셈하는 방식보다 반복 횟수를 줄임
  • 기타 :
    • 8458a37 commit 에서 mul_normalize의 코드 가독성 및 주석 내용을 보강함.
    • 특히, 왜 10^16 단위로 묶어 처리하는지 그 이유(overflow-safe 범위 등) 를 주석에 추가함.

6. 22e64b0 , 7173da2, 3c681f9, 43fb7b0, 7b9ed7d, 6df99e4 : Float Numeric 타입 도입에 따른 Hash Join 동작 변경

  • NUMERIC 타입의 Hash Join에서, 필요한 경우에만 Normalize를 수행하는 하이브리드 방식을 적용함.
    • Fixed <-> Fixed : 기존과 동일하게 공통 precision/scale 기준으로 CAST 후 처리
    • Fixed <-> Float : 공통 타입을 Float Numeric으로 결정하고, Hash key 생성 시 Normalize 수행
  • 다음 경우에는 Normalize 없이 해시 계산 :
    • Fixed Numeric 인 경우
    • Float Numeric 처리 시 Normalize 생략 조건을 다음과 같이 추가함
      • scale = 0
      • precision이 DB_MAX_NUMERIC_PRECISION(43)이고 scale이 음수인 경우
      • 양수 scale인 경우에는 precision이 DB_MAX_NUMERIC_PRECISION(43)이어도 trailing zero 확인이 필요함
  • 43fb7b0 : Fixed Numeric 간 Hash Join 시 공통 precision 기준을 기존 DB_MAX_NUMERIC_PRECISION(43)에서 DB_MAX_FIXED_NUMERIC_PRECISION(38)로 수정
  • 7b9ed7d, 6df99e4 : hash 값을 계산하는 과정에서 메모리 범위를 벗어나는 문제 수정.

7. a15e515 : Float Numeric 타입 도입에 따른 PL/CSQL 동작 변경

  • numeric의 parsing, 묵시적 형변환, 공통 타입, 산술 연산 등 수정
  • Numeric 파싱, 묵시적 변환, 공통 타입 결정, 산술 연산 로직 전반을 Float Numeric 기반으로 수정
  • FUNCTION의 RETURN 타입이 numeric이면 항상 Float Numeric으로 처리하도록 변경

8. 0f0e66e : Float Numeric 도입에 따른 시스템 파라미터 정리

8-1) compat_numeric_division_scale

  • 파라미터를 PRM_HIDDEN 및 PRM_DEPRECATED 로 전환
  • 나눗셈 결과가 항상 Float Numeric 으로 처리되면서 더 이상 의미가 없어 사용되지 않음

8-2) stored_procedure_return_numeric_size

  • 파라미터를 PRM_HIDDEN 및 PRM_DEPRECATED 로 전환
  • PL/CSQL에서 RETURN 타입이 numeric인 경우 이제 항상 Float Numeric 으로 출력되므로 파라미터 설정이 무효화됨

9. 8458a37 : scale 보정(div_normalize) 나눗셈 성능 최적화

  • 주의 :
    • div_normalize는 trailing zero를 제거하기 위한 함수가 아닙니다.
  • 목적 :
    • 값이 필요 이상으로 큰 자릿수를 가지고 있을 때, 지정된 scale만큼 10^exponent로 나누어 내부 값(coefficient)의 자릿수를 조정(감소)하는 데 사용됩니다.
    • 연산 결과가 저장 가능한 최대 자릿수(43자리, 18byte)를 초과하는 경우, 버려진 구간(나머지)의 최상위 digit을 구해 반올림 여부를 판단하기 위해 사용됩니다. (43자리를 초과하는 경우, 44번째 자리의 digit을 이용해 반올림 여부 결정)
  • 동작 :
    • 기존의 10^1 단위 반복 나눗셈을, 최대 10^16 단위로 묶어 한 번에 처리하도록 개선함.
    • 남은 자릿수가 16 미만이면 10^1 ~ 10^15 범위에서 한 번에 처리
    • 10을 반복해서 나누던 기존 방식 대비 나눗셈 반복 횟수를 크게 줄임
  • 기타 :
    • 왜 10^16 단위로 묶어 처리하는지 그 이유(overflow-safe 범위 등) 는 "5. mul_normalize" 함수의 주석 부분에 작성.

10. 43fb7b0 : numeric_compare 함수 성능 최적화

  • Fixed Numeric 비교 시 공통 precision/scale 계산 결과가 38을 초과하면 정수부와 소수부를 분리해 두 번 비교해야 하므로 성능이 떨어짐.
  • 이에 따라 부호가 다르거나 precision/scale이 동일한 경우에는 기존 fast-path를 유지하고, 그 외의 모든 경우는 float_numeric_compare 함수를 사용할 수 있도록 통합함.

11. 8c116a6 : MODIFY/CHANGE 버그 수정 및 외 2가지 문제 수정

  • 1.mr_data_read(val, mem)_numeric에서 size = -1 처리 로직 수정
    • 기존에는 size가 -1이어도 항상 DB_NUMERIC_BUF_SIZE(18 bytes)로 처리되어, mr_data_length에서 계산된 실제 size와 불일치가 발생하는 문제 수정.
  • 2.AUTO_INCREMENT 컬럼이 NUMERIC Default일 때 (38,0)으로 동작하도록 조건 분기 공통화
    • do_create_auto_increment_serial()do_update_maxvalue_of_auto_increment_serial() 함수 수행 전 개별적으로 domain을 변경하던 방식을 제거하고, 상위 조건에서 일관적으로 domain이 (38,0)으로 설정되도록 로직을 통합함.
  • 3.작은 precision에서 큰 precision으로 NUMERIC MODIFY/CHANGE 할 때 버그 수정
    • precision 축소 또는 scale 변경이 포함된 경우에는 기존과 동일하게 전체 cast를 수행함.
    • precision이 확장되는 경우 기존에는 cast를 수행하지 않았으나, 아래 이유로 전체 cast 대신 domain cast만 수행하도록 수정함.
      • precision 값에 따라 read/write 시 사용되는 byte 길이가 달라짐.
      • precision이 변경되었는데 domain cast를 생략하면 read/write 시 byte 길이가 맞지 않아 정상적으로 값이 해석/저장되지 않음.
    • Float Numeric으로 확장되는 경우, 기존 domain precision이 아니라 데이터의 실제 precision을 계산하여 header에 저장하도록 수정함.
    • 해당 문제는 index가 존재하는 경우 아래와 같이 재현 가능함
create table t1 (col1 NUMERIC(5)); 
create index idx_01 on t1 (col1);
insert into t1 values (1.1);

ALTER TABLE t1 MODIFY col1 NUMERIC(20);

12. 820e444, 51da324 : 정수 컬럼에 소수 값 입력 시 잘못된 변환 동작 수정

  • INT와 BIGINT 컬럼에 1.1 값을 INSERT할 때, 값이 1이 아닌 11로 저장되거나 Cannot coerce 오류가 발생하던 문제를 수정함.
  • 51da324 : numeric_get_pow_of_10() 함수가 powers_of_10 배열의 마지막 18byte(DB_NUMERIC_BUF_SIZE)에 해당하는 포인터를 직접 반환하도록 수정함.
    • 기존에는 numeric_overflow() 함수에서 powers_of_10 전체를 받아 18byte를 별도로 가공했으나, 이번 변경으로 해당 처리를 원래 방식으로 되돌리고, 필요한 18byte 포인터는 numeric_get_pow_of_10()에서 바로 반환하도록 로직을 정리함.

13. 6df99e4 : ELT() 내장 함수가 확장된 Float/FIxed Numeric의 scale 범위에서도 올바르게 동작하도록 수정

14. 737da03 : 묵시적 형변환 및 공통 타입 처리 방식 원복

  • Float Numeric으로 변환하던 부분을 다시 Double로 원복 (PL 포함)

15. 27337fb : 스펙 변경 및 이슈 수정 (3건)

15-1) Float numeric 타입의 precision / scale 범위 조정

  • Precision : 43 -> 40
  • Scale : -211 -> -214
  • db_value_buf : 18 -> 17
  • Header : 2 -> 3

15-2) Float numeric 가변 길이 저장 방식 적용 (원복)

  • 5e0a051 커밋에서 float numeric 가변 길이 저장 방식 원복 했습니다.

15-3) loaddb 유틸리티 수정

  • CS 모드에서 Float numeric 범위를 허용하도록 수정

16. e77e0cd : 이슈 수정 (5건)

16-1) round() 함수의 특정 케이스에서 발생하던 overflow 문제를 해결합니다.
16-2) cast() 함수에서 double 지수 표현을 numeric 타입으로 변환할 수 있는 범위를 확장합니다.
16-3) 산술 연산 결과에 대한 overflow 처리 로직을 추가합니다.

  • 결과 scale이 DB_MIN_NUMERIC_SCALE(-214)보다 커지는 경우 overflow로 처리됩니다.
  • 결과 scale이 DB_MAX_NUMERIC_SCALE(252)보다 작아지는 경우, underflow로 처리하지 않고 0.000… 형태로 표시됩니다. (IEEE 754 Floating Point 표준 기준)

16-4) 복합 인덱스 key 생성 및 조회 과정에서 발생하던 core dump 문제를 해결합니다.

  • 해당 커밋에서 mr_index_lengthval_numeric(), mr_index_lengthmem_numeric() 함수를 잘못 수정하여, 322c7ed 커밋에서 원복 후 다른 방법으로 수정함.

16-5) 나눗셈 연산 결과가 40자리를 초과하는 경우 적용되는 반올림 로직을 수정합니다.

  • 기존에는 무한 소수를 고려하여, 값의 크기와 무관하게 항상 precision를 41자리까지 확장한 뒤 나눗셈 연산을 수행하고, 결과를 40자리로 반올림했습니다.
  • 변경 후에는 precision를 최대 40자리까지만 확장하며, 나눗셈 결과로 발생하는 나머지 값을 기준으로 반올림 여부를 판단하도록 수정합니다.

17. 322c7ed : precision, scale 값을 얻는 중복 코드를 공통 함수로 분리

  • 이전 커밋에서 mr_index_lengthval_numeric(), mr_index_lengthmem_numeric() 함수를 잘못 수정하여 원복한 뒤, 다른 방법으로 재수정함.
  • SQL에서 사용되는 내장 함수에서 numeric 값을 double로 변환하는 과정 중, scale을 얻는 로직을 공통 함수를 사용하도록 수정함.

18. 66a9c30 : numeric 처리 정확도 개선 및 server–pl_server 동작 정합성 수정

18-1) (server) numeric 오버플로우 및 반올림 처리를 위해, server의 기존 정수/실수 리터럴 값에 +1을 추가함.
18-2) (server) numeric 파싱 과정에서 다음 로직을 추가함.

  • scale이 -214보다 작은 경우 overflow 처리
  • scale이 252보다 큰 경우 반올림 처리

18-3) (server) 나눗셈 연산 시 mantissa 계산 방식 수정

  • 기존에는 연산 중 tmp buffer 오버플로우를 피하기 위해, 큰 수를 작은 수로 나누어 지수를 맞춘 뒤 mantissa를 비교하는 방식을 사용함.
  • 아래 두 가지 이유로, 작은 수를 큰 수만큼 곱하여 지수를 맞춘 뒤 mantissa를 비교하도록 변경함.
      1. 성능 향상
      • 나눗셈 보다 곱셈의 연산이 더 빠름
      1. 나눗셈 정확도 향상
      • 기존 방식에서는 나눗셈 과정에서 mantissa 정밀도가 손실되는 문제가 있었음
      • 예를 들어, (40,39) 자릿수의 큰 수를 (2,0) 수준으로 줄여 비교할 경우, 실제로는 서로 다른 값임에도 동일한 값으로 판단되어 최종 결과가 (40,39)가 아닌 (39,38)로 계산되는 문제가 발생함
        SELECT 10 (2,0)
               / 1.000000000000000000000000000000000000001 (40,39);
        -- result : 9.99999999999999999999999999999999999999 (39,38)
      • 이는 큰 수를 나누는 과정에서 발생하는 정밀도 손실 문제로, 곱셈 방식으로 변경할 경우 아래와 같이 의도한 결과를 얻을 수 있음
        -- result : 9.999999999999999999999999999999999999990 (40,39)

18-4) (pl_server) BigDecimal의 precision/scale을 중복으로 검사하고 scale을 보정하던 로직을 공통 함수로 통합함.
18-5) (pl_server) TypeNumeric의 key 값이 유니크하도록 수정함.
18-6) (pl_server) 비교 연산 시 트레일링 제로로 인해 동일한 값이 다르게 비교되던 문제를 수정함.
18-7) (pl_server) 나눗셈 연산 결과가 server와 다르게 출력되던 문제를 수정함

  • server에서는 무한 소수 발생을 고려하여 연산 시 precision을 항상 40으로 맞춰 계산하며, 이 과정에서 결과 값에 트레일링 제로가 채워짐.
  • 동일한 동작을 pl_server에도 적용함
  • 단, ORACLE_COMPAT_NUMBER_BEHAVIOR 파라미터가 ON인 경우에는 해당 로직이 동작하지 않도록 제한함.

19. 43a6eaf : mod() 함수 버그 수정

19-1) mod(m, n) 함수 수행 시 n의 값이 0인 경우, m의 값을 그대로 반환해야 하나, m이 실수인 경우 db_value->domainprecision/scale 값을 잘못 읽어 NULL이 반환되던 문제를 수정함.

ex) select mod(0.1,0);

19-2) float numeric 저장 방식을 가변 길이로 변경한 이후, unload/loaddb 유틸리티가 정상적으로 동작하지 않던 문제를 수정함. (원복)

  • 5e0a051 커밋에서 float numeric 가변 길이 저장 방식 원복 했습니다.

20. 5e0a051 : float numeric 가변 길이 저장 방식 원복

  • float numeric 타입의 저장 방식을 가변 길이로 수정했다고 판단했으나, 실제로는 여전히 20byte 고정 길이로 저장되고 있음을 확인함.
  • 이는 PR_TYPE tp_Numeric 전역 구조체에서 varp_arg 값이 고정 길이 기준으로 사용되고 있어, mr_data_*mem/val 관련 함수 수정만으로는 float numeric 타입에 가변 길이 저장 방식을 적용할 수 없음.
  • fixed numeric 과 동일한 방식으로 가변 처리할 경우, 다음과 같은 문제점이 있음.
      1. mr_data_*mem/val 이외의 코드 영역에도 불필요한 조건 분기가 추가되어 성능 저하 및 가독성 저하가 발생함.
      1. ALTER 구문을 통해 컬럼 타입을 다른 타입으로 변경하는 과정에서 기존 데이터를 정상적으로 읽지 못해 NULL 이 반환되는 문제가 확인됨.
  • 따라서, float numeric 타입은 기존 동작과 동일하게 항상 20byte 고정 길이로 저장되도록 다시 원복함.

21. e64c268 : tp_Numeric(DB_TYPE_NUMERIC) 저장 구조를 가변 길이 방식으로 변경

  • tp_Numeric(DB_TYPE_NUMERIC) 타입의 저장 구조를 기존 고정 길이(fixed) 방식에서 가변 길이(variable) 방식으로 변경함.
  • common type 관련 코드 롤백 과정에서, hash join 수행 시 common type을 계산하던 로직이 롤백되지 않아, 해당 부분을 제거하여 원복 시킴.

22. 4302554 : ELT() 내장 함수 수행 로직에서 불필요한 함수 호출을 줄이도록 수정함.

23. 811c671 : 코드 리뷰 내용 반영 및 loaddb SA 모드 버그 수정

23-1) loaddb SA 모드에서 발생하던 core dump 문제 수정

  • PR_TYPE tp_Numeric4번째 인자(size_arg)를 최소값으로 설정한 경우, SA 모드에서 loaddb 수행 시 메모리 크기 계산이 맞지 않아 core dump가 발생하던 문제를 수정함.

23-2) 코드 리뷰 내용 반영

  • Float numeric 판별 조건을 통일함
    • 기존에는 db_value->domainprecision == 40 && scale == 0으로 확인하던 로직을 precision == 40만으로 판별하도록 변경함.
  • loaddb 수행 시 precision > 38 인 경우 float numeric으로 변환하도록 수정
    • 기존에 precision == 40인 경우에만 float numeric으로 인식했으나, precision == 39 처럼 경계에 있는 값이 fixed numeric 으로 처리되면서 불필요한 분기 로직이 수행되는 문제가 있었음.
    • 이를 precision > 38 조건으로 수정하여, 불필요한 분기 수행 문제를 해소함.

24. 36049f4 : 특정 산술 연산(+, -, *) 케이스에서 cub_serverPL/CSQL의 결과가 서로 달라지는 문제 수정

  • 차이가 발생한 원인은 PL/CSQL 쪽에서 연산 전에 자릿수(precision/scale)를 계산한 뒤, 연산 과정에서 자릿수를 제한하고 반올림을 수행한 다음, 결과를 다시 최대 precision/scale 범위에 맞게 재조정(반올림 포함)하기 때문입니다.
  • 즉, 이 과정은 결과적으로 반올림이 두 번 적용되는 것과 동일하여 값 차이가 발생합니다.
  • 따라서 해당 케이스를 해결하기 위해 연산 전 자릿수 제한 및 사전 반올림 로직을 제거합니다.

25. ddcae74, 0cf248e : TO_NUMBER() 결과 불일치 수정, 반환 도메인 FLOAT NUMERIC 적용

  • TO_NUMBER()는 NUMERIC 값을 가공하는 함수이므로, 반환 도메인(DOMAIN)은 항상 FLOAT NUMERIC으로 처리하도록 변경.
  • TO_NUMBER() 함수 수행 시 결과 값이 의도와 다르게 나오는 문제 수정.
create class foo(f varchar(10));
insert into foo values('1');
insert into foo values('2');

select to_number(f) from foo order by 1;
1
2

select to_number(f) from foo order by 1 desc;
2
1

-- 아래 case는 기존 develop 에서 결과가 반대로 출력됨.
select to_number(f,99999999999999999999999999999999999999) from foo order by 1;
1
2

26. 3f04ec1, 90ee8d4, e8a0df9 : CTP(SQL) 수행 중 의도하지 않은 결과가 발생하거나 core dump가 발생하는 문제를 수정함

26-1) 기존 연산 함수(numeric_db_value_add/sub/mul/div)의 반환 타입을 항상 Float Numeric으로 처리하도록 수정

  • 기존에는 fixed numeric 전용으로 가정하고 있었으나, float numeric 도입 이후 NUMERIC 값이 한 번이라도 가공(연산/내장 함수 등)되면 Float Numeric으로 처리하는 신규 룰에 맞춰 동작을 일관화함
  • 실제로 float numeric 값이 인자로 들어오는 케이스가 존재하여, 해당 함수들에도 신규 룰을 전면 적용함

26-2) serial/auto_increment 관련 연산(nextval 등)에서 결과가 Float Numeric으로 반환되 발생하는 문제 수정

  • serialauto_increment는 항상 fixed numeric으로 관리되어야 함
  • 1번 변경으로 인해 nextval 등의 연산 결과가 Float Numeric으로 나오게 되어, 저장 및 후속 처리를 위해 fixed numeric으로 재변환하도록 수정함

26-3) SUM(), AVG() 처리 시 인자가 numeric인 경우 domain 결정 로직 보완
- SUM(), AVG() 수행 전 DOMAIN 이 numeric인 경우 내부적으로 별도 cast가 수행되지 않아 domain 설정이 부정확할 수 있었음
- float/fixed numeric을 구분해 올바른 domain이 설정되도록 수정함
- GROUP BY와 함께 사용할 경우 DOMAIN 정보가 덮어씌어지는 문제도 함께 수정함

26-4) NUMERIC음수 변환 함수 호출이 실수로 제거된 부분 다시 추가함

  • 322c7ed 커밋에서 precision/scale 값을 얻는 중복 코드를 공통 함수로 분리하는 과정에서 해당 호출이 제거된 것을 확인하여 원복함

26-5) view 테이블에서 numeric(0) 사용 시 size ovfcore 발생하는 문제 해결함

  • precision이 0인 경우 -1 처리로 인해 쓰레기 값으로 size를 계산하던 문제 있었음
  • _gv_numeric_precision_to_bytes_lookup 배열을 1개 확장하여, precision이 0인 경우 0을 반환하도록 수정함

26-6) GROUP BY 절에서 LAST_INSERT_ID() 함수를 사용할 때 의도와 다른 결과가 출력되는 문제를 수정함

26-7) mr_data_*mem_numeric 관련 NULL 처리 오류 수정

  • mr_data_*mem_numeric 함수의 NULL 처리 방식을 varchar 타입과 동일하게 수정함.
  • 특정 케이스에서 fixed numeric 컬럼에 NULL 값을 저장한 후 조회 시, 실제 값이 NULL임에도 불구하고 0으로 반환되던 문제를 수정함.

26-8) SUM, AVG 함수 오류 수정

  • sum(all col1) over() 및 sum(distinct col1) over() 수행 시 발생하던 오류를 수정함.
  • 26-3) 의 수정 방식은 잘못된 수정으로 확인되어 e8a0df9 커밋에서 수정함.

26-9) numeric precision–byte 변환 LUT 공식 수정

  • numeric precision을 byte 단위로 변환하는 LUT 공식이 read/write 과정에서 사용되고 있음.
  • 기존 공식에서는 precision7, 12 등의 값인 경우, 최상위 바이트최상위 비트(MSB)부호 비트가 아닌 값 비트로 채워져 잘못된 결과가 반환되는 문제가 발생함.
  • 이를 해결하기 위해 precision 계산 공식을 다음과 같이 수정함.
   AS-IS 공식 : ceil(precision / log10(256))
   TO-BE 공식 : ceil((precision / log10(256) + 1) / 8)
  • 변경된 공식은 최상위 바이트최상위 비트으로 사용되는 precision의 경우, 부호 비트 확보를 위해 1바이트를 추가로 할당하도록 보정함.

27-10) JOIN + START WITH ... CONNECT BY 수행 시 결과 불일치 문제 수정

  • JOIN 수행 결과에 대해 테이블 컬럼의 domain(numeric(10,2)) 기준으로 hash key가 생성됨.
  • 그러나 START WITH ... CONNECT BY 구문 수행 시, probe_regu_list의 domain이 numeric(40,0) (float numeric)으로 변경됨.
  • 이로 인해 check_hash_list_scan() 단계에서 START WITH 절int 값numeric(10,2)가 아닌 float numeric 기준으로 cast되며,
    예를 들어 1 → 1.00 (100) 형태로 변환되지 않아 hash key 불일치가 발생함.
  • probe 값 계산 시, 이전에 hash key를 생성한 numeric domainfixed numeric(precision/scale 보유)인 경우, float numeric 도메인 정보를 fixed numeric domain으로 재설정(cast)하도록 수정함.
  • 이를 통해 hash key 생성이 의도한 결과 처럼 생성되어 문제를 해결함.

…1 and phase-2 for validating numeric results has been reverted to its original implementation.
@jongmin-won jongmin-won self-assigned this Nov 27, 2025
@jongmin-won jongmin-won marked this pull request as ready for review December 1, 2025 01:20
@chatgpt-codex-connector
Copy link

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

jongmin-won added 3 commits December 2, 2025 04:29
2. Fixed the missing Fixed Numeric condition in the Hash Join execution path
… from 43 to 38

2. Optimized the performance of the existing numeric_compare function
…tion.

   This assertion is applied only when the internal buffer represents a
   positive magnitude value. For two's-complement negative buffers used
   in comparison paths, a non-zero carry is a valid outcome and therefore
   excluded from this assertion.

2. Updated SERIAL and AUTO_INCREMENT behavior so that an error is raised
   when the current value exceeds precision 38, matching the behavior of
   the develop branch.
jongmin-won added 3 commits December 9, 2025 04:17
…meric

2. Unify the conditional logic so that AUTO_INCREMENT columns using the NUMERIC default always operate as (38,0)
3. Improve behavior when MODIFY/CHANGE increases the precision of a NUMERIC column
…ns either stored 11 instead of 1, or resulted in a Cannot coerce error.
…or certain arithmetic operations (+, -, *).
* when comparing with TP_DOMAIN, use db_value_precision() and db_value_scale() instead.
*/
void
db_get_numeric_precision_and_scale (const DB_VALUE * value, int *precision_ptr, int *scale_ptr,
Copy link
Contributor

Choose a reason for hiding this comment

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

precision_ptr, scale_ptr 가 유효한지 NULL 체크 코드가 필요해 보입니다.

Copy link
Contributor Author

@jongmin-won jongmin-won Feb 3, 2026

Choose a reason for hiding this comment

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

리뷰 감사합니다.
c6485eb 커밋에서 말씀해주신 내용을 반영하여 수정했습니다.

…cub_server behavior from the type-checking phase to a later stage after literal validation.

2. During the rollback of the previous common type changes, the PL/CSQL add function missed a required conversion for numeric + string operations to double. This omission has been fixed.
@kangmin5505 kangmin5505 requested a review from Copilot February 3, 2026 09:57
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 47 out of 47 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

return NULL;
}

if (prec > DB_MAX_NUMERIC_PRECISION || scale > DB_MAX_NUMERIC_SCALE || prec < 0 || scale < DB_MIN_NUMERIC_SCALE)
Copy link
Contributor

@hyunikn hyunikn Feb 5, 2026

Choose a reason for hiding this comment

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

범위 검사가 필요 없어 졌나요?
assert 로라도 남겨두는 것이 좋지 않을까요.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

네, 범위 검사는 필요 없습니다.

pt_make_prim_data_type_fortonum() 함수는 TO_NUMBER() 내장 함수를 수행할 때 PT_DATA_TYPE(DOMAIN) 값을 결정하는 역할을 합니다.
그리고 TO_NUMBER()NUMERIC 값을 가공하므로 내부적으로 항상 FLOAT NUMERIC으로 처리됩니다.
따라서 별도의 범위 검사는 불필요합니다.

Copy link
Contributor

Choose a reason for hiding this comment

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

그럼, pt_make_prim_data_type_fortonum() 로 넘어오는 인자 prec, scale 는 언제나 DB_MAX_NUMERIC_PRECISION 과 0 이겠군요.

Copy link
Contributor

@hyunikn hyunikn Feb 6, 2026

Choose a reason for hiding this comment

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

그렇다면, 인자 prec 와 scale 이 없어지는 것이 좋겠습니다.

{
*p_precision = DB_MAX_NUMERIC_PRECISION;
*p_scale = DB_DEFAULT_NUMERIC_PRECISION;
*p_scale = DB_LEGACY_DEFAULT_NUMERIC_PRECISION;
Copy link
Contributor

Choose a reason for hiding this comment

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

이 함수 pt_to_regu_resolve_domain() 을 호출하는 곳이 없습니다.
사용하지 않는 함수이므로 pt_to_regu_resolve_domain() 를 지우는 것이 좋을 것 같습니다.

Copy link
Contributor

Choose a reason for hiding this comment

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

이번 commit 에서 사용이 모두 없어졌군요.

{
if (before_dec_point + after_dec_point > DB_MAX_FIXED_NUMERIC_PRECISION ||
after_dec_point > DB_DEFAULT_NUMERIC_PRECISION || before_dec_point > precision - scale)
after_dec_point > DB_LEGACY_DEFAULT_NUMERIC_PRECISION || before_dec_point > precision - scale)
Copy link
Contributor

Choose a reason for hiding this comment

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

소수점 이후 자리수와 예전 numeric default precision 과 비교하고 있는 듯 합니다.
어떤 의미 일까요.

Copy link
Contributor Author

@jongmin-won jongmin-won Feb 6, 2026

Choose a reason for hiding this comment

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

해당 함수는 TO_NUMBER() 사용 시 호출되는 함수입니다.

아래 comment의 질문과 동일하게, 해당 로직의 정확한 의도를 명확히 파악하기 어려웠습니다.
따라서 동작 변경을 최소화하기 위해 기존과 동일하게 동작하도록 DB_LEGACY_DEFAULT_NUMERIC_PRECISION(15) 매크로를 추가하여 적용했습니다.

/* scientific notation */
precision = DB_MAX_FIXED_NUMERIC_PRECISION;
scale = DB_DEFAULT_NUMERIC_PRECISION;
scale = DB_LEGACY_DEFAULT_NUMERIC_PRECISION;
Copy link
Contributor

Choose a reason for hiding this comment

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

scale 에 precision 값을 대입한다는 것이 어떤 의미일까요.
혹시 15 라는 값을 써야 하는데, DB_LEGACY_DEFAULT_NUMERIC_PRECISION 가 15 값을 가져서 쓴 것일까요.

Copy link
Contributor Author

@jongmin-won jongmin-won Feb 6, 2026

Choose a reason for hiding this comment

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

해당 함수는 TO_NUMBER() 사용 시 호출되는 함수입니다.

scale에 precision 값을 대입한 이유는 저도 정확히 파악하지 못했습니다.
어떤 의도로 DB_DEFAULT_NUMERIC_PRECISION 값을 scale에 넣었는지 현재로서는 추측이 어렵습니다.

말씀 주신 것처럼 DB_LEGACY_DEFAULT_NUMERIC_PRECISION(15) 매크로를 추가 이유는,
float numeric 도입으로 DB_DEFAULT_NUMERIC_PRECISION 값이 15 -> 40으로 변경되었기 때문입니다.

이로 인해 기존에 DB_DEFAULT_NUMERIC_PRECISION(15)에 의존하던 동작을 유지하기 위해,
기존 값(15)을 대체하는 용도로 DB_LEGACY_DEFAULT_NUMERIC_PRECISION을 추가해 사용했습니다.

-- develop 코드
if (use_default_precision == 1)
  {
    /* scientific notation */
	precision = DB_MAX_NUMERIC_PRECISION; /* 38 */
	scale = DB_DEFAULT_NUMERIC_PRECISION; /* 15 */
	break;
  }

Copy link
Contributor

@hyunikn hyunikn Feb 6, 2026

Choose a reason for hiding this comment

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

develop 코드부터 그랬었군요.
위에 after_dec_point > DB_LEGACY_DEFAULT_NUMERIC_PRECISION 비교도 비슷한 상황일 것 같습니다.
값이 15 이면서 적절한 이름을 갖는 다른 매크로 상수를 정의해서 사용하는 것이 좋을 것 같습니다.

Copy link
Contributor

Choose a reason for hiding this comment

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

예를 들면,

#define DB_DEFAULT_NUMERIC_SCALE_FOR_TO_NUMBER     (15)

jongmin-won added 2 commits February 7, 2026 01:27
…b/mul/div) to always return Float Numeric

2. Fixed an issue where results were returned as Float Numeric during serial/auto_increment-related operations (e.g., nextval)
3. Improved the domain resolution logic for ADD() and AVG() when the argument is numeric
4. Re-added a mistakenly removed call to the NUMERIC negation conversion function
5. Resolved a crash caused by size overflow when using numeric(0) in a view table
2. Fix errors in the SUM function
3. Fix numeric precision-to-byte conversion LUT formula
4. Fix inconsistent results when executing JOIN with START WITH ... CONNECT BY
Comment on lines +16603 to +16649

/* Adjust probe domain precision/scale from rest_regu_list for hash list scan */
if (probe_regu && xasl->spec_list->s.list_node.list_regu_list_rest)
{
REGU_VARIABLE_LIST rest_regu_numeric = NULL;

/* Find first numeric item in rest_regu_list with fixed precision */
for (REGU_VARIABLE_LIST rest_iter = xasl->spec_list->s.list_node.list_regu_list_rest;
rest_iter != NULL; rest_iter = rest_iter->next)
{
if (TP_DOMAIN_TYPE (rest_iter->value.domain) == DB_TYPE_NUMERIC &&
rest_iter->value.domain->precision != DB_DEFAULT_NUMERIC_PRECISION)
{
rest_regu_numeric = rest_iter;
break;
}
}

/* Adjust first numeric probe item if found */
if (rest_regu_numeric)
{
DB_TYPE vtype1 = REGU_VARIABLE_GET_TYPE (&probe_regu->value);

if (vtype1 == DB_TYPE_NUMERIC &&
probe_regu->value.domain && probe_regu->value.domain->precision == DB_DEFAULT_NUMERIC_PRECISION)
{
/* in START WITH ... CONNECT BY, join and expression evaluation may widen
* probe_regu_list domain to float numeric.
*
* since tp_value_coerce() always casts values to the probe domain,
* the cast behavior depends on probe_regu_list->value.domain (vtype1's domain).
* when the probe domain is float numeric, integer values are not scaled,
* which can produce different hash keys from fixed numeric columns.
*
* to avoid this mismatch, restore precision/scale from rest_regu_list
* when it represents a fixed numeric domain.
*/
TP_DOMAIN *new_domain = tp_domain_copy (probe_regu->value.domain, false);
if (new_domain != NULL)
{
new_domain->precision = rest_regu_numeric->value.domain->precision;
new_domain->scale = rest_regu_numeric->value.domain->scale;
probe_regu->value.domain = new_domain;
}
}
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

관련 TC : _13_issues/_20_2h/cbrd_23749.sql

CREATE TABLE tree(ID numeric(10,2), MgrID INT, Name VARCHAR(32), BirthYear INT);

CREATE TABLE tree(ID numeric(10,2), MgrID INT, Name VARCHAR(32), BirthYear INT);
CREATE TABLE tree2(id int, treeid int, job varchar(32));
INSERT INTO tree VALUES (1,NULL,'Kim', 1963),(2,NULL,'Moy', 1958),(3,1,'Jonas', 1976),(4,1,'Smith', 1974),(5,2,'Verma', 1973),(6,2,'Foster', 1972),(7,6,'Brown', 1981);
INSERT INTO tree2 VALUES(1,1,'Partner'),(2,2,'Partner'),(3,3,'Developer'),(4,4,'Developer'),(5,5,'Sales Exec.'),(6,6,'Sales Exec.'),(7,7,'Assistant'),(8,null,'Secretary');

SELECT t.id FROM tree t INNER JOIN tree2 t2 ON t.id=t2.treeid START WITH t.mgrid is null CONNECT BY prior t.id=t.mgrid ORDER BY t.id;

Copy link
Contributor Author

@jongmin-won jongmin-won Feb 13, 2026

Choose a reason for hiding this comment

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

JOIN + START WITH ... CONNECT BY 수행 시 결과 불일치 문제 수정

  • JOIN 수행 결과에 대해 테이블 컬럼의 domain(numeric(10,2)) 기준으로 hash key가 생성됨.
  • 그러나 START WITH ... CONNECT BY 구문 수행 시, probe_regu_list의 domain이 numeric(40,0) (float numeric)으로 변경됨.
  • 이로 인해 check_hash_list_scan() 단계에서 START WITH 절의 int 값이 numeric(10,2)가 아닌 float numeric 기준으로 cast되며,
    예를 들어 1 → 1.00 (100) 형태로 변환되지 않아 hash key 불일치가 발생함.
  • probe 값 계산 시, 이전에 hash key를 생성한 numeric domain이 fixed numeric(precision/scale 보유)인 경우,
    float numeric 값을 해당 fixed numeric domain으로 재설정(cast)하도록 수정함.
  • 이를 통해 hash key 생성이 의도한 결과 처럼 생성되어 문제를 해결함.

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.

8 participants