Соответствие многострочному выражению SQL в pgdump - PullRequest
0 голосов
/ 04 августа 2020

У меня есть PostgreSQL дамп базы данных pg_dump версии 9.5.2, который содержит DDL, а также INSERT INTO операторы для каждой таблицы в данной базе данных. Дамп выглядит так:

SET statement_timeout = 0;
SET lock_timeout = 0;
SET client_encoding = 'UTF8';

CREATE TABLE unimportant_table (
    id integer NOT NULL,
    col1 character varying
);

CREATE TABLE important_table (
    id integer NOT NULL,
    col2 character varying NOT NULL,
    unimportant_col character varying NOT NULL
);

INSERT INTO unimportant_table VALUES (123456, 'some data split into
-  multiple
-  lines
just for fun');

INSERT INTO important_table VALUES (987654321, 'some important data', 'another crap split into

-  lines');

...
-- thousands of inserts into both tables

Файл дампа действительно большой, и он создан другой компанией, поэтому я не могу повлиять на процесс экспорта. Мне нужно создать 2 файла из этого дампа:

  1. Все операторы DDL (все операторы, которые не начинаются с INSERT INTO)
  2. Все операторы INSERT INTO important_table (я хочу только восстановить некоторые таблицы из дампа)

Если все операторы будут в одной строке без символа новой строки в данных, будет очень легко создать скрипт 2 SQL с помощью grep, например:

grep -v '^INSERT INTO .*;$' my_dump.sql > ddl.sql
grep -o '^INSERT INTO important_table .*;$' my_dump.sql > important_table.sql
# Create empty structures
psql < ddl.sql
# Import only one table for now
psql < important_table.sql

Сначала я думал об использовании grep, но я не нашел, как обрабатывать несколько строк одновременно, затем я попробовал sed, но он возвращает только однострочные вставки. Я также использовал https://regex101.com/, чтобы найти правильное регулярное выражение, но я не знаю, как объединить его с grep или sed:

^(?!(INSERT INTO)).*$                              -- for ddl
^INSERT INTO important_table(\s|[[:alnum:]])*;$    -- for inserts

Я нашел аналогичный вопрос pcregrep multiline SQL match , но ответа нет. Кроме того, я не возражаю, если решение будет работать с grep, sed или с чем угодно, что вы предлагаете, но оно должно работать на Ubuntu 18.04.4 TLS.

1 Ответ

1 голос
/ 04 августа 2020

Вот решение на основе bash, которое использует perl однострочники для подготовки данных SQL дампа для последующих операторов grep. В моем подходе цель состоит в том, чтобы получить один оператор SQL в одной строке через сценарий, который я назвал prepare.sh. Это стало немного сложнее, потому что я хотел разместить точки с запятой и кавычки в ваших строках данных вставки (они, наряду с разрывами строк, представлены их шестнадцатеричными кодами в промежуточных вывод):

РЕДАКТИРОВАТЬ: В ответ на комментарий @ 32cupo ниже приведен модифицированный набор сценариев, который позволяет избежать xargs с большими наборами данных (хотя у меня нет огромных файлов дампа для тестирования):

#!/bin/bash
perl -pne 's/;(?=\s*$)/__ENDOFSTATEMENT__/g' \
| perl -pne 's/\\/\\\\x5c/g' \
| perl -pne 's/\n/\\\\x0a/g' \
| perl -pne 's/"/\\\\x22/g' \
| perl -pne 's/'\''/\\\\x27/g' \
| perl -pne 's/__ENDOFSTATEMENT__/;\n/g' \

Затем отдельный скрипт (называемый ddl.sh) включает ваш grep оператор для DDL (и с помощью l oop передает только меньшие фрагменты (строки) в xargs):

#!/bin/bash
while read -r line; do
    <<<"$line" xargs -I{} echo -e "{}"
done < <(grep -viE '^(\\\\x0a)*insert into')

Другой отдельный сценарий (называемый important_table.sh) включает ваш оператор grep для вставляет в important-table :

#!/bin/bash
while read -r line; do
    <<<"$line" xargs -I{} echo -e "{}"
done < <(grep -iE '^(\\\\x0a)*insert into important_table')

Вот набор скриптов в действии (обратите внимание, что я добавил в ваши данные вставки точки с запятой и кавычки):

~/$ cat dump.sql
SET statement_timeout = 0;
SET lock_timeout = 0;
SET client_encoding = 'UTF8';

CREATE TABLE unimportant_table (
    id integer NOT NULL,
    col1 character varying
);

CREATE TABLE important_table (
    id integer NOT NULL,
    col2 character varying NOT NULL,
    unimportant_col character varying NOT NULL
);

INSERT INTO unimportant_table VALUES (123456, 'some data split into
-  multiple
-  lines
;just for fun');

INSERT INTO important_table VALUES (987654321, 'some important ";data"', 'another crap split into
-  lines;');

...
-- thousands of inserts into both tables
~/$ cat dump.sql | ./prepare.sh | ./ddl.sh >ddl.sql
~/$ cat ddl.sql
SET statement_timeout = 0;

SET lock_timeout = 0;

SET client_encoding = 'UTF8';


CREATE TABLE unimportant_table (
    id integer NOT NULL,
    col1 character varying
);


CREATE TABLE important_table (
    id integer NOT NULL,
    col2 character varying NOT NULL,
    unimportant_col character varying NOT NULL
);


...
-- thousands of inserts into both tables

~/$ cat dump.sql | ./prepare.sh | ./important_table.sh > important_table.sql
~/$ cat important_table.sql


INSERT INTO important_table VALUES (987654321, 'some important ";data"', 'another crap split into
-  lines;');
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...