2010年12月29日水曜日

SQL Anywhere SELECT結果でのUPDATE

あるテーブルのSELECT結果を使って別テーブルのUPDATEをする。

このようなことをしたい場合SQL Anywhereでは UPDATE~FROM~WHERE 構文を使うことで実現できる。この構文ではFROM句で取得したあるテーブルのデータをWHERE句で結合して更新をかける。

例として、TableAとTableBがあったときにTableAからcol1,col2列の値を読み込み、その値で同じpkeyを持つTableBの行を書き換えるには以下のようなSQLを使う。


UPDATE TableB SET col1=A.col1, col2=A.col2
FROM (
select pkey, col1, col2
from TableA
) A
WHERE pkey = A.pkey


他のDBでは同じことを複数の列をSETに書いて UPDATE table SET(col1,col2...)=(SELECT col1,col2...) のようにできるものもあるようだが、SQL Anywhereではこの構文は使えないようである。

2010年12月28日火曜日

SQL Anywhere PHP Module

SQL Anywhere を PHP でつかうための SQL Anywhere PHP Module。

SQL Anywhere バージョン10.0.1以降で使える。

ソースもあるのでサポート対象外のPHPバージョンについてもビルドをがんばれば何とかなるかもしれない。

ダウンロード

2010年12月8日水曜日

JSONLint

JSONをライブラリを使わずに生成して受け側でSyntax Errorが出てしまったときなど、括弧が多いフォーマットなので、どこが間違っているか目ではなかなか見つけられない。

そんなときにJSONLintのサイトを使うと便利。JSONをカット&ペーストで入れると、どこにエラーがあるかを表示して整形までしてくれる。

http://www.jsonlint.com/

2010年12月5日日曜日

Android エミュレータにメディアデータを追加

Androidエミュレーター(Virtual Device)にmp3などの音楽ファイルを転送し標準のメディアプレイヤーで再生できるようにする方法。たまにしかやらない作業なのでいつもやり方を忘れてしまう・・・ここにメモしておこう。ここで使ったホスト機はWindowsです。また、Virtual Deviceには作成したときにSDCARDの容量が適当に割り当てられていることとします。


  1. Virtual Device起動。

  2. コマンドプロンプトから adb shell でシェルに入り mkdir /sdcard/music でフォルダを作成する。

  3. コマンドプロンプトに戻り adb push {mp3ファイル} /sdcard/music を実行して、さっき作ったフォルダにmp3ファイルを転送。({mp3ファイル}のところにはファイル名いれる)

  4. Virtual Deviceのアプリの一覧から "Dev Tools" を実行し "Media Scanner" を実行する









"Media Scanner" を実行すると上記のような画面になり、標準のメディアプレイヤーで追加したファイルを認識できるようになる。

2010年11月18日木曜日

java.util.Dateとandroid.text.format.Time どちらを使うべきか?

Androidにはjava.util.Dateやjava.util.Calendarに似たクラスandroid.text.format.Timeがあり、日付データを扱うときどちらを使うべきか迷うところであるが、ドキュメントによるとjava.util.Calendarより高速な代替品と書いてあるので、文字列にして表示したり日付計算する場合は後者を使うのがよさそうに思える。

http://developer.android.com/reference/android/text/format/Time.html

まだドキュメントを読んだ限りなので、ちょっと実際に使って試してみることにしよう。

2010-12-20 追記
android.text.format.TimeはSerializableでないことが判明。つまりIntentに入れてActivity間で受け渡すデータとしては使えないので注意が必要です。

Timeをサブクラス化してSerializableをimplementsしたものを作ればいいのかもしれないが、将来的にTimeのインスタンス変数にSerializableでないものが入ってくるとアウトなので今回は利用を見送る。

2010年9月9日木曜日

Android nativeコードでファイル書き込み

AndroidでJNIを使ってnativeコードからファイルを読み書きする方法を調べた。ファイルは /data/data/{pkgname} 以下のフォルダに読み書きすることができるらしい。読み書きはLinuxでのファイルIOと同じ関数open/read/write/closeが使える。

Javaからnativeの関数に byte[]配列を渡してそれをファイルに書き込む関数を作ってみた。以下のJavaソースをjavahで変換して対応するヘッダファイルを作成。

FileManager.java

package test.filetest;
public class FileManager {
public native int write(byte[] data);
static { System.loadLibrary("filetest"); }
}


test_filetest_FileManager.h

#include <jni.h>

#ifndef _Included_test_filetest_FileManager
#define _Included_test_filetest_FileManager
#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT jint JNICALL Java_test_filetest_FileManager_write
(JNIEnv *, jobject, jbyteArray);

#ifdef __cplusplus
}
#endif
#endif


Java_test_filetest_FileManager_write関数の実装は以下のようにしてみた。エラーから抜けるのにgotoを多用しているので人により好き嫌いあるかもしれないが、NDKだとtry-catchが使えないようなのでこの方法が楽といえば楽。

test_filetest_FileManager.cpp

#include "test_filetest_FileManager.h"
#include <string.h>
#include <fcntl.h>
#include <android/log.h>

#define _DBGPRINTF(...) __android_log_print(3, "filetest", __VA_ARGS__)

JNIEXPORT jint JNICALL Java_test_filetest_FileManager_write
(JNIEnv* env, jobject caller, jbyteArray jBin)
{
jbyte* bin = NULL;
int binSize;
int err = 0;
int s;

_DBGPRINTF("Java_test_filetest_FileManager_write");

// ファイルを /data/data/{pkgname} 以下のフォルダに読み書きする
// ここでは hello.dat を書き込み用にオープン(O_WRONLY)。無ければ作成(O_CREAT)
// ファイルのmodeを 0666 に設定
int fd = open("/data/data/test.filetest/hello.dat",
O_WRONLY|O_CREAT,
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
_DBGPRINTF("fd=%d\n", fd);
if (fd < 0) {
_DBGPRINTF("Error: open");
err = -1;
goto error_exit0;
}

// 渡されたJava byte配列を C byte 配列に変換
bin = env->GetByteArrayElements(jBin, NULL);
if (bin == NULL) {
_DBGPRINTF("Error: GetByteArrayElements");
err = -1;
goto error_exit1;
}
// 渡されたJava byte配列の長さを取得
binSize = env->GetArrayLength(jBin);
_DBGPRINTF("Write: %d bytes");

// writeで書き込み
s = write(fd, (void*)bin, binSize);
_DBGPRINTF("Write: ret=%d", s);
if (s < 0) {
_DBGPRINTF("Error: write");
err = -1;
}
// C byte配列を使い終わったのでメモリから解放
env->ReleaseByteArrayElements(jBin, bin, 0);

error_exit1:
// ファイルクローズ
close(fd);

error_exit0:
return err;
}


Androidのファイルシステムの中身は adb shell コマンドでシェルに入ることで確認できる。プログラムを実行すると、/data/data/test.filetestフォルダには確かにファイルができていた。

# cd /data/data/test.filetest
cd /data/data/test.filetest
# ls -l
ls -l
-rwxr-xrwT app_28 app_28 256 2010-09-09 13:31 hello.dat
drwxr-xr-x system system 2010-09-09 13:23 lib



その上位のフォルダ一覧を見てみると、フォルダ(パッケージ名)ごとに所有者やパーミションがついているのがわかる。アプリごとに所有者が違うということはAndroidはこの仕組みを使ってアプリごとのアクセス管理をしているのだろうか?

# cd /data/data
cd /data/data
# ls -l
ls -l
drwxr-xr-x app_28 app_28 2010-09-09 13:23 test.filetest
drwxr-xr-x app_24 app_24 2010-07-14 12:15 jp.hews.intent
drwxr-xr-x app_21 app_21 2010-01-27 13:32 com.android.mms
drwxr-xr-x app_5 app_5 2010-01-27 13:32 com.android.camera
drwxr-xr-x app_4 app_4 2010-01-27 13:32 com.android.email
...



2010/9/27追記:
openの際に O_CREAT が指定されている場合にはmode(ファイルパーミション)指定が必要のため追加

2010年6月21日月曜日

SQL Anywhere 自動採番したIDを取得する

データベースSQL Anywhereにはテーブル列のデフォルト値にAUTOINCREMENTを指定することで行をinsertしたときに自動採番した値が入るようになる。

たとえば以下のようなテーブルを作っておいて、

CREATE TABLE mytbl (
rid INTEGER NOT NULL DEFAULT AUTOINCREMENT CONSTRAINT PRIMARY KEY,
val VARCHAR(20) NOT NULL
)


ridは指定しないで行を書き込む。

INSERT INTO mytbl (val) VALUES('aaaaa');
INSERT INTO mytbl (val) VALUES('bbbbb');
INSERT INTO mytbl (val) VALUES('ccccc');


この結果は以下の3行となる。

  • rid=1, val='aaaaa'

  • rid=2, val='bbbbb'

  • rid=3, val='ccccc'




さて、ここで採番された値を知る方法であるが、グローバル変数@@identityに最後に割り振られた値が格納されるので以下のSQLを実行することで値を取得できる。

SELECT @@identity;


例の場合は結果は3になる。

2010年6月18日金曜日

Bloggerにソースコードを載せる方法

Bloggerでコードをきれいに表示するガジェット(ウィジェット?)にSyntaxHighlighterというものがあると知り早速使ってみる。自分のBloggerへm-namikiさんの日記を参考に追加してみた。
FireFoxで作業したところ途中でダウンロード風のダイアログが出て迷ったが、「ブラウザで開く」を選ぶことで追加が完了。

コードが以下のようにいい感じに表示される。


public class MyClass {
public void hello() {
System.out.println("Hello World");
}
}


残念ながらプレビューの段階では普通のpreタグと同じような表示になるが投稿するとちゃんと表示される。

2010年6月17日木曜日