2017-05-19

Tcl extension and TDBC driver for CrateDB database : cratedb-tcl 0.1

Source code:
cratedb-tcl


如果需要知道 CrateDB 的一些資料:
CrateDB


因為 CrateDB REST API 支援 Parameter Substitution,所以實際上可以用來模擬 prepare/execute 的行為,這個套件為了驗證這個想法而寫的。

也就是實際上是使用 TclCurl 發出 POST request,然後取得結果。而為了模擬,所以我們將步驟分為幾個部份:
  • prepare: 取得 SQL code,只是放在某個變數中
  • param: 使用者設定參數的型別 (TYPE) 與值 (VALUE)
  • 當使用者呼叫 execute,我們將前面二者的資料結合並且設定好 Parameter Substitution 以後,發出 POST request 然後取得結果
而因為模擬了 prepare/execute,所以我們就可以使用 TDBC 中的 ::tdbc::tokenize 分析 SQL 並且進行參數代換的工作,這部份完成以後,就有一個基本可用的 TDBC driver。

但是需要注意的是因為是用模擬的,跟一般資料庫的行為還是有一些差距,當設定  PARAM 時如果沒有為某個欄位指定 TYPE/VALUE,一般會設為 NULL,雖然 TDBC 的部份我有做一些處理,但是還是沒辦法跟一般的資料庫行為完全一樣。

讓我驚嚇的部份是 CrateDB 欄位部份會自動按照變數 欄位的字母大小排序,也就是在 insert 時不指定欄位順序的話,就會出現插入資料到錯誤的欄位。我反覆測試的時候發現的,目前不知道是 CrateDB 的設計還是 bug。

TclCurl DELETE request (using -customrequest)

package require TclCurl

proc httpBlobDelete {url} {
    set curlHandle [curl::init]
    $curlHandle configure -url $url -customrequest DELETE
    catch { $curlHandle perform } curlErrorNumber
    if { $curlErrorNumber != 0 } {
        return -code error [curl::easystrerror $curlErrorNumber]
    }
    
    set responsecode [$curlHandle getinfo responsecode]
    $curlHandle cleanup
    
    if {$responsecode == 204} {
        return -code ok
    } elseif {$responsecode == 404} {
        return -code error "Not Found"
    } else {
            return -code error "ERROR"
    }
}

用來測試 CrateDB REST API 中 BLOB delete 的程式。

如果 TclCurl 要指定 DELETE request,使用 -customrequest 來指定。因為 CrateDB 會回傳 status code 來表示檔案已成功刪除 (204),或者是沒有這個檔案 (404),所以取得 responsecode 以後判斷。大致上是這樣。


更新:
CrateDB 加入 BLOB 資料使用 PUT,下面是測試的程式:
package require TclCurl

proc httpBlobPut {url data} {
    set curlHandle [curl::init]
    $curlHandle configure -url $url -customrequest PUT -postfields $data
    catch { $curlHandle perform } curlErrorNumber
    if { $curlErrorNumber != 0 } {
        return -code error [curl::easystrerror $curlErrorNumber]
    }
    
    set responsecode [$curlHandle getinfo responsecode]
    $curlHandle cleanup
    
    if {$responsecode == 201} {
        return -code ok
    } elseif {$responsecode == 409} {
        return -code error "Conflict"
    } else {
            return -code error "ERROR"
    }
}


使用 GET 讀取內容:
proc httpBlobGet {url} {
    set curlHandle [curl::init]
    $curlHandle configure -url $url -bodyvar html
    catch { $curlHandle perform } curlErrorNumber
    if { $curlErrorNumber != 0 } {
        return -code error [curl::easystrerror $curlErrorNumber]
    }
    
    set responsecode [$curlHandle getinfo responsecode]
    $curlHandle cleanup
    
    if {$responsecode == 200} {
        return -code ok $html
    } elseif {$responsecode == 404} {
        return -code error "Not Found"
    } else {
            return -code error "ERROR"
    }
}

2017-05-14

info library

info library

info library returns the name of the library directory in which standard Tcl scripts are stored.

