最近の更新

2009-09-27
2009-07-06
2009-04-11
2009-04-09
2009-03-06

Latest File Release

sticker (0.1.5.2)2009-10-25 12:47

サイドバー

Stickleリファレンス

もくじ

  • はじめに
  • オブジェクトの種類

はじめに

 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」には任意のコンテキスト名を記述します。
 「(」と「)」で囲まれた部分は、コンテキストのプロパティです。
各プロパティは、プロパティ名と値を「:」で区切って指定します。
また、プロパティとプロパティの間は「,」で区切ります。
コンテキストオブジェクトは、以下のプロパティを持ちます。

プロパティ名
driverJDBCドライバクラス名
driverJarFileJDBCドライバのJarファイルのパス
urlデータベースへの接続URL
userデータベースに接続するためのユーザー名
passデータベースに接続するためのパスワード
autoCommitなし

autoCommitプロパティだけは値を持たず、またオプションです。
autoCommitを指定した場合には、このコンテキストでのデータベーストランザクションは、すべて自動的にコミットされます。
指定しなかった場合、トランザクションは自動ではコミットされませんので、後述のsqlステートメントオブジェクトを使用して、明示的にコミットする必要があります。

データソース

 コンテキストであるデータベースサーバを除くと、Stickleが扱うデータソースには、以下の2種類があります。

  • 仮想テーブル
  • CSVファイル

仮想テーブル

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」からはじまるブロックを追加することもできます。
このブロックが意味するのは、その名のとおり制約です。
constraintブロック内には、カラム名からはじまるネスとしたブロックを、必要な数だけ記述します。
「必要な数だけ」というのは、つまり制約を持たせたいカラムそれぞれについて一つずつ、ブロックを記述するということです。
上の例では、「ColumnNameA」、「ColumnNameB」の両方に対して、ブロックが記述されています。
各ブロック内には、「nullable」か「option」、またはその両方を記述します。
nullableを指定したカラムは、NULL値を許容するカラムになります。
optionには、「:」に続いてパラメータを指定します。
この値は、stickerがローカルデータベースを生成する際に、そのまま使用されます。
sticker manualの<column>タグの説明にある、option属性を参照してください。
nullableとoptionは、「,」で区切って、両方を指定することもできます。

CSVファイル

csv.CsvName ( 
	fileName: "c:\sample.csv",
	fileCharset: "UTF-8",
	separator: ",",
	quote: "\"",
	skipFirstLine
)

 Stickerは、CSVファイルからデータベースへのデータ転送をサポートしています。
Stickleでは、CSVファイルをデータソースの1つとして扱うことができます。
 CsvNameの箇所には、データソースとしてのCSVオブジェクトの任意の名前を記述します。
これは、あくまでスクリプト中でこのCSVオブジェクトを扱う際の識別名であり、ファイル名とは無関係です。
スクリプト中で識別しやすい名前を付けてください。
 名前に続く「()」内に、CSVファイルの属性を指定するパラメータを記述します。
以下、それぞれのパラメータについて説明します。

fileNameCSVファイルのパス
fileCharsetCSVファイルの文字コード名

||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: SQLステートメントの実行
  • transportTo: データ転送
  • shell: 外部プロセスの起動
  • info: ログ出力
  • stop: 処理の終了
  • if: 条件分岐
  • iterate: 繰り返し
  • catchException: 例外処理

以下で、各ステートメントを説明します。

sql: SQLステートメントの実行

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: データ転送

transportTo.TableNameOrCsvName {
	"SELECT * FROM aTable"
}

 前述のsqlオブジェクトとともに、Stickleにとって最も重要なタスクの実行を定義するのするのが、transportToオブジェクトです。
 「TableNameOrCsvName」の箇所で、転送先を指定します。
使用できる名前は、コンテキストのデータベース上に存在するテーブル名か、または「virtual」オブジェクト(仮想テーブル)の名前です。
 「{」と「}」で囲まれたブロック内に、転送元のデータを定義します。
上の例のようにSQLステートメントを直接記述することもできますが、前述の「csv」オブジェクトやカーソルバインドの名前を指定することもできます。
transportToステートメントは、contextブロック内にしか記述することはできません。

shell: 外部プロセスの起動

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: ログ出力

info "メッセージ"

 Stickerは、ログ出力を行うことができます。
ログレベルはINFOに固定されています。

stop: 処理の終了

stop

 このステートメントに処理が達すると、stickerは処理を停止します。

if: 条件分岐

if BindingName is Value {
	// ステートメント
}

 「if」ではじまるステートメントによって、処理の分岐を表現します。
上記のサンプル中で、「BindingName is Value」の部分が条件式です。
BindingName」の箇所にバインディング名を記述し、「Value」の箇所に値を記述します。
バインディングの評価結果が指定した値と等しい場合に、続くブロック内に記述されているステートメントが実行されます。
ifステートメントは、contextブロック内にしか記述することはできません。

iterate: 繰り返し

iterate BindingName {
	// ステートメント
}

 「iterate」ではじまるステートメントによって、処理の繰り返しを表現します。
上記のサンプル中で、「BindingName」の箇所にバインディング名を記述します。
ただし、リテラルバインドでなくカーソルバインドを指定する必要があります。
カーソルバインドのSQLの実行によって得られるレコードセットに対して、先頭レコードから順に1レコードずつ、ブロック内のステートメントが実行されます。
iterateブロック内では、カーソルバインドによって生成されるレコードセットが含むカラム名を文字列中のプレースホルダとして使用することで、取得したデータの値を利用することができます。
カラム名によるプレースホルダは、「_$$」と「$$_」で囲んで記述します。

def aBind = sql.toVirtual { "SELECT sample FROM aTable" }

iterate aBind {
	info "サンプル値: _$$sample$$_."
}
iterateステートメントは、contextブロック内にしか記述することはできません。

catchException: 例外処理

catchException {
	// ステートメント
}

 sticker実行中、いつエラーが発生した場合でも、その時点で処理が中断され、catchExceptionブロック内のステートメントが実行されます。
catchExceptionブロック内には、他の箇所と同様、すべてのステートメントを記述することができます。