今回、C言語が変換元として指定されたのは、C言語で書かれたシステムが大量に存在するからだとDARPは今回の発表の中で次のように説明しています。
米国防総省DARPA、C言語のコードからRustへの自動変換実現を目指す「TRACTOR」プログラム開始 - Publickey
⇧ う~む、Pythonの内部で利用されてるっぽいCPythonとかを刷新して欲しい気がしますな...
他にも、コアな部分でC言語に依存しているプログラミング言語とかありそうな気がするので、影響範囲が広過ぎる気はしますな...
PostgreSQLのPL/pgSQLとは?
PostgreSQLの公式のドキュメントによると、
43.1. 概要
PL/pgSQLは、PostgreSQLデータベースシステム用の読み込み可能な手続き言語です。
PL/pgSQLの設計目的は、次のような読み込み可能な手続き言語でした。
PL/pgSQLで作成した関数は、組み込み関数が使えるところであれば、どこでも使用できます。
PostgreSQL 9.0以降ではPL/pgSQLはデフォルトでインストールされます。 しかしこれはまだロード可能なモジュールですので、特にセキュリティに厳しい管理者は削除することもできます。
⇧ う~む、分からん...
公式のドキュメントではないですが、
一方バックエンドの方は、中心となるのがデータベース処理を実行するデータベースエンジンです。 データベースエンジンにはユーザが作成したアプリケーションを実行する機能があります。 この機能を使って、ユーザは柔軟に PostgreSQL の機能を拡張できます。 良く利用されるのは、ほかのデータベースで言うところの「ストアドプロシジャ」で、PostgreSQL ではユーザ定義関数と呼びます。言語別に以下のようなものが利用できます。
⇧ 上記サイト様によりますと、他の「RDBMS(Relational DataBase Management Systems)」だと「ストアドプロシージャ」と呼ばれる機能が、PostgreSQLでは「ユーザー定義関数」と呼ばれ、「PL/pgSQL」はPostgreSQLの「ユーザー定義関数」を実現するPostgreSQLの機能の1つということらしい。
と思ったら、
2018年 10月にリリースされたPostgreSQL11からストアド・プロシージャが実装されています。
⇧ 上記サイト様によりますと、「PostgreSQL 11」からPostgreSQLにも「ストアド・プロシージャ」が導入されたらしいという情報もあり、情報が錯綜しておりますと...
カオス過ぎるんだが...
ストアド・ファンクションの主な特徴は、下記の通りです。
⇧ とりあえず、
- PL/pgSQL
- function ←関数
- procedure ←プロシージャ
のどちらかを作る感じになるということなんでしょうかね?
話が脱線しましたが、「PL/pgSQL」の「関数」ないしは「プロシージャ」は、PostgreSQLのインストールされているマシンで作成でき、保管もされると思われますと。
一応、PostgreSQLの公式のドキュメントによると、
インスタンスのすべてのSQLオブジェクトの構造を記述するテーブルの集まり。 システムカタログはpg_catalog
スキーマに存在します。 これらのテーブルは内部表現のデータを格納しているので、典型的にはユーザが調べる目的には適しません。 pg_catalog
スキーマにもユーザによりわかりやすい多くのビューが提供されており、一部の情報にはより便利なアクセスを提供しています。 一方SQL標準によって管理されているものと同じあるいはさらに追加の情報を提供するinformation_schema
スキーマ(第37章参照)に追加のテーブルとビューがあります。
詳細については5.9を参照してください。
https://www.postgresql.jp/document/16/html/glossary.html#GLOSSARY-SYSTEM-CATALOG
⇧ PostgreSQLで用意されている「システムカタログ」というテーブル群があり、
53.39. pg_proc
pg_proc
カタログは関数、プロシージャ、集約関数あるいはWINDOW関数(これらをまとめてルーチンとも言います)に関する情報を格納します。 CREATE FUNCTION、CREATE PROCEDUREと38.3を参照してください。
https://www.postgresql.jp/document/16/html/catalog-pg-proc.html
⇧ PostgreSQLの「PL/pgSQL」で作成した「関数」の情報も格納されるとあるので。
PythonでPostgreSQLのPL/pgSQLを利用するには、PostgreSQLのドライバーがインストールされていれば良さ気
で、Pythonのアプリケーションの話にはなりますが、「PL/pgSQL」の「関数」を実行するには、
⇧ Python側で、PostgreSQLのドライバーがインストールされていれば良さそうでありますと。
とりあえず、
⇧ Python向けのPostgreSQLのドライバーは、5つ用意されておりますと。
自分の環境では、
⇧ 前回の記事で、「psycopg3」をインストールしていたので、Python側から「PL/pgSQL」の「関数」を呼び出すための要件は整っていそう。
PostgreSQL側でPL/pgSQLの関数を作成する
Python側から呼び出す「PL/pgSQL」の「関数」を、PostgreSQL側で作成します。
⇧ 上記サイト様を参考に作成してみます。
気を付けたいのが、テーブル名の部分は、
- 「ダブルクォーテーション」で囲む
- 「スキーマ名.テーブル名」の形にする
のいずれかにしていないとエラーが出てしまうことがあるということでしょうか、と言うかエラーになって実行できなかったんで...
「user」テーブルという名前が、PostgreSQLのオブジェクトとバッティングしたりしてるってことなのかな?
ネット上の情報だと、テーブル名だけの記述のサンプルが多いからして、正解が分からない...
コーディングのルールとかハッキリさせて欲しいんですけどね...
PostgreSQLにログインし、以下を実行。
CREATE OR REPLACE FUNCTION select_all_user_func() RETURNS SETOF "user" AS $$ BEGIN -- userテーブルから全レコードを取得し、結果を返す RETURN QUERY SELECT * FROM "user"; END; $$ LANGUAGE plpgsql;
作成できているか、「pg_proc」テーブルを確認してみます。
⇧「pg_proc」テーブルに追加されているので「PL/pgSQL」の「関数」が作成できていそうです。
PythonからPostgreSQLのPL/pgSQLの関数を呼び出してみる
では、「VS Code(Visual Studio Code)」で、「PL/pgSQL」の「関数」を呼び出すPythonのソースコードを追加していきます。
その前に
⇧ PostgreSQLのデータベースとしてtestdbを作成しており、userテーブルを作成していて、1レコード登録してある状態です。
今回、追加したソースコード以外は、
⇧ 上記の記事の時のものを利用しています。
ソースコードは、以下のようになりました。
今回は、「PL/pgSQL」の「関数」が呼び出せるかどうかのチェックをしたいだけだったので、手っ取り早く試すために、データベース接続情報とかハードコーディングしてしまっていますが、外部ファイルに定義するようにして、外部ファイルから読み込むようにしましょう。
■C:\Users\Toshinobu\Desktop\soft_work\python_work\fastapi\app\src\main\py\call\procedural_language\select_all_user_func.py
import asyncio import sys from pprint import pprint from typing import List from sqlalchemy import func, select from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine from sqlalchemy.orm import sessionmaker from app.src.main.py.entity.user_entity import UserEntity # Windows環境でのイベントループポリシーの設定 if sys.platform == "win32": asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) # from sqlalchemy.ext.compiler import compiles ################################################################ # PostgreSQLのデータベース接続情報 ################################################################ CONNECTION_DB_URL = "postgresql+psycopg://test_user:password@172.24.91.141:5432/testdb" engine = create_async_engine(CONNECTION_DB_URL, echo=True) async_session = sessionmaker(engine, expire_on_commit=False, class_=AsyncSession) ################################################################ # PL/pgSQLの関数を呼び出す処理の関数 ################################################################ # async def call_select_all_user_func() -> UserEntity: # async with async_session() as session: # result = await session.execute(select(func.select_all_user_func())) # print("■■■PL/PgSQLの関数の呼び出し結果■■■") # pprint(result) # users = result.fetchall() # pprint(users) # if not users: # print("No users found.") # return users async def call_select_all_user_func() -> List[UserEntity]: async with async_session() as session: result = await session.execute(select(func.select_all_user_func())) print("■■■PL/PgSQLの関数の呼び出し結果■■■") pprint(result) users = result.scalars().all() print("■■■users■■■") print(type(users)) pprint(users) if not users: print("No users found.") return users ################################################################ # メイン処理 ################################################################ ################################################################ # 関数を呼び出す ################################################################ # users = asyncio.run(call_select_all_user_func()) # if users: # for user in users: # print(user) # else: # print("The user table is empty.") users = asyncio.run(call_select_all_user_func()) if users: for user in users: print(user) else: print("The user table is empty.")
で、保存。実行すると、
⇧「PL/pgSQL」の「関数」を呼び出すことができていそうです。
とりあえず、
- psycopg3
- SQLAlchemy
のどちらの公式ドキュメントにも、「PL/pgSQL」の「関数」をPythonから呼び出す実装の方法についての言及が見当たらなかったんよね...
stackoverflowの情報とMicrosoft Copilotの情報を元にコーディングしてるから、正しい実装になっているのか判断が付かない...
公式のドキュメントで記載されていないのなら、記載して欲しいと思う今日この頃...
不毛な時間に疲弊するのみですな...
毎度モヤモヤ感が半端ない…
今回はこのへんで。