nataraj: (Default)
[personal profile] nataraj
Есть дамп mysql'ной базы. Задача: вынуть оттуда данные.
Разворачивать этот дамп в базу категорически не хочется... Хотя бы потому что в проекте mysql не используется...
Парсить регулярными выражениями строки в которых заведомо внутри кавычек могут оказаться скобки, запятые и те же кавычки закранированные слэшами -- удовльствия мало.

Предполагаемое решение:

# my $str = "INSERT INTO `libbook` VALUES (1,'Aarh_Andrej_Aida',7162,'2007-06-20 13:24:00','Аида',0,0,'ru','fb2',0,'','','1.0','Mon Jun 10 21:40:30 2013'),(2,'Aarh_Andrej_Arlekino_i_P\\'ero',8066,'2007-06-20 13:24:01','Арлекино и Пьеро',0,0,'ru','fb2',0,'','','1.0','Mon Jun 10 21:40:30 2013');";

open F, 'lib.libbook.sql';
my $str;
while ($str = )
{
last if $str =~ /^INSERT INTO \`libbook\` VALUES \(/;
}

$str =~s/^INSERT INTO \`libbook\` VALUES \(/\=\(\[/; # Все начинается с "=(["
$str =~s/\)\,\(/\]\,\[/g; # Заменяем круглые скобки на квадратные
$str =~s/\)\;/\]\)\;/;

# Двойные кавычки экранировать не надо, ибо они в mysql уже заэкранированны.

$str =~s/(\d)\,\'/$1\,\"/g; # заменяем одинарные кавычки на двойные
$str =~s/\'\,(\d)/\"\,$1/g;
$str =~s/\'\,\'/\"\,\"/g;
$str =~s/\'\]/\"\]/g;

$str =~ s/([A-Za-z])/"\\x".unpack("H*",$1)/ge; # заменяем все латинские буквы на /x последовательности (типа защита от ijection)
$str = '@l'.$str; # добавляем в начало @l в которую все это будет присваиваться...

my @l=();

eval $str;

foreach (@l)
{
print $_->[0]," - ",$_->[1]," - \t", $_->[4],"\n";
}

Date: 2007-12-19 07:02 am (UTC)
vitus_wagner: My photo 2005 (Default)
From: [personal profile] vitus_wagner
вообще-то есть модуль SQL:Statement. может-поможет?

Date: 2007-12-19 09:14 am (UTC)
ext_613079: Default userpic (Default)
From: [identity profile] shaplov.livejournal.com
О спасибо!
Почитаю...

Date: 2007-12-19 08:16 pm (UTC)
ext_613079: Default userpic (Default)
From: [identity profile] shaplov.livejournal.com
Тохлая форона... не прег'од'иллость...

испытания показали, что оно не умеет работать с многочисленными VALUES при INSERT

use SQL::Statement;
use Data::Dumper;
my $parser = SQL::Parser->new();
$parser->{RaiseError}=1;
$parser->{PrintError}=0;

my $sql = "INSERT INTO aaa VALUES ('aaa','bbb',123)";
# my $sql = "INSERT INTO aaa VALUES ('aaa','bbb',123),('ccc','ddd',333)";

my $stmt = SQL::Statement->new($sql,$parser);
my @rowValues = $stmt->row_values();
print Dumper(\@rowValues);

Если раскомментировать закомментированную строку, то работать перестает...

Date: 2007-12-19 08:20 pm (UTC)
vitus_wagner: My photo 2005 (Default)
From: [personal profile] vitus_wagner
Поправь. Это будет проще чем писать парсер самому, с нуля. Потому что авторы его хотя и не учли эту особенность синтаксиса, но наверняка учли десяток других, о которых ты не вспомнишь, пока не напорешься посреди многомегабайтного дампа.

Или хотя бы почитай внимательно на предмет того, какие грабли они там обходят.

Date: 2007-12-19 09:18 pm (UTC)
ext_613079: Default userpic (Default)
From: [identity profile] shaplov.livejournal.com
Это будет проще чем писать парсер самому, с нуля.
Тут фокус в том, что я не пишу парсер... Я использую родной парсер перла. Данные от INSERT'а очень сильно похожи на массив ArrayRef'ов. С точностью до квадратности скобок и двойности кавычек. Чем я и решил воспользваоться.

пока не напорешься посреди многомегабайтного дампа.
Я на многомегобайтном дампе это уже проверял....
Грабли вида, в очень редких местах вдруг в тексте круглая скобка заменилась на квадратную, меня вполне устраивают, в рамках этой задачи...


Или хотя бы почитай внимательно на предмет того, какие грабли они там обходят.
Мне более интересно, какие грабли они туда положили... Конструкция вида
my $sql = "INSERT INTO aaa VALUES (111,222,'aaa'),('sss',555,666)";
работает корректно. А вот если поменять строку на число -- работать перестает...
Я конечно попробую посмотреть может в cpan'е лежит более правильная версия... Но... не радует меня модуль в котором такие ошибки...

Date: 2007-12-29 06:28 am (UTC)
From: [identity profile] vnaum.livejournal.com
> Тут фокус в том, что я не пишу парсер... Я использую родной парсер перла.
Ты его eval-ишь?
Чужие данные?
Неизвестно кем написанные?
Меня терзают смутные сомнения, что скормить его mysql-клиенту (http://shaplov.livejournal.com/351695.html?thread=1126607#t1126607) всё-таки будет безопаснее на порядок...

Date: 2007-12-29 12:01 pm (UTC)
ext_613079: Default userpic (Default)
From: [identity profile] shaplov.livejournal.com
Задача: задать такой $str чтобы например, созадлся пустой файл с именем aaa в текущей директории

my $str = '("bbb","ccc","ddd");';

$str =~ s/([A-Za-z])/"\\x".unpack("H*",$1)/ge;
$str =~ s/([\$\@\%\`])/\\$1/g;

my @l =();
$str="\@l =$str";
eval $str;

Я решения не вижу.
Edited Date: 2007-12-29 12:02 pm (UTC)

Date: 2007-12-29 03:54 pm (UTC)
From: [identity profile] vnaum.livejournal.com
Тут мало не видеть решения, надо видеть отсутствие решения.
Как говорит Шнайер, "каждый может придумать шифр, который не в силах разгадать".
Извольте:
my $str = '("bbb","ccc","ddd",\`>aaa\`);';

Для сравнения:
Если мы вместо GRANT ALL явно распишем что можно делать (CREATE TABLE, DROP TABLE и INSERT) - то внутри базы он не сможет сделать ничего, кроме того что мы перечислили (mysql обещает).
Остаются "команды клиента", вроде вызова команд оболочки через "\!". Как с этим бороться - известно давно, создаётся непривилегированный пользователь без домашнего каталога. По вкусу - chroot и ulimit.

Date: 2007-12-20 06:15 pm (UTC)
ext_613079: Default userpic (Default)
From: [identity profile] shaplov.livejournal.com
Почитал код. Она вообще не должна уметь многострочный INSERT. Почему получалось так, что таки частично умеет, разбираться не стал...

Date: 2007-12-19 09:03 am (UTC)
From: [identity profile] beldmit.livejournal.com
Коля. Любовь к трем велосипедам... Ну зачем бы не плюнуть дамп в базу, если операция разовая?

Date: 2007-12-19 09:13 am (UTC)
ext_613079: Default userpic (Default)
From: [identity profile] shaplov.livejournal.com
Не... операция эта примерно из серии раз в месяц. Дамп приходит от третьей стороны и к тому же по не шифрованному каналу. То есть в ней, если смотреть параноидально, может оказаться любой код... Что можно сделать получив рутовую(!) консоль к мусклю -- я боюсь себе даже представить... Поэтому как угодно, только через не через sql'ный интерпретатор... Думаю по ссылке Витуса схожу, перед тем как окончательно что-то писать...
Edited Date: 2007-12-19 09:15 am (UTC)

Date: 2007-12-19 12:37 pm (UTC)
From: [identity profile] vnaum.livejournal.com
> Что можно сделать получив рутовую(!) консоль к мусклю -- я боюсь себе даже
> представить...

Зачем рутовую-то?
GRANT ALL ON loaddb.* TO someuser
И от этого someuser грузить.

Date: 2007-12-19 07:54 pm (UTC)
ext_613079: Default userpic (Default)
From: [identity profile] shaplov.livejournal.com
Гм... да... действительно... там не надо создавать базы данных, только таблицы... В этом месте я пожалуй не прав.
Но даже не рутовую консоль от mysql'я все равно доверять третьей стороне -- не очень хорошо. Я не верю что через нее нельзя mysql хакнуть...

Date: 2007-12-19 08:21 pm (UTC)
vitus_wagner: My photo 2005 (Default)
From: [personal profile] vitus_wagner
Интересно, а SQLite этот дамп не сожрет? SQLite все же демоническими свойствами не обладает - обычный юзерский процесс, который работает с одним конкретным файлом в файловой системе.

Profile

nataraj: (Default)
Swami Dhyan Nataraj

July 2024

S M T W T F S
 123456
789 10111213
14151617181920
21222324252627
28293031   

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 21st, 2026 03:13 am
Powered by Dreamwidth Studios