我忘記我有沒有記錄過這件事,就是 openSUSE 和 Ubuntu 如果你使用 info library 取得資訊,openSUSE (64 位元) 是在 /usr/lib64/tcl/tcl8.6,但是 Debian/Ubuntu 使用不同的方式來組織 32/64 位元目錄,所以會拿到不同的資訊。

如果是純粹 Tcl 所撰寫的套件,openSUSE 也有可能會放在 /usr/share/tcl 這個目錄下面。

2017-05-12

tclcubrid v0.9.5

Source code

tclcubrid

About


CUBRID is an open source SQL-based relational database management system with object extensions developed by Naver Corporation for web applications.

tclcubrid is a Tcl extension by using CUBRID CCI (CCI Client Interface) driver to connect CUBRID. I write this extension to research CUBRID and CCI (CCI Client Interface) driver.

Main changelog

  1. Improve set/multiset/sequence type handle for fetch_row_list/fetch_row_dict method.
    Now tclcubrid will return a Tcl list for set/multiset/sequence type.
    It is an INCOMPATIBILITY change! User maybe need update source code.
  2. Add blob/clob write size check

改進對於 set/multiset/sequence type 的處理。同時加入更多 blob/clob size 的檢查。


更新:
CUBRID 網站怪怪的,我本來想指向正確的文件位址,結果位址一直變動。最後我覺得煩了,我把位址暫時清掉,然後也重置了  tclcubrid 的 git repository。

更新:
早上起來發現網站又回復為原來的樣子,所以我把連結加回去了,希望接下來不會又出現連結失效的問題。

2017-05-03

TclCurl and YQL

我不太確定 YQL 是不是還有在維護,不過這是用來測試 TclCurl Http GET 的程式,送出查詢給 Yahoo Query Language (YQL),然後取得結果。

package require Tcl 8.6
package require TclOO
package require TclCurl

oo::class create CurlYQL {
    variable html_result
    
    constructor {} {
        set html_result ""
    }
    
    destructor {
    }    
    
    method query {query args} {
        variable url
        variable pairs

        set url "https://query.yahooapis.com/v1/public/yql"
        set pairs {}

        lappend pairs "[curl::escape format]=[curl::escape json]"
        lappend pairs "[curl::escape q]=[curl::escape $query]"
        
        foreach {name value} $args {
            lappend pairs "[curl::escape $name]=[curl::escape $value]"
        }
    
        append url ? [join $pairs &]

        set curlHandle [curl::init]
        $curlHandle configure -url $url -bodyvar [namespace current]::html_result
        catch { $curlHandle perform } curlErrorNumber
        if { $curlErrorNumber != 0 } {
            error [curl::easystrerror $curlErrorNumber]
        }

        $curlHandle cleanup
    }
    
    #
    # get the results
    #
    method getResults {} {
        return $html_result
    }
}

所以接下來就是測試。

送出查詢到 Yhaoo Finance (for CSV file) 查詢 SPY, VOO, IVV 的股價,我們拿到結果以後,使用 rl_json 分析結果並且印出來。

package require rl_json

set curlyql [CurlYQL new]
$curlyql query {select * from csv where url='http://download.finance.yahoo.com/d/quotes.csv?s=SPY,VOO,IVV&f=sl1d1t1c1ohgv&e=.csv' and columns='symbol,price,date,time,change,col1,high,low,col2'}
set query_result [$curlyql getResults]

if {[::rl_json::json exists $query_result query]==1} {
    set rows [::rl_json::json get $query_result query results row]

    puts "========================================\n"
    foreach row $rows {        
        puts "symbol: [dict get $row symbol]"
        puts "price: [dict get $row price]"
        puts "date: [dict get $row date]"
        puts "time: [dict get $row time]"
        puts "change: [dict get $row change]"
        puts "col1: [dict get $row col1]"
        puts "high: [dict get $row high]"
        puts "low: [dict get $row low]"
        puts "col2: [dict get $row col2]"
        puts "========================================\n"
    }
}

$curlyql destroy

* 注意:rl_json 新增加的 command json 放在 namespace rl_json 內,不過使用說明上沒有特別明講,所以需要注意一下這件事。

* 更新:
我把資料放到 Github 上了。