コンテンツにスキップ

11.6 Python

概要

パッケージ2.4を基準とします。PyPIのパッケージ名はmachbaseapi(小文字)です。 純粋なPython実装のため、ネイティブバイナリ(.so/.dll/.dylib)は不要です。 既存のmachbaseの使用フローは維持されます。

  • インストールするパッケージ名: machbaseapi
  • 従来どおりimport machbaseAPIを使用
  • DB-API形式のconnect()cursor()をサポート
  • 2.4からcursor(prepared=True)でサーバーの文を複数の呼び出しで再利用
  • append*にはon_ackコールバックを追加でき、ACKを観測可能
  • append()appendByTime()appendData()appendDataByTime()は型リストを省略しても動作し、サーバーメタデータから型を自動推論
  • 2.3からAppend行の末尾の一部の列を省略すると、AppendのNULLビットによりNULLとして保存
  • TAGテーブルはvalue列までが必須で、後続の追加列とメタデータ列は省略時にNULLとして保存可能
  • 接続プールオプション(pool_namepool_sizepool_reset_session)は非サポート

マルチデータベース

connect(database=...)で初期データベースを指定できます。現在のカタログのgetter/setterはないため、 接続後にSELECT CURRENT_DATABASE()で確認し、SQLのUSEで変更します。

conn = connect(
    host='127.0.0.1', port=5656,
    user='APP_A', password='secret', database='FACTORY_A',
)
cur = conn.cursor()
cur.execute('SELECT CURRENT_DATABASE()')
print(cur.fetchone())
cur.execute('USE FACTORY_B')

既存互換のmachbase.open()にはデータベース引数がありません。マルチデータベース操作には最新の connect()を使用してください。接続プールと文のバインディング規則の詳細は マルチデータベース運用ガイドを 参照してください。

インストール

