↑ ↑ ↓ ↓ ← → ← → B A Start

Патчим mysqldump в домашних условиях

Бекапы это хорошо, а еще лучше когда они работают так как надо когда они нужны. На одном из проектов понадобилось восстановить дамп из 745 триггеров и накатить их на рабочую MySQL базу. 

MySQL позволяет использовать любые имена триггеров, в том числе с использованием точек (например: analitica.cron.indeg.y.run.a_insert). А mysqldump при создании дампа не учитывает это обстоятельство и добавляет конструкцию для их дропа следующего вида:

/*!50032 DROP TRIGGER IF EXISTS analitica.cron.indeg.y.run.a_insert */;

Подвох ожидает при попытке эти дампы накатить на базу где эти триггеры уже созданы. С точки зрения MySQL этот запрос не дропнет триггер, потому что не найдет триггер с таким именем. Для корректной работы имя триггера должно быть заключено в апострофы.

В попытках найти обходное решение зарепортил соответствующий репорт в баг трекер Перконы, а они уже продублировали аналогичный репорт в официальный трекер MySQL.

Поскольку исправлять этот баг будут долго, а дампы мне нужны прямой сейчас. Решить эту задачу я решил самым прямолинейным способом, а именно самостоятельно пропатчив mysqldump. Для этого склонировал официальный репозиторий перконовского дитрибутива MySQL 5.6 с GitHub’а.

git clone --recursive --depth 1 https://github.com/percona/percona-server/

Открыл файл client/mysqldump.c и добавил апострофы к конструкции DROP TRIGGER IF EXISTS в паре мест. Если посмотреть diff, то получается такой патч:

