⌨ Labor omnia vincit ☮

Common Lisp, MySQL and openSUSE

Posted in Lisp, SuSE [ru] by anaumov on 06.03.2015

functionalС недавних пор позволил себе наглость писать на Common Lisp’е (CL) на работе. Добрался до скриптов, которые до меня были написанны на perl’e, а точнее – понадобилось кое-что в них добавить, и я решил, что переписать их на CL будет и быстрее и полезнее для меня. Скажу сразу, что нет ничего, что можно сделать на CL, но нельзя, к примеру, на perl или python. Другим будет лишь подход к решению, несмотря на то, что, к примеру, на python тоже можно очень не плохо писать в функциональном стиле. Именно из-за этого подхода программисты CL находят его использование столь интересным, гибким и выразительным.
В этом посте я постараюсь показать, что в использование CL нет ничего сверхестественного. Дополнительные библиотеки, скачиваемые из интернета, стандартная библиотека языка… постораемся сделать что-то практическое.

Итак, я использую clisp, и quicklisp в качестве library manager’a. На его домашней странице вы найдете подробное руководство по установке и использовании.

Для начала найдем все библиотеки, имена которых содержат “mysql”:

> (ql:system-apropos "mysql")

#SYSTEM cl-mysql / cl-mysql-20120208-git / quicklisp 2014-08-26>
#SYSTEM cl-mysql-test / cl-mysql-20120208-git / quicklisp 2014-08-26>
#SYSTEM clsql-mysql / clsql-20140713-git / quicklisp 2014-08-26>
#SYSTEM dbd-mysql / cl-dbi-20140826-git / quicklisp 2014-08-26>

Нам нужна cl-mysql. Устанавливаем:

> (ql:quickload "cl-mysql")

To load "cl-mysql":
  Install 5 Quicklisp releases:
    alexandria babel cffi cl-mysql trivial-features
; Fetching #
; 8.09KB
==================================================
8,284 bytes in 0.00 seconds (8736.33KB/sec)
; Fetching #
; 238.72KB
==================================================
244,450 bytes in 0.54 seconds (438.44KB/sec)
; Fetching #
; 48.70KB
==================================================
49,872 bytes in 0.03 seconds (1763.46KB/sec)
; Fetching #
; 207.21KB
==================================================
212,186 bytes in 0.37 seconds (567.45KB/sec)
; Fetching #
; 24.96KB
==================================================
25,561 bytes in 0.09 seconds (268.06KB/sec)
; Loading "cl-mysql"
[package alexandria.0.dev]........................
[package babel-encodings].........................
[package babel]...................................
[package cffi-sys]................................
[package cffi]....................................
[package cffi-features]...........................
[package com.hackinghat.cl-mysql-system]..
*** - Unable to load foreign library (LIBMYSQLCLIENT).
      FFI:OPEN-FOREIGN-LIBRARY: Cannot open library "libmysqlclient_r.so":
"libmysqlclient_r.so: cannot open shared object file: No such file or directory"
The following restarts are available:
RETRY          :R1      Try loading the foreign library again.
USE-VALUE      :R2      Use another library instead.
SKIP           :R3      skip 75 75 (USE-FOREIGN-LIBRARY LIBMYSQLCLIENT)-4
RETRY          :R4      retry 75 75 (USE-FOREIGN-LIBRARY LIBMYSQLCLIENT)-4
STOP           :R5      stop loading file /home/anaumov/.cache/common-lisp/clisp-2.49- \
unix-x64/home/anaumov/quicklisp/dists/quicklisp/software/cl-mysql-20120208-git/system.fas
TRY-RECOMPILING :R6     Recompile system and try loading it again
RETRY          :R7      Retry loading FASL for #.
ACCEPT         :R8      Continue, treating loading FASL for # as having been successful.
ABORT          :R9      Give up on "cl-mysql"
ABORT          :R10     Abort main loop
Break 1 CL-MYSQL-SYSTEM[4]>

Знакомая всем пользователям Linux ошибка отсутствия необходимой библиотеки. Clisp-интерпретатор предлагает несколько вариантов дальнейшей работы. Мы продолжим работу с ним, но для начала нам нужно установить rpm-пакет (в другой консоли), содержащий файл libmysqlclient_r.so:

> sudo zypper in libmysqlclient_r18

