2010年1月30日土曜日

OpenOffice.org と Python マクロ 2 限目

今回は、OpenOffice.org Base で登録したデータベースにアクセスしてみる。

では、OpenOffice.org Base を起動する。
起動したら、適当に新規データベースを登録する。

登録されているデータベースを確認してみる。
メイン画面で、「ツール」メニュー > 「オプション」を選択する。
オプション画面が開いたら、「OpenOffice.org Base」 > 「データベース」を選択する。
「登録されたデータベース」に、いくつかデータベースがリストされているのを確認する。
ここに表示されれている登録名の一覧を表示するマクロを作成してみる。

以下のソースコードを helloDb.py としてマクロ格納先(1限目を参照)へ作成する。

#!
# -*- coding: utf_8 -*-

import uno

def helloDb():
    msg = getDataSourceNames()
    message(XSCRIPTCONTEXT.getDesktop(), msg, u"データベース一覧")

def getDataSourceNames():
    ctx = uno.getComponentContext()
    smgr = ctx.ServiceManager
    dbc = smgr.createInstance("com.sun.star.sdb.DatabaseContext")
    dbNames = dbc.getElementNames()
    result = ""
    for name in dbNames:
        result += name + ", "
    return(result)

def message(desktop, msg = "", title = ""):
    frame = desktop.getCurrentFrame()
    win = frame.getContainerWindow()
    toolkit = win.getToolkit()
    rect = uno.createUnoStruct("com.sun.star.awt.Rectangle")
    msgbox = toolkit.createMessageBox(win, rect, "messbox", 1, title, msg)
    msgbox.execute()

g_exportedScripts = helloDb,


実行すると、メッセージダイアログに登録されたデータベース名がリストアップされているはず。


次に、データベース(ここでは”資産管理”)に登録されているクエリーの一覧を取得してみる。

データベースに適当なクエリーを登録する。
以下のソースコードを helloDbQuery.py として保存する。

#!
# -*- coding: utf_8 -*-

import uno

def helloDbQuery():
    msg = getQueryNames()
    message(XSCRIPTCONTEXT.getDesktop(), msg, u"クエリー一覧")

def getQueryNames():
    ctx = uno.getComponentContext()
    smgr = ctx.ServiceManager
    dbc = smgr.createInstance("com.sun.star.sdb.DatabaseContext")
    ds = dbc.getByName(u"資産管理")
    con = ds.getConnection("", "")
    queries = con.getQueries()
    queryNames = queries.getElementNames()
    result = ""
    for name in queryNames:
        result += name + ", "
    return(result)

def message(desktop, msg = "", title = ""):
    frame = desktop.getCurrentFrame()
    win = frame.getContainerWindow()
    toolkit = win.getToolkit()
    rect = uno.createUnoStruct("com.sun.star.awt.Rectangle")
    msgbox = toolkit.createMessageBox(win, rect, "messbox", 1, title, msg)
    msgbox.execute()

g_exportedScripts = helloDbQuery,


実行すると、クエリー一覧が表示される。


次に、SQLを実行してみる。
(ここでは、「資産管理」データベースに「資産」テーブルを、カラム数を 3つで作成してあり、カラムタイプは、 VARCHAR 型としてある。作成した「資産」テーブルには、適当にレコードを追加しておいた。)
以下のソースコードを helloDbQueryResult.py として保存

#!
# -*- coding: utf_8 -*-

import uno

def helloDbQueryResult():
    msg = getQueryResult()
    message(XSCRIPTCONTEXT.getDesktop(), msg, u"クエリー結果一覧")

def getQueryResult():
    ctx = uno.getComponentContext()
    manager = ctx.ServiceManager
    dbctx = manager.createInstance("com.sun.star.sdb.DatabaseContext")
    ds = dbctx.getByName(u"資産管理")
    conn = ds.getConnection("", "")
    stmt = conn.createStatement()

    result = stmt.executeQuery(u"SELECT * FROM \"資産\"")
    msg = ""
    while(result != None and result.next()):
        msg += result.getString(3) + ", "
    return(msg)

def message(desktop, msg = "", title = ""):
    frame = desktop.getCurrentFrame()
    win = frame.getContainerWindow()
    toolkit = win.getToolkit()
    rect = uno.createUnoStruct("com.sun.star.awt.Rectangle")
    msgbox = toolkit.createMessageBox(win, rect, "messbox", 1, title, msg)
    msgbox.execute()

g_exportedScripts = helloDbQueryResult,


実行すると、テーブルに定義したデータの3カラム目の値が全て表示される。


次に、Prepared Statement を使ってみる。
以下のソースコードを helloDbPStmt.py として保存。

#!
# -*- coding: utf_8 -*-

import uno

def helloDbPStmt():
    msg = getQueryResult()
    message(XSCRIPTCONTEXT.getDesktop(), msg, u"クエリー結果一覧")

def getQueryResult():
    ctx = uno.getComponentContext()
    manager = ctx.ServiceManager
    dbctx = manager.createInstance("com.sun.star.sdb.DatabaseContext")
    ds = dbctx.getByName(u"資産管理")
    conn = ds.getConnection("", "")

    stmt = conn.prepareStatement(u"SELECT * FROM \"資産\" WHERE \"AssetName\" like ?")
    stmt.setString(1, u"%株式%")

    result = stmt.executeQuery()
    msg = ""
    while(result != None and result.next()):
        msg += result.getString(3) + ", "
    return(msg)

def message(desktop, msg = "", title = ""):
    frame = desktop.getCurrentFrame()
    win = frame.getContainerWindow()
    toolkit = win.getToolkit()
    rect = uno.createUnoStruct("com.sun.star.awt.Rectangle")
    msgbox = toolkit.createMessageBox(win, rect, "messbox", 1, title, msg)
    msgbox.execute()

g_exportedScripts = helloDbPStmt,


実行すると、3カラム目の内容に”株式”が含まれているものを、中間一致で検索した結果が表示される。

SQL を以下のようにいじった

stmt = conn.prepareStatement(u"SELECT AssetId, 'hoge', ? FROM 資産")

実行してみると、stmt.setString メソッドの箇所で以下のようなエラーとなった
com.sun.star.uno.RuntimeException: 'ascii' codec can't encode characters in position 71-72: ordinal not in range(128), traceback follows
  C:\Program Files (x86)\OpenOffice.org 3\Basis\program\uno.py:327 in function _uno_struct__repr__() [return repr(self.__dict__["value"])]
  C:\Program Files (x86)\OpenOffice.org 3\Basis\program\pythonscript.py:28 in function lastException2String() [ret = str(excType) + ": "+str(excInstance) + "\n" + \]
  C:\Program Files (x86)\OpenOffice.org 3\Basis\program\pythonscript.py:776 in function invoke() [text = lastException2String()]


はは~ん、資産をダブルクォートで囲んでないからだなぁ、と思って以下のように変えて実行した
stmt = conn.prepareStatement(u"SELECT AssetId, 'hoge', ? FROM \"資産\"")


ブブーッ!はずれ!
エラーの内容は変わらず・・・
ウンウン唸って考えて、以下のようにカラム名をダブルクォートで囲ってみた

stmt = conn.prepareStatement(u"SELECT \"AssetId\", 'hoge', ? FROM \"資産\"")


ピンポンピンポ~ン!正解!
試しに、テーブル名のダブルクォートを外してみたら、問題なく動いた・・・なぜ?

まあ、とりあえずは、なんでもダブルクォートで囲っておくことにするか・・・


ようやく、何とかなりそうな気がしてきた。
これで野望に近づける。

まあ、要は、データベースに保存した資産の情報から、現状の資産配分を知りたいのですよ。
データが入れ子になっているので、単純な SQL では難しい・・・