要件

  • pipを使用できるPython 3.6以降
  • 接続可能なMachbaseサーバーとアカウント情報(デフォルトアカウントSYS/MANAGER、ポート5656
  • 2.4にはネイティブライブラリの依存関係なし

PyPIからインストール

pip3 install machbaseapi

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

インストールパッケージからオフラインでインストール

インターネットに接続できない環境では、Machbaseインストールパッケージに含まれるwheelをインストールします。

python3 -m pip install \
  $MACHBASE_HOME/3rd-party/python3-module/machbaseapi-2.4-py3-none-any.whl

同じディレクトリのソース配布ファイルmachbaseapi-2.4.tar.gzも使用できます。 インストール前にPython 3.6以降であることを確認します。

モジュールの確認

python3 - <<'PY'
from machbaseAPI import machbase, connect
print('machbaseクラスのインポート:', bool(machbase))
print('connect関数の存在:', callable(connect))
print('module import:', __import__('machbaseAPI'))
PY

このコマンドが成功すれば、パッケージを正常にインポートできます。

クイックスタート

次のDB-API例はサンプルLOGテーブルを作成して入力・検索し、テーブルと接続を片付けます。 パスワードは環境変数で渡します。

import os
from machbaseAPI import connect

conn = connect(
    host=os.getenv('MACH_HOST', '127.0.0.1'),
    port=int(os.getenv('MACH_PORT', '5656')),
    user=os.getenv('MACH_USER', 'SYS'),
    password=os.environ['MACHBASE_PASSWORD'],
)
cur = conn.cursor()

try:
    cur.execute(
        'CREATE LOG TABLE py_sample '
        '(ts DATETIME, device VARCHAR(40), value DOUBLE)'
    )
    cur.execute(
        "INSERT INTO py_sample VALUES ("
        "TO_DATE('2026-01-01','YYYY-MM-DD'), 'sensor-1', 20.5)"
    )
    cur.execute('SELECT device, value FROM py_sample')
    print(cur.fetchall())
finally:
    cur.execute('DROP TABLE py_sample')
    cur.close()
    conn.close()

結果の処理

DB-APIカーソルはexecute()fetchone()fetchall()を提供します。作業後にカーソルと接続を閉じ、 サンプルオブジェクトが本番データベースに残らないよう削除します。

INSERT結果のROWID

Standard EditionでDB-APIカーソルを使って単一のINSERT ... VALUESを実行した後、 cursor.lastrowidで入力行のROWIDを確認できます。

cursor.execute(
    "INSERT INTO orders(item) VALUES(%s)",
    ("pump",),
)
row_id = cursor.lastrowid

値は任意精度のPython intで、符号なし64ビットROWIDを正の値として保持します。 ROWIDのない実行ではNoneです。executemany()、Append、INSERT ... SELECT、UPSERTは ROWIDを返しません。実行失敗後も前の値を再利用しないでください。詳細な条件は ROWIDとINSERT結果IDを参照してください。

DB-API結果のNULL許容性メタデータ

DB-APIカーソルではcursor.description[i][6]null_ok値で、SELECT結果列のNULL許容性を 確認します。

cursor.execute(sql)

for column in cursor.description:
    name = column[0]
    null_ok = column[6]
    print(name, null_ok)
null_ok意味
FalseNULLにならない
TrueNULLになり得る
None判定不能

NoneNOT NULLを意味しないため、NULLが発生し得るものとして処理します。 SQL結果の判定規則は NULL許容性メタデータのサポート範囲を 参照してください。

Machbase SQLでは''はSQLのNULLのため、null_okTrueです。ただしPythonコネクターは、 互換性のため文字列型のSQL NULLをPythonの空文字列""として返す場合があります。 null_okは列のNULL許容性を示すもので、個々の行がNULLかは示しません。行ごとの区別が必要な場合は、 SQLのIS NULL条件またはそれを使用したCASE結果も検索してください。

SELECT結果のPRIMARY KEYメタデータ

Machbase 8.7.0サーバーと対応SDKを使用すると、cursor.column_metadatais_primary_keyで SELECT結果の直接の列がPRIMARY KEYか確認できます。

cursor.execute("SELECT ID, VALUE, ID + 1 AS ID_EXPR FROM T_PK")
for column in cursor.column_metadata:
    print(column.name, column.is_primary_key)

cursor.descriptionのDB-API標準の7番目の値(null_ok)は従来どおりNULL許容性のみを示します。 式・集計式・外部結合のNULL補完側の列はPKではないため、is_primary_keyFalseです。 旧バージョンのサーバーまたはSDKではPKフラグが提供されない場合があります。

Named Bind Parameter

Python DB-APIモジュールのparamstyle"named"です。cursor.execute()cursor.executemany()にマッピングを渡すと、:nameのSQLをサーバーのprepare/bind経路で実行します。

from decimal import Decimal
from machbaseAPI import connect

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

cur.execute(
    """INSERT INTO SENSOR_DATA (ID, NAME, VALUE)
       VALUES (:id, :name, :value)""",
    {
        "id": 600,
        "name": "python-client",
        "value": Decimal("52.125000"),
    },
)

cur.execute(
    """SELECT ID, NAME FROM SENSOR_DATA
       WHERE ID = :id OR PARENT_ID = :id""",
    {"id": 600},
)

executemany()では各行をマッピングとして渡します。

cur.executemany(
    "INSERT INTO SENSOR_DATA (ID, NAME, VALUE) "
    "VALUES (:id, :name, :value)",
    [
        {"id": 601, "name": "batch-a", "value": Decimal("1.5")},
        {"id": 602, "name": "batch-b", "value": None},
    ],
)

サーバーのプリペアドステートメントの寿命は、カーソルの種類と呼び出し方式によって異なります。

カーソル呼び出しサーバーの文の再利用範囲
通常カーソルexecute(sql, params)その呼び出しのみ
通常カーソルexecutemany(sql, rows)その呼び出し内
プリペアドカーソルexecute() / executemany()同じ元SQLを使用する後続の呼び出し

通常カーソルの:nameとマッピングはサーバーprepare/bindを使用しますが、呼び出しの完了時に文を閉じます。 複数の呼び出しで同じ文を再利用する場合はcursor(prepared=True)を使用します。

マッピングのキーは先頭のコロンなしで指定し、大文字・小文字を区別します。同名が繰り返されると1つの値を 全位置に適用します。名前の欠落、余分なキー、名前付きと位置指定の混用はProgrammingErrorを返します。 旧サーバーで名前付きAPIを使用すると、SQLSTATE 0A000NotSupportedErrorを返します。

互換性のため%s%(name)sも維持します。この2形式はクライアントでSQLリテラルを生成する通常カーソルの 既存経路です。プリペアドカーソルでは%s?%(name)s:nameへ変換し、サーバーの prepare/bind経路で実行します。

共通の名前構文は Named Bind Parameter syntaxを参照してください。

プリペアドカーソル(2.4)

connection.cursor(prepared=True)はサーバーのプリペアドステートメントを1つ保持し、同じSQLを 複数回実行する際に再利用します。繰り返しINSERT、条件検索、同じSQLのバッチ実行に使用します。

from machbaseAPI import connect

conn = connect(
    host="127.0.0.1",
    port=5656,
    user="SYS",
    password="MANAGER",
)
cur = conn.cursor(dictionary=False, raw=False, prepared=True)

sql = "INSERT INTO SENSOR_DATA (ID, NAME, VALUE) VALUES (%s, %s, %s)"
cur.execute(sql, (700, "sensor-a", 21.5))
cur.execute(sql, (701, "sensor-b", 22.1))
cur.executemany(
    sql,
    [
        (702, "sensor-c", 23.0),
        (703, "sensor-d", None),
    ],
)

cur.close()
conn.close()

cursor()の関連引数は次のとおりです。

  • dictionary=True: 検索結果を列名ベースの辞書として返します。
  • dictionary=False: 検索結果をタプルとして返します。
  • raw=True: 既存のraw結果の仕様を維持します。
  • prepared=True: 公開型MachbasePreparedCursorを返します。
  • prepared=False: 既存の通常カーソルを返すデフォルト値です。

パラメーターマーカー

プリペアドカーソルはPython DB-API形式とMachbaseネイティブ形式の両方をサポートします。

公開プレースホルダーサーバーのプレースホルダーパラメーター形式
%s?tuple、listなどのシーケンス
??tuple、listなどのシーケンス
%(name)s:namedictionaryなどのマッピング
:name:namedictionaryなどのマッピング

文字列リテラル、引用符で囲まれた識別子、--コメント、/* ... */コメント内のプレースホルダー状の 文字は変換しません。1つのSQLで位置指定と名前付きプレースホルダーを混用できません。 名前付きプレースホルダーの名前は英字、_$で始まり、以降は数字も使用できます。 名前付きプレースホルダーはMachbase 8.7.0サーバーと対応SDKでサポートします。

sql = (
    "SELECT ID, NAME FROM SENSOR_DATA "
    "WHERE ID = %(target)s OR PARENT_ID = %(target)s"
)
cur.execute(sql, {"target": 700})
rows = cur.fetchall()

文の再利用

プリペアドカーソルは、元のSQL文字列が前の呼び出しと完全に同じ場合にキャッシュしたサーバーの文を 再利用します。空白やコメントも含めて文字列が異なると、既存の文を解放して新しい文を準備します。

insert_cur = conn.cursor(prepared=True)
select_cur = conn.cursor(prepared=True)

1つのカーソルが保持するサーバーの文は1つです。複数のSQLをそれぞれ継続して再利用する場合は、 上記のようにSQLごとにプリペアドカーソルを作成します。executemany()終了後も文は保持され、 同じSQLの後続のexecute()またはexecutemany()で再利用されます。 空のパラメーターリストを渡すと、文を準備・実行せず0を返します。

エラーと終了

次の入力はProgrammingErrorになります。

  • プレースホルダーがあるのにパラメーターを渡さない場合
  • 位置指定プレースホルダーにマッピング、名前付きプレースホルダーにシーケンスを渡す場合
  • 位置指定と名前付きプレースホルダーを混用する場合
  • 名前付きパラメーターのキーが欠ける、または不要なキーが追加される場合
  • プレースホルダーのないSQLに空でないパラメーターを渡す場合

プレースホルダーのないSQLには、パラメーターなしとしてNone、空のシーケンス、空のマッピングを 渡せます。空のマッピングは内部でNoneに正規化されるため、プロトコルバージョンに関係なく同じ意味で 処理されます。

パラメーターエラーが発生してもキャッシュした文は保持されるため、正しいパラメーターで同じSQLを 再実行できます。旧サーバーで名前付きパラメーターを使用すると、サーバーのPREPARE前に NotSupportedErrorとSQLSTATE 0A000が発生します。このエラーは現在のキャッシュ文を解放・置換しません。 旧サーバーでは位置指定プレースホルダーを使用します。

cursor.close()はキャッシュしたサーバーの文を解放します。同じカーソルを2回閉じても安全で、 接続が先に閉じられた場合はネットワーク要求なしでローカル状態だけを解放します。 閉じたプリペアドカーソルでexecute()executemany()、フェッチAPIを呼ぶとInterfaceErrorになります。

プリペアドカーソルはSQLの許容範囲やPython APIのauto-commit動作を変更しません。 テーブル別のDML範囲はサポート範囲と制約を参照してください。

サポートAPIマトリクス

クラスAPI説明戻り値
machbaseopen(host, user, password, port)基本アカウントとポートでMachbaseサーバーに接続します。成功時1、失敗時0
machbaseopenEx(host, user, password, port, conn_str)追加の接続文字列プロパティで拡張接続します。1または0
machbaseclose()現在のセッションを終了します。1または0
machbaseisOpened()ハンドルが開いているか確認します。1または0
machbaseisConnected()サーバーとの接続状態を確認します。1または0
machbaseexecute(sql)SQLを直接実行します。SELECTWITHDESCDESCRIBESHOWselect()、それ以外は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
machbaseappendOpenColumns(table_name, columns, types=None)Machbase DBMS 8.7.0で選択列またはARRAY要素を対象に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.4)

