コンテンツにスキップ

Python

概要

本ガイドはパッケージ 2.3 を対象とします。インストール名は小文字の machbaseapi で、純粋な Python 実装になりました。ネイティブの .so/.dll/.dylib は不要です。

import machbaseAPI と既存の machbase の呼び出し方を引き続き使用できます。

  • PyPI のパッケージ名:machbaseapi
  • インポート:import machbaseAPI
  • DB-API 形式の connect() と cursor() を利用可能
  • APPEND API の任意引数 on_ack で応答コールバックを取得可能
  • append()、appendByTime()、appendData()、appendDataByTime() は列型コードを省略でき、メタデータから型を推論します。
  • 2.3 では、APPEND 行の省略した末尾列を null-bit メタデータにより NULL として保存します。
  • TAG テーブルでは value 列までの値が必須です。その後の追加列やメタデータ列は省略でき、NULL で保存します。
  • 2.3 では接続プール設定(pool_name、pool_size、pool_reset_session)はサポートしません。

以下は、従来形式のスクリプトの入口である machbase クラスを使用します。

インストール

要件

  • pip を利用できる Python 3.6 以降。
  • 接続可能なサーバーと認証情報(既定はポート 5656 の SYS/MANAGER)。
  • 2.3 ではネイティブの Machbase 共有ライブラリーは不要です。

PyPI からのインストール

pip3 install machbaseapi

pip3 が PATH にない場合は python3 -m pip install machbaseapi を使用します。

モジュールの確認

python3 - <<'PY'
from machbaseAPI import machbase, connect
print('machbase class import ok:', bool(machbase))
print('connect function exists:', callable(connect))
print('module import:', __import__('machbaseAPI'))
PY

成功すれば、インポートとインスタンス作成が可能であることを確認できます。

connect() による DB-API の例も実行できます。

from machbaseAPI import connect

conn = connect(host='127.0.0.1', port=5656, user='SYS', password='MANAGER')
cur = conn.cursor()
cur.execute('SELECT * FROM m$tables LIMIT 1')
print(cur.fetchall())
conn.close()

クイックスタート

ローカルサーバーに接続し、テーブルを作成して挿入、検索し、セッションを閉じる例です。

#!/usr/bin/env python3
import json
from machbaseAPI import machbase

def main():
    db = machbase()
    if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0:
        raise SystemExit(db.result())

    try:
        rc = db.execute('drop table py_sample')
        print('drop table rc:', rc)
        print('drop table result:', db.result())

        ddl = (
            "create table py_sample ("
            "ts datetime,"
            "device varchar(40),"
            "value double"
            ")"
        )
        if db.execute(ddl) == 0:
            raise SystemExit(db.result())
        print('create table result:', db.result())

        for seq in range(3):
            sql = (
                "insert into py_sample values ("
                f"to_date('2024-01-0{seq+1}','YYYY-MM-DD'),"
                f"'sensor-{seq}',"
                f"{20.5 + seq}"
                ")"
            )
            if db.execute(sql) == 0:
                raise SystemExit(db.result())
            print('insert result:', db.result())

        if db.select('select * from py_sample order by ts') == 0:
            raise SystemExit(db.result())

        while True:
            rc, payload = db.fetch()
            if rc == 0:
                break
            row = json.loads(payload)
            print('row:', row)

        db.selectClose()
    finally:
        if db.close() == 0:
            raise SystemExit(db.result())

if __name__ == '__main__':
    main()

結果の処理

machbase の多くのメソッドは、成功時 1、失敗時 0 を返します。各呼び出し後に db.result() で JSON 形式の結果を取得します。select() の結果は、db.fetch() が (0, None) を返すまで繰り返し取得し、db.selectClose() で解放します。

対応 API