> rpm -ql libmysqlclient_r18
/usr/lib64/libmysqlclient_r.so.18
/usr/lib64/libmysqlclient_r.so.18.0.0

> cd /usr/lib64
# ln -s libmysqlclient.so.18.0.0 libmysqlclient_r.so

Последняя команда создает линк из-за несоответствия имени библиотеки. После этого возвращаемся в clisp (оставили его открытым?) и предлагаем попробывать еще раз: RETRY. После этого уснановка продолжается. Проверим все ли в порядке, и можем ли мы теперь работать с базой данных:

> (use-package :cl-mysql)
T

> (cl-mysql:connect
   :host "127.0.0.1"
   :database "centreon"
   :user "user"
   :password "foobar")
#COM.HACKINGHAT.CL-MYSQL-SYSTEM:CONNECTION-POOL #x0003345319D8

Connect выводит адрес созданного пула – объекта cl-mysql пакета. Его синтаксис, кстати, один в один напоминает аналог из sqlalchemy. Синтаксис позволяет использовать язык SQL в качестве параметра cl-mysql:query, поэтому тут тоже ничего нового. Рассмотрим один пример.

(defun views-columns()
    (cl-mysql:connect :host "127.0.0.1"
                      :database "information_schema"
                      :user "user"
                      :password "foobar")

    (loop for i in (car (car (cl-mysql:query "show columns from VIEW")))
        do (format t "~A~%" i)))

Заголовок (шапку таблицы) мы получаем в виде еще одного cписка. Я обрезал его при помощи car.
Вот что выдаст функция views-columns:

(TABLE_CATALOG varchar(512) YES NIL NIL NIL)
(TABLE_SCHEMA varchar(64) NO NIL NIL NIL)
(TABLE_NAME varchar(64) NO NIL NIL NIL)
(VIEW_DEFINITION longtext NO NIL NIL NIL)
(CHECK_OPTION varchar(8) NO NIL NIL NIL)
(IS_UPDATABLE varchar(3) NO NIL NIL NIL)
(DEFINER varchar(77) NO NIL NIL NIL)
(SECURITY_TYPE varchar(7) NO NIL NIL NIL)
(CHARACTER_SET_CLIENT varchar(32) NO NIL NIL NIL)
(COLLATION_CONNECTION varchar(32) NO NIL NIL NIL)

Для сравнения вывод той же команды в mysql-интрепретаторе:

mysql> show columns from VIEWS;
+----------------------+--------------+------+-----+---------+-------+
| Field                | Type         | Null | Key | Default | Extra |
+----------------------+--------------+------+-----+---------+-------+
| TABLE_CATALOG        | varchar(512) | YES  |     | NULL    |       |
| TABLE_SCHEMA         | varchar(64)  | NO   |     |         |       |
| TABLE_NAME           | varchar(64)  | NO   |     |         |       |
| VIEW_DEFINITION      | longtext     | NO   |     | NULL    |       |
| CHECK_OPTION         | varchar(8)   | NO   |     |         |       |
| IS_UPDATABLE         | varchar(3)   | NO   |     |         |       |
| DEFINER              | varchar(77)  | NO   |     |         |       |
| SECURITY_TYPE        | varchar(7)   | NO   |     |         |       |
| CHARACTER_SET_CLIENT | varchar(32)  | NO   |     |         |       |
| COLLATION_CONNECTION | varchar(32)  | NO   |     |         |       |
+----------------------+--------------+------+-----+---------+-------+
10 rows in set (0.02 sec)

to be or not to be

Вопреки распространенному мнению, Lisp жив. Библиотеки, как мы только что убедились, для него есть, они поддерживаются, и их установка не вызывает никаких проблем. Синтаксис CL очень схож с python: cкобки вы перестанене замечать уже на следующий день его использования, а ориентироваться в коде будете по отступам.

Зачем Lisp, когда есть Python? Если кого-то до сих пор задается этим вопросом, загляните в статью Ерика Реймонда или, возможно, вас заинтересует мнение Ричарда Столлмана. Сам я далеко не специалист в Lisp, тем не менее программирование на CL помогает мне лучше писать функциональный код на, к примеру, том же python. Многие идеи, реализованные в Lisp полвека назад, только начинают сейчас включать в Java, в python они до сих пор реализованны частично.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: