RFC 28: OGR SQL 일반화 표현식

저자: 프랑크 바르메르담

연락처: warmerdam@pobox.com

상태: 승인, 구현

요약

OGR SQL 평가 엔진은 현재 SELECT 문에서 열에 일반 목적 함수를 적용하지 못 합니다. 몇몇 특수 목적 함수들을 (예: CAST, COUNT, AVG, MAX, MIN, 및 SUM) 지원하지만 좀 더 일반적인 표현식들의 일부로서 지원하는 것은 아니며, 일반적으로 매우 제한된 준비가 필요합니다. 이 작업 항목의 목적은 OGR SQL SELECT 문의 산출 필드 목록에서 일반 목적 표현식 평가를 상당하게 지원할 수 있도록 OGR SQL 엔진을 확장하고, 표준 SQL과 호환되는 방식으로 몇몇 예비 처리 함수를 구현하는 것입니다. 마찬가지로 WHERE 절에 사용되는 표현식도 산술 및 함수 같은 비논리 연산의 평가를 지원하도록 일반화할 것입니다. 예를 들면 구현 이후 다음과 같은 SQL 문도 평가할 수 있게 하려 합니다:

SELECT CONCAT(first_name, ' ', last_name) AS full_name FROM customers
SELECT id, "Regional Road" AS roadtypename FROM roads where roadtype=3
SELECT (subtotal+salestax) as totalcost from invoice_info where 100 <= (subtotal+salestax)

https://svn.osgeo.org/gdal/sandbox/warmerdam/gdal-rfc28/ 에서 구현 프로토타입을 살펴볼 수 있습니다.

기술적 접근

현재 논리 표현식은 기반 요소가 <constant_value> 형식이어야 하는 매우 제한된 서식을 입력받습니다. 일반화 작업의 일환으로, 비논리 표현식을 지원하고 연산자의 왼쪽 및 오른쪽도 동일하게 취급할 것입니다. 현재 OGR SQL 파서(parser)는 그때그때 즉석에서(ad hoc) 처리하기 때문에 이렇게 일반화된 형식의 표현식으로 실질적으로 확장할 수 없습니다. 그렇기 때문에 이 지점에서 표현식을 위한 Yacc/bison 기반 파서 문법으로 넘어갈 것입니다.

SELECT 문의 일부가 표현식인 경우 기존 즉석(ad hoc) SELECT 파싱을 계속해서 사용하는 것은 별로 실용적이지 않기 때문에, SELECT 문 전체를 파싱하는 데 Yacc/bison 기반 파서도 사용할 것입니다.

현재 표현식 노드가 (함수의 인자에 대해) 0개에서 n개 사이의(0-n) 하위 노드를 가지도록, 그리고 필드 참조 및 상수값을 연산을 정의하는 노드에 내장하는 대신 개별 리프(leaf) 노드로 취급하도록 일반화할 것입니다.

이에 따른 부작용으로 WHERE 절도 논리 비교뿐만이 아니라 좀 더 일반적인 표현식을 지원할 것입니다. 다음은 그 예시입니다:

SELECT * WHERE (subtotal+salestax) > 100.0

새 함수

  • 산술: +, -, *, /, **

  • 문자열: CONCAT, SUBSTR

SELECT 규칙

SELECT <field-list> FROM <table_def>
     [LEFT JOIN <table_def>
      ON [<table_ref>.]<key_field> = [<table_ref>.].<key_field>]*
     [WHERE <where-expr>]
     [ORDER BY <sort specification list>]

<field-list> ::= <column-spec> [ { , <column-spec> }... ]

<column-spec> ::= <field-spec> [ <as clause> ]
                 | CAST ( <field-spec> AS <data type> ) [ <as clause> ]

<field-spec> ::= [DISTINCT] <field_ref>
                 | <cumm-field-func> ( [DISTINCT] <field-ref> )
                 | <field-expr>
                 | Count(*)

<field-expr> ::= <field_ref>
                 | <constant-value>
                 | <field-expr> <field-operator> <field-expr>
                 | <field-func> ( <field-expr-list> )
                 | ( <field-expr> )

<field-expr-list> ::= field-expr
                 |  field-expr , field-expr-list
                 |  <empty>

<as clause> ::= [ AS ] <column_name>

<data type> ::= character [ ( field_length ) ]
                | float [ ( field_length ) ]
                | numeric [ ( field_length [, field_precision ] ) ]
                | integer [ ( field_length ) ]
                | date [ ( field_length ) ]
                | time [ ( field_length ) ]
                | timestamp [ ( field_length ) ]

<cumm-field-func> ::= AVG | MAX | MIN | SUM | COUNT

<field-operator> ::= '+' | '-' | '/' | '*' | '||'

<field-func> ::= CONCAT | SUBSTR

<field_ref>  ::= [<table_ref>.]field_name

특별 메모

기존 CAST, 그리고 열 요약 함수 COUNT, AVG, MIN, MAX 및 SUM을 거의 함수처럼 취급할 것이지만, 열 정의에 대한 루트 연산(root operation)으로 제한되며 (여전히) 특수 사례로 취급할 것입니다.

호환성에 미치는 영향

예전에는 따옴표 없는 필드 이름으로 사용할 수 있었던 몇몇 식별자를 이제는 따옴표로 감싸야 할 것입니다. 이 문법에서 식별자가 키워드일 것이기 때문입니다. 이 키워드 집합은 다음과 같습니다:

  • IN

  • LIKE

  • NULL

  • IS

  • SELECT

  • LEFT

  • JOIN

  • WHERE

  • ON

  • ORDER

  • BY

  • FROM

  • AS

  • ASC

  • DESC

  • DISTINCT

  • CAST

예전 구현은 C로 작성되었고, OGDI 라이브러리의 WHERE 절 평가자를 포함하는 다른 맥락에서 쉽게 사용할 수 있도록 GDAL/OGR 서비스를 하나도 사용하지 않았습니다. 이 업데이트 이후 C++로 코드를 작성하고, CPL 오류 및 다른 서비스들을 직접 사용하도록 통합합니다. 즉 GDAL과 OGDI가 사용하는 구현이 갈라질 것이라는 의미입니다.

대부분의 경우 예전에는 오류를 발생시켰을 몇몇 OGR SQL 선언문이 작동하게 될 것입니다.

성능에 미치는 영향

단순 SELECT 문의 경우 평가 속도가 크게 달라지지 않을 것으로 기대하지만, 각 산출 필드를 (아마도 필드로부터 나온 값을 가진 노드가 하나 있는) 표현식으로 평가해야 할 것입니다.

구현 계획

프랑크 바르메르담이 GDAL/OGR 1.8버전 배포판에 맞춰 이 RFC를 구현, 테스트 및 문서화할 것입니다.

테스트

기존 OGR SQL 테스트 스위트의 모든 테스트를 통과할 것입니다. 새 기능을 테스트하기 위해 새로운 autotest/ogr/ogr_sql_rfc28.py 스크립트를 도입할 것입니다.

문서화

새 기능을 설명하기 위해 OGR SQL 문서를 업데이트할 것입니다.