クラスAPI説明戻り値
machbaseopen(host, user, password, port)サーバーに接続。既定の認証情報とポートを使用可能。成功時 1、失敗時 0
machbaseopenEx(host, user, password, port, conn_str)追加の接続文字列属性を指定して接続。1 または 0
machbaseclose()現在のセッションを終了。1 または 0
machbaseisOpened()ハンドルが開いているか確認。1 または 0
machbaseisConnected()サーバーへの接続状態を確認。1 または 0
machbaseexecute(sql)SQL を直接実行。SELECT、WITH、DESC、DESCRIBE、SHOW は select()、それ以外は exec_direct() を使用。1 または 0
machbaseschema(sql)スキーマ関連の文を実行。1 または 0
machbasetables()すべてのテーブルのメタデータを取得。1 または 0
machbasecolumns(table_name)指定テーブルの列メタデータを取得。1 または 0
machbasecolumn(table_name)低水準のカタログ呼び出しで列構成を取得。1 または 0
machbasestatistics(table_name, user='SYS')CLI 経由でテーブル統計を取得。1 または 0
machbaseselect(sql)ストリーミング SELECT または DESC を実行。1 または 0
machbasefetch()select() 後に次の行を取得。(rc, json_str)
machbaseselectClose()結果セットのカーソルを閉じる。1 または 0
machbaseresult()最新の JSON ペイロードを返す。JSON 文字列
machbaseappendOpen(table_name, types=None)列型コードを指定して APPEND を開始。省略時はサーバーのスキーマを取得可能。1 または 0
machbaseappendData(table_name, rows_or_types, values=None, format='YYYY-MM-DD HH24:MI:SS', on_ack=None)有効な APPEND セッションで行を入力。型を省略する場合は第 2 引数に行を指定。呼び出し時に直ちに送信。1 または 0
machbaseappendDataByTime(table_name, rows_or_types, values=None, format='YYYY-MM-DD HH24:MI:SS', aTimes=None, on_ack=None)エポック時刻を指定して入力。型を省略する場合は第 2 引数に行、aTimes に時刻を指定。呼び出し時に直ちに送信。1 または 0
machbaseappendFlush()送信済み APPEND の保留応答を確認する同期ポイント。遅延送信バッファーのフラッシュ API ではない。1 または 0
machbaseappendClose()APPEND セッションを閉じる。1 または 0
machbaseappend(table_name, rows_or_types, aValues=None, format='YYYY-MM-DD HH24:MI:SS')開始、入力、終了をまとめて行う。型を省略する場合は第 2 引数に行を指定。1 または 0
machbaseappendByTime(table_name, rows_or_types, aValues=None, format='YYYY-MM-DD HH24:MI:SS', aTimes=None)時刻付き APPEND のラッパー。型を省略する場合は第 2 引数に行、aTimes に時刻を指定。1 または 0

DB-API 形式の API(2.3)

API説明戻り値
connect(**kwargs)DB-API 接続を作成。host、port、user、password などをキーワード引数で指定。MachbaseConnection
cursor(dictionary=True)カーソルを作成(True:辞書の行、False:タプルの行)。MachbaseCursor
cursor.execute(sql, params=None)SQL 文を実行。cursor
cursor.fetchone()1行を取得。tuple | dict | None
cursor.fetchmany(size)最大 size 行を取得。list
cursor.fetchall()すべての行を取得。list
cursor.close()カーソルを閉じる。None
cursor.rowcount影響を受けた行数。int
connection.append(table, rows, types=None, times=None, strict=False)Append プロトコルで行を入力。2.3 以降では省略した末尾列を NULL で補完。入力行数

2.3:列型の省略と末尾列の NULL 補完(推奨)

append() と appendByTime() は、型のリストを省略できます。 第 2 引数に行を渡し、サーバーのメタデータで型を処理します。 2.3 以降では末尾の列を省略でき、null-bit メタデータによって NULL として保存します。

#!/usr/bin/env python3
from machbaseAPI.machbaseAPI import machbase

def main():
    db = machbase()
    if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0:
        raise SystemExit(db.result())

    try:
        db.execute('drop table py_append_auto')
        db.result()
        ddl = 'create table py_append_auto(ts datetime, tag varchar(16), reading double)'
        if db.execute(ddl) == 0:
            raise SystemExit(db.result())
        db.result()

        rows = [
            ['2024-01-01 10:00:00', 'node-1', 30.0],
            ['2024-01-01 10:01:00', 'node-1', 30.5],
        ]
        if db.append('PY_APPEND_AUTO', rows) == 0:
            raise SystemExit(db.result())
        print('append without types result:', db.result())
    finally:
        if db.close() == 0:
            raise SystemExit(db.result())

