2008年10月3日金曜日

トランザクションとデータ確認1 ~MySQLのデータをGAEへ

PHP(MySQL) 側で PEAR の HTTP/Request.php を利用し、概略は以下のような流れで1レコードづつ Loop させて POST する。

5回程度のLoop とした。SQL の offset を追加しながら、間隔をあけて実行。
SELECT * FROM information_schema.columns where table_schema ='joomlaj' order by table_name, ordinal_position limit 0,5

SELECT * FROM information_schema.columns where table_schema ='joomlaj' order by table_name, ordinal_position limit 5,5


 require_once "HTTP/Request.php";

$req =& new HTTP_Request($post_url);
$req->setMethod(HTTP_REQUEST_METHOD_POST);

 ・・・

$database->setQuery( $sql2 );
$rows = @$database->loadAssocList();

foreach($fields[$table] as $field=>$type) { ?>
eval($get_fld_value);
$req->addPostData(strtolower($field), $value);


$request .= '&table='.$table ;
$request .= '&table_name='.$table_name ;
$req->addPostData('table', $table);
$req->addPostData('table_name', $table_name);

if (!PEAR::isError($req->sendRequest())) {
$response1 = $req->getResponseBody();
} else {
$response1 = "";
}



POST されたものを受ける、Python(Google App Engine の Cloud )側での概要はこちら

*1 PHP の fsockopen ではGAEのSDKでは動作しても cloud への POST はうまくかないようなので注意

2008年10月2日木曜日

Dynamic Datastore MySQLのデータをGAEへ

information_schema スキーマのcolumns テーブルについては以下のように決め打ちで対応した。
Datastore 側の key_name にはスキーマ、テーブル、カラム名を結合したものを設定した。

key = information_schema_columns.table_schema + "_"
key += information_schema_columns.table_name+ "."
key += information_schema_columns.column_name

Information_schema_columns.get_or_insert(key,
table_catalog = self.request.get('table_catalog'),
table_schema = self.request.get('table_schema'),
table_name = self.request.get('table_name'),
column_name = self.request.get('column_name'),
ordinal_position = ordinal_position,
column_default = column_default,
is_nullable = self.request.get('is_nullable'),
data_type = self.request.get('data_type'),
character_maximum_length = character_maximum_length,
character_octet_length = character_octet_length,
numeric_precision = numeric_precision,
numeric_scale = numeric_scale,
character_set_name = self.request.get('character_set_name'),
collation_name = self.request.get('collation_name'),
column_type = self.request.get('column_type'),
column_key = self.request.get('column_key') ,
extra = self.request.get('extra'),
privileges = self.request.get('privileges'),
column_comment = self.request.get('column_comment'))

けれども、この情報を利用してデータを転送する汎用的なものを作成しなければならない。
RDBMSには動的SQLという仕組みがあるが、 Datastore ではどのように対応したらいいのであろうか。

Pythonでリフレクションする」*1 などと参考にいろいろと試行錯誤、ようやくそれらしいものができた。
苦労したのはまず、

1.  動的に Class を作成するには ?

clazz = globals()[cls.capitalize()]
obj = clazz()

 
2.  動的に作成できた Class の Attribute を動的に作成するには ?

setattr


3. get_or_insert() でなくて、単純に put() するときの key_name の指定方法 ?

4. key_name にはなにを設定するか ?

Joomla! では id あるいは cid 列を設定しているようなので、まずはこれらを利用することに。


def post_mysql_data(self,cls):
clazz = globals()[cls.capitalize()]
obj = clazz()
table = cls
rr = db.GqlQuery("select * from Information_schema_columns where table_name = :1", table )

col = ""
for r in rr:
if r.column_name == 'id' or r.column_name == 'cid':
column_value = self.request.get(r.column_name)
key_name = 'id' + column_value
j = clazz(key_name = key_name)

if j:
for r in rr:
column_value = self.request.get(r.column_name)
if r.data_type == 'varchar' or r.data_type == 'text' or r.data_type == 'longtext' :
if column_value : setattr(j,r.column_name,column_value)
if r.data_type == 'bigint' or r.data_type == 'tinyint' or r.data_type == 'int' :
if column_value : setattr(j,r.column_name,int(column_value))
if r.data_type == 'datetime':
if column_value :
if column_value == '0000-00-00 00:00:00':column_value = '1901-01-01 00:00:00'
column_value = datetime.datetime.strptime(column_value,'%Y-%m-%d %H:%M:%S')
setattr(j,r.column_name,column_value)
col = j.put()


*1  shisashiの開発日記 http://shisashi.blogspot.com/

information.schema.columns MySQLのデータをGAEへ

拡張機能のライブラリ Joomla! Extensions Directory の
Administration - Database Management の中の
を使うと、 Joomla! というCMSの Administration 画面で phpMyAdmin ライクの操作を行なうことができる。
テーブル構造から class の定義の変換についてはオリジナルの components を作成してみたが、以降はこの Extention Components をベースにすることにした。

PHP 側から MySQL のデータを Google App Engine の Cloud に POST して、それを Python側で受けて datastore に put()  するフローとなる。

事前に各model の定義は作成しておいたとしても、datastore に put する際に column ごとにデータの型が intger なのか text なのか、わかっている必要がある。

Cloud 側のデータの型は数字もすべてテキストとし保存してしまってもよいのかもしれないが、いずれにしろまず、列情報を持つ MySQL のテーブルを Cloud に転送する第1ターゲットとすることにした。


SELECT * FROM information_schema.columns where table_schema ='joomlaj' order by table_name, ordinal_position limit 0,10

MySQLのデータをGAEへ

テンプレートの良し悪しで画面の感じがまったくかわってしまう。
PHP で書かれている Joomla とういうCMSのテンプレートの質が高い。また拡張ライブラリが充実している。

GAE にこれらのテンプレートを応用しようとした場合、 やはり Joomla 側のキーとなるいくつかのテーブルと同様のものを Cloud に作成する必要がある。

Joomla! の components の作成手順を参考にまずテーブルに対応する class の定義を作成するようにした。 以下がまず作成した対応一覧。

if ($data_type == "bigint" ) { $datastore_type = " = db.IntegerProperty()" ;}
if ($data_type == "tinyint") { $datastore_type = " = db.IntegerProperty()" ;}
if ($data_type == "int" ) { $datastore_type = " = db.IntegerProperty()" ;}
if ($data_type == "varchar") { $datastore_type = " = db.StringProperty()" ; }
if ($data_type == "text") { $datastore_type = " = db.TextProperty()" ; }
if ($data_type == "longtext"){ $datastore_type = " = db.TextProperty()" ; }
if ($data_type == "datetime"){ $datastore_type = " = db.DateTimeProperty()" ; }
views/auto/tmpl/defaul.php



2008年10月1日水曜日

fsock でcloud にPOSTしても値が届かない

php の fsockopen にて データを POST する、
local の Google App Engine の SDK 環境では動作しても、本番環境の Cloud では
501 エラーなども発生。

チェックが厳しいためか。
http://code.google.com/p/gears/wiki/ContentRangePostProposal


結局 PEAR を利用したところ、無事 cloud に対してでも POST できるようになった。
http://pear.php.net/manual/ja/package.http.http-request.headers.php

2008年9月22日月曜日

Joomla

・ 管理メニューで Top Menu が表示されない
->   モジュール管理 にて Top Menu を有効にする

- インストール時に サンプル を選択しないと、 jos_menu_types  に seed data が登録されないことが原因
joomlaj\installation_\sql\mysql\sample_data_sql
INSERT INTO `#__menu_types` VALUES
(2, 'usermenu', 'User Menu', 'A Menu for logged in Users'),
(3, 'topmenu', 'Top Menu', 'Top level navigation'),
(4, 'othermenu', 'Resources', 'Additional links'),
(5, 'ExamplePages', 'Example Pages', 'Example Pages'),
(6, 'keyconcepts', 'Key Concepts', 'This describes some critical information for new Users.');


・ 最終更新 の日付の日の部分が %d のまま表示される。
/language/ja-JP/ja-JP.ini の以下を変更(結局スペースを追加)
DATE_FORMAT_LC2=%Y年  %B %d日(%A) %H:%M
#DATE_FORMAT_LC2=%Y年%B%d日(%A) %H:%M


無料Joomla!テンプレー          http://www.joomlashack.jp/content/view/4/9/
Joomla ジャパン                    http://www.joomla.jp/
Joomla Template Tutorial    http://dev.joomla.org/content/view/1136/79/


Joomla! 1.5 変更部分
・ メニューの構築手順
  外部ファイルの取り込みがエクステンションに一元化
・ テンプレートではtemplateDetails.xml の役割
  モジュールポディションの設定、テンプレートパラメータの設定が可能
  テンプレート側にポディション

・ 特定のメニューから呼び出されたページに対し、テンプレートを指定することができる
  セクションと、その配下にカテゴリーの2層構造でしかコンテンツを管理することができない
  --->  メニューと組み合わせが必要
  Assign 対応していない template もある。



・ Joomla! 1.5.3 でタイトルタグにサイト名を表示させるための変更

・  機能拡張     http://extensions.joomla.org/
    Joomla! 1.5 Template Tutorials Project


・ Zend Framework の動作


・phpフレームワーク・オブジェクト指向入門 http://phpc2.seesaa.net/
PHP5の新機能(クラス関係) http://www.atmarkit.co.jp/fcoding/articles/php5/02/php502a.html
・引数の値渡しと参照渡し http://ww7.tiki.ne.jp/~inabah/php/004_002.htm

Home Developer Manual 11. API Reference [REVIEW] database->loadAssocList

Tutorial:Developing a Model-View-Controller Component - Part 1

2008年9月19日金曜日

Uploading index definitions Error


何日かぶりに appcfg.py update xxxx/ で更新しようとしたところ以下のエラーで先に進まなくなってしまった。
タイミングとして新しいイメージファイルをいくも追加したので、それが原因かと思ったが、そうではないらしい。

Uploading index definitions.
Error 400: --- begin server output ---
Building a composite index failed: ApplicationError: 3
--- end server output ---

Issue 287:Explosion with >100 indexes


To vacuum your indexes: 
1. Create a backup of your index.yaml specification
2. Remove the definitions of the indexes in Error from your index.yaml file
3. Run appcfg.py vacuum_indexes your_app_dir/
4. Replace the modified version of your index.yaml file with the original
5. Run appcfg.py update your_app_dir/


を参考に まず index.yaml をクリアしてから vacuum すると、

This index is no longer defined in your index.yaml file.

ancestor: true
kind: Timeline
properties: []

Are you sure you want to delete this index? (N/y/a): y

ときかれるので、N として、いかにも不要そうな複合インデックスをいくつか削除して
appcfg.py vacuum_indexes your_app_dir/

にて今度は Y にて削除した。
いくつも削除したため、ダッシュボードでみると index の delete のタスクが走りだした。このタスク中に appcfg.py update xxxx/ すると
Server Error (500) A server error has occured.
となる。しばらく、時間をおいたところ無事 update できたが、その直後から今度はindex 作成のタスクがいくつも走りだした。




http://code.google.com/appengine/docs/datastore/queriesandindexes.html#Big_Entities_and_Exploding_Indexes

To handle "Error" indexes, first remove them from your index.yaml file and run appcfg.py vacuum_indexes. Then, either reformulate the index definition and corresponding queries or remove the entities that are causing the index to "explode." Finally, add the index back to index.yaml and run appcfg.py update_indexes.

MacOS Sequoia で Apache+PHP の再設定

 新しいXcodeが使いたかったので MacOS15(Sequoia) にアップグレードしたところ、やはりApacheでPHPが動かなくなっていた。 結論としては brew, openssl, php, httpd を全て再度インストールしたところ動くようになった。 以下、作業ロ...