Мы делаем LibreDB Studio, SQL-редактор под MIT (https://github.com/libredb/libredb-studio).
В прошлый раз я публиковал здесь анонс проекта, и обратная связь оказалась полезнее, чем где бы то ни было ещё, поэтому прихожу с вопросом, а не с релизом.Вопрос поднял один из контрибьюторов, и у нас нет уверенного ответа. Пусть в редакторе набрано:
```
CREATE TABLE test (...);
INSERT INTO test VALUES (...);
SELECT * FROM test;
```
Что должно произойти по "Выполнить"?
Варианты, которые мы рассматриваем:
1. Выполняется весь буфер. Для части кода есть отдельное "Выполнить выделенное".
2. Выполняется оператор под курсором. Весь буфер идёт через отдельное "Выполнить всё".
3. Выделение имеет приоритет: нет выделения, выполняется оператор под курсором; есть выделение, выполняется выделенное; "Выполнить всё" вынесено отдельно.
Как сейчас сделано у нас, чтобы вопрос не выглядел абстрактным: работает третий вариант, но без последней части. Есть выделение, выполняется оно; нет выделения, выполняется оператор, внутри которого стоит курсор. Отдельной команды "Выполнить всё" нет вообще, весь буфер можно выполнить только через Ctrl+A. Это и есть дыра, из-за которой мы вообще завели обсуждение.
Отдельный вопрос, который на практике оказывается важнее первого: транзакции. Должен ли скрипт из нескольких операторов по умолчанию идти в одной транзакции, или управление транзакцией всегда остаётся явным делом пользователя?
Что у нас сделано сейчас и почему:
- Неявная транзакция не открывается. Операторы выполняются последовательно, выполнение останавливается на первой ошибке.
- Если пользователь сам написал BEGIN и не написал COMMIT, транзакция откатывается по завершении скрипта. Причина не в идеологии, а измерена: соединение кэшируется на уровне процесса и переиспользуется, поэтому оставленная открытой транзакция достаётся следующему запросу. На PostgreSQL 17 следующий запрос другого пользователя получал "current transaction is aborted", на SQLite и DuckDB его запись просто терялась.
- Разбор на операторы идёт по диалекту, а не по простому поиску ";". Причина тоже измерена: PostgreSQL вкладывает блочные комментарии, поэтому /* a /* b */ ; DROP TABLE users; -- */ SELECT 1 там является одним оператором, а плоский разбор превращал его в три, второй из которых был голый DROP. Для Cassandra, ScyllaDB и ClickHouse та же история с //.
Интересно услышать, к чему вы привыкли и что считаете правильным: DBeaver, DataGrip, SSMS, pgAdmin, TablePlus, Toad, PL/SQL Developer, phpMyAdmin ведут себя по-разному. Ответы вида "я работаю в psql и GUI мне не нужен" тоже полезны, тогда напишите, какое именно поведение psql вы хотели бы видеть воспроизведённым: autocommit по оператору, \i, ON_ERROR_STOP.
Обсуждение на GitHub, если хочется посмотреть исходную формулировку или ответить там: https://github.com/orgs/libredb/discussions/776