API説明戻り値
connect(**kwargs)DB-API接続を作成。hostportuserpasswordなどはキーワード引数で渡します。MachbaseConnection
cursor(dictionary=True, raw=False, prepared=False)通常またはプリペアドカーソルを作成MachbaseCursorまたはMachbasePreparedCursor
cursor.execute(sql, params=None)SQLを実行cursor
cursor.executemany(sql, seq_of_params)同じSQLを複数のマッピングまたはシーケンスで実行実行回数
cursor.fetchone()1件取得`tuple
cursor.fetchmany(size)最大size件取得list
cursor.fetchall()全件取得list
cursor.description結果列メタデータ。7番目の値はnull_okです。`tuple
cursor.lastrowid成功した単一INSERTのROWID。非サポートの入力方式または失敗後はNoneです。`int
cursor.close()カーソルを終了None
cursor.rowcount影響行数int
connection.append(table, rows, *, types=None, times=None, date_format=..., strict=False, columns=None)Appendで行を追加。columnsは選択列またはARRAY要素対象を指定します。入力行数

2.3 Appendの型省略と末尾NULLパディング(推奨)

append()appendByTime()は型リストを省略して呼び出せます。第2引数に行の集合をそのまま渡すと、 サーバーメタデータに基づいて処理します。2.3以降は入力行の末尾の一部の列を省略でき、省略した列は AppendのNULLビットにより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 Appendの末尾NULLの例

connect().append()も同じ末尾NULLパディング規則を使用します。途中の列を飛ばす位置指定入力は サポートしないため、途中の値を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を明示しているため、valueNULLとして保存されます。

TAGテーブルのAppendとメタデータNULLの例

TAGテーブルはnametimevalueに対応する値まで必須です。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()

この例のstatussitelineはすべてNULLで保存されます。一方、valueを省略したTAGの Appendはエラーになります。

machbaseクラスの互換API

既存アプリケーションとの互換性のため維持されるmachbaseクラスを説明します。 新規コードには前述のDB-API connect()方式を推奨します。 getSessionId()count()checkBit()などは旧ネイティブパッケージにはありましたが、 現在の純粋なPython実装にはありません。必要に応じて2.4の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()は、送信済み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:
        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 * 1_000_000_000,
            1704106860 * 1_000_000_000,
        ]

        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()

aTimesは行と同じ順序のエポックナノ秒のシーケンスです。 秒単位のUnixタイムスタンプをそのまま渡さないでください。

ARRAYと選択列Append

Machbase DBMS 8.7.0はARRAYをPythonのlistで返し、prepared入力にはlistまたはtupleを 使用できます。要素NULLはコレクション内のNone、配列全体のNULLは列自体のNoneです。

列リストなしのconnection.append(table, rows)SparseArrayを渡すこともできます。

from machbaseAPI import SparseArray

sparse = SparseArray(4).set(1, 200).set(3, 400)
connection.append("ARRAY_APPEND_FULL_EXAMPLE", [[2, sparse]])

このコードはID LONG, A INT32[4]テーブルと開いた接続を前提とします。全体NULL・空のスパース配列・ 結果確認を含む通常入力の例を参照してください。 legacyラッパーにはappendOpen(table)の例が あります。

選択対象はconnection.append(..., columns=...)で指定します。行ごとに異なるARRAY位置を入力する 場合はSparseArrayを使用します。要素位置を指定した対象とSparseArray.set()の位置は0始まりです。

from machbaseAPI import SparseArray, connect

connection = connect(
    host="127.0.0.1",
    port=5656,
    user="SYS",
    password="MANAGER",
)
try:
    connection.append(
        "ARRAY_APPEND_EXAMPLE",
        [[1, 10, 40]],
        columns=["ID", "A[0]", "A[3]"],
    )

    sparse = SparseArray(4).set(1, 200).set(3, 400)
    connection.append(
        "ARRAY_APPEND_EXAMPLE",
        [[2, sparse]],
        columns=["ID", "A"],
    )
finally:
    connection.close()

SparseArray.clear()は要素数を維持して全要素をNULLに戻します。NULLの区別、検証、既存互換APIの 詳細例はSparse ARRAYと選択列Append APIを参照してください。

最終更新日