if __name__ == '__main__':
    main()

DB-API で末尾列を NULL にする例

connect().append() も同じ規則です。位置指定の入力では途中の列を飛ばせないため、途中を NULL にする場合は None を明示します。

from machbaseAPI import connect

conn = connect(host='127.0.0.1', port=5656, user='SYS', password='MANAGER')
cur = conn.cursor()

try:
    cur.execute('drop table py_append_null')
except Exception:
    pass
cur.execute('create table py_append_null(ts datetime, name varchar(20), value double, note varchar(40))')

conn.append('PY_APPEND_NULL', [
    ['2024-01-01 10:00:00', 'sensor-1', 12.3],
    ['2024-01-01 10:00:01', 'sensor-2', None, 'manual null'],
])

cur.execute('select ts, name, value, note from py_append_null order by ts')
print(cur.fetchall())
conn.close()

1行目は note を省略するので NULL になります。2 行目は value に None を渡すので、value が NULL になります。

TAG テーブルの APPEND とメタデータの NULL

TAG テーブルでは name、time、value が必須です。value より後の追加列とメタデータ列は省略でき、NULL になります。

from machbaseAPI import connect

conn = connect(host='127.0.0.1', port=5656, user='SYS', password='MANAGER')
cur = conn.cursor()

try:
    cur.execute('drop table py_tag_append_null')
except Exception:
    pass
cur.execute('''
    create tag table py_tag_append_null (
        name varchar(40) primary key,
        time datetime basetime,
        value double summarized,
        status varchar(20)
    ) metadata (
        site varchar(20),
        line integer
    )
''')

conn.append('PY_TAG_APPEND_NULL', [
    ['tag-1', '2024-01-01 10:00:00', 12.3],
])

cur.execute('select name, time, value, status, site, line from py_tag_append_null')
print(cur.fetchall())
conn.close()

この例では status、site、line が NULL になります。value を省略した TAG APPEND は失敗します。

API と使用例(従来形式の machbase クラス)

以下は 2.3 でも利用できる従来形式の machbase クラスの例です。 古いネイティブ版にあった getSessionId()、count()、checkBit() は、 現在の純粋な Python 実装では提供しません。必要に応じて、2.3のDB-APIの例を参照してください。

各例のホスト、ポート、ユーザー、パスワードを環境に合わせて変更します。各スクリプトは独立して python3 script.py で実行できます。

接続管理

machbase.open(), machbase.isOpened(), machbase.isConnected(), machbase.close()

#!/usr/bin/env python3
from machbaseAPI.machbaseAPI import machbase

def main():
    db = machbase()
    print('isOpened before open:', db.isOpened())
    print('isConnected before open:', db.isConnected())

    if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0:
        raise SystemExit(db.result())

    print('isOpened after open:', db.isOpened())
    print('isConnected after open:', db.isConnected())

    if db.close() == 0:
        raise SystemExit(db.result())

    print('isOpened after close:', db.isOpened())
    print('isConnected after close:', db.isConnected())

if __name__ == '__main__':
    main()

machbase.openEx()

#!/usr/bin/env python3
from machbaseAPI.machbaseAPI import machbase

def main():
    db = machbase()
    conn_str = 'APP_NAME=python-demo'
    if db.openEx('127.0.0.1', 'SYS', 'MANAGER', 5656, conn_str) == 0:
        raise SystemExit(db.result())
    print('connected with openEx:', db.isConnected())
    if db.close() == 0:
        raise SystemExit(db.result())

if __name__ == '__main__':
    main()

DML と結果バッファー

machbase.execute(), machbase.result()

#!/usr/bin/env python3
import json
from machbaseAPI.machbaseAPI import machbase

def main():
    db = machbase()
    if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0:
        raise SystemExit(db.result())

    try:
        rc = db.execute('drop table py_exec_demo')
        print('drop table rc:', rc)
        print('drop table result:', db.result())

        ddl = 'create table py_exec_demo(id integer, note varchar(32))'
        if db.execute(ddl) == 0:
            raise SystemExit(db.result())
        print('create table result:', db.result())

        for idx in range(2):
            sql = f"insert into py_exec_demo values ({idx}, 'row-{idx}')"
            if db.execute(sql) == 0:
                raise SystemExit(db.result())
            print('insert result:', db.result())

        if db.execute('select * from py_exec_demo order by id') == 0:
            raise SystemExit(db.result())
        payload = db.result()
        print('select payload:', payload)
        rows = json.loads(payload)
        print('decoded rows:', rows)
        print('row count:', len(rows))
    finally:
        if db.close() == 0:
            raise SystemExit(db.result())

if __name__ == '__main__':
    main()

ストリーミング SELECT

machbase.select(), machbase.fetch(), machbase.selectClose()

#!/usr/bin/env python3
import json
from machbaseAPI.machbaseAPI import machbase

def main():
    db = machbase()
    if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0:
        raise SystemExit(db.result())

    try:
        rc = db.execute('drop table py_select_demo')
        print('drop table rc:', rc)
        print('drop table result:', db.result())

        ddl = 'create table py_select_demo(id integer, value double)'
        if db.execute(ddl) == 0:
            raise SystemExit(db.result())
        print('create table result:', db.result())

        for idx in range(5):
            sql = f"insert into py_select_demo values ({idx}, {idx * 1.5})"
            if db.execute(sql) == 0:
                raise SystemExit(db.result())
            print('insert result:', db.result())

        if db.select('select id, value from py_select_demo order by id') == 0:
            raise SystemExit(db.result())

        fetched = 0
        while True:
            rc, payload = db.fetch()
            if rc == 0:
                break
            print('fetched row:', json.loads(payload))
            fetched += 1
        print('fetched rows:', fetched)

        db.selectClose()
    finally:
        if db.close() == 0:
            raise SystemExit(db.result())

if __name__ == '__main__':
    main()

スキーマ操作

machbase.schema()

#!/usr/bin/env python3
from machbaseAPI.machbaseAPI import machbase

def main():
    db = machbase()
    if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0:
        raise SystemExit(db.result())

    try:
        rc = db.schema('drop table py_schema_demo')
        print('schema drop rc:', rc)
        print('schema drop result:', db.result())

        ddl = 'create table py_schema_demo(name varchar(20), created datetime)'
        if db.schema(ddl) == 0:
            raise SystemExit(db.result())
        print('schema create result:', db.result())
    finally:
        if db.close() == 0:
            raise SystemExit(db.result())

if __name__ == '__main__':
    main()

メタデータと統計

machbase.tables(), machbase.columns(), machbase.column(), machbase.statistics()

#!/usr/bin/env python3
from machbaseAPI.machbaseAPI import machbase

def main():
    db = machbase()
    if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0:
        raise SystemExit(db.result())

    try:
        if db.tables() == 0:
            raise SystemExit(db.result())
        print('tables metadata:', db.result())

        if db.columns('PY_EXEC_DEMO') == 0:
            raise SystemExit(db.result())
        print('columns metadata:', db.result())

        if db.column('PY_EXEC_DEMO') == 0:
            raise SystemExit(db.result())
        print('column metadata:', db.result())

        if db.statistics('PY_EXEC_DEMO') == 0:
            raise SystemExit(db.result())
        print('statistics output:', db.result())
    finally:
        if db.close() == 0:
            raise SystemExit(db.result())

if __name__ == '__main__':
    main()

Append プロトコルの基本操作

appendOpen()、appendData()、appendFlush()、appendClose() で効率よく行を入力できます。 2.1以降では、列型を省略してappendOpen()を開始でき、サーバーのメタデータを自動的に使用します。 appendData() と appendDataByTime() は呼び出し時に直ちにデータを送信します。appendFlush() は、送信済みデータの保留応答を確認する同期ポイントです。