@@ -3517,7 +3517,7 @@ static void dump_trigger_old(FILE *sql_file, MYSQL_RES *show_triggers_rs,
     fprintf(sql_file, "/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;\n");

   if (opt_drop_trigger)
-    fprintf(sql_file, "/*!50032 DROP TRIGGER IF EXISTS %s */;\n", (*show_trigger_row)[0]);
+    fprintf(sql_file, "/*!50032 DROP TRIGGER IF EXISTS `%s` */;\n", (*show_trigger_row)[0]);

   fprintf(sql_file,
           "DELIMITER ;;\n"
@@ -3604,7 +3604,7 @@ static int dump_trigger(FILE *sql_file, MYSQL_RES *show_create_trigger_rs,
     switch_sql_mode(sql_file, ";", row[1]);

     if (opt_drop_trigger)
-      fprintf(sql_file, "/*!50032 DROP TRIGGER IF EXISTS %s */;\n", row[0]);
+      fprintf(sql_file, "/*!50032 DROP TRIGGER IF EXISTS `%s` */;\n", row[0]);

Чтобы собрать пропатченую версию надо поставить пару пакетов и на Ubuntu/Debian, запустить cmake с параметрами из документации к Перконе, а затем make‘ом собрать только mysqldump.

apt-get install build-essential cmake bison libaio-dev libncurses5-dev libreadline-dev
cmake . -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_CONFIG=mysql_release -DFEATURE_SET=community -DWITH_EMBEDDED_SERVER=OFF
make mysqldump

После компиляции получаем патченую версию mysqldump, в которой имена триггеров экранируются корректно. Можно дампить новым дампером:

./percona-server/client/mysqldump \
    --socket=/var/run/mysqld/mysqld.sock \
    -uroot -p --routines --events --triggers \
    --add-drop-trigger --quote-names \
    --no-create-info --no-data --no-create-db --skip-opt \
    database_name | sed -r 's/DEFINER[ ]*=[ ]*[^*]*\*/\*/' > dump.sql

Как я стал электронным гражданином Эстонии

В начале мая я прочитал заметку в которой шла речь о начале предоставления Эстонией электронного гражданства. Полученную таким образом визу можно использовать чтобы подписывать документы электронной подписью, открывать банковский счет в эстонский банках и регистрировать фирму. Для получения электронного гражданства требовалось — заполнить анкету и оплатить визовый сбор.

Решение заполнить анкету появилось под влиянием хайпа, а увидев среди пунктов обоснований получения электронного гражданства пункт «Fan of e-Residency» заполнил все поля, оплатил и стал ждать.

Первое письмо получил ровно через месяц после подачи анкеты 18 июля. В письме сообщалось, что моя анкета принята к рассмотрению, а спустя еще месяц, 20 июля пришло сообщение о положительном решении.

e-Residency

И вот наконец спустя почти 3 месяца ожидания я получил в посольстве заветный и скромный конверт, содержащий в себе:

  • Непосредственно карточку с чипом;
  • Небольшой складной USB считывать;
  • Конверт с PIN/PUK кодами.

Наиболее любопытным из этого набора оказался USB считыватель карточки который из формата usb-флешки раскладывается в Т-образную конструкцию для подключения карточки к ноутбуку. 

e-Residency

Для работы с картой есть два убогих приложения. Одно из них установит сертификат в браузер, для идентификации и позволяет менять PIN коды. Второе приложение позволяет подписывать документы, шифровать любые файлы и получить доступ к почте в домене @eesti.ee.

Raspberry Pi - Cheat Sheet

Установка дистрибутива на SD

Raspberry PI SD Installer OS X — простой консольный скрипт для записи любых .img или .iso образов на SD флешки. Использование на OSX или Linux:

sudo ./install ~/Downloads/raspbian.img

Нахождение Raspberry Pi в сети

Подключили ethernet кабель, вставили флешку с Raspbian и запустили, но нет лишнего HDMI монитора и клавиатуры? Выход есть и это — Adafruit Raspberry Pi Finder. Использование на OSX или Linux:

curl -SLs https://apt.adafruit.com/bootstrap | bash
  • Найдет Raspberry Pi в локальной сети по MAC-адресу;
  • Установит Occidentalis для настройки Wi-Fi соединения;
  • Установит и настроит набор сетевых утилит, таких как avahi-daemon и netatalk.

Общая системная конфигурация

sudo raspi-config

Настройка Wi-Fi соединения

Самый простой способ настройки Wi-Fi соединения, это установить Adafruit Occidentalis. Теперь чтобы настроить Hostname и Wi-Fi достаточно просто создать текстовый файл /boot/occidentalis.txt и после перезагрузки автоматически произойдет настройка всех сетевых интерфейсов:

# Пример файла /boot/occidentalis.txt

# hostname for your Raspberry Pi:
hostname=mypiname

# basic wireless networking options:
wifi_ssid="your network here"
wifi_password="your password or passphrase here"

Установка русской локали

sudo nano /etc/locale.gen
sudo locale-gen

Настройка часового пояса

echo "Europe/Moscow" | sudo tee /etc/timezone
sudo dpkg-reconfigure --frontend noninteractive tzdata

Настройка соединения с Bluetooth клавиатурой

Установка необходимых пакетов:

apt-get --no-install-recommends install bluetooth bluez-utils python-gobject

Показать локальные устройства

hcitool dev

Запросить удалённые устройства

hcitool scan

Запросить спаривание с клавиатурой, ввести любой PIN, потом затем ввести такой же на клавиатуре и нажать enter.

bluez-simple-agent hci0 xx:xx:xx:xx:xx:xx

После подтверждения спаривания необходимо подключить само устройство и добавить к автоматическому подключению в дальнейшем:

bluez-test-device trusted xx:xx:xx:xx:xx:xx yes
bluez-test-input connect xx:xx:xx:xx:xx:xx yes

Также этот документ доступен на Github, форки и дополнения приветствуются GIST

Книги о путешествиях и не только

Подборка из пяти книг о путешествиях, которые я прочитал с начала 2015 года и советую тем, кто так же как и я не равнодушен к такого рода литературе.

«Пляж», Алекс Гарленд — столько раз путешествовал в Таиланд, а эта книга каждый раз ускользала из моего поля интересов. Теперь же спустя год после посещения района островов, описанных в книге, прочитал ее и не пожалел. Приятно сравнить современный Бангкок с видением города образца 1995 года.

«Tokyo on Foot», Florent Chavouet — красочный путеводитель (если это можно так назвать) французского художника по городу Токио. Переехав на шесть месяцев в Японию он каждый день делал зарисовки и заметки того, что происходило вокруг него. Каждую страницу этого путеводителя хочется разглядывать до мелочей.

«Самый большой дурак под солнцем», Кристоф Рехаге — книга на которую я случайно обратил внимание еще в Венгерском аэропорту, и купив которую я прочитал запоем меньше чем за неделю. Это увлекательная история о человеке совершившем путешествие пешком через Китай, и взгляд европейца на современный Китай, за пределами крупных городов и конечно это истории людей, которых он встречал на своем пути.

«Journeys of a Lifetime: 500 of the World’s Greatest Trips» — очень большая и красивая книга, определенно прекрасный источник вдохновения для будущих путешествий.

«Shoreditch Wild Life», Dougie Wallace — альбом фотографий весёлого и безумного лондонского квартала — Шордич. Именно здесь проходят самые долгие и шумные вечеринки, по улицам ходят фрики всех мастей, а стены домов пестрят работами именитых граффити-художников.

Особенности работы с MS-SQL в Yii Framework 2

В очередной раз связавшись с взаимодействием Microsoft SQL Server и PHP, в том числе через Yii 2, наступил на пару граблей о которых хотел бы рассказать.

Установка кодировки UTF-8

Подключаясь к MS-SQL серверу напрямую через *PDO* невозможно поставить кодировку отличную от CP1251, а чтобы поставить UTF-8 лучше использовать прослойку FreeTDS, которая ставится на сервер и прозрачно проксирует все запросы на удаленный сервер. Стандартная установка в Debian/Ubuntu через apt-get:

apt-get install php5-sybase freetds-bin freetds-dev

Когда все установлено необходимо добавить в конфигурацию FreeTDS новую секцию с параметрами MS-SQL сервера:

[mssqlserver]
;   Если servername составной (10.10.0.1/production),
;   то необходимо разбить на host и instance
;   и не указывать port
host = 10.10.0.1
instance = production
client charset = UTF-8
tds version = 7.0
text size = 20971520

А в Yii 2 приложении строку подключения необходимо модифицировать, заменив адрес сервера на название секции из конфига FreeTDS. Например стандартный файл /config/db.php может иметь вид:

<?php

return [
    'class' => 'yii\db\Connection',
    'dsn' => 'dblib:host=mssqlserver;dbname=my_database',
    'username' => 'sa',
    'password' => 'superpass',
    'charset' => 'utf8',
];

Хранимые процедуры

С хранимыми процедурами MS-SQL не все так однозначно, и если они возвращают курсор, то в этом случае нет проблем и можно вызывать так:

$command = Yii::$app->db->createCommand('EXEC GetOrderInfo @guid=:orderguid');
$command->bindValue(':orderguid', '43b9f14e-4953-416a-a83e-6bb9e8cd0493');
$result = $command->queryAll();

Если же процедура (в примере ниже Proc2) возвращает int, то описанный выше метод не сработает и необходимо выкручиваться описывая курсор самостоятельно, используя такую конструкцию:

$command = Yii::$app->db->createCommand("EXEC ('
    DECLARE @result int;
    EXEC @result = Proc2;
    SELECT @result;
')");
$result = $command->queryScalar();

И наконец небольшой SQL запрос для тех хочет получить полный текст процедуры, а также получить список и тип входящих параметров, которые администратры MS-SQL серверов так не любят описывать в документации:

SELECT OBJECT_DEFINITION (OBJECT_ID(N'Proc2'))