2026年2月18日 (水)

ミックの楽しいSQLパズル / 書籍

ミックさん、インプレス様から恵贈いただきました。 :)

馴染みやすいタイトル。

SQLパズル本!
ぶ、ぶ厚いw
1日、1SQLパズルにチャレンジするか

 

ありがとうございました

Hbbfdbdbqae8e5h

Hbbfdbcbsaq0_xs

| | | コメント (0)

2025年8月22日 (金)

帰ってきた! 標準はあるにはあるが癖の多いSQL #17 - ANY_VALUE() ってなかなかいいじゃん、癖無さそう!

さて、
今回は久々に、標準はあるにはあるが癖の多いSQLシリーズです! 

データが小さいとその価値はほぼわからないかもしれませんが、ひょんなところで出会ってしまった! と、いうような状況で役立つかもしれませんwwww

今日のお題は、ANY_VALUE()関数。 集約関数の仲間です:)

MySQLやOracle Databaseのマニュアルでは使い所を理解しやすい解説があります。おすすめです。
一方、PostgreSQLのマニュアルシンプルすぎる解説ゆえ、この関数はなに? なにが美味しいの? みたいな顔になってしまうかもしれません。がw、ググってみてください、いろいろ見つかります!

この関数に出会ってよかった! ということを思いながらw
以下の曲をBGMにして眺めてみてください:)

ラブ・ストーリーは突然に / 小田和正


少量のデータだとその良さに気づきにくいのですが、万が一の時は、ANY_VALUE()集約関数を思い出してみてください。
リソース消費は数が多くなるとボディーブローにはなるので、リソース使用量削減に重箱の隅をつつくようなことしないといけないとかw そんな時にも役立つかも。。。しれないです。


参考)

Oracle / ANY_VALUE() - 19cからサポートされました
https://docs.oracle.com/cd/F19136_01/sqlrf/any_value.html

MySQL / ANY_VALUE() - 5.7からサポートされました
https://dev.mysql.com/doc/refman/8.0/ja/miscellaneous-functions.html#function_any-value

PostgreSQL / ANY_VALUE() - 16からサポートされました
https://www.postgresql.jp/document/17/html/functions-aggregate.html


環境

HostOS : macOS Sonoma 14.7.7 (arm64)
VirtualBox 7.1 (arm64)

GuestOS : Oracle Linux 8u10 (arm64)
 Oracle Database 23ai 23.8 (arm64)
 PostgreSQL 17.5 (arm64)
 MySQL 8.4.6 (arm64)

テストケース

テストケース1)

集約する列データ長が長がーーーい

テストケース2)

集約する列データは短めでもデータ量が多いケース

の2つを用意しました。
データ量はどちらも多めにしました。理由は、集計関数やGROUP BYの性能差分はデータ量が少ないと差分が見にくいためです:)
これぐらいデータにして、やっと、ふむふむと頷ける差分が見えるのではないかと思います。

計測は3回実行しています(1回目には諸々ノイズが乗りやすいので参考程度にしています)

 

では、先に結果から。
全体的に ANY_VALUE()が軽めの傾向として出てきているのは間違いないと思います。あえてそういう目的で追加してきた関数ですし。MySQLやOracle DatabaseのマニュアルではANY_VALUE()集約関数についての解説もわかりやすいとおもいます。
ANY_VALUE()の用途が広く認知されれば、可読性向上という意味もきっちり出てきそうな気はします。(個人的にはw。今は微妙は感じを持っている方は多いと思いますが、非集約列をGROUP BY句に記述するのも、MIN/MAX集約関数を使うのも可読性という意味では微妙だと思っているので、そういう目的の関数の登場で方向は定まるのではないかと。。。。w)
PostgreSQLのマニュアルに目を向けると、他の関数の説明とのバランスもあると思うのでw、さらりと書かれていて、初めて見た方は、君は何? 
という感じになりそうではあるのですが、ググると結構情報も多くなってきたので何ものかを知るのに困ることもないと思います。

 

個別のまとめ

Oracle Database 23ai free

環境による差異は多少ありそうですが、GROUP BYで対処する場合とANY_VALUE()で対処する場合では、列サイズが長い場合にはANY_VALUE()の方が効果的に対処できそうですね。CPUに優しくなっています。
一方該当列の列サイズが比較的短い場合には、GROUP BY / ANY_VALUE()大きな差はでにくです。ANYU_VALUE()の認知度次第ですが、この手のハンドリングのための記述として認知度があがると、可読性としては向上しそうな気がします。

注)軽かった順に列挙してます。

テストケース1)

ANY_VALUE() -> GROUP BY句で対処 -> MAX()

テストケース2)

ANY_VALUE() -> GROUP BY句で対処 -> MAX()

 

PostgreSQL

PostgreSQLでは、やはり、ANY_VALUE()が早いですが、MAX()とかなり近い結果となり、GROUP BYが最も遅いという結果になりました。
面白い。

テストケース1)

ANY_VALUE() -> MAX() -> GROUP BY句で対処

テストケース2)

ANY_VALUE() -> MAX() -> GROUP BY句で対処

 

MySQL

MySQLではすべてが、Aggregate using temporary table となっていたので条件的には同じ状態で比較できた分わかりやすい結果になっていました。
MySQLでもこの手のケースでANY_VALUE()を利用しておいた方がお得でしょうね。

テストケース1)

ANY_VALUE() -> MAX() -> GROUP BY句で対処

テストケース2)

ANY_VALUE() -> MAX() -> GROUP BY句で対処

 


Oracle Databaseでの処理時間まとめ

SQLモニターを利用して取得.

列サイズ長め GROUP BY

Global Stats
==============================================================================
| Elapsed | Cpu | IO | Application | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
==============================================================================
| 0.67 | 0.56 | 0.11 | 0.00 | 2 | 250K | 1981 | 2GB |
| 0.62 | 0.53 | 0.09 | | 2 | 250K | 1981 | 2GB |
| 0.61 | 0.52 | 0.09 | | 2 | 250K | 1981 | 2GB |
==============================================================================

 

MAX

Global Stats
================================================================
| Elapsed | Cpu | IO | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
================================================================
| 0.78 | 0.67 | 0.11 | 2 | 250K | 1981 | 2GB |
| 0.74 | 0.65 | 0.09 | 2 | 250K | 1981 | 2GB |
| 0.73 | 0.65 | 0.09 | 2 | 250K | 1981 | 2GB |
================================================================

 

ANY_VALUE

Global Stats
================================================================
| Elapsed | Cpu | IO | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
================================================================
| 0.34 | 0.25 | 0.09 | 2 | 250K | 1981 | 2GB |
| 0.33 | 0.25 | 0.09 | 2 | 250K | 1981 | 2GB |
| 0.34 | 0.25 | 0.09 | 2 | 250K | 1981 | 2GB |
================================================================

 

列サイズ短めで件数が多い

GROUP BY

Global Stats
================================================================
| Elapsed | Cpu | IO | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
================================================================
| 1.65 | 1.42 | 0.23 | 2 | 171K | 1363 | 1GB |
| 1.15 | 1.10 | 0.06 | 2 | 171K | 1363 | 1GB |
| 1.16 | 1.10 | 0.06 | 2 | 171K | 1363 | 1GB |
================================================================

 

MAX

Global Stats
================================================================
| Elapsed | Cpu | IO | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
================================================================
| 1.66 | 1.55 | 0.12 | 2 | 171K | 1363 | 1GB |
| 1.29 | 1.23 | 0.06 | 2 | 171K | 1363 | 1GB |
| 1.29 | 1.23 | 0.06 | 2 | 171K | 1363 | 1GB |
================================================================

 

ANY_VALUE

Global Stats
================================================================
| Elapsed | Cpu | IO | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
================================================================
| 1.47 | 1.38 | 0.10 | 2 | 171K | 1363 | 1GB |
| 1.15 | 1.09 | 0.06 | 2 | 171K | 1363 | 1GB |
| 1.15 | 1.09 | 0.06 | 2 | 171K | 1363 | 1GB |
================================================================

 


PostgreSQL

PostgreSQLのwork_memが小さかった影響で、GROUP BYによる対処ではTemp落ちして一人負けしてました。設定チューニングしていたらMAX/ANY_VALUEに近い結果になっていたかもね。(Oracleみたいにデフォでいい感じってあれではなかった、しくじりw)
とはいえ、MAX()とANY_VALUE()の差があまりないのもPostgreSQLの特徴ですかね。

 

列サイズ長め

GROUP BY

 Execution Time: 3533.979 ms
Execution Time: 3570.032 ms
Execution Time: 3553.467 ms

 

MAX

 Execution Time: 439.917 ms
Execution Time: 434.463 ms
Execution Time: 434.348 ms

 

ANY_VALUE

 Execution Time: 461.668 ms
Execution Time: 444.132 ms
Execution Time: 431.056 ms

 

 

列サイズ短めで件数が多い

GROUP BY

 Execution Time: 4300.000 ms
Execution Time: 4635.630 ms
Execution Time: 4595.763 ms

 

MAX

 Execution Time: 4449.759 ms
Execution Time: 4449.591 ms
Execution Time: 4425.708 ms

 

ANY_VALUE

 Execution Time: 4240.994 ms
Execution Time: 4145.707 ms
Execution Time: 4018.328 ms

 


MySQL

列サイズ長め

GROUP BY

1 row in set (13.16 sec)
1 row in set (13.03 sec)
1 row in set (13.03 sec)

 

MAX

1 row in set (8.59 sec)
1 row in set (8.60 sec)
1 row in set (9.40 sec)

 

ANY_VALUE

1 row in set (0.49 sec)
1 row in set (0.43 sec)
1 row in set (0.49 sec)

 

列サイズ短めで件数が多い

GROUP BY

1 row in set (21.31 sec)
1 row in set (21.90 sec)
1 row in set (20.89 sec)

 

MAX

1 row in set (15.68 sec)
1 row in set (16.16 sec)
1 row in set (16.16 sec)

 

ANY_VALUE

1 row in set (8.35 sec)
1 row in set (8.54 sec)
1 row in set (8.20 sec)

 

ということで、

帰ってきた! 標準はあるにはあるが癖の多いSQL #17 - ANY_VALUE() 、
癖があるとおもったのですが、癖はなかったですw

では、また。

 

朝晩の風が、あきっぽい、北のエリアより。。。夏祭りが終われば、あっというまに秋、、、になるはずw

Enjoy SQL! and RDBMS!

 



関連エントリー

標準はあるにはあるが癖の多いSQL 全部俺 #1 Pagination
標準はあるにはあるが癖の多いSQL 全部俺 #2 関数名は同じでも引数が逆の罠!
標準はあるにはあるが癖の多いSQL 全部俺 #3 データ型確認したい時あるんです
標準はあるにはあるが癖の多いSQL 全部俺 #4 リテラル値での除算の内部精度も違うのよ!
標準はあるにはあるが癖の多いSQL 全部俺 #5 和暦変換機能ある方が少数派
標準はあるにはあるが癖の多いSQL 全部俺 #6 時間厳守!
標準はあるにはあるが癖の多いSQL 全部俺 #7 期間リテラル!
標準はあるにはあるが癖の多いSQL 全部俺 #8 翌月末日って何日?
標準はあるにはあるが癖の多いSQL 全部俺 #9 部分文字列の扱いでも癖が出る><
標準はあるにはあるが癖の多いSQL 全部俺 #10 文字列連結の罠(有名なやつ)
標準はあるにはあるが癖の多いSQL 全部俺 #11 デュエル、じゃなくて、デュアル
標準はあるにはあるが癖の多いSQL 全部俺 #12 文字[列]探すにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #13 あると便利ですが意外となかったり
標準はあるにはあるが癖の多いSQL 全部俺 #14 連番の集合を返すにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #15 SQL command line client
標準はあるにはあるが癖の多いSQL 全部俺 #16 SQLのレントゲンを撮る方法
標準はあるにはあるが癖の多いSQL 全部俺 #17 その空白は許されないのか?
標準はあるにはあるが癖の多いSQL 全部俺 #18 (+)の外部結合は方言
標準はあるにはあるが癖の多いSQL 全部俺 #19 帰ってきた、部分文字列の扱いでも癖w
標準はあるにはあるが癖の多いSQL 全部俺 #20 結果セットを単一列に連結するにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #21 演算結果にも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #22 集合演算にも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #23 複数行INSERTにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #24 乱数作るにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #25 SQL de Fractalsにも癖がある:)
標準はあるにはあるが癖の多いSQL 全部俺 おまけ SQL de 湯婆婆やるにも癖がでるw
帰ってきた! 標準はあるにはあるが癖の多いSQL #1 SQL de ROT13 やるにも癖が出るw
帰ってきた! 標準はあるにはあるが癖の多いSQL #2 Actual Plan取得中のキャンセルでも癖が出る
帰ってきた! 標準はあるにはあるが癖の多いSQL #3 オプティマイザの結合順評価テーブル数上限にも癖が出る
帰ってきた! 標準はあるにはあるが癖の多いSQL #4 Optimizer Traceの取得でも癖がでる
帰ってきた! 標準はあるにはあるが癖の多いSQL #5 - Optimizer Hint でも癖が多い
帰ってきた! 標準はあるにはあるが癖の多いSQL #6 - Hash Joinの結合ツリーにも癖がでる
帰ってきた! 標準はあるにはあるが癖の多いSQL #7 - Hash Joinの実行計画にも癖がでる
帰ってきた! 標準はあるにはあるが癖の多いSQL #8 - Hash Joinさせるにも癖が出る
帰ってきた! 標準はあるにはあるが癖の多いSQL #9、BOOLEAN型にも癖が出る
帰ってきた! 標準はあるにはあるが癖の多いSQL #10、BOOLEAN型にも癖が出る(後編)
帰ってきた! 標準はあるにはあるが癖の多いSQL #10、BOOLEAN型にも癖が出る(後編)の おまけ - SQL*PlusのautotraceでSQL Analysis Reportが出力される! (23ai〜)
帰ってきた! 標準はあるにはあるが癖の多いSQL #11 - 引用符にも癖がでるし、NULLのソート構文にも癖がある!(前編)
帰ってきた! 標準はあるにはあるが癖の多いSQL #12 - 引用符にも癖がでるし、NULLのソート構文にも癖がある!(後編)ー 列エイリアスの扱いにも癖がある!
帰ってきた! 標準はあるにはあるが癖の多いSQL #13 - コメント書くにも癖がある
帰ってきた! 標準はあるにはあるが癖の多いSQL #14 - コメントを書く位置にも癖がでる (SQL Clientにも癖がある)
帰ってきた! 標準はあるにはあるが癖の多いSQL #15 - 実行計画でスカラー副問合せの見せ方にも癖がでる
帰ってきた! 標準はあるにはあるが癖の多いSQL #16 - FROM句のインラインビューのエイリアスにもクセがある(必須だったり、任意だったり)

 



以下、興味のある方向けのログと今回適当に作ったデータ作成スクリプトなどを載せています。以降は長いので興味のない方は飛ばしてくださいww


ーーーーーーーログーーーーーーー

Oracle Database

-- 列サイズ長め(準備)
SCOTT@localhost:1521/freepdb1> @any_value.sql
1* DROP TABLE IF EXISTS any_value_table PURGE

表が削除されました。

経過: 00:00:00.20
1 CREATE TABLE any_value_table
2 (
3 ordered_date DATE NOT NULL
4 , order_id INTEGER NOT NULL
5 , product_id INTEGER NOT NULL
6 , product_name VARCHAR(2000) NOT NULL
7 , qty INTEGER NOT NULL
8 , CONSTRAINT pk_any_value_table PRIMARY KEY (order_id, product_id, ordered_date)
9* )

表が作成されました。

経過: 00:00:00.04
1 DECLARE
2 o_date DATE := SYSDATE;
3 BEGIN
4 FOR i IN 1..1000000 LOOP
5 INSERT INTO any_value_table
6 (ordered_date
7 , order_id
8 , product_id
9 , product_name
10 , qty
11 ) VALUES (o_date, i, 1, 'ITEM_1'||lpad('*',1600,'*'), 1);
12 IF mod(i,100) = 0 THEN commit; END IF;
13 END LOOP;
14* END;

PL/SQLプロシージャが正常に完了しました。

経過: 00:02:58.25

PL/SQLプロシージャが正常に完了しました。

経過: 00:00:42.26

SEGMENT_NAME GB
------------------------------ ----------
ANY_VALUE_TABLE 1.96582031

経過: 00:00:00.03

...中略...

-- 2回目
非集計列がGROUP BY句に定義もされず、集計関数も利用されていない場合は、エラーになることの確認!
SCOTT@localhost:1521/freepdb1> @any_value_test
1 SELECT
2 product_id
3 ,product_name
4 ,SUM(qty) AS total
5 FROM
6 any_value_table
7 GROUP BY
8* product_id
,product_name
*
行3でエラーが発生しました。:
ORA-00979: "PRODUCT_NAME": GROUP BY句に出現するか、集計関数で使用される必要があります
ヘルプ:
https://docs.oracle.com/error-help/db/ora-00979/

経過: 00:00:00.01
1 SELECT /*+ MONITOR */
2 product_id
3 ,product_name
4 ,SUM(qty) AS total
5 FROM
6 any_value_table
7 GROUP BY
8 product_id
9* , product_name

PRODUCT_ID PRODUCT_NAME                                                     TOTAL
---------- ----------------------------------------------------------------------------------------------------------- ----------
1 ITEM_1***************************************************************************************************** 1000000
***********************************************************************************************************

...中略...

***********************************************************************************************************
***********************************************************************************************************
*

経過: 00:00:00.58

...中略...

SQL Text
------------------------------
SELECT /*+ MONITOR */ product_id ,product_name
,SUM(qty) AS total FROM any_value_table
GROUP BY product_id , product_name

...中略...

Global Stats
================================================================
| Elapsed | Cpu | IO | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
================================================================
| 0.62 | 0.53 | 0.09 | 2 | 250K | 1981 | 2GB |
================================================================

SQL Plan Monitoring Details (Plan Hash Value=3772843140)
=====================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | (%) | (# samples) |
=====================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 1 | +1 | 1 | 1 | | | | |
| 1 | HASH GROUP BY | | 1 | 69634 | 1 | +1 | 1 | 1 | | | 100.00 | Cpu (1) |
| 2 | TABLE ACCESS FULL | ANY_VALUE_TABLE | 1M | 69619 | 1 | +1 | 1 | 1M | 1981 | 2GB | | |
=====================================================================================================================================================

...中略...

SQL Text
------------------------------
SELECT /*+ MONITOR */ product_id ,MAX(product_name) AS product_name
,SUM(qty) AS total FROM any_value_table
GROUP BY product_id

...中略...

Global Stats
================================================================
| Elapsed | Cpu | IO | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
================================================================
| 0.74 | 0.65 | 0.09 | 2 | 250K | 1981 | 2GB |
================================================================

SQL Plan Monitoring Details (Plan Hash Value=3772843140)
=====================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | (%) | (# samples) |
=====================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 1 | +0 | 1 | 1 | | | | |
| 1 | HASH GROUP BY | | 1 | 69634 | 1 | +0 | 1 | 1 | | | | |
| 2 | TABLE ACCESS FULL | ANY_VALUE_TABLE | 1M | 69619 | 1 | +0 | 1 | 1M | 1981 | 2GB | | |
=====================================================================================================================================================

...中略...

SQL Text
------------------------------
SELECT /*+ MONITOR */ product_id ,ANY_VALUE(product_name) AS product_name
,SUM(qty) AS total FROM any_value_table
GROUP BY product_id

...中略...

Global Stats
================================================================
| Elapsed | Cpu | IO | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
================================================================
| 0.33 | 0.25 | 0.09 | 2 | 250K | 1981 | 2GB |
================================================================

SQL Plan Monitoring Details (Plan Hash Value=3772843140)
=====================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | (%) | (# samples) |
=====================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 1 | +1 | 1 | 1 | | | | |
| 1 | HASH GROUP BY | | 1 | 69634 | 1 | +1 | 1 | 1 | | | 100.00 | Cpu (1) |
| 2 | TABLE ACCESS FULL | ANY_VALUE_TABLE | 1M | 69619 | 1 | +1 | 1 | 1M | 1981 | 2GB | | |
=====================================================================================================================================================

...中略...

-- 列サイズ短めで件数が多い(準備)
SCOTT@localhost:1521/freepdb1> @any_value2.sql
1* DROP TABLE IF EXISTS any_value_table PURGE

表が削除されました。

経過: 00:00:00.13
1 CREATE TABLE any_value_table
2 (
3 ordered_date DATE NOT NULL
4 , order_id INTEGER NOT NULL
5 , product_id INTEGER NOT NULL
6 , product_name VARCHAR(2000) NOT NULL
7 , qty INTEGER NOT NULL
8 , CONSTRAINT pk_any_value_table PRIMARY KEY (order_id, product_id, ordered_date)
9* )

表が作成されました。

経過: 00:00:00.01
1 DECLARE
2 o_date DATE := SYSDATE;
3 BEGIN
4 FOR i IN 1..20000000 LOOP
5 INSERT INTO any_value_table
6 (ordered_date
7 , order_id
8 , product_id
9 , product_name
10 , qty
11 ) VALUES (o_date, i, 1, 'ITEM_1'||LPAD('*',30,'*'), 1);
12 IF mod(i,1000) = 0 THEN commit; END IF;
13 END LOOP;
14* END;

PL/SQLプロシージャが正常に完了しました。

経過: 00:12:27.16

PL/SQLプロシージャが正常に完了しました。

経過: 00:00:17.83

SEGMENT_NAME GB
------------------------------ ----------
ANY_VALUE_TABLE 1.3125

経過: 00:00:00.06

...中略...

-- 2回目
SCOTT@localhost:1521/freepdb1> @any_value_test2
1 SELECT /*+ monitor */
2 product_id
3 ,product_name
4 ,SUM(qty) AS total
5 FROM
6 any_value_table
7 GROUP BY
8 product_id
9* , product_name

PRODUCT_ID PRODUCT_NAME TOTAL
---------- ------------------------------------ ----------
1 ITEM_1****************************** 20000000

経過: 00:00:01.11

...中略...

SQL Text
------------------------------
SELECT /*+ monitor */ product_id ,product_name
,SUM(qty) AS total FROM any_value_table
GROUP BY product_id , product_name

...中略...

Global Stats
================================================================
| Elapsed | Cpu | IO | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
================================================================
| 1.15 | 1.10 | 0.06 | 2 | 171K | 1363 | 1GB |
================================================================

SQL Plan Monitoring Details (Plan Hash Value=3772843140)
=====================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | (%) | (# samples) |
=====================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 1 | +1 | 1 | 1 | | | | |
| 1 | HASH GROUP BY | | 1 | 46860 | 1 | +1 | 1 | 1 | | | | |
| 2 | TABLE ACCESS FULL | ANY_VALUE_TABLE | 20M | 46510 | 1 | +1 | 1 | 20M | 1363 | 1GB | 100.00 | Cpu (1) |
=====================================================================================================================================================

...中略...

SQL Text
------------------------------
SELECT /*+ monitor */ product_id ,MAX(product_name) AS product_name
,SUM(qty) AS total FROM any_value_table
GROUP BY product_id

...中略...

Global Stats
================================================================
| Elapsed | Cpu | IO | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
================================================================
| 1.29 | 1.23 | 0.06 | 2 | 171K | 1363 | 1GB |
================================================================

SQL Plan Monitoring Details (Plan Hash Value=3772843140)
=====================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | (%) | (# samples) |
=====================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 1 | +2 | 1 | 1 | | | | |
| 1 | HASH GROUP BY | | 1 | 46860 | 1 | +2 | 1 | 1 | | | | |
| 2 | TABLE ACCESS FULL | ANY_VALUE_TABLE | 20M | 46510 | 2 | +1 | 1 | 20M | 1363 | 1GB | 100.00 | Cpu (1) |
=====================================================================================================================================================

...中略...

SQL Text
------------------------------
SELECT /*+ monitor */ product_id ,ANY_VALUE(product_name) AS product_name
,SUM(qty) AS total FROM any_value_table
GROUP BY product_id

...中略...

Global Stats
================================================================
| Elapsed | Cpu | IO | Fetch | Buffer | Read | Read |
| Time(s) | Time(s) | Waits(s) | Calls | Gets | Reqs | Bytes |
================================================================
| 1.15 | 1.09 | 0.06 | 2 | 171K | 1363 | 1GB |
================================================================

SQL Plan Monitoring Details (Plan Hash Value=3772843140)
==========================================================================================================================================================
| Id | Operation | Name | Rows | Cost | Time | Start | Execs | Rows | Read | Read | Activity | Activity Detail |
| | | | (Estim) | | Active(s) | Active | | (Actual) | Reqs | Bytes | (%) | (# samples) |
==========================================================================================================================================================
| 0 | SELECT STATEMENT | | | | 1 | +1 | 1 | 1 | | | | |
| 1 | HASH GROUP BY | | 1 | 46860 | 1 | +1 | 1 | 1 | | | | |
| 2 | TABLE ACCESS FULL | ANY_VALUE_TABLE | 20M | 46510 | 2 | +0 | 1 | 20M | 1363 | 1GB | 100.00 | direct path read (1) |
==========================================================================================================================================================

 


PostgreSQL

-- 列サイズ長め(準備)
perftestdb=> \i ./any_value.sql
Timing is on.
DROP TABLE
Time: 7.248 ms
CREATE TABLE
Time: 3.827 ms
DO
Time: 24680.064 ms (00:24.680)
ANALYZE
Time: 104.675 ms
Timing is off.

...中略...

-- 2回目
PostgreSQLでも非集計列をGROUP BYに記述しないと、エラーになりますよね。
perftestdb=> \i ./any_value_test.sql
psql:any_value_test.sql:11: ERROR: column "any_value_table.product_name" must appear in the GROUP BY clause
or be used in an aggregate function
LINE 3: ,product_name
^


注)出力内容は見やすく加工しちゃってます
product_id | product_name | total
------------+-------------------------------------------------------------------------------------------------------------+--------
1 | ITEM_1***************************************************************************************************** | 1000000
***********************************************************************************************************
***********************************************************************************************************

...中略...

***********************************************************************************************************
***********************************************************************************************************
*
(1 row)


GROUP BYで対処したケースで、work_memセットし忘れてデフォのままだったので Temp落ちして一人負けしてました。すみません。
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------
GroupAggregate (cost=2471963.84..2491963.84 rows=1000000 width=1622) (actual time=3044.982..3044.983 rows=1 loops=1)
Output: product_id, product_name, sum(qty)
Group Key: any_value_table.product_id, any_value_table.product_name
Buffers: shared hit=250000, temp read=598111 written=598519
-> Sort (cost=2471963.84..2474463.84 rows=1000000 width=1618) (actual time=2479.915..2867.067 rows=1000000 loops=1)
Output: product_id, product_name, qty
Sort Key: any_value_table.product_id, any_value_table.product_name
Sort Method: external merge Disk: 1595032kB
Buffers: shared hit=250000, temp read=598111 written=598519
-> Seq Scan on scott.any_value_table (cost=0.00..260000.00 rows=1000000 width=1618) (actual time=0.012..216.822 rows=1000000 loops=1)
Output: product_id, product_name, qty
Buffers: shared hit=250000
Planning:
Buffers: shared hit=2
Memory: used=14kB allocated=16kB
Planning Time: 0.409 ms
Execution Time: 3570.032 ms
(17 rows)

...中略...

QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=267500.00..267500.01 rows=1 width=44) (actual time=434.445..434.445 rows=1 loops=1)
Output: product_id, max((product_name)::text), sum(qty)
Group Key: any_value_table.product_id
Batches: 1 Memory Usage: 24kB
Buffers: shared hit=250000
-> Seq Scan on scott.any_value_table (cost=0.00..260000.00 rows=1000000 width=1618) (actual time=0.003..122.488 rows=1000000 loops=1)
Output: ordered_date, order_id, product_id, product_name, qty
Buffers: shared hit=250000
Planning:
Memory: used=14kB allocated=16kB
Planning Time: 0.324 ms
Execution Time: 434.463 ms
(12 rows)

...中略...

QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=267500.00..267500.01 rows=1 width=44) (actual time=444.114..444.114 rows=1 loops=1)
Output: product_id, any_value(product_name), sum(qty)
Group Key: any_value_table.product_id
Batches: 1 Memory Usage: 24kB
Buffers: shared hit=250000
-> Seq Scan on scott.any_value_table (cost=0.00..260000.00 rows=1000000 width=1618) (actual time=0.003..138.239 rows=1000000 loops=1)
Output: ordered_date, order_id, product_id, product_name, qty
Buffers: shared hit=250000
Planning:
Memory: used=14kB allocated=16kB
Planning Time: 0.043 ms
Execution Time: 444.132 ms
(12 rows)

...中略...

-- 列サイズ短めで件数が多い(準備)
perftestdb=> \i ./any_value2.sql
Timing is on.
DROP TABLE
Time: 126.466 ms
CREATE TABLE
Time: 6.143 ms
DO
Time: 80158.605 ms (01:20.159)
ANALYZE
Time: 136.012 ms
Timing is off.
perftestdb=>

...中略...

-- 2回目
perftestdb=> \i ./any_value_test2.sql
SET
product_id | product_name | total
------------+--------------------------------------+----------
1 | ITEM_1****************************** | 20000000
(1 row)

QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=556186.00..556186.01 rows=1 width=49) (actual time=4635.607..4635.608 rows=1 loops=1)
Output: product_id, product_name, sum(qty)
Group Key: any_value_table.product_id, any_value_table.product_name
Batches: 1 Memory Usage: 24kB
Buffers: shared hit=206186
-> Seq Scan on scott.any_value_table (cost=0.00..406186.00 rows=20000000 width=45) (actual time=0.004..1041.109 rows=20000000 loops=1)
Output: ordered_date, order_id, product_id, product_name, qty
Buffers: shared hit=206186
Planning:
Buffers: shared hit=3
Memory: used=14kB allocated=16kB
Planning Time: 0.063 ms
Execution Time: 4635.630 ms
(13 rows)

...中略...

QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=556186.00..556186.01 rows=1 width=44) (actual time=4449.572..4449.572 rows=1 loops=1)
Output: product_id, max((product_name)::text), sum(qty)
Group Key: any_value_table.product_id
Batches: 1 Memory Usage: 24kB
Buffers: shared hit=206186
-> Seq Scan on scott.any_value_table (cost=0.00..406186.00 rows=20000000 width=45) (actual time=0.004..1007.065 rows=20000000 loops=1)
Output: ordered_date, order_id, product_id, product_name, qty
Buffers: shared hit=206186
Planning:
Memory: used=14kB allocated=16kB
Planning Time: 0.049 ms
Execution Time: 4449.591 ms
(12 rows)

...中略...

QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------
HashAggregate (cost=556186.00..556186.01 rows=1 width=44) (actual time=4145.688..4145.688 rows=1 loops=1)
Output: product_id, any_value(product_name), sum(qty)
Group Key: any_value_table.product_id
Batches: 1 Memory Usage: 24kB
Buffers: shared hit=206186
-> Seq Scan on scott.any_value_table (cost=0.00..406186.00 rows=20000000 width=45) (actual time=0.005..1006.129 rows=20000000 loops=1)
Output: ordered_date, order_id, product_id, product_name, qty
Buffers: shared hit=206186
Planning:
Memory: used=14kB allocated=16kB
Planning Time: 0.050 ms
Execution Time: 4145.707 ms
(12 rows)

 

MySQL

-- 列サイズ長め(準備)
mysql> \. /home/master/any_value.sql
Query OK, 0 rows affected (0.03 sec)

Empty set (0.00 sec)

Query OK, 0 rows affected (0.05 sec)

Empty set (0.00 sec)

Query OK, 0 rows affected (0.05 sec)

Empty set (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

Query OK, 0 rows affected (0.00 sec)

+--------------+
| @@AUTOCOMMIT |
+--------------+
| 0 |
+--------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (2 min 38.38 sec)

Empty set (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

+--------------+
| @@AUTOCOMMIT |
+--------------+
| 1 |
+--------------+
1 row in set (0.00 sec)

+----------------------------+---------+----------+----------+
| Table | Op | Msg_type | Msg_text |
+----------------------------+---------+----------+----------+
| perftestdb.any_value_table | analyze | status | OK |
+----------------------------+---------+----------+----------+
1 row in set (0.01 sec)

...中略...

-- 2回目
MySQLでも今のリリースでは、非集計列をGROUP BY 句に記述しないとエラーになりますよね。
mysql> \. /home/master/any_value_test.sql
ERROR 1055 (42000): Expression #2 of SELECT list is not in GROUP BY clause and contains nonaggregated column
'perftestdb.any_value_table.product_name' which is not functionally dependent on columns in GROUP BY clause;
this is incompatible with sql_mode=only_full_group_by


注)出力内容は見やすく加工しちゃってます
+------------+-------------------------------------------------------------------------------------------------------------+----------+
| product_id | product_name | total |
+------------+-------------------------------------------------------------------------------------------------------------+----------+
| 1 | ITEM_1***************************************************************************************************** | 20000000 |
| | *********************************************************************************************************** | |
| | *********************************************************************************************************** | |

...中略...

| | *********************************************************************************************************** | |
| | *********************************************************************************************************** | |
| | * | |
+------------+-------------------------------------------------------------------------------------------------------------+----------+
1 row in set (13.03 sec)

+-------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+-------------------------------------------------------------------------------------------------------------+
| -> Table scan on (actual time=12979..12979 rows=1 loops=1)
-> Aggregate using temporary table (actual time=12979..12979 rows=1 loops=1)
-> Table scan on any_value_table (cost=116731 rows=888992) (actual time=0.0124..290 rows=1e+6 loops=1)
|
+-------------------------------------------------------------------------------------------------------------+
1 row in set (12.98 sec)

...中略...

+-------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+-------------------------------------------------------------------------------------------------------------+
| -> Table scan on (actual time=8620..8620 rows=1 loops=1)
-> Aggregate using temporary table (actual time=8620..8620 rows=1 loops=1)
-> Table scan on any_value_table (cost=116731 rows=888992) (actual time=0.0136..288 rows=1e+6 loops=1)
|
+-------------------------------------------------------------------------------------------------------------+
1 row in set (8.62 sec)

...中略...

+-------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+-------------------------------------------------------------------------------------------------------------+
| -> Table scan on (actual time=492..492 rows=1 loops=1)
-> Aggregate using temporary table (actual time=492..492 rows=1 loops=1)
-> Table scan on any_value_table (cost=116731 rows=888992) (actual time=0.0163..258 rows=1e+6 loops=1)
|
+-------------------------------------------------------------------------------------------------------------+
1 row in set (0.49 sec)

...中略...


-- 列サイズ短めで件数が多い(準備)
mysql> \. /home/master/any_value2.sql
Query OK, 0 rows affected (0.03 sec)

Empty set (0.00 sec)

Query OK, 0 rows affected (0.04 sec)

Empty set (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

Empty set (0.00 sec)

Query OK, 0 rows affected (0.02 sec)

Query OK, 0 rows affected (0.00 sec)

+--------------+
| @@AUTOCOMMIT |
+--------------+
| 0 |
+--------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (9 min 11.20 sec)

Empty set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

+--------------+
| @@AUTOCOMMIT |
+--------------+
| 1 |
+--------------+
1 row in set (0.00 sec)

+----------------------------+---------+----------+----------+
| Table | Op | Msg_type | Msg_text |
+----------------------------+---------+----------+----------+
| perftestdb.any_value_table | analyze | status | OK |
+----------------------------+---------+----------+----------+
1 row in set (0.03 sec)

...中略...

-- 2回目
mysql> \. /home/master/any_value_test2.sql
+------------+--------------------------------------+----------+
| product_id | product_name | total |
+------------+--------------------------------------+----------+
| 1 | ITEM_1****************************** | 20000000 |
+------------+--------------------------------------+----------+
1 row in set (21.90 sec)

+-------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+-------------------------------------------------------------------------------------------------------------+
| -> Table scan on (actual time=22964..22964 rows=1 loops=1)
-> Aggregate using temporary table (actual time=22964..22964 rows=1 loops=1)
-> Table scan on any_value_table (cost=2.01e+6 rows=19.9e+6) (actual time=0.0134..4447 rows=20e+6 loops=1)
|
+-------------------------------------------------------------------------------------------------------------+
1 row in set (22.97 sec)

...中略...

+-------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+-------------------------------------------------------------------------------------------------------------+
| -> Table scan on (actual time=17478..17478 rows=1 loops=1)
-> Aggregate using temporary table (actual time=17478..17478 rows=1 loops=1)
-> Table scan on any_value_table (cost=2.01e+6 rows=19.9e+6) (actual time=0.0115..4399 rows=20e+6 loops=1)
|
+-------------------------------------------------------------------------------------------------------------+
1 row in set (17.48 sec)

...中略...

+-------------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+-------------------------------------------------------------------------------------------------------------+
| -> Table scan on (actual time=9273..9273 rows=1 loops=1)
-> Aggregate using temporary table (actual time=9273..9273 rows=1 loops=1)
-> Table scan on any_value_table (cost=2.01e+6 rows=19.9e+6) (actual time=0.0116..4208 rows=20e+6 loops=1)
|
+-------------------------------------------------------------------------------------------------------------+
1 row in set (9.28 sec)

 



-------------------- Scripts ----------------------

Oracle Database

列長の長いテストケース準備

any_value.sql

DROP TABLE IF EXISTS any_value_table PURGE
.
l
/

CREATE TABLE any_value_table
(
ordered_date DATE NOT NULL
, order_id INTEGER NOT NULL
, product_id INTEGER NOT NULL
, product_name VARCHAR(2000) NOT NULL
, qty INTEGER NOT NULL
, CONSTRAINT pk_any_value_table PRIMARY KEY (order_id, product_id, ordered_date)
)
.
l
/

DECLARE
o_date DATE := SYSDATE;
BEGIN
FOR i IN 1..1000000 LOOP
INSERT INTO any_value_table
(ordered_date
, order_id
, product_id
, product_name
, qty
) VALUES (o_date, i, 1, 'ITEM_1'||lpad('*',1600,'*'), 1);
IF mod(i,100) = 0 THEN commit; END IF;
END LOOP;
END;
.
l
/

EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname=>'SCOTT',tabname=>'any_value_table',cascade=>true,no_invalidate=>false);
select segment_name,bytes/1024/1024/1024 "GB" from user_segments where segment_name = upper('any_value_table');

 

列長の長いケースのテスト(エラーになるSQL含む)

any_value_test.sql

SET LINESIZE 300
SET PAGESIZE 1000
SET LONGCHUNK 1000
SET LONG 100000

-- error --
SELECT
product_id
,product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
.
l
/

SELECT /*+ monitor */
product_id
,product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
, product_name
.
l
/
select DBMS_SQLTUNE.REPORT_SQL_MONITOR(SQL_ID=>NULL,TYPE=>'TEXT');

SELECT /*+ monitor */
product_id
,MAX(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
.
l
/
select DBMS_SQLTUNE.REPORT_SQL_MONITOR(SQL_ID=>NULL,TYPE=>'TEXT');


SELECT /*+ monitor */
product_id
,ANY_VALUE(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
.
l
/
select DBMS_SQLTUNE.REPORT_SQL_MONITOR(SQL_ID=>NULL,TYPE=>'TEXT');

 

 

列サイズ短めで件数が多いテストケースの準備

any_value2.sql


DROP TABLE IF EXISTS any_value_table PURGE
.
l
/

CREATE TABLE any_value_table
(
ordered_date DATE NOT NULL
, order_id INTEGER NOT NULL
, product_id INTEGER NOT NULL
, product_name VARCHAR(2000) NOT NULL
, qty INTEGER NOT NULL
, CONSTRAINT pk_any_value_table PRIMARY KEY (order_id, product_id, ordered_date)
)
.
l
/


DECLARE
o_date DATE := SYSDATE;
BEGIN
FOR i IN 1..20000000 LOOP
INSERT INTO any_value_table
(ordered_date
, order_id
, product_id
, product_name
, qty
) VALUES (o_date, i, 1, 'ITEM_1'||LPAD('*',30,'*'), 1);
IF mod(i,1000) = 0 THEN commit; END IF;v END LOOP;
END;
.
l
/

col product_name for a30
EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname=>'SCOTT',tabname=>'any_value_table',cascade=>true,no_invalidate=>false);
select segment_name,bytes/1024/1024/1024 "GB" from user_segments where segment_name = upper('any_value_table');

 

列サイズ短めで件数が多いテストケースの準備

any_value_test2.sql

SET LINESIZE 300
SET PAGESIZE 1000
SET LONGCHUNK 1000
SET LONG 100000


SELECT /*+ monitor */
product_id
,product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
, product_name
.
l
/

select DBMS_SQLTUNE.REPORT_SQL_MONITOR(SQL_ID=>NULL,TYPE=>'TEXT');

SELECT /*+ monitor */
product_id
,MAX(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
.
l
/

select DBMS_SQLTUNE.REPORT_SQL_MONITOR(SQL_ID=>NULL,TYPE=>'TEXT');

SELECT /*+ monitor */
product_id
,ANY_VALUE(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
.
l
/
select DBMS_SQLTUNE.REPORT_SQL_MONITOR(SQL_ID=>NULL,TYPE=>'TEXT');

 


PostgreSQL

 

列長の長いテストケース準備

any_value.sql

\timing
DROP TABLE IF EXISTS any_value_table;

CREATE TABLE any_value_table
(
ordered_date DATE NOT NULL
, order_id INTEGER NOT NULL
, product_id INTEGER NOT NULL
, product_name VARCHAR(2000) NOT NULL
, qty INTEGER NOT NULL
, CONSTRAINT pk_any_value_table PRIMARY KEY (order_id, product_id, ordered_date)
);

DO $$
DECLARE
o_date DATE := CURRENT_DATE;
BEGIN
FOR i IN 1..1000000 LOOP
INSERT INTO any_value_table
(ordered_date
, order_id
, product_id
, product_name
, qty
) VALUES (o_date, i, 1, 'ITEM_1'||lpad('*',1600,'*'), 1);
IF mod(i,100) = 0 THEN
COMMIT;
END IF;
END LOOP;
END
$$;

analyze any_value_table;
\timing

 

列長の長いテストケース(エラーケース含む)
any_value_test.sql

-- error --
SELECT
product_id
,product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
;

set max_parallel_workers_per_gather = 0;
SELECT
product_id
,product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
, product_name
;

explain (analyze,buffers,memory,summary,verbose)
SELECT
product_id
,product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
, product_name
;

SELECT
product_id
,MAX(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
;

explain (analyze,buffers,memory,summary,verbose)
SELECT
product_id
,MAX(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
;

SELECT
product_id
,ANY_VALUE(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
;

explain (analyze,buffers,memory,summary,verbose)
SELECT
product_id
,ANY_VALUE(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
;

 

列サイズ短めで件数が多いテストケースの準備

any_value2.sql

\timing
DROP TABLE IF EXISTS any_value_table;

CREATE TABLE any_value_table
(
ordered_date DATE NOT NULL
, order_id INTEGER NOT NULL
, product_id INTEGER NOT NULL
, product_name VARCHAR(2000) NOT NULL
, qty INTEGER NOT NULL
, CONSTRAINT pk_any_value_table PRIMARY KEY (order_id, product_id, ordered_date)
);

DO $$
DECLARE
o_date DATE := CURRENT_DATE;
BEGIN
FOR i IN 1..20000000 LOOP
INSERT INTO any_value_table
(ordered_date
, order_id
, product_id
, product_name
, qty
) VALUES (o_date, i, 1, 'ITEM_1'||LPAD('*',30,'*'), 1);
IF mod(i,1000) = 0 THEN commit; END IF;
END LOOP;
END
$$
;

analyze any_value_table;
\timing

 

列サイズ短めで件数が多いテストケース

any_value_test2.sql

set max_parallel_workers_per_gather = 0;

SELECT
product_id
,product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
, product_name;

explain (analyze,buffers,memory,summary,verbose)
SELECT
product_id
,product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
, product_name;


SELECT
product_id
,MAX(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id;


explain (analyze,buffers,memory,summary,verbose)
SELECT
product_id
,MAX(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id;


SELECT
product_id
,ANY_VALUE(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id;

explain (analyze,buffers,memory,summary,verbose)
SELECT
product_id
,ANY_VALUE(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id;

 

 


MySQL

 

列長の長いテストケース準備

any_value.sql

DROP TABLE IF EXISTS any_value_table;
show warnings;

CREATE TABLE any_value_table
(
ordered_date DATE NOT NULL
, order_id INTEGER NOT NULL
, product_id INTEGER NOT NULL
, product_name VARCHAR(2000) NOT NULL
, qty INTEGER NOT NULL
, CONSTRAINT pk_any_value_table PRIMARY KEY (order_id, product_id, ordered_date)
);
show warnings;

DROP PROCEDURE IF EXISTS make_any_table_data;
show warnings;

DELIMITER $$
CREATE PROCEDURE make_any_table_data()
BEGIN
DECLARE o_date DATE DEFAULT CURRENT_DATE;
DECLARE i INTEGER DEFAULT 1;
DECLARE r_count INTEGER DEFAULT 1000000;
loop1: LOOP
INSERT INTO any_value_table
(ordered_date
, order_id
, product_id
, product_name
, qty
) VALUES (o_date, i, 1, CONCAT('ITEM_1', lpad('*',1600,'*')), 1);
IF mod(i,100) = 0 THEN commit; END IF;
SET i = i + 1;
IF i > r_count THEN LEAVE loop1; END IF;
END LOOP loop1;
END
$$
DELIMITER ;

set AUTOCOMMIT=0;
select @@AUTOCOMMIT;

CALL make_any_table_data;
show warnings;

set AUTOCOMMIT=1;
select @@AUTOCOMMIT;

analyze table any_value_table;

 

列長の長いテストケース(エラーケース含む)

any_value_test.sql

-- error --
SELECT
product_id
,product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
;


SELECT
product_id
,product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
, product_name
;

explain analyze format=tree
SELECT
product_id
,product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
, product_name
;


SELECT
product_id
,MAX(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
;

explain analyze format=tree
SELECT
product_id
,MAX(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
;

SELECT
product_id
,ANY_VALUE(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
;


explain analyze format=tree
SELECT
product_id
,ANY_VALUE(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
;

 

列サイズ短めで件数が多いテストケース(準備)

any_value2.sql

DROP TABLE IF EXISTS any_value_table;
show warnings;

CREATE TABLE any_value_table
(
ordered_date DATE NOT NULL
, order_id INTEGER NOT NULL
, product_id INTEGER NOT NULL
, product_name VARCHAR(2000) NOT NULL
, qty INTEGER NOT NULL
, CONSTRAINT pk_any_value_table PRIMARY KEY (order_id, product_id, ordered_date)
);
show warnings;

DROP PROCEDURE IF EXISTS make_any_table_data;
show warnings;

DELIMITER $$
CREATE PROCEDURE make_any_table_data()
BEGIN
DECLARE o_date DATE DEFAULT CURRENT_DATE;
DECLARE i INTEGER DEFAULT 1;
DECLARE r_count INTEGER DEFAULT 20000000;
loop1: LOOP
INSERT INTO any_value_table
(ordered_date
, order_id
, product_id
, product_name
, qty
) VALUES (o_date, i, 1, CONCAT('ITEM_1', LPAD('*',30,'*')), 1);
IF mod(i,1000) = 0 THEN commit; END IF;
SET i = i + 1;
IF i > r_count THEN LEAVE loop1; END IF;
END LOOP loop1;
END
$$
DELIMITER ;

set AUTOCOMMIT=0;
select @@AUTOCOMMIT;

CALL make_any_table_data;
show warnings;

set AUTOCOMMIT=1;
select @@AUTOCOMMIT;

analyze table any_value_table;

 

列サイズ短めで件数が多いテストケース

any_value_test2.sql

SELECT  
product_id
,product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
, product_name;

explain analyze format=tree
SELECT
product_id
,product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id
, product_name;

SELECT
product_id
,MAX(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id;


explain analyze format=tree
SELECT
product_id
,MAX(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id;


SELECT
product_id
,ANY_VALUE(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id;

explain analyze format=tree
SELECT
product_id
,ANY_VALUE(product_name) AS product_name
,SUM(qty) AS total
FROM
any_value_table
GROUP BY
product_id;

 

| | | コメント (0)

2025年5月26日 (月)

スマートロジックの亜種のお話 / PostgreSQL, MySQL, Oracle Databaseそれぞれの影響

本題に入る前に、

祝! Mac De Oracle 20周年記念!!!!! Happy 20th Anniversary Mac De Oracle !!!

20年前の第一回目の記事はどんな内容だったでしょう!!!!
Panther De Oracle10g その1

MacOS (Mac OS X 10.3 / Panther ) に直接イントールして遊べる Oracle Database があったころの話ですw
なつかしい!
また、当時は失敗作と名高いw (今のMac Studio並の筐体)PowerMac G4 Cube 450Mhz改 Sonnet 1.2Ghz 832GMB RAM を使っていました。これまた懐かしいSonnetのCPUカードで。

そして最後に、最も大切なブログの名前 "Mac De Oracle" は、どう閃いたのか!!!
当時、Zopeネタのブログ、 "Cube De Zope" からG4 Cube繋がりでインスパイアされて、 de だけ頂いて (^^) 、
(知ってるかたどれぐらいいるのでしょうね)

付けたタイトルが、Mac De Oracle でした。

あ、忘れちゃいけない、そもそもブログ書いたら〜。Oracleの!!
と、背中を推してくれたのは妻なんですけどねw 
彼女の一言がなかったら Mac De Oracleも Oracle ACEにもなってなかったでしょうね。
ありがとう!

 

ということで、

これからも雑多なネタ織り交ぜて、楽しく書いていくことになるw
Mac De Oracle (まだ残してあるIntel MacのVirtalBoxで動いてたりするネタも多いのですけどもw) を、よろしくお願いいたします。 m(_ _)m

 



では、本日のおはなし。(ちょいと長めです)

 

WHERE句でCOALESCE関数を利用したスマートロジックの亜種って、Poor performanceを起こすってネタ、世間ではかなり書かれている印象なのですが、今日は、そんな中でも癖の強そうな、COALESCE関数を使ったスマートロジックの亜種の話。。

スマートロジックの亜種と書いた理由は、動的SQLで素直に書けばなんの問題のないもない比較的単純なSQL文を、COALESCE関数とNULLを組み合わせ動的SQLを回避したいという意図で書かれたものだから。。です。

また、この亜種は利用するデータベース(オプティマイザーだが)で影響の出方も異なるというところが、興味深いところだったりします。
なお、影響が小さそうに見える症状でも、膨大な量のデータも扱っている方達には、塵も積もれば。。。。という点には、むむむむ。。。となるはず。。

Oracle Database 21c, MySQL 8.0.36, PostgreSQL 16.3 いずれも、ちょい前のリリースにしてあります。前からそうだからってのも診てもらおうと。。。
(なお、今回利用している環境は、MacBook Intel 上のVirtualBoxのVMを利用しています。このためだけにIntel Macが残っているww)

piraruku ~ % sw_vers
ProductName: macOS
ProductVersion: 12.7.6
BuildVersion: 21H1320
piraruku ~ % /usr/sbin/system_profiler SPHardwareDataType | grep -E '(Processor|Cores|Memory|Chip|Model Name)'
Model Name: MacBook
Processor Name: Dual-Core Intel Core m5
Processor Speed: 1.2 GHz
Number of Processors: 1
Total Number of Cores: 2
Memory: 8 GB
piraruku ~ % VBoxManage -V
7.0.10r158379

 

 

Oracle Databaseの表と索引、データ件数ですが、MySQL, PostgreSQLでも同一の表、索引、データを登録してあります。

SCOTT@orclpdb1> desc customers
名前 NULL? 型
----------------------------------------- -------- ----------------------------------
CUSTOMER_ID NOT NULL NUMBER(6)
FIRST_NAME NOT NULL VARCHAR2(20)
LAST_NAME NOT NULL VARCHAR2(20)
ADDRESS VARCHAR2(40)
PHONE_NUMBER VARCHAR2(25)

SCOTT@orclpdb1> desc orders
名前 NULL? 型
----------------------------------------- -------- ----------------------------------
ORDER_ID NOT NULL NUMBER(12)
ORDER_DATE NOT NULL TIMESTAMP(6) WITH LOCAL TIME ZONE
ORDER_MODE VARCHAR2(8)
CUSTOMER_ID NOT NULL NUMBER(6)
ORDER_STATUS NUMBER(2)
ORDER_TOTAL NUMBER(8,2)
SALES_REP_ID NUMBER(6)
PROMOTION_ID NUMBER(6)


TABLE_NAME INDEX_NAME COLUMN_NAME
------------------------------ ------------------------------ ------------------------------
CUSTOMERS PK_CUSTOMERS CUSTOMER_ID
ORDERS FK_ORDERS_CUSTOMERS CUSTOMER_ID
ORDERS PK_ORDERS ORDER_ID

SCOTT@orclpdb1> select count(1) from orders;

COUNT(1)
----------
105

SCOTT@orclpdb1> select count(1) from customers;

COUNT(1)
----------
319

 

 

 

まずは、問題のSQL文の例から診てもらいましょう。

SELECT
orders.order_id
, orders.order_date
, customers.first_name FROM orders INNER JOIN customers ON orders.customer_id = customers.customer_id WHERE customers.customer_id = COALESCE(:cust_id, customers.customer_id) AND orders.order_id = COALESCE(:order_id, orders.order_id);

 

みなさん, 上記SQL文のWHERE句で、なにをスマートにやりたい(と思っている)のか、わかりますか?

答え

バインド変数(cust_id, order_id)にどちも NULL がセットされた場合は、全顧客のオーダーをリスト.
特定のcust_idが指定されたら、該当顧客の前オーダーをリスト(このときorder_idはNULL).
特定のorder_idが指定された、該当オーダーをリスト(このときcust_idはNULL).
どちらの変数にも特定のオーダーと顧客が指定されたら該当するオーダーをリスト。

ようするに、全件取得と特定のデータの取得で個別のWHEREの条件に書きかける動的SQLにすればよいわけですけども、
動的SQLを回避したい、ただそこだけに着目してしまった"スマートロジックの亜種"になっています。

WHERE句のCOALESCE関数。SELECTリストならともかく、検索時の弊害が多くなる使い方ですよね。
スマートなように見えているのは机の上だけです。

実際にオプティマイザがどうするか次第ですが、大抵の場合、検索時のフィルタリングが諸悪の根源になる場合が多いいですよね。ご存知の方も多いと思います。
(データ量が多い場合は軽視できない部分です。それらについてもググると沢山ヒットするはずです)

で、
Oracle Database/MySQL/PostgreSQLのうち一つで、フィルタリング以外の影響を引き起こすことに気がついてしまったので、メモがわりに書いておきまっす”

(今回利用したスクリプトは後半に貼ってあります)


Oracle Database 21c から診てみましょう。

SCOTT@orclpdb1> select banner_legacy from v$version;

BANNER_LEGACY
----------------------------------------------------------------------
Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 - Production

 

 

1) :cust_id, :order_id どちらも NULL にした場合(なお、バインドピークは有効のままです)

事前の想定通り、全データ取得のケースであるにもかかわらず、Table full scannの操作で、COALESCE関数を伴うフィルタリングが現れています。明らかに電力の無駄遣いw データが少ないと影響は見えにくいですが。
(HASH JOINで利用されている赤字にしている作業用メモリサイズは覚えておいてくださいね。改善後の実行計画の部分で必要になります)

SCOTT@orclpdb1> @testrun1 null null

CUST_ID
----------
[null]

ORDER_ID
----------
[null]

1 SELECT
2 /*+
3 gather_plan_statistics
4 */
5 orders.order_id
6 , orders.order_date
7 , customers.first_name
8 FROM
9 orders
10 INNER JOIN customers
11 ON
12 orders.customer_id = customers.customer_id
13 WHERE
14 customers.customer_id = COALESCE(:cust_id, customers.customer_id)
15* AND orders.order_id = COALESCE(:order_id, orders.order_id)

...略...

Plan hash value: 23084738

-------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | Cost (%CPU)| A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
-------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 6 (100)| 105 |00:00:00.01 | 13 | | | |
|* 1 | HASH JOIN | | 1 | 6 (0)| 105 |00:00:00.01 | 13 | 1376K| 1376K| 1558K (0)|
|* 2 | TABLE ACCESS FULL| ORDERS | 1 | 5 (0)| 105 |00:00:00.01 | 2 | | | |
|* 3 | TABLE ACCESS FULL| CUSTOMERS | 1 | 1 (0)| 319 |00:00:00.01 | 11 | | | |
-------------------------------------------------------------------------------------------------------------------------

...略...

Predicate Information (identified by operation id):
---------------------------------------------------

1 - access("ORDERS"."CUSTOMER_ID"="CUSTOMERS"."CUSTOMER_ID")
2 - filter("ORDERS"."ORDER_ID"=COALESCE(:ORDER_ID,"ORDERS"."ORDER_ID"))
3 - filter("CUSTOMERS"."CUSTOMER_ID"=COALESCE(:CUST_ID,"CUSTOMERS"."CUSTOMER_ID"))

 

なお、opt_param('_optim_peek_user_binds', 'false')ヒントでbind peekをオフにしても同じ結果でした。

2) :cust_id, :order_idともに値をNULL以外に設定した場合(バインドピーク有効のままですがハードパースさせています)

実行計画が変化しました。ただ、ORDERSではTable Full Scanのままです。(データ量が少ない影響かもしれないですね。とは言え気になるw)

SCOTT@orclpdb1> @testrun1 144 2435

CUST_ID
----------
144

ORDER_ID
----------
2435

...略...

Plan hash value: 4191309613

----------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 6 (100)| 1 |00:00:00.01 | 4 |
| 1 | NESTED LOOPS | | 1 | 1 | 30 | 6 (0)| 1 |00:00:00.01 | 4 |
| 2 | NESTED LOOPS | | 1 | 1 | 30 | 6 (0)| 1 |00:00:00.01 | 3 |
|* 3 | TABLE ACCESS FULL | ORDERS | 1 | 1 | 19 | 5 (0)| 1 |00:00:00.01 | 2 |
|* 4 | INDEX UNIQUE SCAN | PK_CUSTOMERS | 1 | 1 | | 0 (0)| 1 |00:00:00.01 | 1 |
| 5 | TABLE ACCESS BY INDEX ROWID| CUSTOMERS | 1 | 1 | 11 | 1 (0)| 1 |00:00:00.01 | 1 |
----------------------------------------------------------------------------------------------------------------------------

...略...

Predicate Information (identified by operation id):
---------------------------------------------------

3 - filter("ORDERS"."ORDER_ID"=COALESCE(:ORDER_ID,"ORDERS"."ORDER_ID"))
4 - access("ORDERS"."CUSTOMER_ID"="CUSTOMERS"."CUSTOMER_ID")
filter("CUSTOMERS"."CUSTOMER_ID"=COALESCE(:CUST_ID,"CUSTOMERS"."CUSTOMER_ID"))

 

 

ORDERSの主キー索引をユニークスキャンさせるようにindexヒントを追加すると素直に効いてくれますね。ですが、ここがポイントです。index full scanしています。

ここ試験にでますよ。これCOALESCE関数の影響です。主キー索引からindex unique scanすればよいはずですが、できななくなるんですよ。

index full scan + table access by index rowid batched (1行だけ) ですが. 結局、無駄なデータにアクセスして捨てていることになりますね。ほとんどを。これじゃダメですよね。
実行計画は、全くスマートじゃなくなっていますww

SCOTT@orclpdb1> @testrun1 144 2435

...略...

1 SELECT
2 /*+
3 gather_plan_statistics
4 index(orders pk_orders)
5 */
6 orders.order_id

...略...

Plan hash value: 109917740

--------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | Cost (%CPU)| A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3 (100)| 1 |00:00:00.01 | 4 |
| 1 | NESTED LOOPS | | 1 | 3 (0)| 1 |00:00:00.01 | 4 |
| 2 | NESTED LOOPS | | 1 | 3 (0)| 1 |00:00:00.01 | 3 |
| 3 | TABLE ACCESS BY INDEX ROWID BATCHED| ORDERS | 1 | 2 (0)| 1 |00:00:00.01 | 2 |
|* 4 | INDEX FULL SCAN | PK_ORDERS | 1 | 1 (0)| 1 |00:00:00.01 | 1 |
|* 5 | INDEX UNIQUE SCAN | PK_CUSTOMERS | 1 | 0 (0)| 1 |00:00:00.01 | 1 |
| 6 | TABLE ACCESS BY INDEX ROWID | CUSTOMERS | 1 | 1 (0)| 1 |00:00:00.01 | 1 |
--------------------------------------------------------------------------------------------------------------------

...略...

Predicate Information (identified by operation id):
---------------------------------------------------

4 - filter("ORDERS"."ORDER_ID"=COALESCE(:ORDER_ID,"ORDERS"."ORDER_ID"))
5 - access("ORDERS"."CUSTOMER_ID"="CUSTOMERS"."CUSTOMER_ID")
filter("CUSTOMERS"."CUSTOMER_ID"=COALESCE(:CUST_ID,"CUSTOMERS"."CUSTOMER_ID"))

 

 

3) 1)を動的SQLで回避した場合、全件取得はWHERE句のない文になりますよね!

最適な実行計画にするために動的SQL化し生成されたSQL文を実行して1)のケースがどう改善されるか診てみましょう

全行取得するのでWHERE句は不要。シンプルになりました。
余計なフィルタリングも消えました。

この例だとMERGE JOINになっていますが、データ量が少ない影響だと推測。
ソートに使うメモリを索引を使って回避している動きがあることから利用するメモリサイズが少なくなるためでしょうね。データ量が大きくなるとHash Joinに切り替わるかもしれないですね。
(理由は、1)の実行計画のHASH JOINが利用するメモリサイズとの比較で小さくなっていることがわかります)

  1  SELECT
2 /*+
3 gather_plan_statistics
4 */
5 orders.order_id
6 , orders.order_date
7 , customers.first_name
8 FROM
9 orders
10 INNER JOIN customers
11 ON
12* orders.customer_id = customers.customer_id

...略...

Plan hash value: 3079428679

---------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | Cost (%CPU)| A-Rows | A-Time | Buffers | OMem | 1Mem | Used-Mem |
---------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 9 (100)| 105 |00:00:00.01 | 20 | | | |
| 1 | MERGE JOIN | | 1 | 9 (12)| 105 |00:00:00.01 | 20 | | | |
| 2 | TABLE ACCESS BY INDEX ROWID| ORDERS | 1 | 2 (0)| 105 |00:00:00.01 | 16 | | | |
| 3 | INDEX FULL SCAN | FK_ORDERS_CUSTOMERS | 1 | 1 (0)| 105 |00:00:00.01 | 8 | | | |
|* 4 | SORT JOIN | | 105 | 7 (15)| 105 |00:00:00.01 | 4 | 20480 | 20480 |18432 (0)|
| 5 | TABLE ACCESS FULL | CUSTOMERS | 1 | 6 (0)| 319 |00:00:00.01 | 4 | | | |
---------------------------------------------------------------------------------------------------------------------------------------------

...略...

Predicate Information (identified by operation id):
---------------------------------------------------

4 - access("ORDERS"."CUSTOMER_ID"="CUSTOMERS"."CUSTOMER_ID")
filter("ORDERS"."CUSTOMER_ID"="CUSTOMERS"."CUSTOMER_ID")

 

4) 2)の改善

動的SQL化によりCOALESCE関数は不要でわかりやすいSQL文ですよね。こちらのほうが自然ですw

見ての通り、WHERE句に記述されているCOALESCE関数を含むフィルタリングが消え、スッキリしたPredicate Informationの内容に変化しました。これで安心!

  1  SELECT
2 /*+
3 gather_plan_statistics
4 */
5 orders.order_id
6 , orders.order_date
7 , customers.first_name
8 FROM
9 orders
10 INNER JOIN customers
11 ON
12 orders.customer_id = customers.customer_id WHERE
13 customers.customer_id = :cust_id
14* AND orders.order_id = :order_id

...略...

-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | Cost (%CPU)| A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 2 (100)| 1 |00:00:00.01 | 4 |
| 1 | NESTED LOOPS | | 1 | 2 (0)| 1 |00:00:00.01 | 4 |
| 2 | TABLE ACCESS BY INDEX ROWID| CUSTOMERS | 1 | 1 (0)| 1 |00:00:00.01 | 2 |
|* 3 | INDEX UNIQUE SCAN | PK_CUSTOMERS | 1 | 0 (0)| 1 |00:00:00.01 | 1 |
|* 4 | TABLE ACCESS BY INDEX ROWID| ORDERS | 1 | 1 (0)| 1 |00:00:00.01 | 2 |
|* 5 | INDEX UNIQUE SCAN | PK_ORDERS | 1 | 0 (0)| 1 |00:00:00.01 | 1 |
-----------------------------------------------------------------------------------------------------------

...略...

Predicate Information (identified by operation id):
---------------------------------------------------

3 - access("CUSTOMERS"."CUSTOMER_ID"=:CUST_ID)
4 - filter("ORDERS"."CUSTOMER_ID"=:CUST_ID)
5 - access("ORDERS"."ORDER_ID"=:ORDER_ID)

 

次は、MySQL 8.0.36

mysql> select version();
+-----------+
| version() |
+-----------+
| 8.0.36 |
+-----------+

1) :cust_id, :order_id どちらも NULL にした場合

Oracle Databaseでの症状同様に、無駄なフィルタリングが現れていますよね

mysql> set @cust_id = null;
Query OK, 0 rows affected (0.00 sec)

mysql> set @order_id = null;
Query OK, 0 rows affected (0.00 sec)

mysql> select @cust_id;
+--------------------+
| @cust_id |
+--------------------+
| NULL |
+--------------------+v1 row in set (0.00 sec)

mysql> select @order_id;
+----------------------+
| @order_id |
+----------------------+
| NULL |
+----------------------+
1 row in set (0.01 sec)

mysql> explain format=tree
-> SELECT
-> orders.order_id
-> , orders.order_date
-> , customers.first_name
-> FROM
-> orders
-> INNER JOIN customers
-> ON
-> orders.customer_id = customers.customer_id
-> WHERE
-> customers.customer_id = COALESCE(@cust_id, customers.customer_id)
-> AND orders.order_id = COALESCE(@order_id, orders.order_id);
+-----------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+-----------------------------------------------------------------------------------------------------------+
| -> Nested loop inner join (cost=13.6 rows=10.5)
-> Filter: ((cast(orders.customer_id as double) = cast(coalesce(((@cust_id)),orders.customer_id) as double))
and (cast(orders.order_id as double) = cast(coalesce(((@order_id)),orders.order_id) as double))) (cost=2.05 rows=10.5)
-> Table scan on orders (cost=2.05 rows=105)
-> Single-row index lookup on customers using PRIMARY (customer_id=orders.customer_id) (cost=1.01 rows=1)
|
+-----------------------------------------------------------------------------------------------------------+

 

2):cust_id, :order_idねともに値をNULL以外に設定した場合

このケースもOracle Databaseでの症状に類ていますよね。ふむふむ

mysql> set @cust_id = 144;
Query OK, 0 rows affected (0.00 sec)

mysql> set @order_id = 2435;
Query OK, 0 rows affected (0.00 sec)

mysql> select @cust_id;
+----------+
| @cust_id |
+----------+
| 144 |
+----------+
1 row in set (0.00 sec)

mysql> select @order_id;
+-----------+
| @order_id |
+-----------+
| 2435 |
+-----------+
1 row in set (0.00 sec)

mysql> explain format=tree
-> SELECT
-> orders.order_id
-> , orders.order_date
-> , customers.first_name
-> FROM
-> orders
-> INNER JOIN customers
-> ON
-> orders.customer_id = customers.customer_id
-> WHERE
-> customers.customer_id = COALESCE(@cust_id, customers.customer_id)
-> AND orders.order_id = COALESCE(@order_id, orders.order_id);
+-----------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+-----------------------------------------------------------------------------------------------------------+
| -> Nested loop inner join (cost=13.6 rows=10.5)
-> Filter: ((orders.customer_id = coalesce(((@cust_id)),orders.customer_id))
and (orders.order_id = coalesce(((@order_id)),orders.order_id))) (cost=2.05 rows=10.5)
-> Table scan on orders (cost=2.05 rows=105)
-> Single-row index lookup on customers using PRIMARY (customer_id=orders.customer_id) (cost=1.01 rows=1)
|
+-----------------------------------------------------------------------------------------------------------+

 

 

3) 1)を動的SQLにして適切なSQLになった対策後の結果

そもそも全行取得するのになんでフィルタリングさせちゃうようなWHERE句を書くのかと。。
フィルタリングはなくなり綺麗なものです。

mysql> explain format=tree
-> SELECT
-> orders.order_id
-> , orders.order_date
-> , customers.first_name
-> FROM
-> orders
-> INNER JOIN customers
-> ON
-> orders.customer_id = customers.customer_id;
+-----------------------------------------------------------------------------------------------------------+
| EXPLAIN |
+-----------------------------------------------------------------------------------------------------------+
| -> Nested loop inner join (cost=127 rows=105)
-> Table scan on orders (cost=11.5 rows=105)
-> Single-row index lookup on customers using PRIMARY (customer_id=orders.customer_id) (cost=1 rows=1)
|
+-----------------------------------------------------------------------------------------------------------+

 

 

4) 3)同様に動的SQLにして、COALESCE関数を排除した結果。

無駄なフルタリングも一歳なし。こうでなくちゃw COAESCE関数を含むフィルタなんていらんのですよ。

mysql> set @cust_id = 144;
Query OK, 0 rows affected (0.00 sec)

mysql> set @order_id = 2435;
Query OK, 0 rows affected (0.00 sec)

mysql> select @cust_id;
+----------+
| @cust_id |
+----------+
| 144 |
+----------+
1 row in set (0.00 sec)

mysql> select @order_id;
+-----------+
| @order_id |
+-----------+
| 2435 |
+-----------+
1 row in set (0.00 sec)

mysql> explain format=tree
-> SELECT
-> orders.order_id
-> , orders.order_date
-> , customers.first_name
-> FROM
-> orders
-> INNER JOIN customers
-> ON
-> orders.customer_id = customers.customer_id
-> WHERE
-> customers.customer_id = @cust_id
-> AND orders.order_id = @order_id;
+-------------------------------------------------------+
| EXPLAIN |
+-------------------------------------------------------+
| -> Rows fetched before execution (cost=0..0 rows=1)
|
+-------------------------------------------------------+

 

 

そして、最後は、PostgreSQL 16.3 

とりを務めているぐらいなのでw、
Oracle Database, MySQLとはちょっと違った影響がありそうなのは、気づいている方が多そう。。。。
それがどのような違いなのか診てみましょう

perftestdb=> select version();
version
---------------------------------------------------------------------------------------------------------
PostgreSQL 16.3 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-22), 64-bit
(1 行)

 

 

1) :cust_id, :order_id どちらも NULL にした場合

全行取得してINNER JOINするだけですが、Join Cardinarityが変です!!!!!

Rows Removed by Join Filter: 3129とあります。105rows*31rowsなので、なぜか直積しちゃってますね。わぉ! 細かいところだが一部のROWSなんとなく合わないようなきもするが、そこは見てないことにしておこう。。 フィルタリングが余計なのはOracle Database, MySQLと同じ。

症状としては重症の類ですよね。

データが多くなった場合の直積はフィルタリング以上にキツイですよーーーーっ!

perftestdb=> \pset null [null]
Null表示は"[null]"です。
perftestdb=> \set cust_id NULL
perftestdb=> \set order_id NULL
perftestdb=> \echo :cust_id
NULL
perftestdb=> \echo :order_id
NULL
perftestdb=> explain (analyze,verbose)
perftestdb-> SELECT
perftestdb-> orders.order_id
perftestdb-> , orders.order_date
perftestdb-> , customers.first_name
perftestdb-> FROM
perftestdb-> orders
perftestdb-> INNER JOIN customers
perftestdb-> ON
perftestdb-> orders.customer_id = customers.customer_id
perftestdb-> WHERE
perftestdb-> customers.customer_id = COALESCE(:cust_id, customers.customer_id)
perftestdb-> AND orders.order_id = COALESCE(:order_id, orders.order_id);

QUERY PLAN
--------------------------------------------------------------------------------------------------------------
Nested Loop (cost=0.00..10.33 rows=1 width=18) (actual time=0.025..1.416 rows=105 loops=1)
Output: orders.order_id, orders.order_date, customers.first_name
Inner Unique: true
Join Filter: (orders.customer_id = customers.customer_id)
Rows Removed by Join Filter: 3129
-> Seq Scan on public.orders (cost=0.00..2.31 rows=1 width=16) (actual time=0.016..0.041 rows=105 loops=1)
Output: orders.order_id, orders.order_date, orders.order_mode, orders.customer_id
, orders.order_status, orders.order_total, orders.sales_rep_id, orders.promotion_id
Filter: (orders.order_id = COALESCE(orders.order_id))
-> Seq Scan on public.customers (cost=0.00..7.99 rows=2 width=10) (actual time=0.001..0.007 rows=31 loops=105)
Output: customers.customer_id, customers.first_name
, customers.last_name, customers.address, customers.phone_number
Filter: (customers.customer_id = COALESCE(customers.customer_id))
Planning Time: 0.456 ms
Execution Time: 1.453 ms

 

 

2):cust_id, :order_idともに値をNULL以外に設定した場合

主キーを利用するかと思いきや、COALESCE関数の影響で全表走査してフィルタリングしてほぼ捨ててますね なぜ(???)

perftestdb=> \pset null [null]
Null表示は"[null]"です。
perftestdb=> \set cust_id 144
perftestdb=> \set order_id 2435
perftestdb=> \echo :cust_id
144
perftestdb=> \echo :order_id
2435
perftestdb=> explain (analyze,verbose)
SELECT
orders.order_id
, orders.order_date
, customers.first_name
FROM
orders
INNER JOIN customers
ON
orders.customer_id = customers.customer_id
WHERE
customers.customer_id = COALESCE(:cust_id, customers.customer_id)
AND orders.order_id = COALESCE(:order_id, orders.order_id);

QUERY PLAN
--------------------------------------------------------------------------------------------------------------
Nested Loop (cost=0.00..10.57 rows=1 width=18) (actual time=0.062..0.155 rows=1 loops=1)
Output: orders.order_id, orders.order_date, customers.first_name
-> Seq Scan on public.orders (cost=0.00..2.58 rows=1 width=16)
(actual time=0.038..0.064 rows=1 loops=1)

Output: orders.order_id, orders.order_date, orders.order_mode, orders.customer_id
, orders.order_status, orders.order_total, orders.sales_rep_id, orders.promotion_id
Filter: ((orders.customer_id = 144) AND (orders.order_id = 2435))
Rows Removed by Filter: 104
-> Seq Scan on public.customers (cost=0.00..7.99 rows=1 width=10)
(actual time=0.020..0.085 rows=1 loops=1)

Output: customers.customer_id, customers.first_name
, customers.last_name, customers.address, customers.phone_number
Filter: (customers.customer_id = 144)
Rows Removed by Filter: 318
Planning Time: 0.253 ms
Execution Time: 0.225 ms

 

ちょいと気になるのでヒントでどうなるか追加で診ておきましょう。このケースでは改善。
pg_hint_planで索引スキャンでよりよくできますね。(データ量の影響だろうか。。)

perftestdb=> explain (analyze,verbose)
SELECT
/*+
IndexScan(orders pk_orders)
IndexScan(customers pk_customers)
*/
orders.order_id
, orders.order_date
, customers.first_name
FROM
orders
INNER JOIN customers
ON
orders.customer_id = customers.customer_id
WHERE
customers.customer_id = COALESCE(:cust_id, customers.customer_id)
AND orders.order_id = COALESCE(:order_id, orders.order_id);

QUERY PLAN
--------------------------------------------------------------------------------------------------------------
Nested Loop (cost=0.29..16.34 rows=1 width=18) (actual time=0.039..0.043 rows=1 loops=1)
Output: orders.order_id, orders.order_date, customers.first_name
-> Index Scan using pk_orders on public.orders
(cost=0.14..8.16 rows=1 width=16) (actual time=0.027..0.028 rows=1 loops=1)

Output: orders.order_id, orders.order_date, orders.order_mode, orders.customer_id
, orders.order_status, orders.order_total, orders.sales_rep_id, orders.promotion_id
Index Cond: (orders.order_id = 2435)
Filter: (orders.customer_id = 144)
-> Index Scan using pk_customers on public.customers
(cost=0.15..8.17 rows=1 width=10) (actual time=0.008..0.010 rows=1 loops=1)

Output: customers.customer_id, customers.first_name, customers.last_name
, customers.address, customers.phone_number
Index Cond: (customers.customer_id = 144)
Planning Time: 0.290 ms
Execution Time: 0.083 ms

 

 

3) 1)の対策後。動的SQLにしてWHERE句を除外するだけです

無駄なWHERE句が消えて、スッキリ。こちらもOracle Databaseの改善後に類似したMerge Joinになってますね。直積が無くなってますねーーーー

perftestdb=> \pset null [null]
Null表示は"[null]"です。
perftestdb=> \set cust_id NULL
perftestdb=> \set order_id NULL
perftestdb=> \echo :cust_id
NULL
perftestdb=> \echo :order_id
NULL
perftestdb=>
perftestdb=> explain (analyze,verbose)
perftestdb-> SELECT
perftestdb-> orders.order_id
perftestdb-> , orders.order_date
perftestdb-> , customers.first_name
perftestdb-> FROM
perftestdb-> orders
perftestdb-> INNER JOIN customers
perftestdb-> ON
perftestdb-> orders.customer_id = customers.customer_id
perftestdb-> ;
QUERY PLAN
-----------------------------------------------------------------------------------------------------
Merge Join (cost=5.72..11.81 rows=105 width=18) (actual time=0.116..0.240 rows=105 loops=1)
Output: orders.order_id, orders.order_date, customers.first_name
Merge Cond: (customers.customer_id = orders.customer_id)
-> Index Scan using pk_customers on public.customers (cost=0.15..19.93 rows=319 width=10)
(actual time=0.012..0.040 rows=71 loops=1)
Output: customers.customer_id, customers.first_name
, customers.last_name, customers.address, customers.phone_number
-> Sort (cost=5.57..5.84 rows=105 width=16) (actual time=0.098..0.118 rows=105 loops=1)
Output: orders.order_id, orders.order_date, orders.customer_id
Sort Key: orders.customer_id
Sort Method: quicksort Memory: 29kB
-> Seq Scan on public.orders (cost=0.00..2.05 rows=105 width=16)
(actual time=0.012..0.047 rows=105 loops=1)
Output: orders.order_id, orders.order_date, orders.customer_id
Planning Time: 0.324 ms
Execution Time: 0.289 ms

 

 

4) 3)と同様の対策。動的SQLにしてCOALESCE関数を利用しない。一般的な条件を付加するだけです。

データ少ないからか、Seq Scanのままですね。
まじかw

perftestdb=> \pset null [null]
Null表示は"[null]"です。
perftestdb=> \set cust_id 144
perftestdb=> \set order_id 2435
perftestdb=> \echo :cust_id
144
perftestdb=> \echo :order_id
2435
perftestdb=> explain (analyze,verbose)
perftestdb-> SELECT
perftestdb-> orders.order_id
perftestdb-> , orders.order_date
perftestdb-> , customers.first_name
perftestdb-> FROM
perftestdb-> orders
perftestdb-> INNER JOIN customers
perftestdb-> ON
perftestdb-> orders.customer_id = customers.customer_id
perftestdb-> WHERE
perftestdb-> customers.customer_id = :cust_id
perftestdb-> AND orders.order_id = :order_id;

QUERY PLAN
----------------------------------------------------------------------------------------------------------------
Nested Loop (cost=0.00..10.57 rows=1 width=18) (actual time=0.037..0.097 rows=1 loops=1)
Output: orders.order_id, orders.order_date, customers.first_name
-> Seq Scan on public.orders (cost=0.00..2.58 rows=1 width=16)
(actual time=0.022..0.039 rows=1 loops=1)

Output: orders.order_id, orders.order_date, orders.order_mode, orders.customer_id
     , orders.order_status, orders.order_total, orders.sales_rep_id, orders.promotion_id
Filter: ((orders.customer_id = 144) AND (orders.order_id = 2435))
Rows Removed by Filter: 104
-> Seq Scan on public.customers (cost=0.00..7.99 rows=1 width=10)
(actual time=0.011..0.053 rows=1 loops=1)

Output: customers.customer_id, customers.first_name, customers.last_name
     , customers.address, customers.phone_number
Filter: (customers.customer_id = 144)
Rows Removed by Filter: 318
Planning Time: 0.199 ms
Execution Time: 0.132 ms

 

pg_hint_planIndexScanを強制してみましょう。。すんなり改善。
プランナーの判断だと索引使ってくれなかったのですが、ヒントで改善できる状況は確認。状況に応じて人がアシストしてあげるのがいいですかね。

perftestdb=> explain (analyze,verbose)
perftestdb-> SELECT
perftestdb-> /*+
perftestdb*> IndexScan(orders pk_orders)
perftestdb*> IndexScan(customers pk_customers)
perftestdb*> */
perftestdb-> orders.order_id
perftestdb-> , orders.order_date
perftestdb-> , customers.first_name
perftestdb-> FROM
perftestdb-> orders
perftestdb-> INNER JOIN customers
perftestdb-> ON
perftestdb-> orders.customer_id = customers.customer_id
perftestdb-> WHERE
perftestdb-> customers.customer_id = :cust_id
perftestdb-> AND orders.order_id = :order_id;

QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------
Nested Loop (cost=0.29..16.34 rows=1 width=18) (actual time=0.039..0.043 rows=1 loops=1)
Output: orders.order_id, orders.order_date, customers.first_name
-> Index Scan using pk_orders on public.orders (cost=0.14..8.16 rows=1 width=16)
(actual time=0.027..0.028 rows=1 loops=1)

Output: orders.order_id, orders.order_date, orders.order_mode, orders.customer_id
     , orders.order_status, orders.order_total, orders.sales_rep_id, orders.promotion_id
Index Cond: (orders.order_id = 2435)
Filter: (orders.customer_id = 144)
-> Index Scan using pk_customers on public.customers (cost=0.15..8.17 rows=1 width=10)
(actual time=0.008..0.010 rows=1 loops=1)

Output: customers.customer_id, customers.first_name, customers.last_name
     , customers.address, customers.phone_number
Index Cond: (customers.customer_id = 144)
Planning Time: 0.290 ms
Execution Time: 0.083 ms
(11 行)

 

 

まとめると、
当初の想定通りいいことは全くない!! スマートなやりかたに見えているだけでしたよね
COALESCE関数をWHERE句で利用したスマートロジックはかなりリスキー。

今回試した全てのケースで、余分なフィルタリングが常に行われたりするリスクに加え、
PostgreSQLでは直積まで発生しちゃいました。やばいです。

 

ということで、

Mac De Oracle ブログ開設 20周年記念のエントリー。おわり。

では、まだ。

Enjoy SQLs! and Optimizers!

 

 


==== サンプルコード ====
Oracle Database側で簡易的に動的SQL化して生成した全件取得、キー指定版のSQLをPostgreSQL/MySQLで再利用しました。

Oracle database

SCOTT@orclpdb1> !cat testrun1.sql
set termout on
variable cust_id number
variable order_id number
set autop on
set null [null]
exec :cust_id := &1
exec :order_id := &2

SELECT
/*+
gather_plan_statistics
*/
orders.order_id
, orders.order_date
, customers.first_name
FROM
orders
INNER JOIN customers
ON
orders.customer_id = customers.customer_id
WHERE
customers.customer_id = COALESCE(:cust_id, customers.customer_id)
AND orders.order_id = COALESCE(:order_id, orders.order_id)
.
l
set termout off
/
set termout on
@show_actualplan.sql

-- 簡易的にSQL*PLus内で動的SQLを組み立てて実行
set feed off
set timi off
set head off
set termout off
set veri off
spool temp_sql.sql
SELECT
'SELECT
/*+
gather_plan_statistics
*/
orders.order_id
, orders.order_date
, customers.first_name
FROM
orders
INNER JOIN customers
ON
orders.customer_id = customers.customer_id '
||
CASE
WHEN
:cust_id IS NOT NULL
AND :order_id IS NOT NULL
THEN
'WHERE
customers.customer_id = :cust_id
AND orders.order_id = :order_id'
END
FROM
dual;
select '.' from dual;
select 'l' from dual;
select 'set termout off' from dual;
select '/' from dual;
select 'set termout on' from dual;
select '@show_actualplan.sql' from dual;
spo off
set feed on
set timi on
set head on
set termout on
set veri on
@temp_sql.sql

undefine 1
undefine 2
undefine cust_id
undefine order_id

 

show_actualplan.sql

set long 20000
set longchunk 400
select * from table(dbms_xplan.display_cursor(format=>'ALL ALLSTATS LAST +OUTLINE'));

 

 

MySQL

set @cust_id = null;
set @order_id = null;
select @cust_id;
select @order_id;


--スマートロジック版(すまーとじゃないけど)
explain format=tree
SELECT
orders.order_id
, orders.order_date
, customers.first_name
FROM
orders
INNER JOIN customers
ON
orders.customer_id = customers.customer_id
WHERE
customers.customer_id = COALESCE(@cust_id, customers.customer_id)
AND orders.order_id = COALESCE(@order_id, orders.order_id);


--動的SQL(生成済み全件取得のSQL)
explain format=tree
SELECT
orders.order_id
, orders.order_date
, customers.first_name
FROM
orders
INNER JOIN customers
ON
orders.customer_id = customers.customer_id;


set @cust_id = 144;
set @order_id = 2435;
select @cust_id;
select @order_id;


--スマートロジック版(すまーとじゃないけど)
explain format=tree
SELECT
orders.order_id
, orders.order_date
, customers.first_name
FROM
orders
INNER JOIN customers
ON
orders.customer_id = customers.customer_id
WHERE
customers.customer_id = COALESCE(@cust_id, customers.customer_id)
AND orders.order_id = COALESCE(@order_id, orders.order_id);


--動的SQL(生成済みキー指定のSQL)
explain format=tree
SELECT
orders.order_id
, orders.order_date
, customers.first_name
FROM
orders
INNER JOIN customers
ON
orders.customer_id = customers.customer_id
WHERE
customers.customer_id = @cust_id
AND orders.order_id = @order_id;

 

 

PostgreSQL

\pset null [null]
\set cust_id NULL
\set order_id NULL
\echo :cust_id
\echo :order_id

--スマートロジック版(すまーとじゃないけど)
explain (analyze,verbose)
SELECT
orders.order_id
, orders.order_date
, customers.first_name
FROM
orders
INNER JOIN customers
ON
orders.customer_id = customers.customer_id
WHERE
customers.customer_id = COALESCE(:cust_id, customers.customer_id)
AND orders.order_id = COALESCE(:order_id, orders.order_id);


--動的SQL(生成済み全件取得のSQL)
explain (analyze,verbose)
SELECT
orders.order_id
, orders.order_date
, customers.first_name
FROM
orders
INNER JOIN customers
ON
orders.customer_id = customers.customer_id
;


\pset null [null]
\set cust_id 144
\set order_id 2435
\echo :cust_id
\echo :order_id


--スマートロジック版(すまーとじゃないけど)
explain (analyze,verbose)
SELECT
orders.order_id
, orders.order_date
, customers.first_name
FROM
orders
INNER JOIN customers
ON
orders.customer_id = customers.customer_id
WHERE
customers.customer_id = COALESCE(:cust_id, customers.customer_id)
AND orders.order_id = COALESCE(:order_id, orders.order_id);


--スマートロジック版(すまーとじゃないけど、キー指定版、SQL hint付き)
explain (analyze,verbose)
SELECT
/*+
IndexScan(orders pk_orders)
IndexScan(customers pk_customers)
*/
orders.order_id
, orders.order_date
, customers.first_name
FROM
orders
INNER JOIN customers
ON
orders.customer_id = customers.customer_id
WHERE
customers.customer_id = COALESCE(:cust_id, customers.customer_id)
AND orders.order_id = COALESCE(:order_id, orders.order_id);


--動的SQL(生成済みキー指定のSQL、SQL hint付き)
explain (analyze,verbose)
SELECT
/*+
IndexScan(orders pk_orders)
IndexScan(customers pk_customers)
*/
orders.order_id
, orders.order_date
, customers.first_name
FROM
orders
INNER JOIN customers
ON
orders.customer_id = customers.customer_id
WHERE
customers.customer_id = :cust_id
AND orders.order_id = :order_id;


--動的SQL(生成済みキー指定のSQL)
explain (analyze,verbose)
SELECT
orders.order_id
, orders.order_date
, customers.first_name
FROM
orders
INNER JOIN customers
ON
orders.customer_id = customers.customer_id
WHERE
customers.customer_id = :cust_id
AND orders.order_id = :order_id;

| | | コメント (0)

2022年4月 9日 (土)

標準はあるにはあるが癖の多いSQL - #27 LNNVL is 何? と思った方向け

Previously on Mac De Oracle.
前回のエントリで使った関数覚えてますか? LNNVL関数。 

Oracle純正の方言で、他のデータベースがネイティブでサポートしてるのって無さそうと思いつつ、気になったので軽くしらべてみた。

LNNVL
https://docs.oracle.com/en/database/oracle/oracle-database/21/sqlrf/LNNVL.html#GUID-FBCCE9B1-614E-45FA-8EE1-DFAA4F936867


基本的に移行対応や互換目的ぐらいですね。

Oracle Database の LNNVL を PostgreSQL で実現する
https://taityo-diary.hatenablog.jp/entry/2018/04/30/222335

PolarDB for Oracle にはある模様ですね。互換ということなので、だよね。というところですね。
https://www.alibabacloud.com/help/en/polardb-for-oracle/latest/lnnvl-function

折角なので、↑の例題の答えあわせしてみました。


SCOTT@orclpdb1>  set null [null]
SCOTT@orclpdb1> select * from account where lnnvl(year is not null);

NAME YEAR
------------------------------------------------------------ ----------
peter2007 [null]

SCOTT@orclpdb1> select * from account where lnnvl(year<2003);

NAME YEAR
------------------------------------------------------------ ----------
peter2003 2003
peter2004 2004
peter2005 2005
peter2006 2006
peter2007 [null]

SCOTT@orclpdb1> select * from account where lnnvl(year is null);

NAME YEAR
------------------------------------------------------------ ----------
peter2001 2001
peter2002 2002
peter2003 2003
peter2004 2004
peter2005 2005
peter2006 2006

6行が選択されました。

SCOTT@orclpdb1> select * from account where lnnvl(year=2008);

NAME YEAR
------------------------------------------------------------ ----------
peter2001 2001
peter2002 2002
peter2003 2003
peter2004 2004
peter2005 2005
peter2006 2006
peter2007 [null]

7行が選択されました。

SCOTT@orclpdb1> select * from account where lnnvl(year! =2008);

NAME YEAR
------------------------------------------------------------ ----------
peter2007 [null]

合ってそう。

PostgreSQLのExtensionである、oraface ではサポートしてますね。移行需要多いですからね。
https://github.com/orafce/orafce/search?q=LNNVL

たまたま見つけたのですが、Apache Spark。コメントのやりとりみて、まあ、そうですよねーーーというオチだったw
https://issues.apache.org/jira/browse/SPARK-21931

NVL2ほどは見当たらない、かなり強めの方言ですからね。 RedshiftやSnowflakeでもないね。これww 
では、また。

 



標準はあるにはあるが癖の多いSQL 全部俺 #1 Pagination
標準はあるにはあるが癖の多いSQL 全部俺 #2 関数名は同じでも引数が逆の罠!
標準はあるにはあるが癖の多いSQL 全部俺 #3 データ型確認したい時あるんです
標準はあるにはあるが癖の多いSQL 全部俺 #4 リテラル値での除算の内部精度も違うのよ!
標準はあるにはあるが癖の多いSQL 全部俺 #5 和暦変換機能ある方が少数派
標準はあるにはあるが癖の多いSQL 全部俺 #6 時間厳守!
標準はあるにはあるが癖の多いSQL 全部俺 #7 期間リテラル!
標準はあるにはあるが癖の多いSQL 全部俺 #8 翌月末日って何日?
標準はあるにはあるが癖の多いSQL 全部俺 #9 部分文字列の扱いでも癖が出る><
標準はあるにはあるが癖の多いSQL 全部俺 #10 文字列連結の罠(有名なやつ)
標準はあるにはあるが癖の多いSQL 全部俺 #11 デュエル、じゃなくて、デュアル
標準はあるにはあるが癖の多いSQL 全部俺 #12 文字[列]探すにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #13 あると便利ですが意外となかったり
標準はあるにはあるが癖の多いSQL 全部俺 #14 連番の集合を返すにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #15 SQL command line client
標準はあるにはあるが癖の多いSQL 全部俺 #16 SQLのレントゲンを撮る方法
標準はあるにはあるが癖の多いSQL 全部俺 #17 その空白は許されないのか?
標準はあるにはあるが癖の多いSQL 全部俺 #18 (+)の外部結合は方言
標準はあるにはあるが癖の多いSQL 全部俺 #19 帰ってきた、部分文字列の扱いでも癖w
標準はあるにはあるが癖の多いSQL 全部俺 #20 結果セットを単一列に連結するにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #21 演算結果にも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #22 集合演算にも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #23 複数行INSERTにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #24 乱数作るにも癖がある
標準はあるにはあるが癖の多いSQL 全部俺 #25 SQL de Fractalsにも癖がある:)
標準はあるにはあるが癖の多いSQL 全部俺 #26 おまけ SQL de 湯婆婆やるにも癖がでるw

 

| | | コメント (0)

2021年12月 1日 (水)

誰がどんな名前のペットを飼っているのかな? その1 / JPOUG Advent Calendar Day 1

今年も師走の風物詩、JPOUGアドベントカレンダーがはじまりましたー。2021も残すところ1ヶ月。来年も元気にOnline, In personでお会いしたいですね!

前置きはごれぐらいにして、

今回の私のエントリー、Oracleというかデータベース使う必要はないのですが、RDBMSというかSQLで解けるじゃん、この問題! 
ということで、中二の期末試験で「時間があったらチャレンジしてね!」という問題をネタにしてみました。

なお、本エントリーと、12/23日のエントリーの二部構成にして、本エントリーではネタ振りのみです!w

SQLがからんでいればどうやって解いても良いと思っています。冬の夜長に、ワイン片手に、頭の体操するのもよいのではないでしょうか? 
皆さんも考えてみてくださいね。

この問題、中学二年の数学のおまけの問題なので、紙と鉛筆、頭の良い方は、頭の中だけでも解けるわけですがw  
あえて、SQLで頑張ってみましょうw

問題は以下の通り。



Hiro, Larry, Scott, Steveは、Cat, Dog, Snake, Turtleのうち、どれか 1 種類のペットを飼っています。同じ種類のペットおよび、同じ名前のペットを飼っている人はいません。 4 人のペットの名前は、Lisa, Taro, TIger, Wendyのいずれかです。

  • Hiro :「僕が飼っているのは、Tiger だよ。 Turtle じゃないよ」
  • Larry : 「Snake の名前は、Lisa じゃないよ」
  • Scott : 「僕は Snake を飼っているよ」
  • Steve : 「Dog の名前は Wendy だよ。僕は Dog はかってないけど」

誰がどんな名前のペットを飼っているのかな?



 

答え合せは12/23の窓で行う予定です。

みなさん、お好きな方法で解いてみてください。。 :)

ちなみに、私は、愚直な方法でw 答えを導きだすつもりです。 みなさんは、よりスマートな方法を考えてみるのもおもしろいかもしれませんね!

答えではないですが、私がパッと考えている脳内イメージをアウトプットしておきます。(私のイメージにこだわる必要はないので、みなさんは自由な発想で取り組んでいただければと思います)

問題から、ざっくりとエンティティをイメージしてみると3つ。

  • ペットのオーナー
  • ペットの名前
  • 動物の種類

ただ、これだと、多:多の関係になってしまうので、関連エンティティぐらいは作ったほうが無難ですよね。そのままデカルト演算して答えを導きだすツワモノもいるかもしれませんがw 

で、関連エンティティをこれまた、ざっくりイメージしてみると、こちらも3つありそうですよね。問題文をよーく読み込んでみてください。3つ見えますよー。

  • 「ペットのオーナー」と「ペットの名前」を関連づけるエンティティ
  • 「ペットの名前」と「動物の種類」を関連づけるエンティティ
  • 「ペットのオーナー」と「動物の種類」を関連づけるエンティティ

こんな感じ、で6つのエンティティが浮かんだのですが、みなさんはどうみえますか?

 

少々悩んだののですが、この問題を解くために、後半の3つのエンティティを表で実装するか、ビューで実装するかってところもあるかなぁと。表にしなくてもビューでもいいかーと。

ということで、私は、以下を3表を元に、

  • ペットのオーナー
  • ペットの名前
  • 動物の種類

関連は、以下の3つのビューで実装してみようかなーと。(妄想中)

  • 「ペットのオーナー」と「ペットの名前」を関連づけるビュー
  • 「ペットの名前」と「動物の種類」を関連づけるビュー
  • 「ペットのオーナー」と「動物の種類」を関連づけるビュー

3つの表と3つのビューを駆使してw SQLだけで、愚直に、解く予定ですw

なお、元になる3エンティティに対応した表のDDLとデータは以下のような感じで。


create table owners (name varchar2(30) not null unique);
create table pets (name varchar2(30) not null unique);
create table animals (kind varchar2(30) not null unique);
-- owners
insert into owners(name) values('Hiro');
insert into owners(name) values('Larry');
insert into owners(name) values('Scott');
insert into owners(name) values('Steve');
-- pets
insert into pets(name) values('Lisa');
insert into pets(name) values('Taro');
insert into pets(name) values('Tiger');
insert into pets(name) values('Wendy');
-- animals
insert into animals(kind) values('Cat');
insert into animals(kind) values('Dog');
insert into animals(kind) values('Snake');
insert into animals(kind) values('Turtle');
commit;

SCOTT@ORCL> select name from owners;

NAME
-------------------------------
Hiro
Larry
Scott
Steve

Elapsed: 00:00:00.01
SCOTT@ORCL> select name from pets;

NAME
------------------------------
Lisa
Taro
Tiger
Wendy

Elapsed: 00:00:00.01
SCOTT@ORCL> select kind from animals;

KIND
------------------------------
Cat
Dog
Snake
Turtle

Elapsed: 00:00:00.01

 

では、12/23の答え合せまで、みなさんも、ワイングラス片手に、(お酒が苦手な方はウィルキンソンでもw)自由にあそんでみてください :)

明日は、12/2、二つ目の窓は、渡部さんです。お楽しみにーっ。

 

| | | コメント (0)

2016年3月19日 (土)

Relational Database Index Design and the Optimizers [Kindle版]とUSE THE INDEX, LUKE

時代は繰り返すw のか? という感じで何周目かのIndex only scanとかのネタを元にした資料とか作ることが多くて。。。


索引の設計って、基本的に、機械的だと思っているのですが、皆さんはどう思っているのか気になる今日この頃。
初心者ならともかく、そうでもない感じの方が、腕組みして、眉間にしわ寄せてるのをみるとちょっと心配になっちゃったり。

と昨日のtwで見かけたやつとかも含めて参考になりそうな書籍を載せておきますね。


最初は私のお気に入りの一冊(ハードカバー本でしたが、最近kindle版がでてました。そして私が買った時より高いw
この書籍は2011 db tech showcaseでTom Kyteさんが紹介していたもので、速攻でポチった記憶があります。
そしてその頃は、8,000円台でしたw(円高だったからねぇ)

この書籍ではCovering Index → FAT Index / Semi Covering Index → Semi FAT Indexと記載されています。


Web上でも読めるんですが、書籍化されPDF版もでてます。
SQLパフォーマンス詳解(原文タイトルSQL Performance Explained)


USE THE INDEX, LUKE - 開発者のためのSQLパフォーマンスの全て

| | | コメント (0) | トラックバック (0)

2016年3月17日 (木)

こんなのでいいのかなぁ。ズンドコキヨシ  ObjectScript / MUMPS



2016/3/18追記#3

よ〜く見てたら、ズン!は4回だったw 結局この83文字のパターンマッチング版でよかったのか〜〜w (おしまい)

S l="",w(0)="ズン!",w(1)="ドコ!" F  S l=l_w($R(2)) I l ?.E4"ズン!"1"ドコ!" W !,l,"キ・ヨ・シ!" Q

USER>S l="",w(0)="ズン!",w(1)="ドコ!" F  S l=l_w($R(2)) I l ?.E4"ズン!"1"ドコ!" W !,l,"キ・ヨ・シ!" Q

ズン!ズン!ドコ!ズン!ドコ!ドコ!ズン!ズン!ドコ!ズン!ズン!ドコ!ドコ!ズン!ドコ!ドコ!ドコ!ズン!ドコ!ズン!ドコ!ズン!ドコ!ドコ!ズン!ズン!ズン!ズン!ドコ!キ・ヨ・シ!



2016/3/18追記#2

旧構文のFORとIFを使えば82文字まで短縮できた。

S l="",w(0)="ズン!",w(1)="ドコ!" F  S l=l_w($R(2)) I l["ズン!ズン!ズン!ドコ!" W !,l,"キ・ヨ・シ!" Q

USER>S l="",w(0)="ズン!",w(1)="ドコ!" F  S l=l_w($R(2)) I l["ズン!ズン!ズン!ドコ!" W !,l,"キ・ヨ・シ!" Q

ドコ!ズン!ズン!ドコ!ドコ!ズン!ドコ!ズン!ズン!ズン!ズン!ズン!ドコ!キ・ヨ・シ!


調子に乗ってパターンマッチに書き換えたら1文字増えて83文字w orz

S l="",w(0)="ズン!",w(1)="ドコ!" F  S l=l_w($R(2)) I l ?.E3"ズン!"1"ドコ!" W !,l,"キ・ヨ・シ!" Q

USER>S l="",w(0)="ズン!",w(1)="ドコ!" F  S l=l_w($R(2)) I l ?.E3"ズン!"1"ドコ!" W !,l,"キ・ヨ・シ!" Q

ズン!ズン!ドコ!ドコ!ズン!ズン!ドコ!ズン!ズン!ズン!ドコ!キ・ヨ・シ!



2016/3/18追記

85文字までに縮めたw もうむりか?

S l="",w(0)="ズン!",w(1)="ドコ!" F {S l=l_w($R(2)) I l["ズン!ズン!ズン!ドコ!" {W !,l,"キ・ヨ・シ!" Q}}

USER>S l="",w(0)="ズン!",w(1)="ドコ!" F {S l=l_w($R(2)) I l["ズン!ズン!ズン!ドコ!" {W !,l,"キ・ヨ・シ!" Q}}

ズン!ズン!ドコ!ドコ!ズン!ズン!ドコ!ズン!ズン!ドコ!ズン!ドコ!ドコ!ズン!ズン!ズン!ドコ!キ・ヨ・シ!

こんなのでいいのかなぁ。ズンドコキヨシ

もっといいのが浮かびそうだっただけど、眠気で頭まわらなくなってきたので、一旦これでw

ズンドコキヨシまとめ


M言語というか、MUMPSというか、Caché ObjectScriptでやっつけてみた

S s=0 F {S r=$R(2) W !,$CASE(r,0:"ズン!",1:"ドコ!") S s=$CASE(r,0:$CASE(s,0:1,1:2,2:3,:3),1:$CASE(s,3:4,:0)) W:s=4 !,"キ・ヨ・シ!" Q:s=4}
USER>S s=0 F {S r=$R(2) W !,$CASE(r,0:"ズン!",1:"ドコ!") S s=$CASE(r,0:$CASE(s,0:1,1:2,2:3,:3),1:$CASE(s,3:4,:0)) W:s=4 !,"キ・ヨ・シ!" Q:s=4}

ズン!
ズン!
ドコ!
ドコ!
ドコ!
ズン!
ドコ!
ズン!
ズン!
ドコ!
ズン!
ドコ!
ドコ!
ズン!
ズン!
ドコ!
ズン!
ズン!
ズン!
ズン!
ズン!
ズン!
ズン!
ドコ!
キ・ヨ・シ!

USER>halt
[oracle@pleco ˜]$

| | | コメント (0) | トラックバック (0)

2015年5月17日 (日)

ClubDB2 200回記念に参加してきた :)

ミックさんの出版記念というか、200回記念に、37回目以来、7年ぶりにClubDB2 200回 「SQLにおける手続き型の復権」に参加してきた。

ClubDB2なのに、Oracleを使ってデモをしていたのは、ヒントが使えるからですよね。(ここ重要)
ヒントを使って実行計画を変えたとき、駆動表や、索引使用の有無でどのような結果になるのか追いやすいんですよ == 勉強しやすいといったほうがよいかもしれませんね。

おっと、 本題から外れすぎた w m(_ _)m

Clubdb2_200

1年振りにミックさんにお会いして、久々にミック節を聞かせてもらいました。 楽しかったです!
(1年振り以上ですよ! とミックさんから言われたんだけど、そうだっけ?w)

そして、37回目にもご一緒だった、木村明治さん!。
ミックさんと共著された書籍が発売されてますよね :)。


ClubDB2といいながら、MySQL系の方や、PostgreSQL系の方もちらほら参加している点も面白いですよね。

最後は予想通り、ミックさんのサイン会でした:)


| | | コメント (0) | トラックバック (0)

2014年6月28日 (土)

InterSystems Symposia 2014に行ってきた

db tech showcase 2014 Osakaより先だったのだけど...
InterSystems Symposia 2014に行ってきた。という話。

CachéはSQLでアクセスする必要はないのだけど、RDBMSからの乗り換え組でSQLから乗り換えコストの低減目的で導入されたインターフェースだというのは間違いなし、
昔からM言語をやってきた人達からすれば、SQLアクセスだと! はぁ〜? 的な感じも無くはないし、おまけ的なイメージは強いんだろうな。
その分のオーバーヘッドもあるしな〜。 と思ってたのですが....

最近の動きを見ているとSQLアクセスにも本気なのかな。と思わせる様子があるんだよね。

Caché SQL 最新情報の資料P3部分でダイレクトアクセス(元からあるNoSQLな部分)とSQLアクセスのメリット、デメリットの解説やビットマップインデックスのメンテナンス機能。

20140628_124018
Caché SQL 最新情報のセッション資料は上のリンクからダウンロードできますよ!


そして、 Push Subquery Conditions into UNION LegsなどのSQL実行計画最適化、OracleのUSE_CONCAT相当など多数のヒント、パラレルクエリなど"おまけのインターフェース"とは思えなくなってきた感がある。


ちなみに、Caché自体はスパース多次元配列なので行指向、列指向のようなことはないんだけど、列指向的な加工もできちゃうわけで、それはそれで面白いかなと、勝ってに妄想してみたりw

たまには、右脳を活性化しないとね、イメージ力大事 :)

| | | コメント (0) | トラックバック (0)

2014年6月21日 (土)

db tech showcase 2014 Osaka に行ってきた

I love your data(どこかのパクリw) な人たちが、いろいろなDBMSを見聞きし、それぞれの思いで、何年か先の未来に、それぞれの思いを馳せる

そんな、集まりが、 db tech showcase 2014 Osaka 

(ん....俺っぽくない出だしを書いててワロタ....)


に臨時休業(自分ではこれも仕事のうちなんだがw 仕事って思ってないだけw)して参加した。
https://www.facebook.com/db.tech.showcase

Slideshare : セッション資料はここ


話を聞いていたら、オレオレレプリケーションできそうな気になるから不思議 :) .
オレオレ、ゴルゲやオレオレ、attunityとか、自分で作って試してみると、面倒くさいポイントとか見えていいかもね。
Attunity Replicateの画面を初めてみたけど、シンプルで好きなデザイン。
B31 : LogMinerってレプリケーションソフトで使われてるけどどうなってる? / 森田俊哉(インサイトテクノロジー)


Oracle以外の話も聴きたくてNoSQL系などをチョイス。 割り切った実装で特定用途でその力を発揮する。割り切り大事。
D32 : Amazon Redshift Deep Dive / 大久保順(アマゾンデータサービスジャパン)


B33 : Riak: 本物の高可用性を実現する仕組みとは? / 佐藤 貴彦 (Bashoジャパン)


D34 : データウェアハウス・エンジンTeradataのご紹介とビッグデータ統合アーキテクチャー / 山本 泰史(日本テラデータ)


The Machine!にも関連するのだろうけど、Memristorの話題も!
D35 : インメモリーデータベース徹底比較 / 小森博之(日本HP)


そしてスペシャルセッション、遠い未来じゃないはなし
A36 : ウエアラブルとO2Oが切り拓くICTの新地平 / 村上憲郎

vessylもそんな”もの”の一つかもしれない。飲みものの分析ができるんだからトイレにも応用できるんじゃないか的な :)
日本のトイレがそうなるかは分からないけど、先にやってくれたら面白いかもね。
毎日が健康診断、データはかかりつけの医師に共有されていて、気になるデータが見つかると、洗面台のミラー風マルチタッチデバイスに情報がプッシュされ...必要なら、その場で通院予約、その後待たされることなく診察なんて時間の無駄がなくていいな〜と、ぼーっと妄想していたり。

楽しいやね。 :)

そういえばそんなシーンのある映画で思い出したのがこれ




T-シャツ、ありがとうございました。


Bqilsptcyaae4vjjpglarge

東京から大阪への新幹線で日帰りだと電池切れ感が半端ないので一泊することをおすすめしますw


| | | コメント (0) | トラックバック (0)

2012年10月21日 (日)

Unconference at db tech showcase 2012の資料公開 :)

db tech showcase 2012
Unconference at db tech showcase 2012

db tech showcaseの一角をJPOUGが占拠してUnconferenceを開催しました。 db tech showcase関係者の皆様、このような機会を与えて頂き大変感謝します。
そして、お疲れさまでした。



Index Only Access 3部作の最終回?! として 「Index Only Accessが実装されるたった一つの理由」と題したセッションを行いました。
実行計画を取得するために操作したデータベースの中には人生二度目のデータベース複数もあり、かなりの時間を裂いて調べた割にはセッション時間が少々短めになってしまいました。m(_ _)m

なぜ、このテーマを選んだか.

PostgreSQLがリリースされてから9.1まで実装されなかったIndex Only Accessでしたが、9.2でついに実装されました。

そして..db tech showcase 2012は...

SQL> select dbms_name from all_dbms where dbms_category like "%";

DBMS_NAME
------------------
Oracle
DB2
MySQL
PostgreSQL
SQL Server
Vecterwise
MongoDB
Symfoware
Clustrix
InfiniDB
.
.
.
.

的な雰囲気となっていることもあり、Index Only Accessの魚拓をあつめて比較、Index Only Accessが実装される理由について今一度、考えてみたいな..と。
タイトル見ただけで理由が想像できた方は、資料見なくても大丈夫だと思いますよ。:) 
 

H/Wの性能が急速に伸びてきている影響もあるように感じますが、無駄に広範囲な検索や、無駄にビッグなデータとなっていること気にしていないのではないか? というケースが多くなっていると感じています。
DBMSはアクセスするデータをより少なくするための工夫をしているのに...エンジニアがそれをうまく使っていない、使えていない、設計できてない...そんな"感じ"がするんです。

セッション資料を公開しました。
S1a


じゃ、like "%てない" 状況をどうすればいいか....答えは、小田さんのセッションの中にあった。。。。:)


#不慣れなDBMSもあり、こんなメトリックみたほうが分かりやすいよ〜、などのツッコミ歓迎します.


| | | コメント (0) | トラックバック (0)

2012年9月 2日 (日)

Index Only Accessネタのおまけのおまけ

Caché de Index Only Access できるのか?

CachéってSQLもサポートしてるので、Index Only Accessサポートしてるのかな〜と素朴な疑問から調べてみたもののマニュアルには記載されていない。
書かれていなきゃどうなるか、試すのが手っ取り早いですね。
(ダウンロードするにはフォームからリクエストする必要があります。1セッション限定の試用ライセンスのようです。他の制限は該当ページ読んでくださいな。)



OracleのIndex Only Accessは以下のエントリを参考にしてください。

いん!、イン!、Index どっぷり Inde Only Access生活w - Oracle OpenWorld Unconference presented by JPOUG

JPOUG SET EVENTS 20120721 - 「(続)いん!、イン!、Index 大人の事情縛りのSQLチューニング」資料公開

MySQL/PostgreSQLのIndex Only Accessは以下のエントリを参考にしてください。
Index Only Accessネタのおまけ


いつもはMacBook Air使うんですが、今回は都合により母艦のVirtualBoxを使いました (^^;;

MacPro Mid 2012 12Core/24GB (OS X Mountain Lion Server)
VirtualBox4.1.20 for MacOS X
GuestOS:CentOS5.8 x86_64 (CPU数とメモリサイズはMacBook Airのx86環境と同じ)

Caché 2012.1 for Linux x86_64


まず、ターミナルで接続して表、索引、データ登録、他のデータベースで言う統計情報取得から。

[oracle@pleco ˜]$ csession cache -U samples

ノード: pleco.macdeoracle.jp インスタンス: CACHE

SAMPLES>

SAMPLES>d $System.SQL.Shell()
SQL Command Line Shell
----------------------------------------------------

The command prefix is currently set to: <<nothing>>.
Enter q to quit, ? for help.
SAMPLES>>
SAMPLES>>create table tab3(unique_id numeric(10) not null, item_code char(15) not null, data varchar(500), is_delete numeric(1), status_code char(2))
1. create table tab3(unique_id numeric(10) not null, item_code char(15) not null, data varchar(500), is_delete numeric(1), status_code char(2))

0 Rows Affected
statement prepare time: 0.0118s, elapsed execute time: 0.2405s.
---------------------------------------------------------------------------
SAMPLES>>
SAMPLES>>alter table tab3 add constraint tab3_pk primary key(unique_id)
3. alter table tab3 add constraint tab3_pk primary key(unique_id)

0 Rows Affected
statement prepare time: 0.0092s, elapsed execute time: 4.9465s.
---------------------------------------------------------------------------
SAMPLES>>
SAMPLES>>create table tab311 (unique_id numeric(10) not null,sub_item_code char(10),data varchar(500),is_delete numeric(1))
4. create table tab311 (unique_id numeric(10) not null,sub_item_code char(10),data varchar(500),is_delete numeric(1))

0 Rows Affected
statement prepare time: 0.0115s, elapsed execute time: 0.1953s.
---------------------------------------------------------------------------
SAMPLES>>create table tab31 (item_code char(15) not null,sub_item_code char(10),data varchar(500),is_delete numeric(1))
5. create table tab31 (item_code char(15) not null,sub_item_code char(10),data varchar(500),is_delete numeric(1))

0 Rows Affected
statement prepare time: 0.0133s, elapsed execute time: 0.1985s.
---------------------------------------------------------------------------
SAMPLES>>
SAMPLES>>alter table tab31 add constraint tab31_pk primary key(item_code)
7. alter table tab31 add constraint tab31_pk primary key(item_code)

0 Rows Affected
statement prepare time: 0.0102s, elapsed execute time: 0.2589s.
---------------------------------------------------------------------------
SAMPLES>>alter table tab311 add constraint tab311_pk primary key(unique_id)
8. alter table tab311 add constraint tab311_pk primary key(unique_id)

0 Rows Affected
statement prepare time: 0.0116s, elapsed execute time: 0.2627s.
---------------------------------------------------------------------------
SAMPLES>>create index tab311_ix on tab311(sub_item_code)
9. create index tab311_ix on tab311(sub_item_code)

0 Rows Affected
statement prepare time: 0.0111s, elapsed execute time: 0.2870s.
---------------------------------------------------------------------------
SAMPLES>>q

確認は管理ポータルで!(どこみればよいか分からなかったので楽な方法で..)

Desc_tab3

Tab3_indexes_no_index_only

Desc_tab31

Tab31_indexes_no_index_only

Desc_tab311

Tab311_indexes_no_index_only_scan

Oracleなら統計情報取得、他のRDBMSならアナライズ(昔はオラクルもアナライズだったんですけどね)、Cachéの世界では「テーブルチューニング」というそうな。
(管理ポータルから実行しています)
Table_analyze

Tab31_analyze

Tab311_analyze

表と索引ができたのでデータ登録。
これまたOracleとは勝っても違うし、DSMの時代(DIGITAL STANDARD MUMPS)から大きく拡張されてるのでかなり辛いな〜MUMPS思い出すというより別物に近い感じw。あの当時はSQL使えねーしというより必要ねーし、だったしね (^^;;;

以下、データ作成中のログ..
グルグル回しているのは気にしないでねw

[oracle@pleco ˜]$ csession cache -U samples

ノード: pleco.macdeoracle.JP インスタンス: CACHE

SAMPLES>
SAMPLES>
SAMPLES>s rs=##class(%SQL.Statement).%ExecDirect(,"start transaction")
TL1:SAMPLES>s sql="insert into SQLUser.tab3 values(?,to_char((?#500000)+1,'FM099999999999999'),repeat('*',250-length(to_char(?)))||to_char(?),0,'00')"
TL1:SAMPLES>s stmt=##class(%SQL.Statement).%New() s stat=stmt.%Prepare(sql)
TL1:SAMPLES>f i=1:1:1000000 {s rs=stmt.%Execute(i,i,i,i)}
TL1:SAMPLES>s rs=##class(%SQL.Statement).%ExecDirect(,"commit")
SAMPLES>d $System.SQL.Shell()

SQL Command Line Shell
----------------------------------------------------

The command prefix is currently set to: <<nothing>>.
Enter q to quit, ? for help.
SAMPLES>>select count(1) from tab3
7. select count(1) from tab3

Aggregate_1
1000000

1 Rows(s) Affected
statement prepare time: 0.0009s, elapsed execute time: 2.6558s.
---------------------------------------------------------------------------
SAMPLES>>select min(unique_id) as "min", max(unique_id) as "max" from tab3
8. select min(unique_id) as "min", max(unique_id) as "max" from tab3

min max
1 1000000

1 Rows(s) Affected
statement prepare time: 0.1423s, elapsed execute time: 0.0006s.
---------------------------------------------------------------------------
SAMPLES>>select min(item_code) "min",max(item_code) "max" from tab3
9. select min(item_code) "min",max(item_code) "max" from tab3

min max
000000000000001 000000000500000

1 Rows(s) Affected
statement prepare time: 0.1324s, elapsed execute time: 3.4683s.
---------------------------------------------------------------------------
SAMPLES>>
SAMPLES>>q

SAMPLES>halt
[oracle@pleco ˜]$

SAMPLES>d $System.SQL.SetAutoCommit(2)
SAMPLES>s rs=##class(%SQL.Statement).%ExecDirect(,"start transaction")
TL1:SAMPLES>s sql="insert into SQLUser.tab31 values(to_char(?,'FM099999999999999'),to_char((?#500000)+1,'FM0999999999'),repeat('*',250-length(to_char(?)))||to_char(?),0)"
TL1:SAMPLES>s stmt=##class(%SQL.Statement).%New() s stat=stmt.%Prepare(sql)
TL1:SAMPLES>f i=1:1:2000000 {s rs=stmt.%Execute(i,i,i,i)}
TL1:SAMPLES>s rs=##class(%SQL.Statement).%ExecDirect(,"commit")

SAMPLES>d $System.SQL.Shell()
SQL Command Line Shell
----------------------------------------------------

The command prefix is currently set to: <<nothing>>.
Enter q to quit, ? for help.
SAMPLES>>select count(1) from tab31
2. select count(1) from tab31

Aggregate_1
2000000

1 Rows(s) Affected
statement prepare time: 0.1349s, elapsed execute time: 6.0684s.
---------------------------------------------------------------------------
SAMPLES>>select min(item_code) "item_code(MIN)",max(item_code) "item_code(MAX)" from tab31
3. select min(item_code) "item_code(MIN)",max(item_code) "item_code(MAX)" from tab31

item_code(MIN) item_code(MAX)
000000000000001 000000002000000

1 Rows(s) Affected
statement prepare time: 0.1361s, elapsed execute time: 0.0010s.
---------------------------------------------------------------------------
SAMPLES>>select min(sub_item_code) "sub_item_code(MIN)",max(sub_item_code) "sub_item_code(MAX)" from tab31
4. select min(sub_item_code) "sub_item_code(MIN)",max(sub_item_code) "sub_item_code(MAX)" from tab31

sub_item_code(MIN) sub_item_code(MAX)
0000000001 0000500000

1 Rows(s) Affected
statement prepare time: 0.1391s, elapsed execute time: 6.7417s.
---------------------------------------------------------------------------
SAMPLES>>q
SAMPLES>

SAMPLES>d $System.SQL.SetAutoCommit(2)
SAMPLES>s rs=##class(%SQL.Statement).%ExecDirect(,"start transaction")
TL1:SAMPLES>s sql="insert into SQLUser.tab311 values(?,to_char((?#500000)+1,'FM0999999999'),repeat('*',250-length(to_char(?)))||to_char(?),0)"
TL1:SAMPLES>s stmt=##class(%SQL.Statement).%New() s stat=stmt.%Prepare(sql)
TL1:SAMPLES>f i=1:1:2000000 {s rs=stmt.%Execute(i,i,i,i)}
TL1:SAMPLES>s rs=##class(%SQL.Statement).%ExecDirect(,"commit")

SAMPLES>d $System.SQL.Shell()

SQL Command Line Shell
----------------------------------------------------

The command prefix is currently set to: <<nothing>>.
Enter q to quit, ? for help.
SAMPLES>>select count(1) from tab311
5. select count(1) from tab311

Aggregate_1
2000000

1 Rows(s) Affected
statement prepare time: 0.0009s, elapsed execute time: 3.7845s.
---------------------------------------------------------------------------
SAMPLES>>select min(sub_item_code) "sub_item_code(MIN)", max(sub_item_code) "sub_item_code(MAX)" from tab311
6. select min(sub_item_code) "sub_item_code(MIN)", max(sub_item_code) "sub_item_code(MAX)" from tab311

sub_item_code(MIN) sub_item_code(MAX)
0000000001 0000500000

1 Rows(s) Affected
statement prepare time: 0.1558s, elapsed execute time: 0.0004s.
---------------------------------------------------------------------------
SAMPLES>>q


本題からはずれるのですが... SQL使ってるとはいっても、ベースはMUMPSというかM言語だからね〜というお話を。。

tab3表及び主キー制約で作成された索引に対応するglobals。索引を見るとSparse Multidimensional Arrayをうまく利用しているのがよくわかる :)
Cachéの表や索引の実態はSparse Multidimensional Arrayなんだお。

1:      ^User.tab3D    =     1512812
2: ^User.tab3D(512813) = $lb("",1,"000000000000002","***************** ...中略... *******************************1",0,"00")
3: ^User.tab3D(512814) = $lb("",2,"000000000000003","***************** ...中略... *******************************2",0,"00")
4: ^User.tab3D(512815) = $lb("",3,"000000000000004","***************** ...中略... *******************************3",0,"00")
...以下略...

tab3表の主キー索引

1:      ^User.tab3I("tab3pk",1,512813)    =     ""
2: ^User.tab3I("tab3pk",2,512814) = ""
3: ^User.tab3I("tab3pk",3,512815) = ""
...以下略...

次は、tab31表と主キー索引

1:      ^User.tab31D    =     2000000
2: ^User.tab31D(1) = $lb("","000000000000001","0000000002","***************** ...中略... *************************1",0)
3: ^User.tab31D(2) = $lb("","000000000000002","0000000003","***************** ...中略... *************************2",0)
4: ^User.tab31D(3) = $lb("","000000000000003","0000000004","***************** ...中略... *************************3",0)
...以下略...


1:      ^User.tab31I("tab31pk"," 000000000000001",1)    =     ""
2: ^User.tab31I("tab31pk"," 000000000000002",2) = ""
3: ^User.tab31I("tab31pk"," 000000000000003",3) = ""
...以下略...


最後に、tab311表と主キー索引及び、非ユニーク索引に対応したSparse Multidimensional Arrayの内容

1:      ^User.tab311D    =     2000000
2: ^User.tab311D(1) = $lb("",1,"0000000002","********************************* ...中略... ************************1",0)
3: ^User.tab311D(2) = $lb("",2,"0000000003","********************************* ...中略... ************************2",0)
4: ^User.tab311D(3) = $lb("",3,"0000000004","********************************* ...中略... ************************3",0)
...以下略...

1:      ^User.tab311I("tab311ix"," 0000000001",500000)    =     ""
2: ^User.tab311I("tab311ix"," 0000000001",1000000) = ""
3: ^User.tab311I("tab311ix"," 0000000001",1500000) = ""
4: ^User.tab311I("tab311ix"," 0000000001",2000000) = ""
5: ^User.tab311I("tab311ix"," 0000000002",1) = ""
6: ^User.tab311I("tab311ix"," 0000000002",500001) = ""
7: ^User.tab311I("tab311ix"," 0000000002",1000001) = ""
8: ^User.tab311I("tab311ix"," 0000000002",1500001) = ""
9: ^User.tab311I("tab311ix"," 0000000003",2) = ""
10: ^User.tab311I("tab311ix"," 0000000003",500002) = ""
11: ^User.tab311I("tab311ix"," 0000000003",1000002) = ""
12: ^User.tab311I("tab311ix"," 0000000003",1500002) = ""
13: ^User.tab311I("tab311ix"," 0000000004",3) = ""
14: ^User.tab311I("tab311ix"," 0000000004",500003) = ""
15: ^User.tab311I("tab311ix"," 0000000004",1000003) = ""
16: ^User.tab311I("tab311ix"," 0000000004",1500003) = ""
...以下略...


実行するクエリはOracle/MySQL/PostgreSQLで実行したものと同じです。

select
t1.unique_id,
t1.item_code,
(
select
max(t3.unique_id)
from
tab31 t2 join tab311 t3
on
t2.sub_item_code = t3.sub_item_code
and t3.is_delete = 0
where
t2.item_code = t1.item_code
and t2.is_delete = 0
) current_sub_item
from
tab3 t1
where
t1.unique_id between 1 and 10000
and t1.is_delete = 0
and t1.status_code = '00'


以下、管理ポータルのSQL実行プラン表示で取得した実行計画とコスト。
Index Only AccessではないのでCacheのSQLの世界で表アクセスを意味するオペレーションである、Read Master mapがスカラー問合せ部分に現れている。
ちなみに、索引アクセスを意味するオペレーションは、Read index mapのようだ。

実行プランが以下に表示されます:
クエリ文字列

SELECT t1 . unique_id , t1 . item_code , ( SELECT MAX ( t3 . unique_id ) FROM tab31 t2 JOIN tab311 t3 ON t2 . sub_item_code = t3 . sub_item_code AND t3 .
is_delete = ? WHERE t2 . item_code = t1 . item_code AND t2 . is_delete = ? ) current_sub_item FROM tab3 t1 WHERE t1 . unique_id BETWEEN ? AND ? AND t1 .
is_delete = ? AND t1 . status_code = ?

クエリプラン
相対コスト = 74082

Call module B, which populates bitmap temp-file A.
Read bitmap temp-file A, looping on ID.
For each row:
Read master map SQLUser.tab3.IDKEY, using the given idkey value.
Output the row.

module B
Read index map SQLUser.tab3.tab3_pk, looping on unique_id (with a range condition) and ID.
For each row:
Add ID bit to bitmap temp-file A.

subquery
Call module E.
Determine subquery result.

module E
Read index map SQLUser.tab31.tab31_pk, using the given %SQLUPPER(item_code), and looping on ID.
For each row:
Read master map SQLUser.tab31.IDKEY, using the given idkey value.
Read index map SQLUser.tab311.tab311_ix, using the given %SQLUPPER(sub_item_code), and looping on ID.
For each row:
Read master map SQLUser.tab311.IDKEY, using the given idkey value.
Accumulate the max(unique_id).


では、Index Only Accessによるチューニング。 Covering Indexを2つ作成します。(Oracle/MySQL/PostgreSQLで作成した索引と同じ名称にしてあります)

[oracle@pleco ˜]$ csession cache -U samples

ノード: pleco.macdeoracle.JP インスタンス: CACHE

SAMPLES>d $System.SQL.Shell()
SQL Command Line Shell
----------------------------------------------------

The command prefix is currently set to: <<nothing>>.
Enter q to quit, ? for help.
SAMPLES>>create index tab31_demo_ix on tab31(item_code, is_delete, sub_item_code)
1. create index tab31_demo_ix on tab31(item_code, is_delete, sub_item_code)

0 Rows Affected
statement prepare time: 4.8277s, elapsed execute time: 9.6483s.
---------------------------------------------------------------------------
SAMPLES>>create index tab311_demo_ix on tab311(sub_item_code, is_delete, unique_id)
2. create index tab311_demo_ix on tab311(sub_item_code, is_delete, unique_id)

0 Rows Affected
statement prepare time: 0.0130s, elapsed execute time: 8.6777s.
---------------------------------------------------------------------------
SAMPLES>>

索引は正しく作成されています。(管理ポータルから確認した結果)
Tab31_indexes_index_only

Tab311_indexes_inde_only

お〜〜〜〜〜っ!。 CacheのSQLワールドでもIndex Only Accessになってる〜〜〜。 (ヒントのような仕組みはないようなのですが、狙い通りの索引が利用されていますね)
スカラー副問合せの実行計画から Read Master Map(表に対応するSparse Multidimensional Array)をアクセスする操作が消え、Read index Map(索引に対応するSparse Multidimensional Array)をアクセスする操作だけになっていることが確認できた。 :)

以下、管理ポータルの「SQL実行」>「実行計画」で取得した実行計画

クエリプラン
相対コスト = 74082

Call module B, which populates bitmap temp-file A.
Read bitmap temp-file A, looping on ID.
For each row:
Read master map SQLUser.tab3.IDKEY, using the given idkey value.
Output the row.

module B
Read index map SQLUser.tab3.tab3_pk, looping on unique_id (with a range condition) and ID.
For each row:
Add ID bit to bitmap temp-file A.

subquery
Call module E.
Determine subquery result.

module E
Read index map SQLUser.tab31.tab31_demo_ix, using the given %SQLUPPER(item_code) and is_delete, and looping on %SQLUPPER(sub_item_code) and ID.
For each row:
Read index map SQLUser.tab311.tab311_demo_ix, using the given %SQLUPPER(sub_item_code) and is_delete, and looping on unique_id and ID.
For each row:
Accumulate the max(unique_id).

| | | コメント (0) | トラックバック (0)

2012年8月21日 (火)

Index Only Accessネタのおまけ

2012/10/13追記
MySQL(InnoDB)の主キーはClustered Indexなので主キーアクセスである場合はCovering indexは不要ですね。(^^;; 
PostgreSQL9.2のIndex-only scanですが、vacuumさえしっかりやっていればcovering indexを利用するようになることを確認。

前述の2点を後日追加予定です。



随分間があいてしまいました、m(_ _)m

Oracle以外でも多数の商用/OSS RDBMSでIndex Only Accessできるんですよね。
ということで、MySQL/PostgreSQLの実行計画ではどのように表示されるのか、Oracleのように索引だけ作れば勝ってにIndex Only Accessやってくれるのか?、などなど簡単に確かめてみました。(備忘録)

OracleのIndex Only Accessは以下のエントリを参考にしてください。
いん!、イン!、Index どっぷり Inde Only Access生活w - Oracle OpenWorld Unconference presented by JPOUG
JPOUG SET EVENTS 20120721 - 「(続)いん!、イン!、Index 大人の事情縛りのSQLチューニング」資料公開

今回使ったのは、MySQL 5.5.27/PostgreSQL 9.1.4そしてBeta阪ですが9.2 Beta4です。
環境はOracleが乗ってる環境と同じです。

MacBook Air late 2010 13inch 2GB (MacOS X Lion)
VirtualBox4.1.18 for MacOS X
GuestOS:CentOS5.8 x86

ちなみに、データ作りに時間を割けなかったので、クラスタリングファクターはどちらのも低めとなっています。実行計画上どのように見えるのか知りたかっただけなので. (^^;;;

MySQL 5.5.27

Oracleのデモでも使っていたスカラー副問合せで試してみました。最初は、Index Rancge Scanをグルグル。
この場合は索引、表をそれぞれアクセスします。

mysql> explain 
-> select
-> t1.unique_id,
-> t1.item_code,
-> (
-> select
-> max(t3.unique_id)
-> from
-> tab31 t2 join tab311 t3
-> on
-> t2.sub_item_code = t3.sub_item_code
-> and t3.is_delete = 0
-> where
-> t2.item_code = t1.item_code
-> and t2.is_delete = 0
-> ) current_sub_item
-> from
-> tab3 t1
-> where
-> t1.unique_id between 1 and 10000
-> and t1.is_delete = 0
-> and t1.status_code = '00'
-> ;
+----+--------------------+-------+--------+---------------+-----------+---------+------------------------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+--------+---------------+-----------+---------+------------------------+-------+-------------+
| 1 | PRIMARY | t1 | range | PRIMARY | PRIMARY | 5 | NULL | 20108 | Using where |
| 2 | DEPENDENT SUBQUERY | t2 | eq_ref | PRIMARY | PRIMARY | 45 | scott.t1.item_code | 1 | Using where |
| 2 | DEPENDENT SUBQUERY | t3 | ref | tab311_ix | tab311_ix | 31 | scott.t2.sub_item_code | 1 | Using where |
+----+--------------------+-------+--------+---------------+-----------+---------+------------------------+-------+-------------+
3 rows in set (0.00 sec)

mysql>


Index Only Accessさせた場合の実行計画です。
Extra列に Using indexと出ていればIndex Only Accessになっています。
ちなみに、Oracleとちがって勝ってにCovering Indexを使ってくれなかったのでSQLヒントを使っています。Oracleのヒントと随分書き方違うので戸惑うよ(^^;;;

mysql> explain
-> select
-> t1.unique_id,
-> t1.item_code,
-> (
-> select
-> max(t3.unique_id)
-> from
-> tab31 t2 ignore index(primary) join tab311 t3 ignore index(tab311_ix)
-> on
-> t2.sub_item_code = t3.sub_item_code
-> and t3.is_delete = 0
-> where
-> t2.item_code = t1.item_code
-> and t2.is_delete = 0
-> ) current_sub_item
-> from
-> tab3 t1
-> where
-> t1.unique_id between 1 and 10000
-> and t1.is_delete = 0
-> and t1.status_code = '00'
-> ;
+----+--------------------+-------+-------+----------------+----------------+---------+------------------------------+-------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+-------+----------------+----------------+---------+------------------------------+-------+--------------------------+
| 1 | PRIMARY | t1 | range | PRIMARY | PRIMARY | 5 | NULL | 20108 | Using where |
| 2 | DEPENDENT SUBQUERY | t2 | ref | tab31_demo_ix | tab31_demo_ix | 47 | scott.t1.item_code,const | 10000 | Using where; Using index |
| 2 | DEPENDENT SUBQUERY | t3 | ref | tab311_demo_ix | tab311_demo_ix | 33 | scott.t2.sub_item_code,const | 10000 | Using where; Using index |
+----+--------------------+-------+-------+----------------+----------------+---------+------------------------------+-------+--------------------------+
3 rows in set (0.00 sec)

mysql>


PostgreSQL 9.1

PostgreSQL9.1まではIndex Only Accessが実装されていないとのこと。(実は今年になってはじめて知ったことなのですが、その時は、「え?! そうなの?」って感じでした)

※実行時間のバラツキがあるため実行統計情報から表や索引ブロックアクセス状況を確認しています。

scott=> select * from pg_statio_user_tables where relname in ('tab31','tab311');
relid | schemaname | relname | heap_blks_read | heap_blks_hit | idx_blks_read | idx_blks_hit | toast_blks_read | toast_blks_hit | tidx_blks_read | tidx_blks_hit
-------+------------+---------+----------------+---------------+---------------+--------------+-----------------+----------------+----------------+---------------
16401 | public | tab311 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
16395 | public | tab31 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0

scott=> select * from pg_statio_user_indexes where relname in ('tab31','tab311');
relid | indexrelid | schemaname | relname | indexrelname | idx_blks_read | idx_blks_hit
-------+------------+------------+---------+----------------+---------------+--------------
16401 | 16411 | public | tab311 | tab311_pk | 0 | 0
16395 | 16454 | public | tab31 | tab31_demo_ix | 0 | 0
16401 | 16455 | public | tab311 | tab311_demo_ix | 0 | 0

scott=> explain analyze verbose
scott-> select
scott-> t1.unique_id,
scott-> t1.item_code,
scott-> (
scott(> select
scott(> max(t3.unique_id)
scott(> from
scott(> tab31 t2 join tab311 t3
scott(> on
scott(> t2.sub_item_code = t3.sub_item_code
scott(> and t3.is_delete = 0
scott(> where
scott(> t2.item_code = t1.item_code
scott(> and t2.is_delete = 0
scott(> ) current_sub_item
scott-> from
scott-> tab3 t1
scott-> where
scott-> t1.unique_id between 1 and 10000
scott-> and t1.is_delete = 0
scott-> and t1.status_code = '00'
scott-> ;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------
Index Scan using tab3_pk on public.tab3 t1 (cost=0.00..2050286.39 rows=10326 width=22) (actual time=45.613..6560.751 rows=10000 loops=1)
Output: t1.unique_id, t1.item_code, (SubPlan 1)
Index Cond: ((t1.unique_id >= 1::numeric) AND (t1.unique_id <= 10000::numeric))
Filter: ((t1.is_delete = 0::numeric) AND (t1.status_code = '00'::bpchar))
SubPlan 1
-> Aggregate (cost=198.47..198.48 rows=1 width=6) (actual time=0.650..0.651 rows=1 loops=10000)
Output: max(t3.unique_id)
-> Nested Loop (cost=0.00..198.46 rows=4 width=6) (actual time=0.143..0.621 rows=40 loops=10000)
Output: t3.unique_id
-> Index Scan using tab31_pk on public.tab31 t2 (cost=0.00..8.58 rows=1 width=11) (actual time=0.010..0.011 rows=1 loops=10000)
Output: t2.item_code, t2.sub_item_code, t2.data, t2.is_delete
Index Cond: (t2.item_code = t1.item_code)
Filter: (t2.is_delete = 0::numeric)
-> Index Scan using tab311_ix on public.tab311 t3 (cost=0.00..189.27 rows=49 width=17) (actual time=0.130..0.565 rows=40 loops=10000)
Output: t3.unique_id, t3.sub_item_code, t3.data, t3.is_delete
Index Cond: (t3.sub_item_code = t2.sub_item_code)
Filter: (t3.is_delete = 0::numeric)
Total runtime: 6566.636 ms
(18 行)

時間: 6618.795 ms
scott=>

適切な索引を利用しているのでIndex Unique/Range Scanとテーブルブロックへのアクセスが確認できます。(当然といえば当然ですよね)

scott=> select * from pg_statio_user_tables where relname in ('tab31','tab311');
relid | schemaname | relname | heap_blks_read | heap_blks_hit | idx_blks_read | idx_blks_hit | toast_blks_read | toast_blks_hit | tidx_blks_read | tidx_blks_hit
-------+------------+---------+----------------+---------------+---------------+--------------+-----------------+----------------+----------------+---------------
16401 | public | tab311 | 15389 | 36920 | 1983 | 30033 | 0 | 0 | 0 | 0
16395 | public | tab31 | 401 | 9599 | 64 | 30057 | 0 | 0 | 0 | 0

scott=> select * from pg_statio_user_indexes where relname in ('tab31','tab311');
relid | indexrelid | schemaname | relname | indexrelname | idx_blks_read | idx_blks_hit
-------+------------+------------+---------+----------------+---------------+--------------
16401 | 16411 | public | tab311 | tab311_pk | 0 | 0
16395 | 16454 | public | tab31 | tab31_demo_ix | 64 | 30057
16401 | 16455 | public | tab311 | tab311_demo_ix | 1983 | 30033

Index Only AccessさせるためのCovering Index(FAT index)を作ってみましたが、Index Range/Unique Scanのままですね。
ちなみに、PostgreSQLってOracleやMySQLのようなSQLヒントがありません。(あったらごめんなさい。調べきれてないだけです。m(_ _)m
Covering Indexだけを残して邪魔な索引を削除することでCovering indexをアクセスさせています。

scott=> select * from pg_statio_user_tables where relname in ('tab31','tab311');
relid | schemaname | relname | heap_blks_read | heap_blks_hit | idx_blks_read | idx_blks_hit | toast_blks_read | toast_blks_hit | tidx_blks_read | tidx_blks_hit
-------+------------+---------+----------------+---------------+---------------+--------------+-----------------+----------------+----------------+---------------
16401 | public | tab311 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
16395 | public | tab31 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0

scott=> select * from pg_statio_user_indexes where relname in ('tab31','tab311');
relid | indexrelid | schemaname | relname | indexrelname | idx_blks_read | idx_blks_hit
-------+------------+------------+---------+----------------+---------------+--------------
16401 | 16411 | public | tab311 | tab311_pk | 0 | 0
16395 | 16454 | public | tab31 | tab31_demo_ix | 0 | 0
16401 | 16455 | public | tab311 | tab311_demo_ix | 0 | 0


scott=> explain analyze verbose
scott-> select
scott-> t1.unique_id,
scott-> t1.item_code,
scott-> (
scott(> select
scott(> max(t3.unique_id)
scott(> from
scott(> tab31 t2 join tab311 t3
scott(> on
scott(> t2.sub_item_code = t3.sub_item_code
scott(> and t3.is_delete = 0
scott(> where
scott(> t2.item_code = t1.item_code
scott(> and t2.is_delete = 0
scott(> ) current_sub_item
scott-> from
scott-> tab3 t1
scott-> where
scott-> t1.unique_id between 1 and 10000
scott-> and t1.is_delete = 0
scott-> and t1.status_code = '00'
scott-> ;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------------------------
Index Scan using tab3_pk on public.tab3 t1 (cost=0.00..2109597.62 rows=10326 width=22) (actual time=0.677..1808.056 rows=10000 loops=1)
Output: t1.unique_id, t1.item_code, (SubPlan 1)
Index Cond: ((t1.unique_id >= 1::numeric) AND (t1.unique_id <= 10000::numeric))
Filter: ((t1.is_delete = 0::numeric) AND (t1.status_code = '00'::bpchar))
SubPlan 1
-> Aggregate (cost=204.21..204.22 rows=1 width=6) (actual time=0.176..0.176 rows=1 loops=10000)
Output: max(t3.unique_id)
-> Nested Loop (cost=0.00..204.20 rows=4 width=6) (actual time=0.024..0.137 rows=40 loops=10000)
Output: t3.unique_id
-> Index Scan using tab31_demo_ix on public.tab31 t2 (cost=0.00..8.76 rows=1 width=11) (actual time=0.007..0.009 rows=1 loops=10000)
Output: t2.item_code, t2.sub_item_code, t2.data, t2.is_delete
Index Cond: ((t2.item_code = t1.item_code) AND (t2.is_delete = 0::numeric))
-> Index Scan using tab311_demo_ix on public.tab311 t3 (cost=0.00..194.84 rows=49 width=17) (actual time=0.013..0.068 rows=40 loops=10000)
Output: t3.unique_id, t3.sub_item_code, t3.data, t3.is_delete
Index Cond: ((t3.sub_item_code = t2.sub_item_code) AND (t3.is_delete = 0::numeric))
Total runtime: 4762.819 ms
(16 行)

時間: 4855.100 ms
scott=>

実行計画上、Filterはなくなりましたが、表ブロックもアクセスしているのでIndex Only Accessにはなっていません。(ほんとにIndex Only AccessというかIndex-only Scanは9.1までは実装されていないんですね。)

scott=> select * from pg_statio_user_tables where relname in ('tab31','tab311');
relid | schemaname | relname | heap_blks_read | heap_blks_hit | idx_blks_read | idx_blks_hit | toast_blks_read | toast_blks_hit | tidx_blks_read | tidx_blks_hit
-------+------------+---------+----------------+---------------+---------------+--------------+-----------------+----------------+----------------+---------------
16401 | public | tab311 | 15390 | 36919 | 1982 | 30034 | 0 | 0 | 0 | 0
16395 | public | tab31 | 401 | 9599 | 62 | 30059 | 0 | 0 | 0 | 0

scott=> select * from pg_statio_user_indexes where relname in ('tab31','tab311');
relid | indexrelid | schemaname | relname | indexrelname | idx_blks_read | idx_blks_hit
-------+------------+------------+---------+----------------+---------------+--------------
16401 | 16411 | public | tab311 | tab311_pk | 0 | 0
16395 | 16454 | public | tab31 | tab31_demo_ix | 62 | 30059
16401 | 16455 | public | tab311 | tab311_demo_ix | 1982 | 30034

PostgreSQL 9.2 Beta4

最後に、PostgreSQL 9.2 Beta4 です。このリリースではPostgreSQLでは初めて、Index Only Access(マニュアルでは Index-only Scanと記載されています)
PostgreSQL方面の方がIndex-only Scanと書くかたが多いのもこの影響でしょうね。日本人からするとIndex Only AccessよりIndex Only Scanの方が発音しやすい?(私だけか?)気がしますw

scott=> explain analyze verbose
scott-> select
scott-> t1.unique_id,
scott-> t1.item_code,
scott-> (
scott(> select
scott(> max(t3.unique_id)
scott(> from
scott(> tab31 t2 join tab311 t3
scott(> on
scott(> t2.sub_item_code = t3.sub_item_code
scott(> and t3.is_delete = 0
scott(> where
scott(> t2.item_code = t1.item_code
scott(> and t2.is_delete = 0
scott(> ) current_sub_item
scott-> from
scott-> tab3 t1
scott-> where
scott-> t1.unique_id between 1 and 10000
scott-> and t1.is_delete = 0
scott-> and t1.status_code = '00'
scott-> ;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------
Index Scan using tab3_pk on public.tab3 t1 (cost=0.00..1925706.85 rows=9421 width=22) (actual time=41.205..6202.096 rows=10000 loops=1)
Output: t1.unique_id, t1.item_code, (SubPlan 1)
Index Cond: ((t1.unique_id >= 1::numeric) AND (t1.unique_id <= 10000::numeric))
Filter: ((t1.is_delete = 0::numeric) AND (t1.status_code = '00'::bpchar))
SubPlan 1
-> Aggregate (cost=204.32..204.33 rows=1 width=6) (actual time=0.613..0.614 rows=1 loops=10000)
Output: max(t3.unique_id)
-> Nested Loop (cost=0.00..204.31 rows=4 width=6) (actual time=0.110..0.584 rows=40 loops=10000)
Output: t3.unique_id
-> Index Scan using tab31_pk on public.tab31 t2 (cost=0.00..11.35 rows=1 width=11) (actual time=0.012..0.013 rows=1 loops=10000)
Output: t2.item_code, t2.sub_item_code, t2.data, t2.is_delete
Index Cond: (t2.item_code = t1.item_code)
Filter: (t2.is_delete = 0::numeric)
-> Index Scan using tab311_ix on public.tab311 t3 (cost=0.00..192.47 rows=49 width=17) (actual time=0.095..0.525 rows=40 loops=10000)
Output: t3.unique_id, t3.sub_item_code, t3.data, t3.is_delete
Index Cond: (t3.sub_item_code = t2.sub_item_code)
Filter: (t3.is_delete = 0::numeric)
Total runtime: 6207.935 ms
(18 行)

時間: 6313.789 ms
scott=>

9.2でもIndex Only Accessでなければ表ブロックもアクセスしますよね〜。そりゃそうだ。:)

scott=> select * from pg_statio_user_tables where relname in ('tab31','tab311');
relid | schemaname | relname | heap_blks_read | heap_blks_hit | idx_blks_read | idx_blks_hit | toast_blks_read | toast_blks_hit | tidx_blks_read | tidx_blks_hit
-------+------------+---------+----------------+---------------+---------------+--------------+-----------------+----------------+----------------+---------------
16404 | public | tab311 | 15390 | 36919 | 1649 | 29996 | 0 | 0 | 0 | 0
16398 | public | tab31 | 401 | 9599 | 39 | 30037 | 0 | 0 | 0 | 0

scott=> select * from pg_statio_user_indexes where relname in ('tab31','tab311');
relid | indexrelid | schemaname | relname | indexrelname | idx_blks_read | idx_blks_hit
-------+------------+------------+---------+--------------+---------------+--------------
16404 | 16414 | public | tab311 | tab311_pk | 0 | 0
16398 | 16432 | public | tab31 | tab31_pk | 39 | 30037
16404 | 16434 | public | tab311 | tab311_ix | 1649 | 29996

いよいよ、PostgreSQL9.2 Beta4のIndex-only Scanの番です。:)
お〜〜〜っ、 Index Scan using xxxxという部分が、Index Only Scan using xxxxとなっています! が、 Heap Fetches 400000とある? どゆこと?

scott=> explain analyze verbose
scott-> select
scott-> t1.unique_id,
scott-> t1.item_code,
scott-> (
scott(> select
scott(> max(t3.unique_id)
scott(> from
scott(> tab31 t2 join tab311 t3
scott(> on
scott(> t2.sub_item_code = t3.sub_item_code
scott(> and t3.is_delete = 0
scott(> where
scott(> t2.item_code = t1.item_code
scott(> and t2.is_delete = 0
scott(> ) current_sub_item
scott-> from
scott-> tab3 t1
scott-> where
scott-> t1.unique_id between 1 and 10000
scott-> and t1.is_delete = 0
scott-> and t1.status_code = '00'
scott-> ;

QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
Index Scan using tab3_pk on public.tab3 t1 (cost=0.00..2000896.05 rows=9421 width=22) (actual time=0.410..1728.699 rows=10000 loops=1)
Output: t1.unique_id, t1.item_code, (SubPlan 1)
Index Cond: ((t1.unique_id >= 1::numeric) AND (t1.unique_id <= 10000::numeric))
Filter: ((t1.is_delete = 0::numeric) AND (t1.status_code = '00'::bpchar))
SubPlan 1
-> Aggregate (cost=212.30..212.31 rows=1 width=6) (actual time=0.168..0.168 rows=1 loops=10000)
Output: max(t3.unique_id)
-> Nested Loop (cost=0.00..212.29 rows=4 width=6) (actual time=0.023..0.131 rows=40 loops=10000)
Output: t3.unique_id
-> Index Only Scan using tab31_demo_ix on public.tab31 t2 (cost=0.00..13.13 rows=1 width=11) (actual time=0.006..0.007 rows=1 loops=10000)
Output: t2.item_code, t2.is_delete, t2.sub_item_code
Index Cond: ((t2.item_code = t1.item_code) AND (t2.is_delete = 0::numeric))
Heap Fetches: 10000
-> Index Only Scan using tab311_demo_ix on public.tab311 t3 (cost=0.00..198.67 rows=49 width=17) (actual time=0.013..0.066 rows=40 loops=10000)
Output: t3.sub_item_code, t3.is_delete, t3.unique_id
Index Cond: ((t3.sub_item_code = t2.sub_item_code) AND (t3.is_delete = 0::numeric))
Heap Fetches: 400000
Total runtime: 5412.612 ms
(18 行)

時間: 5465.400 ms
scott=>

やはり! Heap Fetchesとあるのでおかしいと思っていたら...orz. なんで表ブロックアクセスしてんの〜〜〜っ。実行計画は、Index Only Scan。謎。

scott=> select * from pg_statio_user_tables where relname in ('tab31','tab311');
relid | schemaname | relname | heap_blks_read | heap_blks_hit | idx_blks_read | idx_blks_hit | toast_blks_read | toast_blks_hit | tidx_blks_read | tidx_blks_hit
-------+------------+---------+----------------+---------------+---------------+--------------+-----------------+----------------+----------------+---------------
16404 | public | tab311 | 15389 | 36920 | 1983 | 30033 | 0 | 0 | 0 | 0
16398 | public | tab31 | 401 | 9599 | 64 | 30057 | 0 | 0 | 0 | 0

scott=> select * from pg_statio_user_indexes where relname in ('tab31','tab311');
relid | indexrelid | schemaname | relname | indexrelname | idx_blks_read | idx_blks_hit
-------+------------+------------+---------+----------------+---------------+--------------
16404 | 16414 | public | tab311 | tab311_pk | 0 | 0
16398 | 16435 | public | tab31 | tab31_demo_ix | 64 | 30057
16404 | 16436 | public | tab311 | tab311_demo_ix | 1983 | 30033


何故、Inde Only Scanなのに表ブロックをアクセスしてしまうのか、わかった〜〜〜っ、と思う。(vacuum analyze が必要らしい。ちなみに前述の結果はデータをINSERTし、analyzeコマンドだけを実施した状態だった)

気持ちを落ち着けて〜〜〜!

[oracle@leaffish ˜]$ psql -U oracle scott
タイミングは on です。
psql (9.2beta4)
"help" でヘルプを表示します.

scott=# vacuum analyze tab311;
scott=# vacuum analyze tab31;


こんどこそ! できた〜〜〜〜っ!と思う。
Heap Fetchesも0だし、表ブロックへのアクセスもほぼない。ほぼない。大切なので2度書きました。表ブロックへのアクセスは0にはならないようです。今のところ。こまけーことはいいんだよ的で、ワイルド。 :) 数ブロックアクセスしているのはどのようなブロックなのでしょうね

scott=> explain analyze verbose
scott-> select
scott-> t1.unique_id,
scott-> t1.item_code,
scott-> (
scott(> select
scott(> max(t3.unique_id)
scott(> from
scott(> tab31 t2 join tab311 t3
scott(> on
scott(> t2.sub_item_code = t3.sub_item_code
scott(> and t3.is_delete = 0
scott(> where
scott(> t2.item_code = t1.item_code
scott(> and t2.is_delete = 0
scott(> ) current_sub_item
scott-> from
scott-> tab3 t1
scott-> where
scott-> t1.unique_id between 1 and 10000
scott-> and t1.is_delete = 0
scott-> and t1.status_code = '00'
scott-> ;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
Index Scan using tab3_pk on public.tab3 t1 (cost=0.00..188801.90 rows=9921 width=22) (actual time=0.255..1116.525 rows=10000 loops=1)
Output: t1.unique_id, t1.item_code, (SubPlan 1)
Index Cond: ((t1.unique_id >= 1::numeric) AND (t1.unique_id <= 10000::numeric))
Filter: ((t1.is_delete = 0::numeric) AND (t1.status_code = '00'::bpchar))
SubPlan 1
-> Aggregate (cost=18.95..18.96 rows=1 width=6) (actual time=0.108..0.109 rows=1 loops=10000)
Output: max(t3.unique_id)
-> Nested Loop (cost=0.00..18.94 rows=4 width=6) (actual time=0.019..0.081 rows=40 loops=10000)
Output: t3.unique_id
-> Index Only Scan using tab31_demo_ix on public.tab31 t2 (cost=0.00..9.13 rows=1 width=11) (actual time=0.005..0.005 rows=1 loops=10000)
Output: t2.item_code, t2.is_delete, t2.sub_item_code
Index Cond: ((t2.item_code = t1.item_code) AND (t2.is_delete = 0::numeric))
Heap Fetches: 0
-> Index Only Scan using tab311_demo_ix on public.tab311 t3 (cost=0.00..9.32 rows=49 width=17) (actual time=0.012..0.036 rows=40 loops=10000)
Output: t3.sub_item_code, t3.is_delete, t3.unique_id
Index Cond: ((t3.sub_item_code = t2.sub_item_code) AND (t3.is_delete = 0::numeric))
Heap Fetches: 0
Total runtime: 1121.140 ms
(18 行)

時間: 1123.194 ms

scott=> select * from pg_statio_user_tables where relname in ('tab31','tab311');
relid | schemaname | relname | heap_blks_read | heap_blks_hit | idx_blks_read | idx_blks_hit | toast_blks_read | toast_blks_hit | tidx_blks_read | tidx_blks_hit
-------+------------+---------+----------------+---------------+---------------+--------------+-----------------+----------------+----------------+---------------
16404 | public | tab311 | 0 | 3 | 0 | 32015 | 0 | 0 | 0 | 0
16398 | public | tab31 | 0 | 1 | 0 | 30120 | 0 | 0 | 0 | 0

scott=> select * from pg_statio_user_indexes where relname in ('tab31','tab311');
relid | indexrelid | schemaname | relname | indexrelname | idx_blks_read | idx_blks_hit
-------+------------+------------+---------+----------------+---------------+--------------
16404 | 16414 | public | tab311 | tab311_pk | 0 | 0
16398 | 16421 | public | tab31 | tab31_demo_ix | 0 | 30120
16404 | 16422 | public | tab311 | tab311_demo_ix | 0 | 32015




参考:
INDEX FULL SCANを狙う - MySQL Casual Advent Calendar 2011
Covering Index と self-join と MySQL
How are index-only scans implemented in InnoDB
PostgreSQL 9.2 highlight: Index-only scans
PostgreSQLアーキテクチャ入門(INSIGHT OUT 2011)

| | | コメント (0) | トラックバック (0)

2011年11月 1日 (火)

鬼熱かった! :: Insight out 2011- DB tech showcase

書くのおそくなっちゃいました m(_ _)m

10月19日〜21日に開催されたInsight out 2011- DB tech showcase
に、つまみ食いながらなんとか参加し、インサイトテクノロジーさんの鬼熱い魂を感じてきた :)

無理矢理空き時間作って参加したセッションは以下の通り。

  • Deep Dive into Oracle Database Patch (Oracle) - 諸橋渉
  • Why Why is probably the right answer (Oracle) - Tom Kyte
  • Rac Buffer Sharingの仕組み (Oracle) - 山下正
  • Effective Indexing (Oracle) - Tom Kyte
  • New challenges Information security technologies are facing (others) - David Maman
  • Developer and Indexes (Oracle) - Anjo Kolk

MySQLとかPostgreSQLとかOSSなのはOSCとかでも聴けるかなーと思いきづいたらOracle中心だったw

Effective Indexing/Developer and Indexes というセッションは予想以上だった、Indexを理解してるのって重要だよなーと改めて感じたセッションだった。

Tom Kyteさんが紹介していた書籍、「Relational Database Index Design and the Optimizers」


鬼熱い語りの山下さんのセッション、前回のOOWのUnconferenceの続編か?と思わせるような諸橋さんのセッション、つい引き込まれちゃいましたよ:)

参加者やスピーカが鬼熱いエンジニアであることは間違いないが、何と言っても、世界中からデータベースに関わる凄い方々を集めてしまうインサイトテクノロジーさんが一番、鬼熱いんじゃないかと感じた3日間だった。

来年も開催して頂きたいイベントだ。


Img_2299


| | | コメント (0) | トラックバック (0)

2009年12月10日 (木)

Firebird徹底入門が発売されたので...

"待望の『Firebird徹底入門』本日発売!"とのことで。

| | | コメント (0) | トラックバック (0)

2009年8月 8日 (土)

第18回オープンソーステクノロジー勉強会 - MySQLハッキングの手引き

第18回オープンソーステクノロジー勉強会 - MySQLハッキングの手引きに参加してきた。
定員60名だったようだがそれ以上いたんじゃないかな...(人数が多かったらしく抽選で参加者が選ばれたようだが。。。)
MySQLハッキングの手引きということで入門的な内容だったようだがMySQLのソースを見た事がない私にはなんのことやらってところは多かったものの、ニンマリしてしまうようなデモやら話やら....松信さんのマシンガントークで時間内に終わることを想定していた私は見事に裏切られた(時間オーバーしても長いとは感じませんでしたが)。
おもしろいテーマでした。時間があったらプラグインなんか作ってみようか思ってしまうぐらいだから。。資料は公開されるということなので楽しみにしています。

前回参加したときは懇親会には不参加だったが今回は最後までいましたよ〜〜。:)

Oracleネタ以外がつづいてますが、あしからず。。。ネタ仕込み中なので・・・



第18回オープンソーステクノロジー勉強会 −開催のご報告− GREE Labs

セミナーのアジェンダ

・MySQLアーキテクチャ
・ソースコード入手とビルド方法
・デバッグ方法
・プラグイン開発方法(デモ有り)
・本体拡張方法(デモ有り)
・本家へのコントリビュートの方法

| | | コメント (0) | トラックバック (0)

2009年5月22日 (金)

DB2 で PL/SQL

DB2新版はPL/SQL対応、Oracleユーザーの移行狙う@ ITmedia

へぇ〜、それじゃ、昨日作ったケンブリッジ関数もDB2 9.7で動作するようになるのか〜〜。へぇ〜。mod_plsqlというかPL/SQL gatewayはどうなんだろうか?、Oracleが提供しているPL/SQLパッケージも対応しているのだろうか? 機会があったら質問しておこうっと。

できれば他のRDBMSでもやってくれるとありがたいかも...

PL/SQL : Write Once Run Any RDBMS なんてね。

| | | コメント (0) | トラックバック (0)

2009年5月11日 (月)

Cache' デベロッパーズガイドを頂きました。m(_ _)m

先月の今頃だが、[CodeZine_News号外 2009-04-09]オブジェクトDB Caché入門書プレゼントという案内が来ていたので、いつものノリで応募していたのだが、プレゼントに当選したようで、Caché デベロッパーズガイドが本日届いた。ありがとうございました。

(最近よく当選するんだよな〜、くじ運は悪いのに・・・)

Mac で Oracleな当ブログですが過去、Cachéネタも幾つかあったりします。:)

10日後は何日?、翌月末日って何日?
Mac de Caché というか MUMPS というか Objectscript か



| | | コメント (0) | トラックバック (0)

2009年1月26日 (月)

10日後は何日?、翌月末日って何日?

ichii386さん「相対的な日付って」記事に背骨というか脊髄反応的にコメントした勢いで、今日の10日後は何日?翌月末日って何日?の算出を幾つかやってみた。(「オリジナルの記事は今月末を求めているんですけど・・・・」・・・・ハイ、私が読み間違えて”翌月末”と勘違いしてました。今気付いたよ。w)

なんでgnuとphpだけなの? という突っ込みはなしで…。
なんでFirebirdが無いのかとか、CachéでSQLを使わないでMUMPSというかM言語というかCaché ObjectScriptなのかとか、Oracle11gなのに、MySQLは5.0PostgreSQLは7.4.9なのかとか、というツッコミはなしで...w

前提:
今日は1月24日として、10日後、翌月末日を算出します。

まずはPowerPC版のは古いのしかなかったのでCaché 5.2 for MacOSX(PowerPC)
MUMPS(M言語)がCachéで拡張?されてObjectiveになっちゃってObjectScriptと呼ばれているのには少々戸惑うけど、そこは昔取った杵柄。SQLも使えるけどM言語の方が作り易かったので。。w
ObjectScriptだと日付レベルで何日前とか何日後という計算は簡単なのだが、何ヶ月後とかいう計算は面倒なので。
(算出方法は翌々月の1日の前日が翌月末という考え方です。)

G5Server:˜ discus$ csession cache -U user

USER>
USER>w !,$zversion

Cache for UNIX (Mac OS X/32-bit) 5.2 (Build 329U_su) Wed Jun 21 2006 11:29:29 EDT
USER>
USER>
USER>w !,$zd($h+10,3)

2009-02-03
USER>s now=$h, y=$e($zd(now),7,10), m=$e($zd(now),1,2) w !,$zd($zdh($s(m<11:y_m+2_"01", m>10:y+1_m-10_"01"),5)-1,3)

2009-02-28
USER>
USER>halt
G5Server:˜ discus$

次は、Oracle11g EE 11.1.0.6.0 for Linux(x86)
OracleのSQLだとlast_day()や期間リテラルで簡単に算出できる。お気楽モード :-)

G5Server:˜ discus$ sqlplus /nolog

SQL*Plus: Release 10.1.0.3.0 - Production on 土 1月 24 13:53:33 2009

Copyright (c) 1982, 2004, Oracle. All rights reserved.

> conn scott/tiger@lampeye
接続されました。
SCOTT> select * from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - Production
PL/SQL Release 11.1.0.6.0 - Production
CORE 11.1.0.6.0 Production
TNS for Linux: Version 11.1.0.6.0 - Production
NLSRTL Version 11.1.0.6.0 - Production

SCOTT>
SCOTT> alter session set nls_date_format = 'yyyy-mm-dd';

セッションが変更されました。

SCOTT> select sysdate + interval '10' day from dual;

SYSDATE+IN
----------
2009-02-03

SCOTT> select last_day(sysdate + interval '1' month) from dual;

LAST_DAY(S
----------
2009-02-28

SCOTT>
SCOTT> exit
Oracle Database 11g Enterprise Edition Release 11.1.0.6.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing optionsとの接続が切断されました。
G5Server:˜ discus$

お次は、MySQL Community Server 5.0.67 for MacOSX(PowerPC)版
MySQL5.0でもOracleと同様にlast_day()と期間リテラルだけで算出できます。こちらもOracle同様、余計なことを悩まなくてすみますね。(^^)

G5Server:˜ discus$ mysql --version
mysql Ver 14.12 Distrib 5.0.67, for apple-darwin8.11.0 (powerpc) using readline 5.1
G5Server:˜ discus$ mysql -u scott -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 177
Server version: 5.0.67 MySQL Community Server (GPL)

Type 'help;' or '\h' for help. Type '\c' to clear the buffer.

mysql> select curdate() + interval 10 day;
+-----------------------------+
| curdate() + interval 10 day |
+-----------------------------+
| 2009-02-03 |
+-----------------------------+
1 row in set (0.00 sec)

mysql> select last_day(curdate() + interval 1 month);
+----------------------------------------+
| last_day(curdate() + interval 1 month) |
+----------------------------------------+
| 2009-02-28 |
+----------------------------------------+
1 row in set (0.00 sec)

mysql>
mysql> exit
Bye
G5Server:˜ discus$

最後にPosgreSQL 7.4.9 for MacOSX(PowerPC)版
10日後は期間リテラルで単純に算出可能だが、OracleやMySQLとは異なりlast_day()のような関数が無い(マニュアルをみたけど該当する関数が見当たらない)ので翌々月1日の前日で算出してみた。

G5Server:˜ discus$ psql -U scott postgresql749
Password:
Welcome to psql 7.4.9, the PostgreSQL interactive terminal.

Type: \copyright for distribution terms
\h for help with SQL commands
\? for help on internal slash commands
\g or terminate with semicolon to execute query
\q to quit

postgresql749=#
postgresql749=# select version();
version
-------------------------------------------------------------------------------------------------------------------------
PostgreSQL 7.4.9 on powerpc-apple-darwin8.3.0, compiled by GCC gcc (GCC) 3.3 20030304 (Apple Computer, Inc. build 1809)
(1 row)

postgresql749=# select cast(current_date + interval '10 day' as date);
date
------------
2009-02-03
(1 row)

postgresql749=# select cast(to_date(to_char(current_date + interval'2 months','yyyymm')||'01','yyyymmdd') - interval '1 day' as date);
date
------------
2009-02-28
(1 row)


postgresql749=# \q
G5Server:˜ discus$


CachéではObjectScript(M言語)を使ったので脇に置いといて、他の3つのデータベースのSQLでは期間リテラル(interval)の書き方が微妙に異なる点は知っておいたほうがいいかも。



今日も息子は保育園でバイバイせず結構泣いてた、最近、保育園にくるとパパもママもSee Ya! といっていなくなってしまうことに気付いた模様。いずれ慣れるだろうけど。。

| | | コメント (0) | トラックバック (0)

2008年10月31日 (金)

MySQL User Conference Tokyo 2008(二日目)

今日はMySQL User Conference 2008の2日目に参加してきました。
(iPhone Tech Talkとバッディングしていて昨日は参加できなかったので)

その会場で、私が初めてMySQLとPostgreSQLを仕事として使った際にお世話になった方々と再会。お元気そうでなによりでした。(^^)

ところでココログさん最初はPostgreSQLだったのですね、全く知らなかった。しかも今はMySQLだということも知らなかったよ。。移行作業の経緯を知って、あ、あのとき、裏ではそんな事やっていたのか〜〜〜〜〜と、遠い目。

ココログさん(というかSix Apartさんかな)、お疲れさまでした。


Img_0108

懇親会会場では、みなさんお腹減っていたようで、あっという間に・・・・

Img_0110

近くに抽選会でサーバに当選した方が居たので目録だけ撮ってみました。

Img_0113


いつものように頂いたノベルティーはブログ de ノベルティにて。

| | | コメント (0) | トラックバック (0)

2008年10月23日 (木)

Mac de Caché というか MUMPS というか Objectscript か

Cachéはむか〜〜し、むか〜し日本DEC時代に関わっていたDSM-11やVAX/DSMようするにMUMPSを祖先に持つ。今ではSQL/トランザクション制御/ODBCもサポートしているというからOracle11gと他のデータベース間でOracle Generic Connectivityで遊ぶのも面白いかな・・・ということで試しにインストール。
そういえばCodezineで記事を書いている佐藤さんって日本DEC時代に担当していたディストリクトは違うけどDSM-11やVAX/DSMを担当されていた方だよな〜多分、随分前なので多分としか書けないけど。近いうちに確認できるだろうけど。(^^)


Cachéのéをタイプするためにフランス語タイプできるようにしちゃったし。 w

Cache_001

Cache_002

Cache_003

Cache_004

Cache_005

Cache_006

Cache_007

Cache_008

Cache_009

Cache_010

サポートされているプラットフォームの一覧をみるとPowerPC版MacOSXはTigerまでということになっている。
ちなみに、x86版MacOSXであれば最新版がダウンロードできるようだが、PowerPC版はダウンロードできないようだ。今回インストールしたのは一昨年にダウンロードしていたものなので1年半ぐらい前のバージョン。いつかは試そうと思いつついままで塩漬けだったわけです。
http://www.intersystems.com/cache/technology/product-tables/prodversion.html

無償版ダウンロードページは以下「但し、このシングルユーザライセンスは、評価・テストを目的としたもので商用アプリケーションの開発、販売、運用には使用できません。」とのこと。
http://www.intersystems.co.jp/cache/downloads/index.html

昔のMUMPS(M言語)の言語仕様しか覚えていないので暫しCaché Objectscriptのリファレンスを斜め読み。。イメージはそんなに変ってないか。。。ということでHello World!では面白くないのでMUMPS言語というか、M言語というか Caché ObjectscriptでFizz Buzzしてみた。
(新しいObjectscriptの文法でコーディングするならコマンドや慣習として省略形でコーディングすることが多かったMUMPSだけど、今は省略形は利用しないほうが読み易いよね、きっと。
MUMPSは習慣的に省略形のコマンドや関数でコーディングされているものが多かったから(現在でも省略形でコーディングする事が多いのかは知らない・・・・)、私が初めてMUMPSのコードを見たときは何じゃこれ! なんの記号? プログラムなのかこれ? と感じたことを思い出した。今回のコードも省略形使ってますが。www

MacOSXのTerminalを起動して。。。。(インストール後にはCachéが自動起動してる。。)
う〜〜〜〜ん、MUMPSの子孫だけどサンプルコード見るとJavaとかC的な文法もあるのね今のMUMPSじゃなくてObjectscriptは・・・今回は昔のMUMPSっぽく書いたけど。。

G5Server:˜ discus$ 
G5Server:˜ discus$ csession cache -U user

USER>

USER>f i=1:1:100 w $case(i#15,0:"FizzBuzz",:$case(i#3,0:"Fizz",:$case(i#5,0:"Buzz",:i))),!
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz

・・・・中略・・・・

89
FizzBuzz
91
92
Fizz
94
Buzz
Fizz
97
98
Fizz
Buzz

USER>
USER>halt
G5Server:~ discus$

ついでにシャットダウンしてみるか。。。

G5Server:~ discus$ 
G5Server:˜ discus$ sudo ccontrol stop cache
Password:

Cache Shutdown Status: 3:51 pm 19 Oct 2008

0 interactive jobs (Telnet/Lat)
0 background jobs (from job command)
0 Cache Direct server jobs
0 Cache Objects server jobs
0 CSP server jobs
0 ODBC server jobs
26 system jobs

Do you want to broadcast a message to anyone? No => No
Do you want to see the Cache status report? No => Yes

Cache System Status: 3:51 pm 19 Oct 2008
Process Device Namespace Routine CPU,Glob Pr User/Location
355 CONTROL 0,0 0
379 WRTDMN 227,23 0
380 GARCOL 0,0 0
381 JRNDMN 13830,141 0
389 EXPDMN 0,0 0
382 SLAVWD 7,126 0
385 SLAVWD 0,0 0
383 SLAVWD 0,0 0
388 SLAVWD 0,0 0
384 SLAVWD 0,0 0
387 SLAVWD 0,0 0
386 SLAVWD 0,0 0
419 /dev/null %SYS %SYS.Task 124096,23819 0 TASKMGR
398 /dev/null %SYS MONITOR 46080,3557 0
1838 /dev/ttyp1 %SYS SYS.Process 8256,1067 0 %System
400 /dev/null %SYS CLNDMN 704,47 0
401 /dev/null %SYS RECEIVE 90752,10111 0
402 /dev/null %SYS ECPWork 192,65 0
403 /dev/null %SYS ECPWork 192,64 0
404 /dev/null %SYS ECPWork 192,63 0
405 /dev/null %SYS ECPWork 192,63 0
406 /dev/null %SYS ECPWork 192,63 0
407 /dev/null %SYS ECPWork 192,63 0
408 /dev/null %SYS ECPWork 192,63 0
409 /dev/null %SYS ECPWork 192,63 0
1170 /dev/null %SYS %CSP.Daemon 12224,1290 0
411 |TCP|1972 %SYS %SYS.SERVER 192,65 0
416 /dev/null %SYS %MONAPP 61760,11240 0

2 user, 26 system, 32 mb global/1 mb routine cache

Do you want to broadcast a message to anyone? No => No
Do you want to see the Cache status report? No => No
Do you want to run the user defined shutdown routine? Yes => No
Are you ready for the system to halt? Yes => Yes

15:52:19 Shutting down Cache
15:52:20 Notifying Clients
15:52:20 No user shutdown routines to execute
15:52:20 Stopping User Jobs
15:52:20 Stopping Network Servers
15:52:21 Withdrawing from License Domain
15:52:21 Waiting for users to stop
15:52:21 Stopping Client Networking
15:52:21 Removing database locks
15:52:21 Updating Journal File
15:52:22 Waiting for database updates to complete
15:52:23 Database updates complete
15:52:23 Stopping System Jobs
15:52:27 Shutdown complete
G5Server:˜ discus$


ということで、あとはOracle Generic ConnectivityをOracle11gで試すときまでのお楽しみ・・・?!

| | | コメント (0) | トラックバック (0)

2008年10月10日 (金)

MySQL User Conference 2008

MySQL User Conference 2008が10月30日と31日に開催される。すでに事前受付サイトもオープンしている。ただ30日のiPhone関連セミナーとバッティングしてるんだよな〜。(iPhoneセミナーが受けられようならそちら優先ということで・・・。。なんで行きたいセミナーってバッティングすることが多いのかね。まったく・・・)

| | | コメント (0) | トラックバック (0)

2008年10月 1日 (水)

さて・・

Oracle11gMySQL5.0PostgreSQL8.3、(FireBird2.1もやるか)、それにOpenfiler2.3なども利用して旧リリースで試していたことを再度試しておこうかそろそろ。
たとえば、HeterogeneousRACのネタなど。まず、RACからやりますか..。

| | | コメント (0) | トラックバック (0)

2008年3月10日 (月)

Mac de Ruby on Rails - #9 - ClubDB2番外編

Mac で Oracleな私ですが、第37回 ClubDB2番外編!Ruby on Rails 入門へ行ってきました。

いや〜〜、株式会社万葉の大場さんのセミナー面白かったですね。Mac使ってたし(笑)。
予定があったのでセミナー後の食事会?には参加できませんでしたが、RoRなどDB2から脱線?したネタがあればまた参加したいと思います。XMLDBネタが近々あるようだが、それはそれで聞いてみたい気もする。。


ちなみに、DB2の知識は、DB2 UDB 5.2で止まってる。。はず、と言いつつDBマガジンの記事は読んでますよ。


今回仕入れたネタも使って遊んだ結果などはいずれ。。。

2008/3/15追記
そう言えば、このセミナーで頂いたDB2 9:pureXML overview and fast startの紹介を忘れていたので追記しておきます。 (^^;;;
IBMさんのサイトではPDF版やHTML版が公開されている。

Db2_9_purexml_overview

| | | コメント (0) | トラックバック (0)

2008年2月 5日 (火)

IBM Informix Dynamic Server Developer Edition for MAC OS X (Cheetah 2" Beta Download)

IBM Informix Dynamic Server for MacOSX("Cheetah 2" Beta Download)がダウンロードできるようになっていますね。

http://www.marketwire.com/mw/release.do?id=811175&sourceType=1
http://www-306.ibm.com/software/info/ids/index.jsp

これでDB2 UDB以外のメジャーな商用DBがMacOSX上でも動く事になりますね。
Oracle11g for MacOSXはどんな状況なんだろうなぁ実際のところ...

日本国内のサポートの有無に関係なくMacOSXで動作する商用データベース(ORDBMS/RDBMS/ODBMSに関係なく)を列挙しておく・・・

データベースMacOSXのバージョン備考
Oracle10g R1 EE/SE/SEONE?MacOSX(PPC) Panther / TIgerTigerでは10.1.0.5.0 patchsetが必要。
Sybase ASE 12.5.xMacOSX(PPC only?) Jaguar以上無償版あり
Caché 2007.1.MacOSX(PPC/Intel) Tiger無償版あり

注1)無償版と書きましたが商用利用などに制限のあるものもありますので詳細は各リンク先を参照してください。
注2)Oracle 10g XEはリリースされていないが、Oracle Mix(ユーザ登録が必要)ではOracle11g XE for MacOSX Leopardがあったらいいな〜なんて話もでている。

ちなみに、MacOSXのOracleに関して、Oracle Certification Matrixのページを見れば詳しい状況がわかります。
http://www.oracle.com/technology/support/metalink/index.html

3

4

| | | コメント (0) | トラックバック (0)

2008年1月22日 (火)

24(テレビドラマではないよ)

Wigitize

24時間で作られたドットコムサイト『Wigitize』でも取り上げられていたのでいろいろ覗いてみたついでにWidgetを作って貼付けてみた。元からあるココログの「最近の記事」と比べても見劣りしないでしょ。
記事にもあるように24時間でどのようにしてWigitizeを構築していったのか、プロセスが細かく書かれていて実に面白い。


ココログオリジナルの「最新の記事」(左)とWigitizeで作って少々加工した「最新の記事」(右)
9 8

あ、24時間で作るといえば、Wif2008の予選会も24時間で与えられたテーマのWebデザインを完成させるのが条件でしたね。予選の作品が公開されたようです。。。Wif2008ネタは別エントリで。

日本からは8チームエントリしているように見えるが実際には5チームとのこと。
Wif2008_preselect

| | | コメント (0) | トラックバック (0)

2008年1月17日 (木)

Sun が MySQLを買収

Sun、MySQLを買収

いや〜、驚きましたね!
PostgreSQLのサポートを提供しているSunですがMySQLを買収するとは。

InnoDBなどがOracleに買収されてしまい、なんとなくいやな雰囲気(Oracleさんも買収買収でバックマンになりはじめたねぇ〜と感じ始めていた)を感じていた今日このごろ。Sunによる買収なのでデータベースの世界もおもしろい状況になりそうな雰囲気を感じます。Falconの開発にも拍車がかかる事でしょうね。期待していますよ〜。:)

Oracle AppsLabのエントリでも書かれてますね - Acquisition Wednesday

| | | コメント (0) | トラックバック (0)

2008年1月13日 (日)

Mac de Ruby on Rails - #1

さて、ウチの奥さんから遅れること?年、rubyをやってみようかと思っていたんですが中々手が進まず、風邪をひいてデータベースを触っていないこの時期に少しでも進めてみようと思い立ち私のPowerBook G4で環境作り。
ただ元来データベース周りが得意分野なのでRubyそのものというよりRuby on Railsで遊ぶことに。。。
今のところはデータベースはSQLite3を利用する環境なのですが・・いずれはOracleと繋げる予定・・・。

というのも・・・

S/N Ratioより引用

先週開催されていたオラクルの年次カンファレンス「Oracle OpenWorld 2007」の開始に合わせて、新サービス「Oracle Mix」のベータがローンチしました。Oracle Mixは、ソーシャル ネットワーク、アイデア共有、グループ コラボレーション、Q&Aフォーラムなどの機能を提供しています。

Oracle Mixは、Oracle Applications (オラクルの業務アプリケーション製品群) の開発チーム内のグループ「Oracle AppsLab」と、Martin Fowlerが所属していることでも有名なThoughtWorksが協力して開発したサービスです。

なんて事もあり興味を持ったとうのもあるんですけどね。

ところで、Oracle AppsLabといえば・・・以前私のエントリがPingback(かな?)でAppsLabのエントリにトラックバックされていたっけ。。。(^^;;;

ちなみに、Oracle Mixに登録しちゃってます。。:)
Oraclemix

さて、前置きはこれくらいにして本題です。。

奥さんのMacBook Proは既にMac OS X LeopardなのでなにもしなくてもRuby on Railsは利用できるんですが、私のPowerBook G4はまだMac OS X Leopardへアップデートしてないんですよいろんな都合で。なのでインストール作業から・・・・・

RubyもRuby on Railsも初めてなので、ググったり奥さんが買っていた書籍などを参考に・・・PowerBook G4 1Ghz(1GB ram) MacOSX Tiger 10.4.11へRuby on Railsをインストールしてみた。

MacPortsがあると便利とのことなのでまずは、MacPorts 1.6.0のTiger版をダウンロード。あとはMacPorts-1.6.0-10.4-Tiger.dmgをダブルクリック、さらにMacPorts-1.6.0.pkgをダブルクリックしてインストールすればOK。
Macport


MacPortsなどは、/opt/local以下にインストールされる。(XCodeは事前にインストールしておくべし。)

Last login: Sat Jan 12 20:01:35 on ttyp1
Welcome to Darwin!
pb17:˜ discus$ cd /opt/local/bin
pb17:/opt/local/bin discus$ ls
daemondo port portf portindex portmirror
pb17:/opt/local/bin discus $ port -v
MacPorts 1.600
Entering interactive mode... ("help" for help, "quit" to quit)
[local/bin] > quit
Goodbye
pb17:/opt/local/bin discus $


次にMacPortsのアップデート。

pb17:/opt/local/bin discus$ sudo ./port -v selfupdate
Password:
Synchronizing local ports tree from rsync://rsync.macports.org/release/ports/
receiving file list ... done
./
aqua/Affiche/
aqua/AppKiDo/
aqua/AquaLess/
aqua/ArpSpyX/

・・・・中略・・・・

zope/zope-zopezen/
zope/zope-zphotoslides/
zope/zope-zphotoslides/files/
zope/zope-zsyncer/

sent 74 bytes received 291810 bytes 20129.93 bytes/sec
total size is 16241925 speedup is 55.65

MacPorts base version 1.600 installed
receiving file list ... done

sent 73 bytes received 6617 bytes 2676.00 bytes/sec
total size is 3962384 speedup is 592.28

Downloaded MacPorts base version 1.600

The MacPorts installation is not outdated and so was not updated
selfupdate done!
pb17:/opt/local/bin discus$
pb17:/opt/local/bin discus$ ruby -v
ruby 1.8.2 (2004-12-25) [powerpc-darwin8.0]

MacOSX Tiger 10.4には、ruby 1.8.2は既にインストールされている。


環境変数 $PATHに/opt/local/binを追加。

pb17:/opt/local/bin discus $ echo $PATH
/opt/local/bin:/usr/local/mysql/bin:/bin:/sbin:/usr/bin:/usr/sbin

pb17:/opt/local/bin discus $ cd


次にRubyGemsパッケージ管理システムをMacPorts1.6を利用してインストール。インストール後には、Rubyも1.8.6へ更新されている。

pb17:˜ discus$ sudo port install rb-rubygems
Password:
---> Fetching expat
---> Attempting to fetch expat-2.0.1.tar.gz from http://downloads.sourceforge.net/expat
---> Verifying checksum(s) for expat

・・・・中略・・・・

---> Installing rb-rubygems 0.9.4_0
---> Activating rb-rubygems 0.9.4_0
---> Cleaning rb-rubygems
pb17:˜ discus$ ruby --version
ruby 1.8.6 (2007-09-23 patchlevel 110) [powerpc-darwin8.11.0]
pb17:˜ discus$


そしてRubyGemsでrailsをインストールしようとしたが、以下のようなエラーが発生して全くうまくいかない。。困った〜〜。

pb17:˜ discus$ sudo gem install rails --include-dependencies
Password:
/opt/local/lib/ruby/vendor_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require': no such file to load -- sources (LoadError)
from /opt/local/lib/ruby/vendor_ruby/1.8/rubygems/custom_require.rb:27:in `require'
from /opt/local/lib/ruby/vendor_ruby/1.8/rubygems/source_info_cache.rb:6
from /opt/local/lib/ruby/vendor_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
from /opt/local/lib/ruby/vendor_ruby/1.8/rubygems/custom_require.rb:27:in `require'
from /opt/local/lib/ruby/vendor_ruby/1.8/rubygems/remote_installer.rb:12
from /opt/local/lib/ruby/vendor_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
from /opt/local/lib/ruby/vendor_ruby/1.8/rubygems/custom_require.rb:27:in `require'
from /opt/local/lib/ruby/vendor_ruby/1.8/rubygems.rb:112:in `manage_gems'
from /opt/local/bin/gem:10
pb17:˜ discus$


前述のエラーメッセージでググってみたら「ソースからインストールするとうまくいくよ!」という内容のエントリを発見。
/opt以下削除してから再度MacPortsのインストール及びアップデートからやり直し。(尚、$PATH環境変数へは。/opt/local/binは設定したまま)

pb17:˜ discus$ sudo port -v selfupdate
Password:
Synchronizing local ports tree from rsync://rsync.macports.org/release/ports/
receiving file list ... done

sent 74 bytes received 291834 bytes 11447.37 bytes/sec
total size is 16241915 speedup is 55.64

MacPorts base version 1.600 installed
receiving file list ... done

sent 73 bytes received 6621 bytes 4462.67 bytes/sec
total size is 3962384 speedup is 591.93

Downloaded MacPorts base version 1.600

The MacPorts installation is not outdated and so was not updated
selfupdate done!


次に、RubyGems 0.9.4をインストール(1.0.1がリリースされていたが敢て、古いバージョンをインストール)
curlを使わなくてもいいんですが・・・とりあえずコマンドで作業を進めて行きます。(このエントリの後半で1.0.1へアップデートします。)

pb17:˜ discus$ curl -L -O http://rubyforge.org/frs/download.php/20989/rubygems-0.9.4.tgz
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 200k 100 200k 0 0 49807 0 0:00:04 0:00:04 --:--:-- 81744

pb17:˜ discus$ tar zxvf rubygems-0.9.4.tgz
rubygems-0.9.4/
rubygems-0.9.4/.document
rubygems-0.9.4/bin/
rubygems-0.9.4/bin/gem

・・・・中略・・・・

rubygems-0.9.4/test/user_capture.rb
rubygems-0.9.4/test/yaml_data.rb
rubygems-0.9.4/TODO
pb17:˜ discus$


解凍したら setup.rbを実行してRubyGems 0.9.4をインストール。

pb17:˜ discus$ cd rubygems-0.9.4
pb17:˜/rubygems-0.9.4 discus$ sudo ruby ./setup.rb
Password:
---> bin
<--- bin
---> lib
---> lib/rbconfig
<--- lib/rbconfig

・・・・中略・・・・

<--- lib
Successfully built RubyGem
Name: sources
Version: 0.0.1
File: sources-0.0.1.gem
Removing old RubyGems RDoc and ri...
Installing rubygems-0.9.4 ri...
Installing rubygems-0.9.4 rdoc...

As of RubyGems 0.8.0, library stubs are no longer needed.
Searching $LOAD_PATH for stubs to optionally delete (may take a while)...
...done.
No library stubs found.

pb17:˜/rubygems-0.9.4 discus$


ソースからインストールしたRubyGemsを使ってrailsをインストール・・・

pb17:˜/rubygems-0.9.4 discus$ sudo gem install rails --include-dependencies
Bulk updating Gem source index for: http://gems.rubyforge.org
Successfully installed rails-2.0.2
Successfully installed rake-0.8.0
Successfully installed activesupport-2.0.2

・・・・中略・・・・

Installing RDoc documentation for actionpack-2.0.2...
Installing RDoc documentation for actionmailer-2.0.2...
Installing RDoc documentation for activeresource-2.0.2...
pb17:˜/rubygems-0.9.4 discus$ rails -v
Rails 2.0.2
pb17:˜/rubygems-0.9.4 discus$ cd
うまくいった〜〜。パチパチ。


ついでにSQLite3もインストール(こちらはMacPortsでインストールできた。)

pb17:˜ discus$ sudo port install sqlite3
---> Fetching gawk
---> Attempting to fetch gawk-3.1.5.tar.bz2 from http://ftp.gnu.org/gnu/gawk

・・・・中略・・・・

---> Installing sqlite3 3.5.4_0+darwin_8
---> Activating sqlite3 3.5.4_0+darwin_8
---> Cleaning sqlite3
pb17:˜ discus$


さらにSQLite3インターフェースのインストール

pb17:˜ discus$ sudo port install rb-sqlite3
Password:
---> Fetching rb-sqlite3
---> Attempting to fetch sqlite3-ruby-1.2.1.tar.bz2 from http://rubyforge.org/frs/download.php/17096/
---> Verifying checksum(s) for rb-sqlite3
---> Extracting rb-sqlite3
---> Configuring rb-sqlite3
---> Building rb-sqlite3 with target setup
---> Staging rb-sqlite3 into destroot
---> Installing rb-sqlite3 1.2.1_0
---> Activating rb-sqlite3 1.2.1_0
---> Cleaning rb-sqlite3
pb17:˜ discus$ sudo gem install sqlite3-ruby
Select which gem to install for your platform (powerpc-darwin8.11.0)
1. sqlite3-ruby 1.2.1 (mswin32)
2. sqlite3-ruby 1.2.1 (ruby)
3. sqlite3-ruby 1.2.0 (mswin32)
4. sqlite3-ruby 1.2.0 (ruby)
5. Skip this gem
6. Cancel installation
> 2
Building native extensions. This could take a while...
Successfully installed sqlite3-ruby-1.2.1
Installing ri documentation for sqlite3-ruby-1.2.1...
Installing RDoc documentation for sqlite3-ruby-1.2.1...
pb17:˜ discus$


インストールできたのでrailsアプリケーションの作成準備。


pb17:˜ discus$ cd /Volumes/Repository
pb17:/Volumes/Repository discus$ mkdir discus
pb17:/Volumes/Repository discus$ cd discus
pb17:/Volumes/Repository/discus discus$ rails rails-demo
create
create app/controllers
create app/helpers
create app/models
create app/views/layouts

・・・・中略・・・・

create doc/README_FOR_APP
create log/server.log
create log/production.log
create log/development.log
create log/test.log
pb17:/Volumes/Repository/discus discus$
pb17:/Volumes/Repository/discus/rails-demo discus$ script/server
=> Booting WEBrick...
=> Rails application started on http://0.0.0.0:3000
=> Ctrl-C to shutdown server; call with --help for options
[2008-01-13 22:59:27] INFO WEBrick 1.3.1
[2008-01-13 22:59:27] INFO ruby 1.8.6 (2007-09-23) [powerpc-darwin8.11.0]
[2008-01-13 22:59:27] INFO WEBrick::HTTPServer#start: pid=15815 port=3000
127.0.0.1 - - [13/Jan/2008:23:01:02 JST] "GET / HTTP/1.1" 200 7557-
-> /
127.0.0.1 - - [13/Jan/2008:23:01:02 JST] "GET /favicon.ico HTTP/1.1" 200 0
http://localhost:3000/ -> /favicon.ico
127.0.0.1 - - [13/Jan/2008:23:01:02 JST] "GET /javascripts/prototype.js HTTP/1.1" 200 125605
http://localhost:3000/ -> /javascripts/prototype.js
127.0.0.1 - - [13/Jan/2008:23:01:02 JST] "GET /javascripts/effects.js HTTP/1.1" 200 38916
http://localhost:3000/ -> /javascripts/effects.js
127.0.0.1 - - [13/Jan/2008:23:01:02 JST] "GET /images/rails.png HTTP/1.1" 200 1787
http://localhost:3000/ -> /images/rails.png
127.0.0.1 - - [13/Jan/2008:23:01:33 JST] "GET /rails/info/properties HTTP/1.1" 200 920
http://localhost:3000/ -> /rails/info/properties
^C[2008-01-13 23:02:09] INFO going to shutdown ...
[2008-01-13 23:02:09] INFO WEBrick::HTTPServer#start done.
pb17:/Volumes/Repository/discus/rails-demo discus$

なんとかここまでできました〜〜。
Ror_demo2


最後に、はじめにも書いていましたがgemsを最新版にアップデートしておきます。

pb17:˜ discus$ gem -v
0.9.4
pb17:˜ discus$ sudo gem update --system
Updating RubyGems...
Attempting remote update of rubygems-update
Successfully installed rubygems-update-1.0.1
Updating version of RubyGems to 1.0.1
Installing RubyGems 1.0.1
install -c -m 0644 rbconfig/datadir.rb /opt/local/lib/ruby/site_ruby/1.8/rbconfig/datadir.rb
install -c -m 0644 rubygems/builder.rb /opt/local/lib/ruby/site_ruby/1.8/rubygems/builder.rb
install -c -m 0644 rubygems/command.rb /opt/local/lib/ruby/site_ruby/1.8/rubygems/command.rb
install -c -m 0644 rubygems/command_manager.rb /opt/local/lib/ruby/site_ruby/1.8/rubygems/command_manager.rb

・・・・中略・・・・

rm -rf /opt/local/lib/ruby/gems/1.8/doc/rubygems-0.9.4
Installing rubygems-1.0.1 ri into /opt/local/lib/ruby/gems/1.8/doc/rubygems-1.0.1/ri...
Installing rubygems-1.0.1 rdoc into /opt/local/lib/ruby/gems/1.8/doc/rubygems-1.0.1/rdoc...
As of RubyGems 0.8.0, library stubs are no longer needed.
Searching $LOAD_PATH for stubs to optionally delete (may take a while)...
...done.
No library stubs found.
RubyGems system software updated
pb17:˜ discus$ gem -v
1.0.1
pb17:˜ discus$

これでRubyGemsのアップデートもなんとか完了〜〜。ホッ。この続きは暇を見て調べながらやって行きましょうかね・・・・。


参考にしたサイトや書籍など。。
http://feeds.japan.cnet.com/~r/cnet/blog/kenn/~3/761095/
http://www.takezou.com/archives/2007/05/ror_install_on.html
http://i.loveruby.net/ja/projects/setup/doc/usage.html
http://mikilab.doshisha.ac.jp/dia/research/report/2006/1014/002/report20061014002.html
http://lapangan.net/darwinports/index.php?HowTo%2FUseMacPorts
http://rubyforge.org/
http://www.rubyonrails.org/down

| | | コメント (0) | トラックバック (0)

2007年12月30日 (日)

MyMiniCity で MySQL Error

今現在私のMyMiniCity - DISCUS HAMBURGにはビルも立ち村のような雰囲気からは随分変化してきた。
左のサイドバーに貼付けてあるのが今現在(30日の10時頃)の状況。

ところで今日アクセスした際、以下のようなMySQLの同時接続数オーバーが発生していた。
MyMiniCityだけに利用しているデータベースはMySQLなんですねぇ。

Myminicity_mysql_error

| | | コメント (0) | トラックバック (0)

2007年12月12日 (水)

大規模Web サイトでのMySQL導入方法および事例紹介」セミナー

20071204001

先週のことだが、大規模Web サイトでのMySQL導入方法および事例紹介」セミナーが六本木にあるスウェーデン大使館内 オーデトリアムで開催されるということで行ってきた。MySQL Conference 2007の内容と多少重複する内容もあったが、DBマガジンでおなじみのMySQL 株式会社 松信 嘉範氏のセッションは興味深い内容だった。

会場となったスウェーデン大使館のオーデトリアムだけでは足りず、ロビーにも椅子とモニターが用意されていたが会場自体が小さいので全体で100名程度で満席となっていた。(オーデトリアム内で立ち見だったし。)

| | | コメント (0) | トラックバック (0)

2007年11月 8日 (木)

Sun Tech Days 2007 in Tokyo - Last Day

やはり、気になったので、有楽町の無印での買い物ついでにSun Tech Days 2007 in Tokyoの最終日の最終セッションへ。

MacOSX Leopardへも組み込まれているDtrace関連と昨日は全く聞けなかったPostgraSQL関連セッション。

Solarisはないので、LeopardのbashからMacOSX 10.5 Leopardで確認だけ。。ちゃんと入ってますDtrace

Dtrace_macosx_leopard

その他、いろいろ試してみたいのだが、それは後日時間を取ってやってみようかと。。。予定は未定。

| | | コメント (0) | トラックバック (0)

2007年9月13日 (木)

MySQL Users Conference Japan 2007 #2

MySQL Users Conference Japan 2007の最終日です。

コンファレンスの内容などは、他方々のブログ等のエントリで十分なので特に書く事もないのだが、例によって参加したセッションの一こまを。

● パネルディスカッション: MySQL の独自性と優位点

Kaj Arno, VP Community, MySQL AB
Patrick Bolduan, MTV Japan (Customer)
Kai Seidler, XAMPP (Community Member)
Marten Mickos, CEO, MySQL AB
Michael "Monty" Widenius, MySQL Fellow and Co-founder, MySQL AB
Brian Aker, Director of Architecture, MySQL AB

Cimg6581

● MySQL の Plugin API 詳細解説(ストレージエンジン自作入門)

Brian Aker  - Director of Architecture, MySQL AB
Cimg6582

● MySQL Cluster 入門

Stewart Smith - Cluster Developer, MySQL AB
Cimg6585

● MySQL Cluster の詳細解説

Stewart Smith - Cluster Developer, MySQL AB
Cimg6586

● MySQL 5.1の詳細解説

Brian Aker - Stewart Smith
Cimg6587

● MySQL テクニカルケーススタディ(海外事例解説)

Jimmy Guerrero - Product Manager for MySQL Cluster, MySQL AB
Cimg6588

● レセプション

今日はこの後、しっかりと夕食を食べることになっているので、軽く摘んでおきました。(^^
ワインやビールもありましたが何せ車なのでウーロンだけ〜。
レセプションの最後に抽選があったんですけど、当たっちゃいました。くじ運悪い私が!。
頂いたものは後日、ブログ de ノベルティへ。

Cimg6594

20070912001 20070912002 20070912003

スーツよりジーンズな方が多いのは、それだけで楽しかったりして。

あ、忘れるところだったが、Q&Aで、MySQLの storage engineとしてDB2を利用できるようにするという話題に関しても少々触れていたましたねぇ。今後どうなるんでしょうねぇ。



2007/9/13追記
セッションで使用したプレゼン内容は、あとで公開されるようなことを言っていましたね。そういえば。
ということで、セッションの資料が公開されたらリンクを追加する予定。

以下のエントリは詳細なメモが記載されてますね (^^;。
http://d.hatena.ne.jp/akiyan/20070911

従業員用食堂か〜〜、気付かなかったよ〜。 1200円も払ってまずい煮込みハンバーグ+マッシュポテトだったよ。(><)
http://nonn-et-twk.net/twk/node/93

| | | コメント (0) | トラックバック (0)

2007年9月11日 (火)

MySQL Users Conference Japan 2007 #1

え〜〜っ。またまた、オラクル以外のネタ。 MySQL Users Conference Japan 2007に来ています。
(Generic ConnectivitiyネタでもMySQLはやってますが、なにせ、4.x及び、4.1なのでね。。。いずれ、5.x系のMySQLと10g R1 又は、11g R1でGeneric Connectivityネタもやりたいし。。。MacOSX版のOracle11gがリリースされればの話ですが。。)

Mysqlucjapan2007

Cimg6560

ということで、本日参加したセッションは、

● MySQL高可用性ソリューションの概要

Overview of MySQL HA solutions
- Jimmy Guerrero (Product Manager for MySQL Cluster, MySQL AB)

● 社内外の開発者が参加するMySQLの開発モデル

MySQL architecture of Participation
- Kaj Arno (VP Community Relations, MySQL AB)

Cimg6564 Cimg6565

● MySQLパフォーマンスチューニング&ベンチマーク

Performance Tuning and Benchmarks
- Colin Charles (Community Relations Manager, APAC at MySQL AB)

Cimg6566

● Web 2.0に向けたMySQLアーキテクチャ

Web 2.0 and emerging web technologies
- Brian Aker (Director of architecture. MySQL AB)

Cimg6568

ちなみに、Brian Akerさんは、Mac使ってプレゼンしてましたね〜。

それに、ランチビュッフェも頂きました。。
Cimg6563 Cimg6562


MySQL 5.1.xのパーティショニングのタイプもOracleと同じようなタイプをサポートしているようなのでコンポジットパーティションで組み合わせる事ができるパーティショニングタイプなんかも調べておこうか。 そういえば、Oracle11gでは、コンポジットパーティションで利用できるパーティションタイプの組み合わせがかなり増えていたなぁ。

明日も楽しみじゃ。

| | | コメント (0) | トラックバック (0)

2007年6月24日 (日)

OSC 2007 .DB

今日は、Open Source Conference 2007 .DBに行ってきました。 結構な人数が来てましたね。

朝は寝坊したこともあり、10時からのセッションには間に合わず。。。 orz、
ということで、DBマガジンでもおなじみの増永良文氏のセッションなど午後からのものを中心に。。

 


Cimg4826 Cimg4834

頂いたノベルティは、こちら。

| | | コメント (0) | トラックバック (0)

2006年11月 1日 (水)

Mac De Oracle - Oracle以外のDB

ひさびさに、Mac De Oracle以外のデータベースネタを1つ。

InterSystemsのCache 5.2.0.32.9.0のシングルユーザ版はフル機能で無料
最近は、Oracle10g XEなども無料だ。ただ、Oracle10g XEには、MacOSX版がないのだが、Cache 5.2には、MacOSX版も用意されている。

ちなみに、
MacOSX版はないが、IBM DB2 express-CというDB2の無料版もある。

| | | コメント (0) | トラックバック (0)

2006年5月27日 (土)

Mac De Mac De Oracle Heterogeneous! #80

久々のGeneric Connectivityネタです

今回は、Firebird 1.5と Heterogeneous! 。 ただ、ODBCドライバに影響されやすい
Generic Connectivityなので、Firebird_ODBC_1.2.0.69-Win32だと問題があるようだ。

踏み台にするWindowsには、Oracle10g EE R2を利用した。前回までは、Oracle10g EE R1。

踏み台側の環境は以下。
Windows XP Professional SP2
  Firebird V1.5.3.4870 for Windows
  Firebird_ODBC_1.2.0.69-Win32
 
  Oracle10g EE R2 10.2.0.1.0 for Windows

Mac側は以前の記事を参考にしてほしい。

1.ODBC

システムDSN
DSN:
firebird_windows

ここがポイント!
For a Windows server:
servername:DriveLetter:¥filesystem-path¥database-file

という形式で指定しないとデータベースを 見つけられない。

以下のようにFirebirdのサンプルデータベースを指定した。
Database:
catfish:C:¥Program Files¥Firebird¥Firebird_1_5¥examples¥EMPLOYEE.FDB

ユーザ名とパスワードはサンプルデータベースのユーザとパスワードを指定した。

Odbc

2. init.ora

initfirebird_windows.ora

#
# HS init parameters
#
HS_FDS_CONNECT_INFO = firebird_windows
HS_FDS_TRACE_LEVEL = off
HS_FDS_SHAREABLE_NAME = C:¥WINNT¥system32¥IscDbc.dll

3.listener.ora

SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(SID_NAME = PLSExtProc)
(ORACLE_HOME = E:¥oracle¥product¥10.2.0¥catfish)
(PROGRAM = extproc)
)

(SID_DESC =
(SID_NAME = mysqldb4026_windows)
(ORACLE_HOME = E:¥oracle¥product¥10.2.0¥catfish)
(PROGRAM = hsodbc)
)

(SID_DESC =
(SID_NAME = firebird_windows)
(ORACLE_HOME = E:¥oracle¥product¥10.2.0¥catfish)

(PROGRAM = hsodbc)
)
)

LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))
(ADDRESS = (PROTOCOL = TCP)(HOST = catfish)(PORT = 1521))
)
)

4.tnsnames.ora

FIREBIRD_WIN =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = catfish)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SID = firebird_windows)
)
(HS = OK)
)

MYSQL4026_WIN =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = catfish)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SID = mysql4026_windows)
)
(HS = OK)
)

5. SQL*Plusから

以下のデータベースリンクを作成(パブリックデータベースリンクでもOK)
create database link firebird_win
connect to "SYSDBA" identified by "masterkey" using 'FIREBIRD_WIN';

Oracle10g R1では、指定したデータベースリンク名に一致する
データベースリンク名を作成することができたのだが、
Oracle10g R2では、.REGRESS.RDBMS.DEV.US.ORACLE.COMという
ドメイン名がご丁寧に付加される。(悪さはしていない模様。)

SQL> select db_link from user_db_links;

DB_LINK
---------------------------------------------------
FIREBIRD_WIN.REGRESS.RDBMS.DEV.US.ORACLE.COM
MYSQL4026_WIN.REGRESS.RDBMS.DEV.US.ORACLE.COM

SQL>

ディクショナリビューは問題なく問い合わせられる。が・・・

SQL> select table_name from user_tables@firebird_win;

TABLE_NAME
--------------------------------------------------------------

RDB$CHARACTER_SETS
RDB$CHECK_CONSTRAINTS
RDB$COLLATIONS
RDB$DATABASE

中略

DEPARTMENT
EMP
EMPLOYEE
EMPLOYEE_PROJECT
FISHES
JOB
PROJECT
PROJ_DEPT_BUDGET
SALARY_HISTORY
SALES

44行が選択されました。

SQL>
SQL>

一般の表では、文字型の表示がだめ。
(エンコーディング関連で逃げられるものなのか・・・???)

ODBCドライバ側の問題なのだろうかね。(可能性としては高そう)

SQL> select * from "FISHES"@firebird_win;

ID NAME
---------- ---------------------------------------------------
1 discus
2 atfish
3 on tetra

SQL>
SQL> insert into "FISHES"@firebird_win values(4,'guppy');

1行が作成されました。

SQL> commit;

コミットが完了しました。

SQL> select * from "FISHES"@firebird_win;

ID NAME
---------- -----------------------------------------------------------
1 discus
2 atfish
3 on tetragu
4 py

SQL>

Firebirdの isqlから fishes表を問合せた結果をみると
Oracle側から insertしたデータでも正しく問い合わせられる。

SQL> select * from fishes;

ID NAME
============ ==========

1 discus
2 catfish
3 neon tetra
4 guppy

SQL>

と現時点ではこんな感じなので、FirebirdとHeterogeneous! ネタはいずれまた。
今回は、Firebird_ODBC_1.2.0.69-Win32 というODBCドライバを利用したが
v2.0のODBCドライバもリリースされているようなので時間があったら 
ODBCドライバ v2.0でも試してみましょうかね。

尚、この内容は OTN-Jの掲示板FirebirdへのODBC接続に投稿したものとほぼ同じ内容です。 

| | | コメント (0) | トラックバック (0)

2006年3月28日 (火)

Mac De Oracle Heterogeneous! #79

前回のつづき

Generic Connectivyty経由でMySQL4.0.x、MySQL4.1.13aの文字型にアクセス最終回

この検証でそれなりにネタは仕入れる事ができたので、この辺りでGeneric Connectivityは一旦終了する。

=========まとめ=======

利用している MyODBCドライバなどはこちら

Generic Connectivityの文字型マッピング
MySQL Oracle10g R1 Generic Connectivityでの利用 備 考
サイズ binary属性 文字長セマンティクス version サイズ 文字長セマンティクス
char型 20 -- バイト 4.0.25 char型 20 バイト

問合せ、登録、更新とも問題ないのだが、MySQL側でbinary属性が指定されていない場合には、DMLの書き方により、リモートソートが実行され、英字の大文字小文字が区別されなかったり、nullや空文字は、昇順ソートの場合先頭に置かれる。検証では、リモートマップされるクエリをインラインビューに書き換え、そのインラインビューに対して、NO_MERGEヒントを付加することで回避することができた。Oracleは空文字をnullとして扱うので、その点には注意。

定義したサイズを超える文字列を登録した場合には、エラーとなる。但し、char(20)まででしか確認していない。データディクショナリで確認したところ、char(255)では、MySQL側がバイトセマンティクスであるはずなのに、Oracle側では文字セマンティクスで、32512文字とマッピングされている。今回の検証ではこの件については深く検証していないので要注意。

binary バイト
255 -- バイト 32512 文字
binary 文字
20 -- 文字 4.1.13a char型 40 バイト

問合せ、登録、更新とも問題ないのだが、MySQL側でbinary属性が指定されていない場合には、DMLの書き方により、リモートソートが実行され、英字の大文字小文字が区別されなかったり、nullや空文字は、昇順ソートの場合先頭に置かれる。検証では、リモートマップされるクエリをインラインビューに書き換え、そのインラインビューに対して、NO_MERGEヒントを付加することで回避することができた。Oracleは空文字をnullとして扱うので、その点には注意。

定義したサイズを超える文字列を登録した場合には、エラーとなる。但し、char(20)まででしか確認していない。データディクショナリで確認したところ、char(255)では、MySQL側がバイトセマンティクスであるはずなのに、Oracle側では文字セマンティクスで、32256文字とマッピングされ、MySQL4.0.25の場合とより多少少ない。今回の検証ではこの件については深く検証していないので要注意。

binary バイト
255 -- 文字 varchar2型 32256 文字
binary 文字
127 -- 文字 char型 32256 文字

char(127)はSJISで254バイトのchar(254)でなく、なんと、char(32256 char)としてマッピングされている。登録に関しては未テスト。

128 -- 文字 varchar2型 256 バイト char(255)とchar(128)の差からは想像できない、varchar2(32256 char)とvarchar2(256)というマッピングの差があるので要注意。
varchar型 20 -- バイト 4.0.25 varchar2型 20 バイト

問合せ、登録、更新とも問題ないのだが、MySQL側でbinary属性が指定されていない場合には、DMLの書き方により、リモートソートが実行され、英字の大文字小文字が区別されなかったり、nullや空文字は、昇順ソートの場合先頭に置かれる。検証では、リモートマップされるクエリをインラインビューに書き換え、そのインラインビューに対して、NO_MERGEヒントを付加することで回避することができた。Oracleは空文字をnullとして扱うので、その点には注意。

定義したサイズを超える文字列を登録した場合には、エラーとなる。但し、varchar(20)まででしか確認していない。データディクショナリで確認したところ、varchar(255)では、MySQL側がバイトセマンティクスであるはずなのに、Oracle側では文字セマンティクスで、32512文字とマッピングされている。今回の検証ではこの件については深く検証していないので要注意。

binary バイト
255 -- バイト varchar2型 32512 文字
binary 文字
20 -- 文字 4.1.13a varchar2型 40 バイト

問合せ、登録、更新とも問題ないのだが、MySQL側でbinary属性が指定されていない場合には、DMLの書き方により、リモートソートが実行され、英字の大文字小文字が区別されなかったり、nullや空文字は、昇順ソートの場合先頭に置かれる。検証では、リモートマップされるクエリをインラインビューに書き換え、そのインラインビューに対して、NO_MERGEヒントを付加することで回避することができた。Oracleは空文字をnullとして扱うので、その点には注意。

定義したサイズを超える文字列を登録した場合には、エラーとなる。但し、varchar(20)まででしか確認していない。データディクショナリで確認したところ、varchar(255)では、MySQL側がバイトセマンティクスであるはずなのに、Oracle側では文字セマンティクスで、32256文字とマッピングされ、MySQL4.0.25の場合とより多少少ない。今回の検証ではこの件については深く検証していないので要注意。

binary バイト
255 -- 文字 varchar2型 32256 文字
binary
256 -- 文字 long型 -- バイト × varchar(256)を超えるとlong型にマッピングされてしまうので、tinytext型、text型と同じ扱いになる。binary属性が付いていれば、tinyblob型やblob型と同じ扱いになる。
tinytext型 -- -- バイト 4.0.25 long型 -- バイト × tinytext型の最大サイズは255バイト。登録、更新は可能なのだが、long型にマッピングされているためほとんどの関数は利用できない。ソートは未確認だが、binary属性の無いchar型又は、varchar型と同じであると考えている。また、問合せについて、この検証ではまったく問い合わせることができなかったため、Generic Connectivity経由での利用は諦めたほうがよいと思われる。(ODBCドライバなどを替えれば動作する可能せもあるだろうが、その検証にかかるコストも考慮する必要あり。)Oracleは空文字をnullとして扱うので注意。
-- -- バイト 4.1.13a long型 -- バイト
tinyblob型 -- -- バイト 4.0.25 long raw型 -- バイト × tinyblob型の最大サイズは255バイト。登録、更新は可能なのだが、long raw型にマッピングされているためほとんどの関数は利用できない。ソートは未確認だが、binary属性のchar型又は、varchar型と同じであると考えている。また、問合せに関して、この検証ではまったく問い合わせることができなかったため、Generic Connectivity経由での利用は諦めたほうがよいと思われる。(ODBCドライバなどを替えれば動作する可能せもあるだろうが、その検証にかかるコストも考慮する必要あり。)Oracleは空文字をnullとして扱うので注意。
-- -- バイト 4.1.13a long raw型 -- バイト
text型 -- -- バイト 4.0.25 long型 -- バイト × text型の最大サイズは65535バイト。登録、更新は可能なのだが、long型にマッピングされているためほとんどの関数は利用できない。ソートは未確認だが、binary属性の無いchar型又は、varchar型と同じであると考えている。また、問合せに関しては、この検証ではまったく問い合わせることができなかったため、Generic Connectivity経由での利用は諦めたほうがよいと思われる。(ODBCドライバなどを替えれば動作する可能せもあるだろうが、その検証にかかるコストも考慮する必要あり。)Oracleは空文字をnullとして扱うので注意。
-- -- バイト 4.1.13a long型 -- バイト
blob型 -- -- バイト 4.0.25 long raw型 -- バイト × blob型の最大サイズは65535バイト。登録、更新は可能なのだが、long raw型にマッピングされているためほとんどの関数は利用できない。ソートは未確認だが、binary属性のchar型又は、varchar型と同じであると考えている。また、問合せに関しては、この検証ではまったく問い合わせることができなかったため、Generic Connectivity経由での利用は諦めたほうがよいと思われる。(ODBCドライバなどを替えれば動作する可能せもあるだろうが、その検証にかかるコストも考慮する必要あり。)Oracleは空文字をnullとして扱うので注意。
-- -- バイト 4.1.13a long raw型 -- バイト


さて、久々にGeneric Connectivity以外のネタにしますかね。次回からは。

| | | コメント (0) | トラックバック (0)

2006年3月27日 (月)

Mac De Oracle Heterogeneous! #78

前回のつづき。Generic Connectivyty経由でMySQL4.1.13aの文字型にアクセス。八回目。

LONG型にマッピングされた列を問い合わせることができない! という挙動の調査#2

これまではDMLやDDLを利用してどの型にマッピングされているかを確認してきた。理由は、実際に問合せや更新が可能なのかという点も同時に確かめたかったからなのだが、データディクショナリを参照し、どの型にマッピングされているのか再確認してみることにした。

Generic Connectivityでも異機種データベース側のいくつかのディクショナリがマッピングされており、Oracleの user_tablesビューや、user_tab_columnsビューとして問い合わせることができる。
(尚、Genenric Connectivity経由で、利用できるディクショナリの解説は、マニュアル「Oracle Database Heterogeneous Connectivity 管理者ガイド」の付録Cを参照のこと。

ただ、今回は以下ようにな特殊な構成であるため、

gencon_blog_img1

各データディクショナリ毎にシノニムを作成しなければ、MacOSX上のOracle10gからそれらのディクショナリを参照することはできない。
(単に面倒だったからとうこともあるのだが)今回は、Window XP上のOracle10g上で各リモート表のシノニムに対して sql*plusの descコマンドで確認した。

以下、ディクショナリを確認した結果の型を見て、驚いたのだが、文字セマンティクスでマッピングされている箇所がある。MySQL4.0.25はバイトセマンティクスであるが、一部の型は、文字セマンティクスとしてマッピングされている。明らかに、これはまずいはず。

たとえば、 MySQL4.1.13aで、varchar(20)として定義した列は、VARCHAR2(40)とバイトセマンティクスでマッピングされているのだが、varchar(255)と定義してある列は、VARCHAR2(32256 CHAR)と文字セマンティクスでマッピングされていたのだ。
しかも、文字数も255でななく、32256なのである。

char(n)の nの値と文字セマンティクスか否かでキッチリ判断しているのかと考えていたのだが、それは”甘い”考えだったことに気付く。


SQL> desc varchar_test_mysql4113a_mac_sv;
名前 NULL? 型
----------------------------------------- -------- ----------------------------
id NOT NULL NUMBER(10)
r_varchar_20 VARCHAR2(40)
r_varchar_20_binary VARCHAR2(40)
r_varchar_255 VARCHAR2(32256 CHAR)
r_varchar_255_binary VARCHAR2(32256 CHAR)
r_tinytext LONG
r_tinyblob LONG RAW
r_text LONG
r_blob LONG RAW
r_varchar_256 LONG

マッピングを制御するようなパラメータは存在しないため、バイトセマンティクスになるのか、文字セマンティクスにマッピングするかを制御することはできない。

char_test_mysql4113a_mac_svというシノニムに対応するリモート表において、r_char_127は CHAR(127)、r_char_128は CHAR(128)と定義してあるのだが、Generic Connectivity経由でOracleにマッピングされた結果は、ご覧の通り。MySQL4.1.13aの r_char_127は、CHAR(32256 CHAR)と文字セマンティクス、 r_char_128は、VHARCHAR2(256)とバイトセマンティクスとなっている。

一方、PostgreSQL7.4.9の r_char_127 は、CHAR(127)、r_char_128 は、CHAR(128) と定義されているが、Generic Connectivity経由でOracleの型にマッピングされ、r_char_127は、CHAR(127)とバイトセマンティクス、r_char_128は、CHAR(128 CHAR)と文字セマンティクスとしてマッピングされてしまう。

Generic Connectity経由でアクセスする場合の一番の難所は数値型よりも、文字型のほうかもしれない。
256バイト未満の文字列しか扱っていない場合には、それほど気にしなくとも利用できる可能性は高いと思うが、それを超えるサイズを扱う場合(データベースのキャラクタセットも影響する)や、text型や、blob型を利用する場合には、事前に十分な評価テストは必須である。
(Oracle社とのサポート契約があれば、サポート等から関連する情報を入手したほうが良いだろう。開発コストや、運用保守コストなどを考えれば、Generic Connectivityより、Oracleに移行したほうがベターという結論になる場合もあるだろう。)


SQL> desc char_test_mysql4113a_mac_sv
名前 NULL? 型
----------------------------------------- -------- ----------------------------
id NOT NULL NUMBER(10)
r_char_20 CHAR(40)
r_char_20_binary CHAR(40)
r_char_255 VARCHAR2(32256 CHAR)
r_char_255_binary VARCHAR2(32256 CHAR)
r_char_127 CHAR(32256 CHAR)
r_char_128 VARCHAR2(256)

SQL> desc varchar_test_mysql4025_mac
名前 NULL? 型
----------------------------------------- -------- ----------------------------
id NOT NULL NUMBER(10)
r_varchar_20 VARCHAR2(20)
r_varchar_20_binary VARCHAR2(20)
r_varchar_255 VARCHAR2(32512 CHAR)
r_varchar_255_binary VARCHAR2(32512 CHAR)
r_tinytext LONG
r_tinyblob LONG RAW
r_text LONG
r_blob LONG RAW

SQL> desc char_test_mysql4025_mac
名前 NULL? 型
----------------------------------------- -------- ----------------------------
id NOT NULL NUMBER(10)
r_char_20 CHAR(20)
r_char_20_binary CHAR(20)
r_char_255 CHAR(32512 CHAR)
r_char_255_binary CHAR(32512 CHAR)

SQL> desc char_test_postgresql749_mac
名前 NULL? 型
----------------------------------------- -------- ----------------------------
id NUMBER(10)
r_char_20 CHAR(20)
r_char_2000 VARCHAR2(20480 CHAR)
r_char_2001 VARCHAR2(20736 CHAR)
r_varchar_20 VARCHAR2(20)
r_varchar_4000 VARCHAR2(8192 CHAR)
r_varchar_4001 LONG
r_text LONG
r_char_254 CHAR(32256 CHAR)
r_char_255 CHAR(32512 CHAR)
r_char_127 CHAR(127) 
r_char_128 CHAR(128 CHAR)
r_char_256 VARCHAR2(256)  

ところで、MySQLでは、LONGまたは、LONG RAW型にマッピングされていた列は全く問い合わせることができなかったのだが、PostgreSQLでは問い合わせることができる。

問題は、ODBC Driverなのかもしれないと疑い始めたのだが、Generic Connectivity側に何らかの問題があるという可能性を否定できる情報もない。。。

以下は、PostgreSQLで Generic Connectivity経由で long型にマッピングされる r_text列を問い合わせた結果(MySQLの場合と明らかに違う)


CORYDORAS> col r_text for a40
CORYDORAS> col r_varchar_4001 for a40
CORYDORAS> set linesize 132
CORYDORAS> set null "null"
CORYDORAS> l
1 select
2 "id","r_text","r_varchar_4001"
3 from
4 char_test_postgresql749_mac@oracle10g_win
5 where
6* "id" between 30 and 33

CORYDORAS> /

id r_text r_varchar_4001
---------- ---------------------------------------- ----------------------------------------
30 null null
31 null null
32 12345678901234567890 null
33 12345678901234567890 null

CORYDORAS>

今日はここまで、次回へづづく。

MySQL4.0.x、MySQL4.1.x、PostgreSQL7.4.9の基本的な型をGeneric Connecvitiy経由で Oracleかアクセスするというネタも、次回で一旦終了する。また確認したいことがあれば再開する予定である。

| | | コメント (0) | トラックバック (0)

2006年3月26日 (日)

Mac De Oracle Heterogeneous! #77

前回のつづき。Generic Connectivyty経由でMySQL4.1.13aの文字型にアクセス。七回目。

LONG型にマッピングされた列を問い合わせることができない!

7.TINYTEXT型、TINYBLOB型、TEXT型、BLOB型(追加検証)

以前簡単に触れた事なのだが、TINYTEXT型、TINYBLOB型、TEXT型、BLOB型は、 Generic Connectivity経由で、OracleのLONG型にマッピングされていると判断したのは以下のような結果からだった。
この判断間違っていたのか?・・・。


CORYDORAS> l
1* create table hoge as select "id","r_blob" from varchar_test_mysql4113a_mac_sv@oracle10g_win
CORYDORAS> /
create table hoge as select "id","r_blob" from varchar_test_mysql4113a_mac_sv@oracle10g_win
*
行1でエラーが発生しました。:
ORA-00997: LONGデータ型は使用できません。

CORYDORAS> l
1* create table hoge as select "id","r_tinytext" from varchar_test_mysql4113a_mac_sv@oracle10g_win
CORYDORAS> /
create table hoge as select "id","r_tinytext" from varchar_test_mysql4113a_mac_sv@oracle10g_win
*
行1でエラーが発生しました。:
ORA-00997: LONGデータ型は使用できません。

CORYDORAS> l
1* create table hoge as select "id","r_tinyblob" from varchar_test_mysql4113a_mac_sv@oracle10g_win
CORYDORAS> /
create table hoge as select "id","r_tinyblob" from varchar_test_mysql4113a_mac_sv@oracle10g_win
*
行1でエラーが発生しました。:
ORA-00997: LONGデータ型は使用できません。

CORYDORAS>

OracleのLONG型にマッピングされている、TINYTEXT型、TINYBLOB型、TEXT型、BLOB型の列には、Generic Connectivity経由でデータ登録可能なのだが、

OracleのLONG型にマッピングされている関係でほとんどのスカラ関数は利用できない。

さらに、MySQL4.0.25、MySQL4.1.13aともLONG型にマッピングされたデータを問い合わせることが出来ないという現象に遭遇してしまったのだ。(これはまずい)
LONG型ならば問い合わせることができるはずなのだが、TINYTEXT型、TINYBLOB型、TEXT型、BLOB型の単純なクエリ全てがエラーとなってしまうのだ。
以下の結果を観る限り、シンタックスエラーが返されているためGeneric Connectivity経由でリモートサイトに割り振っているSQL文がまずいのかもしれない。(MyODBCの問題なのか、OracleのGeneric Connectivityの問題なのか? いずれにしても、SQLが多少書き換えられているのは間違いないので、書き換えるための元の情報が間違っているのか、書き換える処理に問題があるのかのいずれかということになる。)


CORYDORAS> select "r_tinytext" from varchar_test_mysql4113a_mac_sv@oracle10g_win;
ERROR:
ORA-28500:
OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][MySQL][ODBC 3.51 Driver][mysqld-4.1.13a]You
have an error in your SQL syntax; check the manual that corresponds to your
MySQL server version for the right syntax to use near '"varchar_test" WHERE
"id"=1' at line 1 (SQL State: 37000; SQL Code: 1064)
ORA-02063: 先行のエラー・メッセージを参照してください2
lines(MYSQL4113A_MAC_SV)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。

レコードが選択されませんでした。

前述のクエリに、条件を加えてみたところ興味深いエラーが返された。
The column 'A1.r_tinytext' is a chapter or a BLOB という部分である。
BLOBにマッピングされているのか?? と疑心暗鬼。 


CORYDORAS> l
1 select "r_tinytext" from varchar_test_mysql4113a_mac_sv@oracle10g_win
2* where "r_tinytext" = ''
CORYDORAS> /
select "r_tinytext" from varchar_test_mysql4113a_mac_sv@oracle10g_win
*
行1でエラーが発生しました。:
ORA-28500:
OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][A03C] The column 'A1.r_tinytext' is a chapter
or a BLOB, it can't be used in expressions, ORDER/GROUP BY clause or DISTINCT
query
ORA-02063: 先行のエラー・メッセージを参照してください2
lines(MYSQL4113A_MAC_SV)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。

CORYDORAS>

どの型にマップされているのかを再確認した。
MySQL側で、TINYTEXT型だけの列を持つ表を作成しデータを登録しておく。(一意性制約や、主キー制約も付加していない点に注目)
次に、Generic Connectivity経由で該当する列を問い合わせてみると、やはりエラーになる。


mysql> create table hoge (test_tinytext tinytext);
Query OK, 0 rows affected (0.00 sec)

mysql> insert into hoge values('あいう');
Query OK, 1 row affected (0.01 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from hoge;
+---------------+
| test_tinytext |
+---------------+
| あいう |
+---------------+
1 row in set (0.00 sec)

mysql>

mysql> desc hoge
-> ;
+---------------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+----------+------+-----+---------+-------+
| test_tinytext | tinytext | YES | | NULL | |
+---------------+----------+------+-----+---------+-------+
1 row in set (0.00 sec)

Generic Connectivity経由で問い合わせた結果。


CORYDORAS> select "test_tinytext" from hoge_mysql4113a_mac_sv@oracle10g_win;
select "test_tinytext" from hoge_mysql4113a_mac_sv@oracle10g_win
*
行1でエラーが発生しました。:
ORA-28500:
OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][D015] The table hoge contains a chapter or a
blob. It must also contain a column with unique index.
ORA-02063: 先行のエラー・メッセージを参照してください2
lines(MYSQL4113A_MAC_SV)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。

エラーメッセージに従い、主キー制約を追加してみた。。。


mysql> alter table hoge add column id int primary key;
Query OK, 1 row affected (0.38 sec)
Records: 1 Duplicates: 0 Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> desc hoge;
+---------------+----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+----------+------+-----+---------+-------+
| test_tinytext | tinytext | YES | | NULL | |
| id | int(11) | | PRI | 0 | |
+---------------+----------+------+-----+---------+-------+
2 rows in set (0.00 sec)

mysql>
mysql> update hoge set id =1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

Generic Connectivity経由で問い合わせた結果。
主キー制約を追加したのだが、結果はやはりシンタックスエラーとなる。(だめだな、こりゃ)


CORYDORAS> select "id","test_tinytext" from hoge_mysql4113a_mac_sv@oracle10g_win;
ERROR:
ORA-28500:
OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][MySQL][ODBC 3.51 Driver][mysqld-4.1.13a]You
have an error in your SQL syntax; check the manual that corresponds to your
MySQL server version for the right syntax to use near '"hoge" WHERE "id"=0' at
line 1 (SQL State: 37000; SQL Code: 1064)
ORA-02063: 先行のエラー・メッセージを参照してください2
lines(MYSQL4113A_MAC_SV)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。

LONG型ではなくLOB型にマッピングされているとすれば、主キー制約又一意制約が必要であると、マニュアルに記載されている通りの挙動だとは思うのだが・・・・。(尚、MySQL4.0.25でも同じ結果であった。)

今日はここまで、次回につづく。

| | | コメント (0) | トラックバック (0)

2006年3月25日 (土)

Mac De Oracle Heterogeneous! #76

前回のつづき。Generic Connectivyty経由でMySQL4.1.13aの文字型にアクセス。六回目。

6.文字列の登録

char(20)へのデータ登録。特に気になる点はない。


CORYDORAS> insert into
2 char_test_mysql4113a_mac_sv@oracle10g_win("id","r_char_20")
3 values(300,null);

1行が作成されました。

CORYDORAS> insert into
2 char_test_mysql4113a_mac_sv@oracle10g_win("id","r_char_20")
3 values(301,'');

1行が作成されました。

CORYDORAS> insert into
2 char_test_mysql4113a_mac_sv@oracle10g_win("id","r_char_20")
3 values(302,' あ ');

1行が作成されました。

CORYDORAS> insert into
2 char_test_mysql4113a_mac_sv@oracle10g_win("id","r_char_20")
3 values(303,'12345678901234567890');

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> insert into
2 char_test_mysql4113a_mac_sv@oracle10g_win("id","r_char_20")
3 values(304,'123456789012345678901');

1行が作成されました。

CORYDORAS> edit
file afiedt.bufが書き込まれました。

1 insert into
2 char_test_mysql4113a_mac_sv@oracle10g_win("id","r_char_20")
3* values(305,'1234567890123456789012345678901234567890')
CORYDORAS> /

1行が作成されました。

CORYDORAS> edit
file afiedt.bufが書き込まれました。

1 insert into
2 char_test_mysql4113a_mac_sv@oracle10g_win("id","r_char_20")
3* values(305,'12345678901234567890123456789012345678901')
CORYDORAS> /
insert into
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][A0C9] Value for column r_char_20 exceeds column's length.
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(MYSQL4113A_MAC_SV)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。

CORYDORAS> rollback;

ロールバックが完了しました。

CORYDORAS> insert into
2 char_test_mysql4113a_mac_sv@oracle10g_win("id","r_char_20")
3 values(304,'12345678901234567890');

1行が作成されました。

CORYDORAS> edit
file afiedt.bufが書き込まれました。

1 insert into
2 char_test_mysql4113a_mac_sv@oracle10g_win("id","r_char_20")
3* values(304,'123456789012345678901')
CORYDORAS> /
insert into
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][A0C9] Value for column r_char_20 exceeds column's length.
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(MYSQL4113A_MAC_SV)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。

CORYDORAS>


varchar(20)へのデータ登録。特に気になる点はない。


CORYDORAS> insert into varchar_test_mysql4113a_mac_sv@oracle10g_win("id","r_varchar_20")
2 values(300,null);

1行が作成されました。

CORYDORAS> insert into varchar_test_mysql4113a_mac_sv@oracle10g_win("id","r_varchar_20")
2 values(301,'');

1行が作成されました。

CORYDORAS> insert into varchar_test_mysql4113a_mac_sv@oracle10g_win("id","r_varchar_20")
2 values(302,' あ ');

1行が作成されました。

CORYDORAS> insert into varchar_test_mysql4113a_mac_sv@oracle10g_win("id","r_varchar_20")
2 values(303,'12345678901234567890');

1行が作成されました。

CORYDORAS> insert into varchar_test_mysql4113a_mac_sv@oracle10g_win("id","r_varchar_20")
2 values(304,'12345678901234567890');

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> insert into varchar_test_mysql4113a_mac_sv@oracle10g_win("id","r_varchar_20")
2 values(305,'1234567890123456789012345678901234567890');

1行が作成されました。

CORYDORAS> edit
file afiedt.bufが書き込まれました。

1 insert into varchar_test_mysql4113a_mac_sv@oracle10g_win("id","r_varchar_20")
2* values(305,'12345678901234567890123456789012345678901')
CORYDORAS> /
insert into varchar_test_mysql4113a_mac_sv@oracle10g_win("id","r_varchar_20")
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][A0C9] Value for column r_varchar_20 exceeds column's length.
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(MYSQL4113A_MAC_SV)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> insert into varchar_test_mysql4113a_mac_sv@oracle10g_win("id","r_varchar_20")
2 values(306,'123456789012345678901');
insert into varchar_test_mysql4113a_mac_sv@oracle10g_win("id","r_varchar_20")
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][A0C9] Value for column r_varchar_20 exceeds column's length.
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(MYSQL4113A_MAC_SV)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。

CORYDORAS> rollback;

ロールバックが完了しました。

CORYDORAS>


今日は、ここまで、次回につづく。

| | | コメント (0) | トラックバック (0)

2006年3月24日 (金)

Mac De Oracle Heterogeneous! #75

前回のつづき。Generic Connectivyty経由でMySQL4.1.13aの文字型にアクセス。五回目。

5.ソート

MySQL4.0.xの場合と同じデータを登録してある。


CORYDORAS> col hex_sjis for a20
CORYDORAS> l
1 select
2 "id",
3 "r_varchar_20",
4 dump("r_varchar_20",16) as hex_sjis
5 from
6 varchar_test_mysql4113a_mac_sv@oracle10g_win
7 where
8* "id" between 1 and 18
CORYDORAS> /

id r_varchar_20 HEX_SJIS
---------- ---------------------------------------- --------------------
1 C Typ=1 Len=1: 43
2 c Typ=1 Len=1: 63
3 B Typ=1 Len=1: 42
4 b Typ=1 Len=1: 62
5 A Typ=1 Len=1: 41
6 a Typ=1 Len=1: 61
7 お Typ=1 Len=2: 82,a8
8 え Typ=1 Len=2: 82,a6
9 う Typ=1 Len=2: 82,a4
10 い Typ=1 Len=2: 82,a2
11 あ Typ=1 Len=2: 82,a0
12 ぉ Typ=1 Len=2: 82,a7
13 ぇ Typ=1 Len=2: 82,a5
14 ぅ Typ=1 Len=2: 82,a3
15 ぃ Typ=1 Len=2: 82,a1
16 ぁ Typ=1 Len=2: 82,9f
17 null NULL
18 null NULL

18行が選択されました。

CORYDORAS>

"r_varchar_20"は、binary属性がないため、MySQL側でソート処理が行われるとソート結果が異ってしまうのだが、以下のようにOracle側にしか存在しない関数があることでOracle側でソートされている。

CORYDORAS> l
1 select
2 "id",
3 "r_varchar_20",
4 dump("r_varchar_20",16) as hex_sjis
5 from
6 varchar_test_mysql4113a_mac_sv@oracle10g_win
7 where
8 "id" between 1 and 18
9 order by
10* "r_varchar_20"
CORYDORAS> /

id r_varchar_20 HEX_SJIS
---------- ---------------------------------------- --------------------
5 A Typ=1 Len=1: 41
3 B Typ=1 Len=1: 42
1 C Typ=1 Len=1: 43
6 a Typ=1 Len=1: 61
4 b Typ=1 Len=1: 62
2 c Typ=1 Len=1: 63
16 ぁ Typ=1 Len=2: 82,9f
11 あ Typ=1 Len=2: 82,a0
15 ぃ Typ=1 Len=2: 82,a1
10 い Typ=1 Len=2: 82,a2
14 ぅ Typ=1 Len=2: 82,a3
9 う Typ=1 Len=2: 82,a4
13 ぇ Typ=1 Len=2: 82,a5
8 え Typ=1 Len=2: 82,a6
12 ぉ Typ=1 Len=2: 82,a7
7 お Typ=1 Len=2: 82,a8
17 null NULL
18 null NULL

18行が選択されました。

dump()関数を取り去ると、文全てがリモートマップされ、ソート結果もMySQL側のソート結果となってしまう。


CORYDORAS> edit
file afiedt.bufが書き込まれました。

1 select
2 "id",
3 "r_varchar_20"
4 from
5 varchar_test_mysql4113a_mac_sv@oracle10g_win
6 where
7 "id" between 1 and 18
8 order by
9* "r_varchar_20"
CORYDORAS> /

id r_varchar_20
---------- ----------------------------------------
17 null
18 null
5 A
6 a
3 B
4 b
1 C
2 c
16 ぁ
11 あ
15 ぃ
10 い
14 ぅ
9 う
13 ぇ
8 え
12 ぉ
7 お

18行が選択されました。

さて、MySQL4.0.25の場合と同様、インラインビューに書き換え、NO_MERGEヒントを追加する。このように書き換えることでリモートソート回避を強制させることが出来る。


CORYDORAS> edit
file afiedt.bufが書き込まれました。

1 select *
2 from
3 (
4 select /*+ NO_MERGE */
5 "id",
6 "r_varchar_20"
7 from
8 varchar_test_mysql4113a_mac_sv@oracle10g_win
9 where
10 "id" between 1 and 18
11 )
12 order by
13* "r_varchar_20"
CORYDORAS> /

id r_varchar_20
---------- ----------------------------------------
5 A
3 B
1 C
6 a
4 b
2 c
16 ぁ
11 あ
15 ぃ
10 い
14 ぅ
9 う
13 ぇ
8 え
12 ぉ
7 お
17 null
18 null

18行が選択されました。

オートトレースで実行計画と統計情報を取得してみると、確かにOracle側でソートされている。


CORYDORAS> set null ""
CORYDORAS> set autot on
CORYDORAS> l
1 select *
2 from
3 (
4 select /*+ NO_MERGE */
5 "id",
6 "r_varchar_20"
7 from
8 varchar_test_mysql4113a_mac_sv@oracle10g_win
9 where
10 "id" between 1 and 18
11 )
12 order by
13* "r_varchar_20"
CORYDORAS> /

id r_varchar_20
---------- ----------------------------------------
5 A
3 B
1 C
6 a
4 b
2 c
16 ぁ
11 あ
15 ぃ
10 い
14 ぅ
9 う
13 ぇ
8 え
12 ぉ
7 お
17
18

18行が選択されました。

実行計画
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=53 Card=5 Bytes=275)
1 0 SORT (ORDER BY) (Cost=53 Card=5 Bytes=275)
2 1 VIEW (Cost=52 Card=5 Bytes=275)
3 2 REMOTE* (Cost=52 Card=5 Bytes=275) ORACLE10G_WIN

3 SERIAL_FROM_REMOTE SELECT "id","r_varchar_20" FROM "VARCHAR_TES
T_MYSQL4113A_MAC_SV" "VARCHAR_TEST_M

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
0 consistent gets
0 physical reads
0 redo size
812 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
18 rows processed

CORYDORAS>

今日はここまで、次回へつづく。

| | | コメント (0) | トラックバック (0)

2006年3月23日 (木)

Mac De Oracle Heterogeneous! #74

前回のつづき

4.tinytext型、tinyblob型、text型、blob型

MySQL4.0.xの場合と同様の結果(length関数等が利用できない)であったためlong型にマッピングされていると思っていたのだが、ほんとうにlong型なのか?という挙動に気付いた。その挙動については別途まとめる予定であり、合わせてPostgreSQL7.4.9のtext型についても再検証する予定であるが、今回はlength()関数等の利用でエラーとなったログだけを載せておく。

CORYDORAS> select
2 "id",
3 "r_tinytext",
4 length("r_tinytext") as "文字数",
5 lengthb("r_tinytext") as "文字サイズ",
6 substr(
7 dump("r_tinytext",16),
8 1,
9 instr(dump("r_tinytext",16),' ')
10 ) as "dump"
11 from
12 varchar_test_mysql4113a_mac_sv@oracle10g_win
13 where
14 "id" = 30;
select
*
行1でエラーが発生しました。:
ORA-02070: データベースMYSQL4113A_MAC_SVはこのコンテキストではLENGTHをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。

CORYDORAS> l
1 select
2 "id",
3 "r_tinyblob",
4 length("r_tinyblob") as "文字数",
5 lengthb("r_tinyblob") as "文字サイズ",
6 substr(
7 dump("r_tinyblob",16),
8 1,
9 instr(dump("r_tinyblob",16),' ')
10 ) as "dump"
11 from
12 varchar_test_mysql4113a_mac_sv@oracle10g_win
13 where
14* "id" = 30
CORYDORAS> /
select
*
行1でエラーが発生しました。:
ORA-02070: データベースMYSQL4113A_MAC_SVはこのコンテキストではLENGTHをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。

CORYDORAS> l
1 select
2 "id",
3 "r_text",
4 length("r_text") as "文字数",
5 lengthb("r_text") as "文字サイズ",
6 substr(
7 dump("r_text",16),
8 1,
9 instr(dump("r_text",16),' ')
10 ) as "dump"
11 from
12 varchar_test_mysql4113a_mac_sv@oracle10g_win
13 where
14* "id" = 30
CORYDORAS> /
select
*
行1でエラーが発生しました。:
ORA-02070: データベースMYSQL4113A_MAC_SVはこのコンテキストではLENGTHをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。

CORYDORAS> l
1 select
2 "id",
3 "r_blob",
4 length("r_blob") as "文字数",
5 lengthb("r_blob") as "文字サイズ",
6 substr(
7 dump("r_blob",16),
8 1,
9 instr(dump("r_blob",16),' ')
10 ) as "dump"
11 from
12 varchar_test_mysql4113a_mac_sv@oracle10g_win
13 where
14* "id" = 30
CORYDORAS> /
select
*
行1でエラーが発生しました。:
ORA-02070: データベースMYSQL4113A_MAC_SVはこのコンテキストではLENGTHをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。

CORYDORAS>

今日はここまで。

Oracle, Oracle以外のデータベース, Mac, Tiger Server De Oracle10g, 異機種間接続サービス(Oracle Generic Connectivity) | | | コメント (0) | トラックバック (0)

Mac De Oracle Heterogeneous! #73

前回のつづき。Generic Connectivyty経由でMySQL4.1.13aの文字型にアクセス。三回目。

3.varchar型

MySQL4.0.xとは異なり、文字セマンティクスになっているという点以外は注意する点はないだろう。Oracleのvarchat2型にマッピングされている。

1)varchar(20)で、binary属性の有無のみ異なる2列。

CORYDORAS> set null "null"
CORYDORAS> col r_varchar_20 for a40
CORYDORAS> col dump for a20
CORYDORAS> set linesize 132
CORYDORAS> l
1 select
2 "id",
3 "r_varchar_20",
4 length("r_varchar_20") as "文字数",
5 lengthb("r_varchar_20") as "文字サイズ",
6 substr(
7 dump("r_varchar_20",16),
8 1,
9 instr(dump("r_varchar_20",16),' ')
10 ) as "dump"
11 from
12 varchar_test_mysql4113a_mac_sv@oracle10g_win
13 where
14* "id" between 19 and 23
CORYDORAS> /

id r_varchar_20 文字数 文字サイズ dump
---------- ---------------------------------------- ---------- ---------- --------------------
19 あ 2 3 Typ=1
20 null null null null
21 null null null null
22 12345678901234567890 20 20 Typ=1
23 12345678901234567890 20 40 Typ=1

CORYDORAS>
CORYDORAS> col r_varchar_20_binary for a40
CORYDORAS> l
1 select
2 "id",
3 "r_varchar_20_binary",
4 length("r_varchar_20_binary") as "文字数",
5 lengthb("r_varchar_20_binary") as "文字サイズ",
6 substr(
7 dump("r_varchar_20_binary",16),
8 1,
9 instr(dump("r_varchar_20_binary",16),' ')
10 ) as "dump"
11 from
12 varchar_test_mysql4113a_mac_sv@oracle10g_win
13 where
14* "id" between 24 and 28
CORYDORAS> /

id r_varchar_20_binary 文字数 文字サイズ dump
---------- ---------------------------------------- ---------- ---------- --------------------
24 あ 2 3 Typ=1
25 null null null null
26 null null null null
27 12345678901234567890 20 20 Typ=1
28 12345678901234567890 20 40 Typ=1

CORYDORAS>

2)varchar(255)で、binary属性の有無がことなる2列。
CORYDORAS> col r_varchar_255 for a40
CORYDORAS> l
1 select
2 "id",
3 "r_varchar_255",
4 length("r_varchar_255") as "文字数",
5 lengthb("r_varchar_255") as "文字サイズ",
6 substr(
7 dump("r_varchar_255",16),
8 1,
9 instr(dump("r_varchar_255",16),' ')
10 ) as "dump"
11 from
12 varchar_test_mysql4113a_mac_sv@oracle10g_win
13 where
14* "id" = 29
CORYDORAS> /

id r_varchar_255 文字数 文字サイズ dump
---------- ---------------------------------------- ---------- ---------- --------------------
29 **************************************** 255 255 Typ=1
****************************************
****************************************
****************************************
****************************************
****************************************
***************

CORYDORAS>
CORYDORAS> col r_varchar_255_binary for a40
CORYDORAS> l
1 select
2 "id",
3 "r_varchar_255_binary",
4 length("r_varchar_255_binary") as "文字数",
5 lengthb("r_varchar_255_binary") as "文字サイズ",
6 substr(
7 dump("r_varchar_255_binary",16),
8 1,
9 instr(dump("r_varchar_255_binary",16),' ')
10 ) as "dump"
11 from
12 varchar_test_mysql4113a_mac_sv@oracle10g_win
13 where
14* "id" = 29
CORYDORAS> /

id r_varchar_255_binary 文字数 文字サイズ dump
---------- ---------------------------------------- ---------- ---------- --------------------
29 **************************************** 255 255 Typ=1
****************************************
****************************************
****************************************
****************************************
****************************************
***************

CORYDORAS>

MySQL4.1.x以降ではvarchar(256)以上のサイズを定義すると、自動的に text型に変換されるので用注意。

mysql> alter table varchar_test add column r_varchar_256 varchar(256);
Query OK, 34 rows affected, 1 warning (0.92 sec)
Records: 34 Duplicates: 0 Warnings: 0

mysql> desc varchar_test;
+----------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+--------------+------+-----+---------+-------+
| id | int(11) | | PRI | 0 | |
| r_varchar_20 | varchar(20) | YES | | NULL | |
| r_varchar_20_binary | varchar(20) | YES | | NULL | |
| r_varchar_255 | varchar(255) | YES | | NULL | |
| r_varchar_255_binary | varchar(255) | YES | | NULL | |
| r_tinytext | tinytext | YES | | NULL | |
| r_tinyblob | tinyblob | YES | | NULL | |
| r_text | text | YES | | NULL | |
| r_blob | blob | YES | | NULL | |
| r_varchar_256 | text | YES | | NULL | |
+----------------------+--------------+------+-----+---------+-------+
10 rows in set (0.01 sec)

mysql>


今日はここまで、次回へつづく。

| | | コメント (0) | トラックバック (0)

2006年3月22日 (水)

Mac De Oracle Heterogeneous! #72

前回のつづき。Generic Connectivyty経由でMySQL4.1.13aの文字型にアクセス。二回目。

さて、MySQl4.0.xと比べ、文字セマンティクスである点に注意が必要だと書いたが、char(255)及び、char(255) binaryとして定義した列ではその違いを再確認できる。

char(255)と定義すると、MySQL4.1.xでは、文字セマンティクスであることから、255文字(SJISでは510バイト)ということになる。
Generic Connectivity経由で問い合わせた以下結果を見てもらいたい。dump関数が返すデータ型がvarchar2型になっている点に気付いていただけただろうか? 
ODBC Driverが ODBCデータ型である、SQL_CHAR型とSQL_VARCHAR型とのマッピング変更をデータサイズにより変更している。

CORYDORAS> col r_char_255 for a40
CORYDORAS> l
1 select
2 "r_char_255",
3 length("r_char_255") as "文字数",
4 lengthb("r_char_255") as "文字サイズ",
5 substr(
6 dump("r_char_255"),
7 1,
8 instr(dump("r_char_255"),' ')
9 ) as "dump"
10 from
11 char_test_mysql4113a_mac_sv@oracle10g_win
12 where
13* "id" = 11
CORYDORAS> /

r_char_255 文字数 文字サイズ dump
---------------------------------------- ---------- ---------- --------------------
**************************************** 255 255 Typ=1
****************************************
****************************************
****************************************
****************************************
****************************************
***************

CORYDORAS>
CORYDORAS> col r_char_255_binary for a40
CORYDORAS> l
1 select
2 "r_char_255_binary",
3 length("r_char_255_binary") as "文字数",
4 lengthb("r_char_255_binary") as "文字サイズ",
5 substr(
6 dump("r_char_255_binary"),
7 1,
8 instr(dump("r_char_255_binary"),' ')
9 ) as "dump"
10 from
11 char_test_mysql4113a_mac_sv@oracle10g_win
12 where
13* "id" = 11
CORYDORAS> /

r_char_255_binary 文字数 文字サイズ dump
---------------------------------------- ---------- ---------- --------------------
**************************************** 255 255 Typ=1
****************************************
****************************************
****************************************
****************************************
****************************************
***************

CORYDORAS>

char_test表に char(127) と char(128)の2列を追加して検証した結果を以下に示す。
文字セマンティクスでは、キャラクタセットがSJISであれば127文字は254バイト、128文字は256バイトである。

mysql> desc char_test;
+-------------------+-----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+-----------+------+-----+---------+-------+
| id | int(11) | | PRI | 0 | |
| r_char_20 | char(20) | YES | | NULL | |
| r_char_20_binary | char(20) | YES | | NULL | |
| r_char_255 | char(255) | YES | | NULL | |
| r_char_255_binary | char(255) | YES | | NULL | |
| r_char_127 | char(127) | YES | | NULL | |
| r_char_128 | char(128) | YES | | NULL | |
+-------------------+-----------+------+-----+---------+-------+

CORYDORAS> set linesize 132
CORYDORAS>
CORYDORAS> l
1 select
2 "r_char_127",
3 length("r_char_127") as "文字数",
4 lengthb("r_char_127") as "文字サイズ",
5 substr(
6 dump("r_char_127",16),
7 1,
8 instr(dump("r_char_127",16),' ')
9 ) as "dump"
10 from
11 char_test_mysql4113a_mac_sv@oracle10g_win
12 where
13* "id" = 99
CORYDORAS> /

r_char_127 文字数 文字サイズ dump
---------------------------------------- ---------- ---------- --------------------
**************************************** 254 254 Typ=96
****************************************
****************************************
*******

CORYDORAS> col r_char_128 for a40
CORYDORAS> l
1 select
2 "r_char_128",
3 length("r_char_128") as "文字数",
4 lengthb("r_char_128") as "文字サイズ",
5 substr(
6 dump("r_char_128",16),
7 1,
8 instr(dump("r_char_128",16),' ')
9 ) as "dump"
10 from
11 char_test_mysql4113a_mac_sv@oracle10g_win
12 where
13* "id" = 100
CORYDORAS> /

r_char_128 文字数 文字サイズ dump
---------------------------------------- ---------- ---------- --------------------
**************************************** 128 128 Typ=1
****************************************
****************************************
********

CORYDORAS>

予想どおり、127×2=254までは、ODBCのSQL_CHAR型 -> OracleのCHAR型に、128×2=256で ODBCのSQL_VARCHAR型->OracleのVARCHAR2型に、ぞれぞれマッピングされている。

文字列の実サイズは、r_char_128列に登録しているデータの方が短い(この例では)ため、見た目は結構歪なマッピングに見えてしまう・・・・。文字セマンティクスになっている影響がここにも現れている。


今日はここまで、次回につづく。

| | | コメント (0) | トラックバック (0)

2006年3月21日 (火)

Mac De Oracle Heterogeneous! #71

前回のつづき。Generic Connectivyty経由でMySQL4.1.13aの文字型にアクセス。一回目。

2.char型


char(20)及び、char(20) binaryとして定義した列は、Generic Connectivity経由ではOracleのchar型にマッピングされる。
型のマッピングに関してはMySQL4.0.xと同じなので特に問題はなさそうだ。ただし、MySQL4.1.xでは、文字セマンティクスになっているため char(20)と定義した場合には、20文字という意味になり、キャラクタセットがSJISである下記例においては、最大40バイトであるという点に注意が必要である。

CORYDORAS> set null "null"
CORYDORAS> col dump for a20
CORYDORAS> l
1 select
2 "r_char_20",
3 length("r_char_20") as "文字数",
4 lengthb("r_char_20") as "文字サイズ",
5 substr(
6 dump("r_char_20",16),
7 1,
8 instr(dump("r_char_20",16),' ')
9 ) as "dump"
10 from
11 char_test_mysql4113a_mac_sv@oracle10g_win
12 where
13* "id" <=5
CORYDORAS> /

r_char_20 文字数 文字サイズ dump
---------------------------------------- ---------- ---------- --------------------
あ 39 40 Typ=96
null null null null
40 40 Typ=96
12345678901234567890 40 40 Typ=96
12345678901234567890 20 40 Typ=96

CORYDORAS>
CORYDORAS> col r_char_20_binary for a40
CORYDORAS> l
1 select
2 "r_char_20_binary",
3 length("r_char_20_binary") as "文字数",
4 lengthb("r_char_20_binary") as "文字サイズ",
5 substr(
6 dump("r_char_20_binary",16),
7 1,
8 instr(dump("r_char_20_binary",16),' ')
9 ) as "dump"
10 from
11 char_test_mysql4113a_mac_sv@oracle10g_win
12 where
13* "id" between 6 and 10
CORYDORAS> /

r_char_20_binary 文字数 文字サイズ dump
---------------------------------------- ---------- ---------- --------------------
あ 39 40 Typ=96
null null null null
40 40 Typ=96
12345678901234567890 40 40 Typ=96
12345678901234567890 20 40 Typ=96

CORYDORAS>

今日はここまで、次回につづく。

| | | コメント (0) | トラックバック (0)

2006年3月20日 (月)

Mac De Oracle Heterogeneous! #70

前回のつづき。Generic Connectivyty経由でMySQL4.1.13aの文字型にアクセス。準備。

MySQL4.0.13aは、Generic Connectivityを介して以下の経路でアクセスする。
(尚、MySQL4.0.25のまとめは、MySQL4.1.13aのまとめに含める予定である。)

gencon_blog_mac_my

1.準備

MacOSX Serverに構築したMySQL4.1.13aには、char_test表と、varchar_test表を作成してあり、以下のようなデータを登録しておいた。

mysql> select
-> id,
-> r_char_20,
-> r_char_20_binary
-> from
-> char_test;
+----+------------------------------------------+------------------------------------------+
| id | r_char_20 | r_char_20_binary |
+----+------------------------------------------+------------------------------------------+
| 1 | あ | NULL |
| 2 | NULL | NULL |
| 3 | | NULL |
| 4 | 12345678901234567890 | NULL |
| 5 | 12345678901234567890 | NULL |
| 6 | NULL | あ |
| 7 | NULL | NULL |
| 8 | NULL | |
| 9 | NULL | 12345678901234567890 |
| 10 | NULL | 12345678901234567890 |
+----+------------------------------------------+------------------------------------------+
10 rows in set (0.02 sec)

mysql>
mysql> select
-> id,
-> length(r_char_255),
-> length(r_char_255_binary)
-> from
-> char_test
-> where
-> id = 11;
+----+--------------------+---------------------------+
| id | length(r_char_255) | length(r_char_255_binary) |
+----+--------------------+---------------------------+
| 11 | 255 | 255 |
+----+--------------------+---------------------------+
1 row in set (0.07 sec)

mysql>
mysql> select
-> id,
-> r_varchar_20,
-> r_varchar_20_binary
-> from
-> varchar_test;
+----+--------------+---------------------+
| id | r_varchar_20 | r_varchar_20_binary |
+----+--------------+---------------------+
| 1 | C | C |
| 2 | c | c |
| 3 | B | B |
| 4 | b | b |
| 5 | A | A |
| 6 | a | a |
| 7 | お | お |
| 8 | え | え |
| 9 | う | う |
| 10 | い | い |
| 11 | あ | あ |
| 12 | ぉ | ぉ |
| 13 | ぇ | ぇ |
| 14 | ぅ | ぅ |
| 15 | ぃ | ぃ |
| 16 | ぁ | ぁ |
| 17 | NULL | NULL |
| 18 | | |
+----+--------------+---------------------+
18 rows in set (0.00 sec)

mysql>
mysql> select
-> id,
-> r_varchar_20,
-> r_varchar_20_binary
-> from
-> varchar_test
-> where
-> id between 19 and 28;
+----+------------------------------------------+------------------------------------------+
| id | r_varchar_20 | r_varchar_20_binary |
+----+------------------------------------------+------------------------------------------+
| 19 | あ | NULL |
| 20 | NULL | NULL |
| 21 | | NULL |
| 22 | 12345678901234567890 | NULL |
| 23 | 12345678901234567890 | NULL |
| 24 | NULL | あ |
| 25 | NULL | NULL |
| 26 | NULL | |
| 27 | NULL | 12345678901234567890 |
| 28 | NULL | 12345678901234567890 |
+----+------------------------------------------+------------------------------------------+
10 rows in set (0.02 sec)

mysql>
mysql> select
-> id,
-> length(r_varchar_255),
-> length(r_varchar_255_binary)
-> from
-> varchar_test
-> where
-> id = 29;
+----+-----------------------+------------------------------+
| id | length(r_varchar_255) | length(r_varchar_255_binary) |
+----+-----------------------+------------------------------+
| 29 | 255 | 255 |
+----+-----------------------+------------------------------+
1 row in set (0.00 sec)

mysql> select
-> id,
-> length(r_tinytext),
-> length(r_tinyblob)
-> from
-> varchar_test
-> where
-> id = 30;
+----+--------------------+--------------------+
| id | length(r_tinytext) | length(r_tinyblob) |
+----+--------------------+--------------------+
| 30 | 255 | 255 |
+----+--------------------+--------------------+
1 row in set (0.00 sec)

mysql> select
-> id,
-> length(r_text),
-> length(r_blob)
-> from
-> varchar_test
-> where
-> id between 31 and 34;
+----+----------------+----------------+
| id | length(r_text) | length(r_blob) |
+----+----------------+----------------+
| 31 | 2000 | 2000 |
| 32 | 2001 | 2001 |
| 33 | 4000 | 4000 |
| 34 | 4001 | 4001 |
+----+----------------+----------------+
4 rows in set (0.00 sec)

mysql>

今日はここまで、次回へつづく。

| | | コメント (0) | トラックバック (0)

2006年3月19日 (日)

Mac De Oracle Heterogeneous! #69

前回のつづき。Generic Connectivyty経由でMySQL4.0.25の文字型にアクセス。最終回。

3.文字列の登録

varchar型へ、NULL、空文字、' あ '、最大サイズの文字列登録。特に問題になるようなことは無さそうだ。

CORYDORAS> insert into varchar_test_mysql4025_mac@oracle10g_win("id","r_varchar_20") values(100,null);

1行が作成されました。

CORYDORAS> insert into varchar_test_mysql4025_mac@oracle10g_win("id","r_varchar_20") values(101,'');

1行が作成されました。

CORYDORAS> insert into varchar_test_mysql4025_mac@oracle10g_win("id","r_varchar_20") values(102,' あ ');

1行が作成されました。

CORYDORAS> insert into varchar_test_mysql4025_mac@oracle10g_win("id","r_varchar_20") values(103,'12345678901234567890');

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。


MySQL4.0.25上で実行した場合とは異なり文字列の切り捨てはエラーとして処理される。(バイトセマンティクスなので、varchar(20)では、20バイトを超える文字列はエラーとなる。Generic Connectivity経由でOracleと連携する場合には都合が良さそうだ。)

CORYDORAS> insert into varchar_test_mysql4025_mac@oracle10g_win("id","r_varchar_20")
2 values(104,'12345678901234567890');
insert into varchar_test_mysql4025_mac@oracle10g_win("id","r_varchar_20")
*
行1でエラーが発生しました。:
ORA-28500:
OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][A0C9] Value for column r_varchar_20 exceeds
column's length.
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(MYSQL4025_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。

CORYDORAS> insert into varchar_test_mysql4025_mac@oracle10g_win("id","r_varchar_20")
2 values(104,'12345678901');
insert into varchar_test_mysql4025_mac@oracle10g_win("id","r_varchar_20")
*
行1でエラーが発生しました。:
ORA-28500:
OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][A0C9] Value for column r_varchar_20 exceeds
column's length.
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(MYSQL4025_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


20バイト(SJISなので全角なら10文字まで)分のデータを登録しておく。

CORYDORAS> l
1 insert into varchar_test_mysql4025_mac@oracle10g_win("id","r_varchar_20")
2* values(104,'1234567890')
CORYDORAS> /

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS>

char型についても、varchar型と同じデータを登録。

CORYDORAS> insert into char_test_mysql4025_mac@oracle10g_win("id","r_char_20") values(200,null);

1行が作成されました。

CORYDORAS> insert into char_test_mysql4025_mac@oracle10g_win("id","r_char_20") values(201,'');

1行が作成されました。

CORYDORAS> insert into char_test_mysql4025_mac@oracle10g_win("id","r_char_20") values(202,' あ ');

1行が作成されました。

CORYDORAS> insert into char_test_mysql4025_mac@oracle10g_win("id","r_char_20") values(203,'12345678901234567890');

1行が作成されました。

CORYDORAS> insert into char_test_mysql4025_mac@oracle10g_win("id","r_char_20") values(204,'1234567890');

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。


varchar型と同様、char型でも超過分の文字が切り捨てられて登録される危険性はないようだ。

CORYDORAS> insert into char_test_mysql4025_mac@oracle10g_win("id","r_char_20") values(205,'123456789012345678901');
insert into char_test_mysql4025_mac@oracle10g_win("id","r_char_20") values(205,'123456789012345678901')
*
行1でエラーが発生しました。:
ORA-28500:
OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][A0C9] Value for column r_char_20 exceeds
column's length.
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(MYSQL4025_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。

CORYDORAS> rollback;

ロールバックが完了しました。


tinytext型、tinyblob型、text型、blob型にもデータを登録。

CORYDORAS> insert into varchar_test_mysql4025_mac@oracle10g_win("id","r_tinytext","r_tinyblob") values(205,'あいう','えお');

1行が作成されました。

CORYDORAS> insert into varchar_test_mysql4025_mac@oracle10g_win("id","r_text","r_blob") values(206,'かきく','けこ');

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。


Genericn Connectivity経由で登録したデータの確認。(tinytext型、tinyblob型、text型、blob型を除く)

CORYDORAS> select
2 "id",
3 "r_char_20",
4 lengthb("r_char_20") as "bytes"
5 from
6 char_test_mysql4025_mac@oracle10g_win
7 where
8 "id" >= 200;

id r_char_20 bytes
---------- ---------------------------------------- ----------
200 null null
201 20
202 あ 20
203 12345678901234567890 20
204 1234567890 20

CORYDORAS>
CORYDORAS> l
1 select
2 "id",
3 "r_varchar_20",
4 lengthb("r_varchar_20") as "bytes"
5 from
6 varchar_test_mysql4025_mac@oracle10g_win
7 where
8* "id" between 100 and 104
CORYDORAS> /

id r_varchar_20 bytes
---------- ---------------------------------------- ----------
100 null null
101 null null
102 あ 3
103 12345678901234567890 20
104 1234567890 20

CORYDORAS>

tinytext型、tinyblob型、text型、blob型についてはデータ登録だけを行った。MySQL4.1.13aの同型の検証に含める予定である。
次回は、Generic Connectivity経由で、MySQL4.1.13aの文字型にアクセス。

| | | コメント (0) | トラックバック (0)

2006年3月18日 (土)

Mac De Oracle Heterogeneous! #68

前回のつづき。Generic Connectivyty経由でMySQL4.0.25の文字型にアクセス。五回目。

前回のおさらい。
リモートソートが行われる場合と、そうでない場合があるということであった。
異機種間接続サービスにおいて、コストベースオプティマイザが行う最適化に、リモートソートの排除という記述があるのだが、なにもせず常にそれが行われるということでないようだ。

下記、クエリでは、DML全体がリモートで実行されているため、ソートもリモートソートとなり MySQLのbinary属性のないvarchar型のソート結果(つまり、NULLや空文字が昇順で先頭になり、英字大文字小文字を区別しない)となっている。 

CORYDORAS> l
1 select
2 "id",
3 "r_varchar_20"
4 from
5 varchar_test_mysql4025_mac@oracle10g_win
6 where
7 "id" between 1 and 18
8 order by
9* "r_varchar_20"
CORYDORAS> /

id r_varchar_20
---------- ----------------------------------------
17
18
5 A
6 a
3 B
4 b
1 C
2 c
16 ぁ
11 あ
15 ぃ
10 い
14 ぅ
9 う
13 ぇ
8 え
12 ぉ
7 お

18行が選択されました。

実行計画
----------------------------------------------------------
0 SELECT STATEMENT (REMOTE) Optimizer=ALL_ROWS (Cost=53 Card=5 Bytes=175)
1 0 SORT (ORDER BY) (Cost=53 Card=5 Bytes=175)
2 1 REMOTE* (Cost=52 Card=5 Bytes=175) MYSQL4025_MAC

2 SERIAL_FROM_REMOTE SELECT "id","r_varchar_20" FROM "varchar_tes
t" WHERE "id">=1 AND "id"<=18

統計
----------------------------------------------------------
1 recursive calls
0 db block gets
0 consistent gets
0 physical reads
0 redo size
755 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
18 rows processed

ということで、コストベースオプティマイザの動きを制御できないか? といろいろ調べるた結果、下記の書き換えと、ヒントを利用することにした。
ヒントを利用しなくとも、利用する関数によっては Oracle(ローカル)側でソートするようになるのだが、これも状況次第なので、ご自分の環境で十分なテストを行うことをお勧めする。

まず、該当部分だけをインラインビューに書き換える。(これだけでは全てリモートマップされてしまう)

CORYDORAS> l
1 select *
2 from
3 (
4 select
5 "id",
6 "r_varchar_20"
7 from
8 varchar_test_mysql4025_mac@oracle10g_win
9 where
10 "id" between 1 and 18
11 )
12 order by
13* "r_varchar_20"
CORYDORAS> /

id r_varchar_20
---------- ----------------------------------------
17
18
5 A
6 a
3 B
4 b
1 C
2 c
16 ぁ
11 あ
15 ぃ
10 い
14 ぅ
9 う
13 ぇ
8 え
12 ぉ
7 お

18行が選択されました。

実行計画
----------------------------------------------------------
0 SELECT STATEMENT (REMOTE) Optimizer=ALL_ROWS (Cost=53 Card=5 Bytes=175)
1 0 SORT (ORDER BY) (Cost=53 Card=5 Bytes=175)
2 1 REMOTE* (Cost=52 Card=5 Bytes=175) MYSQL4025_MAC

2 SERIAL_FROM_REMOTE SELECT "id","r_varchar_20" FROM "varchar_tes
t" WHERE "id">=1 AND "id"<=18

統計
----------------------------------------------------------
1 recursive calls
0 db block gets
0 consistent gets
0 physical reads
0 redo size
755 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
18 rows processed

CORYDORAS>

次に、異機種間接続機能向けに使えそうなヒントは NO_MERGEヒント、DRIVING_SITEヒント、REMOTE_MAPPEDヒントのようなのだが、REMOTE_MAPPEDヒントは明文化されていないのとクエリをリモートサイトで実行させるためと思われる名称のヒントであるため対象外とした。

まずは、NO_MERGEヒントから試してみた、

CORYDORAS> set autot on
CORYDORAS> l
1 select *
2 from
3 (
4 select /*+ NO_MERGE */
5 "id",
6 "r_varchar_20"
7 from
8 varchar_test_mysql4025_mac@oracle10g_win
9 where
10 "id" between 1 and 18
11 )
12 order by
13* "r_varchar_20"
CORYDORAS> /

id r_varchar_20
---------- ----------------------------------------
5 A
3 B
1 C
6 a
4 b
2 c
16 ぁ
11 あ
15 ぃ
10 い
14 ぅ
9 う
13 ぇ
8 え
12 ぉ
7 お
17
18

18行が選択されました。

実行計画
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=53 Card=5 Bytes=175)
1 0 SORT (ORDER BY) (Cost=53 Card=5 Bytes=175)
2 1 VIEW (Cost=52 Card=5 Bytes=175)
3 2 REMOTE* (Cost=52 Card=5 Bytes=175) ORACLE10G_WIN

3 SERIAL_FROM_REMOTE SELECT "id","r_varchar_20" FROM "VARCHAR_TES
T_MYSQL4025_MAC" "VARCHAR_TEST_MYSQL

統計
----------------------------------------------------------
0 recursive calls
0 db block gets
0 consistent gets
0 physical reads
0 redo size
812 bytes sent via SQL*Net to client
523 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
18 rows processed

CORYDORAS>
 
思い通りのソート結果を得られた。自動トレースの実行計画、統計情報からソートがローカルデータベース側(つまり、Oracle側)で実行されているという状況を確認できた。


NO_MERGEヒントで目的の結果を得られたので、DRIVING_SITEヒントの確認は省略。
NO_MERGEヒントを利用したクエリとそうでないクエリの実行計画を explain plan文と、utlxpls.sqlスクリプトでさらに確認した結果は以下。

CORYDORAS> l
1 explain plan for
2 select *
3 from
4 (
5 select
6 "id",
7 "r_varchar_20"
8 from
9 varchar_test_mysql4025_mac@oracle10g_win
10 where
11 "id" between 1 and 18
12 )
13 order by
14* "r_varchar_20"
CORYDORAS> /

解析されました。

CORYDORAS> @?/rdbms/admin/utlxpls

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 4028966153

-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT REMOTE| | 5 | 175 | 53 (2)| 00:00:01 |
| 1 | SORT ORDER BY | | 5 | 175 | 53 (2)| 00:00:01 |
| 2 | REMOTE | | 5 | 175 | 52 (0)| 00:00:01 |
-------------------------------------------------------------------------------

Note
-----
- fully remote statement

13行が選択されました。

CORYDORAS> select id,other from plan_table where operation='REMOTE';

ID OTHER
---------- --------------------------------------------------------------------------------
2 SELECT "id","r_varchar_20" FROM "varchar_test" WHERE "id">=1 AND "id"<=18

CORYDORAS>

以下は、NO_MERGEヒントを利用した結果。

CORYDORAS> l
1 explain plan for
2 select *
3 from
4 (
5 select /*+ NO_MERGE */
6 "id",
7 "r_varchar_20"
8 from
9 varchar_test_mysql4025_mac@oracle10g_win
10 where
11 "id" between 1 and 18
12 )
13 order by
14* "r_varchar_20"
CORYDORAS> /

解析されました。

CORYDORAS> @?/rdbms/admin/utlxpls

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 4108374534

-------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 5 | 175 | 53 (2)| 00:00:01 |
| 1 | SORT ORDER BY | | 5 | 175 | 53 (2)| 00:00:01 |
| 2 | VIEW | | 5 | 175 | 52 (0)| 00:00:01 |
| 3 | REMOTE | | 5 | 175 | 52 (0)| 00:00:01 |
-------------------------------------------------------------------------

10行が選択されました。

CORYDORAS> select id,other from plan_table where operation='REMOTE';

ID OTHER
---------- --------------------------------------------------------------------------------
3 SELECT "id","r_varchar_20" FROM "VARCHAR_TEST_MYSQL4025_MAC" "VARCHAR_TEST_MYSQL
       4025_MAC" WHERE "id">=1 AND "id"<=18

CORYDORAS>

さらに、プランスタビリティ機能を利用すればアクセスプランを固定化できるはずである。
今日はここまで、次回へつづく。

| | | コメント (0) | トラックバック (0)

2006年3月16日 (木)

Mac De Oracle Heterogeneous! #67

前回のつづき。Generic Connectivyty経由でMySQL4.0.25の文字型にアクセス。四回目。

2.文字列のソート

ソートする前の状態

CORYDORAS> l
1 select
2 "id",
3 "r_varchar_20",
4 dump("r_varchar_20",16) as hex_sjis
5 from
6 varchar_test_mysql4025_mac@oracle10g_win
7 where
8* "id" between 1 and 18
CORYDORAS> /

id r_varchar_20 HEX_SJIS
---------- ---------------------------------------- --------------------
1 C Typ=1 Len=1: 43
2 c Typ=1 Len=1: 63
3 B Typ=1 Len=1: 42
4 b Typ=1 Len=1: 62
5 A Typ=1 Len=1: 41
6 a Typ=1 Len=1: 61
7 お Typ=1 Len=2: 82,a8
8 え Typ=1 Len=2: 82,a6
9 う Typ=1 Len=2: 82,a4
10 い Typ=1 Len=2: 82,a2
11 あ Typ=1 Len=2: 82,a0
12 ぉ Typ=1 Len=2: 82,a7
13 ぇ Typ=1 Len=2: 82,a5
14 ぅ Typ=1 Len=2: 82,a3
15 ぃ Typ=1 Len=2: 82,a1
16 ぁ Typ=1 Len=2: 82,9f
17 NULL
18 NULL

18行が選択されました。

昇順でソートした結果
CORYDORAS> l
1 select
2 "id",
3 "r_varchar_20",
4 dump("r_varchar_20",16) as hex_sjis
5 from
6 varchar_test_mysql4025_mac@oracle10g_win
7 where
8 "id" between 1 and 18
9 order by
10* "r_varchar_20"
CORYDORAS> /

id r_varchar_20 HEX_SJIS
---------- ---------------------------------------- --------------------
5 A Typ=1 Len=1: 41
3 B Typ=1 Len=1: 42
1 C Typ=1 Len=1: 43
6 a Typ=1 Len=1: 61
4 b Typ=1 Len=1: 62
2 c Typ=1 Len=1: 63
16 ぁ Typ=1 Len=2: 82,9f
11 あ Typ=1 Len=2: 82,a0
15 ぃ Typ=1 Len=2: 82,a1
10 い Typ=1 Len=2: 82,a2
14 ぅ Typ=1 Len=2: 82,a3
9 う Typ=1 Len=2: 82,a4
13 ぇ Typ=1 Len=2: 82,a5
8 え Typ=1 Len=2: 82,a6
12 ぉ Typ=1 Len=2: 82,a7
7 お Typ=1 Len=2: 82,a8
17 NULL
18 NULL

18行が選択されました。

MySQL側ではbinary属性がないと大文字小文字は区別されず、nullや、空文字の扱いも異なるためソート結果が異なるのだが、
Generic Connectivity経由ではbinary属性が無い場合でもソート順に問題はなさそうでだ。。
CORYDORAS> l
1 select
2 "id",
3 "r_varchar_20_binary",
4 dump("r_varchar_20_binary",16) as hex_sjis
5 from
6 varchar_test_mysql4025_mac@oracle10g_win
7 where
8 "id" between 1 and 18
9 order by
10* "r_varchar_20_binary"
CORYDORAS>
CORYDORAS>
CORYDORAS> /

id r_varchar_20_binary HEX_SJIS
---------- ---------------------------------------- --------------------
5 A Typ=1 Len=1: 41
3 B Typ=1 Len=1: 42
1 C Typ=1 Len=1: 43
6 a Typ=1 Len=1: 61
4 b Typ=1 Len=1: 62
2 c Typ=1 Len=1: 63
16 ぁ Typ=1 Len=2: 82,9f
11 あ Typ=1 Len=2: 82,a0
15 ぃ Typ=1 Len=2: 82,a1
10 い Typ=1 Len=2: 82,a2
14 ぅ Typ=1 Len=2: 82,a3
9 う Typ=1 Len=2: 82,a4
13 ぇ Typ=1 Len=2: 82,a5
8 え Typ=1 Len=2: 82,a6
12 ぉ Typ=1 Len=2: 82,a7
7 お Typ=1 Len=2: 82,a8
17 NULL
18 NULL

18行が選択されました。

と安心するのはまだ早い!
クエリの書き方によってソート結果が異なるのだ。
以下の結果を見る限り、リモートソート(以下の場合は、MySQL側でソート処理が行われ、リモートソートの排除が行われていない)が行われているということになる。
CORYDORAS> l
1 select
2 "id",
3 "r_varchar_20"
4 from
5 varchar_test_mysql4025_mac@oracle10g_win
6 where
7 "id" between 1 and 18
8 order by
9* "r_varchar_20"
CORYDORAS> /

id r_varchar_20
---------- ----------------------------------------
17 null
18 null
5 A
6 a
3 B
4 b
1 C
2 c
16 ぁ
11 あ
15 ぃ
10 い
14 ぅ
9 う
13 ぇ
8 え
12 ぉ
7 お

18行が選択されました。

以下に、MySQL側で行ったソート結果を示す。
mysql> edit
-> ¥p
--------------
select
id,
r_varchar_20
from
varchar_test
where
id between 1 and 18
order by
r_varchar_20
--------------

-> ¥g
+----+--------------+
| id | r_varchar_20 |
+----+--------------+
| 17 | NULL |
| 18 | |
| 5 | A |
| 6 | a |
| 3 | B |
| 4 | b |
| 1 | C |
| 2 | c |
| 16 | ぁ |
| 11 | あ |
| 15 | ぃ |
| 10 | い |
| 14 | ぅ |
| 9 | う |
| 13 | ぇ |
| 8 | え |
| 12 | ぉ |
| 7 | お |
+----+--------------+
18 rows in set (0.00 sec)

mysql>

常にリモートソートを排除するようなクエリの書き方は存在するのか?
今日はここまで、次回へつづく。

| | | コメント (0) | トラックバック (0)

2006年3月15日 (水)

Mac De Oracle Heterogeneous! #66

前回のつづき。Generic Connectivyty経由でMySQL4.0.25の文字型にアクセス。三回目。

3)tinytext型、tinyblob型、text型、blob型

Oracleで、blob型というとlob型(ラージオブジェクト)をイメージするが、MySQLでは文字型なので少々戸惑う。Generic Connectivity経由ではどの型にマッピングされているのかを確認したところ、PostgreSQLでlong型にマッピングされていた状況に類似したエラーが返される。

CORYDORAS> col r_tinytext for a40
CORYDORAS> l
1 select
2 "r_tinytext",
3 lengthb("r_tinytext") as "bytes",
4 substr(
5 dump("r_tinytext",16),
6 1,
7 instr(dump("r_tinytext",16),' ')
8 ) as "dump"
9 from
10 varchar_test_mysql4025_mac@oracle10g_win
11 where
12* "id" = 30
CORYDORAS> /
select
*
行1でエラーが発生しました。:
ORA-02070: データベースMYSQL4025_MACはこのコンテキストではLENGTHBをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。

CORYDORAS> col r_tinyblob for a40
CORYDORAS> l
1 select
2 "r_tinyblob",
3 lengthb("r_tinyblob") as "bytes",
4 substr(
5 dump("r_tinyblob",16),
6 1,
7 instr(dump("r_tinyblob",16),' ')
8 ) as "dump"
9 from
10 varchar_test_mysql4025_mac@oracle10g_win
11 where
12* "id" = 30
CORYDORAS> /
select
*
行1でエラーが発生しました。:
ORA-02070: データベースMYSQL4025_MACはこのコンテキストではLENGTHBをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。

CORYDORAS> col r_text for a40
CORYDORAS> l
1 select
2 "r_text",
3 lengthb("r_text") as "bytes",
4 substr(
5 dump("r_text",16),
6 1,
7 instr(dump("r_text",16),' ')
8 ) as "dump"
9 from
10 varchar_test_mysql4025_mac@oracle10g_win
11 where
12* "id" = 31
CORYDORAS> /
select
*
行1でエラーが発生しました。:
ORA-02070: データベースMYSQL4025_MACはこのコンテキストではLENGTHBをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。

CORYDORAS> col r_blob for a40
CORYDORAS> l
1 select
2 "r_blob",
3 lengthb("r_blob") as "bytes",
4 substr(
5 dump("r_blob",16),
6 1,
7 instr(dump("r_blob",16),' ')
8 ) as "dump"
9 from
10 varchar_test_mysql4025_mac@oracle10g_win
11 where
12* "id" = 31
CORYDORAS> /
select
*
行1でエラーが発生しました。:
ORA-02070: データベースMYSQL4025_MACはこのコンテキストではLENGTHBをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。

CORYDORAS>

create table文で確認してみると、はやり、long型にマッピングされている。

CORYDORAS> create table temp_tab as       
2 select "id","r_tinytext" from
3 varchar_test_mysql4025_mac@oracle10g_win
4 where "id" = 30;
select "id","r_tinytext" from
*
行2でエラーが発生しました。:
ORA-00997: LONGデータ型は使用できません。

CORYDORAS> create table temp_tab as
2 select "id","r_tinyblob" from
3 varchar_test_mysql4025_mac@oracle10g_win
4 where "id" = 30;
select "id","r_tinyblob" from
*
行2でエラーが発生しました。:
ORA-00997: LONGデータ型は使用できません。

CORYDORAS> create table temp_tab as
2 select "id","r_text" from
3 varchar_test_mysql4025_mac@oracle10g_win
4 where "id" = 31;
select "id","r_text" from
*
行2でエラーが発生しました。:
ORA-00997: LONGデータ型は使用できません。

CORYDORAS> create table temp_tab as
2 select "id","r_blob" from
3 varchar_test_mysql4025_mac@oracle10g_win
4 where "id" = 31;
select "id","r_blob" from
*
行2でエラーが発生しました。:
ORA-00997: LONGデータ型は使用できません。

CORYDORAS>

MyODBC Driverにはtext型や、blob型の文字列をOracleのvarchar2型にマッピングするようなオプションは存在しないため、直接利用するのであればlong型のまま利用することになる。
MySQL4.0.25 では、PostgreSQLのように、char型や、varchar型で2000バイトや、4000バイトを定義することはできないため、256バイト以上の文字列は、text型か、blob型で定義されている場合が多いと思われる。定義されている表をそのままGeneric Connecvity経由でアクセスするのであれば、long型で利用することになる。
long型で利用するのが不便であれば他の方法を検討するなり、Generic Connectivityを諦める必要はありそうだ。ちなみに、long型にマッピングされているので使いやすいlob型に変換しようと思ってもそう簡単には行かない。
to_lob()関数などの関数はリモート表には利用できないためだ。(long型をうまく扱うための方法を考えなければ。。。)

CORYDORAS> edit
file afiedt.bufが書き込まれました。

1 select
2 "id",to_lob("r_tinytext") as "r_tinytext"
3 from
4 varchar_test_mysql4025_mac@oracle10g_win
5 where
6* "id" = 30
CORYDORAS> /
"id",to_lob("r_tinytext") as "r_tinytext"
*
行2でエラーが発生しました。:
ORA-22992: リモート表から選択されたLOBロケータは使用できません。


今日はここまで。

===================================
いろいろな伏線を張ったまま、放置する可能性もあるので、ご注意を。m(_ _)m 
Generic Connectiviyを利用するどうかの判断は、MySQL、PostgreSQLやODBCのバージョン、プラットフォームに影響される上、実際にどのようなスキーマを持っているかがポイントになる。従って、一概にMySQL4.0.xだから適用できるとか、PostgreSQLだと今ひとつだとか、言い切ることができない。
実システム又は、同等のテスト環境を利用し検証した結果を元に判断するしか無い、というのが現実である。
うまくハマれば、便利な機能であるのも事実。その分かれ目を見極めるためにも検証作業が大切。

| | | コメント (0) | トラックバック (0)

2006年3月14日 (火)

Mac De Oracle Heterogeneous! #65

前回のつづき。Generic Connectivyty経由でMySQL4.0.25の文字型にアクセス。二回目。

1.マッピングされる型の確認

Generic Connectivity経由でMySQL4.0.25の文字型がOracleのどの型にマップされるかを確認。

1)char型

MySQL4.0.25でchar(20)、char(20) binary、char(255)、char(255) binaryとして定義した場合、Oracle側ではchar型にマッピングされる。

CORYDORAS> set null "null"
CORYDORAS> l
1 select
2 "r_char_20",
3 lengthb("r_char_20") as "bytes",
4 substr(
5 dump("r_char_20",16),
6 1,
7 instr(dump("r_char_20",16),' ')
8 ) as "dump"
9 from
10 char_test_mysql4025_mac@oracle10g_win
11 where
12* "id" <= 5
CORYDORAS> /

r_char_20 bytes dump
---------------------------------------- ---------- ----------
あ 20 Typ=96
null null null
20 Typ=96
12345678901234567890 20 Typ=96
1234567890 20 Typ=96

CORYDORAS>
CORYDORAS> l
1 select
2 "r_char_20_binary",
3 lengthb("r_char_20_binary") as "bytes",
4 substr(
5 dump("r_char_20_binary",16),
6 1,
7 instr(dump("r_char_20_binary",16),' ')
8 ) as "dump"
9 from
10 char_test_mysql4025_mac@oracle10g_win
11 where
12* "id" between 6 and 10
CORYDORAS> /

r_char_20_binary bytes dump
---------------------------------------- ---------- ----------
あ 20 Typ=96
null null null
20 Typ=96
12345678901234567890 20 Typ=96
1234567890 20 Typ=96

CORYDORAS>
CORYDORAS> l
1 select
2 "r_char_255",
3 lengthb("r_char_255") as "bytes",
4 substr(
5 dump("r_char_255",16),
6 1,
7 instr(dump("r_char_255",16),' ')
8 ) as "dump"
9 from
10 char_test_mysql4025_mac@oracle10g_win
11 where
12* "id" = 11
CORYDORAS> /

r_char_255 bytes dump
---------------------------------------- ---------- ----------
**************************************** 255 Typ=96
****************************************
****************************************
****************************************
****************************************
****************************************
***************

CORYDORAS>
CORYDORAS> col r_char_255_binary for a40
CORYDORAS> l
1 select
2 "r_char_255_binary",
3 lengthb("r_char_255_binary") as "bytes",
4 substr(
5 dump("r_char_255_binary",16),
6 1,
7 instr(dump("r_char_255_binary",16),' ')
8 ) as "dump"
9 from
10 char_test_mysql4025_mac@oracle10g_win
11 where
12* "id" = 11
CORYDORAS> /

r_char_255_binary bytes dump
---------------------------------------- ---------- ----------
**************************************** 255 Typ=96
****************************************
****************************************
****************************************
****************************************
****************************************
***************

CORYDORAS>


2)varchar型

MySQL4.0.25で、varchar(20)、varchar(20) binary、varchar(255)、varchar(255) binaryとして定義した場合、Oracle側では varchar2型にマッピングされる。

CORYDORAS> l
1 select
2 "r_varchar_20",
3 lengthb("r_varchar_20") as "bytes",
4 substr(
5 dump("r_varchar_20",16),
6 1,
7 instr(dump("r_varchar_20",16),' ')
8 ) as "dump"
9 from
10 varchar_test_mysql4025_mac@oracle10g_win
11 where
12* "id" between 19 and 23
CORYDORAS> /

r_varchar_20 bytes dump
---------------------------------------- ---------- ----------
あ 3 Typ=1
null null null
null null null
12345678901234567890 20 Typ=1
1234567890 20 Typ=1

CORYDORAS>
CORYDORAS> l
1 select
2 "r_varchar_20_binary",
3 lengthb("r_varchar_20_binary") as "bytes",
4 substr(
5 dump("r_varchar_20_binary",16),
6 1,
7 instr(dump("r_varchar_20_binary",16),' ')
8 ) as "dump"
9 from
10 varchar_test_mysql4025_mac@oracle10g_win
11 where
12* "id" between 24 and 28
CORYDORAS> /

r_varchar_20_binary bytes dump
---------------------------------------- ---------- ----------
あ 3 Typ=1
null null null
null null null
12345678901234567890 20 Typ=1
1234567890 20 Typ=1

CORYDORAS>
CORYDORAS> col r_varchar_255 for a40
CORYDORAS> l
1 select
2 "r_varchar_255",
3 lengthb("r_varchar_255") as "bytes",
4 substr(
5 dump("r_varchar_255",16),
6 1,
7 instr(dump("r_varchar_255",16),' ')
8 ) as "dump"
9 from
10 varchar_test_mysql4025_mac@oracle10g_win
11 where
12* "id" = 29
CORYDORAS> /

r_varchar_255 bytes dump
---------------------------------------- ---------- ----------
**************************************** 255 Typ=1
****************************************
****************************************
****************************************
****************************************
****************************************
***************

CORYDORAS>
CORYDORAS> col r_varchar_255_binary for a40
CORYDORAS> l
1 select
2 "r_varchar_255_binary",
3 lengthb("r_varchar_255_binary") as "bytes",
4 substr(
5 dump("r_varchar_255_binary",16),
6 1,
7 instr(dump("r_varchar_255_binary",16),' ')
8 ) as "dump"
9 from
10 varchar_test_mysql4025_mac@oracle10g_win
11 where
12* "id" = 29
CORYDORAS> /

r_varchar_255_binary bytes dump
---------------------------------------- ---------- ----------
**************************************** 255 Typ=1
****************************************
****************************************
****************************************
****************************************
****************************************
***************

CORYDORAS>

今日はここまで。

| | | コメント (0) | トラックバック (0)

2006年3月13日 (月)

Mac De Oracle Heterogeneous! #64

前回のつづき
今回から、Generic Connectivity経由でPowerBook G4 MacOSX 10.4.5のMySQL4.0.25及び、PowerMac G5 Dual2.7GhzのMySQL4.1.13aの文字型にアクセスし、その挙動を検証する。

アクセス経路は以下

gencon_blog_mac_my


MySQL4.0.25及び、MySQL4.1.13aには、以前の記事で解説したような理由から、このような2表を作成してある。

Generic Connectivyty経由でMySQL4.0.25の文字型にアクセス。一回目。

MySQL4.0.25のchar_test表には以下のデータを登録しておく。

mysql> select
-> id,
-> r_char_20,
-> r_char_20_binary
-> from
-> char_test;
+----+----------------------+----------------------+
| id | r_char_20 | r_char_20_binary |
+----+----------------------+----------------------+
| 1 | あ | NULL |
| 2 | NULL | NULL |
| 3 | | NULL |
| 4 | 12345678901234567890 | NULL |
| 5 | 1234567890 | NULL |
| 6 | NULL | あ |
| 7 | NULL | NULL |
| 8 | NULL | |
| 9 | NULL | 12345678901234567890 |
| 10 | NULL | 1234567890 |
+----+----------------------+----------------------+
10 rows in set (0.02 sec)

mysql>
mysql> select
-> id,
-> length(r_char_255),
-> length(r_char_255_binary)
-> from
-> char_test
-> where
-> id = 11;
+----+--------------------+---------------------------+
| id | length(r_char_255) | length(r_char_255_binary) |
+----+--------------------+---------------------------+
| 11 | 255 | 255 |
+----+--------------------+---------------------------+
1 row in set (0.26 sec)

mysql>

MySQL4.0.25のvarchar_test表には以下のデータを登録しておく。

mysql> select
-> id,
-> r_varchar_20,
-> r_varchar_20_binary
-> from
-> varchar_test;
+----+--------------+---------------------+
| id | r_varchar_20 | r_varchar_20_binary |
+----+--------------+---------------------+
| 1 | C | C |
| 2 | c | c |
| 3 | B | B |
| 4 | b | b |
| 5 | A | A |
| 6 | a | a |
| 7 | お | お |
| 8 | え | え |
| 9 | う | う |
| 10 | い | い |
| 11 | あ | あ |
| 12 | ぉ | ぉ |
| 13 | ぇ | ぇ |
| 14 | ぅ | ぅ |
| 15 | ぃ | ぃ |
| 16 | ぁ | ぁ |
| 17 | NULL | NULL |
| 18 | | |
+----+--------------+---------------------+
18 rows in set (0.00 sec)

mysql>
mysql> select
-> id,
-> r_varchar_20,
-> r_varchar_20_binary
-> from
-> varchar_test
-> where
-> id between 19 and 28;
+----+----------------------+----------------------+
| id | r_varchar_20 | r_varchar_20_binary |
+----+----------------------+----------------------+
| 19 | あ | NULL |
| 20 | NULL | NULL |
| 21 | | NULL |
| 22 | 12345678901234567890 | NULL |
| 23 | 1234567890 | NULL |
| 24 | NULL | あ |
| 25 | NULL | NULL |
| 26 | NULL | |
| 27 | NULL | 12345678901234567890 |
| 28 | NULL | 1234567890 |
+----+----------------------+----------------------+
10 rows in set (0.42 sec)

mysql>
mysql> select
-> id,
-> length(r_varchar_255),
-> length(r_varchar_255_binary),
-> length(r_tinytext),
-> length(r_tinyblob),
-> length(r_text),
-> length(r_blob)
-> from
-> varchar_test
-> where
-> id between 29 and 34;
+----+-----------------------+------------------------------+--------------------+--------------------+----------------+----------------+
| id | length(r_varchar_255) | length(r_varchar_255_binary) | length(r_tinytext) | length(r_tinyblob) | length(r_text) | length(r_blob) |
+----+-----------------------+------------------------------+--------------------+--------------------+----------------+----------------+
| 29 | 255 | 255 | NULL | NULL | NULL | NULL |
| 30 | NULL | NULL | 255 | 255 | NULL | NULL |
| 31 | NULL | NULL | NULL | NULL | 2000 | 2000 |
| 32 | NULL | NULL | NULL | NULL | 2001 | 2001 |
| 33 | NULL | NULL | NULL | NULL | 4000 | 4000 |
| 34 | NULL | NULL | NULL | NULL | 4001 | 4001 |
+----+-----------------------+------------------------------+--------------------+--------------------+----------------+----------------+
6 rows in set (0.01 sec)

mysql>


準備が出来たところで、つづきは次回。

| | | コメント (0) | トラックバック (0)

2006年3月12日 (日)

Mac De Oracle Heterogeneous! #63

続きです。Generic Connectivity経由でPostgreSQL7.4.9の文字型にアクセス 最終回のつづき(なんじゃそりゃ)。

=========まとめ=======

利用しているODBC driverはこちらで解説しているドライバー

Generic Connectivityの文字型マッピング
PostgreSQL7.4.9Oracle10g R1Generic Connectivityでの利用備 考
char型 char型 PostgreSQLでのchar型の定義とODBCデータソースのvarchar型最大サイズの設定によりマップされる型が異なる。

char(n)の n が、ODBC データソースの設定でVARCHAR型最大サイズ以下である場合、char型にマップされる。

ただし、本テストでは、n=1024でvarchar2型にマップされた。(255〜1024のどの値でchar型からvarchar2型に切り替わるのかは未確認。単なるバグなのか??)。

n > ODBCデータソースの設定のVARCHRA型最大サイズである場合には、long型にマップされる。

また、Oracle側にマッピングされる際は、常にバイトセマンティクスとして解釈されるため、PostgreSQL側の文字型にマルチバイトが格納されている場合且つ、バイトサイズが n を超える文字は切り捨てられる点に注意すること。そのような列をアクセスする必要がある場合には、PostgreSQL側の影響がなければ、PostgreSQL側の文字型の最大サイズを大きくすることで対応可能だろう。また、これも影響がないことが前提だが、text型に変更して文字の切り捨てを防ぐという方法も使えるかもしれないが、その場合、long型にマッピングされるので要注意。影響が大きくそのような対処ができないのならば、Generic Connectivityを利用せず、外部表を利用したり他の方法を考えたほうが無難。ストアドプロシージャを利用して解決する方法もあるかもしれないが未確認である。
varchar2型
long型
varchar型 varchar2型 PostgreSQLでのvarchar型の定義とODBCデータソースのvarchar型最大サイズの設定によりマップされる型が異なる。

varchar(n)の n が、ODBC データソースの設定でVARCHAR型最大サイズ以下である場合、varchar型にマップされる。

n > ODBCデータソースの設定のVARCHRA型最大サイズである場合には、long型にマップされる。

また、Oracle側にマッピングされる際は、常にバイトセマンティクスとして解釈されるため、PostgreSQL側の文字型にマルチバイトが格納されている場合且つ、バイトサイズが n を超える文字は切り捨てられる点に注意すること。そのような列をアクセスする必要がある場合には、PostgreSQL側の影響がなければ、PostgreSQL側の文字型の最大サイズを大きくすることで対応可能だろう。また、これも影響がないことが前提だが、text型に変更して文字の切り捨てを防ぐという方法も使えるかもしれないが、その場合、long型にマッピングされるので要注意。影響が大きくそのような対処ができないのならば、Generic Connectivityを利用せず、外部表を利用したり他の方法を考えたほうが無難。ストアドプロシージャを利用して解決する方法もあるかもしれないが未確認である。
long型
text型 long型 通常は、long型にマッピングされるが、ODBCデータソーソの設定で、「text型を長文字列として扱う」をチェックしなければ、varchar2型にマッピング(本当にマッピングされるか未確認。m(_ _)m )される。
varchar2型
(未確認)

ソート時の注意
PostgreSQLでは、空文字は、NULLとは区別されているが、Oracleは、空文字をNULLとして扱うので注意が必要である。例として検索時に、 where 列名 = '' 又は、 where 列名 != ''と記述した場合、Oracleでは、 列名 = NULL 又は、列名 != NULLと解釈され不定され正しい結果は得られない、 '' は利用せず、 列名 IS NULL又は、 列名 IS NOT NULLと書くべし。(Oracleを長年利用してきた方ならば間違うことはない事なのだが・・・)

次回、こんどこそ本当にMySQLの文字型にアクセスへつづく。

| | | コメント (0) | トラックバック (0)

2006年3月11日 (土)

Mac De Oracle Heterogeneous! #62

続きです。Generic Connectivity経由でPostgreSQL7.4.9の文字型にアクセス 最終回。

5)文字ソート

空文字は、Oracle側では、NULLとして扱われる点に注意。

CORYDORAS> l
1 select
2 "id",
3 "r_varchar_20",
4 lengthb("r_varchar_20"),
5 dump("r_varchar_20",16) as hex_sjis
6 from
7 char_test_postgresql749_mac@oracle10g_win
8 where
9 "id" between 1 and 18
10 order by
11* "r_varchar_20"
CORYDORAS> /

id r_varchar_20 LENGTHB("R_VARCHAR_20") HEX_SJIS
---------- -------------------- ----------------------- --------------------
5 A 1 Typ=1 Len=1: 41
3 B 1 Typ=1 Len=1: 42
1 C 1 Typ=1 Len=1: 43
6 a 1 Typ=1 Len=1: 61
4 b 1 Typ=1 Len=1: 62
2 c 1 Typ=1 Len=1: 63
16 ぁ 2 Typ=1 Len=2: 82,9f
11 あ 2 Typ=1 Len=2: 82,a0
15 ぃ 2 Typ=1 Len=2: 82,a1
10 い 2 Typ=1 Len=2: 82,a2
14 ぅ 2 Typ=1 Len=2: 82,a3
9 う 2 Typ=1 Len=2: 82,a4
13 ぇ 2 Typ=1 Len=2: 82,a5
8 え 2 Typ=1 Len=2: 82,a6
12 ぉ 2 Typ=1 Len=2: 82,a7
7 お 2 Typ=1 Len=2: 82,a8
17 NULL NULL NULL
18 NULL NULL NULL

18行が選択されました。

CORYDORAS>

=======おまけ========

6) 文字を登録。

利用できる関数はかなり制限されているのだが、DMLをパススルーしてやればなんとかなるだろうね。(以前実験済み

CORYDORAS> list
1 insert into char_test_postgresql749_mac@oracle10g_win("id","r_varchar_4000")
2 values(101,lpad('*',4000,'*'))
CORYDORAS> /
insert into char_test_postgresql749_mac@oracle10g_win("id","r_varchar_4000")
*
行1でエラーが発生しました。:
ORA-02070: データベースPOSTGRESQL749_MACはこのコンテキストではLPADをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。


CORYDORAS> insert into
2 char_test_postgresql749_mac@oracle10g_win("id","r_varchar_20")
3 values(101,'01234567890');
insert into
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][A0C9] Value for column r_varchar_20 exceeds column's length.
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> edit
file afiedt.bufが書き込まれました。

1 insert into
2 char_test_postgresql749_mac@oracle10g_win("id","r_varchar_20")
3* values(101,'0123456789')
CORYDORAS> /

1行が作成されました。

CORYDORAS> rollback;

ロールバックが完了しました。

CORYDORAS>
CORYDORAS> insert into
2 char_test_postgresql749_mac@oracle10g_win("id","r_char_20")
3 values(101,'012345678901234567890');
insert into
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][A0C9] Value for column r_char_20 exceeds column's length.
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> edit
file afiedt.bufが書き込まれました。

1 insert into
2 char_test_postgresql749_mac@oracle10g_win("id","r_char_20")
3* values(101,'01234567890123456789')
CORYDORAS> /

1行が作成されました。


次回、Generic Connectivity経由でPostgreSQL7.4.9の文字型をアクセスする場合の注意点などのまとめへつづく。

| | | コメント (0) | トラックバック (0)

2006年3月10日 (金)

Mac De Oracle Heterogeneous! #61

続きです。Generic Connectivity経由でPostgreSQL7.4.9の文字型にアクセス 五回目。

前回は、PostgreSQL7.4.9のchar(2000)がOracleのlong型にマッピングされているという状況だった。
ということで、PostgreSQL7.4.9のchar型、varchar型が、Oracleのchar型又は、varchar2型にマッピングされるのか、long型にマッピングされるのか? その境界値を探る。また、その値を変更することは可能なのかも合わせて調査する。(ODBCの影響が一番強いと思うのだが。。。)

4−1)100バイトは?
char(100)及び、varchar(100)として定義したデータは、それぞれ、Oracleのchar型、varchar2型として 問い合わせる事ができた。

CORYDORAS> select dump("char100") from char_len_tet_postgresql749_mac@oracle10g_win;

DUMP("CHAR100")
--------------------------------------------------------------------------------
Typ=96 Len=100: 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,4
2,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,
42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42
,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42

CORYDORAS> select dump("varchar100") from char_len_tet_postgresql749_mac@oracle10g_win;

DUMP("VARCHAR100")
--------------------------------------------------------------------------------
Typ=1 Len=100: 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42
,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,4
2,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,
42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42

4−2)255バイトではどう?
char(255)として定義した列は LONG型にマッピングされている。101文字以上255文字未満ということのようだ。

CORYDORAS> select dump("char255") from char_len_tet_postgresql749_mac@oracle10g_win;
select dump("char255") from char_len_tet_postgresql749_mac@oracle10g_win
*
行1でエラーが発生しました。:
ORA-02070:
データベースPOSTGRESQL749_MACはこのコンテキストではDUMPをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。


そこで、思い出したのが、psqlODBCのデータソースの設定。

odbc_before

4−3)じゃ、254バイトまでだな!!
varcharの最大サイズが254文字に設定されているので char(254)として定義した列を問い合わせると、正しく問い合わせる事ができた。

CORYDORAS> select dump("char254") from char_len_tet_postgresql749_mac@oracle10g_win;

DUMP("CHAR254")
--------------------------------------------------------------------------------
Typ=96 Len=254: 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,4
2,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,

中略

,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,4
2,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,
42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42
,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42

4−4)ODBCのvarchar型の最大サイズを4000バイトにしてみた!

psqlODBCの設定を254から 4000に変更した。

odbc_after


char(254)はいままで通りで問題ない。

CORYDORAS> select dump("char254") from char_len_tet_postgresql749_mac@oracle10g_win;

DUMP("CHAR254")
--------------------------------------------------------------------------------
Typ=96 Len=254: 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,4
2,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,
42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42
,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,4
2,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,

中略

42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42
,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42

さて、次が問題なのだが、お〜〜。うまく問い合わせることができた。

CORYDORAS> select dump("char255") from char_len_tet_postgresql749_mac@oracle10g_win;

DUMP("CHAR255")
--------------------------------------------------------------------------------
Typ=96 Len=255: 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,4
2,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,

中略

42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42
,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42

char(1024)として定義した列なのでが、Oracle側のchar型ではなく、varchar2型にマッピングされてはいるものの、問題なく問い合わせることができた。(Oracleのchar型ではなく、varchar2型にマッピングされてしまったことによる問題は多少あるだろうね)
CORYDORAS> select dump("char1024") from char_len_tet_postgresql749_mac@oracle10g_win;

DUMP("CHAR1024")
--------------------------------------------------------------------------------
Typ=1 Len=1024: 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,4
2,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,
42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42

中略

42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,4
2,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,
42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42

varchar(1024)として定義した列も正常に問い合わせることができた。こちらもvarchar2型にマッピングされた。

CORYDORAS> select dump("varchar1024") from char_len_tet_postgresql749_mac@oracle10g_win;

DUMP("VARCHAR1024")
--------------------------------------------------------------------------------
Typ=1 Len=1024: 42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,4
2,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,
42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42

中略

,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,4
2,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,
42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42

CORYDORAS>

PostgreSQL7.4.9のchar型及び、varchar型をGeneric Connectivity経由で利用する場合には、psqlODBCのvarchar型の最大サイズの調整しないと、255バイト以上のデータはSQL_LONGVARCHARというODBCデータ型にマッピングされ、結果的に、Oracle型ではLONG型にマッピングされる。psqlODBCのvarchar型最大サイズを調整すればなんとか対応できそうではある。(ODBC Driver次第なので、不安もあるが・・・ま、いいか。)
とちょっとだけ、ほっとしたところで、次回へつづく。

| | | コメント (0) | トラックバック (0)

2006年3月 9日 (木)

Mac De Oracle Heterogeneous! #60

続きです。Generic Connectivity経由でPostgreSQL7.4.9の文字型にアクセス 四回目。

4)Oracleのchar型、varchar2型の最大サイズ及び、それを超えるサイズで定義した列にアクセス。

以下、問い合わせた結果。

CORYDORAS> select 
2 "id",
3 lengthb("r_char_2000"),
4 lengthb("r_char_2001"),
5 lengthb("r_varchar_4000"),
6 lengthb("r_varchar_4001")
7 from
8 char_test_postgresql749_mac@oracle10g_win
9 where
10 "id" between 34 and 35;
select
*
行1でエラーが発生しました。:
ORA-02070: データベースPOSTGRESQL749_MACはこのコンテキストではLENGTHBをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。

おや? これは、text型の時と同じ症状?!にみえる。

CORYDORAS> edit
file afiedt.bufが書き込まれました。

1 select
2 "id",
3 "r_char_2000"
4 from
5 char_test_postgresql749_mac@oracle10g_win
6 where
7* "id" between 34 and 35
CORYDORAS> /

id r_char_2000
---------- --------------------------------------------------------------------------------
34 ********************************************************************************
35 NULL

単純に問い合わせる事はできるようだ。とすると・・・・・。

CORYDORAS> create table temp1
2 as select "id","r_char_2000"
3 from char_test_postgresql749_mac@oracle10g_win
4 where "id" = 34;
as select "id","r_char_2000"
*
行2でエラーが発生しました。:
ORA-00997: LONGデータ型は使用できません。

やっぱり! long型にマッピングされている!

ちなみに、以下すべてが long型にマッピングされている。char(20)やvarchar(20)ではchar型、varchar2型にマッピングされていたが、long型に切り替えられる境界は? その境界を調整できるのだろうか?(別途調査予定)

CORYDORAS> edit
file afiedt.bufが書き込まれました。

1 create table temp1
2 as select "id","r_char_2001"
3 from char_test_postgresql749_mac@oracle10g_win
4* where "id" = 34
CORYDORAS> /
as select "id","r_char_2001"
*
行2でエラーが発生しました。:
ORA-00997: LONGデータ型は使用できません。


CORYDORAS> edit
file afiedt.bufが書き込まれました。

1 create table temp1
2 as select "id","r_varchar_4000"
3 from char_test_postgresql749_mac@oracle10g_win
4* where "id" = 35
CORYDORAS> /
as select "id","r_varchar_4000"
*
行2でエラーが発生しました。:
ORA-00997: LONGデータ型は使用できません。


CORYDORAS> edit
file afiedt.bufが書き込まれました。

1 create table temp1
2 as select "id","r_varchar_4001"
3 from char_test_postgresql749_mac@oracle10g_win
4* where "id" = 35
CORYDORAS> /
as select "id","r_varchar_4001"
*
行2でエラーが発生しました。:
ORA-00997: LONGデータ型は使用できません。


CORYDORAS>

さてどうしよう・・・・。


次回へつづく。

| | | コメント (0) | トラックバック (0)

2006年3月 8日 (水)

Mac De Oracle Heterogeneous! #59

続きです。Generic Connectivity経由でPostgreSQL7.4.9の文字型にアクセス 三回目。

3)text型として定義した列を問い合わせる

以下、問い合わせた結果。

CORYDORAS> select
2 "id",
3 lengthb("r_text"),
4 length("r_text"),
5 substr(dump("r_text",16),1,7),
6 "r_text"
7 from
8 char_test_postgresql749_mac@oracle10g_win
9 where
10 "id" between 29 and 33;
select
*
行1でエラーが発生しました。:
ORA-02070: データベースPOSTGRESQL749_MACはこのコンテキストではLENGTHBをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。

CORYDORAS> edit
file afiedt.bufが書き込まれました。

1 select
2 "id",
3 substr(dump("r_text",16),1,7),
4 "r_text"
5 from
6 char_test_postgresql749_mac@oracle10g_win
7 where
8* "id" between 29 and 33
CORYDORAS> /
select
*
行1でエラーが発生しました。:
ORA-02070: データベースPOSTGRESQL749_MACはこのコンテキストではSUBSTRをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。

CORYDORAS> edit
file afiedt.bufが書き込まれました。

1 select
2 "id",
3 "r_text"
4 from
5 char_test_postgresql749_mac@oracle10g_win
6 where
7* "id" between 29 and 33
CORYDORAS> /

id r_text
---------- --------------------------------------------------------------------------------
29 あ
30 NULL
31 NULL
32 12345678901234567890
33 12345678901234567890

CORYDORAS> edit
file afiedt.bufが書き込まれました。

1 select
2 "id",
3 dump("r_text",16),
4 "r_text"
5 from
6 char_test_postgresql749_mac@oracle10g_win
7 where
8* "id" between 29 and 33
CORYDORAS> /
select
*
行1でエラーが発生しました。:
ORA-02070: データベースPOSTGRESQL749_MACはこのコンテキストではDUMPをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。

CORYDORAS> create table temp as
2 select
3 "id",
4 "r_text"
5 from
6 char_test_postgresql749_mac@oracle10g_win
7 where
8 "id" between 29 and 33;
"r_text"
*
行4でエラーが発生しました。:
ORA-00997: LONGデータ型は使用できません。

CORYDORAS>

PostgreSQLのtext型は、Oracleのlong型にマッピングされる。
単純に問い合わせるだけならchar(20)や、varchar(20)の場合のような文字の切り捨ては発生しないためよさそうなのだが、long型は対応している関数が少ないので注意が必要だ。(他の型、例えば、CLOB型などに変換してから利用すれば使い勝手もよくできるかもしれないが、さらに検証が必要だ。)


今日はここまで。次回へつづく。

| | | コメント (0) | トラックバック (0)

2006年3月 7日 (火)

Mac De Oracle Heterogeneous! #58

続きです。Generic Connectivity経由でPostgreSQL7.4.9の文字型にアクセス 二回目。

1. char型

1) char(20)として定義した列を問い合わせる

以下、問い合わせた結果。

CORYDORAS> set null 'NULL'
CORYDORAS> list
1 select
2 "id",
3 lengthb("r_char_20"),
4 length("r_char_20"),
5 substr(dump("r_char_20",16),1,7),
6 "r_char_20"
7 from
8 char_test_postgresql749_mac@oracle10g_win
9 where
10* "id" between 19 and 23
CORYDORAS> /

id LENGTHB("R_CHAR_20") LENGTH("R_CHAR_20") SUBSTR(DUMP("R r_char_20
---------- -------------------- ------------------- -------------- --------------------
19 20 19 Typ=96 あ
20 NULL NULL NULL NULL
21 20 20 Typ=96
22 20 20 Typ=96 12345678901234567890
23 20 10 Typ=96 1234567890

CORYDORAS>

char(20)は、Oracle側のchar型にマップされている。 
PostgreSQL上で問い合わせた結果と比較すると、文字数やバイト数が1文字及び1バイトづつ少ない。ODBCの問題である可能性も無いとは言えないが、Oracleはバイトセマンティクスでchar(20)をハンドリングしているようにみえる。id=19,23のデータは文字が切り捨てられている点に注意してもらいたい。ただ、20バイトで単純に切り捨てられているということではなく、文字列として20バイト以内に収まる文字数で切り捨てられているようにも見える。'1234567890123456789あ' という20文字を登録しておき、Generic Connectivity経由でOralce側から問い合わせると、'1234567890123456789'が返されたためだなのだが、状況証拠だけなので偶々という可能性もある。尚、alter session文で、バイトセマンティクスから文字セマンティクスに変更しても状況は変わらない。
PostgreSQLのchar(20)を Oracleのchar(20 char)にマッピングする回避方法はあるのか? 無理矢理だがPostgreSQL側のchar(20)をchar(40)へ変更してしまうという方法で回避できるようならそれでもよいかもしれないが、列サイズの変更により既存プログラムへの影響が懸念される。それ以外の方法としては外部表がお手軽かもしれない。他にはパススルークエリーを利用すればなんとかなるか??。(パススルークエリを利用した回避方法は別途調査してみるか・・)


2)varchar(20)として定義した列を問い合わせる

以下、問い合わせた結果

CORYDORAS> l
1 select
2 "id",
3 lengthb("r_varchar_20"),
4 length("r_varchar_20"),
5 substr(dump("r_varchar_20",16),1,7),
6 "r_varchar_20"
7 from
8 char_test_postgresql749_mac@oracle10g_win
9 where
10* "id" between 24 and 28
CORYDORAS> /

id LENGTHB("R_VARCHAR_20") LENGTH("R_VARCHAR_20") SUBSTR(DUMP("R r_varchar_20
---------- ----------------------- ---------------------- -------------- --------------------
24 4 3 Typ=1 L あ
25 NULL NULL NULL NULL
26 NULL NULL NULL NULL
27 20 20 Typ=1 L 12345678901234567890
28 20 10 Typ=1 L 1234567890

CORYDORAS>

varchar(20)は、Oracleのvarchar2型にマップされている。注意する点は、char(20)のid=23のデータと同じ。

今日はここまで。次回につづく。

| | | コメント (0) | トラックバック (0)

2006年3月 6日 (月)

Mac De Oracle Heterogeneous! #57

前回のつづき、Generic Connectivity経由でPostgreSQL7.4.9の文字型にアクセス 一回目。

アクセス経路は以下の通り。

gencon_blog_mac_pos

PostgreSQL7.4.9には以下のような表を作成した。
Oracleへのマッピングも考慮し、Oracleのchar型及び、varchar2型の最大サイズ及び、最大サイズを超えるサイズで定義した。

postgresql749=> ¥d char_test;
Table "scott.char_test"
Column | Type | Modifiers
----------------+-------------------------+-----------
id | integer | not null
r_char_20 | character(20) |
r_char_2000 | character(2000) |
r_char_2001 | character(2001) |
r_varchar_20 | character varying(20) |
r_varchar_4000 | character varying(4000) |
r_varchar_4001 | character varying(4001) |
r_text | text |
Indexes:
"char_test_pkey" primary key, btree (id)

postgresql749=>

事前に以下のデータを登録してある。

 id | r_varchar_20 | octet_length | hex_euc | hex_sjis | hex_utf8 
----+--------------+--------------+---------+----------+----------
18 | | 0 | | |
5 | A | 1 | 41 | 41 | 41
3 | B | 1 | 42 | 42 | 42
1 | C | 1 | 43 | 43 | 43
6 | a | 1 | 61 | 61 | 61
4 | b | 1 | 62 | 62 | 62
2 | c | 1 | 63 | 63 | 63
16 | ぁ | 2 | a4a1 | 829f | e38181
11 | あ | 2 | a4a2 | 82a0 | e38182
15 | ぃ | 2 | a4a3 | 82a1 | e38183
10 | い | 2 | a4a4 | 82a2 | e38184
14 | ぅ | 2 | a4a5 | 82a3 | e38185
9 | う | 2 | a4a6 | 82a4 | e38186
13 | ぇ | 2 | a4a7 | 82a5 | e38187
8 | え | 2 | a4a8 | 82a6 | e38188
12 | ぉ | 2 | a4a9 | 82a7 | e38189
7 | お | 2 | a4aa | 82a8 | e3818a
17 | | | | |
(18 rows)

postgresql749=>

postgresql749=> select
postgresql749-> id,
postgresql749-> r_char_20,
postgresql749-> length(r_char_20) as length,
postgresql749-> octet_length(r_char_20) as octet_length
postgresql749-> from
postgresql749-> char_test
postgresql749-> where
postgresql749-> id between 19 and 23;
id | r_char_20 | length | octet_length
----+------------------------------------------+--------+--------------
19 | あ | 20 | 21
20 | | |
21 | | 20 | 20
22 | 12345678901234567890 | 20 | 20
23 | 12345678901234567890 | 20 | 40
(5 rows)

postgresql749=>

postgresql749=> select
postgresql749-> id,
postgresql749-> r_varchar_20,
postgresql749-> length(r_varchar_20) as length,
postgresql749-> octet_length(r_varchar_20) as octet_length
postgresql749-> from
postgresql749-> char_test
postgresql749-> where
postgresql749-> id between 24 and 28;
id | r_varchar_20 | length | octet_length
----+------------------------------------------+--------+--------------
24 | あ | 3 | 4
25 | | |
26 | | 0 | 0
27 | 12345678901234567890 | 20 | 20
28 | 12345678901234567890 | 20 | 40
(5 rows)

postgresql749=>

postgresql749=> select
postgresql749-> id,
postgresql749-> r_text,
postgresql749-> length(r_text) as length,
postgresql749-> octet_length(r_text) as octet_length
postgresql749-> from
postgresql749-> char_test
postgresql749-> where
postgresql749-> id between 29 and 33;
id | r_text | length | octet_length
----+------------------------------------------+--------+--------------
29 | あ | 3 | 4
30 | | |
31 | | 0 | 0
32 | 12345678901234567890 | 20 | 20
33 | 12345678901234567890 | 20 | 40
(5 rows)

postgresql749=>

postgresql749=> select
postgresql749-> octet_length(r_char_2000),
postgresql749-> octet_length(r_char_2001),
postgresql749-> octet_length(r_varchar_4000),
postgresql749-> octet_length(r_varchar_4001)
postgresql749-> from
postgresql749-> char_test
postgresql749-> where
postgresql749-> id between 34 and 35;
octet_length | octet_length | octet_length | octet_length
--------------+--------------+--------------+--------------
2000 | 2001 | |
| | 4000 | 4001
(2 rows)

postgresql749=>

次回へつづく。

| | | コメント (0) | トラックバック (0)

2006年3月 5日 (日)

Mac De Oracle Heterogeneous! #56

前回からのつづき。Generic Connectivity経由でMySQL4.0.25、MySQL4.1.13a及び、PostgreSQL7.4.9の文字型にアクセス。(準備)

まず、Windows XP上で踏み台にするOracle10g にMySQL4.0.25、MySQL4.1.13a及び、PostgreSQL7.4.9の各表をアクセスするためのシノニムを作成する。(この例では、プライベートシノニム)

Generic Connectivity用のデータベースリンクを介してアクセスする各表をシノニムとして定義し、
そのシノニムへMacOSX上のOracle10gからOracleの分散データベース機能を利用してアクセスする。この方法で、現時点ではGeneric Connectivityが実装されていないMacOSX上のOracle10gから異機種データベースをアクセスする。

尚、Generic Connectivity経由で、MySQL4.1.13aへ発行する count()関数は正しい結果を得られないためrownum疑似列をmax()関数で取得するという方法で代用している。

作業は赤で囲んだOracle10g上で行っている。

gencon_blog_win_ora


SQL> create synonym char_test_postgresql749_mac for "char_test"@postgresql749_mac;

シノニムが作成されました。

SQL> create synonym char_test_mysql4025_mac for "char_test"@mysql4025_mac;

シノニムが作成されました。

SQL> create synonym varchar_test_mysql4025_mac for "varchar_test"@mysql4025_mac;

シノニムが作成されました。

SQL> create synonym char_test_mysql4113a_mac_sv for "char_test"@mysql4113a_mac_sv;

シノニムが作成されました。

SQL> create synonym varchar_test_mysql4113a_mac_sv for "varchar_test"@mysql4113a_mac_sv;

シノニムが作成されました。

SQL> select synonym_name,table_name,substr(db_link,1,20) as db_link from user_synonyms;

SYNONYM_NAME TABLE_NAME DB_LINK
------------------------------ -------------------- --------------------
EMP_MYSQL4025_MAC emp MYSQL4025_MAC
INNO_EMP_MYSQL4025_MAC inno_emp MYSQL4025_MAC
EMP_MYSQL4026_WIN emp MYSQL4026_WIN
EMP_MYSQL4113A_MAC_SV emp MYSQL4113A_MAC_SV
EMP_POSTGRESQL749_MAC emp POSTGRESQL749_MAC
ORACLE_EMP_MYSQL4026_WIN oracle_emp MYSQL4026_WIN
DATE_TEST_MYSQL4026_WIN date_test MYSQL4026_WIN
DATE_TEST_MYSQL4113A_MAC_SV date_test MYSQL4113A_MAC_SV
DATE_TEST_POSTGRESQL749_MAC date_test POSTGRESQL749_MAC
NUM_TEST_POSTGRESQL749_MAC num_test POSTGRESQL749_MAC
NUM_TEST_MYSQL4113A_MAC_SV num_test MYSQL4113A_MAC_SV
NUM_TEST_MYSQL4025_MAC num_test MYSQL4025_MAC
CHAR_TEST_POSTGRESQL749_MAC char_test POSTGRESQL749_MAC
CHAR_TEST_MYSQL4025_MAC char_test MYSQL4025_MAC
VARCHAR_TEST_MYSQL4025_MAC varchar_test MYSQL4025_MAC
CHAR_TEST_MYSQL4113A_MAC_SV char_test MYSQL4113A_MAC_SV
VARCHAR_TEST_MYSQL4113A_MAC_SV varchar_test MYSQL4113A_MAC_SV

17行が選択されました。

SQL>
SQL> select count(*) from char_test_postgresql749_mac;

COUNT(*)
----------
35

SQL> select count(*) from char_test_mysql4025_mac;

COUNT(*)
----------
11

SQL> select count(*) from varchar_test_mysql4025_mac;

COUNT(*)
----------
34

SQL> select count(*) from char_test_mysql4113a_mac_sv;

COUNT(*)
----------
12593

SQL> select count(*) from varchar_test_mysql4113a_mac_sv;

COUNT(*)
----------
13363

SQL> select max(rownum) from char_test_mysql4113a_mac_sv;

MAX(ROWNUM)
-----------
11

SQL> select max(rownum) from varchar_test_mysql4113a_mac_sv;

MAX(ROWNUM)
-----------
34

SQL>

Windows上で、Generic Connectivityの接続を確認できたので、MacOSXのOracle10gから、WindowsのOracle10g経由で各データベースへの接続を確認する。
Generic Connectivity経由でアクセスする経路は以下の通り。

gencon_blog_my_pos


尚、Generic Connectivity経由で、MySQL4.1.13aへ発行する count()関数は正しい結果を得られないためrownum疑似列をmax()関数で取得するという方法で代用している。

SYS> conn corydoras
パスワードを入力してください:
接続されました。
CORYDORAS>
CORYDORAS>
CORYDORAS>
CORYDORAS> select db_link from user_db_links;

DB_LINK
--------------------------------------------------------------------------------
ORACLE10G_WIN

CORYDORAS> select synonym_name from user_synonyms;

レコードが選択されませんでした。


CORYDORAS> select count(*) from char_test_postgresql749_mac@oracle10g_win;

COUNT(*)
----------
35

CORYDORAS> select count(*) from char_test_mysql4025_mac@oracle10g_win;

COUNT(*)
----------
11

CORYDORAS> select count(*) from varchar_test_mysql4025_mac@oracle10g_win;

COUNT(*)
----------
34

CORYDORAS> select count(*) from char_test_mysql4113a_mac_sv@oracle10g_win;

COUNT(*)
----------
12593

CORYDORAS> select max(rownum) from char_test_mysql4113a_mac_sv@oracle10g_win;

MAX(ROWNUM)
-----------
11

CORYDORAS> select count(*) from varchar_test_mysql4113a_mac_sv@oracle10g_win;

COUNT(*)
----------
13363

CORYDORAS> select max(rownum) from varchar_test_mysql4113a_mac_sv@oracle10g_win;

MAX(ROWNUM)
-----------
34

CORYDORAS>

Generic Connectivity経由の接続を確認することができた。
次回、Generic Connectivity経由でPostgreSQLの文字型にアクセス 一回目につづく。

| | | コメント (0) | トラックバック (0)

2006年3月 4日 (土)

Mac De Oracle Heterogeneous! #55

前回の続き。

MySQLの文字型の最終回。

今回はbinary属性の有無によるソート結果の違いを確認する。

登録したデータは以下。(id列は登録順に昇順とした)

insert into varchar_test(id, r_varchar_20) values(1,'C');
insert into varchar_test(id, r_varchar_20) values(2,'c');
insert into varchar_test(id, r_varchar_20) values(3,'B');
insert into varchar_test(id, r_varchar_20) values(4,'b');
insert into varchar_test(id, r_varchar_20) values(5,'A');
insert into varchar_test(id, r_varchar_20) values(6,'a');
insert into varchar_test(id, r_varchar_20) values(7,'お');
insert into varchar_test(id, r_varchar_20) values(8,'え');
insert into varchar_test(id, r_varchar_20) values(9,'う');
insert into varchar_test(id, r_varchar_20) values(10,'い');
insert into varchar_test(id, r_varchar_20) values(11,'あ');
insert into varchar_test(id, r_varchar_20) values(12,'ぉ');
insert into varchar_test(id, r_varchar_20) values(13,'ぇ');
insert into varchar_test(id, r_varchar_20) values(14,'ぅ');
insert into varchar_test(id, r_varchar_20) values(15,'ぃ');
insert into varchar_test(id, r_varchar_20) values(16,'ぁ');

binary属性が無い場合、char型、varchar型は英字大文字小文字を区別しない。(MySQL4.0.25、MySQL4.1.13aとも同じ)
mysql> 
mysql> select
-> id,
-> r_varchar_20,
-> hex(r_varchar_20) as hex_sjis
-> from
-> varchar_test
-> where
-> id between 1 and 16
-> order by
-> r_varchar_20;
+----+--------------+----------+
| id | r_varchar_20 | hex_sjis |
+----+--------------+----------+
| 5 | A | 41 |
| 6 | a | 61 |
| 3 | B | 42 |
| 4 | b | 62 |
| 1 | C | 43 |
| 2 | c | 63 |
| 16 | ぁ | 829F |
| 11 | あ | 82A0 |
| 15 | ぃ | 82A1 |
| 10 | い | 82A2 |
| 14 | ぅ | 82A3 |
| 9 | う | 82A4 |
| 13 | ぇ | 82A5 |
| 8 | え | 82A6 |
| 12 | ぉ | 82A7 |
| 7 | お | 82A8 |
+----+--------------+----------+
16 rows in set (0.07 sec)

mysql>

binary属性付きの場合、英字大文字に続き、英字小文字の順にソートされる。

mysql> select
-> id,
-> r_varchar_20_binary,
-> hex(r_varchar_20_binary) as hex_sjis
-> from
-> varchar_test
-> where
-> id between 17 and 32
-> order by
-> r_varchar_20_binary;
+----+---------------------+----------+
| id | r_varchar_20_binary | hex_sjis |
+----+---------------------+----------+
| 21 | A | 41 |
| 19 | B | 42 |
| 17 | C | 43 |
| 22 | a | 61 |
| 20 | b | 62 |
| 18 | c | 63 |
| 32 | ぁ | 829F |
| 27 | あ | 82A0 |
| 31 | ぃ | 82A1 |
| 26 | い | 82A2 |
| 30 | ぅ | 82A3 |
| 25 | う | 82A4 |
| 29 | ぇ | 82A5 |
| 24 | え | 82A6 |
| 28 | ぉ | 82A7 |
| 23 | お | 82A8 |
+----+---------------------+----------+
16 rows in set (0.00 sec)

mysql>



ちなみに、Oracleで同じことを行うとのと同じ結果になるのは、binary属性があるchar型又は、varchar型なのである。
SQL> list
1 select
2 string,
3 dump(string, 16) as "hex"
4 from
5 test
6 order by
7 string
SQL> /

STRING hex
------ ------------------------------
A Typ=1 Len=1: 41
B Typ=1 Len=1: 42
C Typ=1 Len=1: 43
a Typ=1 Len=1: 61
b Typ=1 Len=1: 62
c Typ=1 Len=1: 63
ぁ Typ=1 Len=2: 82,9f
あ Typ=1 Len=2: 82,a0
ぃ Typ=1 Len=2: 82,a1
い Typ=1 Len=2: 82,a2
ぅ Typ=1 Len=2: 82,a3
う Typ=1 Len=2: 82,a4
ぇ Typ=1 Len=2: 82,a5
え Typ=1 Len=2: 82,a6
ぉ Typ=1 Len=2: 82,a7
お Typ=1 Len=2: 82,a8

16行が選択されました。


さらにおまけ。
Oracleでは、nlssort()関数を利用した言語ソートを行うこともできる。

SQL> list
1 select
2 string,
3 dump(string, 16) as "hex"
4 from
5 test
6 order by
7 nlssort(string, 'NLS_SORT = japanese')
SQL> /

STRING hex
------ ------------------------------
a Typ=1 Len=1: 61
A Typ=1 Len=1: 41
b Typ=1 Len=1: 62
B Typ=1 Len=1: 42
c Typ=1 Len=1: 63
C Typ=1 Len=1: 43
ぁ Typ=1 Len=2: 82,9f
あ Typ=1 Len=2: 82,a0
ぃ Typ=1 Len=2: 82,a1
い Typ=1 Len=2: 82,a2
ぅ Typ=1 Len=2: 82,a3
う Typ=1 Len=2: 82,a4
ぇ Typ=1 Len=2: 82,a5
え Typ=1 Len=2: 82,a6
ぉ Typ=1 Len=2: 82,a7
お Typ=1 Len=2: 82,a8


ということで、簡単だったが、MySQL4.0.25及び、4.1.13aでの文字型の検証は終わり。(なんとなくPostgreSQLがステキに見えてくる。というのもMySQLが独特な世界を持っているからか?)

次回、PostgreSQLとMySQLの文字型をGeneric Connectivity経由でアクセスへつづく。

| | | コメント (0) | トラックバック (0)

2006年3月 3日 (金)

Mac De Oracle Heterogeneous! #54

前回の続き。

MySQLの文字型の四回目。

1.varchar型の検証

1−1 MySQL4.0.25での検証

1)' あ '、 null、 空文字、シングルバイト文字を20文字登録。

空白の扱いを確認するため、”あ”の前後に空白を付加し、' あ ' として登録した

mysql> insert into varchar_test(id, r_varchar_20) values(33,' ¥202¥240 ');
Query OK, 1 row affected (0.01 sec)
現在リリースされているMacOSXのTerminalは、マルチバイトを入力するとエスケープシーケンスになってしまう。実際に入力しているのは以下のDML。
insert into varchar_test(id, r_varchar_20) values(33, ' あ ');
mysql> 
insert into varchar_test(id, r_varchar_20) values(34,null);
Query OK, 1 row affected (0.00 sec)

mysql> insert into varchar_test(id, r_varchar_20) values(35,'');
Query OK, 1 row affected (0.00 sec)

mysql> insert into varchar_test(id, r_varchar_20) values(36,'12345678901234567890');
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

2)シングルバイト文字で21文字を登録

PostgreSQLとは異なりワーニングもエラーも発生しない。Generic Connectivity経由での登録は要注意だ。

mysql> insert into varchar_test(id, r_varchar_20) values(37,'123456789012345678901');
Query OK, 1 row affected (0.00 sec)

3)マルチバイト文字で20文字を登録。

データベースキャラクタセットはSJISなので実際には40バイトになる文字列なのだが、これも正常?に実行された。

mysql> 
mysql> insert into varchar_test(id, r_varchar_20)
-> values(38,'¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W02X¥202O');
Query OK, 1 row affected (0.00 sec)
Terminalは、マルチバイトを入力するとエスケープシーケンスになってしまう。実際に入力しているのは以下のDML。
insert into varchar_test(id, r_varchar_20) values(38,'12345678901234567890');

4)マルチバイト文字で21文字を登録。

実際には42バイトになる文字列なのでだが正常の実行されてしまった。列は20バイトまでと定義しているのだが

mysql> 
mysql> insert into varchar_test(id, r_varchar_20)
-> values(39,'¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W02X¥202O¥202P');
Query OK, 1 row affected (0.00 sec)
Terminalは、マルチバイトを入力するとエスケープシーケンスになってしまう。実際に入力しているのは以下のDML。
insert into varchar_test(id, r_varchar_20) values(39,'123456789012345678901');

5)文字数、バイトサイズの確認

PostgreSQLの場合と比べて文字数とバイト数が異なることに気付いただろうか?
MySQL4.0.25のchar型と同じなのだ。このリリースのMySQLでは、varchar型とchar型の差が無いことに改めて気付く。

mysql> 
mysql> select
-> id,
-> r_varchar_20,
-> char_length(r_varchar_20) as char_length,
-> length(r_varchar_20) as length
-> from
-> varchar_test
-> where
-> id between 33 and 39;
+----+----------------------+-------------+--------+
| id | r_varchar_20 | char_length | length |
+----+----------------------+-------------+--------+
| 33 | あ | 2 | 3 |
| 34 | NULL | NULL | NULL |
| 35 | | 0 | 0 |
| 36 | 12345678901234567890 | 20 | 20 |
| 37 | 12345678901234567890 | 20 | 20 |
| 38 | 1234567890 | 10 | 20 |
| 39 | 1234567890 | 10 | 20 |
+----+----------------------+-------------+--------+
7 rows in set (0.00 sec)

mysql>
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql>


1−2 MySQL4.1.13aでの検証

1)' あ '、 null、 空文字、シングルバイト文字を20文字登録。

空白の扱いを確認するため、”あ”の前後に空白を付加し、' あ ' として登録した。

mysql> insert into varchar_test(id, r_varchar_20) values(33,' ¥202¥240 ');
Query OK, 1 row affected (0.00 sec)
現在リリースされているMacOSXのTerminalは、マルチバイトを入力するとエスケープシーケンスになってしまう。実際に入力しているのは以下のDML。
insert into varchar_test(id, r_varchar_20) values(33, ' あ ');
mysql> insert into varchar_test(id, r_varchar_20) values(34,null);
Query OK, 1 row affected (0.00 sec)

mysql> insert into varchar_test(id, r_varchar_20) values(35,'');
Query OK, 1 row affected (0.00 sec)

mysql> insert into varchar_test(id, r_varchar_20) values(36,'12345678901234567890');
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.07 sec)

2)シングルバイト文字で21文字を登録

MySQL4.0.25とは異なりワーニングが発生するが、Generic Connectivity経由ではワーニングが拾えないので要注意だ。

mysql> insert into varchar_test(id, r_varchar_20) values(37,'123456789012345678901');
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+------------------------------------------------+
| Level | Code | Message |
+---------+------+------------------------------------------------+
| Warning | 1265 | Data truncated for column 'r_char_20' at row 1 |
+---------+------+------------------------------------------------+
1 row in set (0.00 sec)


3)マルチバイト文字を20文字登録(登録内容はMySQL4.0.25と同じ)

正常に実行される。

mysql> 
mysql> insert into varchar_test(id, r_varchar_20)
-> values(38,'¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O');
Query OK, 1 row affected (0.00 sec)

4)マルチバイト文字を21文字登録(登録内容はMySQL4.0.25と同じ)

文字列が制限を超えるとワーニングがでるようにはなっているが、4.1.xではここまで。ワーニングを拾ってロールバックしなければ、commitされてしまうため文字列が切り捨てられたことすら、気がつかないという状況もありえるので要注意。MySQL5.0.2以降ならばsql_mode='TRADITIONAL'にすればエラー扱いにすることも可能なようだが、4.x台では無理だ。今までの経験から warningは、Generic Connectivity経由では拾えないので、Generic Connectivity経由での登録や更新は要注意だ。

mysql> 
mysql> insert into varchar_test(id, r_varchar_20)
-> values(39,'¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O¥202P');
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> show warnings;
+---------+------+------------------------------------------------+
| Level | Code | Message |
+---------+------+------------------------------------------------+
| Warning | 1265 | Data truncated for column 'r_char_20' at row 1 |
+---------+------+------------------------------------------------+
1 row in set (0.00 sec)

5)文字数、バイトサイズの確認

MySQL4.1.x以降、varchar(n)の n は、文字数を意味するので MySQL4.0.xの文字列とは物理サイズが異なる点に注意。

mysql> 
mysql> select
-> id,
-> r_varchar_20,
-> char_length(r_varchar_20) as char_length,
-> length(r_varchar_20) as length
-> from
-> varchar_test
-> where
-> id between 33 and 39;
+----+------------------------------------------+-------------+--------+
| id | r_varchar_20 | char_length | length |
+----+------------------------------------------+-------------+--------+
| 33 | あ | 2 | 3 |
| 34 | NULL | NULL | NULL |
| 35 | | 0 | 0 |
| 36 | 12345678901234567890 | 20 | 20 |
| 37 | 12345678901234567890 | 20 | 20 |
| 38 | 12345678901234567890 | 20 | 40 |
| 39 | 12345678901234567890 | 20 | 40 |
+----+------------------------------------------+-------------+--------+
6 rows in set (0.00 sec)

mysql>
mysql> rollback;
Query OK, 0 rows affected (0.05 sec)

mysql>

MySQLのvarchar型でもchar型同様、後半の空白をトリムする仕様となっているので注意が必要だ。
マニュアルによると、後半の空白が必要な場合には、text型を利用する必要があるとの記述がある。なんだ?!


text型やblob型が、Generic Connectivity経由で利用できるか不明なのだが、簡単な検証を行っておく。

2.text型とblob型の検証

text型やblob型はOracleなどで言うラージオブジェクトとは別ものらしく、文字列型に分類されている。(ん〜〜〜〜〜。と、うなってみたりして・・)

mysql> insert into varchar_test(id,r_text) values(37,'¥202¥240¥202¥242¥202¥244');
Query OK, 1 row affected (0.00 sec)

mysql> insert into varchar_test(id,r_blob) values(38,'¥202¥240¥202¥242¥202¥244');
Query OK, 1 row affected (0.00 sec)


text型は文字数はマルチバイトで3文字と認識されているが、blob型では6文字と認識される。

mysql> select
-> id,
-> r_text,
-> hex(r_text),
-> char_length(r_text) as ¥203o¥203C¥203g¥220¥224,
-> length(r_text) as ¥225¥266¥216¥232¥220¥224
-> from
-> varchar_test
-> where
-> id = 37;
+----+--------+--------------+----------+----------+
| id | r_text | hex(r_text) | 文字数 | バイト数 |
+----+--------+--------------+----------+----------+
| 37 | あいう | 82A082A282A4 | 3 | 6 |
+----+--------+--------------+----------+----------+
1 row in set (0.00 sec)

mysql> select
-> id,
-> r_blob,
-> hex(r_blob),
-> char_length(r_blob) as ¥203o¥203C¥203g¥220¥224,
-> length(r_blob) as ¥225¥266¥216¥232¥220¥224
-> from
-> varchar_test
-> where
-> id = 38;
+----+--------+--------------+----------+----------+
| id | r_blob | hex(r_blob) | 文字数 | バイト数 |
+----+--------+--------------+----------+----------+
| 38 | あいう | 82A082A282A4 | 6 | 6 |
+----+--------+--------------+----------+----------+
1 row in set (0.00 sec)

mysql>


今日はここまで、次回につづく。

| | | コメント (0) | トラックバック (0)

2006年3月 2日 (木)

Mac De Oracle Heterogeneous! #53

前回の続き。

MySQLの文字型の三回目。

1.char型の検証

1−1 MySQL4.0.25での検証

1)' あ '、 null、 空文字、シングルバイト文字を20文字登録。

空白の扱いを確認するため、”あ”の前後に空白を付加し、' あ ' として登録した。

mysql> insert into char_test(id, r_char_20) values(1,' ¥202¥240 ');
Query OK, 1 row affected (0.00 sec)
現在リリースされているMacOSXのTerminalは、マルチバイトを入力するとエスケープシーケンスになってしまう。実際に入力しているのは以下のDML。
insert into char_test(id, r_char_20) values(1, ' あ ');
mysql> insert into char_test(id, r_char_20) values(2,null);
Query OK, 1 row affected (0.00 sec)

mysql> insert into char_test(id, r_char_20) values(3,'');
Query OK, 1 row affected (0.00 sec)

mysql> insert into char_test(id, r_char_20) values(4,'12345678901234567890');
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

2)シングルバイト文字で21文字を登録

PostgreSQLとは異なりワーニングもエラーも発生しない。Generic Connectivity経由での登録は要注意だ。

mysql> insert into char_test(id, r_char_20) values(5,'123456789012345678901');
Query OK, 1 row affected (0.00 sec)

3)マルチバイト文字で20文字を登録。

データベースキャラクタセットはSJISなので実際には40バイトになる文字列なのだが、これも正常?に実行された。

mysql> insert into char_test(id, r_char_20) 
-> values(6,'¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W2X¥202O');
Query OK, 1 row affected (0.00 sec)
現在リリースされているMacOSXのTerminalは、マルチバイトを入力するとエスケープシーケンスになってしまう。実際に入力しているのは以下のDML。
insert into char_test(id, r_char_20) values(6,'12345678901234567890');

4)マルチバイト文字で21文字を登録。

実際には42バイトになる文字列なのでだが正常の実行されてしまった。列は20バイトまでと定義しているのだが。

mysql> 
mysql> insert into char_test(id, r_char_20)
-> values(7,'¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W2X¥202O¥202P');
Query OK, 1 row affected (0.01 sec)
現在リリースされているMacOSXのTerminalは、マルチバイトを入力するとエスケープシーケンスになってしまう。実際に入力しているのは以下のDML。
insert into char_test(id, r_char_20) values(7,'123456789012345678901');

5)文字数、バイトサイズの確認

PostgreSQLの場合と比べて文字数とバイト数が異なることに気付いただろうか?
MySQL4.0.25のchar型では、文字につづく空白が切り捨てられる。空文字を設定した場合も空文字が設定されている。

mysql> 
mysql> select
-> id,
-> r_char_20,
-> char_length(r_char_20) as char_length,
-> length(r_char_20) as length
-> from
-> char_test
-> where
-> id <= 7;
+----+----------------------+-------------+--------+
| id | r_char_20 | char_length | length |
+----+----------------------+-------------+--------+
| 1 | あ | 2 | 3 |
| 2 | NULL | NULL | NULL |
| 3 | | 0 | 0 |
| 4 | 12345678901234567890 | 20 | 20 |
| 5 | 12345678901234567890 | 20 | 20 |
| 6 | 1234567890 | 10 | 20 |
| 7 | 1234567890 | 10 | 20 |
+----+----------------------+-------------+--------+
7 rows in set (0.00 sec)

mysql>
mysql> rollback;
Query OK, 0 rows affected (0.00 sec)

mysql>


1−2 MySQL4.1.13aでの検証

1)' あ '、 null、 空文字、シングルバイト文字を20文字登録。

空白の扱いを確認するため、”あ”の前後に空白を付加し、' あ ' として登録した。

mysql> insert into char_test(id, r_char_20) values(1,' ¥202¥240 ');
Query OK, 1 row affected (0.00 sec)
現在リリースされているMacOSXのTerminalは、マルチバイトを入力するとエスケープシーケンスになってしまう。実際に入力しているのは以下のDML。
insert into char_test(id, r_char_20) values(1, ' あ ');
mysql> insert into char_test(id, r_char_20) values(2,null);
Query OK, 1 row affected (0.00 sec)

mysql> insert into char_test(id, r_char_20) values(3,'');
Query OK, 1 row affected (0.00 sec)

mysql> insert into char_test(id, r_char_20) values(4,'12345678901234567890');
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.06 sec)

2)シングルバイト文字を21文字登録

MySQL4.0.xとは異なり、ワーニングが返されるが、それ以外の違いはない。

mysql> insert into char_test(id, r_char_20) values(5,'123456789012345678901');
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> show warnings;
+---------+------+------------------------------------------------+
| Level | Code | Message |
+---------+------+------------------------------------------------+
| Warning | 1265 | Data truncated for column 'r_char_20' at row 1 |
+---------+------+------------------------------------------------+
1 row in set (0.00 sec)


3)マルチバイト文字を20文字登録(登録内容はMySQL4.0.25と同じ)

正常に実行される。

mysql> insert into char_test(id, r_char_20) 
-> values(6,'¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O');
Query OK, 1 row affected (0.00 sec)


4)マルチバイト文字を21文字登録(登録内容はMySQL4.0.25と同じ)

文字列が制限を超えるとワーニングがでるようにはなっているが、4.1.xではここまで。ワーニングを拾ってロールバックしなければ、commitされてしまうため文字列が切り捨てられたことすら、気がつかないという状況もありえるので要注意。MySQL5.0.2以降ならばsql_mode='TRADITIONAL'にすればエラー扱いにすることも可能なようだが、4.x台では無理だ。今までの経験から warningは、Generic Connectivity経由では拾えないので、Generic Connectivity経由での登録や更新は要注意だ。

mysql> 
mysql> insert into char_test(id, r_char_20)
-> values(7,'¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O¥202P');
Query OK, 1 row affected, 1 warning (0.00 sec)
mysql> show warnings;
+---------+------+------------------------------------------------+
| Level | Code | Message |
+---------+------+------------------------------------------------+
| Warning | 1265 | Data truncated for column 'r_char_20' at row 1 |
+---------+------+------------------------------------------------+
1 row in set (0.00 sec)


5)文字数、バイトサイズの確認

MySQL4.1.x以降、char(n)の n は、文字数を意味するので MySQL4.0.xとの違いは文字列が取りうる物理サイズということになる。

mysql> 
mysql>
mysql> select
-> id,
-> r_char_20,
-> char_length(r_char_20) as char_length,
-> length(r_char_20) as length
-> from
-> char_test
-> where
-> id <= 7;
+----+------------------------------------------+-------------+--------+
| id | r_char_20 | char_length | length |
+----+------------------------------------------+-------------+--------+
| 1 | あ | 2 | 3 |
| 2 | NULL | NULL | NULL |
| 3 | | 0 | 0 |
| 4 | 12345678901234567890 | 20 | 20 |
| 5 | 12345678901234567890           | 20 | 20 |
| 6 | 12345678901234567890 | 20 | 40 |
| 7 | 12345678901234567890 | 20 | 40 |
+----+------------------------------------------+-------------+--------+
7 rows in set (0.03 sec)

mysql>
mysql> rollback;
Query OK, 0 rows affected (0.05 sec)

mysql>


今日はここまで、次回につづく。

| | | コメント (0) | トラックバック (0)

2006年3月 1日 (水)

Mac De Oracle Heterogeneous! #52

前回の続き。

MySQLの文字型の二回目。

MySQL4.0.25、MySQL4.1.13aともに以下の表を作成した。

mysql> desc char_test;
+-------------------+------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+------------------+------+-----+---------+-------+
| id | int(11) | | PRI | 0 | |
| r_char_20 | char(20) | YES | | NULL | |
| r_char_20_binary | char(20) binary | YES | | NULL | |
| r_char_255 | char(255) | YES | | NULL | |
| r_char_255_binary | char(255) binary | YES | | NULL | |
+-------------------+------------------+------+-----+---------+-------+
5 rows in set (0.00 sec)

mysql> desc varchar_test;
+----------------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+---------------------+------+-----+---------+-------+
| id | int(11) | | PRI | 0 | |
| r_varchar_20 | varchar(20) | YES | | NULL | |
| r_varchar_20_binary | varchar(20) binary | YES | | NULL | |
| r_varchar_255 | varchar(255) | YES | | NULL | |
| r_varchar_255_binary | varchar(255) binary | YES | | NULL | |
| r_tinytext | tinytext | YES | | NULL | |
| r_tinyblob | tinyblob | YES | | NULL | |
| r_text | text | YES | | NULL | |
| r_blob | blob | YES | | NULL | |
+----------------------+---------------------+------+-----+---------+-------+
9 rows in set (0.00 sec)

mysql>

MySQL4.0.xまでは、char型及び、varchar型は最大255バイト。4.1.x以降では65535文字
また、独特な仕様だが、char型とvarchar型は、大文字小文字を区別しない。大文字小文字を区別させるためには binary属性を付けなければならない。binary属性の無い文字型ではソート処理がどうなるのか気になるところだ。

ところで、255バイト以上の文字列はどのようにして格納するのか? とマニュアルを読んでいると、tinytext型、text型、mediumtext型、longtext型、そして、大文字小文字を区別できるtinyblob型、blob型、mediumblob型、longblob型があるとのこと。(blobだとbinary large objectなのかと思っていたのだが、マニュアルによると文字列という表現になっている。ところ変わればなんとやら。。なのだが、generic connectivity経由でOracleのvarchar2型にマッピングできるのかという点は不安材料だ。。)

また、MySQL4.1から文字列型の仕様がかなり変更されたらしく、MySQL4.0.xでは、char(n)又は、varchar(n)の n はバイトを意味していたものが、文字数に変わったようだ。
さらに、キャラクタセットがカラム毎に変えられるらしい、MySQL4.1以降ならば事前に表定義は、”しっかり”確認しておく事をお勧めする。もしそのような表定義であったなら generic connectivity で扱うのは諦めたほうがよいかもしれない。 

今日はここまで、次回につづく。

| | | コメント (0) | トラックバック (0)

2006年2月28日 (火)

Mac De Oracle Heterogeneous! #51

文字型のつづき。今回から、MySQLの文字型の特徴を簡単検証していく。

PowerBook G4 MacOSX Tiger 10.4.5のMySQL4.0.25及び、PowerMac G5 Dual2.7GhzのMySQL4.1.13aを利用した。


gencon_blog_img33

尚、データベース及び、クライアントキャラクタセットともにSJISである。

MySQL4.0.25及び、MySQL4.1.13aには、以下のような表を作成した。。。のだが・・・・・。

mysql> create table char_testA
-> (
-> id int primary key,
-> r_char_20 char(20),
-> r_char_20_binary char(20) binary,
-> r_char_255 char(255),
-> r_char_255_binary char(255) binary,
-> r_varchar_20 varchar(20),
-> r_varchar_20_binary varchar(20) binary,
-> r_varchar_255 varchar(255),
-> r_varchar_255_binary varchar(255) binary,
-> r_tinytext tinytext,
-> r_tinyblob tinyblob,
-> r_text text,
-> r_blob blob
-> ) engine=innodb;

Query OK, 0 rows affected (0.10 sec)

char型で定義した列が全て varchar型になっていたのである。あれれ、何故????

mysql> desc char_test;
+----------------------+---------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------------+---------------------+------+-----+---------+-------+
| id | int(11) | | PRI | 0 | |
| r_char_20 | varchar(20) | YES | | NULL | |
| r_char_20_binary | varchar(20) binary | YES | | NULL | |
| r_char_255 | varchar(255) | YES | | NULL | |
| r_char_255_binary | varchar(255) binary | YES | | NULL | |
| r_varchar_20 | varchar(20) | YES | | NULL | |
| r_varchar_20_binary | varchar(20) binary | YES | | NULL | |
| r_varchar_255 | varchar(255) | YES | | NULL | |
| r_varchar_255_binary | varchar(255) binary | YES | | NULL | |
| r_tinytext | tinytext | YES | | NULL | |
| r_tinyblob | tinyblob | YES | | NULL | |
| r_text | text | YES | | NULL | |
| r_blob | blob | YES | | NULL | |
----------------------+---------------------+------+-----+---------+-------+
13 rows in set (0.00 sec)

DDLもvarcharに変更されている。
mysql> show create table char_test¥G
*************************** 1. row ***************************
Table: char_test
Create Table: CREATE TABLE `char_test` (
`id` int(11) NOT NULL default '0',
`r_char_20` varchar(20) default NULL,
`r_char_20_binary` varchar(20) binary default NULL,
`r_char_255` varchar(255) default NULL,
`r_char_255_binary` varchar(255) binary default NULL,
`r_varchar_20` varchar(20) default NULL,
`r_varchar_20_binary` varchar(20) binary default NULL,
`r_varchar_255` varchar(255) default NULL,
`r_varchar_255_binary` varchar(255) binary default NULL,
`r_tinytext` tinytext,
`r_tinyblob` tinyblob,
`r_text` text,
`r_blob` blob,
PRIMARY KEY (`id`)
) TYPE=InnoDB
1 row in set (0.00 sec)

mysql>

慌てて、マニュアルを確認してみると、

マニュアルから引用ここから


6.5.3.1. カラムの暗黙的な変更

場合によっては、CREATE TABLE ステートメントで指定されているカラムの型、属性が、MySQL によって暗黙的に変更されることがあります(このような変更は ALTER TABLE でも発生する場合があります)。

長さが 4 文字に満たない VARCHAR 型のカラムは CHAR 型に変更される。

テーブルのいずれかのカラムが可変長である場合は、結果的にそのレコード全体が可変長になる。したがって、テーブルに可変長のカラム(VARCHAR、TEXT、BLOB)が含まれている場合、長さが 3 文字を超す CHAR 型のカラムはいずれも VARCHAR 型カラムに変更される。これはカラムの使用方法には影響しない。MySQL では、VARCHAR 型は単に文字を格納するもう 1 つの手段として使用されている。MySQL でこの変換が実行される理由は、スペースを節約し、テーブル処理を迅速化するためである。 See 章 7. MySQL のテーブル型。

バージョン 4.1.0 以降では、255 文字を超える長さを持つ CHAR 型または VARCHAR 型のフィールドはいずれも TEXT 型に変換される。 これは互換性を考慮した機能。


マニュアルから引用ここまで


仕様なら仕方ない。(バグかと思ったよ。。。。)
ということで、char型本来の癖を見る為、char型だけの表とvarchar型、text型、blob型の表に分ける事にした。(尚、mediumtext型、mediumblob型、longtext型及び、longblob型は検証対象外とした。)

char(n) と char(n) binaryの違いは、'A'と'a'を区別するかしないかということ。binary属性を付けると大文字と小文字を区別するようになる。この特徴は要注意だ。PostgreSQLもOracleもDB2でも大文字小文字は区別される、区別したくない場合には、スカラ関数を使い大文字又は、小文字に統一してから比較するからだ。もし、Generic Connectivityを経由してアクセスするMySQLの表がbinary属性のないchar型やvarchar型だと、ソートは注意が必要かもしれない。(ソートについては、Generic Connectivity経由でも検証する)
また、blob型なのに何故、文字型の検証で登場するのかと感じる方もいると思うのだが、blob型は Oracleのlob型に対応するのでは? と思っているのだが、MySQLでは文字列型に分類されており、大文字小文字を区別したい文字列を格納するための型となっている、ちなみに、text型は大文字小文字を区別しない。これらの型の詳細は、MySQLのマニュアル又は、MySQLによる最速RDBMS構築ガイドを参照するとよいだろう。

mysql> create table char_test
-> (
-> id int primary key,
-> r_char_20 char(20),
-> r_char_20_binary char(20) binary,
-> r_char_255 char(255),
-> r_char_255_binary char(255) binary
-> ) engine=innodb;
Query OK, 0 rows affected (0.09 sec)

mysql>
mysql> create table varchar_test
-> (
-> id int primary key,
-> r_varchar_20 varchar(20),
-> r_varchar_20_binary varchar(20) binary,
-> r_varchar_255 varchar(255),
-> r_varchar_255_binary varchar(255) binary,
-> r_tinytext tinytext,
-> r_tinyblob tinyblob,
-> r_text text,
-> r_blob blob
-> ) engine=innodb;
Query OK, 0 rows affected (0.02 sec)


ちなみに、一旦, char型からvarchar型に変更されてしまうと、全列を固定長に戻したとしても、varchar型がchar型に戻されることは無いようだ。以下のログ参照。(ん〜〜〜〜・・・・。いろいろ書きたい気分だがノーコメント。) 
まず、char型だけの表を作成。この定義だとすべてchar型として定義されている。

Welcome to Darwin!
G5Server:˜ discus$ mysql -u discus -p mysqldb41
Enter password:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor. Commands end with ; or ¥g.
Your MySQL connection id is 1 to server version: 4.1.13a

Type 'help;' or '¥h' for help. Type '¥c' to clear the buffer.

mysql> create table char_test
-> (
-> id int primary key,
-> r_char_20 char(20),
-> r_char_20_binary char(20) binary,
-> r_char_255 char(255),
-> r_char_255_binary char(255) binary
-> ) engine=innodb;
Query OK, 0 rows affected (0.22 sec)

mysql> desc char_test;
+-------------------+-----------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+-----------+------+-----+---------+-------+
| id | int(11) | | PRI | 0 | |
| r_char_20 | char(20) | YES | | NULL | |
| r_char_20_binary | char(20) | YES | | NULL | |
| r_char_255 | char(255) | YES | | NULL | |
| r_char_255_binary | char(255) | YES | | NULL | |
+-------------------+-----------+------+-----+---------+-------+
5 rows in set (0.01 sec)

固定長の文字列しかない表であれば、char型のままなのだが、char型とvarchar型(text型、blob型も含む)が混在すると、既存char型は全て、自動的にvarchar型に変更されてしまう。MySQLのchar型、varchar型の仕様からすると、どちらの型でもいいのかもしれないが、他の(PostgreSQLやOracleなど)RDBMSと互換を持たせた挙動にしたい場合には困るかもしれない。(Generic Connectivity経由の挙動確認ではこの辺りも忘れずに!)
mysql> alter table char_test add column r_varchar_20 varchar(20);
Query OK, 0 rows affected (0.52 sec)
Records: 0 Duplicates: 0 Warnings: 0

mysql> desc char_test;
+-------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+--------------+------+-----+---------+-------+
| id | int(11) | | PRI | 0 | |
| r_char_20 | varchar(20) | YES | | NULL | |
| r_char_20_binary | varchar(20) | YES | | NULL | |
| r_char_255 | varchar(255) | YES | | NULL | |
| r_char_255_binary | varchar(255) | YES | | NULL | |
| r_varchar_20 | varchar(20) | YES | | NULL | |
+-------------------+--------------+------+-----+---------+-------+
6 rows in set (0.03 sec)


一旦、char型からvarchar型に自動変更されてしまった表は、そのきっかけになった列を削除しても元には戻らない。
どうしても、char型に戻したいのなら表を再作成するしかない。

mysql> alter table char_test drop column r_varchar_20;
Query OK, 0 rows affected (0.71 sec)
Records: 0 Duplicates: 0 Warnings: 0

mysql> desc char_test;
+-------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+--------------+------+-----+---------+-------+
| id | int(11) | | PRI | 0 | |
| r_char_20 | varchar(20) | YES | | NULL | |
| r_char_20_binary | varchar(20) | YES | | NULL | |
| r_char_255 | varchar(255) | YES | | NULL | |
| r_char_255_binary | varchar(255) | YES | | NULL | |
+-------------------+--------------+------+-----+---------+-------+
5 rows in set (0.02 sec)

mysql> drop table char_test;
Query OK, 0 rows affected (0.05 sec)

mysql>

と、戸惑う仕様がいろいろあるのだが、なんとかやっている。ということで次回へつづく。

| | | コメント (0) | トラックバック (0)

2006年2月27日 (月)

Mac De Oracle Heterogeneous! #50

前回からのつづき。

PostgreSQLの文字型 最終回。

ソートの確認。ロケール関連パラメータをCに設定しているので特に問題ないと思うが、念のために確認。以下のデータを登録しておく。

dpostgresql749=> select id,r_varchar_20 from char_test;
id | r_varchar_20
----+--------------
1 | C
2 | c
3 | B
4 | b
5 | A
6 | a
7 | お
8 | え
9 | う
10 | い
11 | あ
12 | ぉ
13 | ぇ
14 | ぅ
15 | ぃ
16 | ぁ
(16 rows)

postgresql749=>

尚、文字列を16進数表示するユーザ定義関数 strtohex()を利用して文字コードも確認した。
strtohex()関数を作成したログ(抜粋)。詳細はstrtohexのソースに同胞されているドキュメントを参照のこと。
http://ring.atr.jp/archives/misc/db/postgresql-jp/strtohex/?C=M;O=Aからダウンロードできる。

pb17:/usr/local/pgsql/share/contrib postgres$ postmaster -S
pb17:/usr/local/pgsql/share/contrib postgres$ psql -e -f strtohex.sql postgresql749
SET search_path = scott;
SET
CREATE OR REPLACE FUNCTION strtohex(TEXT)
RETURNS TEXT
AS '$libdir/strtohex', 'strtohex'
LANGUAGE C STRICT;
CREATE FUNCTION
commit;
COMMIT
pb17:/usr/local/pgsql/share/contrib postgres$ psql -U scott postgresql749
Password:
Welcome to psql 7.4.9, the PostgreSQL interactive terminal.

Type: ¥copyright for distribution terms
¥h for help with SQL commands
¥? for help on internal slash commands
¥g or terminate with semicolon to execute query
¥q to quit

postgresql749=> select strtohex('a');
strtohex
----------
61
(1 row)

文字列を昇順にソートした結果。(変わったところはないようだ)

postgresql749=> ¥p
select
id,
r_varchar_20,
strtohex(r_varchar_20) as hex_euc,
strtohex(convert(r_varchar_20,'SJIS')) as hex_sjis,
strtohex(convert(r_varchar_20,'UTF-8')) as hex_utf8
from
char_test
order by
r_varchar_20;

postgresql749=> ¥g
id | r_varchar_20 | hex_euc | hex_sjis | hex_utf8
----+--------------+---------+----------+----------
5 | A | 41 | 41 | 41
3 | B | 42 | 42 | 42
1 | C | 43 | 43 | 43
6 | a | 61 | 61 | 61
4 | b | 62 | 62 | 62
2 | c | 63 | 63 | 63
16 | ぁ | a4a1 | 829f | e38181
11 | あ | a4a2 | 82a0 | e38182
15 | ぃ | a4a3 | 82a1 | e38183
10 | い | a4a4 | 82a2 | e38184
14 | ぅ | a4a5 | 82a3 | e38185
9 | う | a4a6 | 82a4 | e38186
13 | ぇ | a4a7 | 82a5 | e38187
8 | え | a4a8 | 82a6 | e38188
12 | ぉ | a4a9 | 82a7 | e38189
7 | お | a4aa | 82a8 | e3818a
(16 rows)


ちなみに、Oracleでソートを行った場合と同じ結果だ。
(言語ソートすると言語固有の文字順にソートされるが、PostgreSQLのロケール関連パラメータを設定した場合にはOracleの言語ソートと同じ結果になるのかは未確認。PostgreSQLのマニュアルを熟読しないと・・・・。

購入したPostgreSQL徹底入門「P.178」では詳細な解説はなく、簡単な解説だけだったのが残念。とはいっても言語ソースが必要になる状況は想定していないので特に問題なし。)

SCOTT> list
1 select
2 id#,
3 r_varchar2,
4 dump(r_varchar2,16) as hex_sjis,
5 dump(convert(r_varchar2,'ja16euc'),16) as hex_euc,
6 dump(convert(r_varchar2,'utf8'),16) as hex_utf8
7 from
8 char_test
9 order by
10* r_varchar2
SCOTT> /

ID# R_VARCHAR2 HEX_SJIS HEX_EUC HEX_UTF8
---------- -------------------- -------------------- -------------------- ----------------------
5 A Typ=1 Len=1: 41 Typ=1 Len=1: 41 Typ=1 Len=1: 41
3 B Typ=1 Len=1: 42 Typ=1 Len=1: 42 Typ=1 Len=1: 42
1 C Typ=1 Len=1: 43 Typ=1 Len=1: 43 Typ=1 Len=1: 43
6 a Typ=1 Len=1: 61 Typ=1 Len=1: 61 Typ=1 Len=1: 61
4 b Typ=1 Len=1: 62 Typ=1 Len=1: 62 Typ=1 Len=1: 62
2 c Typ=1 Len=1: 63 Typ=1 Len=1: 63 Typ=1 Len=1: 63
16 ぁ Typ=1 Len=2: 82,9f Typ=1 Len=2: a4,a1 Typ=1 Len=3: e3,81,81
11 あ Typ=1 Len=2: 82,a0 Typ=1 Len=2: a4,a2 Typ=1 Len=3: e3,81,82
15 ぃ Typ=1 Len=2: 82,a1 Typ=1 Len=2: a4,a3 Typ=1 Len=3: e3,81,83
10 い Typ=1 Len=2: 82,a2 Typ=1 Len=2: a4,a4 Typ=1 Len=3: e3,81,84
14 ぅ Typ=1 Len=2: 82,a3 Typ=1 Len=2: a4,a5 Typ=1 Len=3: e3,81,85
9 う Typ=1 Len=2: 82,a4 Typ=1 Len=2: a4,a6 Typ=1 Len=3: e3,81,86
13 ぇ Typ=1 Len=2: 82,a5 Typ=1 Len=2: a4,a7 Typ=1 Len=3: e3,81,87
8 え Typ=1 Len=2: 82,a6 Typ=1 Len=2: a4,a8 Typ=1 Len=3: e3,81,88
12 ぉ Typ=1 Len=2: 82,a7 Typ=1 Len=2: a4,a9 Typ=1 Len=3: e3,81,89
7 お Typ=1 Len=2: 82,a8 Typ=1 Len=2: a4,aa Typ=1 Len=3: e3,81,8a

16行が選択されました。
ちなみに(テストデータがよくないので申し訳ないのだが)、nlssort関数を利用した言語ソートでは小文字英字の順序の違いに気付くと思う。
SCOTT> 
SCOTT> list
1 select
2 r_varchar2
3 from
4 char_test
5 order by
6* nlssort(r_varchar2, 'nls_sort=japanese')
SCOTT> /

R_VARCHAR2
--------------------
a
A
b
B
c
C











16行が選択されました。

SCOTT>


次回は、MySQLの文字型について同様の検証を行う。

| | | コメント (0) | トラックバック (0)

2006年2月26日 (日)

Mac De Oracle Heterogeneous! #49

前回からのつづき。
PostgreSQLの文字型の四回目。

1.text型の検証

1)' あ '、 null、 空文字、シングルバイト文字及び、マルチバイト文字を20文字登録。

空白の扱いを確認するため、”あ”の前後に空白を付加し、' あ ' として登録した。

postgresql749=> 
postgresql749=> insert into char_test(id, r_text)
postgresql749-> values(1, ' ¥202¥240 ');
INSERT 33747 1
postgresql749=> insert into char_test(id, r_text)
postgresql749-> values(2, null);
INSERT 33748 1
postgresql749=> insert into char_test(id, r_text)
postgresql749-> values(3, '');
INSERT 33749 1
postgresql749=> insert into char_test(id, r_text)
postgresql749-> values(4, '12345678901234567890');
INSERT 33750 1
postgresql749=> insert into char_test(id, r_text)
postgresql749-> values(5, '¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X;
INSERT 33751 1
現在リリースされているMacOSXのTerminalは、マルチバイトを入力するとエスケープシーケンスになってしまう。実際に入力しているのは以下のDML。
insert into char_test(id, r_text) values(5, '12345678901234567890');
postgresql749=> commit;
COMMIT

2)text型の最大サイズ

text型の最大サイズは、約1GB(要するに1GB未満)ということで、許容サイズを超えればエラー。

postgresql749=> insert into char_test(id,r_text) values(99,lpad('*',2048000000,'*'));
ERROR: requested length too large
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into char_test(id,r_text) values(99,lpad('*',1024000000,'*'));
ERROR: requested length too large
postgresql749=> rollback;
ROLLBACK

3)文字数、バイトサイズの確認

空白の扱いは、varchar型と同じだが、Generic Connectivity経由では、Oracleのどの型にマップされるのかがポイント。Generic Connectivity経由では利用できない可能性もあるし、利用できたとしてもVARCHAR2型の最大サイズである4000バイトを超えた場合にはどのような挙動になるのかという点も気になるところだ。
Generic Connectivityを利用せず、PostgreSQLのtext型からOracleへデータ移行するとした場合、PostgreSQLのtext型に登録されている文字列の最大サイズが4000バイトを超えるのならば、CLOB型に、4000バイト以下なら、VARCHAR2型にするのがベストだと思われる。
また、PostgreSQLの文字型は、NULL及び、空文字を設定できるが、Oracleでは、NULLと空文字が、NULLとして扱われているため、PostgreSQLの文字型に空文字を設定した場合は、Oracle側ではNULLとして扱われると予想している。

postgresql749-> ¥p
select
id,
r_text,
length(r_text) as 文字数,
octet_length(r_text) as バイト数
from
char_test

postgresql749-> ¥g
id | r_text | 文字数 | バイト数
----+------------------------------------------+-------+--------
1 | あ | 3 | 4
2 | | |
3 | | 0 | 0
4 | 12345678901234567890 | 20 | 20
5 | 12345678901234567890 | 20 | 40
(5 rows)

postgresql749=>

次回へつづく。

| | | コメント (0) | トラックバック (0)

2006年2月25日 (土)

Mac De Oracle Heterogeneous! #48

前回からのつづき。

PostgreSQLの文字型 三回目。

1.varchar型の検証

1)' あ '、 null、 空文字、シングルバイト文字を20文字登録。

空白の扱いを確認するため、”あ”の前後に空白を付加し、' あ ' として登録した。

postgresql749=> insert into char_test(id, r_varchar_20)
postgresql749-> values(1, ' ¥202¥240 ');
INSERT 33742 1
現在リリースされているMacOSXのTerminalは、マルチバイトを入力するとエスケープシーケンスになってしまう。実際に入力しているのは以下のDML。
insert into char_test(id, r_varchar_20) values(1, ' あ ');
postgresql749=> insert into char_test(id, r_varchar_20)
postgresql749-> values(2, null);
INSERT 33743 1
postgresql749=> insert into char_test(id, r_varchar_20)
postgresql749-> values(3, '');
INSERT 33744 1
postgresql749=> insert into char_test(id, r_varchar_20)
postgresql749-> values(4,'12345678901234567890');
INSERT 33745 1
postgresql749=> commit;
COMMIT


2)シングルバイト文字を21文字登録

20文字を超えるためエラー。(Oracleと連携しても問題になる事はないだろう)

postgresql749=> insert into char_test(id, r_varchar_20)
postgresql749-> values(5,'123456789012345678901');
ERROR: value too long for type character varying(20)
postgresql749=> rollback;
ROLLBACK


3)マルチバイト文字を20文字登録

20文字以内なので問題なく登録できる。

postgresql749=> insert into char_test(id, r_varchar_20)
postgresql749-> values(5,'¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O');
INSERT 33746 1
postgresql749=> commit;
COMMIT
現在リリースされているMacOSXのTerminalは、マルチバイトを入力するとエスケープシーケンスになってしまう。実際に入力しているのは以下のDML。
insert into char_test(id, r_varchar_20) values(5,'12345678901234567890');


4)マルチバイト文字を21文字登録

20文字を超えるためエラー。

postgresql749=> insert into char_test(id, r_varchar_20)
postgresql749-> values(6,'¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O2P');
ERROR: value too long for type character varying(20)
postgresql749=> rollback;
ROLLBACK
現在リリースされているMacOSXのTerminalは、マルチバイトを入力するとエスケープシーケンスになってしまう。実際に入力しているのは以下のDML。
insert into char_test(id, r_varchar_20) values(6,'123456789012345678901');


5)文字数、バイトサイズの確認

空白の扱いは、Oracleと同じようなので問題になることはないだろう。Oracleではvarchar2(20 char)か、varchar2(40)にマッピングすればよいと思うのだが、Generic Connectivity経由の場合はどの型にマッピングされるのか?、また、PostgreSQLの varchar型は、Oracleのvarchar2型より大きいサイズを定義できる(Oracleのvarchar2型は4000バイトが最大だが、PostgreSQLでは約1GBまで可能)ため、Generic Connectivity経由である場合はどのように扱われるのかがポイントになるだろう。

postgresql749=> ¥p
select
id,
r_varchar_20,
length(r_varchar_20) as 文字数,
octet_length(r_varchar_20) as バイト数
from
char_test;
postgresql749=> ¥g
id | r_varchar_20 | 文字数 | バイト数
----+------------------------------------------+-------+--------
1 | あ | 3 | 4
2 | | |
3 | | 0 | 0
4 | 12345678901234567890 | 20 | 20
5 | 12345678901234567890 | 20 | 40
(5 rows)

postgresql749=> delete from char_test;
DELETE 5
postgresql749=> commit;
COMMIT


今日はここまで、続きは次回。

| | | コメント (0) | トラックバック (0)

2006年2月24日 (金)

Mac De Oracle Heterogeneous! #47

前回からのつづき。

PostgreSQLの文字型の二回目。

1.char型の検証

1)' あ '、 null、 空文字、シングルバイト文字を20文字登録。

空白の扱いを確認するため、”あ”の前後に空白を付加し、' あ ' として登録した。

postgresql749=> insert into char_test(id, r_char_20)
postgresql749-> values(1, ' ¥202¥240 ');
INSERT 33737 1
postgresql749=> commit;
COMMIT
postgresql749=> insert into char_test(id, r_char_20)
postgresql749-> values(2, null);
INSERT 33738 1
postgresql749=> insert into char_test(id, r_char_20)
postgresql749-> values(3, '');
INSERT 33739 1
postgresql749=> insert into char_test(id, r_char_20)
postgresql749-> values(4,'12345678901234567890');
INSERT 33740 1
postgresql749=> commit;
COMMIT

2)シングルバイト文字を21文字登録

20文字を超えるためエラー。(Oracleと連携しても問題になる事はないだろう)

postgresql749=> insert into char_test(id, r_char_20)
postgresql749-> values(5,'123456789012345678901');
ERROR: value too long for type character(20)
postgresql749=> rollback;
ROLLBACK

3)マルチバイト文字を20文字登録

20文字以内なので問題なく登録できる。
(MacOSX TigerのTerminalからマルチバイト文字を入力するとエスケープシーケンスに変換されてしまうが表示上は問題ない。いつ改善されるやら。。)
ちなみに、実行したインサート文は以下。

insert into char_test(id, r_char_20) values(5,'12345678901234567890');

postgresql749=> insert into char_test(id, r_char_20)
postgresql749-> values(5,'¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O');
INSERT 33741 1
postgresql749=> commit;
COMMIT

4)マルチバイト文字を21文字登録

20文字を超えるためエラー。
実行したインサート文は以下。

insert into char_test(id, r_char_20) values(27,'123456789012345678901');

postgresql749=> insert into char_test(id, r_char_20)
postgresql749-> values(6,'¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O¥202P¥202Q¥202R¥202S¥202T¥202U¥202V¥202W¥202X¥202O2P');
ERROR: value too long for type character(20)
postgresql749=> rollback;
ROLLBACK

5)文字数、バイトサイズの確認

空白の扱いは、Oracleと同じようなので問題になることはないだろう。Oracleではchar(20 char)か、varchar2(40)にマッピングすればよいと思うのだが、Generic Connectivity経由の場合はどの型にマッピングされるのか?、また、PostgreSQLの char型は、Oracleのchar型より大きいサイズを定義できる(Oracleのchar型は2000バイトが最大だが、PostgreSQLでは約1GBまで可能)ため、Generic Connectivity経由である場合はどのように扱われるのかがポイントになるだろう。

postgresql749=> ¥p
select
id,
r_char_20,
length(r_char_20) as 文字数,
octet_length(r_char_20) as バイト数
from
char_test;
postgresql749=> ¥g
id | r_char_20 | 文字数 | バイト数
----+------------------------------------------+-------+--------
1 | あ | 20 | 21
2 | | |
3 | | 20 | 20
4 | 12345678901234567890 | 20 | 20
5 | 12345678901234567890 | 20 | 40
(5 rows)

postgresql749=>
postgresql749=> delete from char_test;
DELETE 5
postgresql749=> commit;
COMMIT


次回につづく。

| | | コメント (0) | トラックバック (0)

2006年2月23日 (木)

Mac De Oracle Heterogeneous! #46

Generic Connectivityの検証も残すところ文字型のみ。ラージオブジェクトについてはおまけ程度に書く予定だが、その他、各データベースに特有の型は今のところ試す予定はない。(必要になりそうならやるかもしれないが・・)

まず、PostgreSQLとMySQLそれぞれの文字型について癖を把握しておく。
PostgreSQLの文字型 一回目。

PowerBook G4 MacOSX Tiger 10.4.5のPostgreSQL7.4.9を利用した。


gencon_blog_img_postgre

また、クライアントエンコーディングは、SJIS。
データベースキャラクタセットは、EUC。
ソートに影響するローケル関連パラメータLC_COLLATEパラメータ及び、LC_CTYPEパラメータは C とした。 
(ちなみに、LC_COLLATE及び、LC_CTYPEパラメータを設定すると Oracleの言語ソートのようなことができるような記述がマニュアルにはあるのだが、前述した書籍で「日本語を使う場合、initdbで--no-locale。。。」とあったため、この検証では C と設定することとした)

pb17:˜ postgres$ pg_controldata
pg_control version number: 72
Catalog version number: 200310211
Database cluster state: shut down

中略

LC_COLLATE: C
LC_CTYPE: C
pb17:˜ postgres$
pb17:˜ postgres$
pb17:˜ postgres$ echo $PGCLIENTENCODING
SJIS
pb17:˜ postgres$

以下の表を作成した。

postgresql749=> create table char_test
postgresql749-> (
postgresql749(> id int primary key,
postgresql749(> r_char_20 char(20),
postgresql749(> r_char_2000 char(2000),
postgresql749(> r_char_2001 char(2001),
postgresql749(> r_varchar_20 varchar(20),
postgresql749(> r_varchar_4000 varchar(4000),
postgresql749(> r_varchar_4001 varchar(4001),
postgresql749(> r_text text
postgresql749(> );
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "char_test_pkey" for table "char_test"
CREATE TABLE
postgresql749=> ¥d char_test
Table "scott.char_test"
Column | Type | Modifiers
----------------+-------------------------+-----------
id | integer | not null
r_char_20 | character(20) |
r_char_2000 | character(2000) |
r_char_2001 | character(2001) |
r_varchar_20 | character varying(20) |
r_varchar_4000 | character varying(4000) |
r_varchar_4001 | character varying(4001) |
r_text | text |
Indexes:
"char_test_pkey" primary key, btree (id)

postgresql749=>
postgresql749=> commit;
COMMIT
postgresql749=>

Oracleと違い点は、char(n)型及び、varchar(n)型の n は常に文字数ということ。
また、n の上限はなく、最大長が約1GBまで制限がある。
従って、データベースキャラクタセットにより n の上限が変わってくるということになる。
Generic Connectivity経由でアクセスする際にはこの辺りがポイントになるだろう。また、text型がどのような扱いになるのかも気になるところだ。

ちなみに、Oracleでは初期化パラメータ nls_length_semantics を char にしデフォルトを文字単位の長さにするか、列を定義する際に、CHAR修飾子を指定することと同じ。
nls_length_semanticsのデフォルトはBYTEなので、hoge_code1は10文字、hoge_code2は10バイトという意味になる、

create table hoge
(
hoge_code1 CHAR(10 CHAR),
hoge_code2 CHAR(10)
);

今日はここまで。次回につづく。

| | | コメント (0) | トラックバック (0)

2006年2月22日 (水)

Mac De Oracle Heterogeneous! #45

数値型のつづき。

Generic Connectivity経由でMySQL4.0.25及び、MySQL4.1.13aの数値型にアクセス 最終回。

Generic Connectivity経由でdecimal型と同型の符号なしにアクセスした結果。

ここでは、以下のように定義した。

decimal(38,0)と同型の符号なし。
decimal(38,16)と同型の符号なし。

MySQL4.1.13a、MySQL4.0.25では、Oracleのnumber型の精度より低い。これらの型もGeneric Connectivity経由で参照、更新するのは避けたほうがよさそうである。
(実際にはインサート文も検証しているが結果は同じであるため省略)

1)MySQL4.0.25の decimal(38,0)とdecimal(38,0) unsignedを
  Generic Connectivity経由で問い合わせた結果

CORYDORAS> set numwidth 40
CORYDORAS> select
2 "r_decimal_38",
3 "r_decimal_38_unsigned"
4 from
5 num_test_mysql4025_mac@oracle10g_win;

r_decimal_38 r_decimal_38_unsigned
---------------------------------------- ----------------------------------------
NULL NULL
0 0
0 0
NULL NULL

中略

NULL NULL
99999999999999997748809823456034029568 0
-99999999999999997748809823456034029568 99999999999999997748809823456034029568
NULL NULL

中略

NULL NULL

25行が選択されました。

2)MySQL4.1.13aの decimal(38,0)とdecimal(38,0) unsignedを
  Generic Connectivity経由で問い合わせた結果

MySQL4.1.13aでは、不具合では?と思える部分(99999999999999999999999999999999999999が100000000000000035527741686413195739136となり精度が39桁になってしまっている)もある。

CORYDORAS> list
1 select
2 "r_decimal_38",
3 "r_decimal_38_unsigned"
4 from
5* num_test_mysql4113a_mac_sv@oracle10g_win
CORYDORAS> /

r_decimal_38 r_decimal_38_unsigned
---------------------------------------- ----------------------------------------
NULL NULL
0 0
0 0
NULL NULL

中略

NULL NULL
100000000000000035527741686413195739136 0
-99999999999999999999999999999999999999 99999999999999999999999999999999999999
NULL NULL
NULL NULL

27行が選択されました。

CORYDORAS>

3)MySQL4.0.25のdecimal(38,16)とdecimal(38,16) unsignedを
  Generic Connectivity経由で問い合わせた結果

decimalの精度は、doubleと同じというMySQL側の仕様の影響だと思われるが、MySQL独特な動作の一つである数値の丸めが発生し、decimal(38,0)では最大値の精度が23桁になってしまっている。これもgeneric connectivity経由での参照、更新対象にはしないほうがよいだろう。

CORYDORAS> select
2 "r_decimal_38_16",
3 "r_decimal_38_16_unsigned"
4 from
5 num_test_mysql4025_mac@oracle10g_win;

r_decimal_38_16 r_decimal_38_16_unsigned
---------------------------------------- ----------------------------------------
NULL NULL
0 0
0 0
NULL NULL

中略

NULL NULL
-9999999999999999999999.9999999999999999 0
10000000000000000000000 9999999999999999999999.9999999999999999
NULL NULL
NULL NULL

25行が選択されました。

4)MySQL4.1.13aのdecimal(38,16)とdecimal(38,16) unsignedを
  Generic Connectivity経由で問い合わせた結果。

3)とほぼ同じ結果であった。

CORYDORAS> list
1 select
2 "r_decimal_38_16",
3 "r_decimal_38_16_unsigned"
4 from
5* num_test_mysql4113a_mac_sv@oracle10g_win
CORYDORAS> /

r_decimal_38_16 r_decimal_38_16_unsigned
---------------------------------------- ----------------------------------------
NULL NULL
0 0
0 0
NULL NULL

中略

NULL NULL
-9999999999999999999999.9999999999999999 0
10000000000000004194304 9999999999999999999999.9999999999999999

27行が選択されました。

CORYDORAS>


==================================
Generic Connectivity経由での数値型の参照、更新のまとめ(MySQL4.0.x、4.1.x編)


利用している MyODBCドライバなどはこちら

数値型マッピング
MySQL4.0.25
MySQL4.1.13a
Oracle10g R1Generic Connectivityでの利用備 考
tinyint型 number型注1)
tinyint unsigned型 × 直接利用するのは避けたほうがよいだろう。参照するだけならば、MySQLの表データをCSVファイル化し外部表で取り込む等、直接参照しないアプローチを考えたほうがよいだろう。注1)
smallint型 注1)
smallint unsigned型 × 直接利用するのは避けたほうがよいだろう。参照するだけならば、MySQLの表データをCSVファイル化し外部表で取り込む等、直接参照しないアプローチを考えたほうがよいだろう。注1)
mediumint型 注1)
mediumint unsigned型 注1)
int型 注1)
int unsigned型 × 直接利用するのは避けたほうがよいだろう。参照するだけならば、MySQLの表データをCSVファイル化し外部表で取り込む等、直接参照しないアプローチを考えたほうがよいだろう。注1)
bigint型 × 直接利用するのは避けたほうがよいだろう。参照するだけならば、MySQLの表データをCSVファイル化し外部表で取り込む等、直接参照しないアプローチを考えたほうがよいだろう。注1)
bigint unsigned型 × 同上
float型 注1)
float unsigned型 注1)
double型 × 直接利用するのは避けたほうがよいだろう。参照するだけならば、MySQLの表データをCSVファイル化し外部表で取り込む等、直接参照しないアプローチを考えたほうがよいだろう。注1)
double unsigned型 × 同上
decimal(38,0)

double型と同じ精度ということなので、結果を見る限りdecimal(16,0)ぐらいまでなら利用できそうであるが、利用するのは避けたほうが無難かもしれない。どうしても利用したい場合には、Generic Connectivity以外のアプローチを考えたほうがよいかもしれない。例えば、参照だけならば、MySQLのデータをCSVファイル化し外部表で取り込む等。注1)

decimal(38,0) unsigned 同上
decimal(38,16) ×

直接利用するのは避けたほうがよいだろう。参照するだけならば、MySQLの表データをCSVファイル化し外部表で取り込む等、直接参照しないアプローチを考えたほうがよいだろう。注1)

decimal(38,16) unsigned × 同上

注1)数値型を扱う際にinsertやupdate文では、値が有効範囲を超えると数値が最大値、最小値に丸められるというMySQLの仕様に要注意。但し、MySQL5.0.2以降であればSQL_MODEの設定でエラーとして扱うこともできるようなので、それがうまく機能すれば回避することは可能かもしれない。(現時点では未確認)

次回、文字型の検証へつづく。

| | | コメント (0) | トラックバック (0)

2006年2月21日 (火)

Mac De Oracle Heterogeneous! #44

数値型のつづき。

Generic Connectivity経由でMySQL4.0.25及び、MySQL4.1.13aの数値型にアクセス 8回目。

Generic Connectivity経由でdouble型と同型の符号なしにアクセスした結果。

PostgreSQL7.4.9の場合と同様にGeneric Connectivity経由での参照、更新は避けたほうがよい。

問合せの結果だけを載せる。(データの登録も行ったが結果は同じであったため省略)

1)MySQL4.0.25をGeneic Connectivity経由で問い合わせた結果。

CORYDORAS> select
2 "r_double",
3 "r_double_unsigned"
4 from
5 num_test_mysql4025_mac@oracle10g_win;

r_double r_double_unsigned
---------- -----------------
NULL NULL
0 0
0 0
NULL NULL

中略

NULL NULL
-˜ 0
˜ 0
0 0
0 ˜
NULL NULL

中略

NULL NULL

25行が選択されました。

CORYDORAS>

2)MySQl4.1.13aをGeneric Connectivity経由で問い合わせた結果。
CORYDORAS> select
2 "r_double",
3 "r_double_unsigned"
4 from
5 num_test_mysql4113a_mac_sv@oracle10g_win;

r_double r_double_unsigned
---------- -----------------
NULL NULL
0 0
0 0
NULL NULL

中略

NULL NULL
-˜ 0
˜ 0
0 0
0 ˜
NULL NULL

中略

NULL NULL

27行が選択されました。

CORYDORAS>


次につづく。

| | | コメント (0) | トラックバック (0)

2006年2月20日 (月)

Mac De Oracle Heterogeneous! #43

数値型のつづき。

Generic Connectivity経由でMySQL4.0.25及び、MySQL4.1.13aの数値型にアクセス 7回目。

Generic Connectivity経由でfloat型と同型の符号なしにアクセスした結果。

MySQL4.0.2.25、 MySQL4.1.13aともにfloat型の利用は問題ないと思われる。


1)MySQL4.0.25をGeneric Connectivity経由で問い合わせた結果。

CORYDORAS> set numwidth 10
CORYDORAS> list
1 select
2 "r_float",
3 "r_float_unsigned"
4 from
5* num_test_mysql4025_mac@oracle10g_win
CORYDORAS> /

r_float r_float_unsigned
---------- ----------------
NULL NULL
0 0
0 0
NULL NULL

中略

NULL NULL
-3.400E+38 0
3.4000E+38 NULL
-1.200E-38 1.2000E-38
1.2000E-38 3.4000E+38
NULL NULL

中略

NULL NULL

25行が選択されました。

2)MySQL4.1.13aをGeneric Connectivity経由で問い合わせた結果。
CORYDORAS> list
1 select
2 "r_float",
3 "r_float_unsigned"
4 from
5* num_test_mysql4113a_mac_sv@oracle10g_win
CORYDORAS> /

r_float r_float_unsigned
---------- ----------------
NULL NULL
0 0
0 0
NULL NULL

中略

NULL NULL
-3.400E+38 0
3.4000E+38 NULL
-1.200E-38 1.2000E-38
1.2000E-38 3.4000E+38
NULL NULL

中略

NULL NULL

27行が選択されました。

CORYDORAS>

3)MySQL4.0.25へ最大値、最小値、アンダーフローする値、オーバーフローする値を登録した結果。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_float","r_float_unsigned")
2 values(-3.4e38,0);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_float","r_float_unsigned")
2 values(3.4e38,null);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_float","r_float_unsigned")
2 values(-1.2e-38,1.2e-38)
3 ;

1行が作成されました。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_float","r_float_unsigned")
2 values(1.2e-38,3.4e38);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_float","r_float_unsigned")

2 values(-3.5e38,-1.0e38);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_float","r_float_unsigned")
2 values(3.5e38,3.5e38);

1行が作成されました。

CORYDORAS> select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a."r_float",
7 a."r_float_unsigned"
8 from
9 num_test_mysql4025_mac@oracle10g_win a
10 )
11 where
12 "rownum" > 25;

rownum r_float r_float_unsigned
---------- ---------- ----------------
26 -3.400E+38 0
27 3.4000E+38 NULL
28 -1.200E-38 1.2000E-38
29 1.2000E-38 3.4000E+38
30 -3.403E+38 0
31 3.4028E+38 3.4028E+38

6行が選択されました。

CORYDORAS> rollback;

ロールバックが完了しました。


4)MySQL4.1.13aへ最大値、最小値、アンダーフローする値、オーバーフローする値を登録した結果。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_float","r_float_unsigned")
2 values(-3.4e38,0);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_float","r_float_unsigned")
2 values(3.4e38,null);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g 2 _win("r_float","r_float_unsigned")
2 values(-1.2e-38,1.2e-38);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_float","r_float_unsigned")
2 values(1.2e-38,3.4e38);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_float","r_float_unsigned")
2 values(-3.5e38,-1.0e38);

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_float","r_float_unsigned")
2 values(3.5e38,3.5e38);

1行が作成されました。

CORYDORAS> select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a."r_float",
7 a."r_float_unsigned"
8 from
9 num_test_mysql4113a_mac_sv@oracle10g_win a
10 )
11 where
12 "rownum" > 27;

rownum r_float r_float_unsigned
---------- ---------- ----------------
28 -3.400E+38 0
29 3.4000E+38 NULL
30 -1.200E-38 1.2000E-38
31 1.2000E-38 3.4000E+38
32 -3.403E+38 0
33 3.4028E+38 3.4028E+38

6行が選択されました。

CORYDORAS> rollback;

ロールバックが完了しました。

CORYDORAS>


次回につづく。

| | | コメント (0) | トラックバック (0)

2006年2月19日 (日)

Mac De Oracle Heterogeneous! #42

数値型のつづき。

Generic Connectivity経由でMySQL4.0.25及び、MySQL4.1.13aの数値型にアクセス 6回目。

Generic Connectivity経由でbigint型と同型の符号なしにアクセスした結果。

MySQL4.0.2.25、 MySQL4.1.13aともにbigint型は Generic Connectivity経由で利用しないほうがよいだろう。

1)MySQL4.0.25をGeneric Connectivity経由で問い合わせた結果。

0のはずが、48と表示される。最大値、最長値とも設定した値とは異なる値が表示されている。

CORYDORAS> select
2 "r_bigint",
3 "r_bigint_unsigned"
4 from
5 num_test_mysql4025_mac@oracle10g_win;

r_bigint r_bigint_unsigned
---------------------------------------- ----------------------------------------
NULL NULL
48 48
48 48
NULL NULL

中略

NULL NULL
15537418697586989 48
14134441877320249 14697404732553265
NULL NULL

中略

NULL NULL

25行が選択されました。

2)MySQL4.1.13aをGeneric Connectivity経由で問い合わせた結果。

1)の場合と同じくNG。

CORYDORAS> 
CORYDORAS> list
1 select
2 "r_bigint",
3 "r_bigint_unsigned"
4 from
5* num_test_mysql4113a_mac_sv@oracle10g_win
CORYDORAS> /

r_bigint r_bigint_unsigned
---------------------------------------- ----------------------------------------
NULL NULL
48 48
48 48
NULL NULL

中略

NULL NULL
15537418697586989 48
14134441877320249 14697404732553265
15537418697586989 14697404732553265
15537418697586989 14697404732553265
NULL NULL

中略

NULL NULL

27行が選択されました。

3)MySQL4.0.25へ最大値、最小値、許容範囲を超える値を登録した結果。

登録した値とは全く異なる値になってしまう。

CORYDORAS> 
CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_bigint","r_bigint_unsigned")
2 values(-9223372036854775808,0);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_bigint","r_bigint_unsigned")
2 values(9223372036854775807,18446744073709551615);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_bigint","r_bigint_unsigned")
2 values(-9223372036854775809, -1);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_bigint","r_bigint_unsigned")
2 values(9223372036854775808, 18446744073709551616);

1行が作成されました。

CORYDORAS> select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a."r_bigint",
7 a."r_bigint_unsigned"
8 from
9 num_test_mysql4025_mac@oracle10g_win a
10 )
11 where
12 "rownum" > 25;

rownum r_bigint r_bigint_unsigned
---------------------------------------- ---------------------------------------- ----------------------------------------
26 15537418697586989 48
27 14134441877320249 14697404732553265
28 15537418697586989 14697404732553265
29 15537418697586989 14697404732553265

CORYDORAS>
CORYDORAS> rollback;

ロールバックが完了しました。

4)MySQL4.1.13aへ最大値、最小値、許容範囲を超える値を登録。

3)と同じ結果。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_bigint","r_bigint_unsigned")
2 values(-9223372036854775808,0);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_bigint","r_bigint_unsigned")
2 values(9223372036854775807,18446744073709551615);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_bigint","r_bigint_unsigned")
2 values(-9223372036854775809, -1);

1行が作成されました。

CORYDORAS> insert int 2 o num_test_mysql4113a_mac_sv@oracle10g_win("r_bigint","r_bigint_unsigned")
2 values(9223372036854775808, 18446744073709551616);

1行が作成されました。

CORYDORAS> list
1 select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a."r_bigint",
7 a."r_bigint_unsigned"
8 from
9 num_test_mysql4113a_mac_sv@oracle10g_win a
10 )
11 where
12* "rownum" > 27
CORYDORAS> /

rownum r_bigint r_bigint_unsigned
---------------------------------------- ---------------------------------------- ----------------------------------------
28 15537418697586989 48
29 14134441877320249 14697404732553265
30 15537418697586989 14697404732553265
31 15537418697586989 14697404732553265

CORYDORAS> rollback;

ロールバックが完了しました。

CORYDORAS>

次へつづく。

| | | コメント (0) | トラックバック (0)

2006年2月18日 (土)

Mac De Oracle Heterogeneous! #41

数値型のつづき。

Generic Connectivity経由でMySQL4.0.25及び、MySQL4.1.13aの数値型にアクセス 5回目。

Generic Connectivity経由でint型と同型の符号なしにアクセスした結果。

MySQL4.0.2.25、 MySQL4.1.13aともにint型の符号なしは NG。 Generic Connectivity経由で、符号なしint型は利用しないほうがよいだろう。

1)MySQL4.0.25をGeneric Connectivity経由で問い合わせた結果。

CORYDORAS> list
1 select
2 "r_int",
3 "r_int_unsigned"
4 from
5* num_test_mysql4025_mac@oracle10g_win
CORYDORAS> /

r_int r_int_unsigned
---------------------------------------- ----------------------------------------
NULL NULL
0 0
0 0
NULL NULL

中略

NULL NULL
-2147483648 0
2147483647 -1
NULL NULL

中略

NULL NULL

25行が選択されました。

2)MySQL4.1.13aをGeneric Connectivity経由で問い合わせた結果。

CORYDORAS> list
1 select
2 "r_int",
3 "r_int_unsigned"
4 from
5* num_test_mysql4113a_mac_sv@oracle10g_win
CORYDORAS> /

r_int r_int_unsigned
---------------------------------------- ----------------------------------------
NULL NULL
0 0
0 0
NULL NULL

中略

NULL NULL
-2147483648 0
2147483647 -1
NULL NULL

中略

NULL NULL

27行が選択されました。

CORYDORAS>

3)MySQL4.0.25へ最大値、最小値、許容範囲を超える値を登録した結果。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_int", "r_int_unsigned")
2 values(-2147483648,0);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_int", "r_int_unsigned")
2 values(2147483647,4294967295);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_int", "r_int_unsigned")
2 values(-2147483649,-1);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_int", "r_int_unsigned")
2 values(2147483648,4294967296);

1行が作成されました。

CORYDORAS> list
1 select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a."r_int",
7 a."r_int_unsigned"
8 from
9 num_test_mysql4025_mac@oracle10g_win a
10 )
11 where
12* "rownum" > 25
CORYDORAS> /

rownum r_int r_int_unsigned
---------------------------------------- ---------------------------------------- ----------------------------------------
26 -2147483648 0
27 2147483647 -1
28 -2147483648 0
29 2147483647 -1

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS>

4)MySQL4.1.13aへ最大値、最小値、許容範囲を超える値を登録した結果。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_int", "r_int_unsigned")
2 values(-2147483648,0);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_int", "r_int_unsigned")
2 values(2147483647,4294967295);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@o 2 racle10g_win("r_int", "r_int_unsigned")
2 values(-2147483649,-1);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_int", "r_int_unsigned")
2 values(2147483648,4294967296);

1行が作成されました。

CORYDORAS> list
1 select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a."r_int",
7 a."r_int_unsigned"
8 from
9 num_test_mysql4113a_mac_sv@oracle10g_win a
10 )
11 where
12* "rownum" > 27
CORYDORAS> /

rownum r_int r_int_unsigned
---------------------------------------- ---------------------------------------- ----------------------------------------
28 -2147483648 0
29 2147483647 -1
30 -2147483648 0
31 2147483647 -1

CORYDORAS>
CORYDORAS> rollback;

ロールバックが完了しました。

CORYDORAS>

次回につづく。

| | | コメント (0) | トラックバック (0)

2006年2月17日 (金)

Mac De Oracle Heterogeneous! #40

数値型のつづき。

Generic Connectivity経由でMySQL4.0.25及び、MySQL4.1.13aの数値型にアクセス 4回目。

Generic Connectivity経由でmediumint型と同型の符号なしにアクセスした結果。

tinyint,smallint型とは異なり、符号なしでも問題はない。

1)MySQL4.0.25への問合せ。

CORYDORAS> select
2 "r_mediumint",
3 "r_mediumint_unsigned"
4 from
5 num_test_mysql4025_mac@oracle10g_win;

r_mediumint r_mediumint_unsigned
----------- --------------------
NULL NULL
0 0
0 0
NULL NULL

中略

NULL NULL
-8388608 0
8388607 16777215
NULL NULL

中略

NULL NULL

25行が選択されました。

CORYDORAS>

2)MySQL4.0.25への最大値、最小値、及び、許容範囲を超える値の登録。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_mediumint", "r_mediumint_unsigned")
2 values(-8388608,0);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_mediumint", "r_mediumint_unsigned")
2 values(8388607,16777215);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_mediumint", "r_mediumint_unsigned")
2 values(-8388609,-1);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_mediumint", "r_mediumint_unsigned")
2 values(8388608,16777216);

1行が作成されました。


CORYDORAS> list
1 select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a."r_mediumint",
7 a."r_mediumint_unsigned"
8 from
9 num_test_mysql4025_mac@oracle10g_win a
10 )
11 where
12* "rownum" > 25
CORYDORAS> /

rownum r_mediumint r_mediumint_unsigned
---------- ----------- --------------------
26 -8388608 0
27 8388607 16777215
28 -8388608 0
29 8388607 16777215

CORYDORAS> rollback;

ロールバックが完了しました。

3)MySQL4.1.13aへの問合せ。

CORYDORAS> select
2 "r_mediumint",
3 "r_mediumint_unsigned"
4 from
5 num_test_mysql4113a_mac_sv@oracle10g_win;

r_mediumint r_mediumint_unsigned
----------- --------------------
NULL NULL
0 0
0 0
NULL NULL

中略

NULL NULL
-8388608 0
8388607 16777215
NULL NULL

中略

NULL NULL

27行が選択されました。

4)MySQL4.1.13aへの最大値、最小値、及び、許容範囲を超える値の登録。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_mediumint", "r_mediumint_unsigned")
2 values(-8388608,0);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_mediumint", "r_mediumint_unsigned")
2 values(8388607,16777215);

1行が作成されました。

CORYDORAS> insert into num_test_mys 2 ql4113a_mac_sv@oracle10g_win("r_mediumint", "r_mediumint_unsigned")
2 values(-8388609,-1);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_mediumint", "r_mediumint_unsigned")
2 values(8388608,16777216);

1行が作成されました。

CORYDORAS> list
1 select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a."r_mediumint",
7 a."r_mediumint_unsigned"
8 from
9 num_test_mysql4113a_mac_sv@oracle10g_win a
10 )
11 where
12* "rownum" > 27
CORYDORAS> /

rownum r_mediumint r_mediumint_unsigned
---------- ----------- --------------------
28 -8388608 0
29 8388607 16777215
30 -8388608 0
31 8388607 16777215

CORYDORAS> rollback;

ロールバックが完了しました。

CORYDORAS>

次回へつづく。

| | | コメント (0) | トラックバック (0)

2006年2月16日 (木)

Mac De Oracle Heterogeneous! #39

数値型のつづき。

Generic Connectivity経由でMySQL4.0.25及び、MySQL4.1.13aの数値型にアクセス 3回目。

1) smallint型及び、同型の符号なし。

tinyint型の場合と同様に符号なしは、NG。

CORYDORAS> select
2 "r_smallint",
3 "r_smallint_unsigned"
4 from
5 num_test_mysql4025_mac@oracle10g_win;

r_smallint r_smallint_unsigned
---------- -------------------
NULL NULL
0 0
0 0
NULL NULL
NULL NULL
-32768 0
32767 -1
NULL NULL

中略

NULL NULL

25行が選択されました。

CORYDORAS>

1−1)MySQL4.0.25への最大値と最小値、許容範囲を超える値の登録。

これもMySQL側の挙動の通りだが、符号なしは NG。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_smallint", "r_smallint_unsigned")
2 values(-32768,0);

1行が作成されました。

insert into num_test_mysql4025_mac@oracle10g_win("r_smallint", "r_smallint_unsigned")
2 values(32767,65535);

1行が作成されました。

insert into num_test_mysql4025_mac@oracle10g_win("r_smallint", "r_smallint_unsigned")
2 values(-32769,-1);

1行が作成されました。

insert into num_test_mysql4025_mac@oracle10g_win("r_smallint", "r_smallint_unsigned")
2 values(32768,65536);

1行が作成されました。


CORYDORAS> list
1 select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a."r_smallint",
7 a."r_smallint_unsigned"
8 from
9 num_test_mysql4025_mac@oracle10g_win a
10 )
11 where
12* "rownum" > 25
CORYDORAS> /

rownum r_smallint r_smallint_unsigned
---------- ---------- -------------------
26 -32768 0
27 32767 -1
28 -32768 0
29 32767 -1

CORYDORAS>

CORYDORAS> rollback;

ロールバックが完了しました。

1−2)MySQL4.1.13aへの最大値と最小値、許容範囲を超える値の登録。

これもMySQL側の挙動の通りだが、符号なしは NG。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_smallint", "r_smallint_unsigned")
2 values(-32768,0);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_smallint", "r_smallint_unsigned")
2 values(32767,65535);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4113a_mac 2 _sv@oracle10g_win("r_smallint", "r_smallint_unsigned")
2 values(-32769,-1);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_smallint", "r_smallint_unsigned")
2 values(32768,65536);

1行が作成されました。

CORYDORAS> select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a."r_smallint",
7 a."r_smallint_unsigned"
8 from
9 num_test_mysql4113a_mac_sv@oracle10g_win a
10 )
11 where
12 "rownum" > 27;

rownum r_smallint r_smallint_unsigned
---------- ---------- -------------------
28 -32768 0
29 32767 -1
30 -32768 0
31 32767 -1

CORYDORAS> rollback;

ロールバックが完了しました。

CORYDORAS>

次回へつづく。

| | | コメント (0) | トラックバック (0)

2006年2月15日 (水)

Mac De Oracle Heterogeneous! #38

数値型のつづき。
Generic Connectivity経由でMySQL4.0.25及び、MySQL4.1.13aの数値型にアクセス 2回目。 tinyint型と同型の符号なし。

1)MySQLのtinyint型及び、同型の符号なしの検証。

  tinyint型は問題ないのだが、符号なしは NG。

1−1)MySQL4.1.13aにGeneric Connectivity経由で問合せをした結果

CORYDORAS> list
1 select
2 "r_tinyint",
3 "r_tinyint_unsigned"
4 from
5* num_test_mysql4113a_mac_sv@oracle10g_win
CORYDORAS> /

r_tinyint r_tinyint_unsigned
---------- ------------------
NULL NULL
0 0
0 0
-128 0
127 -1
NULL NULL
NULL NULL

中略

NULL NULL

27行が選択されました。

CORYDORAS>

1−2)MySQL4.0.25にGeneric Connectivity経由で問合せをした結果

CORYDORAS> list
1 select
2 "r_tinyint",
3 "r_tinyint_unsigned"
4 from
5* num_test_mysql4025_mac@oracle10g_win
CORYDORAS> /

r_tinyint r_tinyint_unsigned
---------- ------------------
NULL NULL
0 0
0 0
-128 0
127 -1
NULL NULL

中略

NULL NULL

25行が選択されました。

CORYDORAS>

1−3)MySQL4.1.13aへGeneric Connectivity経由でインサート文を発行。
   各型の最小値、最大値、許容範囲を超える値を登録。

MySQL上ではワーニングが返るが、Generic Connectivity経由では正常に処理される。MySQL側では許容範囲を超える数値は丸められ、最小値、最大値に置換される。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_tinyint", "r_tinyint_unsigned")
2 values(-128,0);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_tinyint","r_tinyint_unsigned")
2 values(127,255);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_tinyint","r_tinyint_unsigned")
2 values(-129,-1);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4113a_mac_sv@oracle10g_win("r_tinyint","r_tinyint_unsigned")
2 values(128,256);

1行が作成されました。

CORYDORAS> list
1 select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a."r_tinyint",
7 a."r_tinyint_unsigned"
8 from
9 num_test_mysql4113a_mac_sv@oracle10g_win a
10 )
11 where
12* "rownum" > 27
CORYDORAS> /

rownum r_tinyint r_tinyint_unsigned
---------- ---------- ------------------
28 -128 0
29 127 -1
30 -128 0
31 127 -1

CORYDORAS>

CORYDORAS> rollback;

ロールバックが完了しました。

1−4)MySQL4.0.25へGeneric Connectivity経由でインサート文を発行。
    各型の最小値、最大値、許容範囲を超える値を登録。

結果は、MySQL4.1.13aと同じ。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_tinyint", "r_tinyint_unsigned")
2 values(-128,0);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_tinyint","r_tinyint_unsigned")
2 values(127,255);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_tinyint","r_tinyint_unsigned")
2 values(-129,-1);

1行が作成されました。

CORYDORAS> insert into num_test_mysql4025_mac@oracle10g_win("r_tinyint","r_tinyint_unsigned")
2 values(128,256);

1行が作成されました。

CORYDORAS> list
1 select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a."r_tinyint",
7 a."r_tinyint_unsigned"
8 from
9 num_test_mysql4025_mac@oracle10g_win a
10 )
11 where
12* "rownum" > 25
CORYDORAS> /

rownum r_tinyint r_tinyint_unsigned
---------- ---------- ------------------
26 -128 0
27 127 -1
28 -128 0
29 127 -1

CORYDORAS> rollback;

ロールバックが完了しました。

CORYDORAS> select count(*) from num_test_mysql4025_mac@oracle10g_win;

COUNT(*)
----------
25

CORYDORAS>

次回につづく。

| | | コメント (0) | トラックバック (0)

2006年2月14日 (火)

Mac De Oracle Heterogeneous! #37

数値型のつづき。MySQLでの数値型の癖はある程度見えたので、ここからはGeneric Connectivity経由でMySQL4.0.25及び、MySQL4.1.13aの数値型にアクセスし、その挙動を検証する。

以下のような経路でアクセスしている


gencon_blog_img1

Oracle10g R1(Windows XP Professional)には、num_test_mysql4025_mac(MySQL4.0.25のnum_test表へのシノニム)とnum_test_mysql4113a_mac_sv(MySQL4.1.13aのnum_test表へのシノニム)という2つのシノニムを作成しておく。

CORYDORAS> select synonym_name from user_synonyms@oracle10g_win;

SYNONYM_NAME
------------------------------
NUM_TEST_POSTGRESQL749_MAC
NUM_TEST_MYSQL4113A_MAC_SV
NUM_TEST_MYSQL4025_MAC
DATE_TEST_MYSQL4026_WIN
DATE_TEST_MYSQL4113A_MAC_SV
DATE_TEST_POSTGRESQL749_MAC
EMP_MYSQL4025_MAC
INNO_EMP_MYSQL4025_MAC
EMP_MYSQL4026_WIN
EMP_MYSQL4113A_MAC_SV
EMP_POSTGRESQL749_MAC
ORACLE_EMP_MYSQL4026_WIN

12行が選択されました。

CORYDORAS>

おっと! いきなり問題発生。27行しかないのに count(*)の結果が14130行とは? 問題はMySQL側にあるように思える。MySQL4.0.25では正しい結果が取得できるが、MySQl4.1.13aでは見ての通り。試しに、execute immediate文で試してみたが同じ結果だった。

さて、どうすればいいか? 

ということで、回避策としてrownumの最大値を取得するという方法(なかなかキツいね。)

CORYDORAS> select count(*) from num_test_mysql4113a_mac_sv@oracle10g_win;

COUNT(*)
----------
14130

CORYDORAS> select count(*) from num_test_mysql4025_mac@oracle10g_win;

COUNT(*)
----------
25

CORYDORAS>

CORYDORAS> set serveroutput on;
CORYDORAS> list
1 declare
2 rows pls_integer;
3 begin
4 execute immediate 'select count(*) as ctr from num_test_mysql4113a_mac_sv@oracle10g_win' into rows;
5 dbms_output.put_line(rows);
6* end;
CORYDORAS> /
14130

PL/SQLプロシージャが正常に完了しました。

CORYDORAS> select max(rownum) from num_test_mysql4113a_mac_sv@oracle10g_win;

MAX(ROWNUM)
----------------------------------------
27

CORYDORAS>

さて、最初から凹み気味だが、MySQLの数値型は、Oracleではすべて number型 にマッピングされる。

CORYDORAS> list
1 select
2 dump("r_tinyint") as "tinyint",
3 dump("r_tinyint_unsigned") as "tinyint_unsigned",
4 dump("r_smallint") as "smallint",
5 dump("r_smallint_unsigned") as "smallint_unsigned",
6 dump("r_mediumint") as "mediumint",
7 dump("r_mediumint_unsigned") as "mediumint_unsigned",
8 dump("r_int") as "int",
9 dump("r_int_unsigned") as "int_unsigned"
10 from
11 num_test_mysql4025_mac@oracle10g_win
12 where
13* rownum <= 2
CORYDORAS> /

tinyint tinyint_unsigned smallint smallint_unsigne mediumint mediumint_unsign int int_unsigned
---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ---------------- ----------------
NULL NULL NULL NULL NULL NULL NULL NULL
Typ=2 Len=1: 128 Typ=2 Len=1: 128 Typ=2 Len=1: 128 Typ=2 Len=1: 128 Typ=2 Len=1: 128 Typ=2 Len=1: 128 Typ=2 Len=1: 128 Typ=2 Len=1: 128
CORYDORAS>

次回につづく。

| | | コメント (0) | トラックバック (0)

2006年2月13日 (月)

Mac De Oracle Heterogeneous! #36

数値型の検証のつづき(MySQL編の第4回目)。。decimal型のdecimal(38,0)とdecimal(38,16)、それらの型で符号なし。

1)decimal型

1−1)decimal(38,0)と符号なしdecimal(38,0)

精度はdouble型と同じであるとマニュアルに記載されているので、decimal(38,0)の場合だとOracleのnumber(38,0)より精度が劣るようだ。
decimal型をOracleに取り込むだけなら、精度の範囲内なので利用できそうであるが、OracleからMySQLへ登録したり更新する場合は注意が必要だ。decimal(16,0)くらいなら利用できる可能性はあるが実際に確認してから利用するか否かを決めた方がよさそうである。

mysql> insert into
-> num_test(r_decimal_38, r_decimal_38_unsigned)
-> values(
-> 99999999999999999999999999999999999999,
-> 0
-> );
Query OK, 1 row affected (0.00 sec)

mysql> insert into
-> num_test(r_decimal_38, r_decimal_38_unsigned)
-> values(
-> -99999999999999999999999999999999999999,
-> 99999999999999999999999999999999999999
-> );
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.07 sec)

mysql> insert into
-> num_test(r_decimal_38, r_decimal_38_unsigned)
-> values(100000000000000000000000000000000000000,-1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into
-> num_test(r_decimal_38,r_decimal_38_unsigned)
-> values(-100000000000000000000000000000000000000,100000000000000000000000000000000000000);
Query OK, 1 row affected (0.00 sec)

mysql> select
-> r_decimal_38,
-> r_decimal_38_unsigned
-> from
-> num_test
-> limit
-> 21,-1;
+-----------------------------------------+----------------------------------------+
| r_decimal_38 | r_decimal_38_unsigned |
+-----------------------------------------+----------------------------------------+
| 99999999999999997748809823456034029568 | 0 |
| -99999999999999997748809823456034029568 | 99999999999999997748809823456034029568 |
| 99999999999999997748809823456034029568 | 0 |
| -99999999999999997748809823456034029568 | 99999999999999997748809823456034029568 |
+-----------------------------------------+----------------------------------------+
4 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.39 sec)

mysql>

MySQL4.0.25では正常に見えるが実は、丸め処理が行われている。MySQL4.1.13aで同じインサート文を発行すると2件のワーニングが返される。内容は以下の通り out of range。そして、r_decimal_38の精度は38桁なのだが39桁になってしまった。MySQLのバージョン毎に対応を変えるというか、変えられるような作り込みが必要になる可能性もでてきた。
mysql>
mysql> insert into
-> num_test(r_decimal_38, r_decimal_38_unsigned)
-> values(
-> 99999999999999999999999999999999999999,
-> 0
-> );
Query OK, 1 row affected (0.00 sec)

mysql>
mysql> insert into
-> num_test(r_decimal_38, r_decimal_38_unsigned)
-> values(
-> -99999999999999999999999999999999999999,
-> 99999999999999999999999999999999999999
-> );
Query OK, 1 row affected, 2 warnings (0.01 sec)

mysql> show warnings;
+---------+------+--------------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+--------------------------------------------------------------------------+
| Warning | 1264 | Data truncated; out of range for column 'r_decimal_38' at row 1 |
| Warning | 1264 | Data truncated; out of range for column 'r_decimal_38_unsigned' at row 1 |
+---------+------+--------------------------------------------------------------------------+
2 rows in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.06 sec)


mysql> edit
-> \¥g
+-----------------------------------------+----------------------------------------+
| r_decimal_38 | r_decimal_38_unsigned |
+-----------------------------------------+----------------------------------------+
| 100000000000000035527741686413195739136 | 0 |
| -99999999999999999999999999999999999999 | 99999999999999999999999999999999999999 |
+-----------------------------------------+----------------------------------------+
2 rows in set (0.00 sec)

mysql>

1−2)decimal(38,16)と符号なしdecimal(38,16)

これは問題無さそうだと思い見逃しそうになったのだが、よくよく結果をみてみると、decimal(38.16)で最小値はよいのだが、最大値がまずい。精度が22桁なのに、最大値が23桁になっている。(これも不具合だろうか?。Generic Connectivity経由ではdecimal型も利用しないほうがよいかもしれない。まだ、テストしていないので使えるか不明だが。。)
以下、MySQL4.0.25での実行結果。

mysql> insert into
-> num_test(r_decimal_38_16, r_decimal_38_16_unsigned)
-> values
-> (-9999999999999999999999.9999999999999999,0),
-> ( 9999999999999999999999.9999999999999999,9999999999999999999999.9999999999999999);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 2

mysql> commit;
Query OK, 0 rows affected (0.06 sec)

mysql> insert into
-> num_test(r_decimal_38_16, r_decimal_38_16_unsigned)
-> values(-10000000000000000000000.99999999999999995,-1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into
-> num_test(r_decimal_38_16, r_decimal_38_16_unsigned)
-> values(10000000000000000000000.99999999999999994,10000000000000000000000.99999999999999995);
Query OK, 1 row affected (0.00 sec)

mysql> select
-> r_decimal_38_16,
-> r_decimal_38_16_unsigned
-> from
-> num_test
-> limit
-> 23,-1;
+------------------------------------------+-----------------------------------------+
| r_decimal_38_16 | r_decimal_38_16_unsigned |
+------------------------------------------+-----------------------------------------+
| -9999999999999999999999.9999999999999999 | 0.0000000000000000 |
| 10000000000000000000000.0000000000000000 | 9999999999999999999999.9999999999999999 |
| -9999999999999999999999.9999999999999999 | 0.0000000000000000 |
| 10000000000000000000000.0000000000000000 | 9999999999999999999999.9999999999999999 |
+------------------------------------------+-----------------------------------------+
4 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.38 sec)

mysql>

以下、MySQL4.1.13aでの実行結果。精度が1桁多くなる現象もあるが値も微妙に違う。
mysql> insert into
-> num_test(r_decimal_38_16, r_decimal_38_16_unsigned)
-> values
-> (-9999999999999999999999.9999999999999999,0),
-> ( 9999999999999999999999.9999999999999999,9999999999999999999999.9999999999999999);
Query OK, 2 rows affected, 2 warnings (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 2

mysql>
mysql> commit;
Query OK, 0 rows affected (0.05 sec)

mysql>
mysql> insert into
-> num_test(r_decimal_38_16, r_decimal_38_16_unsigned)
-> values(-10000000000000000000000.99999999999999995,-1);
Query OK, 1 row affected, 2 warnings (0.00 sec)

mysql>
mysql> insert into
-> num_test(r_decimal_38_16, r_decimal_38_16_unsigned)
-> values(10000000000000000000000.99999999999999994,10000000000000000000000.99999999999999995);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> select
-> r_decimal_38_16,
-> r_decimal_38_16_unsigned
-> from
-> num_test
-> limit
-> 25,99;
+------------------------------------------+-----------------------------------------+
| r_decimal_38_16 | r_decimal_38_16_unsigned |
+------------------------------------------+-----------------------------------------+
| -9999999999999999999999.9999999999999999 | 0.0000000000000000 |
| 10000000000000004194304.0000000000000000 | 9999999999999999999999.9999999999999999 |
| -9999999999999999999999.9999999999999999 | 0.0000000000000000 |
| 10000000000000002097152.0000000000000000 | 9999999999999999999999.9999999999999999 |
+------------------------------------------+-----------------------------------------+
4 rows in set (0.00 sec)

mysql>

長いので次回につづく。

| | | コメント (0) | トラックバック (0)

2006年2月12日 (日)

Mac De Oracle Heterogeneous! #35

数値型の検証のつづき(MySQL編の第3回目)・・・float型、double型及び、各型の符号なし

1)float型
MySQL4.0.25とMySQL4.1.13aは同じ挙動であった。オーバーフロー、アンダーフローを丸めてしまう点も同じ。

mysql> insert into 
-> num_test(r_float, r_float_unsigned)
-> values(-3.4e38,0),(3.4e38,null),(-1.2e-38,1.2e-38),(1.2e-38,3.4e38);
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into
-> num_test(r_float, r_float_unsigned)
-> values(-3.5e38,-1.0e38);
Query OK, 1 row affected (0.00 sec)

mysql> insert into
-> num_test(r_float, r_float_unsigned)
-> values(3.5e38,3.5e38);
Query OK, 1 row affected (0.00 sec)

mysql> select
-> r_float,
-> r_float_unsigned
-> from
-> num_test
-> limit
-> 13,-1;
+--------------+------------------+
| r_float | r_float_unsigned |
+--------------+------------------+
| -3.4e+38 | 0 |
| 3.4e+38 | NULL |
| -1.2e-38 | 1.2e-38 |
| 1.2e-38 | 3.4e+38 |
| -3.40282e+38 | 0 |
| 3.40282e+38 | 3.40282e+38 |
+--------------+------------------+
6 rows in set (0.00 sec)

mysql> rollback;

ちなみに、MySQl4.1.13aで同じインサート文を実行すると、ワーニングが2件返され、オーバフローした値、及びアンダーフローした値は、それぞれ最大値、最小値に丸めらる。

mysql> insert into
-> num_test(r_float, r_float_unsigned)
-> values(-3.5e38,-1.0e38);
Query OK, 1 row affected, 2 warnings (0.00 sec)

mysql> show warnings;
+---------+------+---------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+---------------------------------------------------------------------+
| Warning | 1264 | Data truncated; out of range for column 'r_float' at row 1 |
| Warning | 1264 | Data truncated; out of range for column 'r_float_unsigned' at row 1 |
+---------+------+---------------------------------------------------------------------+
2 rows in set (0.00 sec)

mysql>

2)double型
MySQL4.0.25は特に問題なさそうだが、MySQL4.1.13aではdouble型の値が0と−0となってしまった。(これも不具合だろう)。double unsigned型のアンダーフロー処理が改善された反面、double型のオーバフローとアンダーフローの丸め処理がデグっているように見える。

+------------+-------------------+
| r_double | r_double_unsigned |
+------------+-------------------+
| 2.3e-308 | 2.3e-308 |
| -2.3e-308 | 1.79e+308 |

となっているが、MySQL4.1.13aでは、double型の丸め処理に問題がありそうな結果だ。
+------------+-------------------+
| r_double | r_double_unsigned |
+------------+-------------------+
| 0 | 0 |
| -0 | 1.79e+308 |

以下、MySQL4.0.25でインサート文を実行した結果

mysql> insert into
-> num_test(r_double,r_double_unsigned)
-> values(-1.79e308,0),(1.79e308,0),(2.3e-308,2.3e-308),(-2.3e-308,1.79e308);
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.08 sec)

mysql> select
-> r_double,
-> r_double_unsigned
-> from
-> num_test
-> limit
-> 17,-1;
+------------+-------------------+
| r_double | r_double_unsigned |
+------------+-------------------+
| -1.79e+308 | 0 |
| 1.79e+308 | 0 |
| 2.3e-308 | 2.3e-308 |
| -2.3e-308 | 1.79e+308 |
+------------+-------------------+
4 rows in set (0.00 sec)

mysql>

以下、MySQL4.1.13aでインサート文を実行した結果。MySQL4.0.25と比べ、double unsigned型のアンダーフローの丸め処理は改善されているようだが、double型のアンダーフロー及びオーバーフローの丸め処理は挙動がおかしくなってしまったようだ。
mysql> insert into
-> num_test(r_double,r_double_unsigned)
-> values(-1.79e308,0),(1.79e308,0),(2.3e-308,2.3e-308),(-2.3e-308,1.79e308);
Query OK, 4 rows affected (0.00 sec)
Records: 4 Duplicates: 0 Warnings: 0

mysql>
mysql> commit;
Query OK, 0 rows affected (0.08 sec)

mysql> select
-> r_double,
-> r_double_unsigned
-> from
-> num_test
-> limit
-> 19,99;
+------------+-------------------+
| r_double | r_double_unsigned |
+------------+-------------------+
| -1.79e+308 | 0 |
| 1.79e+308 | 0 |

| 0 | 0 |
| -0 | 1.79e+308 |
+------------+-------------------+
4 rows in set (0.00 sec)

以下のような結果からみても、おかしな挙動を示す。(取りあえず使う予定はないからよしとしておくか?!)

mysql> insert into num_test(r_double) values(0.5e-307);
Query OK, 1 row affected (0.00 sec)

mysql> select r_double from num_test limit 27,99;
+----------+
| r_double |
+----------+
| 5e-308 |
+----------+
1 row in set (0.00 sec)

mysql> insert into num_test(r_double) values(2.2e-307);
Query OK, 1 row affected (0.00 sec)

mysql> select r_double from num_test limit 27,99;
+----------+
| r_double |
+----------+
| 5e-308 |
| 0 |
+----------+
2 rows in set (0.00 sec)

mysql> insert into num_test(r_double) values(2.2e-306);
Query OK, 1 row affected (0.00 sec)

mysql> select r_double from num_test limit 27,99;
+----------+
| r_double |
+----------+
| 5e-308 |
| 0 |
| 2.2e-306 |
+----------+
3 rows in set (0.00 sec)

mysql>

長いので次回につづく。

| | | コメント (0) | トラックバック (0)

2006年2月11日 (土)

Mac De Oracle Heterogeneous! #34

数値型の検証のつづき(MySQL編の第2回目)。。。tinyint型、smallint型、mediumint型、int型、bigint型及び、各型の符号なし。

MySQL4.0.25での検証。(MySQL4.1.13aではワーニング返される点がことなるが大きな挙動の差はない。但し、不具合と思われる部分がいくつかある。)
MySQLの仕様なのだが数値型で定義した範囲を超える値を設定した場合はワーニング扱になっている、しかも、上限を超えれば最大値、下限を超えれば最小値に置き換えられる。ちなみに私の知っている商用RDBMSでこのような挙動をするものはないので私にとっては嫌な特徴の一つ。Oracleだけをやってきた方は、”ハマ”りそうな点なので注意しておいたほうがいいだろう。(複数行インサート文では精度超過でワーニングがでるが、MySQL4.0.xでは単一行をインサートする場合はワーニングもでないので要注意。)


1)tinyint型と符号なしtinyint型


Generic Connectivityで扱う場合にも問題は無さそうな気がするが、前述した通り、tinyint型及び、符号なしtinyint型で表現できる範囲を超えた値を設定すると最小値及び最大値に置き換えられてしまうので注意したほうがよい。

mysql> insert into
-> num_test(r_tinyint, r_tinyint_unsigned)
-> values(-128,0);
Query OK, 1 row affected (0.00 sec)

mysql> insert into
-> num_test(r_tinyint, r_tinyint_unsigned)
-> values(127,255);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select
-> r_tinyint,
-> r_tinyint_unsigned
-> from
-> num_test
-> limit
-> 3,-1;
+-----------+--------------------+
| r_tinyint | r_tinyint_unsigned |
+-----------+--------------------+
| -128 | 0 |
| 127 | 255 |
+-----------+--------------------+
2 rows in set (0.01 sec)

mysql>


MySQL4.0.25でも表現可能な範囲を超えた値を設定した場合には複数行インサート文ではワーニングが返される。
mysql> insert into
-> num_test(r_tinyint, r_tinyint_unsigned)
-> values(-129,-1), (128,256);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 4

mysql>
mysql> select
-> r_tinyint,
-> r_tinyint_unsigned
-> from
-> num_test
-> limit
-> 3,-1;
+-----------+--------------------+
| r_tinyint | r_tinyint_unsigned |
+-----------+--------------------+
| -128 | 0 |
| 127 | 255 |
| -128 | 0 |
| 127 | 255 |
+-----------+--------------------+
4 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.06 sec)

mysql> insert into
-> num_test(r_tinyint, r_tinyint_unsigned)
-> values(-129, -1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into
-> num_test(r_tinyint, r_tinyint_unsigned)
-> values(128,256);
Query OK, 1 row affected (0.00 sec)

mysql> select
-> r_tinyint,
-> r_tinyint_unsigned
-> from
-> num_test
-> limit
-> 3,-1;
+-----------+--------------------+
| r_tinyint | r_tinyint_unsigned |
+-----------+--------------------+
| -128 | 0 |
| 127 | 255 |
| -128 | 0 |
| 127 | 255 |
+-----------+--------------------+
4 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.06 sec)

mysql>

2)smallint型と符号なしsmallint型

mysql> insert into
-> num_test(r_smallint, r_smallint_unsigned)
-> values(-32768,0), (32767,65535);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)


以下のインサート文では表現可能な値より大きい又は小さい値を設定している。
mysql> insert into
-> num_test(r_smallint, r_smallint_unsigned)
-> values(-32769,-1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into
-> num_test(r_smallint, r_smallint_unsigned)
-> values(32768,65536);
Query OK, 1 row affected (0.00 sec)

mysql> select
-> r_smallint,
-> r_smallint_unsigned
-> from
-> num_test
-> limit
-> 5,-1;
+------------+---------------------+
| r_smallint | r_smallint_unsigned |
+------------+---------------------+
| -32768 | 0 |
| 32767 | 65535 |
| -32768 | 0 |
| 32767 | 65535 |
+------------+---------------------+
4 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.06 sec)

mysql>

3)mediumint型と符号nasimediumint型

mysql> insert into
-> num_test(r_mediumint, r_mediumint_unsigned)
-> values(-8388608,0), (8388607,16777215);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

以下のインサート文で表現可能な値より大きい又は小さい値を設定している。
mysql> insert into
-> num_test(r_mediumint, r_mediumint_unsigned)
-> values(-8388609,-1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into
-> num_test(r_mediumint, r_mediumint_unsigned)
-> values(8388608,16777216);
Query OK, 1 row affected (0.00 sec)

mysql> select
-> r_mediumint,
-> r_mediumint_unsigned
-> from
-> num_test
-> limit 7,-1;
+-------------+----------------------+
| r_mediumint | r_mediumint_unsigned |
+-------------+----------------------+
| -8388608 | 0 |
| 8388607 | 16777215 |
| -8388608 | 0 |
| 8388607 | 16777215 |
+-------------+----------------------+
4 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.38 sec)

mysql>

4)int型と符号なしint型

mysql> insert into
-> num_test(r_int, r_int_unsigned)
-> values(-2147483648,0), (2147483647,4294967295);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

以下のインサート文では表現可能な値より大きい又は小さい値を設定している。
mysql> insert into
-> num_test(r_int, r_int_unsigned)
-> values(-2147483649,-1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into
-> num_test(r_int, r_int_unsigned)
-> values(2147483648,4294967296);
Query OK, 1 row affected (0.00 sec)

mysql> select
-> r_int,
-> r_int_unsigned
-> from
-> num_test
-> limit
-> 9,-1;
+-------------+----------------+
| r_int | r_int_unsigned |
+-------------+----------------+
| -2147483648 | 0 |
| 2147483647 | 4294967295 |
| -2147483648 | 0 |
| 2147483647 | 4294967295 |
+-------------+----------------+
4 rows in set (0.00 sec)

mysql> rollback;
Query OK, 0 rows affected (0.39 sec)

mysql>

5)bigint型と符号なしbigint型 

3行目のインサート文では、符号なしbigint型に −1 を設定しているが丸められて 0 にはならなず、符号なしbigint型の最大値が設定される。4行目のインサート文では、正の最大値を超える値(9223372036854775808)を設定してるにもかかわらず、負の最大値が設定されている。 (不具合だと思われる。)

mysql> insert into
-> num_test(r_bigint, r_bigint_unsigned)
-> values(-9223372036854775808,0), (9223372036854775807,18446744073709551615);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

以下のインサート文では表現可能な値より大きい又は小さい値を設定している。
mysql> insert into
-> num_test(r_bigint, r_bigint_unsigned)
-> values(-9223372036854775809, -1);
Query OK, 1 row affected (0.00 sec)

mysql> insert into
-> num_test(r_bigint, r_bigint_unsigned)
-> values(9223372036854775808, 18446744073709551616);
Query OK, 1 row affected (0.00 sec)

mysql> select
-> r_bigint,
-> r_bigint_unsigned
-> from
-> num_test
-> limit
-> 11,-1;
+----------------------+----------------------+
| r_bigint | r_bigint_unsigned |
+----------------------+----------------------+
| -9223372036854775808 | 0 |
| 9223372036854775807 | 18446744073709551615 |
| -9223372036854775808 | 18446744073709551615 |
| -9223372036854775808 | 18446744073709551615 |
+----------------------+----------------------+
4 rows in set (0.00 sec)

mysql>


尚、MySQL4.1.13aでは3行目と4行目のインサート文でワーニングが1件返される。(ワーニングは2件じゃないのかな? これも不具合のようだが・・・。)
5.x以降ではどのようになるかは分からないが、少なくともMySQL4.x台を対象にしたGeneric Connectivityで、bigint型は利用しないほうがよいだろう。(厳密に範囲チェックし精度を超えないようにすればなんとかなるかもしれないが・・・・・所詮そのプログラムも人が作るもの。バグがないとも限らない。)

mysql> insert into
-> num_test(r_bigint, r_bigint_unsigned)
-> values(-9223372036854775808,0), (9223372036854775807,18446744073709551615);
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0

mysql>
mysql> commit;
Query OK, 0 rows affected (0.07 sec)

mysql>
以下のインサート文では表現可能な値より大きい又は小さい値を設定している。
mysql> insert into
-> num_test(r_bigint, r_bigint_unsigned)
-> values(-9223372036854775809, -1);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql>
mysql> insert into
-> num_test(r_bigint, r_bigint_unsigned)
-> values(9223372036854775808, 18446744073709551616);
Query OK, 1 row affected, 1 warning (0.00 sec)

mysql> select
-> r_bigint,
-> r_bigint_unsigned
-> from
-> num_test
-> limit
-> 11,99;
+----------------------+----------------------+
| r_bigint | r_bigint_unsigned |
+----------------------+----------------------+
| -9223372036854775808 | 0 |
| 9223372036854775807 | 18446744073709551615 |
| -9223372036854775808 | 18446744073709551615 |
| -9223372036854775808 | 18446744073709551615 |
+----------------------+----------------------+
4 rows in set (0.00 sec)

mysql>

次回につづく。

| | | コメント (0) | トラックバック (0)

2006年2月10日 (金)

Mac De Oracle Heterogeneous! #33

つづきです。数値型の検証(MySQL編の第一回目)。。。PostgreSQLとは一味違った癖がありそうな予感。

赤で囲まれたデータベースを利用した。

gencon_blog_img33

MySQL4.0.25で、null、0、そして空文字を設定した。PostgreSQLやOracleとは異なり、空文字を設定すると0が設定されてしまう。PostgreSQLやOracleではエラーなので注意してたポイントだ。コーディング規約で空文字で数値型を初期化したりしないように縛っていたほうがよいかもしれない。
MySQL4.1.13aで同じことを行うと、仕様変更されたようで、空文字についてはワーニングが返される、しかし、エラーではないのでGeneric Connectivity経由ではエラーになることはないと予想される。この手のワーニングをエラー扱いにできれば、PostgreSQLやOracleと同じハンドリングで済むのだが。
マニュアルと読んでいたら、5.0.2以降では、sql_mode=traditionalとするとワーニングではなくエラーが返されるらしい。。今回は4.0と4.1なので使えない。

以下は、MySQL4.0.25で行った結果である。

mysql> insert into num_test
-> values(null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null);
Query OK, 1 row affected (0.07 sec)

mysql> insert into num_test
-> values(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
Query OK, 1 row affected (0.39 sec)

mysql> insert into num_test
-> values('','','','','','','','','','','','','','','','','','');
Query OK, 1 row affected (0.37 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from num_test¥G
*************************** 1. row ***************************
r_tinyint: NULL
r_tinyint_unsigned: NULL
r_smallint: NULL
r_smallint_unsigned: NULL
r_mediumint: NULL
r_mediumint_unsigned: NULL
r_int: NULL
r_int_unsigned: NULL
r_bigint: NULL
r_bigint_unsigned: NULL
r_float: NULL
r_float_unsigned: NULL
r_double: NULL
r_double_unsigned: NULL
r_decimal_38: NULL
r_decimal_38_unsigned: NULL
r_decimal_38_16: NULL
r_decimal_38_16_unsigned: NULL
*************************** 2. row ***************************
r_tinyint: 0
r_tinyint_unsigned: 0
r_smallint: 0
r_smallint_unsigned: 0
r_mediumint: 0
r_mediumint_unsigned: 0
r_int: 0
r_int_unsigned: 0
r_bigint: 0
r_bigint_unsigned: 0
r_float: 0
r_float_unsigned: 0
r_double: 0
r_double_unsigned: 0
r_decimal_38: 0
r_decimal_38_unsigned: 0
r_decimal_38_16: 0.0000000000000000
r_decimal_38_16_unsigned: 0.0000000000000000
*************************** 3. row ***************************
r_tinyint: 0
r_tinyint_unsigned: 0
r_smallint: 0
r_smallint_unsigned: 0
r_mediumint: 0
r_mediumint_unsigned: 0
r_int: 0
r_int_unsigned: 0
r_bigint: 0
r_bigint_unsigned: 0
r_float: 0
r_float_unsigned: 0
r_double: 0
r_double_unsigned: 0
r_decimal_38: 0
r_decimal_38_unsigned: 0
r_decimal_38_16: 0.0000000000000000
r_decimal_38_16_unsigned: 0.0000000000000000
3 rows in set (0.00 sec)

mysql>

以下は、MySQL4.1.13aで行ったもの。空文字をインサートするとワーニングが返されていることがわかるだろうか?

mysql> insert into num_test
-> values(null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null);
Query OK, 1 row affected (0.10 sec)

mysql> insert into num_test
-> values(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
Query OK, 1 row affected (0.07 sec)

mysql> insert into num_test
-> values('','','','','','','','','','','','','','','','','','');
Query OK, 1 row affected, 13 warnings (0.09 sec)

mysql> commit;


次回につづく。

| | | コメント (0) | トラックバック (0)

2006年2月 9日 (木)

Mac De Oracle Heterogeneous! #32

PostgreSQLに引き続き、MySQLで数値型の検証を行った。(一連の検証では、それほど深く検証している訳ではない。Generic ConnectivityでOracleと他のRDBMSを連携させようと思うのなら、さらに詳細な検証を行うことをお勧めする。MySQL4.0、4.1、5.0とかなりの仕様が変更されているので、各バージョンで挙動が異なることが予想されるのもその理由だ。)

PowerBook G4 MacOSX Tiger 10.4.4のMySQL4.0.25 standardと、PowerMac G5 MacOSX Tiger Server 10.4.3のMySQL4.1.13aで検証を行った。
以下のような経路でアクセスするのだが、

gencon_blog_img1


まず最初はMySQL側で数値型の癖を把握しておく。

Powerbook G4 の MySQL4.0.25及び、PowerMac G5の MySQL4.1.13aには以下の表を作成した。

mysql> desc num_test;
+--------------------------+-------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------------+-------------------------+------+-----+---------+-------+
| r_tinyint | tinyint(4) | YES | | NULL | |
| r_tinyint_unsigned | tinyint(3) unsigned | YES | | NULL | |
| r_smallint | smallint(6) | YES | | NULL | |
| r_smallint_unsigned | smallint(5) unsigned | YES | | NULL | |
| r_mediumint | mediumint(9) | YES | | NULL | |
| r_mediumint_unsigned | mediumint(8) unsigned | YES | | NULL | |
| r_int | int(11) | YES | | NULL | |
| r_int_unsigned | int(10) unsigned | YES | | NULL | |
| r_bigint | bigint(20) | YES | | NULL | |
| r_bigint_unsigned | bigint(20) unsigned | YES | | NULL | |
| r_float | float | YES | | NULL | |
| r_float_unsigned | float unsigned | YES | | NULL | |
| r_double | double | YES | | NULL | |
| r_double_unsigned | double unsigned | YES | | NULL | |
| r_decimal_38 | decimal(38,0) | YES | | NULL | |
| r_decimal_38_unsigned | decimal(38,0) unsigned | YES | | NULL | |
| r_decimal_38_16 | decimal(38,16) | YES | | NULL | |
| r_decimal_38_16_unsigned | decimal(38,16) unsigned | YES | | NULL | |
+--------------------------+-------------------------+------+-----+---------+-------+
18 rows in set (0.00 sec)

mysql>

MySQL4.0.25では問題なかった?!のだが、MySQL4.1.13aで同じDDLを実行するとワーニングがでる。
以下は、MySQL4.1.13aで表を作成したログ。

mysql> create table num_test
-> (
-> r_tinyint tinyint,
-> r_tinyint_unsigned tinyint unsigned,
-> r_smallint smallint,
-> r_smallint_unsigned smallint unsigned,
-> r_mediumint mediumint,
-> r_mediumint_unsigned mediumint unsigned,
-> r_int int,
-> r_int_unsigned int unsigned,
-> r_bigint bigint,
-> r_bigint_unsigned bigint unsigned,
-> r_float float,
-> r_float_unsigned float unsigned,
-> r_double double,
-> r_double_unsigned double unsigned,
-> r_decimal_38 decimal(38,0),
-> r_decimal_38_unsigned decimal(38,0) unsigned,
-> r_decimal_38_16 decimal(38,16),
-> r_decimal_38_16_unsigned decimal(38,16) unsigned
-> ) type=InnoDB;
Query OK, 0 rows affected, 1 warning (0.14 sec)

なんだろう。ワーニングがでるが表は作成されている。

mysql> desc num_test;
+--------------------------+-------------------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------------+-------------------------+------+-----+---------+-------+
| r_tinyint | tinyint(4) | YES | | NULL | |
| r_tinyint_unsigned | tinyint(3) unsigned | YES | | NULL | |
| r_smallint | smallint(6) | YES | | NULL | |
| r_smallint_unsigned | smallint(5) unsigned | YES | | NULL | |
| r_mediumint | mediumint(9) | YES | | NULL | |
| r_mediumint_unsigned | mediumint(8) unsigned | YES | | NULL | |
| r_int | int(11) | YES | | NULL | |
| r_int_unsigned | int(10) unsigned | YES | | NULL | |
| r_bigint | bigint(20) | YES | | NULL | |
| r_bigint_unsigned | bigint(20) unsigned | YES | | NULL | |
| r_float | float | YES | | NULL | |
| r_float_unsigned | float unsigned | YES | | NULL | |
| r_double | double | YES | | NULL | |
| r_double_unsigned | double unsigned | YES | | NULL | |
| r_decimal_38 | decimal(38,0) | YES | | NULL | |
| r_decimal_38_unsigned | decimal(38,0) unsigned | YES | | NULL | |
| r_decimal_38_16 | decimal(38,16) | YES | | NULL | |
| r_decimal_38_16_unsigned | decimal(38,16) unsigned | YES | | NULL | |
+--------------------------+-------------------------+------+-----+---------+-------+
18 rows in set (0.00 sec)

MySQL初心者なのでワーニングメッセージを表示させる方法が判らない。ヘルプで見てみると、 show warnings がそれらしいので試してみと
表のデータベースエンジンの指定は、typeではなく、engineを利用しなさいということらしい。とりあえず表は作成されたのでこのまま進めることにした。
(日付型の検証を行ったときにも出ていたのだが・・・・。確認漏れだ)

mysql> show warnings;
+---------+------+--------------------------------------------------------------------------+
| Level | Code | Message |
+---------+------+--------------------------------------------------------------------------+
| Warning | 1287 | 'TYPE=storage_engine' is deprecated; use 'ENGINE=storage_engine' instead |
+---------+------+--------------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql>

typeよりengineのほうが分かりやすいと思うが、type= としたらエラーにしちゃえばいいじゃん。ワーニングにしておく意味があるのだろうか。と思うのは私だけか?! 
とMySQLのオンラインマニュアルのcreate table文を確認してみたのだが、これに関連する記述が見当たらない。4.1のマニュアルを見ても、typeはengineのシノニムですという記述だけだったのだ。まぁ、マニュアルのメンテ漏れなのだろうとよい方に解釈して、次から engine=innoDB を使う事にする。
次回につづく。

| | | コメント (0) | トラックバック (0)

2006年2月 8日 (水)

Mac De Oracle Heterogeneous! #31

前回のつづきです。やっと、数値型(PostgreSQL編)の最終回。PostgreSQLの数値型をGeneric Connectivity経由でアクセス。

real型。関わっているシステムではほとんど使っていないのだが、念のために試してみた。なんとか使えそう。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_real") values(3.4e38);

1行が作成されました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_real") values(-3.4e38);

1行が作成されました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_real") values(1.2e-38);

1行が作成されました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_real") values(-1.2e-38);

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_real") values(3.5e38);
insert into num_test_postgresql749_mac@oracle10g_win("r_real") values(3.5e38)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: type "real" value out of range: overflow (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_real") values(-3.5e38);
insert into num_test_postgresql749_mac@oracle10g_win("r_real") values(-3.5e38)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: type "real" value out of range: overflow (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_real") values(1.1e-38);
insert into num_test_postgresql749_mac@oracle10g_win("r_real") values(1.1e-38)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: type "real" value out of range: underflow (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_real") values(-1.1e-38);
insert into num_test_postgresql749_mac@oracle10g_win("r_real") values(-1.1e-38)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: type "real" value out of range: underflow (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_real") values(3.4e39);
insert into num_test_postgresql749_mac@oracle10g_win("r_real") values(3.4e39)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: type "real" value out of range: overflow (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_real") values(1.2e-39);
insert into num_test_postgresql749_mac@oracle10g_win("r_real") values(1.2e-39)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: type "real" value out of range: underflow (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> list
1 select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a.*
7 from
8 num_test_postgresql749_mac@oracle10g_win a
9 )
10 where
11* "rownum" > 47
CORYDORAS> /

rownum r_smallint r_integer r_bigint r_numeric38 r_numeric38_16 r_real r_double
---------- ---------- ------------ ----------------------- --------------------------------------- ---------------------------------------- ---------- ----------
48 NULL NULL NULL NULL NULL 3.4000E+38 NULL
49 NULL NULL NULL NULL NULL -3.400E+38 NULL
50 NULL NULL NULL NULL NULL 1.2000E-38 NULL
51 NULL NULL NULL NULL NULL -1.200E-38 NULL

CORYDORAS>

double precision型。関わっているシステムでは全く利用されていなかったのだが、これまた興味本位で調べてみた。問合せでは、tilde表示されていた 1.79e308と-1.79e308だが insert時にはエラーになる。前述した通り、現時点ではdouble precisionは利用しない方が無難かな。
パススルーさせれば登録できなくもないと思うが。。。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_double") values(1.79e308);
insert into num_test_postgresql749_mac@oracle10g_win("r_double") values(1.79e308)
*
行1でエラーが発生しました。:
ORA-01426: 数値オーバーフローが発生しました


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_double") values(-1.79e308);
insert into num_test_postgresql749_mac@oracle10g_win("r_double") values(-1.79e308)
*
行1でエラーが発生しました。:
ORA-01426: 数値オーバーフローが発生しました


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_double") values(2.3e-308);

1行が作成されました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_double") values(-2.3e-308);

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。


CORYDORAS> select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a.*
7 from
8 num_test_postgresql749_mac@oracle10g_win a
9 )
10 where
11 "rownum" > 51;

rownum r_smallint r_integer r_bigint r_numeric38 r_numeric38_16 r_real r_double
---------- ---------- ------------ ----------------------- --------------------------------------- ---------------------------------------- ---------- ----------
52 NULL NULL NULL NULL NULL NULL 0
53 NULL NULL NULL NULL NULL NULL 0

CORYDORAS>

========================
数値型のまとめ(PostgreSQL7.4.9編)

利用している psqlODBCドライバなどはこちら

数値型マッピング
PostgreSQL7.4.9Oracle10g R1Generic Connectivityでの利用備 考
smallint型number型
integer型
bigint型
numeric型 Oracle number型の精度と位置取り範囲内であれば問題なし。但し、精度と位置取りを超えていても格納されている値が精度と位置取り範囲内であれば利用できないこともないが、利用する際には十分な事前調査が必要。
real型
double precision型×Oracle number型の精度範囲内であれば利用できないこともないが、利用するのは避けたほうが無難。どうしても利用したいならOracleのbinary double型にマップするようなアプローチ方法を考えたほうがよいと思う。

numeric型の精度には注意が必要だが、double precision型以外はGeneric Connectivity経由でも違和感無く利用できそうだ。

次回は、MySQLで数値型の癖を確認することにする。

| | | コメント (0) | トラックバック (0)

2006年2月 7日 (火)

Mac De Oracle Heterogeneous! #30

前回のつづきです。numeric型について少しだけ掘り下げてみた。

PostgreSQLのnumeric型の精度は無制限となっている。一方Oracleのnumber型はprecisionが38、scaleが−84から127となっている。
当然だが、Oracleのnumber型の精度と位置取りの制限を超える値の場合は問題が発生する。以下は精度を80に設定した場合の例である。
Oracle側では、number(80,0)とはできないのでエラーになってしまう。但し、PostgreSQL型の定義がnumeric(80,0)であっても、格納されている値が制限範囲内であれば問題はない。numeric型や、decimal型がPostgreSQL側で利用されている場合には、定義されているprecisionやscale及び、格納されている値の最小値、最大値も調査しておいたほうがよいだろう。

PostgreSQL側で numeric(80,0)の列を追加して、値を設定しておく。

pb17:˜ postgres$ psql -U scott postgresql749
Password:
Welcome to psql 7.4.9, the PostgreSQL interactive terminal.

Type: ¥copyright for distribution terms
¥h for help with SQL commands
¥? for help on internal slash commands
¥g or terminate with semicolon to execute query
¥q to quit

postgresql749=>
postgresql749=>
postgresql749=>
postgresql749=> ¥d num_test
Table "scott.num_test"
Column | Type | Modifiers
----------------+------------------+-----------
r_smallint | smallint |
r_integer | integer |
r_bigint | bigint |
r_numeric38 | numeric(38,0) |
r_numeric38_16 | numeric(38,16) |
r_real | real |
r_double | double precision |

postgresql749=> alter table num_test add column r_numeric numeric(80,0);
ALTER TABLE
postgresql749=> commit;
COMMIT
postgresql749=> ¥d num_test
Table "scott.num_test"
Column | Type | Modifiers
----------------+------------------+-----------
r_smallint | smallint |
r_integer | integer |
r_bigint | bigint |
r_numeric38 | numeric(38,0) |
r_numeric38_16 | numeric(38,16) |
r_real | real |
r_double | double precision |
r_numeric | numeric(80,0) |

postgresql749=> insert into num_test(r_numeric) values(9e79);
INSERT 25529 1
postgresql749=> commit;
COMMIT
postgresql749=> select r_numeric from num_test where r_numeric is not null;
r_numeric
----------------------------------------------------------------------------------
90000000000000000000000000000000000000000000000000000000000000000000000000000000
(1 row)

postgresql749=>


Oracle側で問い合わせてみると・・・・・・以下のようになる。number型の精度内の値が設定されていれば問題ないが、それを超えているとエラーが発生する。

CORYDORAS>
CORYDORAS> select "r_numeric" from num_test_postgresql749_mac@oracle10g_win where "r_numeric" is not null;
select "r_numeric" from num_test_postgresql749_mac@oracle10g_win where "r_numeric" is not null
*
行1でエラーが発生しました。:
ORA-28528: 異機種間サービス・データ型の変換中にエラーが発生しました。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(ORACLE10G_WIN)。

CORYDORAS> delete from num_test_postgresql749_mac@oracle10g_win where "r_numeric" > 0;

1行が削除されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric") values(9e37);

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> select "r_numeric" from num_test_postgresql749_mac@oracle10g_win where "r_numeric" > 0;

r_numeric
----------
9.0000E+37

CORYDORAS>


次回につづく。

| | | コメント (0) | トラックバック (0)

2006年2月 6日 (月)

Mac De Oracle Heterogeneous! #29

つづきです。PostgreSQLの数値型をGeneric Connectivity経由でアクセス。

numeric型も特に扱いづらいという点は無さそうだ。(小数点以下を指定してしまった場合の扱いもオラクルと同じで四捨五入してくれる)

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38") values(-99999999999999999999999999999999999999);

1行が作成されました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38") values(99999999999999999999999999999999999999);

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38") values(-100000000000000000000000000000000000000);
insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38") values(-100000000000000000000000000000000000000)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: numeric field overflow (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38") values(100000000000000000000000000000000000000);
insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38") values(100000000000000000000000000000000000000)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: numeric field overflow (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38") values(-0.4);

1行が作成されました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38") values(-0.5);

1行が作成されました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38") values(0.4);

1行が作成されました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38") values(0.5);

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a.*
7 from
8 num_test_postgresql749_mac@oracle10g_win a
9 )
10 where
11 "rownum" > 37;

rownum r_smallint r_integer r_bigint r_numeric38 r_numeric38_16 r_real r_double
---------- ---------- ------------ ----------------------- --------------------------------------- ---------------------------------------- ---------- ----------
38 NULL NULL NULL -99999999999999999999999999999999999999 NULL NULL NULL
39 NULL NULL NULL 99999999999999999999999999999999999999 NULL NULL NULL
40 NULL NULL NULL 0 NULL NULL NULL
41 NULL NULL NULL -1 NULL NULL NULL
42 NULL NULL NULL 0 NULL NULL NULL
43 NULL NULL NULL 1 NULL NULL NULL

6行が選択されました。

CORYDORAS>


scaleを16にした例だが、特に気になる点はない。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(-9999999999999999999999.9999999999999999);

1行が作成されました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(9999999999999999999999.9999999999999999);

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(-9999999999999999999999.99999999999999995);
insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(-9999999999999999999999.99999999999999995)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][A0C9] Value for column r_numeric38_16 exceeds column's length.
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(9999999999999999999999.99999999999999994);

1行が作成されました。

CORYDORAS> rollback;

ロールバックが完了しました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(-9999999999999999999999.99999999999999995);
insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(-9999999999999999999999.99999999999999995)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][A0C9] Value for column r_numeric38_16 exceeds column's length.
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(-9999999999999999999999.99999999999999994);
insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(-9999999999999999999999.99999999999999994)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][A0C9] Value for column r_numeric38_16 exceeds column's length.
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(9999999999999999999999.99999999999999995);
insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(9999999999999999999999.99999999999999995)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: numeric field overflow (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(9999999999999999999999.9999999999999994);

1行が作成されました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(99999999999999999999999.9999999999999999);
insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(99999999999999999999999.9999999999999999)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: numeric field overflow (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(-99999999999999999999999.9999999999999999);
insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(-99999999999999999999999.9999999999999999)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][A0C9] Value for column r_numeric38_16 exceeds column's length.
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(-99999999999999999999999.999999999999999);
insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(-99999999999999999999999.999999999999999)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: numeric field overflow (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(-9999999999999999999999.99999999999999995);
insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(-9999999999999999999999.99999999999999995)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC][A0C9] Value for column r_numeric38_16 exceeds column's length.
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> rollback;

ロールバックが完了しました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(0.99999999999999995);

1行が作成されました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values(0.99999999999999994);

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a.*
7 from
8 num_test_postgresql749_mac@oracle10g_win a
9 )
10 where
11 "rownum" > 43;

rownum r_smallint r_integer r_bigint r_numeric38 r_numeric38_16 r_real r_double
---------- ---------- ------------ ----------------------- --------------------------------------- ---------------------------------------- ---------- ----------
44 NULL NULL NULL NULL -9999999999999999999999.9999999999999999 NULL NULL
45 NULL NULL NULL NULL 9999999999999999999999.9999999999999999 NULL NULL
46 NULL NULL NULL NULL 1.0000000000000000 NULL NULL
47 NULL NULL NULL NULL .9999999999999999 NULL NULL

CORYDORAS>


さて、次回は、real型とdouble precision型。

| | | コメント (0) | トラックバック (0)

2006年2月 5日 (日)

Mac De Oracle Heterogeneous! #28

つづきです。PostgreSQLの数値型をGeneric Connectivity経由でアクセス。

記事の内容とは関係ないけど、実はノベルティグッズ大好きなんです。

ということで昨日getしたノベルティ。しかも2個も!

CIMG8700



最近のOracle紅白まんじゅうなどに触発されてまた、コレクター魂が・・・・。Oracle Master Gold 9iASだったな〜〜昔は・・・今は自動的にSilverですが・・・取得記念の時計。と OOWで128ノードデモ成功記念テディベア3匹+Java TechDay記念のDuke。


CIMG8659CIMG8661

generic connectivity経由でpostgresqlのsmallint型に数値を設定してみた。PostgreSQL上で行った結果と同じである。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_smallint") values(32767);

1行が作成されました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_smallint") values(-32768);

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_smallint") values(32768);
insert into num_test_postgresql749_mac@oracle10g_win("r_smallint") values(32768)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: integer out of range (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_smallint") values(-32769);
insert into num_test_postgresql749_mac@oracle10g_win("r_smallint") values(-32769)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: integer out of range (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。

CORYDORAS> list
1 select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a.*
7 from
8 num_test_postgresql749_mac@oracle10g_win a
9 )
10 where
11* "rownum" > 31
CORYDORAS> /

rownum r_smallint r_integer r_bigint r_numeric38 r_numeric38_16 r_real r_double
---------- ---------- ------------ ----------------------- --------------------------------------- ---------------------------------------- ---------- ----------
32 32767 NULL NULL NULL NULL NULL NULL
33 -32768 NULL NULL NULL NULL NULL NULL

CORYDORAS>

integer型へのinsert文も PostgreSQL上で行った場合と変わらない。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_integer") values(-2147483648);

1行が作成されました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_integer") values(2147483647);

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_integer") values(2147483649);
insert into num_test_postgresql749_mac@oracle10g_win("r_integer") values(2147483649)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: integer out of range (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_integer") values(2147483648);
insert into num_test_postgresql749_mac@oracle10g_win("r_integer") values(2147483648)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: integer out of range (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> rollback;
CORYDORAS> list
1 select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a.*
7 from
8 num_test_postgresql749_mac@oracle10g_win a
9 )
10 where
11* "rownum" > 33
CORYDORAS> /

rownum r_smallint r_integer r_bigint r_numeric38 r_numeric38_16 r_real r_double
---------- ---------- ------------ ----------------------- --------------------------------------- ---------------------------------------- ---------- ----------
34 NULL -2147483648 NULL NULL NULL NULL NULL
35 NULL 2147483647 NULL NULL NULL NULL NULL

CORYDORAS>

bigint型も特に変わった癖は無い。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_bigint") values(-9223372036854775808);

1行が作成されました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_bigint") values(9223372036854775807);

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_bigint") values(-9223372036854775809);
insert into num_test_postgresql749_mac@oracle10g_win("r_bigint") values(-9223372036854775809)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: integer out of range (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_bigint") values(9223372036854775808);
insert into num_test_postgresql749_mac@oracle10g_win("r_bigint") values(9223372036854775808)
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: integer out of range (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> rollback;

ロールバックが完了しました。

CORYDORAS> select *
2 from
3 (
4 select
5 rownum as "rownum",
6 a.*
7 from
8 num_test_postgresql749_mac@oracle10g_win a
9 )
10 where
11 "rownum" > 35;

rownum r_smallint r_integer r_bigint r_numeric38 r_numeric38_16 r_real r_double
---------- ---------- ------------ ----------------------- --------------------------------------- ---------------------------------------- ---------- ----------
36 NULL NULL -9223372036854775808 NULL NULL NULL NULL
37 NULL NULL 9223372036854775807 NULL NULL NULL NULL

CORYDORAS>

次回、numeric型につづく。

| | | コメント (0) | トラックバック (0)

2006年2月 4日 (土)

Mac De Oracle Heterogeneous! #27

つづきです。PostgreSQLの数値型をGeneric Connectivity経由でアクセス。

PostgreSQL側で行ったことと同じ操作を行う。まず、0の設定とnullの設定。問題なし。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win
2 values(0,0,0,0,0,0,0);

1行が作成されました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win
2 values(null,null,null,null,null,null,null);

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> select * from num_test_postgresql749_mac@oracle10g_win;

r_smallint r_integer r_bigint r_numeric38 r_numeric38_16 r_real r_double
---------- ------------ ----------------------- --------------------------------------- ---------------------------------------- ---------- ----------
0 0 0 0 .0000000000000000 0 0
NULL NULL NULL NULL NULL NULL NULL
NULL NULL NULL NULL NULL 0 NULL
NULL NULL NULL NULL NULL NULL 0
32767 NULL NULL NULL NULL NULL NULL
-32768 NULL NULL NULL NULL NULL NULL
NULL -2147483648 NULL NULL NULL NULL NULL
NULL 2147483647 NULL NULL NULL NULL NULL
NULL NULL -9223372036854775808 NULL NULL NULL NULL
NULL NULL 9223372036854775807 NULL NULL NULL NULL
NULL NULL NULL -99999999999999999999999999999999999999 NULL NULL NULL
NULL NULL NULL 0 NULL NULL NULL
NULL NULL NULL -1 NULL NULL NULL
NULL NULL NULL 0 NULL NULL NULL
NULL NULL NULL 99999999999999999999999999999999999999 NULL NULL NULL
NULL NULL NULL NULL -9999999999999999999999.9999999999999999 NULL NULL
NULL NULL NULL NULL 9999999999999999999999.9999999999999999 NULL NULL
NULL NULL NULL NULL 1.0000000000000000 NULL NULL
NULL NULL NULL NULL .9999999999999999 NULL NULL
NULL NULL NULL NULL NULL 3.4000E+38 NULL
NULL NULL NULL NULL NULL -3.400E+38 NULL
NULL NULL NULL NULL NULL 1.2000E-38 NULL
NULL NULL NULL NULL NULL -1.200E-38 NULL
NULL NULL NULL NULL NULL NULL ˜
NULL NULL NULL NULL NULL NULL -˜
NULL NULL NULL NULL NULL NULL 0
NULL NULL NULL NULL NULL NULL 0
0 0 0 0 .0000000000000000 0 0
NULL NULL NULL NULL NULL NULL NULL

29行が選択されました。

CORYDORAS>


空文字の設定もエラーになり、変わった癖はない。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_smallint") values('');
insert into num_test_postgresql749_mac@oracle10g_win("r_smallint") values('')
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: invalid input syntax for integer: "" (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_integer") values('');
insert into num_test_postgresql749_mac@oracle10g_win("r_integer") values('')
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: invalid input syntax for integer: "" (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_bigint") values('');
insert into num_test_postgresql749_mac@oracle10g_win("r_bigint") values('')
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: invalid input syntax for type bigint: "" (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38") values('');
insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38") values('')
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: invalid input syntax for type numeric: " " (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values('');
insert into num_test_postgresql749_mac@oracle10g_win("r_numeric38_16") values('')
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: invalid input syntax for type numeric: " " (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。


CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_real") values('');

1行が作成されました。

CORYDORAS> insert into num_test_postgresql749_mac@oracle10g_win("r_double") values('');

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> select * from num_test_postgresql749_mac@oracle10g_win;

r_smallint r_integer r_bigint r_numeric38 r_numeric38_16 r_real r_double
---------- ------------ ----------------------- --------------------------------------- ---------------------------------------- ---------- ----------
0 0 0 0 .0000000000000000 0 0
NULL NULL NULL NULL NULL NULL NULL
NULL NULL NULL NULL NULL 0 NULL
NULL NULL NULL NULL NULL NULL 0
32767 NULL NULL NULL NULL NULL NULL
-32768 NULL NULL NULL NULL NULL NULL
NULL -2147483648 NULL NULL NULL NULL NULL
NULL 2147483647 NULL NULL NULL NULL NULL
NULL NULL -9223372036854775808 NULL NULL NULL NULL
NULL NULL 9223372036854775807 NULL NULL NULL NULL
NULL NULL NULL -99999999999999999999999999999999999999 NULL NULL NULL
NULL NULL NULL 0 NULL NULL NULL
NULL NULL NULL -1 NULL NULL NULL
NULL NULL NULL 0 NULL NULL NULL
NULL NULL NULL 99999999999999999999999999999999999999 NULL NULL NULL
NULL NULL NULL NULL -9999999999999999999999.9999999999999999 NULL NULL
NULL NULL NULL NULL 9999999999999999999999.9999999999999999 NULL NULL
NULL NULL NULL NULL 1.0000000000000000 NULL NULL
NULL NULL NULL NULL .9999999999999999 NULL NULL
NULL NULL NULL NULL NULL 3.4000E+38 NULL
NULL NULL NULL NULL NULL -3.400E+38 NULL
NULL NULL NULL NULL NULL 1.2000E-38 NULL
NULL NULL NULL NULL NULL -1.200E-38 NULL
NULL NULL NULL NULL NULL NULL ˜
NULL NULL NULL NULL NULL NULL -˜
NULL NULL NULL NULL NULL NULL 0
NULL NULL NULL NULL NULL NULL 0
0 0 0 0 .0000000000000000 0 0
NULL NULL NULL NULL NULL NULL NULL
NULL NULL NULL NULL NULL 0 NULL
NULL NULL NULL NULL NULL NULL 0

31行が選択されました。

CORYDORAS>

長いので次回につづく。

| | | コメント (0) | トラックバック (0)

2006年2月 3日 (金)

Mac De Oracle Heterogeneous! #26

前回は、PostgreSQL7.4.9上で数値型の癖を確認した。

今日はPostgreSQLの数値型をGeneric Connectivity経由でアクセスする。

Oracle10g R1 Windowsに num_test_postgresql749_macというシノニムを作成し、以下の経路で
gencon_blog_img02
アクセスしている。

CORYDORAS> select synonym_name from user_synonyms@oracle10g_win;

SYNONYM_NAME
------------------------------
NUM_TEST_POSTGRESQL749_MAC
DATE_TEST_MYSQL4026_WIN
DATE_TEST_MYSQL4113A_MAC_SV
DATE_TEST_POSTGRESQL749_MAC
EMP_MYSQL4025_MAC
INNO_EMP_MYSQL4025_MAC
EMP_MYSQL4026_WIN
EMP_MYSQL4113A_MAC_SV
EMP_POSTGRESQL749_MAC
ORACLE_EMP_MYSQL4026_WIN

10行が選択されました。

CORYDORAS>


登録済みデータを問い合わせてみる。 PostgreSQL7.4.9の double precision型で問題発生。

CORYDORAS> 

r_smallint r_integer r_bigint r_numeric38 r_numeric38_16 r_real r_double
---------- ------------ ----------------------- --------------------------------------- ---------------------------------------- ---------- ----------
0 0 0 0 .0000000000000000 0 0
NULL NULL NULL NULL NULL NULL NULL
NULL NULL NULL NULL NULL 0 NULL
NULL NULL NULL NULL NULL NULL 0
32767 NULL NULL NULL NULL NULL NULL
-32768 NULL NULL NULL NULL NULL NULL
NULL -2147483648 NULL NULL NULL NULL NULL
NULL 2147483647 NULL NULL NULL NULL NULL
NULL NULL -9223372036854775808 NULL NULL NULL NULL
NULL NULL 9223372036854775807 NULL NULL NULL NULL
NULL NULL NULL -99999999999999999999999999999999999999 NULL NULL NULL
NULL NULL NULL 0 NULL NULL NULL
NULL NULL NULL -1 NULL NULL NULL
NULL NULL NULL 0 NULL NULL NULL
NULL NULL NULL 99999999999999999999999999999999999999 NULL NULL NULL
NULL NULL NULL NULL -9999999999999999999999.9999999999999999 NULL NULL
NULL NULL NULL NULL 9999999999999999999999.9999999999999999 NULL NULL
NULL NULL NULL NULL 1.0000000000000000 NULL NULL
NULL NULL NULL NULL .9999999999999999 NULL NULL
NULL NULL NULL NULL NULL 3.4000E+38 NULL
NULL NULL NULL NULL NULL -3.400E+38 NULL
NULL NULL NULL NULL NULL 1.2000E-38 NULL
NULL NULL NULL NULL NULL -1.200E-38 NULL
NULL NULL NULL NULL NULL NULL ˜
NULL NULL NULL NULL NULL NULL -˜
NULL NULL NULL NULL NULL NULL 0
NULL NULL NULL NULL NULL NULL 0

27行が選択されました。

CORYDORAS>

dump()関数で Oracle側の型を確認してみると、double precision型も含めて、全て number型にマッピングされている。
Oracleのnumber型の精度を超えている箇所は TILDEが表示されている。number型の精度を超えていないことが事前に確認できるようならば、double precision型もマッピングできそうではあるが、直接取り込むようなことはしないほうが無難だと思われる。
指数表現でCSVファイルとして出力、それをOracle側で、BINARY_DOUBLE型マッピングした外部表にして取り込むという方法がよさそうに思える(尚、外部表にして取り込む方法は未確認)。

CORYDORAS> list
1 select
2 dump("r_smallint") as "smallint",
3 dump("r_integer") as "integer",
4 dump("r_bigint") as "bigint",
5 dump("r_numeric38") as "numeric38_0",
6 dump("r_numeric38_16") as "numeric38_16",
7 dump("r_real") as "real",
8 dump("r_double") as "double_precision"
9 from
10 num_test_postgresql749_mac@oracle10g_win
11 where
12* rownum = 1
CORYDORAS> /

smallint integer bigint numeric38_0 numeric38_16 real double_precision
-------------------- -------------------- -------------------- -------------------- -------------------- -------------------- --------------------
Typ=2 Len=1: 128 Typ=2 Len=1: 128 Typ=2 Len=1: 128 Typ=2 Len=1: 128 Typ=2 Len=1: 128 Typ=2 Len=1: 128 Typ=2 Len=1: 128

CORYDORAS>

長くなるので、一旦この辺で。

| | | コメント (0) | トラックバック (0)

2006年2月 2日 (木)

Mac De Oracle Heterogeneous! #25

前回までで日付、時間型の癖は把握できた。ここからは数値型について見ていく。まず初めに、PowerBook G4 1Ghz MacOSX Tiger 10.4.4 (アップデータしたので)に作成した PostgreSQL7.4.9から。

以下のような表をPostgreSQl7.4.9に作成した。

pb17:˜ postgres$ psql -U scott postgresql749
Password:
Welcome to psql 7.4.9, the PostgreSQL interactive terminal.

Type: ¥copyright for distribution terms
¥h for help with SQL commands
¥? for help on internal slash commands
¥g or terminate with semicolon to execute query
¥q to quit

postgresql749=>
postgresql749=> ¥d num_test
Table "scott.num_test"
Column | Type | Modifiers
----------------+------------------+-----------
r_smallint | smallint |
r_integer | integer |
r_bigint | bigint |
r_numeric38 | numeric(38,0) |
r_numeric38_16 | numeric(38,16) |
r_real | real |
r_double | double precision |

postgresql749=>

正常の登録できて当然なところから。

postgresql749=> insert into num_test values(0,0,0,0,0,0,0);
INSERT 25454 1
postgresql749=> commit;
COMMIT
postgresql749=> insert into num_test values(null,null,null,null,null,null,null);
INSERT 25455 1
postgresql749=> commit;
COMMIT

さて、空文字はどうか? real型とdouble precision型では空文字を受け入れる。それぞれ 0 が設定される。それ以外の数値型では空文字は許容されない。

postgresql749=> insert into num_test values('',null,null,null,null,null,null);
ERROR: invalid input syntax for integer: ""
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test values(null,'',null,null,null,null,null);
ERROR: invalid input syntax for integer: ""
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test values(null,null,'',null,null,null,null);
ERROR: invalid input syntax for type bigint: ""
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test values(null,null,null,'',null,null,null);
ERROR: invalid input syntax for type numeric: ""
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test values(null,null,null,null,'',null,null);
ERROR: invalid input syntax for type numeric: ""
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test values(null,null,null,null,null,'',null);
INSERT 25456 1
postgresql749=> commit;
COMMIT
postgresql749=> insert into num_test values(null,null,null,null,null,null,'');
INSERT 25457 1
postgresql749=> commit;
COMMIT
postgresql749=> select * from num_test;
r_smallint | r_integer | r_bigint | r_numeric38 | r_numeric38_16 | r_real | r_double
------------+-----------+----------+-------------+--------------------+--------+----------
0 | 0 | 0 | 0 | 0.0000000000000000 | 0 | 0
| | | | | |
| | | | | 0 |
| | | | | | 0
(4 rows)

postgresql749=>

次はsmallint型。変わった癖は無い。

postgresql749=> insert into num_test(r_smallint) values(32767);
INSERT 25458 1
postgresql749=> insert into num_test(r_smallint) values(-32768);
INSERT 25459 1
postgresql749=> commit;
COMMIT
postgresql749=> insert into num_test(r_smallint) values(32768);
ERROR: integer out of range
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_smallint) values(-32769);
ERROR: integer out of range
postgresql749=> rollback;
ROLLBACK
postgresql749=>

integer型。

postgresql749=> insert into num_test(r_integer) values(-2147483648);
INSERT 25460 1
postgresql749=> commit;
COMMIT
postgresql749=> insert into num_test(r_integer) values(-2147483649);
ERROR: integer out of range
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_integer) values(2147483647);
INSERT 25461 1
postgresql749=> commit;
COMMIT
postgresql749=> insert into num_test(r_integer) values(2147483648);
ERROR: integer out of range
postgresql749=> rollback;
ROLLBACK
postgresql749=>


postgresql749=> insert into num_test(r_bigint) values(-9223372036854775808);
INSERT 25462 1
postgresql749=> commit;
COMMIT
postgresql749=> insert into num_test(r_bigint) values(-9223372036854775809);
ERROR: integer out of range
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_bigint) values(9223372036854775807);
INSERT 25463 1
postgresql749=> commit;
COMMIT
postgresql749=> insert into num_test(r_bigint) values(9223372036854775808);
ERROR: integer out of range
postgresql749=> rollback;
ROLLBACK
postgresql749=>

numeric型で 38,0 の精度。Oracleのnumber型のような使い勝手。

postgresql749=> insert into num_test(r_numeric38) values(-99999999999999999999999999999999999999);
INSERT 25464 1
postgresql749=> commit;
COMMIT
postgresql749=> insert into num_test(r_numeric38) values(-999999999999999999999999999999999999991);
ERROR: numeric field overflow
DETAIL: The absolute value is greater than or equal to 10^38 for field with precision 38, scale 0.
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_numeric38) values(-100000000000000000000000000000000000000);
ERROR: numeric field overflow
DETAIL: The absolute value is greater than or equal to 10^38 for field with precision 38, scale 0.
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_numeric38) values(-0.1);
INSERT 25465 1
postgresql749=> insert into num_test(r_numeric38) values(-0.5);
INSERT 25466 1
postgresql749=> insert into num_test(r_numeric38) values(-0.4);
INSERT 25467 1
postgresql749=> commit;
COMMIT
postgresql749=> select * from num_test;
r_smallint | r_integer | r_bigint | r_numeric38 | r_numeric38_16 | r_real | r_double
------------+-------------+----------------------+-----------------------------------------+--------------------+--------+----------
0 | 0 | 0 | 0 | 0.0000000000000000 | 0 | 0
| | | | | |
| | | | | 0 |
| | | | | | 0
32767 | | | | | |
-32768 | | | | | |
| -2147483648 | | | | |
| 2147483647 | | | | |
| | -9223372036854775808 | | | |
| | 9223372036854775807 | | | |
| | | -99999999999999999999999999999999999999 | | |
| | | 0 | | |
| | | -1 | | |
| | | 0 | | |
(14 rows)

精度を変えたnumeric型も変な癖はないようだ。

postgresql749=> insert into num_test(r_numeric38) values(99999999999999999999999999999999999999);
INSERT 25468 1
postgresql749=> commit;
COMMIT
postgresql749=> insert into num_test(r_numeric38) values(100000000000000000000000000000000000000);
ERROR: numeric field overflow
DETAIL: The absolute value is greater than or equal to 10^38 for field with precision 38, scale 0.
postgresql749=> rollback;
ROLLBACK
postgresql749=>
postgresql749=> insert into num_test(r_numeric38_16) values(-9999999999999999999999.9999999999999999);
INSERT 25476 1
postgresql749=> commit;
COMMIT
postgresql749=> insert into num_test(r_numeric38_16) values(-10000000000000000000000.9999999999999999);
ERROR: numeric field overflow
DETAIL: The absolute value is greater than or equal to 10^22 for field with precision 38, scale 16.
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_numeric38_16) values(9999999999999999999999.9999999999999999);
INSERT 25477 1
postgresql749=> commit;
COMMIT
postgresql749=> insert into num_test(r_numeric38_16) values(10000000000000000000000.9999999999999999);
ERROR: numeric field overflow
DETAIL: The absolute value is greater than or equal to 10^22 for field with precision 38, scale 16.
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_numeric38_16) values(-9999999999999999999999.99999999999999995);
ERROR: numeric field overflow
DETAIL: The absolute value is greater than or equal to 10^22 for field with precision 38, scale 16.
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_numeric38_16) values(9999999999999999999999.99999999999999995);
ERROR: numeric field overflow
DETAIL: The absolute value is greater than or equal to 10^22 for field with precision 38, scale 16.
postgresql749=> rollback
postgresql749-> rollback;
ERROR: syntax error at or near "rollback" at character 10
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test (r_numeric38_16) values(0.99999999999999995);
INSERT 25478 1
postgresql749=> insert into num_test (r_numeric38_16) values(0.99999999999999994);
INSERT 25479 1
postgresql749=> commit;
COMMIT
postgresql749=> select * from num_test;
r_smallint | r_integer | r_bigint | r_numeric38 | r_numeric38_16 | r_real | r_double
------------+-------------+----------------------+-----------------------------------------+------------------------------------------+--------+----------
0 | 0 | 0 | 0 | 0.0000000000000000 | 0 | 0
| | | | | |
| | | | | 0 |
| | | | | | 0
32767 | | | | | |
-32768 | | | | | |
| -2147483648 | | | | |
| 2147483647 | | | | |
| | -9223372036854775808 | | | |
| | 9223372036854775807 | | | |
| | | -99999999999999999999999999999999999999 | | |
| | | 0 | | |
| | | -1 | | |
| | | 0 | | |
| | | 99999999999999999999999999999999999999 | | |
| | | | -9999999999999999999999.9999999999999999 | |
| | | | 9999999999999999999999.9999999999999999 | |
| | | | 1.0000000000000000 | |
| | | | 0.9999999999999999 | |
(19 rows)

postgresql749=>


次は、real型。

postgresql749=> 
postgresql749=> insert into num_test(r_real) values(3.4e38);
INSERT 25487 1
postgresql749=> insert into num_test(r_real) values(-3.4e38);
INSERT 25488 1
postgresql749=> commit;
COMMIT
postgresql749=> insert into num_test(r_real) values(1.2e-38);
INSERT 25489 1
postgresql749=> insert into num_test(r_real) values(-1.2e-38);
INSERT 25490 1
postgresql749=> commit;
COMMIT
postgresql749=> insert into num_test(r_real) values(3.4e39);
ERROR: type "real" value out of range: overflow
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_real) values(-3.4e39);
ERROR: type "real" value out of range: overflow
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_real) values(-3.5e38);
ERROR: type "real" value out of range: overflow
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_real) values(-3.41e38);
ERROR: type "real" value out of range: overflow
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_real) values(1.2e-39);
ERROR: type "real" value out of range: underflow
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_real) values(1.1e-38);
ERROR: type "real" value out of range: underflow
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_real) values(-1.1e-38);
ERROR: type "real" value out of range: underflow
postgresql749=> rollback;
ROLLBACK
postgresql749=> select * from num_test;
r_smallint | r_integer | r_bigint | r_numeric38 | r_numeric38_16 | r_real | r_double
------------+-------------+----------------------+-----------------------------------------+------------------------------------------+----------+----------
0 | 0 | 0 | 0 | 0.0000000000000000 | 0 | 0
| | | | | |
| | | | | 0 |
| | | | | | 0
32767 | | | | | |
-32768 | | | | | |
| -2147483648 | | | | |
| 2147483647 | | | | |
| | -9223372036854775808 | | | |
| | 9223372036854775807 | | | |
| | | -99999999999999999999999999999999999999 | | |
| | | 0 | | |
| | | -1 | | |
| | | 0 | | |
| | | 99999999999999999999999999999999999999 | | |
| | | | -9999999999999999999999.9999999999999999 | |
| | | | 9999999999999999999999.9999999999999999 | |
| | | | 1.0000000000000000 | |
| | | | 0.9999999999999999 | |
| | | | | 3.4e+38 |
| | | | | -3.4e+38 |
| | | | | 1.2e-38 |
| | | | | -1.2e-38 |
(23 rows)

postgresql749=>

最後に double precision型。

postgresql749=> insert into num_test(r_double) values(1.79e308);
INSERT 25495 1
postgresql749=> insert into num_test(r_double) values(-1.79e308);
INSERT 25496 1
postgresql749=> insert into num_test(r_double) values(2.3e-308);
INSERT 25497 1
postgresql749=> insert into num_test(r_double) values(-2.3e-308);
INSERT 25498 1
postgresql749=> commit;
COMMIT
postgresql749=> insert into num_test(r_double) values(1.80e308);
ERROR:"180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000" is out of range for type double precision
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_double) values(-1.80e308);
ERROR:"-18000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000" is out of range for type double precision
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_double) values(1.79e309);
ERROR:"179000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
0000000000000000000000000000000000000000000" is out of range for type double precision
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_double) values(-1.79e309);
ERROR:"-17900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000" is out of range for type double precision
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_double) values(2.2e-308);
ERROR: type "double precision" value out of range: underflow
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_double) values(-2.2e-308);
ERROR: type "double precision" value out of range: underflow
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_double) values(2.3e-309);
ERROR: type "double precision" value out of range: underflow
postgresql749=> rollback;
ROLLBACK
postgresql749=> insert into num_test(r_double) values(-2.3e-309);
ERROR: type "double precision" value out of range: underflow
postgresql749=> rollback;
ROLLBACK
postgresql749=> select * from num_test;
r_smallint | r_integer | r_bigint | r_numeric38 | r_numeric38_16 | r_real | r_double
------------+-------------+----------------------+-----------------------------------------+------------------------------------------+----------+------------
0 | 0 | 0 | 0 | 0.0000000000000000 | 0 | 0
| | | | | |
| | | | | 0 |
| | | | | | 0
32767 | | | | | |
-32768 | | | | | |
| -2147483648 | | | | |
| 2147483647 | | | | |
| | -9223372036854775808 | | | |
| | 9223372036854775807 | | | |
| | | -99999999999999999999999999999999999999 | | |
| | | 0 | | |
| | | -1 | | |
| | | 0 | | |
| | | 99999999999999999999999999999999999999 | | |
| | | | -9999999999999999999999.9999999999999999 | |
| | | | 9999999999999999999999.9999999999999999 | |
| | | | 1.0000000000000000 | |
| | | | 0.9999999999999999 | |
| | | | | 3.4e+38 |
| | | | | -3.4e+38 |
| | | | | 1.2e-38 |
| | | | | -1.2e-38 |
| | | | | | 1.79e+308
| | | | | | -1.79e+308
| | | | | | 2.3e-308
| | | | | | -2.3e-308
(27 rows)

postgresql749=>
postgresql749=> ¥q
pb17:˜ postgres$

日付型とは異なり変わった癖はなさそうな予感。次回はgeneric connectivity経由でOracleからアクセスしてみる。

| | | コメント (0) | トラックバック (0)

2006年1月31日 (火)

Mac De Oracle Heterogeneous! #24

引き続き、Generic Connectivity経由でアクセスした場合、Oracle側では日付、時刻型がどのようにどのように扱われるか確認する。

PostgreSQLの場合と同様に、現在時刻を指定するためにはPL/SQLからexecute immediate文を利用する必要がありそうだ。

CORYDORAS> list
1 insert into date_test_mysql4113a_mac_sv@oracle10g_win
2 values(
3 (select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual),
4 (select to_char(sysdate,'yyyy-mm-dd') from dual),
5 (select to_char(systimestamp, 'yyyy-mm-dd hh24:mi:ss.ff') from dual),
6 (select to_char(sysdate,'hh24:mi:ss') from dual),
7 (select to_char(sysdate,'yyyy') from dual)
8* )
CORYDORAS> /
insert into date_test_mysql4113a_mac_sv@oracle10g_win
*
行1でエラーが発生しました。:
ORA-02070: データベースMYSQL4113A_MAC_SVはこのコンテキストではsubqueriesをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。


CORYDORAS>
CORYDORAS> list
1 declare
2 v_datetime varchar2(19);
3 v_date varchar2(10);
4 v_timestamp varchar2(30);
5 v_time varchar2(8);
6 v_year varchar2(4);
7 begin
8 v_datetime := to_char(sysdate,'yyyy-mm-dd hh24:mi:ss');
9 v_date := to_char(sysdate, 'yyyy-mm-dd');
10 v_timestamp := to_char(systimestamp , 'yyyy-mm-dd hh24:mi:ss.ff');
11 v_time := to_char(sysdate, 'hh24:mi:ss');
12 v_year := to_char(sysdate, 'yyyy');
13 --
14 insert into date_test_mysql4113a_mac_sv@oracle10g_win
15 values(
16 v_datetime, v_date, v_timestamp, v_time, v_year
17 );
18 commit;
19* end;
CORYDORAS> /
insert into date_test_mysql4113a_mac_sv@oracle10g_win
*
行14でエラーが発生しました。:
ORA-06550: 行14、列3:
PL/SQL: ORA-00980: シノニム変換が無効です。
ORA-06550: 行14、列3:
PL/SQL: SQL Statement ignored


CORYDORAS>
CORYDORAS> list
1 declare
2 v_datetime_string varchar2(19);
3 v_date_string varchar2(10);
4 v_timestamp_string varchar2(30);
5 v_time_string varchar2(8);
6 v_year_string varchar2(4);
7 v_sql varchar2(1000);
8 begin
9 v_datetime_string := to_char(sysdate, 'yyyy-mm-dd hh24:mi:ss');
10 v_date_string := to_char(sysdate, 'yyyy-mm-dd');
11 v_timestamp_string := to_char(systimestamp, 'yyyy-mm-dd hh24:mi:ss');
12 v_time_string := to_char(sysdate, 'hh24:mi:ss');
13 v_year_string := to_char(sysdate, 'yyyy');
14 v_sql :=
15 'insert into date_test_mysql4113a_mac_sv@oracle10g_win values('||
16 '''' || v_datetime_string ||
17 ''',''' || v_date_string ||
18 ''',''' || v_timestamp_string ||
19 ''',''' || v_time_string ||
20 ''',''' || v_year_string || ''')'
21 ;
22 execute immediate v_sql;
23 end;
24*
CORYDORAS> /

PL/SQLプロシージャが正常に完了しました。

CORYDORAS> select * from date_test_mysql4113a_mac_sv@oracle10g_win;

r_datetime r_date r_timestamp r_time r_year
-------------------------- -------------------------- -------------------------- -------------------- -------
1990/01/01 00:00:00 2006/01/20 23:04:22
2000/12/01 00:00:00 2006/01/20 23:04:35
1800/01/01 00:00:00 2006/01/20 23:04:51
1810/12/01 00:00:00 2006/01/20 23:05:06
2002/12/01 00:00:00
2006/01/20 23:05:33
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/24 23:12:32
2006/01/24 23:13:19 2006/01/24 00:00:00 2006/01/24 23:13:19 0001/01/01 23:13:19 2006
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/24 23:30:56
2006/01/24 23:32:31
2006/01/24 23:43:53
0000/00/00 00:00:00
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/25 00:06:11
2006/01/27 01:00:12
0000/00/00 00:00:00 0001/01/01 00:00:00 0
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/10 00:30:12 2006/02/10 00:00:00 2006/03/04 13:50:12 0001/01/01 12:30:01 2005
2006/01/27 10:13:10
2006/01/27 10:33:34 2006/01/27 00:00:00 0000/00/00 00:00:00 0001/01/01 10:33:34 2006
2006/01/27 10:48:01 2006/01/27 00:00:00 2006/01/27 10:48:01 0001/01/01 10:48:01 2006

23行が選択されました。

CORYDORAS>

DBMS_HS_PASSTHROUGHパッケージが利用できれば、それを利用する手もあるかもしれないが、このように
gencon_blog_img1

特殊な構成ではどうなのだろうか・・・・。

それは別途調べることにして、単純な環境ならば以下のようにして利用できる。
以下は、Windows XP ProfessionalのOracle10g R1 EEから MacOSX Tiger ServerのMySQL4.1.13a対して、DBMS_HS_PASSTHROUGH.EXECUTE_IMMEDIATEプロシージャを利用してMySQL向けSQLをパススルーして実行した例。
尚、dbms_hs_passthroughパッケージは、仮想パッケージとの記載があった。dba_objectsビュ−を覗いても存在していないし、desc dbms_hs_passthrough としても存在しないので驚かないように。
このようにアクセスしている。
gencon_blog_img99

SQL> select * from "date_test"@mysql4113a_mac_sv;

r_datetime r_date r_timestamp r_time r_year
------------------- ------------------- ------------------- ------------------- ----------
1990/01/01 00:00:00 2006/01/20 23:04:22
2000/12/01 00:00:00 2006/01/20 23:04:35
1800/01/01 00:00:00 2006/01/20 23:04:51
1810/12/01 00:00:00 2006/01/20 23:05:06
2002/12/01 00:00:00
2006/01/20 23:05:33
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/24 23:12:32
2006/01/24 23:13:19 2006/01/24 00:00:00 2006/01/24 23:13:19 0001/01/01 23:13:19 2006
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/24 23:30:56
2006/01/24 23:32:31
2006/01/24 23:43:53
0000/00/00 00:00:00
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/25 00:06:11
2006/01/27 01:00:12
0000/00/00 00:00:00 0001/01/01 00:00:00 0
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/10 00:30:12 2006/02/10 00:00:00 2006/03/04 13:50:12 0001/01/01 12:30:01 2005
2006/01/27 10:13:10
2006/01/27 10:33:34 2006/01/27 00:00:00 0000/00/00 00:00:00 0001/01/01 10:33:34 2006
2006/01/27 10:44:42 2006/01/27 00:00:00 0000/00/00 00:00:00 0001/01/01 10:44:42 2006
2006/01/27 10:48:01 2006/01/27 00:00:00 2006/01/27 10:48:01 0001/01/01 10:48:01 2006

24行が選択されました。

SQL> DECLARE
2 num_rows PLS_INTEGER;
3 BEGIN
4 num_rows := DBMS_HS_PASSTHROUGH.EXECUTE_IMMEDIATE@mysql4113a_mac_sv
5 (
6 'insert into date_test values(now(), now(), now(), now(), now())'
7 );
8 END;
9 /

PL/SQLプロシージャが正常に完了しました。

SQL> select * from "date_test"@mysql4113a_mac_sv;

r_datetime r_date r_timestamp r_time r_year
------------------- ------------------- ------------------- ------------------- ----------
1990/01/01 00:00:00 2006/01/20 23:04:22
2000/12/01 00:00:00 2006/01/20 23:04:35
1800/01/01 00:00:00 2006/01/20 23:04:51
1810/12/01 00:00:00 2006/01/20 23:05:06
2002/12/01 00:00:00
2006/01/20 23:05:33
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/24 23:12:32
2006/01/24 23:13:19 2006/01/24 00:00:00 2006/01/24 23:13:19 0001/01/01 23:13:19 2006
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/24 23:30:56
2006/01/24 23:32:31
2006/01/24 23:43:53
0000/00/00 00:00:00
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/25 00:06:11
2006/01/27 01:00:12
0000/00/00 00:00:00 0001/01/01 00:00:00 0
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/10 00:30:12 2006/02/10 00:00:00 2006/03/04 13:50:12 0001/01/01 12:30:01 2005
2006/01/27 10:13:10
2006/01/27 10:33:34 2006/01/27 00:00:00 0000/00/00 00:00:00 0001/01/01 10:33:34 2006
2006/01/27 10:44:42 2006/01/27 00:00:00 0000/00/00 00:00:00 0001/01/01 10:44:42 2006
2006/01/27 10:48:01 2006/01/27 00:00:00 2006/01/27 10:48:01 0001/01/01 10:48:01 2006
2006/01/28 14:55:38 2006/01/28 00:00:00 2006/01/28 14:55:38 0001/01/01 14:55:38 2006

25行が選択されました。

SQL> commit;

コミットが完了しました。

SQL>

=======================
結構苦戦しそうだが、MySQLの日付型、時刻型を利用する際の注意点をまとめておくと、

利用しているMyODBC Driverは、ここを参照してもらいたい

MySQLOracle
datetime型date型
date型
timestamp型
time型
year型number型
・検索時には、date型ではなく文字列で検索する。 ・MySQL側の型がtimestamp型である場合には、0000年00月00日かをCASE式かDECODE関数を利用してNULLにする必要がる。 ・MySQL側の型がyear型の場合、0ならば、NULLにしておいたほうがよいだろう。 ・逆にOracleからMySQL側に登録する際には、日付や時間の書式チェックを厳重に行うようにしたほうがよい。そうでないと0000年0月0日が設定されてしまう可能性もある。 ・現在日付や時刻を設定する場合には、PL/SQLからexecute immediate文を利用する必要がありそう。
gencon_blog_img1
(このような特殊な構成の場合だけだと思うが。。)  通常の構成ならば、dbms_hs_passthroughパッケージを利用するのもよいだろう。


やっと日付、時間型の確認が終わり、次回は、数値型(多分整数だけ)について、MySQL側の癖から確認してみようと思う。

| | | コメント (0) | トラックバック (0)

2006年1月30日 (月)

Mac De Oracle Heterogeneous! #23

引き続き、Generic Connectivity経由でアクセスした場合、Oracle側では日付、時刻型がどのようにどのように扱われるか確認する。

Oracle側の関数や、逆にMySQL側の関数を利用した場合には、PostgreSQLの場合と同様にエラーとなる。

CORYDORAS> insert into date_test_mysql4113a_mac_sv@oracle10g_win values(sysdate,null,null,null,null);
insert into date_test_mysql4113a_mac_sv@oracle10g_win values(sysdate,null,null,null,null)
*
行1でエラーが発生しました。:
ORA-02070: データベースMYSQL4113A_MAC_SVはこのコンテキストではspecial functionsをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。


CORYDORAS> insert into date_test_mysql4113a_mac_sv@oracle10g_win values(now(),null,null,null,null);
insert into date_test_mysql4113a_mac_sv@oracle10g_win values(now(),null,null,null,null)
*
行1でエラーが発生しました。:
ORA-00904: "NOW": 無効な識別子です。


CORYDORAS> insert into date_test_mysql4113a_mac_sv@oracle10g_win values(to_char(sysdate,'yyyymmddhh24miss'),null,null,null,null);
insert into date_test_mysql4113a_mac_sv@oracle10g_win values(to_char(sysdate,'yyyymmddhh24miss'),null,null,null,null)
*
行1でエラーが発生しました。:
ORA-02070: データベースMYSQL4113A_MAC_SVはこのコンテキストではTO_CHARをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。


CORYDORAS> insert into date_test_mysql4113a_mac_sv@oracle10g_win values(to_date('20061212235534','yyyymmddhh24miss'),null,null,null,null);
insert into date_test_mysql4113a_mac_sv@oracle10g_win values(to_date('20061212235534','yyyymmddhh24miss'),null,null,null,null)
*
行1でエラーが発生しました。:
ORA-02070: データベースMYSQL4113A_MAC_SVはこのコンテキストではTO_DATEをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。


CORYDORAS>

以下のようなリテラル指定ではうまく登録できるようだ。

CORYDORAS> insert into date_test_mysql4113a_mac_sv@oracle10g_win values('2006-01-10 00:30:12','2006-02-10','2006-03-04 13:50:12','12:30:01',2005);

1行が作成されました。

CORYDORAS> select * from date_test_mysql4113a_mac_sv@oracle10g_win;

r_datetime r_date r_timestamp r_time r_year
-------------------------- -------------------------- -------------------------- -------------------- -------
1990/01/01 00:00:00 2006/01/20 23:04:22
2000/12/01 00:00:00 2006/01/20 23:04:35
1800/01/01 00:00:00 2006/01/20 23:04:51
1810/12/01 00:00:00 2006/01/20 23:05:06
2002/12/01 00:00:00
2006/01/20 23:05:33
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/24 23:12:32
2006/01/24 23:13:19 2006/01/24 00:00:00 2006/01/24 23:13:19 0001/01/01 23:13:19 2006
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/24 23:30:56
2006/01/24 23:32:31
2006/01/24 23:43:53
0000/00/00 00:00:00
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/25 00:06:11
2006/01/27 01:00:12
0000/00/00 00:00:00 0001/01/01 00:00:00 0
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/10 00:30:12 2006/02/10 00:00:00 2006/03/04 13:50:12 0001/01/01 12:30:01 2005

20行が選択されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS>

mysql> select * from date_test;
+---------------------+------------+---------------------+----------+--------+
| r_datetime | r_date | r_timestamp | r_time | r_year |
+---------------------+------------+---------------------+----------+--------+
| 1990-01-01 00:00:00 | NULL | 2006-01-20 23:04:22 | NULL | NULL |
| 2000-12-01 00:00:00 | NULL | 2006-01-20 23:04:35 | NULL | NULL |
| NULL | 1800-01-01 | 2006-01-20 23:04:51 | NULL | NULL |
| NULL | 1810-12-01 | 2006-01-20 23:05:06 | NULL | NULL |
| NULL | NULL | 2002-12-01 00:00:00 | NULL | NULL |
| NULL | NULL | 2006-01-20 23:05:33 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| NULL | NULL | 2006-01-24 23:12:32 | NULL | NULL |
| 2006-01-24 23:13:19 | 2006-01-24 | 2006-01-24 23:13:19 | 23:13:19 | 2006 |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| 0000-00-00 00:00:00 | NULL | 2006-01-24 23:30:56 | NULL | NULL |
| 0000-00-00 00:00:00 | NULL | 2006-01-24 23:32:31 | NULL | NULL |
| 2006-00-00 00:00:00 | NULL | 2006-01-24 23:43:53 | NULL | NULL |
| NULL | NULL | 0000-00-00 00:00:00 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| 2006-00-00 00:00:00 | NULL | 2006-01-25 00:06:11 | NULL | NULL |
| NULL | NULL | 2006-01-27 01:00:12 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| 2006-01-10 00:30:12 | 2006-02-10 | 2006-03-04 13:50:12 | 12:30:01 | 2005 |
+---------------------+------------+---------------------+----------+--------+
20 rows in set (0.00 sec)

mysql>

13月とか40日とか、44時、65分、76秒などもOracle側でエラーにならずに登録できる。但し、MySQL側では0000年00月00日という日付になってしまう。Oracle側で日付を問い合わせるとNULLになる(MyODBCドライバの仕様通り)。

CORYDORAS> insert into date_test_mysql4113a_mac_sv@oracle10g_win values('2006-13-40 44:65:76',null,null,null,null);

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> select * from date_test_mysql4113a_mac_sv@oracle10g_win;

r_datetime r_date r_timestamp r_time r_year
-------------------------- -------------------------- -------------------------- -------------------- -------
1990/01/01 00:00:00 2006/01/20 23:04:22
2000/12/01 00:00:00 2006/01/20 23:04:35
1800/01/01 00:00:00 2006/01/20 23:04:51
1810/12/01 00:00:00 2006/01/20 23:05:06
2002/12/01 00:00:00
2006/01/20 23:05:33
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/24 23:12:32
2006/01/24 23:13:19 2006/01/24 00:00:00 2006/01/24 23:13:19 0001/01/01 23:13:19 2006
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/24 23:30:56
2006/01/24 23:32:31
2006/01/24 23:43:53
0000/00/00 00:00:00
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/25 00:06:11
2006/01/27 01:00:12
0000/00/00 00:00:00 0001/01/01 00:00:00 0
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/10 00:30:12 2006/02/10 00:00:00 2006/03/04 13:50:12 0001/01/01 12:30:01 2005
2006/01/27 10:13:10

21行が選択されました。

CORYDORAS>


mysql> select * from date_test;
+---------------------+------------+---------------------+----------+--------+
| r_datetime | r_date | r_timestamp | r_time | r_year |
+---------------------+------------+---------------------+----------+--------+
| 1990-01-01 00:00:00 | NULL | 2006-01-20 23:04:22 | NULL | NULL |
| 2000-12-01 00:00:00 | NULL | 2006-01-20 23:04:35 | NULL | NULL |
| NULL | 1800-01-01 | 2006-01-20 23:04:51 | NULL | NULL |
| NULL | 1810-12-01 | 2006-01-20 23:05:06 | NULL | NULL |
| NULL | NULL | 2002-12-01 00:00:00 | NULL | NULL |
| NULL | NULL | 2006-01-20 23:05:33 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| NULL | NULL | 2006-01-24 23:12:32 | NULL | NULL |
| 2006-01-24 23:13:19 | 2006-01-24 | 2006-01-24 23:13:19 | 23:13:19 | 2006 |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| 0000-00-00 00:00:00 | NULL | 2006-01-24 23:30:56 | NULL | NULL |
| 0000-00-00 00:00:00 | NULL | 2006-01-24 23:32:31 | NULL | NULL |
| 2006-00-00 00:00:00 | NULL | 2006-01-24 23:43:53 | NULL | NULL |
| NULL | NULL | 0000-00-00 00:00:00 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| 2006-00-00 00:00:00 | NULL | 2006-01-25 00:06:11 | NULL | NULL |
| NULL | NULL | 2006-01-27 01:00:12 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| 2006-01-10 00:30:12 | 2006-02-10 | 2006-03-04 13:50:12 | 12:30:01 | 2005 |
| 0000-00-00 00:00:00 | NULL | 2006-01-27 10:13:10 | NULL | NULL |
+---------------------+------------+---------------------+----------+--------+
21 rows in set (0.00 sec)

mysql>

長いので、また、次回につづく。

| | | コメント (0) | トラックバック (0)

2006年1月29日 (日)

Mac De Oracle Heterogeneous! #22

つづきです。前回は、MySQL側で日付、時刻型がどのように登録され、どのような癖があるのかを確認した。

今回は、Generic Connectivity経由でアクセスした場合、Oracle側ではMySQLの日付、時刻型がどのようにどのように扱われるか確認する。

以下のような経路でアクセスしている。


gencon_blog_img01

MySQL4.1.13aには以下のようなデータが登録済み。気になるところは0000年00月00日が許容されている点だろう。

Last login: Thu Jan 26 00:32:31 on console
Welcome to Darwin!
G5Server:˜ discus$ mysql -u discus -p mysqldb41
Enter password:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor. Commands end with ; or ¥g.
Your MySQL connection id is 1 to server version: 4.1.13a

Type 'help;' or '¥h' for help. Type '¥c' to clear the buffer.

mysql>
mysql>
mysql> select * from date_test;
+---------------------+------------+---------------------+----------+--------+
| r_datetime | r_date | r_timestamp | r_time | r_year |
+---------------------+------------+---------------------+----------+--------+
| 1990-01-01 00:00:00 | NULL | 2006-01-20 23:04:22 | NULL | NULL |
| 2000-12-01 00:00:00 | NULL | 2006-01-20 23:04:35 | NULL | NULL |
| NULL | 1800-01-01 | 2006-01-20 23:04:51 | NULL | NULL |
| NULL | 1810-12-01 | 2006-01-20 23:05:06 | NULL | NULL |
| NULL | NULL | 2002-12-01 00:00:00 | NULL | NULL |
| NULL | NULL | 2006-01-20 23:05:33 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| NULL | NULL | 2006-01-24 23:12:32 | NULL | NULL |
| 2006-01-24 23:13:19 | 2006-01-24 | 2006-01-24 23:13:19 | 23:13:19 | 2006 |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| 0000-00-00 00:00:00 | NULL | 2006-01-24 23:30:56 | NULL | NULL |
| 0000-00-00 00:00:00 | NULL | 2006-01-24 23:32:31 | NULL | NULL |
| 2006-00-00 00:00:00 | NULL | 2006-01-24 23:43:53 | NULL | NULL |
| NULL | NULL | 0000-00-00 00:00:00 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| 2006-00-00 00:00:00 | NULL | 2006-01-25 00:06:11 | NULL | NULL |
+---------------------+------------+---------------------+----------+--------+
16 rows in set (0.02 sec)

mysql>

まず、単純に問い合わせてみる。datetime型、date型、timestamp型、time型は、Oracleのdate型にマッピングされている。year型はnumber型にマッピングされている。OracleではMySQLのtime型もdate型として扱われている。一番まずいのは、timestamp型に 0000年00月00日が設定されている場合、オラクル側でも0000年00月00日となってしまう点である。Oracle側ではその後の処理で問題になる。尚、ODBCの仕様では、NULLになるのが正しいようなのでこのテストで利用している MyODBCドライバの問題である可能性が高いと思われる。(timestamp型以外ではNULLが返されている)
CORYDORAS> alter session set nls_date_format = 'yyyy/mm/dd hh24:mi:ss';

セッションが変更されました。

CORYDORAS> alter session set nls_timestamp_format = 'yyyy/mm/dd hh24:mi:ss.ff';

セッションが変更されました。

CORYDORAS> select * from date_test_mysql4113a_mac_sv@oracle10g_win;

r_datetime r_date r_timestamp r_time r_year
------------------- ------------------- ------------------- ------------------- ----------
1990/01/01 00:00:00 2006/01/20 23:04:22
2000/12/01 00:00:00 2006/01/20 23:04:35
1800/01/01 00:00:00 2006/01/20 23:04:51
1810/12/01 00:00:00 2006/01/20 23:05:06
2002/12/01 00:00:00
2006/01/20 23:05:33
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/24 23:12:32
2006/01/24 23:13:19 2006/01/24 00:00:00 2006/01/24 23:13:19 0001/01/01 23:13:19 2006
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/24 23:30:56
2006/01/24 23:32:31
2006/01/24 23:43:53
0000/00/00 00:00:00
0000/00/00 00:00:00 0001/01/01 00:00:00 0
2006/01/25 00:06:11

16行が選択されました。

CORYDORAS>

CORYDORAS> select
2 dump("r_datetime") as r_datetime,
3 dump("r_date") as r_date,
4 dump("r_timestamp") as r_timestamp,
5 dump("r_time") as r_time,
6 dump("r_year") as r_year
7 from
8 date_test_mysql4113a_mac_sv@oracle10g_win;

R_DATETIME R_DATE R_TIMESTAMP R_TIME R_YEAR
------------------------------------ ------------------------------------ ------------------------------------ ------------------------------------ ------------------------------------
Typ=12 Len=7: 119,190,1,1,1,1,1 NULL Typ=12 Len=7: 120,106,1,20,24,5,23 NULL NULL
Typ=12 Len=7: 120,100,12,1,1,1,1 NULL Typ=12 Len=7: 120,106,1,20,24,5,36 NULL NULL
NULL Typ=12 Len=7: 118,100,1,1,1,1,1 Typ=12 Len=7: 120,106,1,20,24,5,52 NULL NULL
NULL Typ=12 Len=7: 118,110,12,1,1,1,1 Typ=12 Len=7: 120,106,1,20,24,6,7 NULL NULL
NULL NULL Typ=12 Len=7: 120,102,12,1,1,1,1 NULL NULL
NULL NULL Typ=12 Len=7: 120,106,1,20,24,6,34 NULL NULL
NULL NULL Typ=12 Len=7: 100,100,0,0,1,1,1 Typ=12 Len=7: 100,101,1,1,1,1,1 Typ=2 Len=1: 128
NULL NULL Typ=12 Len=7: 120,106,1,24,24,13,33 NULL NULL
Typ=12 Len=7: 120,106,1,24,24,14,20 Typ=12 Len=7: 120,106,1,24,1,1,1 Typ=12 Len=7: 120,106,1,24,24,14,20 Typ=12 Len=7: 100,101,1,1,24,14,20 Typ=2 Len=3: 194,21,7
NULL NULL Typ=12 Len=7: 100,100,0,0,1,1,1 Typ=12 Len=7: 100,101,1,1,1,1,1 Typ=2 Len=1: 128
NULL NULL Typ=12 Len=7: 120,106,1,24,24,31,57 NULL NULL
NULL NULL Typ=12 Len=7: 120,106,1,24,24,33,32 NULL NULL
NULL NULL Typ=12 Len=7: 120,106,1,24,24,44,54 NULL NULL
NULL NULL Typ=12 Len=7: 100,100,0,0,1,1,1 NULL NULL
NULL NULL Typ=12 Len=7: 100,100,0,0,1,1,1 Typ=12 Len=7: 100,101,1,1,1,1,1 Typ=2 Len=1: 128
NULL NULL Typ=12 Len=7: 120,106,1,25,1,7,12 NULL NULL

16行が選択されました。

CORYDORAS>

nullを設定するのは問題なかった。次が問題、パススルーされているようで、MySQL側で空文字を設定した場合と同じ結果になる。MySQLではワーニングが表示されたりするが、generic connectivity 経由では正常に?処理されてしまう。(ワーニングを拾う方法はあるのか? 別途調べるか・・)

CORYDORAS> insert into date_test_mysql4113a_mac_sv@oracle10g_win values(null,null,null,null,null);

1行が作成されました。

CORYDORAS> insert into date_test_mysql4113a_mac_sv@oracle10g_win values('','','','','');

1行が作成されました。

CORYDORAS> set null 'NULL'
CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> select * from date_test_mysql4113a_mac_sv@oracle10g_win;

r_datetime r_date r_timestamp r_time r_year
------------------------------ ------------------------------ ------------------------------ ------------------------------ ------
1990/01/01 00:00:00 NULL 2006/01/20 23:04:22 NULL NULL
2000/12/01 00:00:00 NULL 2006/01/20 23:04:35 NULL NULL
NULL 1800/01/01 00:00:00 2006/01/20 23:04:51 NULL NULL
NULL 1810/12/01 00:00:00 2006/01/20 23:05:06 NULL NULL
NULL NULL 2002/12/01 00:00:00 NULL NULL
NULL NULL 2006/01/20 23:05:33 NULL NULL
NULL NULL 0000/00/00 00:00:00 0001/01/01 00:00:00 0
NULL NULL 2006/01/24 23:12:32 NULL NULL
2006/01/24 23:13:19 2006/01/24 00:00:00 2006/01/24 23:13:19 0001/01/01 23:13:19 2006
NULL NULL 0000/00/00 00:00:00 0001/01/01 00:00:00 0
NULL NULL 2006/01/24 23:30:56 NULL NULL
NULL NULL 2006/01/24 23:32:31 NULL NULL
NULL NULL 2006/01/24 23:43:53 NULL NULL
NULL NULL 0000/00/00 00:00:00 NULL NULL
NULL NULL 0000/00/00 00:00:00 0001/01/01 00:00:00 0
NULL NULL 2006/01/25 00:06:11 NULL NULL
NULL NULL 2006/01/27 01:00:12 NULL NULL
NULL NULL 0000/00/00 00:00:00 0001/01/01 00:00:00 0

18行が選択されました。

CORYDORAS>

year型はnumber型にマップされているので仕方ないが、date型にマップされている各型でもオラクルではエラーになる0000年や、00月、00日は登録できてしまう。

CORYDORAS> insert into date_test_mysql4113a_mac_sv@oracle10g_win values('0000-00-00 00:00:00','0000-00-00','0000-00-00 00:00:00.123456','0000-00-00 00:00:00','0000');

1行が作成されました。

CORYDORAS> commit;

コミットが完了しました。

CORYDORAS> select * from date_test_mysql4113a_mac_sv@oracle10g_win;

r_datetime r_date r_timestamp r_time r_year
------------------------------ ------------------------------ ------------------------------ ------------------------------ ------
1990/01/01 00:00:00 NULL 2006/01/20 23:04:22 NULL NULL
2000/12/01 00:00:00 NULL 2006/01/20 23:04:35 NULL NULL
NULL 1800/01/01 00:00:00 2006/01/20 23:04:51 NULL NULL
NULL 1810/12/01 00:00:00 2006/01/20 23:05:06 NULL NULL
NULL NULL 2002/12/01 00:00:00 NULL NULL
NULL NULL 2006/01/20 23:05:33 NULL NULL
NULL NULL 0000/00/00 00:00:00 0001/01/01 00:00:00 0
NULL NULL 2006/01/24 23:12:32 NULL NULL
2006/01/24 23:13:19 2006/01/24 00:00:00 2006/01/24 23:13:19 0001/01/01 23:13:19 2006
NULL NULL 0000/00/00 00:00:00 0001/01/01 00:00:00 0
NULL NULL 2006/01/24 23:30:56 NULL NULL
NULL NULL 2006/01/24 23:32:31 NULL NULL
NULL NULL 2006/01/24 23:43:53 NULL NULL
NULL NULL 0000/00/00 00:00:00 NULL NULL
NULL NULL 0000/00/00 00:00:00 0001/01/01 00:00:00 0
NULL NULL 2006/01/25 00:06:11 NULL NULL
NULL NULL 2006/01/27 01:00:12 NULL NULL
NULL NULL 0000/00/00 00:00:00 0001/01/01 00:00:00 0
NULL NULL 0000/00/00 00:00:00 0001/01/01 00:00:00 0

19行が選択されました。

CORYDORAS>

MySQL側では以下のようになっている。timestamp型の0000−00−00がOracle側ではNULLにならないのでOracle側のクエリでNULLに強制的に変換してやる必要がありそうだ。(year型の場合も強制的にNULLにするか、0001年にするようなクエリにする必要はありそうだ)
mysql> select * from date_test;
+---------------------+------------+---------------------+----------+--------+
| r_datetime | r_date | r_timestamp | r_time | r_year |
+---------------------+------------+---------------------+----------+--------+
| 1990-01-01 00:00:00 | NULL | 2006-01-20 23:04:22 | NULL | NULL |
| 2000-12-01 00:00:00 | NULL | 2006-01-20 23:04:35 | NULL | NULL |
| NULL | 1800-01-01 | 2006-01-20 23:04:51 | NULL | NULL |
| NULL | 1810-12-01 | 2006-01-20 23:05:06 | NULL | NULL |
| NULL | NULL | 2002-12-01 00:00:00 | NULL | NULL |
| NULL | NULL | 2006-01-20 23:05:33 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| NULL | NULL | 2006-01-24 23:12:32 | NULL | NULL |
| 2006-01-24 23:13:19 | 2006-01-24 | 2006-01-24 23:13:19 | 23:13:19 | 2006 |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| 0000-00-00 00:00:00 | NULL | 2006-01-24 23:30:56 | NULL | NULL |
| 0000-00-00 00:00:00 | NULL | 2006-01-24 23:32:31 | NULL | NULL |
| 2006-00-00 00:00:00 | NULL | 2006-01-24 23:43:53 | NULL | NULL |
| NULL | NULL | 0000-00-00 00:00:00 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| 2006-00-00 00:00:00 | NULL | 2006-01-25 00:06:11 | NULL | NULL |
| NULL | NULL | 2006-01-27 01:00:12 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
+---------------------+------------+---------------------+----------+--------+
19 rows in set (0.00 sec)

mysql>

長くなるので次回につづく。

| | | コメント (0) | トラックバック (0)

2006年1月24日 (火)

Mac De Oracle Heterogeneous! #21

つづきです。

今日は、MySQLの日付、時刻型について、Oracleとの違いを見ていく。

最初は、すべて 0 を設定してみる。
なんと正常に登録できてしまう。
しかもOracleやMySQLでも設定できなかった 0月 0日やOracleではエラーになってしまう 0000年が設定できるのである。generic connectivityでは問題になるかもしれないので注意しておく必要がある。

mysql> insert into date_test values(0,0,0,0,0);
Query OK, 1 row affected (0.09 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from date_test;
+---------------------+------------+---------------------+----------+--------+
| r_datetime | r_date | r_timestamp | r_time | r_year |
+---------------------+------------+---------------------+----------+--------+
| 1990-01-01 00:00:00 | NULL | 2006-01-20 23:04:22 | NULL | NULL |
| 2000-12-01 00:00:00 | NULL | 2006-01-20 23:04:35 | NULL | NULL |
| NULL | 1800-01-01 | 2006-01-20 23:04:51 | NULL | NULL |
| NULL | 1810-12-01 | 2006-01-20 23:05:06 | NULL | NULL |
| NULL | NULL | 2002-12-01 00:00:00 | NULL | NULL |
| NULL | NULL | 2006-01-20 23:05:33 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
+---------------------+------------+---------------------+----------+--------+
7 rows in set (0.00 sec)


nullableなのでNULLを設定しても問題ない。ただし、timestamp型はnullにならず必ずタイムスタンプが設定される。この辺りはOracleでも問題なることはないだろう。

mysql> insert into date_test values(null,null,null,null,null);
Query OK, 1 row affected (0.09 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from date_test;
+---------------------+------------+---------------------+----------+--------+
| r_datetime | r_date | r_timestamp | r_time | r_year |
+---------------------+------------+---------------------+----------+--------+
| 1990-01-01 00:00:00 | NULL | 2006-01-20 23:04:22 | NULL | NULL |
| 2000-12-01 00:00:00 | NULL | 2006-01-20 23:04:35 | NULL | NULL |
| NULL | 1800-01-01 | 2006-01-20 23:04:51 | NULL | NULL |
| NULL | 1810-12-01 | 2006-01-20 23:05:06 | NULL | NULL |
| NULL | NULL | 2002-12-01 00:00:00 | NULL | NULL |
| NULL | NULL | 2006-01-20 23:05:33 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| NULL | NULL | 2006-01-24 23:12:32 | NULL | NULL |
+---------------------+------------+---------------------+----------+--------+
8 rows in set (0.00 sec)

mysql>


現在時刻、日付の設定も特に問題になるようなことはなさそうに感じる。ただ warningが出ているが、気にせずcommitすると登録できてしまうので、プログラムミスでwarningを拾わず、rollbackしなかったらおかしな日付が登録される危険性がある。
ちなみに、MySQL4.1.13aでは 1 warningとでているが、MySQL4.0.26-ntでは warining表示すら表示されていなかった。

mysql> insert into date_test values(now(), now(), now(), now(), now());
Query OK, 1 row affected, 1 warning (0.09 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from date_test;
+---------------------+------------+---------------------+----------+--------+
| r_datetime | r_date | r_timestamp | r_time | r_year |
+---------------------+------------+---------------------+----------+--------+
| 1990-01-01 00:00:00 | NULL | 2006-01-20 23:04:22 | NULL | NULL |
| 2000-12-01 00:00:00 | NULL | 2006-01-20 23:04:35 | NULL | NULL |
| NULL | 1800-01-01 | 2006-01-20 23:04:51 | NULL | NULL |
| NULL | 1810-12-01 | 2006-01-20 23:05:06 | NULL | NULL |
| NULL | NULL | 2002-12-01 00:00:00 | NULL | NULL |
| NULL | NULL | 2006-01-20 23:05:33 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| NULL | NULL | 2006-01-24 23:12:32 | NULL | NULL |
| 2006-01-24 23:13:19 | 2006-01-24 | 2006-01-24 23:13:19 | 23:13:19 | 2006 |
+---------------------+------------+---------------------+----------+--------+
9 rows in set (0.00 sec)

mysql>

さて、お次は問題。MySQLでは、PostgreSQLでも設定できなかった空文字が warningはでるがコミットはできてしまう。前述したがwarningを拾わずにcommitしてしまうようなプログラムがあれば日付としておかしな値が設定されてしまう危険性がある。

mysql> insert into date_test values('','','','','');
Query OK, 1 row affected, 5 warnings (0.07 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from date_test;
+---------------------+------------+---------------------+----------+--------+
| r_datetime | r_date | r_timestamp | r_time | r_year |
+---------------------+------------+---------------------+----------+--------+
| 1990-01-01 00:00:00 | NULL | 2006-01-20 23:04:22 | NULL | NULL |
| 2000-12-01 00:00:00 | NULL | 2006-01-20 23:04:35 | NULL | NULL |
| NULL | 1800-01-01 | 2006-01-20 23:04:51 | NULL | NULL |
| NULL | 1810-12-01 | 2006-01-20 23:05:06 | NULL | NULL |
| NULL | NULL | 2002-12-01 00:00:00 | NULL | NULL |
| NULL | NULL | 2006-01-20 23:05:33 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| NULL | NULL | 2006-01-24 23:12:32 | NULL | NULL |
| 2006-01-24 23:13:19 | 2006-01-24 | 2006-01-24 23:13:19 | 23:13:19 | 2006 |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
+---------------------+------------+---------------------+----------+--------+
10 rows in set (0.00 sec)

mysql>

さすがに、13月や35日、26時間、 70分、70秒などは warningとして警告がでるが、やはり commitが行える。内容を見てみると、0000年0月0日 0時0分0秒となる。注意しなければ。。。

mysql> insert into date_test values('2006-13-35 26:70:70',null,null,null,null);
Query OK, 1 row affected, 1 warning (0.06 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from date_test;
+---------------------+------------+---------------------+----------+--------+
| r_datetime | r_date | r_timestamp | r_time | r_year |
+---------------------+------------+---------------------+----------+--------+
| 1990-01-01 00:00:00 | NULL | 2006-01-20 23:04:22 | NULL | NULL |
| 2000-12-01 00:00:00 | NULL | 2006-01-20 23:04:35 | NULL | NULL |
| NULL | 1800-01-01 | 2006-01-20 23:04:51 | NULL | NULL |
| NULL | 1810-12-01 | 2006-01-20 23:05:06 | NULL | NULL |
| NULL | NULL | 2002-12-01 00:00:00 | NULL | NULL |
| NULL | NULL | 2006-01-20 23:05:33 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| NULL | NULL | 2006-01-24 23:12:32 | NULL | NULL |
| 2006-01-24 23:13:19 | 2006-01-24 | 2006-01-24 23:13:19 | 23:13:19 | 2006 |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| 0000-00-00 00:00:00 | NULL | 2006-01-24 23:30:56 | NULL | NULL |
+---------------------+------------+---------------------+----------+--------+
11 rows in set (0.00 sec)

mysql> insert into date_test values('99999999',null,null,null,null);
Query OK, 1 row affected, 1 warning (0.04 sec)

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from date_test;
+---------------------+------------+---------------------+----------+--------+
| r_datetime | r_date | r_timestamp | r_time | r_year |
+---------------------+------------+---------------------+----------+--------+
| 1990-01-01 00:00:00 | NULL | 2006-01-20 23:04:22 | NULL | NULL |
| 2000-12-01 00:00:00 | NULL | 2006-01-20 23:04:35 | NULL | NULL |
| NULL | 1800-01-01 | 2006-01-20 23:04:51 | NULL | NULL |
| NULL | 1810-12-01 | 2006-01-20 23:05:06 | NULL | NULL |
| NULL | NULL | 2002-12-01 00:00:00 | NULL | NULL |
| NULL | NULL | 2006-01-20 23:05:33 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| NULL | NULL | 2006-01-24 23:12:32 | NULL | NULL |
| 2006-01-24 23:13:19 | 2006-01-24 | 2006-01-24 23:13:19 | 23:13:19 | 2006 |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| 0000-00-00 00:00:00 | NULL | 2006-01-24 23:30:56 | NULL | NULL |
| 0000-00-00 00:00:00 | NULL | 2006-01-24 23:32:31 | NULL | NULL |
+---------------------+------------+---------------------+----------+--------+
12 rows in set (0.00 sec)

mysql>

これもあぶない。0月、0日がワーニングもなく登録できるのである。

mysql> insert into date_test values('2006-00-00 00:00:00',null,null,null,null);
Query OK, 1 row affected (0.06 sec)

mysql> select * from date_test;
+---------------------+------------+---------------------+----------+--------+
| r_datetime | r_date | r_timestamp | r_time | r_year |
+---------------------+------------+---------------------+----------+--------+
| 1990-01-01 00:00:00 | NULL | 2006-01-20 23:04:22 | NULL | NULL |
| 2000-12-01 00:00:00 | NULL | 2006-01-20 23:04:35 | NULL | NULL |
| NULL | 1800-01-01 | 2006-01-20 23:04:51 | NULL | NULL |
| NULL | 1810-12-01 | 2006-01-20 23:05:06 | NULL | NULL |
| NULL | NULL | 2002-12-01 00:00:00 | NULL | NULL |
| NULL | NULL | 2006-01-20 23:05:33 | NULL | NULL |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| NULL | NULL | 2006-01-24 23:12:32 | NULL | NULL |
| 2006-01-24 23:13:19 | 2006-01-24 | 2006-01-24 23:13:19 | 23:13:19 | 2006 |
| 0000-00-00 00:00:00 | 0000-00-00 | 0000-00-00 00:00:00 | 00:00:00 | 0000 |
| 0000-00-00 00:00:00 | NULL | 2006-01-24 23:30:56 | NULL | NULL |
| 0000-00-00 00:00:00 | NULL | 2006-01-24 23:32:31 | NULL | NULL |
| 2006-00-00 00:00:00 | NULL | 2006-01-24 23:43:53 | NULL | NULL |
+---------------------+------------+---------------------+----------+--------+
13 rows in set (0.00 sec)

mysql>

ざっと確認してみたところ、ポイントは

0000年
0月
0日

それぞれを許容してしまうあたりだろうか。。


次回は、Generic Connectivityを経由してMySQLにアクセスしてみる。Oracle側ではどの型にマッピングされ、どのような癖があるのかを確認する。

| | | コメント (0) | トラックバック (0)

2006年1月23日 (月)

Mac De Oracle Heterogeneous! #20

前回は、PostgreSQL上で日付や時間型がどのように扱われるか確認してみた。今日はGenneric Connectivity経由でPostgreSQLに日付や時間を登録してみる。

いつものように、date型とtimestamp型の書式を設定しておく

CORYDORAS> alter session set nls_date_format = 'yyyy/mm/dd hh24:mi:ss';

セッションが変更されました。

CORYDORAS> alter session set nls_timestamp_format = 'yyyy/mm/dd hh24:mi:ss.ff';

セッションが変更されました。

Oracle10g R1 (MacOSX Server : PowerMac G5) --> oracle10g_win(データベースリンク) --> Oracle10g R1 (Windows XP Professional)のdate_test_postgresql749_mac(シノニム)--> generic connectivity agent --> MyODBCドライバ --> PostgreSQL7.4.9 の date_test表(MacOSX : PowerBook G4)という経路で問い合わせている。

PostgreSQL7.4.9の date型、time型、timestamp型すべてが、Oracleのdate型にマップされているため以下のような点に注意。

PostgreSQLのtime型は時間だけだが、Oracle側ではdate型になるため、0001/01/01+時間となる。
PostgreSQLのdate型は日付だけだが、Oracle型ではdate型なので 時間が00:00:00になる。
PostgreSQLのtimestamp型は、Oracleのdate型にマップされてしまうため、秒の少数部が欠落する。

ということになる。
以下は、generic connectivity経由でOracleから問い合わせた結果である。dump()関数を利用してデータタイプも確認してある。

CORYDORAS> select * from date_test_postgresql749_mac@oracle10g_win;

r_date r_timestamp r_time
------------------- ------------------- -------------------
1900/01/01 00:00:00
2006/01/20 00:00:00
1981/01/01 00:00:00
1990/12/01 00:00:00
0001/01/01 00:00:00
2007/03/07 00:00:00
0001/01/01 00:00:00
2007/09/11 00:00:00
2006/01/01 00:00:00
0001/01/01 23:59:59
2006/01/02 00:00:00
2006/01/02 03:01:00
2006/01/22 00:00:00 2006/01/22 21:57:25 0001/01/01 21:57:25
2008/11/07 04:50:03

14行が選択されました。

CORYDORAS>
CORYDORAS> list
1 select
2 dump("r_date") as r_date,
3 dump("r_timestamp") as r_timestamp,
4 dump("r_time") as r_time
5 from
6* date_test_postgresql749_mac@oracle10g_win
CORYDORAS> /

R_DATE R_TIMESTAMP R_TIME
---------------------------------------- ---------------------------------------- ----------------------------------------
Typ=12 Len=7: 119,100,1,1,1,1,1 NULL NULL
Typ=12 Len=7: 120,106,1,20,1,1,1 NULL NULL
NULL Typ=12 Len=7: 119,181,1,1,1,1,1 NULL
NULL Typ=12 Len=7: 119,190,12,1,1,1,1 NULL
Typ=12 Len=7: 100,101,1,1,1,1,1 NULL NULL
Typ=12 Len=7: 120,107,3,7,1,1,1 NULL NULL
NULL Typ=12 Len=7: 100,101,1,1,1,1,1 NULL
NULL Typ=12 Len=7: 120,107,9,11,1,1,1 NULL
NULL Typ=12 Len=7: 120,106,1,1,1,1,1 NULL
NULL NULL Typ=12 Len=7: 100,101,1,1,24,60,60
NULL Typ=12 Len=7: 120,106,1,2,1,1,1 NULL
NULL Typ=12 Len=7: 120,106,1,2,4,2,1 NULL
Typ=12 Len=7: 120,106,1,22,1,1,1 Typ=12 Len=7: 120,106,1,22,22,58,26 Typ=12 Len=7: 100,101,1,1,22,58,26
NULL Typ=12 Len=7: 120,108,11,7,5,51,4 NULL

14行が選択されました。

CORYDORAS>

次に、日付、時間型データを登録してみた。
パススルーされているのだろうか、to_date()関数は利用できない。(HS_CALL_NAME初期化パラメータでPostgreSQLのto_date関数が利用できるかは未確認。)

CORYDORAS> insert into date_test_postgresql749_mac@oracle10g_win
2 values(to_date('00000000','yyyymmdd'),null,null);
insert into date_test_postgresql749_mac@oracle10g_win
*
行1でエラーが発生しました。:
ORA-02070: データベースPOSTGRESQL749_MACはこのコンテキストではTO_DATEをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。

PostgreSQL上でもエラーになったINSERT文を実行してみると、これはPostgreSQLまで届いているようだ。PostgreSQL上で実行した時と同じエラーが返ってくる。

CORYDORAS> insert into date_test_postgresql749_mac@oracle10g_win
2 values('00000000',null,null);
insert into date_test_postgresql749_mac@oracle10g_win
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: date/time field value out of range: "00000000" (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。

Oracleのsysdate,systimestampを利用してみる。これは予想通りエラーとなる。

CORYDORAS> 
CORYDORAS> insert into date_test_postgresql749_mac@oracle10g_win
2 values(sysdate,systimestamp,sysdate);
insert into date_test_postgresql749_mac@oracle10g_win
*
行1でエラーが発生しました。:
ORA-02070: データベースPOSTGRESQL749_MACはこのコンテキストではspecial functionsをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。

to_char()関数を利用してみたが、これはto_date()関数と同じで利用できない。

CORYDORAS> insert into date_test_postgresql749_mac@oracle10g_win
2 values(to_char(sysdate,'yyyymmdd'), to_char(systimestamp,'yyyymmddhh24miss.ff'), to_char(sysdate,'hh24miss'));
insert into date_test_postgresql749_mac@oracle10g_win
*
行1でエラーが発生しました。:
ORA-02070: データベースPOSTGRESQL749_MACはこのコンテキストではTO_CHARをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。

では、暗黙型変換に任せて、単純に日付や時間を文字列指定した場合はどうか? 
やっと、登録できた。(よかった、よかった。と安心ばかりはしていられない。。。)


CORYDORAS> insert into date_test_postgresql749_mac@oracle10g_win
2  values('20061231','20060101 125959','235959');

1行が作成されました。

CORYDORAS> select * from date_test_postgresql749_mac@oracle10g_win;

r_date r_timestamp r_time
---------------------------------------- ---------------------------------------- ----------------------------------------
1900/01/01 00:00:00
2006/01/20 00:00:00
1981/01/01 00:00:00
1990/12/01 00:00:00
0001/01/01 00:00:00
2007/03/07 00:00:00
0001/01/01 00:00:00
2007/09/11 00:00:00
2006/01/01 00:00:00
0001/01/01 23:59:59
2006/01/02 00:00:00
2006/01/02 03:01:00
2006/01/22 00:00:00 2006/01/22 21:57:25 0001/01/01 21:57:25
2008/11/07 04:50:03
2006/12/31 00:00:00 2006/01/01 12:59:59 0001/01/01 23:59:59

15行が選択されました。

各列はnullableなのでNULLを設定することも問題ない。

CORYDORAS> 
CORYDORAS> insert into date_test_postgresql749_mac@oracle10g_win
2 values(null,null,null);

1行が作成されました。

Oracleでは、今のところ、空文字=NULLなのでNULLが登録されると予想していたがDML文がパススルーされているようで、PostgreSQL上で実行した場合と同様の結果(エラー)になる。(尚、本来は、空文字とNULLは別もの。オラクルのマニュアルにも記載があり空文字=NULLという扱いにはなっているが将来は変わる可能性があるというようなニュアンスのコメントが記載されている)

CORYDORAS> insert into date_test_postgresql749_mac@oracle10g_win
2 values('',null,null);
insert into date_test_postgresql749_mac@oracle10g_win
*
行1でエラーが発生しました。:
ORA-28500: OracleからOracle以外のシステムへの接続で次のメッセージが戻されました:
[Generic Connectivity Using ODBC]ERROR: invalid input syntax for type date: "" (SQL State: S1000; SQL Code: 7)
ORA-02063: 先行のエラー・メッセージを参照してください2 lines(POSTGRESQL749_MAC)。
ORA-02063: 先行のエラー・メッセージを参照してください3 lines(ORACLE10G_WIN)。

しかし、リテラルでしか登録できないとなると、現在時間や日付を設定したい場合には非常に都合が悪い。スカラー副問合せを利用してみたがこれもエラーとなった。これは困った。

CORYDORAS> 
CORYDORAS> list
1 insert into date_test_postgresql749_mac@oracle10g_win
2 values(
3 (select to_char(sysdate,'yyyymmdd') from dual),
4 (select to_char(systimestamp,'yyyymmdd hh24miss.ff') from dual),
5 (select to_char(sysdate,'hh24miss') from dual)
6* )
CORYDORAS> /
insert into date_test_postgresql749_mac@oracle10g_win
*
行1でエラーが発生しました。:
ORA-02070: データベースPOSTGRESQL749_MACはこのコンテキストではsubqueriesをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。

PL/SQLからなら、なんとかなるかとも知れないと以下のようにしてみたが、今度はシノニム変換で問題が発生した。

CORYDORAS> 
CORYDORAS> declare
2 v_datetime_string varchar2(25);
3 v_date_string varchar2(8);
4 v_time_string varchar2(6);
5 begin
6 v_date_string := to_char(sysdate,'yyyymmdd');
7 v_datetime_string := to_char(systimestamp, 'yyyymmdd hh24miss.ff');
8 v_time_string := to_char(sysdate,'hh24miss');
9 --
10 insert into date_test_postgresql749_mac@oracle10g_win
11 values(v_date_string, v_datetime_string, v_time_string);
12 commit;
13 end;
14 /
insert into date_test_postgresql749_mac@oracle10g_win
*
行10でエラーが発生しました。:
ORA-06550: 行10、列3:
PL/SQL: ORA-00980: シノニム変換が無効です。
ORA-06550: 行10、列3:
PL/SQL: SQL Statement ignored

CORYDORAS>

WindowsのOracle10g R1を踏み台にしている関係なのか、無理矢理構築したOracle10g R1 for MacOSX Serverだからなのか確かなことは言えないが、以下のような流れではシノニムの解決ができないようである。

もちろん、Oracle10g for MacOSX Serverで Oracle Heterogeneous ServiceのGeneric connectivityが正式にサポートされればこのような構成

gencon_blog_img1

にする必要はない。。。。趣味というか興味だけでやっていることなので、こんな”おもしろい”(変わっているとも言う)構成してあるのでご注意を。

ちなみにMacOSX Serverの先にあるOracle10g R1 for Windowsからだと上記PL/SQLブロックで実行可能であった。やはり踏み台方式もしくは無理矢理構築したOracle10g for MacOSX Server側の問題のような気がする。。

SQL> declare
2 v_datetime_string varchar2(25);
3 v_date_string varchar2(8);
4 v_time_string varchar2(6);
5 begin
6 v_date_string := to_char(sysdate,'yyyymmdd');
7 v_datetime_string := to_char(systimestamp, 'yyyymmdd hh24miss.ff');
8 v_time_string := to_char(sysdate,'hh24miss');
9 --
10 insert into date_test_postgresql749_mac
11 values(v_date_string, v_datetime_string, v_time_string);
12 commit;
13 end;
14 /

PL/SQLプロシージャが正常に完了しました。

そして最後の悪あがき! 
insert文をexecute immediate文で実行してみた。おお〜〜っ!、Oracle10g for MacOSX ServerからPL/SQLブロックが実行できた瞬間だった。(爆!)

CORYDORAS> list
1 declare
2 v_timestamp_string varchar2(25);
3 v_date_string varchar2(8);
4 v_time_string varchar2(6);
5 v_sql varchar2(1000);
6 begin
7 v_date_string := to_char(sysdate,'yyyymmdd');
8 v_timestamp_string := to_char(systimestamp,'yyyymmdd hh24miss.ff');
9 v_time_string := to_char(sysdate,'hh24miss');
10 v_sql :=
11 'insert into date_test_postgresql749_mac@oracle10g_win values('||
12 '''' || v_date_string ||
13 ''',''' || v_timestamp_string ||
14 ''',''' || v_time_string || ''')'
15 ;
16 execute immediate v_sql;
17 commit;
18* end;
CORYDORAS> /

PL/SQLプロシージャが正常に完了しました。

CORYDORAS> select * from date_test_postgresql749_mac@oracle10g_win;

r_date r_timestamp r_time
------------------- ------------------- -------------------
1900/01/01 00:00:00
2006/01/20 00:00:00
1981/01/01 00:00:00
1990/12/01 00:00:00
0001/01/01 00:00:00
2007/03/07 00:00:00
0001/01/01 00:00:00
2007/09/11 00:00:00
2006/01/01 00:00:00
0001/01/01 23:59:59
2006/01/02 00:00:00
2006/01/02 03:01:00
2006/01/22 00:00:00 2006/01/22 21:57:25 0001/01/01 21:57:25
2008/11/07 04:50:03
2006/12/12 00:00:00
2006/12/12 12:01:01
0001/01/01 23:59:59
2006/01/23 00:00:00 2006/01/23 23:38:56 0001/01/01 23:38:56
2006/01/23 00:00:00 2006/01/23 23:50:34 0001/01/01 23:50:34

19行が選択されました。

CORYDORAS>


今日はここまで。

======
Generic Connectivity
日付、時間型のまとめ(PostgresSQL7.4.9編)

参照時のポイント
・PostgreSQL7.4.9の date型、time型、timestamp型すべてが、Oracleのdate型にマップされる。
・PostgreSQLのtime型は時間だけだが、Oracle側ではdate型になるため、0001/01/01+時間となる。
・PostgreSQLのdate型は日付だけだが、Oracle型ではdate型なので 時間が00:00:00になる。
・PostgreSQLのtimestamp型は、Oracleのdate型にマップされてしまうため、秒の少数部が欠落する。

検索時のポイント
・to_date()を利用してdate型で検索することも、日付、時間を文字列として検索することも可能(Oracleの動きに類似している)

登録時のポイント
・日付、時間を文字列(リテラル)として指定ことしかできない。
・現在時間や、日付を設定する場合は、PL/SQLからINSERT文や、UPDATE文を実行する。
 (但し、このテストで利用しているような特殊構成ではPL/SQLから実行するDMLは、execute immediate文を利用したダイナミックSQLにしたほうがよいかも。この環境では、たまたま動作しただけかもしれないのでご注意を。)

次回はMySQLで同様の確認を行う予定。

| | | コメント (0) | トラックバック (0)

2006年1月22日 (日)

Mac De Oracle Heterogeneous! #19

続きです。

日付、時間型がOracle側にはどのようにマッピングされるのか、どのような注意点があるのか検証してみる。

今日はPostgreSQL7.4.9の日付型、時間型について確認してみることにする

まず、PostgreSQL7.4.9のdate型、timestamp型、time型が、Oracleのdate型やtimestamp型とどのような違いがあるのかPostgreSQL上で確認してみることにする。

Oracleだとdate型とtimestamp型だけでなのでdate型が年月日だけ、time型が時間だけを格納するという点は覚えておくと良さそう。
timestamp型はOracleのtimestamp型と同じようなので特に注意する点はなさそうである。

重要なのは、Oracleのdate型やtimestamp型は日付や時間の妥当性チェックが厳しいというか、しっかりしているので日付として妥当でない文字列を受け入れることはないのだが、PostgreSQL7.4.9では、それを”調整して”受け入れてしまう点である。PostgreSQLに慣れている方なら驚くことではないと思うが、Oracleには慣れているが、PostgreSQLは初心者ということになると、かなり戸惑うことになる。(前回利用したdate_test表にtime型の列を追加した表を利用した。)

Last login: Fri Jan 20 22:41:46 on ttyp1
Welcome to Darwin!
pb17:˜ stargrass$ su - postgres
Password:
pb17:˜ postgres$ postmaster -S
pb17:˜ postgres$
pb17:˜ postgres$ psql -U scott postgresql749
Password:
Welcome to psql 7.4.9, the PostgreSQL interactive terminal.

Type: ¥copyright for distribution terms
¥h for help with SQL commands
¥? for help on internal slash commands
¥g or terminate with semicolon to execute query
¥q to quit

postgresql749=> alter table date_test add column r_time time;
ALTER TABLE
postgresql749=> commit;
COMMIT
postgresql749=> ¥d date_test;
Table "scott.date_test"
Column | Type | Modifiers
-------------+-----------------------------+-----------
r_date | date |
r_timestamp | timestamp without time zone |
r_time | time without time zone |

postgresql749=> select * from date_test;
r_date | r_timestamp | r_time
------------+---------------------+--------
1900-01-01 | |
2006-01-20 | |
| 1981-01-01 00:00:00 |
| 1990-12-01 00:00:00 |
(4 rows)

※Oracleならエラーになる。
postgresql749=> insert into date_test values(to_date('00000000','yyyymmdd'),null,null);
INSERT 25433 1

※Oracleならエラーになる。
postgresql749=> insert into date_test values(to_date('20061435','yyyymmdd'),null,null);
INSERT 25434 1

※Oracleならエラーになる。
postgresql749=> insert into date_test values(null,to_date('00000000','yyyymmdd'),null);
INSERT 25435 1

※Oracleならエラーになる。
postgresql749=> insert into date_test values(null,to_date('20062040','yyyymmdd'),null);
INSERT 25436 1

※Oracleならエラーになる。
postgresql749=> insert into date_test values(null,to_date('20060101479999','yyyymmddhh24miss'),null);
INSERT 25437 1

postgresql749=> insert into date_test values(null,null,'235959');
INSERT 25438 1

※Oracleならエラーになる。
postgresql749=> insert into date_test values(null,'2006-01-01 240000',null);
INSERT 25439 1

※Oracleならエラーになる。
postgresql749=> insert into date_test values(null,'2006-01-01 266060',null);
INSERT 25440 1


postgresql749=> insert into date_test values(current_date, current_timestamp, current_time);
INSERT 25441 1

※Oracleならエラーになる。
postgresql749=> insert into date_test values(null,to_timestamp('20063433284963','yyyymmddhh24miss'),null);
INSERT 25442 1
postgresql749=> commit;
COMMIT
postgresql749=> select * from date_test;
r_date | r_timestamp | r_time
---------------+----------------------------+-----------------
1900-01-01 | |
2006-01-20 | |
| 1981-01-01 00:00:00 |
| 1990-12-01 00:00:00 |
0001-01-01 BC | |
2007-03-07 | |
| 0001-01-01 00:00:00 BC |
| 2007-09-11 00:00:00 |
| 2006-01-01 00:00:00 |
| | 23:59:59
| 2006-01-02 00:00:00 |
| 2006-01-02 03:01:00 |
2006-01-22 | 2006-01-22 21:57:25.372923 | 21:57:25.372923
| 2008-11-07 04:50:03 |
(14 rows)

postgresql749=>
postgresql749=>

※空文字は指定できないようだ。(Oracleでは、空文字もNULLとして扱っているので Genneric Connectivity経由だとエラーにはならないかもしれない)
postgresql749=> insert into date_test values('',null,null);
ERROR: invalid input syntax for type date: ""
postgresql749=> rollback;
ROLLBACK

見ての通り、Oracleではエラーになるケースが含まれているのだがPostgreSQLではすべて正常に登録できてしまう。(しかも日付は調整された形で登録されてしまう。)
Oracleに慣れていると日付や時間に設定する文字列が日付や時間として妥当であるか厳密にチェックされているという事に慣れすぎているのでかなり驚く。
14月とか20月、63秒なんて存在しないからエラーにするという考え方のOracleと、14月と指定すれば1年と2ヶ月として”勝手に”日付を調整してくれるPostgreSQL、戸惑わないほうがおかしい。


上記は、to_date()や、to_timestamp()という関数の動きなのだが、以下のようにto_date()やto_timestamp()関数を利用しないで暗黙型変換?を利用すると挙動が異なるのでさらに戸惑う。
文字列のままで暗黙型変換だと、ちゃんと文字列が日付や時間として妥当な文字列かチェックしてくれるのである。いや〜結構ハマりそうだ。

postgresql749=> insert into date_test values('00000000',null,null);
ERROR: date/time field value out of range: "00000000"
HINT: Perhaps you need a different "datestyle" setting.
postgresql749=> insert into date_test values('20060101',null,null);
ERROR: current transaction is aborted, commands ignored until end of transaction block
postgresql749=> rollback;
ROLLBACK

postgresql749=> insert into date_test values('20060101',null,null);
INSERT 25443 1

postgresql749=> insert into date_test values('20061349',null,null);
ERROR: date/time field value out of range: "20061349"
HINT: Perhaps you need a different "datestyle" setting.
postgresql749=> insert into date_test values('2006-13-49',null,null);
ERROR: current transaction is aborted, commands ignored until end of transaction block
postgresql749=> select * from date_test;
ERROR: current transaction is aborted, commands ignored until end of transaction block
postgresql749=> rollback;
ROLLBACK

postgresql749=> insert into date_test values('2006-13-49',null,null);
ERROR: date/time field value out of range: "2006-13-49"
HINT: Perhaps you need a different "datestyle" setting.
postgresql749=> rollback;
ROLLBACK

postgresql749=>

ということで今日はここまで。
次回は、Genneric Connectivity経由でPostgreSQLに日付や時間を登録してみる。(どのようになるか楽しみである。)

---
都心では9センチの積雪とか言っていたけど、車にはもっと積もっているような気がする。

| | | コメント (0) | トラックバック (0)

2006年1月21日 (土)

Mac De Oracle Heterogeneous! #18

前回からのつづきです。

Generic Connectivity経由でMySQLにアクセスする際、日付型ではうまく検索できないというものだった。


データ型のマッピンングについて確認していこうと思うが、その前に、日付を条件に指定した検索ができないという問題を回避する方法を探してみることにした。

対象データを日付で絞り込もうとして where句に指定してみると正しく検索できない。

CORYDORAS> list
1 select
2 *
3 from
4 oracle_emp_mysql4026_win@oracle10g_win
5 where
6* "hiredate" >= to_date('19870101','yyyymmdd')
CORYDORAS> /

empno ename job mgr hiredate sal comm deptno
---------- -------------------- ------------------ ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80-12-17 800 20
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
7698 BLAKE MANAGER 7839 81-05-01 2850
7782 CLARK MANAGER 7839 81-06-09 2450 10
7788 SCOTT ANALYST 7566 87-04-19 3000 20
7839 KING PRESIDENT 81-11-17 5000 10
7844 TURNER SALESMAN 7698 81-09-08 1500 0 30
7876 ADAMS CLERK 7788 87-05-23 1100 20
7900 JAMES CLERK 7698 81-12-03 950 30
7902 FORD ANALYST 7566 81-12-03 3000 20
7934 MILLER CLERK 7782 82-01-23 1300 10

14行が選択されました。

経過: 00:00:00.10
CORYDORAS>

上記は、Windows XP Professionalに構築したMySQL4.0.26-nt.

その他のPlatformに構築したMySQLそれにPostgreSQLでも確認してみることにした。

PowerMac G5 Dual 2.7Ghz MacOSX Tiger Serverに構築した MySQL4.1.13a及び、PowerBookに構築した PostgreSQL7.4.9の日付型について試してみた。

今回は以下のような経路でアクセスした。

gencon_blog_img1


dump()関数で型を確認するのもいいがDATEかTIMESTAMPのいずれかなので以下のようなフォーマットを設定して区別しやすくしておく。
どちらの形式で表示されるかでマッピングされているのがdate型かtimestamp型なのかが判る。

CORYDORAS> alter session set nls_date_format = 'yyyy/mm/dd hh24:mi:ss';

セッションが変更されました。

CORYDORAS> alter session set nls_timestamp_format = 'yyyy/mm/dd hh24:mi:ss.ff';

セッションが変更されました。

CORYDORAS>

まずは、PowerMac G5 Dual 2.7Ghz MacOSX Tiger ServerのMySQL4.1.13aで検証した。以下のようなデータを用意。
r_datetime:datetime型、
r_date:date型、
r_timestamp:timestamp型
としてある。
マニュアルによればOracle側ではdate型にマップされることになっているようだ。(実際にはODBCドライバの実装に影響されるようだが。今回 Generic Connectivityで利用しているODBCドライバについてはこちらを参照してほしい。
全データを問い合わせてみると、全てNLS_DATE_FORMATに指定した書式で表示されているのでDATE型にマッピングされているのが判る。

CORYDORAS> 
CORYDORAS> select * from date_test_mysql4113a_mac_sv@oracle10g_win;

r_datetime r_date r_timestamp
------------------- ------------------- -------------------
1990/01/01 00:00:00 2006/01/20 23:04:22
2000/12/01 00:00:00 2006/01/20 23:04:35
1800/01/01 00:00:00 2006/01/20 23:04:51
1810/12/01 00:00:00 2006/01/20 23:05:06
2002/12/01 00:00:00
2006/01/20 23:05:33

6行が選択されました。

では、早速、MySQLのデータを日付を条件として検索してみる。DATE型にマッピングされているようなので、to_date()関数を利用してDATE型同士で検索してみるが1件もヒットしない。
CORYDORAS> select *
2 from
3 date_test_mysql4113a_mac_sv@oracle10g_win
4 where
5 "r_datetime" <= to_date('19910101','yyyymmdd');

レコードが選択されませんでした。

文字列として比較させると該当するデータが返される。どうやらDATE型ではうまく検索できないようである。
CORYDORAS> select * 
2 from
3 date_test_mysql4113a_mac_sv@oracle10g_win
4 where
5 "r_datetime" = '19900101';

r_datetime r_date r_timestamp
------------------- ------------------- -------------------
1990/01/01 00:00:00 2006/01/20 23:04:22

1行が選択されました。

暗黙型変換ではなく、to_char()により明示的に文字列に変換して比較してみると、やはり、正しい結果が得られた。
CORYDORAS> list
1 select *
2 from
3 date_test_mysql4113a_mac_sv@oracle10g_win
4 where
5* to_char("r_datetime",'yyyymmdd') >= '19900201'
CORYDORAS> /

r_datetime r_date r_timestamp
------------------- ------------------- -------------------
2000/12/01 00:00:00 2006/01/20 23:04:35

1行が選択されました。

MySQLのdate型、及び、timestamp型についても同様の結果だった。
CORYDORAS> select *
2 from
3 date_test_mysql4113a_mac_sv@oracle10g_win
4 where
5 "r_date" <= to_date('18100101','yyyymmdd');

レコードが選択されませんでした。

CORYDORAS> select *
2 from
3 date_test_mysql4113a_mac_sv@oracle10g_win
4 where
5 "r_date" <= '18100101';

r_datetime r_date r_timestamp
------------------- ------------------- -------------------
1800/01/01 00:00:00 2006/01/20 23:04:51

1行が選択されました。

CORYDORAS> select *
2 from
3 date_test_mysql4113a_mac_sv@oracle10g_win
4 where
5 "r_timestamp" <= to_date('20040101','yyyymmdd');

レコードが選択されませんでした。

CORYDORAS> list
1 select *
2 from
3 date_test_mysql4113a_mac_sv@oracle10g_win
4 where
5* "r_timestamp" <= '20040101'
CORYDORAS> /

r_datetime r_date r_timestamp
------------------- ------------------- -------------------
2002/12/01 00:00:00

1行が選択されました。

CORYDORAS>


MySQLでは、date型の検索に多少難ありという結果だったが、PostgreSQL7.4.9ではどうなるかも検証してみた。
PostgreSQL7.4.9では、r_dateをdate型、r_timestampをtimestamp型として定義した。問い合わせると、NLS_DATE_FORMATに指定した書式で表示されるので、これらの型もOracle側ではdate型にマッピングされていることが判る。

CORYDORAS> 
CORYDORAS> select * from date_test_postgresql749_mac@oracle10g_win;

r_date r_timestamp
------------------- -------------------
1900/01/01 00:00:00
2006/01/20 00:00:00
1981/01/01 00:00:00
1990/12/01 00:00:00

4行が選択されました。

MySQLの時と同様に、to_date()関数によるdate型での検索、文字列(暗黙型変換)、to_char()関数による明示型変換それぞれについて検証してみた。結果は、どの方法でも正しく検索できた。
Genneric Connectivity経由のアクセスでは、(Oracleデータベースに慣れている方なら)違和感無く利用できる可能性が高いPostgreSQLのほうが楽だと感じる場面が多いかもしれない。(私感)
CORYDORAS> select *
2 from
3 date_test_postgresql749_mac@oracle10g_win
4 where
5 "r_date" <= to_date('19900101','yyyymmdd');

r_date r_timestamp
------------------- -------------------
1900/01/01 00:00:00

1行が選択されました。

CORYDORAS> select *
2 from
3 date_test_postgresql749_mac@oracle10g_win
4 where
5 to_char("r_date",'yyyymmdd') <= '19900101';

r_date r_timestamp
------------------- -------------------
1900/01/01 00:00:00

1行が選択されました。

CORYDORAS> select *
2 from
3 date_test_postgresql749_mac@oracle10g_win
4 where
5 "r_date" <= '19900101';

r_date r_timestamp
------------------- -------------------
1900/01/01 00:00:00

1行が選択されました。

CORYDORAS> select *
2 from
3 date_test_postgresql749_mac@oracle10g_win
4 where
5 "r_timestamp" <= to_date('19820101');

r_date r_timestamp
------------------- -------------------
1981/01/01 00:00:00

1行が選択されました。

CORYDORAS> select *
2 from
3 date_test_postgresql749_mac@oracle10g_win
4 where
5 to_char("r_timestamp",'yyyymmdd') <= '19820101';

r_date r_timestamp
------------------- -------------------
1981/01/01 00:00:00

1行が選択されました。

CORYDORAS> select *
2 from
3 date_test_postgresql749_mac@oracle10g_win
4 where
5 "r_timestamp" <= '19810101';

r_date r_timestamp
------------------- -------------------
1981/01/01 00:00:00

1行が選択されました。

CORYDORAS>

まとめ。
日付型に関して、Generic Connectivity経由(ODBCドライバ経由)の検索では以下のような点に注意する必要がある。
(各ODBCドライバがアップデートされると挙動が異なる可能性が高いので、実際に利用する際には事前に実機調査されることをお勧めする)

MySQLの日付型をGeneric Connectivity経由で検索する場合には、文字型に変換して検索する。
PostgreSQLの日付型をGenneric Connecvitity経由で検索する場合には、日付型でも文字型でも検索できるので特に注意する点はない。(但し、パフォーマンス面を考えると日付型で検索したほうがよいのではないか?。未検証なので想像ですが。)

次回は、Generic Connectivity経由でリンクされているMySQL4.0.x,4.1.x及びPostgreSQL7.4.9の時間型などについて、Oracle側ではどの型にマッピングされ、どのような”癖”があるのか見てみることにする。

| | | コメント (0) | トラックバック (0)

2006年1月20日 (金)

Mac De Oracle Heterogeneous! #17

つづきです。今日は分析用関数編(すべてではないですが、幾つか試してみました。簡単なところだけですが。。)

gencon_blog_img1

以下のような emp表がMySQL上にあります。おなじみの表です。

CORYDORAS> select * from oracle_emp_mysql4026_win@oracle10g_win;

empno ename job mgr hiredate sal comm deptno
---------- -------------------- ------------------ ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80-12-17 800 20
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
7698 BLAKE MANAGER 7839 81-05-01 2850 30
7782 CLARK MANAGER 7839 81-06-09 2450 10
7788 SCOTT ANALYST 7566 87-04-19 3000 20
7839 KING PRESIDENT 81-11-17 5000 10
7844 TURNER SALESMAN 7698 81-09-08 1500 0 30
7876 ADAMS CLERK 7788 87-05-23 1100 20
7900 JAMES CLERK 7698 81-12-03 950 30
7902 FORD ANALYST 7566 81-12-03 3000 20
7934 MILLER CLERK 7782 82-01-23 1300 10

14行が選択されました。

CORYDORAS>

ランキング関数 RANK() 。 

CORYDORAS> 
CORYDORAS> list
1 select
2 rank() over (order by "sal") as rank,
3 "empno",
4 "ename",
5 "sal"
6 from
7* oracle_emp_mysql4026_win@oracle10g_win
CORYDORAS> /

RANK empno ename sal
---------- ---------- -------------------- ----------
1 7369 SMITH 800
2 7900 JAMES 950
3 7876 ADAMS 1100
4 7521 WARD 1250
4 7654 MARTIN 1250
6 7934 MILLER 1300
7 7844 TURNER 1500
8 7499 ALLEN 1600
9 7782 CLARK 2450
10 7698 BLAKE 2850
11 7566 JONES 2975
12 7788 SCOTT 3000
12 7902 FORD 3000
14 7839 KING 5000

14行が選択されました。

CORYDORAS>

同じくランキング関数 ROW_NUMBER()。

CORYDORAS> list
1 select
2 row_number() over (order by "empno") as row_number,
3 "empno",
4 "ename"
5 from
6* oracle_emp_mysql4026_win@oracle10g_win
CORYDORAS> /

ROW_NUMBER empno ename
---------- ---------- --------------------
1 7369 SMITH
2 7499 ALLEN
3 7521 WARD
4 7566 JONES
5 7654 MARTIN
6 7698 BLAKE
7 7782 CLARK
8 7788 SCOTT
9 7839 KING
10 7844 TURNER
11 7876 ADAMS
12 7900 JAMES
13 7902 FORD
14 7934 MILLER

14行が選択されました。

経過: 00:00:00.03
CORYDORAS>

集計ウィンドウ関数 FIRST_VALUE() 及び、LAST_VALUE()。

CORYDORAS> break on deptno on first_empno on last_empno skip page
CORYDORAS> list
1 select
2 first_value("empno")
3 over
4 (
5 partition by "deptno"
6 ) as first_empno,
7 last_value("empno")
8 over
9 (
10 partition by "deptno"
11 ) as last_empno,
12 "deptno",
13 "empno",
14 "ename"
15 from
16 oracle_emp_mysql4026_win@oracle10g_win
17 order by
18 "deptno",
19* "empno"
CORYDORAS> /

FIRST_EMPNO LAST_EMPNO deptno empno ename
----------- ---------- ---------- ---------- --------------------
7782 7934 10 7782 CLARK
7839 KING
7934 MILLER

FIRST_EMPNO LAST_EMPNO deptno empno ename
----------- ---------- ---------- ---------- --------------------
7369 7902 20 7369 SMITH
7566 JONES
7788 SCOTT
7876 ADAMS
7902 FORD

FIRST_EMPNO LAST_EMPNO deptno empno ename
----------- ---------- ---------- ---------- --------------------
7499 7900 30 7499 ALLEN
7521 WARD
7654 MARTIN
7698 BLAKE
7844 TURNER
7900 JAMES

14行が選択されました。

経過: 00:00:00.05
CORYDORAS>

ここまでは、分析用関数を簡単な構文で試していたのだが、その過程でちょっと気になることがあった。
Generic ConnectivityでリンクしているMySQLの日付型である。ODBC経由では MySQL側のDatetime型は、OracleのDATE型にマップされるようなのだが。。。

CORYDORAS> list
1 select
2 "ename",
3 to_char("hiredate", 'yyyy/mm/dd') as hiredate
4 from
5* oracle_emp_mysql4026_win@oracle10g_win
CORYDORAS> /

ename HIREDATE
-------------------- ----------
SMITH 1980/12/17
ALLEN 1981/02/20
WARD 1981/02/22
JONES 1981/04/02
MARTIN 1981/09/28
BLAKE 1981/05/01
CLARK 1981/06/09
SCOTT 1987/04/19
KING 1981/11/17
TURNER 1981/09/08
ADAMS 1987/05/23
JAMES 1981/12/03
FORD 1981/12/03
MILLER 1982/01/23

14行が選択されました。

経過: 00:00:00.05

対象データを日付で絞り込もうとして where句に指定してみると以下のようになってしまう。

CORYDORAS> list
1 select
2 *
3 from
4 oracle_emp_mysql4026_win@oracle10g_win
5 where
6* "hiredate" >= to_date('19870101','yyyymmdd')
CORYDORAS> /

empno ename job mgr hiredate sal comm deptno
---------- -------------------- ------------------ ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80-12-17 800 20
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
7698 BLAKE MANAGER 7839 81-05-01 2850
7782 CLARK MANAGER 7839 81-06-09 2450 10
7788 SCOTT ANALYST 7566 87-04-19 3000 20
7839 KING PRESIDENT 81-11-17 5000 10
7844 TURNER SALESMAN 7698 81-09-08 1500 0 30
7876 ADAMS CLERK 7788 87-05-23 1100 20
7900 JAMES CLERK 7698 81-12-03 950 30
7902 FORD ANALYST 7566 81-12-03 3000 20
7934 MILLER CLERK 7782 82-01-23 1300 10

14行が選択されました。

経過: 00:00:00.10
CORYDORAS>

あれ? 条件に合わないデータまで取得できちゃうの? なんで?
ということで、次回からは異機種データベースとのデータ型の相性というか、データ型マッピングについて確認してみようと思う。
Generic Connectivityの場合、間にあるODBCドライバの影響も受けるはずなのでどのようなことになりますか。。。

ちなみに、oracle10g R1 for MacOSX Server -> oracle10g R1 for Windows間で同じことをやってみると予想通り正しい結果が返る。

CORYDORAS> list
1* select * from emp@oracle10g_win
CORYDORAS> /

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------- ---------- ---------- ----------
7788 SCOTT ANALYST 7566 87-07-13 3000 20
7369 SMITH CLERK 7902 80-12-17 800 20
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
7698 BLAKE MANAGER 7839 81-05-01 2850 30
7782 CLARK MANAGER 7839 81-06-09 2450 10
7839 KING PRESIDENT 81-11-17 5000 10
7844 TURNER SALESMAN 7698 81-09-08 1500 0 30
7900 JAMES CLERK 7698 81-12-03 950 30
7902 FORD ANALYST 7566 81-12-03 3000 20
7934 MILLER CLERK 7782 82-01-23 1300 10
7876 ADAMS CLERK 7788 87-07-13 1100 20

14行が選択されました。

CORYDORAS> select *
2 from
3 emp@oracle10g_win
4 where
5 hiredate >= to_date('19870101','yyyymmdd');

EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO
---------- ---------- --------- ---------- -------- ---------- ---------- ----------
7788 SCOTT ANALYST 7566 87-07-13 3000 20
7876 ADAMS CLERK 7788 87-07-13 1100 20

CORYDORAS>

次回につづく。

| | | コメント (0) | トラックバック (0)

2006年1月19日 (木)

Mac De Oracle Heterogeneous! #16

さて、Generic Connectivityネタはまだ続きます。

今日はMySQLに Oracleではおなじみの scott.emp表を作り、階層問合せをやってみよう!

できるのか不安だが。。

Last login: Tue Jan 17 20:51:04 on console
Welcome to Darwin!
G5Server:˜ discus$ su - oracle
Password:
G5Server:˜ oracle$ sqlplus /nolog

SQL*Plus: Release 10.1.0.3.0 - Production on 火 1月 17 23:08:28 2006

Copyright (c) 1982, 2004, Oracle. All rights reserved.

> conn / as sysdba
アイドル・インスタンスに接続しました。
SYS> startup
ORACLEインスタンスが起動しました。

Total System Global Area 293601280 bytes
Fixed Size 778888 bytes
Variable Size 99360120 bytes
Database Buffers 192937984 bytes
Redo Buffers 524288 bytes
データベースがマウントされました。
データベースがオープンされました。
SYS>
SYS> conn corydoras
パスワードを入力してください:
接続されました。
CORYDORAS>
CORYDORAS>
CORYDORAS>
CORYDORAS>

Oracleではおなじみの、scottユーザにある emp表をMySQL4.0.26 Windowsに作成し、ORACLE_EMP_MYSQL4026_WIN というシノニムを Windows の Oracle10g R1に作成した。

アクセス経路は以下のようなイメージになる。
gencon_blog_img1


CORYDORAS> select synonym_name from user_synonyms@oracle10g_win;

SYNONYM_NAME
------------------------------
EMP_MYSQL4025_MAC
INNO_EMP_MYSQL4025_MAC
EMP_MYSQL4026_WIN
EMP_MYSQL4113A_MAC_SV
EMP_POSTGRESQL749_MAC
ORACLE_EMP_MYSQL4026_WIN

6行が選択されました。

CORYDORAS> select * from oracle_emp_mysql4026_win@oracle10g_win;

empno ename job mgr hiredate sal comm deptno
---------- -------------------- ------------------ ---------- -------- ---------- ---------- ----------
7369 SMITH CLERK 7902 80-12-17 800 20
7499 ALLEN SALESMAN 7698 81-02-20 1600 300 30
7521 WARD SALESMAN 7698 81-02-22 1250 500 30
7566 JONES MANAGER 7839 81-04-02 2975 20
7654 MARTIN SALESMAN 7698 81-09-28 1250 1400 30
7698 BLAKE MANAGER 7839 81-05-01 2850 30
7782 CLARK MANAGER 7839 81-06-09 2450 10
7788 SCOTT ANALYST 7566 87-04-19 3000 20
7839 KING PRESIDENT 81-11-17 5000 10
7844 TURNER SALESMAN 7698 81-09-08 1500 0 30
7876 ADAMS CLERK 7788 87-05-23 1100 20
7900 JAMES CLERK 7698 81-12-03 950 30
7902 FORD ANALYST 7566 81-12-03 3000 20
7934 MILLER CLERK 7782 82-01-23 1300 10

14行が選択されました。

CORYDORAS>

階層問合せを実行してみると・・・・。
CORYDORAS> list
1 select
2 level,
3 "empno",
4 "ename",
5 "mgr"
6 from
7 oracle_emp_mysql4026_win@oracle10g_win
8 start with
9 "mgr" is null
10 connect by
11* prior "empno" = "mgr"
CORYDORAS> /
select
*
行1でエラーが発生しました。:
ORA-02070: データベースMYSQL4026_WINはこのコンテキストではa connect by clauseをサポートしません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。

できないかな〜。
しばし考え込む、MySQL側で階層問い合わせができないのは当然なのだが、階層問い合せ自体ががスルーされないようにできないか。。。
お! ダミー表を用意して外部結合すれば・・・・・早速試してみる。
CORYDORAS> 
CORYDORAS> list
1 select
2 lpad(' ',(level-1)*2,' ')||"empno" as empno,
3 "ename",
4 "mgr",
5 connect_by_isleaf as "Is leaf?"
6 from
7 oracle_emp_mysql4026_win@oracle10g_win remote left outer join
8 (select -1 as dummy from dual) dummy
9 on remote."empno" = dummy.dummy
10 start with
11 "mgr" is null
12 connect by
13* prior "empno" = "mgr"
CORYDORAS> /

EMPNO ename mgr Is leaf?
-------------------- -------------------- ---------- ----------
7839 KING 0
7566 JONES 7839 0
7788 SCOTT 7566 0
7876 ADAMS 7788 1
7902 FORD 7566 0
7369 SMITH 7902 1
7698 BLAKE 7839 0
7499 ALLEN 7698 1
7521 WARD 7698 1
7654 MARTIN 7698 1
7844 TURNER 7698 1
7900 JAMES 7698 1
7782 CLARK 7839 0
7934 MILLER 7782 1

14行が選択されました。

経過: 00:00:00.11
CORYDORAS>
CORYDORAS>

ということで階層問い合せを実行することができた。
ついでに実行計画を取ってみると。
CORYDORAS> set autot trace
CORYDORAS> /

14行が選択されました。


実行計画
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=ALL_ROWS (Cost=55 Card=2000 Bytes=80000)
1 0 CONNECT BY (WITH FILTERING)
2 1 FILTER
3 2 COUNT
4 3 HASH JOIN (RIGHT OUTER) (Cost=55 Card=2000 Bytes=80000)
5 4 TABLE ACCESS (FULL) OF 'DUAL' (TABLE) (Cost=2 Card=1 Bytes=2)
6 4 REMOTE* (Cost=52 Card=2000 Bytes=76000) ORACLE10G_WIN
7 1 HASH JOIN
8 7 CONNECT BY PUMP
9 7 COUNT
10 9 HASH JOIN (RIGHT OUTER) (Cost=55 Card=2000 Bytes=80000)
11 10 TABLE ACCESS (FULL) OF 'DUAL' (TABLE) (Cost=2 Card=1 Bytes=2)
12 10 REMOTE* (Cost=52 Card=2000 Bytes=76000) ORACLE10G_WIN
13 1 COUNT
14 13 HASH JOIN (RIGHT OUTER) (Cost=55 Card=2000 Bytes=80000)
15 14 TABLE ACCESS (FULL) OF 'DUAL' (TABLE) (Cost=2 Card=1 Bytes=2)
16 14 REMOTE* (Cost=52 Card=2000 Bytes=76000) ORACLE10G_WIN


6 SERIAL_FROM_REMOTE SELECT "empno","ename","mgr" FROM "ORACLE_EMP_MYSQL4026_WIN" "REMOTE"
12 SERIAL_FROM_REMOTE SELECT "empno","ename","mgr" FROM "ORACLE_EMP_MYSQL4026_WIN" "REMOTE"
16 SERIAL_FROM_REMOTE SELECT "empno","ename","mgr" FROM "ORACLE_EMP_MYSQL4026_WIN" "REMOTE"


統計
----------------------------------------------------------
0 recursive calls
0 db block gets
15 consistent gets
0 physical reads
0 redo size
917 bytes sent via SQL*Net to client
512 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
5 sorts (memory)
0 sorts (disk)
14 rows processed

CORYDORAS>

巨大な表で重くなることも覚悟の上であればこの手法を用いればいろいろとできそうではある。

| | | コメント (0) | トラックバック (0)

2006年1月18日 (水)

Mac De Oracle Heterogeneous! #15

Generic Connectivityの続き。

前回はリモートトランザクションと分散トランザクションについて確認したが、分散クエリーはどうなのか? 念のため確認しておこう。

unionを利用してSQL1文で行ってみた。尚、表及びデータベースリンクはシノニムにしてあるので必要ないのだが、列名は引用識別子にする必要があるのでお忘れなく。

CORYDORAS> 
CORYDORAS> break on table_name skip page
CORYDORAS> select
2 'mysql4025_mac.emp' as table_name,
3 "empno",
4 "ename"
5 from
6 emp_mysql4025_mac@oracle10g_win
7 union all
8 select
9 'mysql4025_mac.inno_emp' as table_name,
10 "empno",
11 "ename"
12 from
13 inno_emp_mysql4025_mac@oracle10g_win
14 union all
15 select
16 'mysql4026_win.emp' as table_name,
17 "empno",
18 "ename"
19 from
20 emp_mysql4026_win@oracle10g_win
21 union all
22 select
23 'mysql4113a_mac_sv.emp' as table_name,
24 "empno",
25 "ename"
26 from
27 emp_mysql4113a_mac_sv@oracle10g_win
28 union all
29 select
30 'postgresql749_mac.emp' as table_name,
31 "empno",
32 "ename"
33 from
34 emp_postgresql749_mac@oracle10g_win
35 order by
36 1,2;

TABLE_NAME empno ename
------------------------------ ---------- ------------------------------
mysql4025_mac.emp 1 おらおら
2 ほげ
3 化けないよねー〜
4 can't rollback

TABLE_NAME empno ename
------------------------------ ---------- ------------------------------
mysql4025_mac.inno_emp 1 おらおら
2 ほげ
3 化けないよねー〜
4 -ー−〜˜

TABLE_NAME empno ename
------------------------------ ---------- ------------------------------
mysql4026_win.emp 1 おらおら
2 ほげ
3 化けないよな〜−
4 -ー−〜˜

TABLE_NAME empno ename
------------------------------ ---------- ------------------------------
mysql4113a_mac_sv.emp 1 ほげほげ
2 ほげ
3 化けないよな〜−
4 -ー−〜˜

TABLE_NAME empno ename
------------------------------ ---------- ------------------------------
postgresql749_mac.emp 1 ほげほげ
2 ほげ
3 化けないよね〜ー
4 -ー−〜˜

20行が選択されました。

経過: 00:00:00.63
CORYDORAS>

問題なくできそうだ。

| | | コメント (0) | トラックバック (0)

2006年1月17日 (火)

Mac De Oracle Heterogeneous! #14

前回にひきつづき、Generic Connectivityでのトランザクションに関連する挙動を見てみた。

Generic Connectivityでは分散トランザクションは行えない。
分散トランザクションを行おうとした場合、どのようなエラーが発生するか見てみることにする。

CORYDORAS> 
CORYDORAS> -- ここまでは、リモートトランザクションなので問題なく実行できる。
CORYDORAS> insert into emp_mysql4026_win@oracle10g_win values(5,'remote transaction');

1行が作成されました。

経過: 00:00:00.03
CORYDORAS>
CORYDORAS> -- 異なるデータベースを更新しようとしているのでここで分散トランザクションになる。
CORYDORAS> insert into emp_mysql4113a_mac_sv@oracle10g_win values(5,'distributed transaction');
insert into emp_mysql4113a_mac_sv@oracle10g_win values(5,'distributed transaction')
*
行1でエラーが発生しました。:
ORA-02047: 動作中の分散トランザクションは結合できません。
ORA-02063: 先行のエラー・メッセージを参照してくださいline(ORACLE10G_WIN)。


経過: 00:00:00.05
CORYDORAS> rollback;

ロールバックが完了しました。

経過: 00:00:00.05
CORYDORAS>

簡単なテストでトランザクションに関する挙動を見てきたが、リモートトランザクションとして実行するようにすれば特に面倒なことはなさそうである。
MySQLを利用する場合には、非トランザクションセーフなエンジンが表に利用されていないか確認しておいたほうがよい。

| | | コメント (0) | トラックバック (0)

2006年1月16日 (月)

Mac De Oracle Heterogeneous! #13

前回からのつづきです。

Generic Connectivityを利用し、異機種データベースのデータを更新するリモートトランザクションの挙動を確認する。


(Oracle Generic Connectivityではトランザクションに関する制限があり分散トランザクションは行えない。リモートトランザクションとローカルトランザクションだけが行えるということになる。)

PowerBook G4 MacOSX Tiger 10.4.3に構築したMySQL4.0.25のemp表は、エンジンにMyISAMを利用している。MyISAMは非トランザクションセーフである。つまり、トランザクションという概念が存在しない。commit文、rollback文がその意味をなさないのである。したがって、INSERT文、UPDATE文、DELETE文を発行すると即座に反映され、rollbackすることはできない。MySQLをリモートデータベースにしている場合にはアクセスする表がトランザクションセーフなエンジンを利用しているかを事前に確認しておいたほうがよいだろう。

CORYDORAS> 
CORYDORAS> insert into emp_mysql4025_mac@oracle10g_win values(4,'can''t rollback');

1行が作成されました。

経過: 00:00:00.68
CORYDORAS> select * from emp_mysql4025_mac@oracle10g_win;

empno ename
---------- ------------------------------
1 おらおら
2 ほげ
3 化けないよねー〜
4 can't rollback

経過: 00:00:00.03
CORYDORAS> rollback;

ロールバックが完了しました。

経過: 00:00:00.05
CORYDORAS> select * from emp_mysql4025_mac@oracle10g_win;

empno ename
---------- ------------------------------
1 おらおら
2 ほげ
3 化けないよねー〜
4 can't rollback

経過: 00:00:00.05
CORYDORAS>

さて、同じデータベースにInnoDBをエンジンとして作成した表はトランザクションセーフなのでrollbackすることができる。

CORYDORAS> 
CORYDORAS> insert into inno_emp_mysql4025_mac@oracle10g_win values(5,'rollback test');

1行が作成されました。

経過: 00:00:00.03
CORYDORAS> select * from inno_emp_mysql4025_mac@oracle10g_win;

empno ename
---------- ------------------------------
1 おらおら
2 ほげ
3 化けないよねー〜
4 -ー−〜˜
5 rollback test

経過: 00:00:00.43
CORYDORAS> rollback;

ロールバックが完了しました。

経過: 00:00:00.15
CORYDORAS> select * from inno_emp_mysql4025_mac@oracle10g_win;

empno ename
---------- ------------------------------
1 おらおら
2 ほげ
3 化けないよねー〜
4 -ー−〜˜

経過: 00:00:00.06
CORYDORAS>

PostgreSQLもトランザクションセーフなのでrollbackすることができる。

CORYDORAS> 
CORYDORAS> insert into emp_postgresql749_mac@oracle10g_win values(5,'rollback test');

1行が作成されました。

経過: 00:00:00.03
CORYDORAS> select * from emp_postgresql749_mac@oracle10g_win;

empno ename
---------- ------------------------------
1 ほげほげ
2 ほげ
3 化けないよね〜ー
4 -ー−〜˜
5 rollback test

経過: 00:00:00.03
CORYDORAS> rollback;

ロールバックが完了しました。

経過: 00:00:00.01
CORYDORAS> select * from emp_postgresql749_mac@oracle10g_win;

empno ename
---------- ------------------------------
1 ほげほげ
2 ほげ
3 化けないよね〜ー
4 -ー−〜˜

経過: 00:00:00.06
CORYDORAS>

次回は分散トランザクションを行おうとするとどのようなエラーが返されるか確認してみることにする。

| | | コメント (0) | トラックバック (0)

2006年1月15日 (日)

Mac De Oracle Heterogeneous! #12

使用しているフォントによっては判りにくいかもしれないが



半角ダッシュ  :"-"

カタカナ長音符号:"ー"

全角ダッシュ  :"−"

全角波線    :"〜"

チルダ(半角):"˜"



を 



Oracle10g R1 (MacOSX Tiger Server) ---database link + synonym --->

---> Oracle10g R1 (Windows) ---> database link + generic connectivity + odbc--->

---> MySQL or PostgreSQLの表



という流れで Oracle10g R1 (MacOSX Tiger Server)からデータを登録し、



Oracle10g R1 (MacOSX Tiger Server) <---

<--- database link + synonym <--- Oracle10g R1 (windows) <---

<--- database link + generic connectivity + odbc <--- MySQL or PostgreSQLの表



という流れで Oracle10g R1 (MacOSX Tiger Server)より問合せ、文字化けしないか確認してみた。

イメージはこんな感じ

gencon_blog_img1

CORYDORAS> insert into inno_emp_mysql4025_mac@oracle10g_win values(4,'-ー−〜˜');

1行が作成されました。

経過: 00:00:01.51
CORYDORAS> commit;

コミットが完了しました。

経過: 00:00:00.18
CORYDORAS> insert into emp_mysql4026_win@oracle10g_win values(4,'-ー−〜˜');

1行が作成されました。

経過: 00:00:00.05
CORYDORAS> commit;

コミットが完了しました。

経過: 00:00:00.05
CORYDORAS> insert into emp_mysql4113a_mac_sv@oracle10g_win values(4,'-ー−〜˜');

1行が作成されました。

経過: 00:00:00.10
CORYDORAS> commit;

コミットが完了しました。

経過: 00:00:00.16
CORYDORAS> insert into emp_postgresql749_mac@oracle10g_win values(4,'-ー−〜˜');

1行が作成されました。

経過: 00:00:00.05
CORYDORAS> commit;

コミットが完了しました。

経過: 00:00:00.63
CORYDORAS>
CORYDORAS> select * from inno_emp_mysql4025_mac@oracle10g_win;

empno ename
---------- ------------------------------
1 おらおら
2 ほげ
3 化けないよねー〜
4 -ー−〜˜

経過: 00:00:00.08
CORYDORAS> select * from emp_mysql4026_win@oracle10g_win;

empno ename
---------- ------------------------------
1 おらおら
2 ほげ
3 化けないよな〜−
4 -ー−〜˜

経過: 00:00:00.05
CORYDORAS> select * from emp_mysql4113a_mac_sv@oracle10g_win;

empno ename
---------- ------------------------------
1 ほげほげ
2 ほげ
3 化けないよな〜−
4 -ー−〜˜

経過: 00:00:00.06
CORYDORAS> select * from emp_postgresql749_mac@oracle10g_win;

empno ename
---------- ------------------------------
1 ほげほげ
2 ほげ
3 化けないよね〜ー
4 -ー−〜˜

経過: 00:00:00.05
CORYDORAS>

これらに関しては特に問題はでていないようである。
次回はこの環境でトランザクションはどうなるのか?  簡単に確認してみることにする。

| | | コメント (0) | トラックバック (0)

2006年1月14日 (土)

Mac De Oracle Heterogeneous! #11

前回からのつづきです。

やっと準備が完了といいますか、Windowsに作成したOracle10g R1 10.1.0.3.0からMySQLやPostgreSQLにアクセスできることまでは確認した。

さて、問題になるのは、どうやってPowerMac G5 Dual2.7Ghz Oracle10g R1 10.1.0.3.0 for MacOSX ServerからWindows版 Oracle10g R1の向うにあるMySQLやPostgreSQLにアクセスするのかという点である。

データベースリンクのネストなんて文法上許されてない訳だし。。。で思いついたのが。。。。

シノニムを利用するということだった。

では早速、Windows XP Professionalに作成したOracle10g R1 10.1.0.3.0に作ったデータベースリンクを利用して、各データベースに作成した emp表向けシノニムを作成する。

まずは作成済みデータベースリンクを確認しておく。

SQL*Plus: Release 10.1.0.2.0 - Production on 土 1月 14 17:22:34 2006

Copyright (c) 1982, 2004, Oracle. All rights reserved.
SQL> conn / as sysdba
接続されました。
SQL> select * from v$version;

BANNER
---------------------------------------------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.1.0.3.0 - Prod
PL/SQL Release 10.1.0.3.0 - Production
CORE 10.1.0.3.0 Production
TNS for 32-bit Windows: Version 10.1.0.3.0 - Production
NLSRTL Version 10.1.0.3.0 - Production

SQL>
SQL> conn discus
パスワードを入力してください: ************
接続されました。
SQL> select db_link from user_db_links;

DB_LINK
--------------------------------------------------------------------------------
MYSQL4025_MAC
MYSQL4026_WIN
MYSQL4113A_MAC_SV
POSTGRESQL749_MAC

この例では、プライベート・シノニムを作成した。シノニムは各データベースのemp表毎に作成した。
尚、MySQL4.0.25 に作成した emp表は MyISAM 、inno_emp表は、InnoDBその他のMySQLでは、emp表はInnoDBをエンジンとしている。

SQL> set linesize 132
SQL> col ename for a30
SQL>
SQL> -- PowerMac G4 MacOSX Tiger 10.4.3 MySQL4.0.25
SQL> create synonym emp_mysql4025_mac for "emp"@mysql4025_mac;

シノニムが作成されました。

SQL> -- PowerMac G4 MacOSX Tiger 10.4.3 MySQL4.0.25
SQL> create synonym inno_emp_mysql4025_mac for "inno_emp"@mysql4025_mac;

シノニムが作成されました。

SQL> -- AMD AthronMP Dual 2800+ Windows XP Professional
SQL> create synonym emp_mysql4026_win for "emp"@mysql4026_win;

シノニムが作成されました。

SQL> -- PowerMac G5 Dual 2.7Ghz MacOSX Tiger 10.4.3 Server MySQL4.1.13a
SQL> create synonym emp_mysql4113a_mac_sv for "emp"@mysql4113a_mac_sv;

シノニムが作成されました。

SQL> -- PowerMac G4 MacOSX Tiger 10.4.3 PostgreSQL7.4.9
SQL> create synonym emp_postgresql749_mac for "emp"@postgresql749_mac;

シノニムが作成されました。


SQL> select synonym_name from user_synonyms;

SYNONYM_NAME
----------------------------------------------------------
EMP_MYSQL4025_MAC
INNO_EMP_MYSQL4025_MAC
EMP_MYSQL4026_WIN
EMP_MYSQL4113A_MAC_SV
EMP_POSTGRESQL749_MAC

シノニムの確認も兼ねて各表に登録されているデータを確認しておく。

SQL> -- PowerMac G4 MacOSX Tiger 10.4.3 MySQL4.0.25
SQL> select * from emp_mysql4025_mac;

empno ename
---------- ------------------------------
1 おらおら
2 ほげ
3 化けないよねー〜

SQL> -- PowerMac G4 MacOSX Tiger 10.4.3 MySQL4.0.25
SQL> select * from inno_emp_mysql4025_mac;

empno ename
---------- ------------------------------
1 おらおら
2 ほげ
3 化けないよねー〜

SQL> -- AMD AthronMP Dual 2800+ Windows XP Professional
SQL> select * from emp_mysql4026_win;

empno ename
---------- ------------------------------
1 おらおら
2 ほげ
3 化けないよな〜−

SQL> -- PowerMac G5 Dual 2.7Ghz MacOSX Tiger 10.4.3 Server MySQL4.1.13a
SQL> select * from emp_mysql4113a_mac_sv;

empno ename
---------- ------------------------------
1 ほげほげ
2 ほげ
3 化けないよな〜−

SQL> -- PowerMac G4 MacOSX Tiger 10.4.3 PostgreSQL7.4.9
SQL> select * from emp_postgresql749_mac;

empno ename
---------- ------------------------------
1 ほげほげ
2 ほげ
3 化けないよね〜ー

SQL>

となっている。

今回の目的である Windows XP ProfessionalのOracle10g R1を踏み台にして、generic connectivityが組み込まれていない MacOSX版 Oracle10g R1からMySQLやPostgreSQLにアクセスするための準備はもう少しある。
それは、MacOSX Tiger 10.4.3 Serverに構築したOracle10g R1 10.1.0.3.0から Windows XP Professionalに構築したOracle10g R1 10.1.0.3.0にデータベースリンクを作成し、前述したシノニムにアクセスできるようにすることである。
以下は、MacOSX Tiger 10.4.3 ServerのOracle10g R1での作業である。まず tnsnames.oraを編集し、Windows XP Professionalに構築したOracle10g R1に接続できるようにする。接続文字列 CATFISHがそれである。

Last login: Sat Jan 14 16:36:47 on console
Welcome to Darwin!
G5Server:˜ discus$ su - oracle
Password:
G5Server:˜ oracle$ cat $ORACLE_HOME/network/admin/tnsnames.ora
# tnsnames.ora Network Configuration File: /Volumes/Discus/4oracle/oracle/u01/app/oracle/product/10.1.0/tigerx/network/admin/tnsnames.ora
# Generated by Oracle configuration tools.

XTIGER =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.19)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = xtiger)
)
)

CATFISH =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.2)(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = catfish)
)
)

次に CATFISH にアクセスするためのデータベースリンクを作成する。
テスト用にユーザ(corydoras)を新たに作成してプライベートデータベースリンク(oracle10g_win)を作成した。

G5Server:˜ oracle$ 
G5Server:˜ oracle$
G5Server:˜ oracle$ sqlplus /nolog

SQL*Plus: Release 10.1.0.3.0 - Production on 土 1月 14 16:48:04 2006

Copyright (c) 1982, 2004, Oracle. All rights reserved.

> conn / as sysdba
アイドル・インスタンスに接続しました。
SYS> startup
ORACLEインスタンスが起動しました。

Total System Global Area 293601280 bytes
Fixed Size 778888 bytes
Variable Size 99360120 bytes
Database Buffers 192937984 bytes
Redo Buffers 524288 bytes
データベースがマウントされました。
データベースがオープンされました。
SYS>
SYS> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.1.0.3.0 - Prod
PL/SQL Release 10.1.0.3.0 - Production
CORE 10.1.0.3.0 Production
TNS for MacOS X Server: Version 10.1.0.3.0 - Production
NLSRTL Version 10.1.0.3.0 - Production

SYS>
SYS>
SYS>
SYS> create user corydoras identified by xxxxx
2 default tablespace users
3 temporary tablespace temp
4 quota unlimited on users;

ユーザーが作成されました。

SYS> grant
2 connect,
3 create synonym,
4 create database link,
5 create table
6 to
7 corydoras;

権限付与が成功しました。

SYS> conn corydoras
パスワードを入力してください:
接続されました。
CORYDORAS>
CORYDORAS> create database link oracle10g_win
2 connect to discus identified by xxxxx using 'catfish';

データベース・リンクが作成されました。

作成したデータベースリンクでアクセスできるか確認を兼ねて、Windows XP Professional の Oracle10gにある discusユーザの user_db_linksビュー及び user_synonymsビューを問い合わせてみる。

CORYDORAS> select db_link from user_db_links@oracle10g_win;

DB_LINK
--------------------------------------------------------------------------------
MYSQL4025_MAC
MYSQL4026_WIN
MYSQL4113A_MAC_SV
POSTGRESQL749_MAC

CORYDORAS>
CORYDORAS> set linesize 132
CORYDORAS> col db_link for a40
CORYDORAS> select
2 synonym_name,
3 table_name,
4 db_link
5 from user_synonyms@oracle10g_win;

SYNONYM_NAME TABLE_NAME DB_LINK
------------------------------ ------------------------------ ----------------------------------------
EMP_MYSQL4025_MAC emp MYSQL4025_MAC
INNO_EMP_MYSQL4025_MAC inno_emp MYSQL4025_MAC
EMP_MYSQL4026_WIN emp MYSQL4026_WIN
EMP_MYSQL4113A_MAC_SV emp MYSQL4113A_MAC_SV
EMP_POSTGRESQL749_MAC emp POSTGRESQL749_MAC

CORYDORAS>

さて、いよいよ Windows XP Professional に構築した Oracle10g R1 の generic connectivityを経由して、generic connetivityのない MacOSX Server版 Oracle10g R1 から MySQLやPostgreSQLの表を問い合わせてみる! どうなるか。。。。

CORYDORAS> set timi on
CORYDORAS> col ename for a30
CORYDORAS>
CORYDORAS> select * from emp_mysql4025_mac@oracle10g_win;

empno ename
---------- ------------------------------
1 おらおら
2 ほげ
3 化けないよねー〜

経過: 00:00:09.48
CORYDORAS> select * from inno_emp_mysql4025_mac@oracle10g_win;

empno ename
---------- ------------------------------
1 おらおら
2 ほげ
3 化けないよねー〜

経過: 00:00:01.28
CORYDORAS> select * from emp_mysql4026_win@oracle10g_win;

empno ename
---------- ------------------------------
1 おらおら
2 ほげ
3 化けないよな〜−

経過: 00:00:00.70
CORYDORAS> select * from emp_mysql4113a_mac_sv@oracle10g_win;

empno ename
---------- ------------------------------
1 ほげほげ
2 ほげ
3 化けないよな〜−

経過: 00:00:01.11
CORYDORAS> select * from emp_postgresql749_mac@oracle10g_win;

empno ename
---------- ------------------------------
1 ほげほげ
2 ほげ
3 化けないよね〜ー

経過: 00:00:08.45
CORYDORAS>

やりました〜〜〜〜〜!。 ふ〜。ひとまず、狙い通りの結果がで、よかったよかった。これでこのネタで、もう少し引っ張れそうな気が。。しかし、Oracle10g R2のPreview Releaseがされたら、すぐにそちらで遊びだすかもしれない。噂通り早めにIntel版 Macもリリースされたことだし。

| | | コメント (0) | トラックバック (0)

2006年1月13日 (金)

Mac De Oracle Heterogeneous! #10

前回まででWindowsに作成したOracle10g R1をMySQL及び、PostgreSQLをアクセスするHUBにするための構成は完了した。

リスナーの構成を反映させるためリスナーの再起動を行った。まずは再起動したリスナーの状態を確認。
各サービスのインスタンスがリストされているのが判るだろうか?

C:¥Documents and Settings¥Administrator>
C:¥Documents and Settings¥Administrator>lsnrctl status

LSNRCTL for 32-bit Windows: Version 10.1.0.2.0 - Production on 09-1月 -2006 15:02:20

Copyright (c) 1991, 2004, Oracle. All rights reserved.

(DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC)))に接続中
リスナーのステータス
------------------------
別名 LISTENER
バージョン TNSLSNR for 32-bit Windows: Version 10.1.0.2.0 - Production
開始日 09-1月 -2006 15:01:33
稼働時間 0 日 0 時間 0 分 51 秒
トレース・レベル off
セキュリティ ON: Local OS Authentication
SNMP OFF
パラメータ・ファイル E:¥oracle¥product¥10.1.0¥catfish¥network¥admin¥listener.ora
ログ・ファイル E:¥oracle¥product¥10.1.0¥catfish¥network¥log¥listener.log
リスニング・エンドポイントのサマリー...
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(PIPENAME=¥¥.¥pipe¥EXTPROCipc)))
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=192.168.1.2)(PORT=1521)))
サービスのサマリー...
サービス"PLSExtProc"には、1件のインスタンスがあります。
インスタンス"PLSExtProc"、状態UNKNOWNには、このサービスに対する1件のハンドラがあります...
サービス"PostgreSQL749"には、1件のインスタンスがあります。
インスタンス"PostgreSQL749"、状態UNKNOWNには、このサービスに対する1件のハンドラがあります...
サービス"mysql4025_MacOSX"には、1件のインスタンスがあります。
インスタンス"mysql4025_MacOSX"、状態UNKNOWNには、このサービスに対する1件のハンドラがあります...
サービス"mysqldb4026_windows"には、1件のインスタンスがあります。
インスタンス"mysqldb4026_windows"、状態UNKNOWNには、このサービスに対する1件のハンドラがあります...
サービス"mysqldb4113a_MacOSX_Server"には、1件のインスタンスがあります。
インスタンス"mysqldb4113a_MacOSX_Server"、状態UNKNOWNには、このサービスに対する1件のハンドラがあります...
コマンドは正常に終了しました。

C:¥Documents and Settings¥Administrator>




データベースリンクを作成してリモートデータベースにアクセスするのだが、今回はプライベートデータベースリンクを作成することにし、新たにユーザを作成した。
SQL> conn / as sysdba
SQL> create user discus identified by xxxxxxxx
2 default tablespace users
3 temporary tablespace temp
4 quota unlimited on users;

ユーザーが作成されました。

SQL> grant
2 connect,
3 create synonym,
4 create database link,
5 create table
6 to
7 discus;

権限付与が成功しました。




データベースリンクを作成する前に確認しておくことが1点ある。global_names=falseであることを確認しておくことである。
SQL> conn / as sysdba
SQL> show parameter global_names

NAME TYPE VALUE
------------ -------------- ---------------
global_names boolean FALSE
SQL>

もし、trueならば、falseに変更しておく。動的パラメータなので
SQL> alter system set global_names = false scope=both;

システムが変更されました。

SQL>
で変更可能である。
尚、これはspfile の利用を前提に記述している。pfileを利用している場合には、init_<SID>.oraファイルを変更し、再起動が必要である。(ただし、scope=memoryとしてalter system文を発行し、後日再起動しても同じである。)

さていよいよ、プライベートデータベースリンクを作成し、MySQL及び、PostgreSQLにアクセスしてみる。
これがうまくいけば、Windowsに作成したOracle10g R1がMySQL及び、PostgreSQLのデータを纏めるHUBとしての機能を持つ事になる。MySQLやPostgreSQLにアクセスするデータベースリンクの作成で大切な点は、ユーザ名及び、パスワードを "" で囲むことである。ちなみに、MySQLやPostgreSQLにあるオブジェクトも""で囲む必要がる。ようするにユーザ名やパスワードは大文字小文字を区別させる必要があり、オブジェクト名は小文字で参照させるということを意味している。

Note:
"で囲まれた部分を 引用識別子(quoted identifier)と呼ぶ。逆に囲まれていない場合は非引用識別子(nonquoted identifier)と呼ぶ。

SQL> conn discus
パスワードを入力してください: ************
接続されました。
SQL>
SQL>
SQL>
SQL> create database link mysql4026_win
2 connect to "catfish" identified by "xxxxxxx" using 'MYSQL4026_WIN';

データベース・リンクが作成されました。

SQL> select * from "emp"@mysql4026_win;

empno ename
---------- ------------------------------
1 おらおら
2 ほげ
3 化けないよな〜ー

SQL>
SQL> create database link mysql4113a_mac_sv
2 connect to "discus" identified by "xxxxxxxxx" using 'MYSQL4113A_MAC_SV';

データベース・リンクが作成されました。

SQL> select * from "emp"@mysql4113a_mac_sv;

empno ename
---------- ------------------------------
1 ほげほげ
2 ほげ
3 化けないよな〜ー

SQL>
SQL> create database link mysql4025_mac
2 connect to "jobs" identified by "xxxxxx" using 'MYSQL4025_MAC';

データベース・リンクが作成されました。

SQL> select * from "emp"@mysql4025_mac;

empno ename
---------- ------------------------------
1 おらおら
2 ほげ
3 化けないよねー〜

SQL>
SQL> create database link postgresql749_mac
2 connect to "scott" identified by "xxxxxxx" using 'POSTGRESQL749_MAC';

データベース・リンクが作成されました。

SQL> select * from "emp"@postgresql749_mac;

empno ename
---------- ------------------------------
1 ほげほげ
2 ほげ
3 化けないよね〜ー

SQL>

次回はMacOSX Tiger 10.4.3に作成したOracle10g R1から、Windows XP Professionalに作成したOracle10g R1にデータベースリンクを経由してアクセスしてみる。
WindowsのOracle10g R1を踏み台とし、MacOSX Tiger Server 10.4.3のOracle10gから間接的にMySQL及び、PostgreSQLにアクセスできることを確認する。

| | | コメント (0) | トラックバック (0)

2006年1月12日 (木)

Mac De Oracle Heterogeneous! #9

前回のつづきです。

さて、Generic connectivityエージェントの構成も終了し、残すところあと僅か。Oracle Net Serviceの構成を行う。

Oracle Net Service構成ファイルは、%ORACLE_HOME%¥network¥admin以下にある。Oracleに慣れた方なら見慣れた構成ファイル。listener.ora及び、tnsnames.oraファイルである。

listener.oraファイルの内容は以下の通り。
大事な点は SID_NAMEパラメータに データソース名を設定するということと、PROGRAMパラメータには、hsodbc を設定する点である。

# listener.ora Network Configuration File: E:¥oracle¥product¥10.1.0¥catfish¥network¥admin¥listener.ora
# Generated by Oracle configuration tools.

SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(SID_NAME = PLSExtProc)
(ORACLE_HOME = E:¥oracle¥product¥10.1.0¥catfish)
(PROGRAM = extproc)
)
(SID_DESC =
(SID_NAME = mysql4025_MacOSX)
(PROGRAM = hsodbc)
(ORACLE_HOME = E:¥oracle¥product¥10.1.0¥catfish)
)
(SID_DESC =
(SID_NAME = mysqldb4026_windows)
(PROGRAM = hsodbc)
(ORACLE_HOME = E:¥oracle¥product¥10.1.0¥catfish)
)
(SID_DESC =
(SID_NAME = mysqldb4113a_MacOSX_Server)
(PROGRAM = hsodbc)
(ORACLE_HOME = E:¥oracle¥product¥10.1.0¥catfish)
)
(SID_DESC =
(SID_NAME = PostgreSQL749)
(PROGRAM = hsodbc)
(ORACLE_HOME = E:¥oracle¥product¥10.1.0¥catfish)
)
)

LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC))
)
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.2)(PORT = 1521))
)
)
)




tnsnames.oraファイルの内容は以下の通り。
接続文字列は判りやすい名称にすればよいが、SIDパラメータにデータソース名を指定する点がポイント。HS=OK というお約束の設定も忘れずに。

# tnsnames.ora Network Configuration File: E:¥oracle¥product¥10.1.0¥catfish¥network¥admin¥tnsnames.ora
# Generated by Oracle configuration tools.

CATFISH =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.2)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = catfish)
)
)

MYSQL4025_MAC =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.2)(PORT = 1521))
(CONNECT_DATA =
(SID = mysql4025_MacOSX)
)
(HS=OK)
)

MYSQL4026_WIN =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.2)(PORT = 1521))
(CONNECT_DATA =
(SID = mysqldb4026_windows)
)
(HS=OK)
)

MYSQL4113A_MAC_SV =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.2)(PORT = 1521))
(CONNECT_DATA =
(SID = mysqldb4113a_MacOSX_Server)
)
(HS=OK)
)

POSTGRESQL749_MAC =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.2)(PORT = 1521))
(CONNECT_DATA =
(SID = PostgreSQL749)
)
(HS=OK)
)

EXTPROC_CONNECTION_DATA =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC))
)
(CONNECT_DATA =
(SID = PLSExtProc)
(PRESENTATION = RO)
)
)

ここまでで generic connectivityエージェント構成ファイル及び、Oracle Net Serviceの構成が完了した。
さて、次回は、データベースリンクを作成し、MySQLやPostgreSQLにアクセスする。

| | | コメント (0) | トラックバック (0)

2006年1月11日 (水)

Mac De Oracle Heterogeneous! #8

前回のつづきです。

Windows XP Professionalに作成したOracle10g R1をMySQL及び、PostgreSQLのデータを統合するためのHUBとして機能させるためOracle Generic Connectivityエージェントの構成を行う。

Generic Connectivityエージェントの構成ファイルは、%ORACLE_HOME%¥hs¥admin以下に作成する。尚、同ディレクトリにhsodbc.oraという構成ファイルのサンプルがあるので、そのファイルをコピーすれば簡単に作成することができる。また、構成ファイルはODBCデータソース毎に作成する必要がある。
今回は以下のようなに4ファイルを作成した。(尚、unix系では、$ORACLE_HOME/hs/admin以下に構成ファイルを作成する必要がある)

hs


構成ファイルのファイル名は以下の形式にする必要がある。(DSNはデータソース名である)


init<DSN>.ora

今回作成したシステムデータソース名は

mysql4025_MacOSX mysqldb4026_windows mysqldb4113a_MacOSX_Server PostgreSQL749

であるから、構成ファイル名は以下のようになる。

initmysql4025_MacOSX.ora initmysqldb4026_windows.ora initmysqldb4113a_MacOSX_Server.ora initPostgreSQL749.ora

上からそれぞれ、

PowerBook G4 1Ghz 17inch MacOSX Tiger 10.4.3 の MySQL4.0.25 Standard
AMD AthronMP Dual 2800+ Windows XP Professional の MySQL4.0.26-nt Standard
PowerMac G5 Dual 2.7Ghz MacOSX Tiger 10.4.3 Server の MySQL4.1.13a Standard
PowerBook G4 1Ghz 17inch MacOSX Tiger 10.4.3 の PostgreSQL 7.4.9
向けGeneric Connectivity構成ファイルである。

今回の構成ファイルは以下のような内容になっている。(MySQL向け構成ファイルの内容はデータソース名以外同じ)
尚、構成ファイルの各パラメータについては、マニュアル Oracle10g Heterogeneous Connectivity 管理者ガイド参照のこと。

initmysql4025_MacOSX.oraの内容。


# This is a sample agent init file that contains the HS parameters that are
# needed for an ODBC Agent.

#
# HS init parameters
#
HS_FDS_CONNECT_INFO = mysql4025_MacOSX
HS_FDS_TRACE_LEVEL = off
HS_FDS_SHAREABLE_NAME = C:¥WINNT¥system32¥myodbc3.dll

#
# Environment variables required for the non-Oracle system
#
#set <envvar>=<value>




initPostgreSQL749.oraの内容。
PostgreSQL Client 向けにAUTOCOMMITはoffに設定してある。


# This is a sample agent init file that contains the HS parameters that are
# needed for an ODBC Agent.

#
# HS init parameters
#
HS_FDS_CONNECT_INFO = PostgreSQL749
HS_FDS_TRACE_LEVEL = off
HS_FDS_SHAREABLE_NAME = C:¥WINNT¥system32¥psqlodbc.dll

#
# Environment variables required for the non-Oracle system
#
#set <envvar>=<value>
set AUTOCOMMIT=off

これで generic connectivityエージェント構成ファイルができた。続いて Oracle Net Service の構成を行う。

| | | コメント (0) | トラックバック (0)

2006年1月10日 (火)

Mac De Oracle Heterogeneous! #7

前回からのつづきです。

MacOSX Tiger Server 10.4.3 : PowerMac G5 Dual 2.7GhzのMySQL4.1.13aと


MacOSX Tiger 10.4.3 : PowerBook G4 1Ghz 17inchのPostgreSQL7.4.9のデータソース設定と接続テストをFlashで。

MacOSX Tiger Server 10.4.3 PowerMac G5 Dual 2.7GhzのMySQL4.1.13a向けデータソース構成と接続テスト。











MacOSX Tiger 10.4.3 PowerBook G4 1Ghz 17inchのPostgreSQL7.4.9向けデータソース構成と接続テスト。psqlODBCには、MyODBCのような接続テスト機能がないのでMS Accessによる接続テストを行った。








次回は、Generic Connectivityの構成を行う。

| | | コメント (0) | トラックバック (0)

2006年1月 9日 (月)

Mac De Oracle Heterogeneous! #6

前回からのつづきです。

MySQL4.0.25 (MacOSX Tiger : PowerBook G4 1Ghz)及び、MySQL4.0.26-nt (Windows XP Professional)のODBCデータソース構成及び接続テストをFlashで。

MacOSX Tiger : PowerBook G4 1Ghz 17inchのMySQL4.0.25向けシステムデータソース構成と接続テスト。









Windows XP Professional (localhost) にあるMySQL4.0.26-nt向けシステムデータソース構成と接続テスト。







次回、MySQL4.1.13aとPostgreSQL7.4.9のデータソース構成につづく。

| | | コメント (0) | トラックバック (0)

2006年1月 8日 (日)

Mac De Oracle Heterogeneous! #5

前回のつづき。

Windows XP Professional(MySQL及び、PostgreSQLにGeneric Connectivityを経由してアクセスするためにOracle10g R1がインストールしてある)に各データベースのODBCドライバをインストールし、システムデータソースを作成した。

MacOSX 10.4.3 Tiger に構築したPostgreSQL 7.4.9へWindowsからアクセスするためのODBCドライバは、以下URLからダウンロードした。(psqlODBC3.0 Ver.07-03-0208)
http://cre-ent.skcapi.co.jp/〜saito/pgadmin/lib/PGODBC30_07030208.exe

ダウンロードページは以下 http://cre-ent.skcapi.co.jp/〜saito/pgadmin/download

MacOSX 10.4.3 Tiger Serverに構築したMySQL 4.1.13a、MacOSX 10.4.3 Tigerに構築したMySQL 4.0.25、及び、Windows XP Professionalに構築したMySQL 4.0.26-nt の各MySQLへWindowsからアクセスするためのODBCドライバは、以下URLからダウンロードした。(MySQL Connector/ODBC ver 3.51.12)
http://dev.mysql.com/get/Downloads/MyODBC3/mysql-connector-odbc-3.51.12-win32.zip/from/pick

尚、MySQLも PostgreSQLもデフォルトではリモート接続が遮断されているので、MySQLならgrant文でユーザを作成する際にアクセスを許可するホスト又はIP addressを指定しPostgreSQLであれば、/usr/local/pgsql/data/pg_hba.confでリモートアクセスを許可するユーザとip addressを設定する必要がる。
MacOSX Serverに搭載されたMySQL4.1.13aでは、grant文の他に MySQL Adminでリモート接続を許可する必要がある。MySQLのgrant文及び、MacOSX ServerのMySQL Adminでのリモート接続許可については以前の記事を参照してもらいたい。

PostgreSQL7.4.9のpg_hba.confの内容。
(今回は、192.168.1.2からのリモート接続を許可するよう設定した。ドライバのリリースやプラットフォームの違いにより、認証用メドッドが利用できないものもあるのでその都度接続できるか確認したほうがよいだろう。ちなみに、Redhatではmd5もpasswordもエラーとなったので trust に設定したこともあった。Linux上でのunixODBC及び、各ODBCドライバを利用したGeneric Connectivityについてはいずれ公開する予定である。)


# PostgreSQL Client Authentication Configuration File
# ===================================================
#
# Refer to the PostgreSQL Administrator's Guide, chapter "Client
# Authentication" for a complete description. A short synopsis
# follows.
#
# This file controls: which hosts are allowed to connect, how clients
# are authenticated, which PostgreSQL user names they can use, which
# databases they can access. Records take one of seven forms:
#
# local DATABASE USER METHOD [OPTION]
# host DATABASE USER IP-ADDRESS IP-MASK METHOD [OPTION]
# hostssl DATABASE USER IP-ADDRESS IP-MASK METHOD [OPTION]
# hostnossl DATABASE USER IP-ADDRESS IP-MASK METHOD [OPTION]
# host DATABASE USER IP-ADDRESS/CIDR-MASK METHOD [OPTION]
# hostssl DATABASE USER IP-ADDRESS/CIDR-MASK METHOD [OPTION]
# hostnossl DATABASE USER IP-ADDRESS/CIDR-MASK METHOD [OPTION]
#
# (The uppercase quantities should be replaced by actual values.)
# The first field is the connection type: "local" is a Unix-domain socket,
# "host" is either a plain or SSL-encrypted TCP/IP socket, "hostssl" is an
# SSL-encrypted TCP/IP socket, and "hostnossl" is a plain TCP/IP socket.
# DATABASE can be "all", "sameuser", "samegroup", a database name (or
# a comma-separated list thereof), or a file name prefixed with "@".
# USER can be "all", an actual user name or a group name prefixed with
# "+" or a list containing either. IP-ADDRESS and IP-MASK specify the
# set of hosts the record matches. CIDR-MASK is an integer between 0
# and 32 (IPv6) or 128(IPv6) inclusive, that specifies the number of
# significant bits in the mask, so an IPv4 CIDR-MASK of 8 is equivalent
# to an IP-MASK of 255.0.0.0, and an IPv6 CIDR-MASK of 64 is equivalent
# to an IP-MASK of ffff:ffff:ffff:ffff::. METHOD can be "trust", "reject",
# "md5", "crypt", "password", "krb4", "krb5", "ident", or "pam". Note
# that "password" uses clear-text passwords; "md5" is preferred for
# encrypted passwords. OPTION is the ident map or the name of the PAM
# service.
#
# This file is read on server startup and when the postmaster receives
# a SIGHUP signal. If you edit the file on a running system, you have
# to SIGHUP the postmaster for the changes to take effect, or use
# "pg_ctl reload".

# Put your actual configuration here
# ----------------------------------
#
# CAUTION: The default configuration allows any local user to connect
# using any PostgreSQL user name, including the superuser, over either
# Unix-domain sockets or TCP/IP. If you are on a multiple-user
# machine, the default configuration is probably too liberal for you.
# Change it to use something other than "trust" authentication.
#
# If you want to allow non-local connections, you need to add more
# "host" records. Also, remember TCP/IP connections are only enabled
# if you enable "tcpip_socket" in postgresql.conf.

# TYPE DATABASE USER IP-ADDRESS IP-MASK METHOD

local all postgres trust
local all all md5
# IPv4-style local connections:
host all postgres 127.0.0.1 255.255.255.255 trust
host all all 127.0.0.1 255.255.255.255 md5
host all all 192.168.1.2 255.255.255.255 password
# IPv6-style local connections:
host all postgres ::1 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff trust

Windows XP Professionalに前述のMyODBCドライバ及び、PostgreSQLドライバをインストールした後状態。


odbc1

odbc2

odbc3


作成したデータソース(システムDSN)は以下の通り。


odbc4

各データソースの設定内容のはFlashのサイズが大きいのでそれぞれ別記事としてアップする予定なので本日はここまで。

| | | コメント (0) | トラックバック (0)

2006年1月 4日 (水)

Mac De Oracle Heterogeneous! #4

あけましておめでとうございます。

新年第一弾は、Oracle Heterogeneous Service - Generic Connectivityの続きから。

Windows XP ProへのMySQL 4.0.26-ntのインストールは省略する。googleなどで検索すれば多数のあるのでそれらで確認してほしい。また、MacOSX Tiger Serverには、MySQL4.1がインストール済みなのでこれまた省略。ということでメモ程度に表の内容や構成ファイルの設定内容などを記述しておく。

まずは、Windows XP ProfessionalにインストールしたMySQL 4.0.26-ntの構成ファイルと表に関することから。

LinuxやMacOSXでは、my.cnfにデフォルトキャラクタセットを設定していたが、Windowsでは、my.iniを利用して作成するデータベース(mysqldb)のデフォルトキャラクタセットを設定した。(ちなみに、my.cnfを利用することもできる。)

my.iniの場所と内容は以下の通り。

C:¥WINNT¥my.ini

#This File was made using the WinMySQLAdmin 1.4 Tool
#2005/11/25 22:29:45

#Uncomment or Add only the keys that you know how works.
#Read the MySQL Manual for instructions

[mysqld]
default-character-set=sjis
basedir=F:/msql
bind-address=localhost
datadir=F:/msql/data
#language=F:¥msql¥share¥japanese
#slow query log#=
#tmpdir#=
port=3306
#set-variable=key_buffer=16M

[WinMySQLadmin]
Server=F:/msql/bin/mysqld.exe
user=root
password=XXXXXXX

[mysqldb]
default-character-set=sjis


以下、MacOSXのMySQLの場合と同じ手順で作成したデータベースにemp表(エンジンはInnoDB)を作成しデータを登録しておく。

C:¥Documents and Settings¥Administrator>mysql -u catfish -p mysqldb
Enter password: *******
Welcome to the MySQL monitor. Commands end with ; or ¥g.
Your MySQL connection id is 5 to server version: 4.0.26-nt
Type 'help;' or '¥h' for help. Type '¥c' to clear the buffer.
mysql> select * from emp;
+-------+------------------+
| empno | ename |
+-------+------------------+
| 1 | おらおら |
| 2 | ほげ   |
| 3 | 化けないよね〜ー |
+-------+------------------+
3 rows in set (0.01 sec)

mysql>



お次は、
MacOSX 10.4.3 Tiger Serverの MySQL4.1.13a に作成したデータベースにemp表(エンジンはInnoDB)を作成しデータを登録しておく。作成したデータベース名は mysqldb41。)
mysql> use mysqldb41
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql>
mysql> show create database mysqldb41;
+-----------+--------------------------------------------------------------------+
| Database | Create Database |
+-----------+--------------------------------------------------------------------+
| mysqldb41 | CREATE DATABASE `mysqldb41` /*!40100 DEFAULT CHARACTER SET sjis */ |
+-----------+--------------------------------------------------------------------+
1 row in set (0.00 sec)

mysql> show create table emp¥G
*************************** 1. row ***************************
Table: emp
CREATE TABLE `emp` (
`empno` int(11) NOT NULL default '0',
`ename` varchar(40) default NULL,
PRIMARY KEY (`empno`)
) ENGINE=InnoDB DEFAULT CHARSET=sjis
1 row in set (0.00 sec)

mysql> select * from emp;
+-------+------------------+
| empno | ename |
+-------+------------------+
| 1 | おらおら |
| 2 | ほげ   |
| 3 | 化けないよね〜ー |
+-------+------------------+
3 rows in set (0.01 sec)

mysql>

尚、MacOSX 10.4.3 Tiger Serverでは、MySQLの管理ツールとしてMySQLマネージャがインストールされていて起動、停止やリモート接続の可否設定も行える。


gencon_blog4_mysql_admin_icon

gencon_blog4_mysql_admin


ということで以下のMySQL、PostgreSQLデータベースの作成が完了した。これでOracle Generric Connectivityを行うためのリモートデータベースは準備できた。残すはODBC構成及び接続確認とOracle Generic Connectivityの構成、データベースリンクの作成、動作確認である。

Platform Database DB Name Character set
PowerBook G4 1Ghz MacOSX 10.4 Tiger MySQL4.0.25 mysqldb sjis
AMD Athron MP Dual 2800+ Windows XP Professional MySQL4.0.26-nt mysqldb sjis
PowerMac G5 Dual 2.7Ghz MacOSX 10.4 Tiger Server MySQL4.1.13a mysqldb41 sjis
PowerBook G4 1Ghz MacOSX 10.4 Tiger PostgreSQL7.4.9 postgresql749 EUC_JP

次回は、Windows XP Professional で ODBCデータソースの設定及び、接続確認を行う。

| | | コメント (0) | トラックバック (0)

2005年12月31日 (土)

Mac De Oracle Heterogeneous! #3

前回MySQLをインストールした PowerBook G4 1Ghz 17inch (MacOSX 10.4.3 Tiger)にPostgreSQL 7.4.9 もインストールしデータベースを構築する。

http://wwwmaster.postgresql.org/download/mirrors-ftp?file=source%2Fv7.4.9%2Fpostgresql-7.4.9.tar.gzからpostgresql-7.4.9.tar.gzを入手し、適当なフォルダ(/tmpなどで解凍する)。
この例では、/Volumes/WorkVol/temp以下で解凍した。

注意)
今回もPostgreSQLのインストールやデータベース作成は簡単に(それなりに端折って)記述しているのであしからず。
また、MacOSXにPostgreSQLをインストールする記事を書いているBlogも多数あるのでそれらも参考にしてほしい。
(Mac De Oracleでは、MySQLやPostgreSQLの構築方法がメインではなく、Oracle Generic Connectivityの動きを確認する事が目的なので。)

Terminalを起動しPostgreSQL 7.4.9を解凍して出来たディレクトリに移動する。作業はrootで行うので、sudo shでrootになっておく。


Last login: Fri Nov 25 15:56:39 on ttyp1
Welcome to Darwin!
pb17:˜ discus$ sudo sh
Password:
sh-2.05b#
sh-2.05b# cd /Volumes/WorkVol/temp/postgresql-7.4.9
sh-2.05b# ls -l
total 1752
-rw-r--r-- 1 root wheel 1192 Nov 26 08:43 COPYRIGHT
-rw-r--r-- 1 root wheel 3460 Nov 26 08:43 GNUmakefile.in
-rw-r--r-- 1 root wheel 269744 Nov 26 08:43 HISTORY
-rw-r--r-- 1 root wheel 40847 Nov 26 08:43 INSTALL
-rw-r--r-- 1 root wheel 1432 Nov 26 08:43 Makefile
-rw-r--r-- 1 root wheel 1376 Nov 26 08:43 README
-rw-r--r-- 1 root wheel 442 Nov 26 08:43 aclocal.m4
drwxr-xr-x 19 root wheel 646 Nov 26 08:42 config
-rwxr-xr-x 1 root wheel 523803 Nov 26 08:43 configure
-rw-r--r-- 1 root wheel 39896 Nov 26 08:43 configure.in
drwxr-xr-x 53 root wheel 1802 Nov 26 08:42 contrib
drwxr-xr-x 30 root wheel 1020 Nov 26 08:42 doc
drwxr-xr-x 22 root wheel 748 Nov 26 08:43 src


日本語EUCが利用できるようにconfigureする。


sh-2.05b# ./configure --enable-multibyte=EUC_JP
checking build system type... powerpc-apple-darwin8.3.0
checking host system type... powerpc-apple-darwin8.3.0
checking which template to use... darwin
checking whether to build with 64-bit integer date/time support... no
checking whether NLS is wanted... no
checking for default port number... 5432
checking for gcc... gcc

中略

configure: using CPPFLAGS=
configure: using LDFLAGS=
checking for gawk... no
checking for mawk... no
checking for sgmlspl... no
configure: creating ./config.status
config.status: creating GNUmakefile
config.status: creating src/Makefile.global
config.status: creating src/include/pg_config.h
config.status: linking ./src/backend/port/tas/dummy.s to src/backend/port/tas.s
config.status: linking ./src/backend/port/dynloader/darwin.c to src/backend/port/dynloader.c
config.status: linking ./src/backend/port/posix_sema.c to src/backend/port/pg_sema.c
config.status: linking ./src/backend/port/sysv_shmem.c to src/backend/port/pg_shmem.c
config.status: linking ./src/backend/port/dynloader/darwin.h to src/include/dynloader.h
config.status: linking ./src/include/port/darwin.h to src/include/pg_config_os.h
config.status: linking ./src/makefiles/Makefile.darwin to src/Makefile.port
sh-2.05b#

エラーもなくconfigureできたのでコンパイルする。


sh-2.05b# make
make -C doc all
gzip -d -c man.tar.gz | /usr/bin/tar xf -
for file in man1/*.1; do ¥
mv $file $file.bak && ¥
sed -e 's/¥¥fR(l)/¥¥fR(7)/' $file.bak >$file && ¥
rm -f $file.bak || exit; ¥
done
/bin/sh ../config/mkinstalldirs man7
mkdir man7
for file in manl/*.l; do ¥
sed -e '/^¥.TH/s/"l"/"7"/' ¥
-e 's/¥¥fR(l)/¥¥fR(7)/' ¥
$file >man7/`basename $file | sed 's/.l$/.7/'` || exit; ¥
done
make -C src all
make -C port all
gcc -no-cpp-precomp -O2 -fno-strict-aliasing -Wall -Wmissing-prototypes -Wmissing-declarations -I../../src/include -c -o path.o path.c
gcc -no-cpp-precomp -O2 -fno-strict-aliasing -Wall -Wmissing-prototypes -Wmissing-declarations -I../../src/include -c -o sprompt.o sprompt.c
gcc -no-cpp-precomp -O2 -fno-strict-aliasing -Wall -Wmissing-prototypes -Wmissing-declarations -I../../src/include -c thread.c
ar crs libpgport.a path.o sprompt.o thread.o
make -C backend all

中略

rm -f libplpgsql.so
ln -s libplpgsql.so.1.0 libplpgsql.so
All of PostgreSQL successfully made. Ready to install.
sh-2.05b#


コンパイルエラーもないようなので、インストールする。


sh-2.05b# make install
make -C include install
mkdir /usr/local/pgsql/include
mkdir /usr/local/pgsql/include/libpq
mkdir /usr/local/pgsql/include/internal
mkdir /usr/local/pgsql/include/internal/libpq
mkdir /usr/local/pgsql/include/internal/lib

中略

make[4]: Nothing to be done for `all'.
/bin/sh ../../../config/install-sh -c pg_encoding /usr/local/pgsql/bin/pg_encoding
make -C pl install
make -C src install
/bin/sh ../../../../config/install-sh -c -m 755 libplpgsql.so.1.0 /usr/local/pgsql/lib/plpgsql.so
PostgreSQL installation complete.
sh-2.05b#


次に キャタクタセット EUC_JP でデータベースクラスタを作成する。
データベースクラスタを作成しないと、インスタンスが起動できないので注意する。
(尚、MySQL、PostgreSQLは、Oracleとは異なり1インスタンスで複数データベースを管理することができる)

データベースクラスタを作成するには initdb コマンドを利用する。
尚、データベースクラスタは、/usr/local/pgsql/data以下に作成することにする。

インストールが終了すると postgres というユーザが作成されているのでそのユーザで作業する。


pb17:˜ discus$ su - postgres
Password:
pb17:˜ postgres$ /usr/local/pgsql/bin/initdb -D /usr/local/pgsql/data -E EUC_JP
The files belonging to this database system will be owned by user "postgres".
This user must also own the server process.

The database cluster will be initialized with locale C.

fixing permissions on existing directory /usr/local/pgsql/data... ok
creating directory /usr/local/pgsql/data/base... ok
creating directory /usr/local/pgsql/data/global... ok
creating directory /usr/local/pgsql/data/pg_xlog... ok
creating directory /usr/local/pgsql/data/pg_clog... ok
selecting default max_connections... 50
selecting default shared_buffers... 300
creating configuration files... ok
creating template1 database in /usr/local/pgsql/data/base/1... ok
initializing pg_shadow... ok
enabling unlimited row size for system tables... ok
initializing pg_depend... ok
creating system views... ok
loading pg_description... ok
creating conversions... ok
setting privileges on built-in objects... ok
creating information schema... ok
vacuuming database template1... ok
copying template1 to template0... ok

Success. You can now start the database server using:

/usr/local/pgsql/bin/postmaster -D /usr/local/pgsql/data
or
/usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data -l logfile start

pb17:˜ postgres$

データベースクラスタができたのでPostgreSQLのインスタンスを起動する。


pb17:˜ postgres$ /usr/local/pgsql/bin/pg_ctl -D /usr/local/pgsql/data -l logfile start
postmaster successfully started

問題なく起動したようだ。


Oracleでいうところの、SQL*Plusに相当するpsqlを起動する前に環境変数は以下のように設定しておく。
クライアントのキャラクタセットはSJISにする。


pb17:˜ postgres$ cat .bash_profile
export PATH=$PATH:/usr/local/pgsql/bin
export PGDATA=/usr/local/pgsql/data

# client encoding
export PGCLIENTENCODING=SJIS

pb17:˜ postgres$
pb17:˜ postgres$ . .bash_profile


次に postgresql749 というデータベースを作成する。
作成済みデータベースは、psql -l で確認できる。


pb17:˜ postgres$ createdb postgresql749
CREATE DATABASE
pb17:˜ postgres$

pb17:˜ postgres$ psql -l
List of databases
Name | Owner | Encoding
---------------+----------+----------
postgresql749 | postgres | EUC_JP
template0 | postgres | EUC_JP
template1 | postgres | EUC_JP
(3 rows)


psql で postgresql749 データベースに接続する。


pb17:˜ postgres$ psql postgresql749
Welcome to psql 7.4.9, the PostgreSQL interactive terminal.

Type: ¥copyright for distribution terms
¥h for help with SQL commands
¥? for help on internal slash commands
¥g or terminate with semicolon to execute query
¥q to quit

postgresql749=#

※ scott ユーザを作成する。


postgresql749=# create user scott with password 'xxxxxxx';
CREATE USER
postgresql749=# ¥du
List of database users
User name | User ID | Attributes
-----------+---------+----------------------------
postgres | 1 | superuser, create database
scott | 100 |
(2 rows)

postgresql749=#
postgresql749=# select * from pg_user;
usename | usesysid | usecreatedb | usesuper | usecatupd | passwd | valuntil | useconfig
----------+----------+-------------+----------+-----------+----------+----------+-----------
postgres | 1 | t | t | t | ******** | |
scott | 100 | f | f | f | ******** | |
(2 rows)

postgresql749=#

ユーザと同じ名称のスキーマを作成し所有者をscottにする。このようにすることでscottユーザがログインすると優先スキーマがscottスキーマになり、Oracleに近い感覚で利用できることになります。
(Oracleに慣れてしまっていると、つい、ユーザとスキーマが同じようなイメージで固まってしまいますが、実際には違うオブジェクトだということ思い出しますね。たまにはOracle以外のデータベースで遊ぶのもいいかもしれません。)

postgresql749=# create schema scott authorization scott; CREATE SCHEMA postgresql749=#
 postgresql749=# ¥dn
List of schemas
Name | Owner
--------------------+----------
information_schema | postgres
pg_catalog | postgres
pg_temp_1 | postgres
pg_toast | postgres
public | postgres
scott | scott
(6 rows)
pb17:˜ postgres$ psql -U scott postgresql749 Welcome to psql 7.4.9, the PostgreSQL interactive terminal.

Type: ¥copyright for distribution terms
¥h for help with SQL commands
¥? for help on internal slash commands
¥g or terminate with semicolon to execute query
¥q to quit

postgresql749=> select current_schema();
current_schema
----------------
scott
(1 row)


さて、psqlというクライアントでは、AUTOCOMIT ON がデフォルトになっている。これでは都合が悪いので ホームディレクトリに .pgsqlrc を作成し、¥set AUTOCOMMIT off と記述しておく。


postgresql749=#
pb17:˜ postgres$ cat .psqlrc
¥set AUTOCOMMIT off
pb17:˜ postgres$

さて、最後に表を作成する。MySQLと同じくemp表を作成してデータの登録、参照までを行う。


pb17:˜ postgres$ psql -U scott postgresql749
Welcome to psql 7.4.9, the PostgreSQL interactive terminal.

Type: ¥copyright for distribution terms
¥h for help with SQL commands
¥? for help on internal slash commands
¥g or terminate with semicolon to execute query
¥q to quit

postgresql749=>
postgresql749=> create table emp
postgresql749-> (
postgresql749(> empno numeric(10,0) primary key,
postgresql749(> ename varchar(40)
postgresql749(> );
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "emp_pkey" for table "emp"
CREATE TABLE

postgresql749=> ¥d emp
Table "public.emp"
Column | Type | Modifiers
--------+-----------------------+-----------
empno | numeric(10,0) | not null
ename | character varying(40) |
Indexes:
"emp_pkey" primary key, btree (empno)

postgresql749=>
postgresql749=> ¥dt
            List of relations
Schema | Name | Type | Owner
--------+--------+-------+-------
scott | emp | table | scott
(1 row)

postgresql749=> insert into emp values(1,'¥202¥331¥202¥260¥202¥331¥202¥260');
INSERT 25420 1
postgresql749=> insert into emp values(2,'¥202¥331¥202¥260');
INSERT 25421 1
postgresql749=> insert into emp values(3,'¥211¥273¥202¥257¥202¥310¥202¥242¥202¥346¥202¥313¥201`¥201[');
INSERT 25422 1
postgresql749=> commit;
COMMIT


postgresql749=> select * from emp;
empno | ename
-------+------------------
1 | ほげほげ
2 | ほげ
3 | 化けないよね〜ー
(3 rows)

postgresql749=>

ここまでで、PowerBook G4 1Ghz 17inch (MacOSX 10.4.3 Tiger)に MySQL 4.0.25 mysqldb (SJIS) と PostgreSQL 7.4.9 postgresql749 (EUC_JP) という2つのデータベースができた。

次回は、MacOSX 10.4.3 Tiger Server に MySQL4.1.13a、そしてWindows XP Proに MySQL4.0.26-ntのデータベースを作成しODBCドライバの構成まで書く予定である。(尚、Windows XP Proには、Oracle10g R1 EEがインストール済みでデータベースも作成済みである)

| | | コメント (0) | トラックバック (0)

2005年12月30日 (金)

Mac De Oracle Heterogeneous! #2

さて、Generic Connectivityを試す環境作りです。

まず最初は、MacOSX 10.4.3 Tiger (PowerBook G4 1Ghz 17inchに、MySQL 4.0.25 Standardをインストールしてデータベースを構築、表の作成、最後にデータ登録まで行う。

MacOSXでのMySQL構築を書いているBlogも多数存在するので、Mac De Oracleではその辺りは簡単に(端折ってとも言う)書く事にするので悪しからず。

MacOSX 10.4 Serverならば、MySQL4.1も付属していますが、Server版ではないのでダウンロードしてインストールする。
これをダウンロードして利用した。
インストーラをダブルクリックするだけでインストールできるので簡単です。
後は、インストーラに付属しているコントロールパネルをライブラリ/PreferencePanes/以下にコピーすればシステム環境設定から起動停止できるようになります。


gencon_blog2_img1


gencon_blog2_img2



MySQLは、/usr/local/mysql にインストールされるので以下のような感じで環境変数を設定しておく


pb17:〜 discus$ cat .bash_profile

export MYSQL_HOME=/usr/local/mysql
export PATH=$PATH:$MYSQL_HOME/bin

pb17:˜ discus$

以下のようにコマンド起動しても構わないが、システム環境設定にインストールしたコントロールパネルから起動したほうが楽ですね。自動起動の設定もこれでできます。


$ sudo mysqld_safe --user=mysql &

または、以下のコントロールパネルで起動。(私はGUIで起動してます。楽なので)


gencon_blog2_img3


gencon_blog2_img4



文字化けが気になるのでGeneric Connectivityで接続する環境はなるべく同一キャラクタセットにしておきたいがうまい具合に統一されていない場合も多々ある。今回はMySQLのデータベースはすべてsjisを想定しているので作成するデータベースのデフォルトキャラクタセットはsjisに設定しておく。 設定は、/etc/my.cnf で行う。

今回作成する mysqldb データベースのデフォルトキャラクタセットを以下のように設定しておく。


pb17:˜ discus$ cat /etc/my.cnf
[mysqld]
default-character-set = sjis
[mysqldump]
default-character-set = sjis
[mysql]
default-character-set = sjis
[mysqldb]
default-character-set = sjis
pb17:˜ discus$

念のため起動しているか確認。


Last login: Tue Nov 15 21:59:49 on console
Welcome to Darwin!
pb17:˜ discus$ sudo mysqladmin -u root -p ping
Enter password:
mysqld is alive

rootユーザで接続し、jobs というユーザを作成。localhostとWindows XP Proからだけ接続できれば十分なのだが、今回は全ホストからの接続を受け付けるようにした。
(セキュリティ上はNGなのだが。。)
ちなみに、ちゃんとやるのであれば、localhostとWindows XP Proからの接続を受け付けるように grant文を2回実行する必要がある。


pb17:˜ discus$ mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or ¥g.
Your MySQL connection id is 239 to server version: 4.0.25-standard

Type 'help;' or '¥h' for help. Type '¥c' to clear the buffer.

mysql> use mysql
Database changed
mysql> grant all on mysqldb.* to 'jobs'@'%' identified by 'xxxxxxxxxx';
Query OK, 0 rows affected (0.04 sec)

mysql> exit
Bye

mysqldb というデータベースを作成する。


pb17:˜ discus$ sudo sh
Password:
sh-2.05b# mysqladmin -u root -p create mysqldb
Enter password:
sh-2.05b#
sh-2.05b#
sh-2.05b# exit
exit


作成した jobs ユーザで mysqldbに接続し、キャラクタセットの確認後 MyISAMの表及び、InnoDBの表を作成する。最後にマルチバイトを含む文字列の登録と参照を行う。


pb17:˜ discus$ mysql -u jobs -p mysqldb
Enter password:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor. Commands end with ; or ¥g.
Your MySQL connection id is 100 to server version: 4.0.25-standard

Type 'help;' or '¥h' for help. Type '¥c' to clear the buffer.


※デフォルトキャラクタセットを確認しておく。

mysql> show variables like '%char%'¥G
*************************** 1. row ***************************
Variable_name: character_set
Value: sjis
*************************** 2. row ***************************
Variable_name: character_sets
Value: latin1 big5 czech euc_kr gb2312 gbk latin1_de sjis tis620 ujis dec8 dos german1 hp8 koi8_ru latin2 swe7 usa7 cp1251 danish hebrew win1251 estonia hungarian koi8_ukr win1251ukr greek win1250 croat cp1257 latin5
*************************** 3. row ***************************
Variable_name: convert_character_set
Value:
3 rows in set (0.00 sec)

※ emp表をMyISAMエンジンで作成する。

mysql> show create table emp¥G
*************************** 1. row ***************************
Table: emp
Create Table: CREATE TABLE `emp` (
`empno` int(11) NOT NULL default '0',
`ename` varchar(40) default NULL,
PRIMARY KEY (`empno`)
) TYPE=MyISAM
1 row in set (0.00 sec)

※Terminalから日本語を入力すると以下のようになるが、問い合わせると正常に表示される。
(現時点のTerminalの問題点なのでしかたない。)
  ちなみに、Terminalの文字エンードは 日本語MacOS(SJIS系)にしてある。


mysql> insert into emp values(1,'¥202¥250¥202¥347¥202¥250¥202¥347');
Query OK, 1 row affected (0.00 sec)

mysql> insert into emp values(2,'¥202¥331¥202¥260');
Query OK, 1 row affected (0.00 sec)

mysql> insert into emp values(3,'¥211¥273¥202¥257¥202¥310¥202¥242¥202¥346¥202¥313¥201[¥201`');
Query OK, 1 row affected (0.00 sec)


mysql> select * from emp;
+-------+------------------+
| empno | ename |
+-------+------------------+
| 1 | おらおら |
| 2 | ほげ |
| 3 | 化けないよねー〜 |
+-------+------------------+

3 rows in set (0.00 sec)

mysql>
mysql>


トランザクションをサポートしているinnoDBをエンジンに使った表も用意する。(BDBやMAXDBも存在するようだが、InnoDBを使っているところのほうが多そうなのでInnoDBに絞る。
InnoDBは、Oracleのようなマルチバージョニングを行っているエンジンであり、先日Oracleが買収したことでも有名。

(前述の表は、MyISAMをエンジンに利用しているため、commitや、rollbackが行えない。つまり、INSERT文や、UPDATE文、DELETE文は ”常に”AUTOCOMMIT されてしまう。
ROLLBACKができないので、その手の処理はプログラムに実装する必要があるのだ。常にトランザクションを意識している世界でプログラミングしていた方は要注意!)

当然、OracleにあるようなFlush back queryや、Flush back dropも無いのでバックアップから戻すことになる。rollback入力し、エラーが帰ってきたところで、あ! という声が発せられることになる。。。(自分で実験済み! ^^;;; )

ちなみに、今回はMySQLやPostgreSQL側にOracleからデータを参照することをメインに考えているのであまり影響ないが、どのような動きをするのかも確認しておきたいので、MyISAM及びInnoDB両エンジンを利用した表を準備しておく。

注)
show create table inno_emp; としても内容は確認できるが非常に読みにくく表示されるので show create table inno_emp¥G として表示形式を読みやすくしてある。
詳細は、mysql> help  としてヘルプで確認してもらいたい。
 
mysql> show create table inno_emp¥G
*************************** 1. row ***************************
Table: inno_emp
Create Table: CREATE TABLE `inno_emp` (
`empno` int(11) NOT NULL default '0',
`ename` varchar(40) default NULL,
PRIMARY KEY (`empno`)
) TYPE=InnoDB
1 row in set (0.07 sec)

emp表と同じデータを登録しておく。


mysql> insert into inno_emp select * from emp;
Query OK, 3 rows affected (0.08 sec)
Records: 3 Duplicates: 0 Warnings: 0

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from inno_emp;


+-------+------------------+
| empno | ename |
+-------+------------------+
| 1 | おらおら |
| 2 | ほげ |
| 3 | 化けないよねー〜 |
+-------+------------------+
3 rows in set (0.00 sec)

mysql>

ここまでで、 MacOSX 10.4.3 Tiger (PowerBook G4 1Ghz)のMySQL4.0.25のデータベースの準備は完了した。
次は、同じMacに PostgreSQL7.4.9を構築する。

余談だが、妻は今 Scarab De MySQL と格闘中?!(環境できたかな〜)

| | | コメント (1) | トラックバック (0)

2005年12月29日 (木)

Mac De Oracle Heterogeneous! #1

さて、しばらくご無沙汰していた記事投稿再開第一弾は、Generic Connectivityに関するものにした。

Generic Connectivityは、Oracle Database Heterogeneous Connectivity(異機種間接続)機能の一部で、

他に Transparent Gatewayという有償オプションも用意されている。(詳細は、マニュアル「Oracle Database Heterogeneous Connectivity管理者ガイド 10g」を参照するとよいだろう。)

Generic Connectivityは、ODBC又は、OLE DBを利用して行えるOracle Databaseの基本機能の一つ。
今回はODBCドライバが提供されている


MySQL4.0.25 (MacOSX 10.4 Tiger)
MySQL4.0.26-nt (WindowsXP Pro)
MySQL4.1.13a (MacOSX 10.4 Tiger Server付属のもの)
PostgreSQL7.4.9 (MacOSX 10.4 Tiger)

という4つのリモートデータベースに、Mac De Oracleらしく、MacOSX 10.4 Tiger Serverに無理矢理構築した、Oracle10g R1 EE 10.1.0.3から接続して動作上の癖を把握しておくことにした。

しかし、ここで問題発生。
現時点では、MacOSX版 Oracle10g には Heterogeneous Serviceが提供されていないのである。
どうするかしばし考えて浮かんだのが、Windows版又は、Linux版 Oracle10g R1 EEを踏み台にしてMacOSX Server上のOracle10gからアクセスするという方法。
そこまでしてそんなことやりたいのかという声が聞こえてきそうだが、最近、PostgreSQLやってくれとかMySQLがどうの。。。という話も多くなり、それらの勉強も兼ねて試してみることにした。(こんなことも試しておけば何かの役に立つこともあるだろうから。)
#そのうち FireBirdなどでも試してみるかもしれない。

ではまず、各リモートデータベースとするデータベースの構築から行っていく。尚、踏み台にするOracleはWindowsに構築することにした。
(LinuxはOracle9iで遊んでいるため今回は利用しないが、Unix/LinuxではunixODBC(ODBC driver Manager)及び、各データベースに対応したlinux向けODBC Driverがリリースされているし、Blogなどでも結構記事を見かけるのでそれを参考にするとよいだろう。また、unixODBCのODBCConfig(GUI)は、Windowsのデータソース管理の操作性に類似しているので戸惑うことは少ないと思う)

環境は以下の通り。
(キャタクタセットが統一できていれば一番よいが現実問題としてそうも行かない。が、今回、MySQLのデータベースはすべてSJISで作成した)

1、MacOSX 10.4.3 Tiger (PowerBook G4 1Ghz)


PostgreSQL 7.4.9 (キャラクタセット EUC。キャラクタセットにSJISが無いのでEUCにした。)
MySQL 4.0.25 standard (キャラクタセット SJIS)

  #ほんとうは、iMacG5に作りたかったけど、奥さん専用のMacなので今回は遠慮した。(^^;;

2、MacOSX 10.4.3 Tiger Server (Power Mac G5 Dual 2.7Ghz)


MySQL 4.1.13a (キャラクタセットSJIS、MacOSX 10.4 Serverに付属しているもの)
Oracle10g R1 EE 10.1.0.3(キャラクタセット JA16SJISTILDE、無理矢理構築したもの)

3、WindowsXP Professional (AMD AthronMP Dual 2800+)


Oracle10g R1 EE 10.1.0.3(キャラクタセット JA16SJISTILDE)
(これを踏み台にしてMacOSX のOracleから各リモートデータベースをアクセスする)

MySQL 4.0.26-nt standard(キャラクタセット SJIS)


イメージはこんな感じ


Deploymentdiagram_1


次回は、MacOSX 10.4.3 Tiger (PowerBook G4)にMySQL4.0.25 standard のデータベースを作成し、接続確認するための表を作成する。

| | | コメント (0) | トラックバック (0)

2005年6月 2日 (木)

Mac De 商用データベース

Mac De Oracle という記事なので、Oracle以外の商用データベースのことは書いていないのだが、いくつかの商用データベースベンダがMacOS X版をリリースし始めた。

ちょうど、SybaseとOracle が MacOS X 10.2 Jaguar に対応した、エンタープライズ向けデータベースをリリースするという発表があったころ、IBMも調査していたようなのだ。現時点開発中であるという噂もないので、DB2 for Mac OS Xはしばらくないのかもしれないが・・・・。

そこで、現時点で Mac OS X向けにリリースされている商用データベース製品を探してみた。。

Oracle10g for Mac OS X

Adaptive Server Enterprise (ASE) 12.5 for Mac OS X

Cache5 for Mac OS X

MacOS9のころには、商用データベースからは見放された感じがあったMacも、Mac OS X Jaguar以降、確実に見直されてきたように感じる。。。。

| | | コメント (0) | トラックバック (0)