この記事はPostgreSQL Advent Calendar 2019の23日目の記事です。
昨日はnuko_yokohamaさんのQONに関する記事でした。とてもタメになる内容でしたね!本日の記事も皆さんのお役に立てるよう頑張って書きましたので、ご査収のほどよろしくお願い申し上げます。
はじめに
Pythonできると金持ちになれると聞いて、Pythonの学習をはじめました。そう、PL/Pythonですね!
学習方針
どうせお勉強するなら楽しくなくちゃね!ということで、昔買ったRaspberry Piを引っ張り出してきて、そこにPostgreSQL入れてお勉強することにしました。
学習環境
学習環境は以下の通りです。
製品/ソフトウェア | バージョン | 備考 |
---|---|---|
Raspberry Pi | 1 Model B | だいぶ古い |
Raspbian | 10(buster) | 結構新しい |
Python | 2.7.16 | busterに入ってた |
PostgreSQL | 11.5 | apt-getで入れた |
環境構築
SDカードには古いRaspbianが入ってたので、一掃してbusterを入れ直しました。ネットワークはWifiでつなげるのですが、この辺もUSBさしてチョロチョロっと設定すれば簡単につながりました。便利な世の中です。
Pythonも同梱されてるので、さくっと学習をはじめられます。
$ python --version
Python 2.7.16
続けてPostgreSQLのインストール。ソースからビルドしても良かったのですが、なんとなくapt-getでインストールしてみました。ついでに今回の主役であるPL/Pythonも。
# apt-get install postgresql
# apt-get install postgresql-plpython-11
この状態ではまだPL/Python使えないので、CREATE LANGUAGEで登録!
testdb=# CREATE LANGUAGE plpythonu;
CREATE LANGUAGE
testdb=# select * from pg_language ;
lanname | lanowner | lanispl | lanpltrusted | lanplcallfoid | laninline | lanvalidator | lanacl
-----------+----------+---------+--------------+---------------+-----------+--------------+--------
internal | 10 | f | f | 0 | 0 | 2246 |
c | 10 | f | f | 0 | 0 | 2247 |
sql | 10 | f | t | 0 | 0 | 2248 |
plpgsql | 10 | t | t | 13088 | 13089 | 13090 |
plpythonu | 10 | t | f | 16386 | 16387 | 16388 |
(5 行)
余談
Rasbian は、DebianベースのOSなのでPostgreSQLパッケージの内容もちょっと違うのね。pg_ctlがなくて最初面食らったYO!
代わりにpg_ctlclusterってのが入ってた。
https://manpages.debian.org/buster/postgresql-common/pg_ctlcluster.1.en.html
Lesson 1
やっぱり学習の最初は「Hello, World」ですね。
$ cat helloworld.sql
CREATE OR REPLACE FUNCTION hello()
RETURNS TEXT
AS $$
return 'Hello, World'
$$ LANGUAGE plpythonu;
$ psql -f helloworld.sql testdb
CREATE FUNCTION
$ psql testdb -c "SELECT hello();"
hello
--------------
Hello, World
(1 行)
動きました!
もう少し躓いたりするかな?と思ってたけど、意外とあっさり動いてしまいました。
Lesson 2
次はせっかく Raspberry Pi 使ってるので Lチカやりましょう。Lチカ。
今回使った Raspberry Pi 1 Model B でも26pinのGPIO(General Purpose Input/Output)がついてるので、さくっと光らせてみます!
$ cat led.sql
CREATE OR REPLACE FUNCTION led()
RETURNS void
AS $$
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
LED = 17
WAIT_TIME = 5
GPIO.setup(LED, GPIO.OUT)
GPIO.output(LED, GPIO.HIGH)
time.sleep(WAIT_TIME)
GPIO.output(LED, GPIO.LOW)
GPIO.cleanup()
$$ LANGUAGE plpythonu;
$ psql -f led.sql testdb
CREATE FUNCTION
led関数内で、
- ピン17に電気流す(GPIO.HIGH)
- 5秒停止
- ピン17の電気を止める(GPIO.LOW)
するだけのシンプルなものです。
関数も登録できて「楽勝!」と思いきや、あれ?
「光らんばい!!」
どうやら、postgresユーザにgpio使う権限が入ってないのが問題だった模様。
ということで、postgresくんをgpioグループ(997)に混ぜてあげて、pg_ctlclusterで再起動。
pg_ctlclusterは、引数にバージョン・クラスタを指定する必要があります。バージョン・クラスタはpg_lsclustersで確認できます。
# id postgres
uid=110(postgres) gid=116(postgres) groups=116(postgres),997(gpio),115(ssl-cert)
# pg_lsclusters
Ver Cluster Port Status Owner Data directory Log file
11 main 5432 online postgres /var/lib/postgresql/11/main /var/log/postgresql/postgresql-11-main.log
# pg_ctlcluster 11 main restart
改めて、いざLチカ!
$ psql testdb -c "SELECT led()"
led
-----
(1 行)
おー、眩しいです!
いざ、実践!
ここまでできると廻したくなるのが人の性。
AKBまでサーボモータ買いに行ってきました!
トリガ関数を使って、これを回すYO!
$ cat survo_test360_trigger.sql
CREATE TABLE IF NOT EXISTS test(i int);
CREATE OR REPLACE FUNCTION survo360_trig()
RETURNS trigger
AS $$
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
gp_out = 18
GPIO.setup(gp_out, GPIO.OUT)
servo = GPIO.PWM(gp_out, 50)
servo.start(0)
servo.ChangeDutyCycle(8.0)
time.sleep(1.0)
servo.stop()
GPIO.cleanup()
$$ LANGUAGE plpythonu;
CREATE TRIGGER trig_survo360 BEFORE INSERT OR UPDATE OR DELETE ON test
FOR EACH ROW EXECUTE FUNCTION survo360_trig();
$ psql test -f survo_test360_trigger.sql
CREATE TABLE
CREATE FUNCTION
CREATE TRIGGER
こちらの関数では、PWM(Pulse Width Module)というのを使って周波数密度を変えてサーボモータを制御してます。
これで無事にtestテーブルへのDML(INSERT/UPDATE/DELETE)発行でサーボモータを廻すことに成功しました!
Zoetrope
せっかくなのでZoetrope作ってみました〜
Zoetrope(回転のぞき絵)
回転のぞき絵(かいてんのぞきえ、英: Zoetrope、仏: Zootrope)とは、静止画を素早く入れ替えることで、あたかも動いているかのように見せる器具。
WikiPediaより
slonikくんも楽しげに廻ってくれるようになりました。
現場からは以上です。
まとめ
今年も毒にも薬にもならないエントリでしたが、これからも楽しくPostgreSQLライフを送りたいと思います!
明日はatmitaniさんの「PostgreSQLの統計情報を可視化(環境構築編)」ということで本当に役に立ちそうで楽しみです〜。