#!/usr/bin/env python3
from machbaseAPI.machbaseAPI import machbase

def main():
    db = machbase()
    if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0:
        raise SystemExit(db.result())

    try:
        rc = db.execute('drop table py_append_demo')
        print('drop table rc:', rc)
        print('drop table result:', db.result())

        ddl = 'create table py_append_demo(ts datetime, device varchar(32), value double)'
        if db.execute(ddl) == 0:
            raise SystemExit(db.result())
        print('create table result:', db.result())

        if db.appendOpen('PY_APPEND_DEMO') == 0:
            raise SystemExit(db.result())

        rows = [
            ['2024-01-01 09:00:00', 'sensor-a', 21.5],
            ['2024-01-01 09:05:00', 'sensor-b', 22.1],
        ]
        if db.appendData('PY_APPEND_DEMO', rows) == 0:
            raise SystemExit(db.result())
        print('appendData result:', db.result())

        if db.appendFlush() == 0:
            raise SystemExit(db.result())
        print('appendFlush result:', db.result())

        if db.appendClose() == 0:
            raise SystemExit(db.result())
        print('appendClose result:', db.result())
    finally:
        if db.close() == 0:
            raise SystemExit(db.result())

if __name__ == '__main__':
    main()

APPEND の便利なラッパー

machbase.append()

#!/usr/bin/env python3
from machbaseAPI.machbaseAPI import machbase

def main():
    db = machbase()
    if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0:
        raise SystemExit(db.result())

    try:
        db.execute('drop table py_append_auto')
        db.result()
        ddl = 'create table py_append_auto(ts datetime, tag varchar(16), reading double)'
        if db.execute(ddl) == 0:
            raise SystemExit(db.result())
        db.result()

        values = [
            ['2024-01-01 10:00:00', 'node-1', 30.0],
            ['2024-01-01 10:01:00', 'node-1', 30.5],
        ]
        if db.append('PY_APPEND_AUTO', values) == 0:
            raise SystemExit(db.result())
        print('append() result:', db.result())
    finally:
        if db.close() == 0:
            raise SystemExit(db.result())

if __name__ == '__main__':
    main()

machbase.appendDataByTime(), machbase.appendByTime()

#!/usr/bin/env python3
from machbaseAPI.machbaseAPI import machbase

def main():
    db = machbase()
    if db.open('127.0.0.1', 'SYS', 'MANAGER', 5656) == 0:
        raise SystemExit(db.result())

    try:
        db.execute('drop table py_append_time')
        db.result()
        ddl = 'create table py_append_time(ts datetime, tag varchar(16), reading double)'
        if db.execute(ddl) == 0:
            raise SystemExit(db.result())
        db.result()

        rows = [
            ['2024-01-01 11:00:00', 'node-2', 40.1],
            ['2024-01-01 11:01:00', 'node-2', 40.7],
        ]
        epoch_times = [1704106800, 1704106860]

        if db.appendOpen('PY_APPEND_TIME') == 0:
            raise SystemExit(db.result())
        if db.appendDataByTime('PY_APPEND_TIME', rows, aTimes=epoch_times) == 0:
            raise SystemExit(db.result())
        print('appendDataByTime result:', db.result())
        db.appendClose()

        if db.appendByTime('PY_APPEND_TIME', rows, aTimes=epoch_times) == 0:
            raise SystemExit(db.result())
        print('appendByTime result:', db.result())
    finally:
        if db.close() == 0:
            raise SystemExit(db.result())

if __name__ == '__main__':
    main()

診断

machbase.checkBit()

checkBit() は旧版でネイティブのポインターサイズを確認するもので、2.3 の純粋な Python 版にはありません。

低水準バインディング

2.3 では、従来の ctypes ヘルパーである get_library_path()、openDB()、execAppend*()、getlAddrやgetrAddrなどのポインター操作APIは提供しません。 低水準の C 層にアクセスする場合は、2.0 より前のパッケージを引き続き使用してください。

最終更新日