Подсветка синтаксиса PostgreSQL

    Спешу поделиться хорошей новостью: жизнь авторов статей про PostgreSQL и их читателей стала немного лучше.

    Как знают все хаброписатели, для оформления исходного кода используется специальный тег <source>, который подсвечивает синтаксис. Не секрет также, что подсветка не всегда получается идеальной, и тогда авторы (которым не все равно, как выглядят их статьи) вынуждены заниматься самодеятельностью — расцвечивать свой код с помощью <font color=...>.

    Особенно печально все было с PostgreSQL, поскольку подсветка охватывала более или менее стандартный SQL и категорически не понимала специфики нашей СУБД. Шло время, Алексей boomburum старательно исправлял мои font-ы на source (а я — обратно), пока не стало очевидно, что подсветку надо чинить. Наконец Далер daleraliyorov подсказал выход: добавить поддержку PostgreSQL в библиотеку highlightjs, которой пользуется Хабр. И вот — готово, встречайте.

    pgsql: SQL, PL/pgSQL и все-все-все


    Итак, секрет правильной подсветки — в новом языке pgsql. Его можно выбрать в меню (кнопка «исходный код») или указать вручную. В html для этого надо написать

    <source lang="pgsql">
    мой код
    </source>

    а в markdown — так:

    ```pgsql
    мой код
    ```

    В принципе, highlightjs умеет определять язык сама, но нормально это работает только для больших фрагментов кода; на маленьких кусочках автоопределение часто промахивается. Кроме того, автоопределение требует времени, так что если указать язык явно, код быстрее заиграет красками.

    Например, чтобы получить

    CREATE TABLE aircrafts_data (
        aircraft_code character(3) NOT NULL,
        model jsonb NOT NULL,
        range integer NOT NULL,
        CONSTRAINT aircrafts_range_check CHECK ((range > 0))
    );
    

    мы пишем

    <source lang="pgsql">
    CREATE TABLE aircrafts_data (
        aircraft_code character(3) NOT NULL,
        model jsonb NOT NULL,
        range integer NOT NULL,
        CONSTRAINT aircrafts_range_check CHECK ((range > 0))
    );
    </source>

    Тот же самый язык pgsql расцвечивает и код на PL/pgSQL. Например, чтобы получить

    CREATE FUNCTION get_available_flightid(date) RETURNS SETOF integer AS $$
    BEGIN
      RETURN QUERY
        SELECT flightid FROM flight WHERE flightdate >= $1 AND flightdate < ($1 + 1);
      IF NOT FOUND THEN
        RAISE EXCEPTION 'Нет рейсов на дату: %.', $1;
      END IF;
      RETURN;
    END
    $$ LANGUAGE plpgsql;
    

    пишем

    <source lang="pgsql">
    CREATE FUNCTION get_available_flightid(date) RETURNS SETOF integer AS $$
    ...
    $$ LANGUAGE plpgsql;
    </source>

    Небольшая тонкость состоит в том, что символьные строки, заключенные в доллары, всегда подсвечиваются как код, а строки в апострофах не подсвечиваются никогда. Я рассматривал разные варианты, но именно этот показался наиболее адекватным.

    Способность highlightjs автоматически определять язык фрагмента позволяет подсвечивать функции и на других языках. Например, все будет работать и для PL/Perl:

    CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$
        my ($x, $y) = @_;
        if (not defined $x) {
            return undef if not defined $y;
            return $y;
        }
        return $x if not defined $y;
        return $x if $x > $y;
        return $y;
    $$ LANGUAGE plperl;
    

    Для этого не нужно ничего специального, просто пишем

    <source lang="pgsql">
    CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$
    ...
    $$ LANGUAGE plperl;
    </source>

    Конечно, выбранный язык зависит только от того, что написано внутри долларов, и никак не определяется тем, что написано после LANGUAGE.

    В целом подсветка соответствует вышедшей недавно 11-й версии PostgreSQL.

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

    plaintext: текст, просто текст


    Иногда в статье требуется оформить результаты запроса. Конечно, никаких ключевых слов там нет, подсвечивать ничего не нужно, но хочется, чтобы текст смотрелся «консольно», так же, как код. Для этого теперь можно использовать специальный язык plaintext. Например, чтобы получить

    WITH xmldata(data) AS (VALUES ($$
    <example xmlns="http://example.com/myns" xmlns:B="http://example.com/b">
     <item foo="1" B:bar="2"/>
     <item foo="3" B:bar="4"/>
     <item foo="4" B:bar="5"/>
    </example>$$::xml)
    )
    SELECT xmltable.*
      FROM XMLTABLE(XMLNAMESPACES('http://example.com/myns' AS x,
                                  'http://example.com/b' AS "B"),
                 '/x:example/x:item'
                    PASSING (SELECT data FROM xmldata)
                    COLUMNS foo int PATH '@foo',
                      bar int PATH '@B:bar');
    

     foo | bar
    -----+-----
       1 |   2
       3 |   4
       4 |   5
    (3 rows)
    

    пишем

    <source lang="pgsql">
    WITH xmldata(data) AS (VALUES ($$
    ...
    </source>
    <source lang="plaintext">
     foo | bar
    -----+-----
       1 |   2
       3 |   4
       4 |   5
    (3 rows)
    </source>

    Plaintext всегда надо указывать явно, автоматически он не определяется.

    Надеюсь, что нововведение вам понравится и пригодится. Если найдете ошибку в том, как подсвечивается код (а ошибки неизбежны, слишком уж контекстно-зависимый синтаксис у SQL), создавайте задачу на github проекта, а еще лучше — предлагайте решение.

    P. S. Не забывайте про конференцию PGConf, которая состоится 4–6 февраля в Москве. Заявки на доклады принимаются до 5 декабря!
    • +25
    • 5,2k
    • 5
    Postgres Professional
    224,00
    Российский вендор PostgreSQL
    Поделиться публикацией

    Комментарии 5

      +1
      выбранный язык зависит только от того, что написано внутри долларов,

      Это непонятно. Как именно определяется язык? python и JS тоже правильно подсвечиваются?
        +1
        Определяется автоматически тем механизмом, который есть в библиотеке. Грубо говоря, по очереди пробуется каждый язык и выбирается тот, который нашел больше всего подходящих «фрагментов».

        Но выбор идет не из всего списка языков, а из того, что ожидаемо встретить в контексте Постгреса (чтобы уменьшить ложные срабатывания). Сейчас это (кроме самого pgsql): perl, python, tcl, r, lua, java, php, ruby, bash, scheme, xml, json. Почему-то javascript я не вписал… Поправлю при случае.
        +2
        Спасибо за своего рода пост-анонс, наверное, не будем повторяться в блоге компании (ну или вкратце упомянем это изменение в следующей пятничной «Прямой линии») :)

        Действительно, с тегом source иногда были проблемы — сейчас, если явно не указан алиас одного из поддерживаемых языков, подсветки не будет (как это было раньше). Решили так сделать для того, чтобы у пользователей грузилось меньше кода (даже когда не нужно что-то подсвечивать), а авторы, если хотят подсветки, могут сами её указать.

        Насчёт раскраски кода путём font color — это, скорее, костыль был и здорово, что в нём сейчас нет потребности.
          0
          если явно не указан алиас одного из поддерживаемых языков, подсветки не будет (как это было раньше)

          Наверное, это сильно раньше было, потому что еще пару дней назад раскрашивалось автоматически (:
          Но в целом правильное решение имхо.
            0
            Да, это поменялось буквально вчера-позавчера.

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое