언젠가 부터가 현재 상태를 알 수 없는 UI 들이 등장하기 시작했다. 

알림톡이 처음 오면 활성화 되는 버튼 상태

알림톡 받지 않기를 선택하면 알림톡 받기라는 버튼으로 변경된다. 

알림톡을 받지 않기 상태일 때 알림톡 받기로 버튼이 변경된다.



이게 도대체 내 상태가 알림톡 받기 상태인지, 아니면 버튼을 누르면 알림톡 받지 않기 인지 전혀 알 수 없다. (물론 아래 설명을 읽어보면 알 수 있다. 그런데 나중에는 맨 위로 스크롤 하지 않는 한 해당 설명을 다시 읽을 수 없다.그 때는 내가 알림톡 받지 않기를 눌렀는지 아니면 눌러야 되는 것인지 전혀 알 수 없다. )

어느 순간 부터 내 상태 설명이 빠지고 버튼이 누르면 동작하는 방식만을 설명하는 form field가 생겨났다. 이게 기존 경험이 없다면 어떤 동작인지 전혀 알 수 없다. 뭔가 설명이 필요하다면 좋은 UX라고 할 수 있을지 모르겠다. 

 회사에서 한 프로젝트가 IE11 을 버리기로 했다.(내부 admin 시스템은 사용자가 사용하는게 아니라서 크롬에 최적화 해서 사용하고 있었다. 그런데 사용자 사이트는 누가 사용할지 모르기 때문에 IE11을 지원하고 있었다.) 이제는 IE11 때문에 사용 못했던 코드를 더욱 가감하게 사용할 수 있게 되었다. (물론 다른 프로젝트는 아직 IE11을 유지하고 있다. ) 

 이렇게 해서 여러가지 일을 처리하다 기존에는 관심을 가지지 않았던 신기한 JS 함수를 알게 되었다. 
IntersectionObserver 라고 해서 특정 element 가 화면에 viewport 에 보여주는지 여부를 알려주는 함수가 존재했다. 전에 이러한 기능을 구현하려고 했으면 timeout 함수로 주기적으로 element 가 어디에 위치하는지 검사 해야 했다. 그런데 이 함수가 있으면 그 것보다는 효율적으로 적절하게 이벤트를 호출해 주는 것 같다.  이 기능을 이용해서 특정 element 가 현재 viewport 를 기준으로 위에 존재하는지, viewport 에 보이는지, viewport 아래에 위치하는지 확인 할 수 있는 기능을 사용할 수 있다. 

https://stackoverflow.com/a/58981159/6652082

 

  sqlite3 에서 virtual table 을 구현한 것 중 기본 제공하는 기능이 csv 파일을 table 처럼 읽는 기능을 제공하는 csvtab이다. virtual table 을 분석하기 아주 좋은 구조라서 정리해 보았다. 해당 코드는 https://github.com/sqlite/sqlite/blob/version-3.38.5/ext/misc/csv.c  에서 볼 수 있다. 

 우선 csvtab 은 write 하는 기능이 없고, 당연히 transaction 관련 기능도 없다. 그래서 간단한 편이다. 앞에서 설명한(https://yiunsr.tistory.com/879) 함수이름에 x 접두어 대신 csvtab 접두어를 사용하고 있다. 

csvtab 을 이용하는 방법은 

CREATE VIRTUAL TABLE temp.csv USING csv(filename=FILENAME);


 이렇게 하거나 

CREATE VIRTUAL TABLE temp.csv2 USING csv(
    filename = "../http.log",
    schema = "CREATE TABLE x(date,ipaddr,url,referrer,userAgent)"
);

이렇게 schema 를 전달 할 수 있다. 또 data 인자롤 통해서 실제 csv 데이터를 넣을 수도 있다. 실제 예제를 찾지는 못했지만 아래처럼 될 것 같다.

CREATE VIRTUAL TABLE temp.csv2 USING csv(
    data = "2021-01-01,1.120.12.12,http://google.com,,chrome\n",
    schema = "CREATE TABLE x(date,ipaddr,url,referrer,userAgent)"
);



CsvReader (https://github.com/sqlite/sqlite/blob/version-3.38.5/ext/misc/csv.c#L74)
* csv 파일에 대한 handler 를 가지고 있고, 해당 파일을 읽은 데이터를 buffer 에 저장해주는 기능을 함
* csv를 파싱할 때 필요한 데이터들을 저장하고 있음. 
* nLine 은 현재 line 을 의미하는데 에러 표시를 위해 사용된다. (컴파일러 이런 것에 몇째 줄에서 오류가 있음. 이런 것 표시할 때 사용하는 line) line 은 csv 와 row 와 다르다. csv 는 column 에 " 를 이용해서 column 안에 Newline(https://ko.wikipedia.org/wiki/%EC%83%88%EC%A4%84_%EB%AC%B8%EC%9E%90) 을 가질 수 있는데 이럴 경우 csv row 는 증가하지 않지만 nLine 은 증가한다. 

CsvTable(https://github.com/sqlite/sqlite/blob/version-3.38.5/ext/misc/csv.c#L307)
* sqlite3_vtab 가 첫 멤버인데, C++의 상속의 역할을 하는 것 같음. using csv 를 사용할 때, 전달되는 paramer 인 filename, data 를 저장하고 csv 파일의 데이터 시작위치(파일 BOM, header 를 제외하고 시작하는 위치), csv 의 column 개수를 저장한다.

static char *csv_read_one_field(CsvReader *p)
* csv데이터를 파싱해서 csv column은 CsvReader.z 에 넣어두고, CsvReader.term 에 column 다음 글자(일반적으로 콤마, newline같은 csv 구분자를 저자하고 있을 것이다. )를 저장한다. 

csvtabCreate
* 내부적으로 csvtabConnect 함수를 호출함. eponymous virtual table 이 되지 않기 위해서 따로 정의해서 사용하고 있음

​csvtabConnect
* CsvTable 메모리 할당
* schema 정의가 안 된 경우 csv 파일을 읽어서 schema 를 자동으로 만들고, 전달된 경우 해당 schema 를 이용해서 sqlite3_declare_vtab 를 호출한다. schema가 정의되어 있지않으면 실제로 csv 파일을 읽거나 생성할 때 전달받은 data 을 받아서 column 개수를 확인 한 후, c1, c2, ... 이런 형태로 column 이름을 정한다. 
* SQLITE_VTAB_DIRECTONLY (trigger 와 view 을 사용할 수 없음)을 설정한다. 

csvtabDisconnect
*
csvtabConnect 에서 할당한 메모리 해제

csvtabBestIndex
* forward full table scan 만을 지원해서 적당히 cost 값을 넣는 것 같다. 어떤 연산이든 상관없이 cost 에 1000000을 넣는다. 

csvtabOpen
* cursor(CsvCursor)에서 사용한 메모리 할당, csv 파일을 open 한다. 

csvtabClose
*
csvtabOpen 에서 사용한 메모리 해제, csv 파일을 닫는다. 

csvtabFilter
* 메모리 할당한 것들에 대해 초기화, 실질적은 동작은 csvtabNext 에서 한다. full table scan 만을 지원하기 때문에 cursor를 csv 파일의 데이터 시작위치로 옮긴다.

csvtabNext
* 하나의 column 을 가져오고 csv 파일의 row의 모든 column 이 csvCursor 에 저장된다. 
* 이 과정에서 cursor의 iRowid 를 값을 증가시키고 값이 없으면 cursor의 iRowid를 -1 로 세팅한다. 
* csv_read_one_field 가 호출되는 과정에서 자동으로 다음 row 를 가져올 수 있도록 설정될 것이다. 

csvtabColumn
* csvCursor 에 저장된 column 데이터를 sqlite3_result_text 를 호출해서 sqlite engine 에 넘겨준다. 
* 실질적으로 데이터가 넘어 가는 부분이다. 

csvtabRowid
* 현재 cursor 의 iRowid 를 리턴한다. 

csvtabEof
* 현재 cursordml iRowid 가 음수이면 eof 이다. 



딱히 뭔가 실질적으로 데이터를 필터링(sql 에서 where 하는 로직때문에 불필요한 row 자체를 전달하지 않는 동작)이 없다. 느낌으로는 sqlite engine 에 다시 뭔가 row 데이터를 검증하는 로직이 있을 것 같다. 뭔가 bloom filter 처럼 아닌 row를 제외해서 csvtabNext 가 알아서 설정하면 효율적으로 동작하고, 아니더라도 sqlite 엔진이 알아서 실제 데이터를 가지고 filtering 해주는 것으로 추정된다.