入ったけど、起動できなかった。。。
まー仕方ないかw
2010年4月28日水曜日
Android携帯を選ぶ時のポイント
今年から日本で発売されているAndroid機種にも選択肢が生まれ、そろそろAndroid携帯を買いたいけどどれを選んで良いのか解らないって思う人が出てくるだろう。
という事で自分が去年から使っていて気付いた点をまとめてみた。
という事で自分が去年から使っていて気付いた点をまとめてみた。
- OSのバージョン
現在は1.0系と2.0系の両方の商品が出回っている。
DoCoMoから発売されているXperiaは1.6でSoftbankからのDesireは2.1だ。
これは正直言って2.1の方が便利。何が便利かというと具体的には2点です。- 1点目はマルチアカウント対応。
こちらは自分にとっては必須機能である。。。何故かというと現在自分はGoogleAppsを利用ているのですが、このGoogleAppsでのアカウントではマップアプリでマイマップが使えないのです。。。
なので、マップの時はGmailアカウントを利用しています。つまりGoogleAppsアカウントの利用を考えている人はマルチアカウント対応じゃないと利用できない機能があるという事です。 - 2点目はマルチタッチ
これは残念ながらあまり必要性は感じていません。。。
もちろんあれば便利なんですが、必ずしも必要があるとも思えせんね。。。
今後は対応していないと利用できないアプリも出てくるでしょうから、あと1年後には必須になっているかもしれませんが。。。
- 1点目はマルチアカウント対応。
- ディスプレイ(画面)のサイズ
4.0インチを目安に購入する事をお勧めします。基本的にはソフトウェアキーボードという画面上に表示されるキーボードで入力するのですが、これが画面が大きい方が入力しやすいです。昔より今は電話するよりメールする方が多いので、そのメールの操作がしやすい画面が大きい方が時代には合ってると思います。
あとYoutubeなんかの動画やマンガや小説なんかの書籍を見る事もこれからは普通になってくると思うので、やっぱり画面は大きい方が良いです。
ちなみにデメリットとしては消費電力が多いので、電池の寿命が。。。ですが、これは別にこれだけの問題ではないので予備バッテリーはスマートフォンでは必須です。 - メーカー
現在一番優位なのはHTCというメーカーだと思います。HTCは世界で販売端末数が多い事やそのアメリカでも多くの機種が発売されているので、非公式な情報が多いです。アメリカ人は好奇心を持った人が多いんですかね~w
ドコモから去年出たHT-03Aは情報が多いのでめちゃくちゃできますw
自分も今は中身を2.0系のROMに入れ替えて楽しんでます♪ - キャリア
現在は圧倒的にドコモが有利ですね。。。
2010年にはLTEという新しい通信企画にもドコモは参入しているので、12月位には何か出るのかもしれませんね。DELLから公開されているサンダーという機種もLTE版が来年出るそうです。LTEの特徴は通信速度100Mbpsと光並の速度となっているのでKDDI(AU)が絡んでるWiMaxより早いようです。ソフトバンクは何をやろうとしてるのか知らないですが、iPhoneは次にどの規格を想定してるんでしょうね。。。 - その他
CPUは現在1Ghzあたりで並んでます。あとはメモリーですね。。。
自分的にはRAMが多い方が良い気がしますが、ROMもやっぱり必要ですね。
何しろこれは多い方が良いですw
それより自分はカメラの性能やその他のハードが気になります。
カメラに手ぶれ補正はあるのか?
ストロボライトはあるのか?
Felica対応なのか?(今のところ無いです。。。)
ラジオ対応なのか?(必要ないですが。。。)
あとは。。。
Flash対応か?別に今のところは無くてもいいんですがね。。。
これはOS2.1以上ならこれからは対応させてくるでしょう。
メールとか日本語入力が。。。とかいう記事を見ますがAndroidはiPhoneと違ってそこらへんのアプリも自分で入れる事ができちゃうので、あまり気にする必要は無いかと思います。
2010年4月27日火曜日
遂に発売HTC Desire♪
今日が発売日ですね♪
周りに買う予定な人はいないので残念ですが。。。
まずは画面フィルムの売れ行きからチェックですかね(笑)
Xperiaより売れるのか売れないのか。。。
ちなみにAmazonで買う人へ。
下記の商品は出品者がAmazonじゃないので送料なようです。。。
周りに買う予定な人はいないので残念ですが。。。
まずは画面フィルムの売れ行きからチェックですかね(笑)
Xperiaより売れるのか売れないのか。。。
ちなみにAmazonで買う人へ。
下記の商品は出品者がAmazonじゃないので送料なようです。。。
2010年4月23日金曜日
DELL のAndroid端末、その名は「Thunder」
DELLのAndroid端末の写真を発見しました。
http://japanese.engadget.com/2010/04/21/android-thunder/
注目なのはLTE版が来年に出るというところですね(@@
ドコモはLTEを進めているので、来年にこのDELLのLTE端末を出してくる確率高くないでしょうか?
ま~DELL以外からもLTE版が出るでしょうし。解らないですが、少なくてもLTE版のAndroid端末が来年には存在する事はこれでほぼ確定でしょうし来年が楽しみになってきました♪
こんなオシャレタイプも出るみたいですね。。。
http://japanese.engadget.com/2010/04/22/flash/
そしてこんなタブレットPC型もあるんですね。。。
http://japanese.engadget.com/2010/04/22/5-streak-android-2-1/
あっ これもDELL。。。ようけ出すんですね。。。
http://japanese.engadget.com/2010/04/22/qwerty-android-smoke/
http://japanese.engadget.com/2010/04/21/android-thunder/
注目なのはLTE版が来年に出るというところですね(@@
ドコモはLTEを進めているので、来年にこのDELLのLTE端末を出してくる確率高くないでしょうか?
ま~DELL以外からもLTE版が出るでしょうし。解らないですが、少なくてもLTE版のAndroid端末が来年には存在する事はこれでほぼ確定でしょうし来年が楽しみになってきました♪
こんなオシャレタイプも出るみたいですね。。。
http://japanese.engadget.com/2010/04/22/flash/
そしてこんなタブレットPC型もあるんですね。。。
http://japanese.engadget.com/2010/04/22/5-streak-android-2-1/
あっ これもDELL。。。ようけ出すんですね。。。
http://japanese.engadget.com/2010/04/22/qwerty-android-smoke/
2010年4月22日木曜日
添付メールを送信する際のヘッダー順について
sendmailコマンドから送信する際にヘッダー情報の出力順に悩まされたのでメモ。
添付メールを送信する際にはFromよりもToよりもSubjectよりも後の必要があるみたい。
でもContent-Typeよりは前にする必要がある?
添付メールが無ければ別にFromなどより前でContent-Typeを出力しても大丈夫だった。
もっと正確な順番が決められているんだろうな。。。
添付メールを送信する際にはFromよりもToよりもSubjectよりも後の必要があるみたい。
でもContent-Typeよりは前にする必要がある?
添付メールが無ければ別にFromなどより前でContent-Typeを出力しても大丈夫だった。
もっと正確な順番が決められているんだろうな。。。
2010年4月16日金曜日
Android 2.1搭載 のAndroid携帯 HTC DROID Incredible
HTCから更に新しいが出ますね~。
カメラも800万画素で1CPUはSnapdragon 1GHzプロセッサ。
スペックはま~どうでもよくて気になるのはまたHTCかって事ですね。
やっぱりAndroid携帯はHTCの一人勝ち状態っぽいですね。
HTCだったらROMも多そうだしな。。。
やっぱりAndroidを買うならHTCなのかな。。。
日本メーカーもっと頑張ってほしいな。。。
テストケース生成ツールの PICT を利用してみた
PICTはMicrosoftから出ているアプリなようで生成方法はAll-Pair法というもの。
PICTはコマンドラインから実行するちょっととっつきにくい感じなようなので、PictMasterというExcelマクロを利用して実際は生成する事にした。
まずは PICT 本体の入手。
http://www.pairwise.org/
ここの Available Tools というリンクをクリックして、
からダウンロードした。
その後 Pict Master を
http://sourceforge.jp/projects/pictmaster/
マニュアルが含まれているので、あとはそのマニュアルに沿って利用するだけ。
水準の区切り方が気に入らないけどめちゃくちゃ使いやすいです♪
もっと早く使っておけばよかった。。。
PICTはコマンドラインから実行するちょっととっつきにくい感じなようなので、PictMasterというExcelマクロを利用して実際は生成する事にした。
まずは PICT 本体の入手。
http://www.pairwise.org/
ここの Available Tools というリンクをクリックして、
20. | PICT | Microsoft | Command-line, free |
その後 Pict Master を
http://sourceforge.jp/projects/pictmaster/
マニュアルが含まれているので、あとはそのマニュアルに沿って利用するだけ。
水準の区切り方が気に入らないけどめちゃくちゃ使いやすいです♪
もっと早く使っておけばよかった。。。
今だ人気なXperia
ドコモからの次のAndroid端末はXperia mini という噂もあるせいか、Xperiaの人気はまだまだあるようですね。。。
今週の水曜日にヨドバシカメラ梅田店に問い合わせたら、予約の受付もやっておらず週末に数台入荷するが、何台入荷するか解らないため朝から来てもらうしか無いとの事でした♪
もちろん行く気は無いんですがw
写真はXperiaとXperia mini を比較しているところ。
こんな小さいのいらないだろう。。。
HT-03Aで小さいのには懲りたよ。。。
今週の水曜日にヨドバシカメラ梅田店に問い合わせたら、予約の受付もやっておらず週末に数台入荷するが、何台入荷するか解らないため朝から来てもらうしか無いとの事でした♪
もちろん行く気は無いんですがw
写真はXperiaとXperia mini を比較しているところ。
こんな小さいのいらないだろう。。。
HT-03Aで小さいのには懲りたよ。。。
2010年4月15日木曜日
PHP PEAR::MDB2 の問題点
実は結構有名なのかこれ(?)って感じなのですが、システムのテスト中にいつもさくさくっと動いていた箇所で突如エラーが出ました。。。
あれ?何で?って事でログを調べてみると。
2010-04-15 18:24:45 JSTERROR: 準備された文 "mdb2_statement_pgsql_346f901ff5a29904456a4af1572e6465" はすでに存在します
こんなエラーログが。。。
これをヒントに調べていると下記事例を発見しました。
http://cocky.exblog.jp/7914642/
しかし、問題は今回発生したページはとてもprepareを100回以上もやっているようなところではないという事。。。
というか番号ってある?
今のMDB2には無いの?
ってそれより確率アップじゃ。。。
設定の問題かな。。。
とりあえずMDB2を修正して使う気は無いので利用するのはやめておこう。。。
今度はPDOという事で。。。
あれ?何で?って事でログを調べてみると。
2010-04-15 18:24:45 JSTERROR: 準備された文 "mdb2_statement_pgsql_346f901ff5a29904456a4af1572e6465" はすでに存在します
こんなエラーログが。。。
これをヒントに調べていると下記事例を発見しました。
http://cocky.exblog.jp/7914642/
しかし、問題は今回発生したページはとてもprepareを100回以上もやっているようなところではないという事。。。
というか番号ってある?
今のMDB2には無いの?
ってそれより確率アップじゃ。。。
設定の問題かな。。。
とりあえずMDB2を修正して使う気は無いので利用するのはやめておこう。。。
今度はPDOという事で。。。
2010年4月12日月曜日
SuperEclair v3.0 [BETA]を入れてみた
早いという噂だったので、「SuperEclair v3.0 [BETA]」を入れてみた。
というか今使ってる「Eclear2.1」が動画を見れない不具合があったので、嫌気がさしていた。。。
でも自分はGoogleAppsアカウントを利用しているので、マルチアカウント対応じゃないとMapなどがフル機能で利用できない。。。
なんて色々あって入れてみた。
ダウンロードはこちらから
http://forum.xda-developers.com/showthread.php?t=654937
※もし無理なら下記からチャンジしてみは?
http://www.4shared.com/file/4CMUyXrs/SuperEclair_v30BETA.html
結果動画が見れた!!
やった♪ Eclear系のROMだと見れないんだと勝手にルール付けしていたので、嬉しかった(笑)
や~よかったよかった♪
これで当分また自分がXperiaを買う事は無くなったかな。。。
Appsアカウントにマイマップが対応してくれてら即買うのにな。。。
ちなみに「HelixLauncher」というアプリを入れると更に高速で動作するようです。
というか今使ってる「Eclear2.1」が動画を見れない不具合があったので、嫌気がさしていた。。。
でも自分はGoogleAppsアカウントを利用しているので、マルチアカウント対応じゃないとMapなどがフル機能で利用できない。。。
なんて色々あって入れてみた。
ダウンロードはこちらから
http://forum.xda-developers.com/showthread.php?t=654937
※もし無理なら下記からチャンジしてみは?
http://www.4shared.com/file/4CMUyXrs/SuperEclair_v30BETA.html
結果動画が見れた!!
やった♪ Eclear系のROMだと見れないんだと勝手にルール付けしていたので、嬉しかった(笑)
や~よかったよかった♪
これで当分また自分がXperiaを買う事は無くなったかな。。。
Appsアカウントにマイマップが対応してくれてら即買うのにな。。。
ちなみに「HelixLauncher」というアプリを入れると更に高速で動作するようです。
DoCoMoの場合のAPN設定値
結構メモし忘れてリカバリーしちゃうのでここにメモ
契約者毎に設定が違うわけでもなく共通なようですからね。
・mopera U(Biz・ホーダイ)
APN : mpr2.bizho.net
ユーザ名 : none
MMSC : none
MCC : 440
MNC : 10
上記以外は<未設定>
* ”mopera U設定”
APN : 0120.mopera.ne.jp
その他は「mopera U(Biz・ホーダイ)」と同様
契約者毎に設定が違うわけでもなく共通なようですからね。
・mopera U(Biz・ホーダイ)
APN : mpr2.bizho.net
ユーザ名 : none
MMSC : none
MCC : 440
MNC : 10
上記以外は<未設定>
* ”mopera U設定”
APN : 0120.mopera.ne.jp
その他は「mopera U(Biz・ホーダイ)」と同様
2010年4月11日日曜日
PHP + Apache(Windows) chmodは使わないのベスト
Windows環境でのApache+PHPを利用している場合に「chmod」を利用してファイル権限を変更しようとするとファイルが読み取り専用になってしまう。
具体的には下記のように記述をするとファイルが読み取り専用となってしまった。
今回はWindowsを開発環境としていたため、本番ではLinuxで動くので問題無いっちゃ~問題ない。
でも気持ち悪いのでchmodを使用する際には下記のようにした。
具体的には下記のように記述をするとファイルが読み取り専用となってしまった。
今回はWindowsを開発環境としていたため、本番ではLinuxで動くので問題無いっちゃ~問題ない。
@chmod($filepath, 0777);
でも気持ち悪いのでchmodを使用する際には下記のようにした。
if (PHP_OS != "WIN32" && PHP_OS != "WINNT") {
@chmod($filepath, 0777);
}
相変わらず人気な「Documents To Go 2.0 Main App」
タイトル: Documents To Go 2.0 Main App
パッケージ名: com.dataviz.docstogo
MicrosoftのExcelやWord、PowerPointなどのファイルをAndroid携帯で確認したい時なんかに以前おすすめしたこのアプリ、有料の方は他のアプリと比べてお高いが、フリーでも見るだけなら十分かな?
GoogleもオンラインでOffice関連提供してるんだしアプリ出してくれればな。。。
もちろん無料でw
パッケージ名: com.dataviz.docstogo
MicrosoftのExcelやWord、PowerPointなどのファイルをAndroid携帯で確認したい時なんかに以前おすすめしたこのアプリ、有料の方は他のアプリと比べてお高いが、フリーでも見るだけなら十分かな?
GoogleもオンラインでOffice関連提供してるんだしアプリ出してくれればな。。。
もちろん無料でw
Zend_Db_Adapter_Pdo_Odbc 不具合修正しました。
昨日更新した内容では「':シングルクォート」のエスケープ処理が間違っていたので、そこらへんを修正。
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Db
* @subpackage Adapter
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*
*/
/**
* Zend_Db_Adapter_Pdo_Abstract
*/
require_once 'Zend/Db/Adapter/Pdo/Abstract.php';
/**
* Class for connecting to ODBC System databases and performing common operations.
*
* @category Zend
* @package Zend_Db
* @subpackage Adapter
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Default_Plugin_Zend_Db_Adapter_Pdo_Odbc extends Zend_Db_Adapter_Pdo_Abstract
{
/**
* PDO type.
*
* @var string
*/
protected $_pdoType = 'odbc';
protected $_rowCount;
/**
* Keys are UPPERCASE SQL datatypes or the constants
* Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE.
*
* Values are:
* 0 = 32-bit integer
* 1 = 64-bit integer
* 2 = float or decimal
*
* @var array Associative array of datatypes to values 0, 1, or 2.
*/
protected $_numericDataTypes = array(
Zend_Db::INT_TYPE => Zend_Db::INT_TYPE,
Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE,
Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE,
'INT' => Zend_Db::INT_TYPE,
'SMALLINT' => Zend_Db::INT_TYPE,
'TINYINT' => Zend_Db::INT_TYPE,
'BIGINT' => Zend_Db::BIGINT_TYPE,
'DECIMAL' => Zend_Db::FLOAT_TYPE,
'FLOAT' => Zend_Db::FLOAT_TYPE,
'MONEY' => Zend_Db::FLOAT_TYPE,
'NUMERIC' => Zend_Db::FLOAT_TYPE,
'REAL' => Zend_Db::FLOAT_TYPE,
'SMALLMONEY' => Zend_Db::FLOAT_TYPE
);
/**
* Creates a PDO DSN for the adapter from $this->_config settings.
*
* @return string
*/
protected function _dsn()
{
// baseline of DSN parts
$dsn = $this->_config;
// don't pass the username and password in the DSN
unset($dsn['username']);
unset($dsn['password']);
unset($dsn['driver_options']);
unset($dsn['port']);
// this driver supports multiple DSN prefixes
// @see http://www.php.net/manual/en/ref.pdo-dblib.connection.php
if (isset($dsn['pdoType'])) {
switch (strtolower($dsn['pdoType'])) {
default:
$this->_pdoType = 'odbc';
break;
}
unset($dsn['pdoType']);
}
if (isset($dsn['dbname'])) {
$dsn = $this->_pdoType . ':' . $dsn['dbname'];
} else {
// use all remaining parts in the DSN
foreach ($dsn as $key => $val) {
$dsn[$key] = "$key=$val";
}
$dsn = $this->_pdoType . ':' . implode(';', $dsn);
}
return $dsn;
}
/**
* @return void
*/
protected function _connect()
{
if ($this->_connection) {
return;
}
parent::_connect();
$this->_connection->exec('SET QUOTED_IDENTIFIER ON');
}
/**
* Begin a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _beginTransaction()
{
$this->_connect();
$this->_connection->exec('BEGIN TRANSACTION');
return true;
}
/**
* Commit a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _commit()
{
$this->_connect();
$this->_connection->exec('COMMIT TRANSACTION');
return true;
}
/**
* Roll-back a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _rollBack() {
$this->_connect();
$this->_connection->exec('ROLLBACK TRANSACTION');
return true;
}
/**
* Returns a list of the tables in the database.
*
* @return array
*/
public function listTables()
{
$sql = "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name";
return $this->fetchCol($sql);
}
/**
* Returns the column descriptions for a table.
*
* The return value is an associative array keyed by the column name,
* as returned by the RDBMS.
*
* The value of each array element is an associative array
* with the following keys:
*
* SCHEMA_NAME => string; name of database or schema
* TABLE_NAME => string;
* COLUMN_NAME => string; column name
* COLUMN_POSITION => number; ordinal position of column in table
* DATA_TYPE => string; SQL datatype name of column
* DEFAULT => string; default expression of column, null if none
* NULLABLE => boolean; true if column can have nulls
* LENGTH => number; length of CHAR/VARCHAR
* SCALE => number; scale of NUMERIC/DECIMAL
* PRECISION => number; precision of NUMERIC/DECIMAL
* UNSIGNED => boolean; unsigned property of an integer type
* PRIMARY => boolean; true if column is part of the primary key
* PRIMARY_POSITION => integer; position of column in primary key
* PRIMARY_AUTO => integer; position of auto-generated column in primary key
*
* @todo Discover column primary key position.
* @todo Discover integer unsigned property.
*
* @param string $tableName
* @param string $schemaName OPTIONAL
* @return array
*/
public function describeTable($tableName, $schemaName = null)
{
if ($schemaName != null) {
if (strpos($schemaName, '.') !== false) {
$result = explode('.', $schemaName);
$schemaName = $result[1];
}
}
/**
* Discover metadata information about this table.
*/
$sql = "exec sp_columns @table_name = " . $this->quoteIdentifier($tableName, true);
if ($schemaName != null) {
$sql .= ", @table_owner = " . $this->quoteIdentifier($schemaName, true);
}
$stmt = $this->query($sql);
$result = $stmt->fetchAll(Zend_Db::FETCH_NUM);
$stmt->closeCursor();
$table_name = 2;
$column_name = 3;
$type_name = 5;
$precision = 6;
$length = 7;
$scale = 8;
$nullable = 10;
$column_def = 12;
$column_position = 16;
/**
* Discover primary key column(s) for this table.
*/
$sql = "exec sp_pkeys @table_name = " . $this->quoteIdentifier($tableName, true);
if ($schemaName != null) {
$sql .= ", @table_owner = " . $this->quoteIdentifier($schemaName, true);
}
$stmt = $this->query($sql);
$primaryKeysResult = $stmt->fetchAll(Zend_Db::FETCH_NUM);
$stmt->closeCursor();
$pkey_column_name = 3;
$pkey_key_seq = 4;
foreach ($primaryKeysResult as $pkeysRow) {
$primaryKeyColumn[$pkeysRow[$pkey_column_name]] = $pkeysRow[$pkey_key_seq];
}
$desc = array();
$p = 1;
foreach ($result as $key => $row) {
$identity = false;
$words = explode(' ', $row[$type_name], 2);
if (isset($words[0])) {
$type = $words[0];
if (isset($words[1])) {
$identity = (bool) preg_match('/identity/', $words[1]);
}
}
$isPrimary = array_key_exists($row[$column_name], $primaryKeyColumn);
if ($isPrimary) {
$primaryPosition = $primaryKeyColumn[$row[$column_name]];
} else {
$primaryPosition = null;
}
$desc[$this->foldCase($row[$column_name])] = array(
'SCHEMA_NAME' => null, // @todo
'TABLE_NAME' => $this->foldCase($row[$table_name]),
'COLUMN_NAME' => $this->foldCase($row[$column_name]),
'COLUMN_POSITION' => (int) $row[$column_position],
'DATA_TYPE' => $type,
'DEFAULT' => $row[$column_def],
'NULLABLE' => (bool) $row[$nullable],
'LENGTH' => $row[$length],
'SCALE' => $row[$scale],
'PRECISION' => $row[$precision],
'UNSIGNED' => null, // @todo
'PRIMARY' => $isPrimary,
'PRIMARY_POSITION' => $primaryPosition,
'IDENTITY' => $identity
);
}
return $desc;
}
/**
* Adds an adapter-specific LIMIT clause to the SELECT statement.
*
* @link http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html
*
* @param string $sql
* @param integer $count
* @param integer $offset OPTIONAL
* @return string
*/
public function limit($sql, $count, $offset = 0)
{
$count = intval($count);
if ($count <= 0) {
/** @see Zend_Db_Adapter_Exception */
require_once 'Zend/Db/Adapter/Exception.php';
throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid");
}
$offset = intval($offset);
if ($offset < 0) {
/** @see Zend_Db_Adapter_Exception */
require_once 'Zend/Db/Adapter/Exception.php';
throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid");
}
$sql = preg_replace(
'/^SELECT\s+(DISTINCT\s)?/i',
'SELECT $1TOP ' . ($count+$offset) . ' ',
$sql
);
if ($offset > 0) {
$orderby = stristr($sql, 'ORDER BY');
if ($orderby !== false) {
$orderParts = explode(',', substr($orderby, 8));
$pregReplaceCount = null;
$orderbyInverseParts = array();
foreach ($orderParts as $orderPart) {
$orderPart = rtrim($orderPart);
$inv = preg_replace('/\s+desc$/i', ' ASC', $orderPart, 1, $pregReplaceCount);
if ($pregReplaceCount) {
$orderbyInverseParts[] = $inv;
continue;
}
$inv = preg_replace('/\s+asc$/i', ' DESC', $orderPart, 1, $pregReplaceCount);
if ($pregReplaceCount) {
$orderbyInverseParts[] = $inv;
continue;
} else {
$orderbyInverseParts[] = $orderPart . ' DESC';
}
}
$orderbyInverse = 'ORDER BY ' . implode(', ', $orderbyInverseParts);
}
if (!is_null($this->getRowCount()) && ($count+$offset) > $this->getRowCount())
$count = $this->getRowCount() - $offset;
$sql = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $sql . ') AS inner_tbl';
if ($orderby !== false) {
$sql .= ' ' . $orderbyInverse . ' ';
}
$sql .= ') AS outer_tbl';
if ($orderby !== false) {
$sql .= ' ' . $orderby;
}
}
return $sql;
}
/**
* Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column.
*
* As a convention, on RDBMS brands that support sequences
* (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence
* from the arguments and returns the last id generated by that sequence.
* On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method
* returns the last value generated for such a column, and the table name
* argument is disregarded.
*
* Microsoft SQL Server does not support sequences, so the arguments to
* this method are ignored.
*
* @param string $tableName OPTIONAL Name of table.
* @param string $primaryKey OPTIONAL Name of primary key column.
* @return string
* @throws Zend_Db_Adapter_Exception
*/
public function lastInsertId($tableName = null, $primaryKey = null)
{
$sql = 'SELECT SCOPE_IDENTITY()';
return (int)$this->fetchOne($sql);
}
public function getServerVersion()
{
try {
$stmt = $this->query("SELECT SERVERPROPERTY('productversion')");
$result = $stmt->fetchAll(Zend_Db::FETCH_NUM);
if (count($result)) {
return $result[0][0];
}
return null;
} catch (PDOException $e) {
return null;
}
}
protected function _quote($value)
{
if (is_int($value)) {
return $value;
} elseif (is_float($value)) {
return sprintf('%F', $value);
}
/*
* Original
* return "'" . addcslashes($value, "\000\n\r\\'\"\032") . "'";
*/
$value = str_replace("'", "''", $value);
return "'" . addcslashes($value, "\000\n\r\032") . "'";
}
public function getRowCount()
{
return $this->_rowCount;
}
public function setRowCount($count)
{
$this->_rowCount = $count;
}
}
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Db
* @subpackage Adapter
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*
*/
/**
* Zend_Db_Adapter_Pdo_Abstract
*/
require_once 'Zend/Db/Adapter/Pdo/Abstract.php';
/**
* Class for connecting to ODBC System databases and performing common operations.
*
* @category Zend
* @package Zend_Db
* @subpackage Adapter
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Default_Plugin_Zend_Db_Adapter_Pdo_Odbc extends Zend_Db_Adapter_Pdo_Abstract
{
/**
* PDO type.
*
* @var string
*/
protected $_pdoType = 'odbc';
protected $_rowCount;
/**
* Keys are UPPERCASE SQL datatypes or the constants
* Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE.
*
* Values are:
* 0 = 32-bit integer
* 1 = 64-bit integer
* 2 = float or decimal
*
* @var array Associative array of datatypes to values 0, 1, or 2.
*/
protected $_numericDataTypes = array(
Zend_Db::INT_TYPE => Zend_Db::INT_TYPE,
Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE,
Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE,
'INT' => Zend_Db::INT_TYPE,
'SMALLINT' => Zend_Db::INT_TYPE,
'TINYINT' => Zend_Db::INT_TYPE,
'BIGINT' => Zend_Db::BIGINT_TYPE,
'DECIMAL' => Zend_Db::FLOAT_TYPE,
'FLOAT' => Zend_Db::FLOAT_TYPE,
'MONEY' => Zend_Db::FLOAT_TYPE,
'NUMERIC' => Zend_Db::FLOAT_TYPE,
'REAL' => Zend_Db::FLOAT_TYPE,
'SMALLMONEY' => Zend_Db::FLOAT_TYPE
);
/**
* Creates a PDO DSN for the adapter from $this->_config settings.
*
* @return string
*/
protected function _dsn()
{
// baseline of DSN parts
$dsn = $this->_config;
// don't pass the username and password in the DSN
unset($dsn['username']);
unset($dsn['password']);
unset($dsn['driver_options']);
unset($dsn['port']);
// this driver supports multiple DSN prefixes
// @see http://www.php.net/manual/en/ref.pdo-dblib.connection.php
if (isset($dsn['pdoType'])) {
switch (strtolower($dsn['pdoType'])) {
default:
$this->_pdoType = 'odbc';
break;
}
unset($dsn['pdoType']);
}
if (isset($dsn['dbname'])) {
$dsn = $this->_pdoType . ':' . $dsn['dbname'];
} else {
// use all remaining parts in the DSN
foreach ($dsn as $key => $val) {
$dsn[$key] = "$key=$val";
}
$dsn = $this->_pdoType . ':' . implode(';', $dsn);
}
return $dsn;
}
/**
* @return void
*/
protected function _connect()
{
if ($this->_connection) {
return;
}
parent::_connect();
$this->_connection->exec('SET QUOTED_IDENTIFIER ON');
}
/**
* Begin a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _beginTransaction()
{
$this->_connect();
$this->_connection->exec('BEGIN TRANSACTION');
return true;
}
/**
* Commit a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _commit()
{
$this->_connect();
$this->_connection->exec('COMMIT TRANSACTION');
return true;
}
/**
* Roll-back a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _rollBack() {
$this->_connect();
$this->_connection->exec('ROLLBACK TRANSACTION');
return true;
}
/**
* Returns a list of the tables in the database.
*
* @return array
*/
public function listTables()
{
$sql = "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name";
return $this->fetchCol($sql);
}
/**
* Returns the column descriptions for a table.
*
* The return value is an associative array keyed by the column name,
* as returned by the RDBMS.
*
* The value of each array element is an associative array
* with the following keys:
*
* SCHEMA_NAME => string; name of database or schema
* TABLE_NAME => string;
* COLUMN_NAME => string; column name
* COLUMN_POSITION => number; ordinal position of column in table
* DATA_TYPE => string; SQL datatype name of column
* DEFAULT => string; default expression of column, null if none
* NULLABLE => boolean; true if column can have nulls
* LENGTH => number; length of CHAR/VARCHAR
* SCALE => number; scale of NUMERIC/DECIMAL
* PRECISION => number; precision of NUMERIC/DECIMAL
* UNSIGNED => boolean; unsigned property of an integer type
* PRIMARY => boolean; true if column is part of the primary key
* PRIMARY_POSITION => integer; position of column in primary key
* PRIMARY_AUTO => integer; position of auto-generated column in primary key
*
* @todo Discover column primary key position.
* @todo Discover integer unsigned property.
*
* @param string $tableName
* @param string $schemaName OPTIONAL
* @return array
*/
public function describeTable($tableName, $schemaName = null)
{
if ($schemaName != null) {
if (strpos($schemaName, '.') !== false) {
$result = explode('.', $schemaName);
$schemaName = $result[1];
}
}
/**
* Discover metadata information about this table.
*/
$sql = "exec sp_columns @table_name = " . $this->quoteIdentifier($tableName, true);
if ($schemaName != null) {
$sql .= ", @table_owner = " . $this->quoteIdentifier($schemaName, true);
}
$stmt = $this->query($sql);
$result = $stmt->fetchAll(Zend_Db::FETCH_NUM);
$stmt->closeCursor();
$table_name = 2;
$column_name = 3;
$type_name = 5;
$precision = 6;
$length = 7;
$scale = 8;
$nullable = 10;
$column_def = 12;
$column_position = 16;
/**
* Discover primary key column(s) for this table.
*/
$sql = "exec sp_pkeys @table_name = " . $this->quoteIdentifier($tableName, true);
if ($schemaName != null) {
$sql .= ", @table_owner = " . $this->quoteIdentifier($schemaName, true);
}
$stmt = $this->query($sql);
$primaryKeysResult = $stmt->fetchAll(Zend_Db::FETCH_NUM);
$stmt->closeCursor();
$pkey_column_name = 3;
$pkey_key_seq = 4;
foreach ($primaryKeysResult as $pkeysRow) {
$primaryKeyColumn[$pkeysRow[$pkey_column_name]] = $pkeysRow[$pkey_key_seq];
}
$desc = array();
$p = 1;
foreach ($result as $key => $row) {
$identity = false;
$words = explode(' ', $row[$type_name], 2);
if (isset($words[0])) {
$type = $words[0];
if (isset($words[1])) {
$identity = (bool) preg_match('/identity/', $words[1]);
}
}
$isPrimary = array_key_exists($row[$column_name], $primaryKeyColumn);
if ($isPrimary) {
$primaryPosition = $primaryKeyColumn[$row[$column_name]];
} else {
$primaryPosition = null;
}
$desc[$this->foldCase($row[$column_name])] = array(
'SCHEMA_NAME' => null, // @todo
'TABLE_NAME' => $this->foldCase($row[$table_name]),
'COLUMN_NAME' => $this->foldCase($row[$column_name]),
'COLUMN_POSITION' => (int) $row[$column_position],
'DATA_TYPE' => $type,
'DEFAULT' => $row[$column_def],
'NULLABLE' => (bool) $row[$nullable],
'LENGTH' => $row[$length],
'SCALE' => $row[$scale],
'PRECISION' => $row[$precision],
'UNSIGNED' => null, // @todo
'PRIMARY' => $isPrimary,
'PRIMARY_POSITION' => $primaryPosition,
'IDENTITY' => $identity
);
}
return $desc;
}
/**
* Adds an adapter-specific LIMIT clause to the SELECT statement.
*
* @link http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html
*
* @param string $sql
* @param integer $count
* @param integer $offset OPTIONAL
* @return string
*/
public function limit($sql, $count, $offset = 0)
{
$count = intval($count);
if ($count <= 0) {
/** @see Zend_Db_Adapter_Exception */
require_once 'Zend/Db/Adapter/Exception.php';
throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid");
}
$offset = intval($offset);
if ($offset < 0) {
/** @see Zend_Db_Adapter_Exception */
require_once 'Zend/Db/Adapter/Exception.php';
throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid");
}
$sql = preg_replace(
'/^SELECT\s+(DISTINCT\s)?/i',
'SELECT $1TOP ' . ($count+$offset) . ' ',
$sql
);
if ($offset > 0) {
$orderby = stristr($sql, 'ORDER BY');
if ($orderby !== false) {
$orderParts = explode(',', substr($orderby, 8));
$pregReplaceCount = null;
$orderbyInverseParts = array();
foreach ($orderParts as $orderPart) {
$orderPart = rtrim($orderPart);
$inv = preg_replace('/\s+desc$/i', ' ASC', $orderPart, 1, $pregReplaceCount);
if ($pregReplaceCount) {
$orderbyInverseParts[] = $inv;
continue;
}
$inv = preg_replace('/\s+asc$/i', ' DESC', $orderPart, 1, $pregReplaceCount);
if ($pregReplaceCount) {
$orderbyInverseParts[] = $inv;
continue;
} else {
$orderbyInverseParts[] = $orderPart . ' DESC';
}
}
$orderbyInverse = 'ORDER BY ' . implode(', ', $orderbyInverseParts);
}
if (!is_null($this->getRowCount()) && ($count+$offset) > $this->getRowCount())
$count = $this->getRowCount() - $offset;
$sql = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $sql . ') AS inner_tbl';
if ($orderby !== false) {
$sql .= ' ' . $orderbyInverse . ' ';
}
$sql .= ') AS outer_tbl';
if ($orderby !== false) {
$sql .= ' ' . $orderby;
}
}
return $sql;
}
/**
* Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column.
*
* As a convention, on RDBMS brands that support sequences
* (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence
* from the arguments and returns the last id generated by that sequence.
* On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method
* returns the last value generated for such a column, and the table name
* argument is disregarded.
*
* Microsoft SQL Server does not support sequences, so the arguments to
* this method are ignored.
*
* @param string $tableName OPTIONAL Name of table.
* @param string $primaryKey OPTIONAL Name of primary key column.
* @return string
* @throws Zend_Db_Adapter_Exception
*/
public function lastInsertId($tableName = null, $primaryKey = null)
{
$sql = 'SELECT SCOPE_IDENTITY()';
return (int)$this->fetchOne($sql);
}
public function getServerVersion()
{
try {
$stmt = $this->query("SELECT SERVERPROPERTY('productversion')");
$result = $stmt->fetchAll(Zend_Db::FETCH_NUM);
if (count($result)) {
return $result[0][0];
}
return null;
} catch (PDOException $e) {
return null;
}
}
protected function _quote($value)
{
if (is_int($value)) {
return $value;
} elseif (is_float($value)) {
return sprintf('%F', $value);
}
/*
* Original
* return "'" . addcslashes($value, "\000\n\r\\'\"\032") . "'";
*/
$value = str_replace("'", "''", $value);
return "'" . addcslashes($value, "\000\n\r\032") . "'";
}
public function getRowCount()
{
return $this->_rowCount;
}
public function setRowCount($count)
{
$this->_rowCount = $count;
}
}
ラベル:
IIS,
PHP,
ZendFramework
2010年4月10日土曜日
Zend_Db_Adapter_Pdo_Odbc 不具合修正しました。
quoteをオーバーライドしているところで問題があったのを修正。
っていうか addslashes に第2パラメーターが存在したとは。。。
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Db
* @subpackage Adapter
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*
*/
/**
* Zend_Db_Adapter_Pdo_Abstract
*/
require_once 'Zend/Db/Adapter/Pdo/Abstract.php';
/**
* Class for connecting to ODBC System databases and performing common operations.
*
* @category Zend
* @package Zend_Db
* @subpackage Adapter
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Db_Adapter_Pdo_Odbc extends Zend_Db_Adapter_Pdo_Abstract
{
/**
* PDO type.
*
* @var string
*/
protected $_pdoType = 'odbc';
protected $_rowCount;
/**
* Keys are UPPERCASE SQL datatypes or the constants
* Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE.
*
* Values are:
* 0 = 32-bit integer
* 1 = 64-bit integer
* 2 = float or decimal
*
* @var array Associative array of datatypes to values 0, 1, or 2.
*/
protected $_numericDataTypes = array(
Zend_Db::INT_TYPE => Zend_Db::INT_TYPE,
Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE,
Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE,
'INT' => Zend_Db::INT_TYPE,
'SMALLINT' => Zend_Db::INT_TYPE,
'TINYINT' => Zend_Db::INT_TYPE,
'BIGINT' => Zend_Db::BIGINT_TYPE,
'DECIMAL' => Zend_Db::FLOAT_TYPE,
'FLOAT' => Zend_Db::FLOAT_TYPE,
'MONEY' => Zend_Db::FLOAT_TYPE,
'NUMERIC' => Zend_Db::FLOAT_TYPE,
'REAL' => Zend_Db::FLOAT_TYPE,
'SMALLMONEY' => Zend_Db::FLOAT_TYPE
);
/**
* Creates a PDO DSN for the adapter from $this->_config settings.
*
* @return string
*/
protected function _dsn()
{
// baseline of DSN parts
$dsn = $this->_config;
// don't pass the username and password in the DSN
unset($dsn['username']);
unset($dsn['password']);
unset($dsn['driver_options']);
unset($dsn['port']);
// this driver supports multiple DSN prefixes
// @see http://www.php.net/manual/en/ref.pdo-dblib.connection.php
if (isset($dsn['pdoType'])) {
switch (strtolower($dsn['pdoType'])) {
default:
$this->_pdoType = 'odbc';
break;
}
unset($dsn['pdoType']);
}
if (isset($dsn['dbname'])) {
$dsn = $this->_pdoType . ':' . $dsn['dbname'];
} else {
// use all remaining parts in the DSN
foreach ($dsn as $key => $val) {
$dsn[$key] = "$key=$val";
}
$dsn = $this->_pdoType . ':' . implode(';', $dsn);
}
return $dsn;
}
/**
* @return void
*/
protected function _connect()
{
if ($this->_connection) {
return;
}
parent::_connect();
$this->_connection->exec('SET QUOTED_IDENTIFIER ON');
}
/**
* Begin a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _beginTransaction()
{
$this->_connect();
$this->_connection->exec('BEGIN TRANSACTION');
return true;
}
/**
* Commit a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _commit()
{
$this->_connect();
$this->_connection->exec('COMMIT TRANSACTION');
return true;
}
/**
* Roll-back a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _rollBack() {
$this->_connect();
$this->_connection->exec('ROLLBACK TRANSACTION');
return true;
}
/**
* Returns a list of the tables in the database.
*
* @return array
*/
public function listTables()
{
$sql = "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name";
return $this->fetchCol($sql);
}
/**
* Returns the column descriptions for a table.
*
* The return value is an associative array keyed by the column name,
* as returned by the RDBMS.
*
* The value of each array element is an associative array
* with the following keys:
*
* SCHEMA_NAME => string; name of database or schema
* TABLE_NAME => string;
* COLUMN_NAME => string; column name
* COLUMN_POSITION => number; ordinal position of column in table
* DATA_TYPE => string; SQL datatype name of column
* DEFAULT => string; default expression of column, null if none
* NULLABLE => boolean; true if column can have nulls
* LENGTH => number; length of CHAR/VARCHAR
* SCALE => number; scale of NUMERIC/DECIMAL
* PRECISION => number; precision of NUMERIC/DECIMAL
* UNSIGNED => boolean; unsigned property of an integer type
* PRIMARY => boolean; true if column is part of the primary key
* PRIMARY_POSITION => integer; position of column in primary key
* PRIMARY_AUTO => integer; position of auto-generated column in primary key
*
* @todo Discover column primary key position.
* @todo Discover integer unsigned property.
*
* @param string $tableName
* @param string $schemaName OPTIONAL
* @return array
*/
public function describeTable($tableName, $schemaName = null)
{
if ($schemaName != null) {
if (strpos($schemaName, '.') !== false) {
$result = explode('.', $schemaName);
$schemaName = $result[1];
}
}
/**
* Discover metadata information about this table.
*/
$sql = "exec sp_columns @table_name = " . $this->quoteIdentifier($tableName, true);
if ($schemaName != null) {
$sql .= ", @table_owner = " . $this->quoteIdentifier($schemaName, true);
}
$stmt = $this->query($sql);
$result = $stmt->fetchAll(Zend_Db::FETCH_NUM);
$stmt->closeCursor();
$table_name = 2;
$column_name = 3;
$type_name = 5;
$precision = 6;
$length = 7;
$scale = 8;
$nullable = 10;
$column_def = 12;
$column_position = 16;
/**
* Discover primary key column(s) for this table.
*/
$sql = "exec sp_pkeys @table_name = " . $this->quoteIdentifier($tableName, true);
if ($schemaName != null) {
$sql .= ", @table_owner = " . $this->quoteIdentifier($schemaName, true);
}
$stmt = $this->query($sql);
$primaryKeysResult = $stmt->fetchAll(Zend_Db::FETCH_NUM);
$stmt->closeCursor();
$pkey_column_name = 3;
$pkey_key_seq = 4;
foreach ($primaryKeysResult as $pkeysRow) {
$primaryKeyColumn[$pkeysRow[$pkey_column_name]] = $pkeysRow[$pkey_key_seq];
}
$desc = array();
$p = 1;
foreach ($result as $key => $row) {
$identity = false;
$words = explode(' ', $row[$type_name], 2);
if (isset($words[0])) {
$type = $words[0];
if (isset($words[1])) {
$identity = (bool) preg_match('/identity/', $words[1]);
}
}
$isPrimary = array_key_exists($row[$column_name], $primaryKeyColumn);
if ($isPrimary) {
$primaryPosition = $primaryKeyColumn[$row[$column_name]];
} else {
$primaryPosition = null;
}
$desc[$this->foldCase($row[$column_name])] = array(
'SCHEMA_NAME' => null, // @todo
'TABLE_NAME' => $this->foldCase($row[$table_name]),
'COLUMN_NAME' => $this->foldCase($row[$column_name]),
'COLUMN_POSITION' => (int) $row[$column_position],
'DATA_TYPE' => $type,
'DEFAULT' => $row[$column_def],
'NULLABLE' => (bool) $row[$nullable],
'LENGTH' => $row[$length],
'SCALE' => $row[$scale],
'PRECISION' => $row[$precision],
'UNSIGNED' => null, // @todo
'PRIMARY' => $isPrimary,
'PRIMARY_POSITION' => $primaryPosition,
'IDENTITY' => $identity
);
}
return $desc;
}
/**
* Adds an adapter-specific LIMIT clause to the SELECT statement.
*
* @link http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html
*
* @param string $sql
* @param integer $count
* @param integer $offset OPTIONAL
* @return string
*/
public function limit($sql, $count, $offset = 0)
{
$count = intval($count);
if ($count <= 0) {
/** @see Zend_Db_Adapter_Exception */
require_once 'Zend/Db/Adapter/Exception.php';
throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid");
}
$offset = intval($offset);
if ($offset < 0) {
/** @see Zend_Db_Adapter_Exception */
require_once 'Zend/Db/Adapter/Exception.php';
throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid");
}
$sql = preg_replace(
'/^SELECT\s+(DISTINCT\s)?/i',
'SELECT $1TOP ' . ($count+$offset) . ' ',
$sql
);
if ($offset > 0) {
$orderby = stristr($sql, 'ORDER BY');
if ($orderby !== false) {
$orderParts = explode(',', substr($orderby, 8));
$pregReplaceCount = null;
$orderbyInverseParts = array();
foreach ($orderParts as $orderPart) {
$orderPart = rtrim($orderPart);
$inv = preg_replace('/\s+desc$/i', ' ASC', $orderPart, 1, $pregReplaceCount);
if ($pregReplaceCount) {
$orderbyInverseParts[] = $inv;
continue;
}
$inv = preg_replace('/\s+asc$/i', ' DESC', $orderPart, 1, $pregReplaceCount);
if ($pregReplaceCount) {
$orderbyInverseParts[] = $inv;
continue;
} else {
$orderbyInverseParts[] = $orderPart . ' DESC';
}
}
$orderbyInverse = 'ORDER BY ' . implode(', ', $orderbyInverseParts);
}
if (!is_null($this->getRowCount()) && ($count+$offset) > $this->getRowCount())
$count = $this->getRowCount() - $offset;
$sql = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $sql . ') AS inner_tbl';
if ($orderby !== false) {
$sql .= ' ' . $orderbyInverse . ' ';
}
$sql .= ') AS outer_tbl';
if ($orderby !== false) {
$sql .= ' ' . $orderby;
}
}
return $sql;
}
/**
* Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column.
*
* As a convention, on RDBMS brands that support sequences
* (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence
* from the arguments and returns the last id generated by that sequence.
* On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method
* returns the last value generated for such a column, and the table name
* argument is disregarded.
*
* Microsoft SQL Server does not support sequences, so the arguments to
* this method are ignored.
*
* @param string $tableName OPTIONAL Name of table.
* @param string $primaryKey OPTIONAL Name of primary key column.
* @return string
* @throws Zend_Db_Adapter_Exception
*/
public function lastInsertId($tableName = null, $primaryKey = null)
{
$sql = 'SELECT SCOPE_IDENTITY()';
return (int)$this->fetchOne($sql);
}
public function getServerVersion()
{
try {
$stmt = $this->query("SELECT SERVERPROPERTY('productversion')");
$result = $stmt->fetchAll(Zend_Db::FETCH_NUM);
if (count($result)) {
return $result[0][0];
}
return null;
} catch (PDOException $e) {
return null;
}
}
protected function _quote($value)
{
if (is_int($value)) {
return $value;
} elseif (is_float($value)) {
return sprintf('%F', $value);
}
/*
* Original
* return "'" . addcslashes($value, "\000\n\r\\'\"\032") . "'";
*/
return "'" . addcslashes($value, "\000\n\r'\"\032") . "'";
}
public function getRowCount()
{
return $this->_rowCount;
}
public function setRowCount($count)
{
$this->_rowCount = $count;
}
}
っていうか addslashes に第2パラメーターが存在したとは。。。
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Db
* @subpackage Adapter
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*
*/
/**
* Zend_Db_Adapter_Pdo_Abstract
*/
require_once 'Zend/Db/Adapter/Pdo/Abstract.php';
/**
* Class for connecting to ODBC System databases and performing common operations.
*
* @category Zend
* @package Zend_Db
* @subpackage Adapter
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Db_Adapter_Pdo_Odbc extends Zend_Db_Adapter_Pdo_Abstract
{
/**
* PDO type.
*
* @var string
*/
protected $_pdoType = 'odbc';
protected $_rowCount;
/**
* Keys are UPPERCASE SQL datatypes or the constants
* Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE.
*
* Values are:
* 0 = 32-bit integer
* 1 = 64-bit integer
* 2 = float or decimal
*
* @var array Associative array of datatypes to values 0, 1, or 2.
*/
protected $_numericDataTypes = array(
Zend_Db::INT_TYPE => Zend_Db::INT_TYPE,
Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE,
Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE,
'INT' => Zend_Db::INT_TYPE,
'SMALLINT' => Zend_Db::INT_TYPE,
'TINYINT' => Zend_Db::INT_TYPE,
'BIGINT' => Zend_Db::BIGINT_TYPE,
'DECIMAL' => Zend_Db::FLOAT_TYPE,
'FLOAT' => Zend_Db::FLOAT_TYPE,
'MONEY' => Zend_Db::FLOAT_TYPE,
'NUMERIC' => Zend_Db::FLOAT_TYPE,
'REAL' => Zend_Db::FLOAT_TYPE,
'SMALLMONEY' => Zend_Db::FLOAT_TYPE
);
/**
* Creates a PDO DSN for the adapter from $this->_config settings.
*
* @return string
*/
protected function _dsn()
{
// baseline of DSN parts
$dsn = $this->_config;
// don't pass the username and password in the DSN
unset($dsn['username']);
unset($dsn['password']);
unset($dsn['driver_options']);
unset($dsn['port']);
// this driver supports multiple DSN prefixes
// @see http://www.php.net/manual/en/ref.pdo-dblib.connection.php
if (isset($dsn['pdoType'])) {
switch (strtolower($dsn['pdoType'])) {
default:
$this->_pdoType = 'odbc';
break;
}
unset($dsn['pdoType']);
}
if (isset($dsn['dbname'])) {
$dsn = $this->_pdoType . ':' . $dsn['dbname'];
} else {
// use all remaining parts in the DSN
foreach ($dsn as $key => $val) {
$dsn[$key] = "$key=$val";
}
$dsn = $this->_pdoType . ':' . implode(';', $dsn);
}
return $dsn;
}
/**
* @return void
*/
protected function _connect()
{
if ($this->_connection) {
return;
}
parent::_connect();
$this->_connection->exec('SET QUOTED_IDENTIFIER ON');
}
/**
* Begin a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _beginTransaction()
{
$this->_connect();
$this->_connection->exec('BEGIN TRANSACTION');
return true;
}
/**
* Commit a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _commit()
{
$this->_connect();
$this->_connection->exec('COMMIT TRANSACTION');
return true;
}
/**
* Roll-back a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _rollBack() {
$this->_connect();
$this->_connection->exec('ROLLBACK TRANSACTION');
return true;
}
/**
* Returns a list of the tables in the database.
*
* @return array
*/
public function listTables()
{
$sql = "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name";
return $this->fetchCol($sql);
}
/**
* Returns the column descriptions for a table.
*
* The return value is an associative array keyed by the column name,
* as returned by the RDBMS.
*
* The value of each array element is an associative array
* with the following keys:
*
* SCHEMA_NAME => string; name of database or schema
* TABLE_NAME => string;
* COLUMN_NAME => string; column name
* COLUMN_POSITION => number; ordinal position of column in table
* DATA_TYPE => string; SQL datatype name of column
* DEFAULT => string; default expression of column, null if none
* NULLABLE => boolean; true if column can have nulls
* LENGTH => number; length of CHAR/VARCHAR
* SCALE => number; scale of NUMERIC/DECIMAL
* PRECISION => number; precision of NUMERIC/DECIMAL
* UNSIGNED => boolean; unsigned property of an integer type
* PRIMARY => boolean; true if column is part of the primary key
* PRIMARY_POSITION => integer; position of column in primary key
* PRIMARY_AUTO => integer; position of auto-generated column in primary key
*
* @todo Discover column primary key position.
* @todo Discover integer unsigned property.
*
* @param string $tableName
* @param string $schemaName OPTIONAL
* @return array
*/
public function describeTable($tableName, $schemaName = null)
{
if ($schemaName != null) {
if (strpos($schemaName, '.') !== false) {
$result = explode('.', $schemaName);
$schemaName = $result[1];
}
}
/**
* Discover metadata information about this table.
*/
$sql = "exec sp_columns @table_name = " . $this->quoteIdentifier($tableName, true);
if ($schemaName != null) {
$sql .= ", @table_owner = " . $this->quoteIdentifier($schemaName, true);
}
$stmt = $this->query($sql);
$result = $stmt->fetchAll(Zend_Db::FETCH_NUM);
$stmt->closeCursor();
$table_name = 2;
$column_name = 3;
$type_name = 5;
$precision = 6;
$length = 7;
$scale = 8;
$nullable = 10;
$column_def = 12;
$column_position = 16;
/**
* Discover primary key column(s) for this table.
*/
$sql = "exec sp_pkeys @table_name = " . $this->quoteIdentifier($tableName, true);
if ($schemaName != null) {
$sql .= ", @table_owner = " . $this->quoteIdentifier($schemaName, true);
}
$stmt = $this->query($sql);
$primaryKeysResult = $stmt->fetchAll(Zend_Db::FETCH_NUM);
$stmt->closeCursor();
$pkey_column_name = 3;
$pkey_key_seq = 4;
foreach ($primaryKeysResult as $pkeysRow) {
$primaryKeyColumn[$pkeysRow[$pkey_column_name]] = $pkeysRow[$pkey_key_seq];
}
$desc = array();
$p = 1;
foreach ($result as $key => $row) {
$identity = false;
$words = explode(' ', $row[$type_name], 2);
if (isset($words[0])) {
$type = $words[0];
if (isset($words[1])) {
$identity = (bool) preg_match('/identity/', $words[1]);
}
}
$isPrimary = array_key_exists($row[$column_name], $primaryKeyColumn);
if ($isPrimary) {
$primaryPosition = $primaryKeyColumn[$row[$column_name]];
} else {
$primaryPosition = null;
}
$desc[$this->foldCase($row[$column_name])] = array(
'SCHEMA_NAME' => null, // @todo
'TABLE_NAME' => $this->foldCase($row[$table_name]),
'COLUMN_NAME' => $this->foldCase($row[$column_name]),
'COLUMN_POSITION' => (int) $row[$column_position],
'DATA_TYPE' => $type,
'DEFAULT' => $row[$column_def],
'NULLABLE' => (bool) $row[$nullable],
'LENGTH' => $row[$length],
'SCALE' => $row[$scale],
'PRECISION' => $row[$precision],
'UNSIGNED' => null, // @todo
'PRIMARY' => $isPrimary,
'PRIMARY_POSITION' => $primaryPosition,
'IDENTITY' => $identity
);
}
return $desc;
}
/**
* Adds an adapter-specific LIMIT clause to the SELECT statement.
*
* @link http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html
*
* @param string $sql
* @param integer $count
* @param integer $offset OPTIONAL
* @return string
*/
public function limit($sql, $count, $offset = 0)
{
$count = intval($count);
if ($count <= 0) {
/** @see Zend_Db_Adapter_Exception */
require_once 'Zend/Db/Adapter/Exception.php';
throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid");
}
$offset = intval($offset);
if ($offset < 0) {
/** @see Zend_Db_Adapter_Exception */
require_once 'Zend/Db/Adapter/Exception.php';
throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid");
}
$sql = preg_replace(
'/^SELECT\s+(DISTINCT\s)?/i',
'SELECT $1TOP ' . ($count+$offset) . ' ',
$sql
);
if ($offset > 0) {
$orderby = stristr($sql, 'ORDER BY');
if ($orderby !== false) {
$orderParts = explode(',', substr($orderby, 8));
$pregReplaceCount = null;
$orderbyInverseParts = array();
foreach ($orderParts as $orderPart) {
$orderPart = rtrim($orderPart);
$inv = preg_replace('/\s+desc$/i', ' ASC', $orderPart, 1, $pregReplaceCount);
if ($pregReplaceCount) {
$orderbyInverseParts[] = $inv;
continue;
}
$inv = preg_replace('/\s+asc$/i', ' DESC', $orderPart, 1, $pregReplaceCount);
if ($pregReplaceCount) {
$orderbyInverseParts[] = $inv;
continue;
} else {
$orderbyInverseParts[] = $orderPart . ' DESC';
}
}
$orderbyInverse = 'ORDER BY ' . implode(', ', $orderbyInverseParts);
}
if (!is_null($this->getRowCount()) && ($count+$offset) > $this->getRowCount())
$count = $this->getRowCount() - $offset;
$sql = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $sql . ') AS inner_tbl';
if ($orderby !== false) {
$sql .= ' ' . $orderbyInverse . ' ';
}
$sql .= ') AS outer_tbl';
if ($orderby !== false) {
$sql .= ' ' . $orderby;
}
}
return $sql;
}
/**
* Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column.
*
* As a convention, on RDBMS brands that support sequences
* (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence
* from the arguments and returns the last id generated by that sequence.
* On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method
* returns the last value generated for such a column, and the table name
* argument is disregarded.
*
* Microsoft SQL Server does not support sequences, so the arguments to
* this method are ignored.
*
* @param string $tableName OPTIONAL Name of table.
* @param string $primaryKey OPTIONAL Name of primary key column.
* @return string
* @throws Zend_Db_Adapter_Exception
*/
public function lastInsertId($tableName = null, $primaryKey = null)
{
$sql = 'SELECT SCOPE_IDENTITY()';
return (int)$this->fetchOne($sql);
}
public function getServerVersion()
{
try {
$stmt = $this->query("SELECT SERVERPROPERTY('productversion')");
$result = $stmt->fetchAll(Zend_Db::FETCH_NUM);
if (count($result)) {
return $result[0][0];
}
return null;
} catch (PDOException $e) {
return null;
}
}
protected function _quote($value)
{
if (is_int($value)) {
return $value;
} elseif (is_float($value)) {
return sprintf('%F', $value);
}
/*
* Original
* return "'" . addcslashes($value, "\000\n\r\\'\"\032") . "'";
*/
return "'" . addcslashes($value, "\000\n\r'\"\032") . "'";
}
public function getRowCount()
{
return $this->_rowCount;
}
public function setRowCount($count)
{
$this->_rowCount = $count;
}
}
2010年4月8日木曜日
ゲーム Number Touth で遊んでみた
今 Number Touch がちょっと周りでブームになってますw
tって言っても周りにAndroidユーザーはまだ4人しかいないんですが。。。
ルールは画面上に表示された数字を順番に押していくというシンプルなゲームです。
15秒以下が難しい領域でしょうか?
10秒を切った人はまだ回りにいません。。。
最高で11秒台でした。
こんな感じの画面です。
非常にシンプルですねw
tって言っても周りにAndroidユーザーはまだ4人しかいないんですが。。。
ルールは画面上に表示された数字を順番に押していくというシンプルなゲームです。
15秒以下が難しい領域でしょうか?
10秒を切った人はまだ回りにいません。。。
最高で11秒台でした。
こんな感じの画面です。
非常にシンプルですねw
My docomo checker で利用料金を確認する。
今回紹介するのは今さらながら「My docomo checker」というあぷりです。もちろん無料です。
こいつはMyDocomoというドコモが提供する利用料金等が解るサイトを閲覧するためのアプリです。
本来ならドコモから出てもよさそうなアプリですが。。。
利用する前にはMy docomoでアカウントを取得しておく必要があります。
こんな感じで利用料を確認できます。
かなり見やすいですね♪
無料通信分「超5328円」って見た時、定額を何故か越えているのかと思いました。。。
グラフでも出るようです。
ちなみにこのアプリ恐らくWi-fi経由だと利用できないかと。。。
Pocket Wi-fi を利用している時は利用できなかったので。。。
2010年4月6日火曜日
PDO_ODBC + SQL Server でInsertしたシーケンスIDが取得できない
PDO_ODBCには「PDO::lastInsertId」というものが用意されているが、ドライバーが対応していないというエラーで利用する事ができなかった。。。
http://www.php.net/manual/ja/pdo.lastinsertid.php
そこでZend_Frameworkの中でZend_Db_Adpter_Pdo_Mssqlで記述されていた、
public function lastInsertId($tableName = null, $primaryKey = null)
{
$sql = 'SELECT SCOPE_IDENTITY()';
return (int)$this->fetchOne($sql);
}
を試してみた。
しかし、取得されるのは常に0。。。
なぜ。。。
どうしようもないし、Zend_Db_Adpter_Pdo_Mssqlだとうまく取得できるのでそこだけ一先ず、Zend_Db_Adpter_Pdo_Mssqlを利用するようにした。。。
http://www.php.net/manual/ja/pdo.lastinsertid.php
そこでZend_Frameworkの中でZend_Db_Adpter_Pdo_Mssqlで記述されていた、
public function lastInsertId($tableName = null, $primaryKey = null)
{
$sql = 'SELECT SCOPE_IDENTITY()';
return (int)$this->fetchOne($sql);
}
を試してみた。
しかし、取得されるのは常に0。。。
なぜ。。。
どうしようもないし、Zend_Db_Adpter_Pdo_Mssqlだとうまく取得できるのでそこだけ一先ず、Zend_Db_Adpter_Pdo_Mssqlを利用するようにした。。。
2010年4月5日月曜日
SQL Server 用に Zend_Db_Adapter_Pdo_Odbc を作ってみた
Zend_Db_Adapter_Pdo_Mssql には不具合が多いので、結局ODBCで対応するようにした。。。
てか Zend_Db_Adapter_Pdo_Odbc が無いので作った。。。
ちなみに今回の問題は4086バイト(?)以上の値を1カラムに保存してSELECTして取得しようとすると4096バイト辺りまでしか取得できないという最悪な不具合。。。
さすがにこれはモジュールの問題なようだったので、諦めた。。。
最初からODBCでやればよかった。。。
下記がソース。
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Db
* @subpackage Adapter
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*
*/
/**
* Zend_Db_Adapter_Pdo_Abstract
*/
require_once 'Zend/Db/Adapter/Pdo/Abstract.php';
/**
* Class for connecting to ODBC System databases and performing common operations.
*
* @category Zend
* @package Zend_Db
* @subpackage Adapter
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Db_Adapter_Pdo_Odbc extends Zend_Db_Adapter_Pdo_Abstract
{
/**
* PDO type.
*
* @var string
*/
protected $_pdoType = 'odbc';
protected $_rowCount;
/**
* Keys are UPPERCASE SQL datatypes or the constants
* Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE.
*
* Values are:
* 0 = 32-bit integer
* 1 = 64-bit integer
* 2 = float or decimal
*
* @var array Associative array of datatypes to values 0, 1, or 2.
*/
protected $_numericDataTypes = array(
Zend_Db::INT_TYPE => Zend_Db::INT_TYPE,
Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE,
Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE,
'INT' => Zend_Db::INT_TYPE,
'SMALLINT' => Zend_Db::INT_TYPE,
'TINYINT' => Zend_Db::INT_TYPE,
'BIGINT' => Zend_Db::BIGINT_TYPE,
'DECIMAL' => Zend_Db::FLOAT_TYPE,
'FLOAT' => Zend_Db::FLOAT_TYPE,
'MONEY' => Zend_Db::FLOAT_TYPE,
'NUMERIC' => Zend_Db::FLOAT_TYPE,
'REAL' => Zend_Db::FLOAT_TYPE,
'SMALLMONEY' => Zend_Db::FLOAT_TYPE
);
/**
* Creates a PDO DSN for the adapter from $this->_config settings.
*
* @return string
*/
protected function _dsn()
{
// baseline of DSN parts
$dsn = $this->_config;
// don't pass the username and password in the DSN
unset($dsn['username']);
unset($dsn['password']);
unset($dsn['driver_options']);
unset($dsn['port']);
// this driver supports multiple DSN prefixes
// @see http://www.php.net/manual/en/ref.pdo-dblib.connection.php
if (isset($dsn['pdoType'])) {
switch (strtolower($dsn['pdoType'])) {
default:
$this->_pdoType = 'odbc';
break;
}
unset($dsn['pdoType']);
}
if (isset($dsn['dbname'])) {
$dsn = $this->_pdoType . ':' . $dsn['dbname'];
} else {
// use all remaining parts in the DSN
foreach ($dsn as $key => $val) {
$dsn[$key] = "$key=$val";
}
$dsn = $this->_pdoType . ':' . implode(';', $dsn);
}
return $dsn;
}
/**
* @return void
*/
protected function _connect()
{
if ($this->_connection) {
return;
}
parent::_connect();
$this->_connection->exec('SET QUOTED_IDENTIFIER ON');
}
/**
* Begin a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _beginTransaction()
{
$this->_connect();
$this->_connection->exec('BEGIN TRANSACTION');
return true;
}
/**
* Commit a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _commit()
{
$this->_connect();
$this->_connection->exec('COMMIT TRANSACTION');
return true;
}
/**
* Roll-back a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _rollBack() {
$this->_connect();
$this->_connection->exec('ROLLBACK TRANSACTION');
return true;
}
/**
* Returns a list of the tables in the database.
*
* @return array
*/
public function listTables()
{
$sql = "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name";
return $this->fetchCol($sql);
}
/**
* Returns the column descriptions for a table.
*
* The return value is an associative array keyed by the column name,
* as returned by the RDBMS.
*
* The value of each array element is an associative array
* with the following keys:
*
* SCHEMA_NAME => string; name of database or schema
* TABLE_NAME => string;
* COLUMN_NAME => string; column name
* COLUMN_POSITION => number; ordinal position of column in table
* DATA_TYPE => string; SQL datatype name of column
* DEFAULT => string; default expression of column, null if none
* NULLABLE => boolean; true if column can have nulls
* LENGTH => number; length of CHAR/VARCHAR
* SCALE => number; scale of NUMERIC/DECIMAL
* PRECISION => number; precision of NUMERIC/DECIMAL
* UNSIGNED => boolean; unsigned property of an integer type
* PRIMARY => boolean; true if column is part of the primary key
* PRIMARY_POSITION => integer; position of column in primary key
* PRIMARY_AUTO => integer; position of auto-generated column in primary key
*
* @todo Discover column primary key position.
* @todo Discover integer unsigned property.
*
* @param string $tableName
* @param string $schemaName OPTIONAL
* @return array
*/
public function describeTable($tableName, $schemaName = null)
{
if ($schemaName != null) {
if (strpos($schemaName, '.') !== false) {
$result = explode('.', $schemaName);
$schemaName = $result[1];
}
}
/**
* Discover metadata information about this table.
*/
$sql = "exec sp_columns @table_name = " . $this->quoteIdentifier($tableName, true);
if ($schemaName != null) {
$sql .= ", @table_owner = " . $this->quoteIdentifier($schemaName, true);
}
$stmt = $this->query($sql);
$result = $stmt->fetchAll(Zend_Db::FETCH_NUM);
$stmt->closeCursor();
$table_name = 2;
$column_name = 3;
$type_name = 5;
$precision = 6;
$length = 7;
$scale = 8;
$nullable = 10;
$column_def = 12;
$column_position = 16;
/**
* Discover primary key column(s) for this table.
*/
$sql = "exec sp_pkeys @table_name = " . $this->quoteIdentifier($tableName, true);
if ($schemaName != null) {
$sql .= ", @table_owner = " . $this->quoteIdentifier($schemaName, true);
}
$stmt = $this->query($sql);
$primaryKeysResult = $stmt->fetchAll(Zend_Db::FETCH_NUM);
$stmt->closeCursor();
$pkey_column_name = 3;
$pkey_key_seq = 4;
foreach ($primaryKeysResult as $pkeysRow) {
$primaryKeyColumn[$pkeysRow[$pkey_column_name]] = $pkeysRow[$pkey_key_seq];
}
$desc = array();
$p = 1;
foreach ($result as $key => $row) {
$identity = false;
$words = explode(' ', $row[$type_name], 2);
if (isset($words[0])) {
$type = $words[0];
if (isset($words[1])) {
$identity = (bool) preg_match('/identity/', $words[1]);
}
}
$isPrimary = array_key_exists($row[$column_name], $primaryKeyColumn);
if ($isPrimary) {
$primaryPosition = $primaryKeyColumn[$row[$column_name]];
} else {
$primaryPosition = null;
}
$desc[$this->foldCase($row[$column_name])] = array(
'SCHEMA_NAME' => null, // @todo
'TABLE_NAME' => $this->foldCase($row[$table_name]),
'COLUMN_NAME' => $this->foldCase($row[$column_name]),
'COLUMN_POSITION' => (int) $row[$column_position],
'DATA_TYPE' => $type,
'DEFAULT' => $row[$column_def],
'NULLABLE' => (bool) $row[$nullable],
'LENGTH' => $row[$length],
'SCALE' => $row[$scale],
'PRECISION' => $row[$precision],
'UNSIGNED' => null, // @todo
'PRIMARY' => $isPrimary,
'PRIMARY_POSITION' => $primaryPosition,
'IDENTITY' => $identity
);
}
return $desc;
}
/**
* Adds an adapter-specific LIMIT clause to the SELECT statement.
*
* @link http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html
*
* @param string $sql
* @param integer $count
* @param integer $offset OPTIONAL
* @return string
*/
public function limit($sql, $count, $offset = 0)
{
$count = intval($count);
if ($count <= 0) {
/** @see Zend_Db_Adapter_Exception */
require_once 'Zend/Db/Adapter/Exception.php';
throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid");
}
$offset = intval($offset);
if ($offset < 0) {
/** @see Zend_Db_Adapter_Exception */
require_once 'Zend/Db/Adapter/Exception.php';
throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid");
}
$sql = preg_replace(
'/^SELECT\s+(DISTINCT\s)?/i',
'SELECT $1TOP ' . ($count+$offset) . ' ',
$sql
);
if ($offset > 0) {
$orderby = stristr($sql, 'ORDER BY');
if ($orderby !== false) {
$orderParts = explode(',', substr($orderby, 8));
$pregReplaceCount = null;
$orderbyInverseParts = array();
foreach ($orderParts as $orderPart) {
$orderPart = rtrim($orderPart);
$inv = preg_replace('/\s+desc$/i', ' ASC', $orderPart, 1, $pregReplaceCount);
if ($pregReplaceCount) {
$orderbyInverseParts[] = $inv;
continue;
}
$inv = preg_replace('/\s+asc$/i', ' DESC', $orderPart, 1, $pregReplaceCount);
if ($pregReplaceCount) {
$orderbyInverseParts[] = $inv;
continue;
} else {
$orderbyInverseParts[] = $orderPart . ' DESC';
}
}
$orderbyInverse = 'ORDER BY ' . implode(', ', $orderbyInverseParts);
}
if (!is_null($this->getRowCount()) && ($count+$offset) > $this->getRowCount())
$count = $this->getRowCount() - $offset;
$sql = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $sql . ') AS inner_tbl';
if ($orderby !== false) {
$sql .= ' ' . $orderbyInverse . ' ';
}
$sql .= ') AS outer_tbl';
if ($orderby !== false) {
$sql .= ' ' . $orderby;
}
}
return $sql;
}
/**
* Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column.
*
* As a convention, on RDBMS brands that support sequences
* (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence
* from the arguments and returns the last id generated by that sequence.
* On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method
* returns the last value generated for such a column, and the table name
* argument is disregarded.
*
* Microsoft SQL Server does not support sequences, so the arguments to
* this method are ignored.
*
* @param string $tableName OPTIONAL Name of table.
* @param string $primaryKey OPTIONAL Name of primary key column.
* @return string
* @throws Zend_Db_Adapter_Exception
*/
public function lastInsertId($tableName = null, $primaryKey = null)
{
$sql = 'SELECT SCOPE_IDENTITY()';
return (int)$this->fetchOne($sql);
}
public function getServerVersion()
{
try {
$stmt = $this->query("SELECT SERVERPROPERTY('productversion')");
$result = $stmt->fetchAll(Zend_Db::FETCH_NUM);
if (count($result)) {
return $result[0][0];
}
return null;
} catch (PDOException $e) {
return null;
}
}
public function quote($value)
{
if (is_int($value) || is_float($value)) {
return $value;
}
else if (is_array($value)) {
$values = array();
foreach ($value as $_val) {
if (is_int($_val) || is_float($_val)) {
$values[] = $_val;
}
else {
$values[] = "'".addslashes($_val)."'";
}
}
return join(',', $values);
}
return "'".addslashes($value)."'";
}
public function getRowCount()
{
return $this->_rowCount;
}
public function setRowCount($count)
{
$this->_rowCount = $count;
}
}
てか Zend_Db_Adapter_Pdo_Odbc が無いので作った。。。
ちなみに今回の問題は4086バイト(?)以上の値を1カラムに保存してSELECTして取得しようとすると4096バイト辺りまでしか取得できないという最悪な不具合。。。
さすがにこれはモジュールの問題なようだったので、諦めた。。。
最初からODBCでやればよかった。。。
下記がソース。
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license@zend.com so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Db
* @subpackage Adapter
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*
*/
/**
* Zend_Db_Adapter_Pdo_Abstract
*/
require_once 'Zend/Db/Adapter/Pdo/Abstract.php';
/**
* Class for connecting to ODBC System databases and performing common operations.
*
* @category Zend
* @package Zend_Db
* @subpackage Adapter
* @copyright Copyright (c) 2005-2007 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Db_Adapter_Pdo_Odbc extends Zend_Db_Adapter_Pdo_Abstract
{
/**
* PDO type.
*
* @var string
*/
protected $_pdoType = 'odbc';
protected $_rowCount;
/**
* Keys are UPPERCASE SQL datatypes or the constants
* Zend_Db::INT_TYPE, Zend_Db::BIGINT_TYPE, or Zend_Db::FLOAT_TYPE.
*
* Values are:
* 0 = 32-bit integer
* 1 = 64-bit integer
* 2 = float or decimal
*
* @var array Associative array of datatypes to values 0, 1, or 2.
*/
protected $_numericDataTypes = array(
Zend_Db::INT_TYPE => Zend_Db::INT_TYPE,
Zend_Db::BIGINT_TYPE => Zend_Db::BIGINT_TYPE,
Zend_Db::FLOAT_TYPE => Zend_Db::FLOAT_TYPE,
'INT' => Zend_Db::INT_TYPE,
'SMALLINT' => Zend_Db::INT_TYPE,
'TINYINT' => Zend_Db::INT_TYPE,
'BIGINT' => Zend_Db::BIGINT_TYPE,
'DECIMAL' => Zend_Db::FLOAT_TYPE,
'FLOAT' => Zend_Db::FLOAT_TYPE,
'MONEY' => Zend_Db::FLOAT_TYPE,
'NUMERIC' => Zend_Db::FLOAT_TYPE,
'REAL' => Zend_Db::FLOAT_TYPE,
'SMALLMONEY' => Zend_Db::FLOAT_TYPE
);
/**
* Creates a PDO DSN for the adapter from $this->_config settings.
*
* @return string
*/
protected function _dsn()
{
// baseline of DSN parts
$dsn = $this->_config;
// don't pass the username and password in the DSN
unset($dsn['username']);
unset($dsn['password']);
unset($dsn['driver_options']);
unset($dsn['port']);
// this driver supports multiple DSN prefixes
// @see http://www.php.net/manual/en/ref.pdo-dblib.connection.php
if (isset($dsn['pdoType'])) {
switch (strtolower($dsn['pdoType'])) {
default:
$this->_pdoType = 'odbc';
break;
}
unset($dsn['pdoType']);
}
if (isset($dsn['dbname'])) {
$dsn = $this->_pdoType . ':' . $dsn['dbname'];
} else {
// use all remaining parts in the DSN
foreach ($dsn as $key => $val) {
$dsn[$key] = "$key=$val";
}
$dsn = $this->_pdoType . ':' . implode(';', $dsn);
}
return $dsn;
}
/**
* @return void
*/
protected function _connect()
{
if ($this->_connection) {
return;
}
parent::_connect();
$this->_connection->exec('SET QUOTED_IDENTIFIER ON');
}
/**
* Begin a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _beginTransaction()
{
$this->_connect();
$this->_connection->exec('BEGIN TRANSACTION');
return true;
}
/**
* Commit a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _commit()
{
$this->_connect();
$this->_connection->exec('COMMIT TRANSACTION');
return true;
}
/**
* Roll-back a transaction.
*
* It is necessary to override the abstract PDO transaction functions here, as
* the PDO driver for MSSQL does not support transactions.
*/
protected function _rollBack() {
$this->_connect();
$this->_connection->exec('ROLLBACK TRANSACTION');
return true;
}
/**
* Returns a list of the tables in the database.
*
* @return array
*/
public function listTables()
{
$sql = "SELECT name FROM sysobjects WHERE type = 'U' ORDER BY name";
return $this->fetchCol($sql);
}
/**
* Returns the column descriptions for a table.
*
* The return value is an associative array keyed by the column name,
* as returned by the RDBMS.
*
* The value of each array element is an associative array
* with the following keys:
*
* SCHEMA_NAME => string; name of database or schema
* TABLE_NAME => string;
* COLUMN_NAME => string; column name
* COLUMN_POSITION => number; ordinal position of column in table
* DATA_TYPE => string; SQL datatype name of column
* DEFAULT => string; default expression of column, null if none
* NULLABLE => boolean; true if column can have nulls
* LENGTH => number; length of CHAR/VARCHAR
* SCALE => number; scale of NUMERIC/DECIMAL
* PRECISION => number; precision of NUMERIC/DECIMAL
* UNSIGNED => boolean; unsigned property of an integer type
* PRIMARY => boolean; true if column is part of the primary key
* PRIMARY_POSITION => integer; position of column in primary key
* PRIMARY_AUTO => integer; position of auto-generated column in primary key
*
* @todo Discover column primary key position.
* @todo Discover integer unsigned property.
*
* @param string $tableName
* @param string $schemaName OPTIONAL
* @return array
*/
public function describeTable($tableName, $schemaName = null)
{
if ($schemaName != null) {
if (strpos($schemaName, '.') !== false) {
$result = explode('.', $schemaName);
$schemaName = $result[1];
}
}
/**
* Discover metadata information about this table.
*/
$sql = "exec sp_columns @table_name = " . $this->quoteIdentifier($tableName, true);
if ($schemaName != null) {
$sql .= ", @table_owner = " . $this->quoteIdentifier($schemaName, true);
}
$stmt = $this->query($sql);
$result = $stmt->fetchAll(Zend_Db::FETCH_NUM);
$stmt->closeCursor();
$table_name = 2;
$column_name = 3;
$type_name = 5;
$precision = 6;
$length = 7;
$scale = 8;
$nullable = 10;
$column_def = 12;
$column_position = 16;
/**
* Discover primary key column(s) for this table.
*/
$sql = "exec sp_pkeys @table_name = " . $this->quoteIdentifier($tableName, true);
if ($schemaName != null) {
$sql .= ", @table_owner = " . $this->quoteIdentifier($schemaName, true);
}
$stmt = $this->query($sql);
$primaryKeysResult = $stmt->fetchAll(Zend_Db::FETCH_NUM);
$stmt->closeCursor();
$pkey_column_name = 3;
$pkey_key_seq = 4;
foreach ($primaryKeysResult as $pkeysRow) {
$primaryKeyColumn[$pkeysRow[$pkey_column_name]] = $pkeysRow[$pkey_key_seq];
}
$desc = array();
$p = 1;
foreach ($result as $key => $row) {
$identity = false;
$words = explode(' ', $row[$type_name], 2);
if (isset($words[0])) {
$type = $words[0];
if (isset($words[1])) {
$identity = (bool) preg_match('/identity/', $words[1]);
}
}
$isPrimary = array_key_exists($row[$column_name], $primaryKeyColumn);
if ($isPrimary) {
$primaryPosition = $primaryKeyColumn[$row[$column_name]];
} else {
$primaryPosition = null;
}
$desc[$this->foldCase($row[$column_name])] = array(
'SCHEMA_NAME' => null, // @todo
'TABLE_NAME' => $this->foldCase($row[$table_name]),
'COLUMN_NAME' => $this->foldCase($row[$column_name]),
'COLUMN_POSITION' => (int) $row[$column_position],
'DATA_TYPE' => $type,
'DEFAULT' => $row[$column_def],
'NULLABLE' => (bool) $row[$nullable],
'LENGTH' => $row[$length],
'SCALE' => $row[$scale],
'PRECISION' => $row[$precision],
'UNSIGNED' => null, // @todo
'PRIMARY' => $isPrimary,
'PRIMARY_POSITION' => $primaryPosition,
'IDENTITY' => $identity
);
}
return $desc;
}
/**
* Adds an adapter-specific LIMIT clause to the SELECT statement.
*
* @link http://lists.bestpractical.com/pipermail/rt-devel/2005-June/007339.html
*
* @param string $sql
* @param integer $count
* @param integer $offset OPTIONAL
* @return string
*/
public function limit($sql, $count, $offset = 0)
{
$count = intval($count);
if ($count <= 0) {
/** @see Zend_Db_Adapter_Exception */
require_once 'Zend/Db/Adapter/Exception.php';
throw new Zend_Db_Adapter_Exception("LIMIT argument count=$count is not valid");
}
$offset = intval($offset);
if ($offset < 0) {
/** @see Zend_Db_Adapter_Exception */
require_once 'Zend/Db/Adapter/Exception.php';
throw new Zend_Db_Adapter_Exception("LIMIT argument offset=$offset is not valid");
}
$sql = preg_replace(
'/^SELECT\s+(DISTINCT\s)?/i',
'SELECT $1TOP ' . ($count+$offset) . ' ',
$sql
);
if ($offset > 0) {
$orderby = stristr($sql, 'ORDER BY');
if ($orderby !== false) {
$orderParts = explode(',', substr($orderby, 8));
$pregReplaceCount = null;
$orderbyInverseParts = array();
foreach ($orderParts as $orderPart) {
$orderPart = rtrim($orderPart);
$inv = preg_replace('/\s+desc$/i', ' ASC', $orderPart, 1, $pregReplaceCount);
if ($pregReplaceCount) {
$orderbyInverseParts[] = $inv;
continue;
}
$inv = preg_replace('/\s+asc$/i', ' DESC', $orderPart, 1, $pregReplaceCount);
if ($pregReplaceCount) {
$orderbyInverseParts[] = $inv;
continue;
} else {
$orderbyInverseParts[] = $orderPart . ' DESC';
}
}
$orderbyInverse = 'ORDER BY ' . implode(', ', $orderbyInverseParts);
}
if (!is_null($this->getRowCount()) && ($count+$offset) > $this->getRowCount())
$count = $this->getRowCount() - $offset;
$sql = 'SELECT * FROM (SELECT TOP ' . $count . ' * FROM (' . $sql . ') AS inner_tbl';
if ($orderby !== false) {
$sql .= ' ' . $orderbyInverse . ' ';
}
$sql .= ') AS outer_tbl';
if ($orderby !== false) {
$sql .= ' ' . $orderby;
}
}
return $sql;
}
/**
* Gets the last ID generated automatically by an IDENTITY/AUTOINCREMENT column.
*
* As a convention, on RDBMS brands that support sequences
* (e.g. Oracle, PostgreSQL, DB2), this method forms the name of a sequence
* from the arguments and returns the last id generated by that sequence.
* On RDBMS brands that support IDENTITY/AUTOINCREMENT columns, this method
* returns the last value generated for such a column, and the table name
* argument is disregarded.
*
* Microsoft SQL Server does not support sequences, so the arguments to
* this method are ignored.
*
* @param string $tableName OPTIONAL Name of table.
* @param string $primaryKey OPTIONAL Name of primary key column.
* @return string
* @throws Zend_Db_Adapter_Exception
*/
public function lastInsertId($tableName = null, $primaryKey = null)
{
$sql = 'SELECT SCOPE_IDENTITY()';
return (int)$this->fetchOne($sql);
}
public function getServerVersion()
{
try {
$stmt = $this->query("SELECT SERVERPROPERTY('productversion')");
$result = $stmt->fetchAll(Zend_Db::FETCH_NUM);
if (count($result)) {
return $result[0][0];
}
return null;
} catch (PDOException $e) {
return null;
}
}
public function quote($value)
{
if (is_int($value) || is_float($value)) {
return $value;
}
else if (is_array($value)) {
$values = array();
foreach ($value as $_val) {
if (is_int($_val) || is_float($_val)) {
$values[] = $_val;
}
else {
$values[] = "'".addslashes($_val)."'";
}
}
return join(',', $values);
}
return "'".addslashes($value)."'";
}
public function getRowCount()
{
return $this->_rowCount;
}
public function setRowCount($count)
{
$this->_rowCount = $count;
}
}
登録:
投稿 (Atom)