sticker (0.1.5.2) | 2009-10-25 12:47 |
Stickleへようこそ。
Stickleは、Stickerがもつデータ転送という明確なドメインをターゲットとする、ドメイン特化言語です。
ドメインの領域が非常に限定されているため、Stickleの言語仕様は、シンプルでコンパクトです。
Stickleスクリプトには、いくつかの種類のオブジェクトがあります。
それらに名前を付け、プロパティをセットし、組み合わせることでロジックを記述します。
まず最初に、Stickleスクリプト全般に渡る些細な前提を確認しておきましょう。
とは言っても、お話すべきことはほんの少ししかありません。
どのような種類のオブジェクトがあるのかは後述しますが、名前を持つすべてのオブジェクトについて、ネーミングルールは以下のとおりです。
これだけです。
現在のスクリプトエンジンの実装により、実際には上記以外にも使用可能な文字があります。
しかし、それらの文字は、実装の今後の変化に伴って使用できなくなる可能性があります。
したがって、それらの文字の使用は推奨しません。
オブジェクトにセットするプロパティ値や、変数にセットする値には、現在のところ以下の制限があります。
上記の文字を含む値を記述する場合には、「"」で囲む必要があります。
また、「"」で囲った文字列の中で「"」を記述する場合、「\」でエスケープする必要があります。
例)
def var = "ダブルクォーテーションは\"と記述します"
Stickleでは、C言語やJavaの「;」のように、行末を明示する必要はありません。
通常は、改行までが1コード行です。
ただし、「;」で区切ることで、複数のコード行を1行にまとめることができます。
例)
info "メッセージ" // 通常は、これで1コード行です。 info "メッセージ"; stop // この場合、「;」の前と後ろで2コード行になります。
「//」以降、行末まではコメントとして扱われます。
Stickleスクリプトでは、C言語の「/* 〜 */」のような範囲コメントはありません。
例)
// コメントです。 def aVariant = "Value" // 行末コメントです。 /* これはコメントになりません。コンパイルエラーになります。 */
ここでいうオブジェクトとは、Stickleスクリプトの言語要素を指します。
Stickleスクリプトのオブジェクトは、大きく以下の4つのカテゴリに分かれます。
Stickleでは、ほとんど常に、どのデータベースサーバを処理の対象としているのかを明確にします。
Stickleにとって、処理の対象とは、データ転送の対象となるデータベースサーバにほかなりません。
処理対象のデータベースサーバを、コンテキストと呼びます。
context.ContextName { // いろいろな処理 }
上の構文の中で、「ContextName」の部分が、定義したコンテキストの名前です。
オブジェクト名として有効な任意の文字列を使用することができます。
「{」と「}」で囲まれた部分が、このコンテキストのスコープをあらわします。
ほとんどのステートメントは、コンテキストのスコープ内に記述することになります。
server.ContextName ( driver: driver name, driverJarFile: jar file path, url: jdbc url, user: your name, pass: password, autoCommit )
コンテキストは、それぞれ特定のデータベースサーバを表します。
どのコンテキストがどのデータベースサーバに対応するのかを定義するには、上の構文を利用します。
コンテキストのスコープの項と同じように、「ContextName」には任意のコンテキスト名を記述します。
「(」と「)」で囲まれた部分は、コンテキストのプロパティです。
各プロパティは、プロパティ名と値を「:」で区切って指定します。
また、プロパティとプロパティの間は「,」で区切ります。
コンテキストオブジェクトは、以下のプロパティを持ちます。
プロパティ名 | 値 |
driver | JDBCドライバクラス名 |
driverJarFile | JDBCドライバのJarファイルのパス |
url | データベースへの接続URL |
user | データベースに接続するためのユーザー名 |
pass | データベースに接続するためのパスワード |
autoCommit | なし |
autoCommitプロパティだけは値を持たず、またオプションです。
autoCommitを指定した場合には、このコンテキストでのデータベーストランザクションは、すべて自動的にコミットされます。
指定しなかった場合、トランザクションは自動ではコミットされませんので、後述のsqlステートメントオブジェクトを使用して、明示的にコミットする必要があります。
コンテキストであるデータベースサーバを除くと、Stickleが扱うデータソースには、以下の2種類があります。
virtual.Tableame ( integer ColumnNameA = 0, varchar(5) ColumnNameB = defaultValue )
Stickerのローカルデータベース上に、テーブルを生成します。
現在のStickerの実装では、ローカルデータベースはインメモリのhsqldbです。
「TableName」の部分に、有効なテーブル名を指定します。
テーブル名に続く括弧内に、カラムを定義します。
各カラムの定義には、型名とカラム名をスペースで区切って記述します。
必要なら、カラム名の後に=を付けて、デフォルト値を指定することもできます。
virtual.Tableame ( integer ColumnNameA = 0, varchar(5) ColumnNameB = defaultValue ).constraint { ColumnNameA { option: PRIMARY_KEY }, ColumnNameB { nullable }, }カラム定義の後ろに「.constraint」からはじまるブロックを追加することもできます。
csv.CsvName ( fileName: "c:\sample.csv", fileCharset: "UTF-8", separator: ",", quote: "\"", skipFirstLine )
Stickerは、CSVファイルからデータベースへのデータ転送をサポートしています。
Stickleでは、CSVファイルをデータソースの1つとして扱うことができます。
CsvNameの箇所には、データソースとしてのCSVオブジェクトの任意の名前を記述します。
これは、あくまでスクリプト中でこのCSVオブジェクトを扱う際の識別名であり、ファイル名とは無関係です。
スクリプト中で識別しやすい名前を付けてください。
名前に続く「()」内に、CSVファイルの属性を指定するパラメータを記述します。
以下、それぞれのパラメータについて説明します。
fileName | CSVファイルのパス |
fileCharset | CSVファイルの文字コード名 |
||seeparator||フィールド区切り文字||Stickerの仕様により、指定できる値は以下の3つに制限されています。
|| ||quote||文字列囲み文字||Stickerの仕様により、指定できる値は以下の3つに制限されています。
||
skipFirstLine | 最初の行を読み飛ばす場合に指定 |
quoteには、「"」を指定する場面も多いかと思いますが、その際に、「\」でエスケープする必要があることを忘れないでください。
バインディングとは、ひとことで言うと変数のようなものです。
代入した値を、ステートメント中で利用することができます。
変数との違いは、Stickleのバインディングに値を代入できるタイミングは、初期化時のみであることです。
そういう意味では、変数というよりむしろ定数と言ったほうがあてはまるかもしれません。
バインディングには、以下の2種類があります。
以下で、それぞれを説明します。
def BindName = "true"
リテラルバインドもカーソルバインドも、コードは「def」ではじまり、スペースをはさんでバインド名が続きます。
上の例では、BindNameの箇所がバインド名です。
バインド名に続く「=」の後に、代入する値を記述します。
def BindName = sql.toVirtual { "SELECT sample FROM aTable" }
「sql」オブジェクトを値として代入するバインディングを、カーソルバインドと呼びます。
カーソルバインドのバインド名をステートメント中で使用することで、同じSQLステートメントを、何度でも再利用することができます。
(この説明では、2種類の異なる「ステートメント」に言及していることに気をつけてください。
StickleのステートメントとSQLステートメントは、同じように「ステートメント」と呼ばれますが、異なるアーキテクチャ上のもので、まったく別物です。)
「sql」オブジェクトについては、後述します。
Stickleの処理は、全てステートメントオブジェクトによって定義されます。
ステートメントと他のオブジェクトとの関係は、以下のとおりです。
コンテキスト | ステートメントがどのコンテキスト中に記述されているかによって、その処理の対象が決まります |
データソース | データソース名をステートメント中で利用することによって、データ転送を行います |
バインディング | バインディングは、ステートメント中で再利用できる値、およびSQLステートメントです |
ステートメントは、Stickleスクリプトの中核をなすオブジェクトです。
ステートメントには、以下の4種類があります。
以下で、各ステートメントを説明します。
sql.toVirtual { "SELECT aColumn FROM aTable WHERE aColumn = value" ignoreError }
Stickerはデータ転送ツールです。
そして、StickleはStickerを制御するためのスクリプトです。
したがって、Stickleにとって最も重要なタスクは、ここで説明するsqlオブジェクトによるSQLステートメントの定義と、後述のtransportToオブジェクトによるデータ転送処理です。
sqlオブジェクトによって、SQLステートメントを発行することができます。
「.toVirtual」はオプションで、記述しない場合にはコンテキストが示すデータベースに対してSQLステートメントを発行します。
記述した場合には、ローカルデータベースに対して発行します。
「{」と「}」で囲まれたブロックの中に、SQLステートメントを記述します。
SQLステートメントは通常スペースを含みますので、たいていは「"」で囲う必要があるでしょう。
SQLステートメントの後ろの「ignoreError」は、オプションです。
指定した場合、SQLを発行した際にデータベースによりエラーが通知されても、無視します。
sqlオブジェクトをコンテキスト中で記述した場合、記述した箇所に処理が達した時点で、即座にSQLステートメントが実行されます。
これに対して、前述のカーソルバインドの値としてsqlオブジェクトを記述した場合、そのバインディングを使用することで、いつでも、また何度でも同じSQLステートメントを実行することができます。
また、sqlステートメントは、contextブロック内にしか記述することはできません。
transportTo.TableNameOrCsvName { "SELECT * FROM aTable" }
前述のsqlオブジェクトとともに、Stickleにとって最も重要なタスクの実行を定義するのするのが、transportToオブジェクトです。
「TableNameOrCsvName」の箇所で、転送先を指定します。
使用できる名前は、コンテキストのデータベース上に存在するテーブル名か、または「virtual」オブジェクト(仮想テーブル)の名前です。
「{」と「}」で囲まれたブロック内に、転送元のデータを定義します。
上の例のようにSQLステートメントを直接記述することもできますが、前述の「csv」オブジェクトやカーソルバインドの名前を指定することもできます。
transportToステートメントは、contextブロック内にしか記述することはできません。
shell.sync { "cmd mkdir sample", stopOnError }
Stickerは、コマンド文字列を指定することで、外部プロセスを起動することもできます。
Stickleでは、「shell」オブジェクトによって、外部プロセスの起動を支持することができます。
「.sync」はオプショナルで、指定する場合には以下の2つのどちらかを記述します。
sync | 外部プロセスを同期的に実行します。 Stickerの処理は、外部プロセスの処理が終了するまでブロックされます。 |
async | 外部プロセスを非同期的に実行します。 Stickerの処理は、外部プロセスの処理の終了を待ちません。 |
省略した場合のデフォルトは「sync」です。
「{」と「}」で囲まれたブロック内に、コマンドの文字列を記述します。
Windows系OSの場合、外部プロセスの実行は、CMD.EXEを経由して行われることに注意してください。
「stopOnError」はオプショナルです。
指定した場合には、外部プロセスの実行結果(OSへのリターン値)が0以外だった場合に、Stickerの処理を停止します。
info "メッセージ"
Stickerは、ログ出力を行うことができます。
ログレベルはINFOに固定されています。
stop
このステートメントに処理が達すると、stickerは処理を停止します。
if BindingName is Value { // ステートメント }
「if」ではじまるステートメントによって、処理の分岐を表現します。
上記のサンプル中で、「BindingName is Value」の部分が条件式です。
「BindingName」の箇所にバインディング名を記述し、「Value」の箇所に値を記述します。
バインディングの評価結果が指定した値と等しい場合に、続くブロック内に記述されているステートメントが実行されます。
ifステートメントは、contextブロック内にしか記述することはできません。
iterate BindingName { // ステートメント }
「iterate」ではじまるステートメントによって、処理の繰り返しを表現します。
上記のサンプル中で、「BindingName」の箇所にバインディング名を記述します。
ただし、リテラルバインドでなくカーソルバインドを指定する必要があります。
カーソルバインドのSQLの実行によって得られるレコードセットに対して、先頭レコードから順に1レコードずつ、ブロック内のステートメントが実行されます。
iterateブロック内では、カーソルバインドによって生成されるレコードセットが含むカラム名を文字列中のプレースホルダとして使用することで、取得したデータの値を利用することができます。
カラム名によるプレースホルダは、「_$$」と「$$_」で囲んで記述します。
def aBind = sql.toVirtual { "SELECT sample FROM aTable" } iterate aBind { info "サンプル値: _$$sample$$_." }iterateステートメントは、contextブロック内にしか記述することはできません。
catchException { // ステートメント }
sticker実行中、いつエラーが発生した場合でも、その時点で処理が中断され、catchExceptionブロック内のステートメントが実行されます。
catchExceptionブロック内には、他の箇所と同様、すべてのステートメントを記述することができます。