Code Monkey home page Code Monkey logo

sqlfmt's Introduction

sqlfmt's People

Contributors

ajwerner avatar knz avatar maddyblue avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sqlfmt's Issues

Undefined errors from CockroachDB when trying to build

I've definitely ran make in the $GOPATH/src/github.com/cockroachdb/cockroach dir, but still seem to be getting this undefined errors.

โžœ  sqlfmt git:(master) bash build.sh
+ IMG=gcr.io/hots-cockroach/sqlfmt:latest
+ go build -o sqlfmt
# github.com/cockroachdb/cockroach/pkg/sql/lex
../../cockroachdb/cockroach/pkg/sql/lex/keywords.go:10:32: undefined: ABORT
../../cockroachdb/cockroach/pkg/sql/lex/keywords.go:11:32: undefined: ACTION
../../cockroachdb/cockroach/pkg/sql/lex/keywords.go:12:32: undefined: ADD
../../cockroachdb/cockroach/pkg/sql/lex/keywords.go:13:32: undefined: ADMIN
../../cockroachdb/cockroach/pkg/sql/lex/keywords.go:14:32: undefined: AGGREGATE
../../cockroachdb/cockroach/pkg/sql/lex/keywords.go:15:32: undefined: ALL
../../cockroachdb/cockroach/pkg/sql/lex/keywords.go:16:32: undefined: ALTER
../../cockroachdb/cockroach/pkg/sql/lex/keywords.go:17:32: undefined: ANALYSE
../../cockroachdb/cockroach/pkg/sql/lex/keywords.go:18:32: undefined: ANALYZE
../../cockroachdb/cockroach/pkg/sql/lex/keywords.go:19:32: undefined: AND
../../cockroachdb/cockroach/pkg/sql/lex/keywords.go:19:32: too many errors

Additional double quotation marks added to the T-SQL statement

see example below:

SELECT len(ISNUll(tableName.clumn,'')) AS CloumnLength FROM tableName;

The formatted SQL was:

SELECT len("isnull"(tablename.clumn, '')) AS cloumnlength FROM tablename;

Additional double quotation marks were added around isnull, it was incorrect.

Purpose: SQL or CockroachDB-flavored SQL?

This library uses the CockroachDB SQL parser, which effectively limits it to use with just CockroachDB, since CockroachDB lacks significant amounts of SQL support: WITH RECURSIVE, CREATE FUNCTION, and CREATE TYPE. And that's just standard ANSI SQL.

IMO, this should either

  1. advertise as CockroachDB SQL formatter

  2. fork from the CockroachDB parser so as to allow contributions to support SQL syntax (regardless of CockroachDB support).

Support for gopherjs

It would be great if we can add support for gopherjs so that we can use the formatter in the browser.

"Fuller" mode with JOIN keywords on the left of "full" mode's center line

C.f.,

    SELECT DISTINCT
           category0_.id AS id1_0_0_,
           segmentati1_.category_id AS category1_9_1_,
           segmentati1_.segmentation_id AS segmenta2_9_1_,
           segmentati2_.id AS id1_8_2_,
           inputtype3_.id AS id1_4_3_,
           operator5_.id AS id1_5_4_,
           configurat6_.key AS key1_1_5_,
           configurat6_.segmentation_id AS segmenta2_1_5_,
           options7_.key AS key1_6_6_,
           ...
      FROM category AS category0_
INNER JOIN segmentation_category AS segmentati1_ ON category0_.id = segmentati1_.category_id
INNER JOIN segmentation AS segmentati2_ ON segmentati1_.segmentation_id = segmentati2_.id
INNER JOIN input_type AS inputtype3_ ON segmentati2_.input_type_id = inputtype3_.id
 LEFT JOIN segmentation_operator AS operators4_ ON segmentati2_.id = operators4_.segmentation_id
 LEFT JOIN operator AS operator5_ ON operators4_.operator_id = operator5_.id
 LEFT JOIN configuration AS configurat6_ ON segmentati2_.id = configurat6_.segmentation_id
 LEFT JOIN option AS options7_ ON segmentati2_.id = options7_.segmentation_id
 LEFT JOIN context AS context8_ ON segmentati2_.context_id = context8_.id
 LEFT JOIN permission AS permission9_ ON segmentati2_.id = permission9_.segmentation_id AND permission9_.mnemonic = '?'
 LEFT JOIN feature AS feature10_ ON segmentati2_.feature_id = feature10_.id
     WHERE category0_.active = true
       AND segmentati2_.active = true
       AND (permission9_.mnemonic IS NULL AND permission9_.segmentation_id IS NULL AND segmentati2_.limited = false OR permission9_.authorized = true)
       AND (feature10_.id IS NULL OR feature10_.active = true AND feature10_.key IN ('?', '?', '?', '?', '?', '?', '?', '?'))
  ORDER BY category0_.ordinality, options7_.display;

vs.

  SELECT DISTINCT
         category0_.id AS id1_0_0_,
         segmentati1_.category_id AS category1_9_1_,
         segmentati1_.segmentation_id AS segmenta2_9_1_,
         segmentati2_.id AS id1_8_2_,
         inputtype3_.id AS id1_4_3_,
         operator5_.id AS id1_5_4_,
         configurat6_.key AS key1_1_5_,
         configurat6_.segmentation_id AS segmenta2_1_5_,
         options7_.key AS key1_6_6_,
         options7_.segmentation_id AS segmenta2_6_6_,
         context8_.id AS id1_2_7_,
         category0_.created_on AS created_2_0_0_,
         category0_.updated_on AS updated_3_0_0_,
         category0_.active AS active4_0_0_,
         category0_.description AS descript5_0_0_,
         category0_.display AS display6_0_0_,
         category0_.key AS key7_0_0_,
         category0_.ordinality AS ordinali8_0_0_,
         segmentati1_.created_on AS created_3_9_1_,
         segmentati1_.updated_on AS updated_4_9_1_,
         segmentati1_.ordinality AS ordinali5_9_1_,
         segmentati1_.category_id AS category1_9_0__,
         segmentati1_.segmentation_id AS segmenta2_9_0__,
         segmentati1_.ordinality AS ordinali5_0__,
         segmentati2_.created_on AS created_2_8_2_,
         segmentati2_.updated_on AS updated_3_8_2_,
         segmentati2_.active AS active4_8_2_,
         segmentati2_.attribute AS attribut5_8_2_,
         segmentati2_.context_id AS context12_8_2_,
         segmentati2_.description AS descript6_8_2_,
         segmentati2_.display AS display7_8_2_,
         segmentati2_.feature_id AS feature13_8_2_,
         segmentati2_.input_type_id AS input_t14_8_2_,
         segmentati2_.key AS key8_8_2_,
         segmentati2_.limited AS limited9_8_2_,
         segmentati2_.options_src AS options10_8_2_,
         segmentati2_.title AS title11_8_2_,
         inputtype3_.created_on AS created_2_4_3_,
         inputtype3_.updated_on AS updated_3_4_3_,
         inputtype3_.active AS active4_4_3_,
         inputtype3_.json_value AS json_val5_4_3_,
         inputtype3_.name AS name6_4_3_,
         operator5_.created_on AS created_2_5_4_,
         operator5_.updated_on AS updated_3_5_4_,
         operator5_.display AS display4_5_4_,
         operator5_.key AS key5_5_4_,
         operators4_.segmentation_id AS segmenta1_10_1__,
         operators4_.operator_id AS operator2_10_1__,
         configurat6_.created_on AS created_3_1_5_,
         configurat6_.updated_on AS updated_4_1_5_,
         configurat6_.bool_value AS bool_val5_1_5_,
         configurat6_.string_value AS string_v6_1_5_,
         configurat6_.segmentation_id AS segmenta2_1_2__,
         configurat6_.key AS key1_1_2__,
         options7_.created_on AS created_3_6_6_,
         options7_.updated_on AS updated_4_6_6_,
         options7_.display AS display5_6_6_,
         options7_.segmentation_id AS segmenta2_6_3__,
         options7_.key AS key1_6_3__,
         context8_.created_on AS created_2_2_7_,
         context8_.updated_on AS updated_3_2_7_,
         context8_.key AS key4_2_7_
    FROM category AS category0_
         INNER JOIN segmentation_category AS segmentati1_ ON category0_.id = segmentati1_.category_id
         INNER JOIN segmentation AS segmentati2_ ON segmentati1_.segmentation_id = segmentati2_.id
         INNER JOIN input_type AS inputtype3_ ON segmentati2_.input_type_id = inputtype3_.id
         LEFT JOIN segmentation_operator AS operators4_ ON segmentati2_.id = operators4_.segmentation_id
         LEFT JOIN operator AS operator5_ ON operators4_.operator_id = operator5_.id
         LEFT JOIN configuration AS configurat6_ ON segmentati2_.id = configurat6_.segmentation_id
         LEFT JOIN option AS options7_ ON segmentati2_.id = options7_.segmentation_id
         LEFT JOIN context AS context8_ ON segmentati2_.context_id = context8_.id
         LEFT JOIN permission AS permission9_ ON segmentati2_.id = permission9_.segmentation_id AND permission9_.mnemonic = '?'
         LEFT JOIN feature AS feature10_ ON segmentati2_.feature_id = feature10_.id
   WHERE category0_.active = true
     AND segmentati2_.active = true
     AND (permission9_.mnemonic IS NULL AND permission9_.segmentation_id IS NULL AND segmentati2_.limited = false OR permission9_.authorized = true)
     AND (feature10_.id IS NULL OR feature10_.active = true AND feature10_.key IN ('?', '?', '?', '?', '?', '?', '?', '?'))
ORDER BY category0_.ordinality, options7_.display;

Extensions

Hi there. This formats beautifully, but I have trouble using it with PostGIS (e.g. it doesn't like the distance operator, <->). Is there any way it could be made a bit more flexible? Perhaps it could take some kind of supplementary list of operators/keywords etc, and possibly some hints about how to deal with them??

union all

select a,b,c from x union all select d,e,f from y

consider supporting colorizing the output

Maybe have a function that wraps node types with annotations and a configuration file that maps node types to colors and another that shows how to output color (i.e., html, ascii).

Feature request: Ignore comments, don't strip them out

Let me know if this is the wrong place to file this. I didn't see any mention of comments in the README or in the sqlfmt blog post.

Given a section of a SQL file with comments like this:

-- How many users took rides that ended in NY?

SELECT COUNT(*) FROM (SELECT users.name, users.address, rides.end_address FROM users JOIN rides ON users.id = rides.rider_id WHERE users.address LIKE '%NY%');

-- +-------+
-- | count |
-- +-------+
-- |  2802 |
-- +-------+
-- (1 row)

If I run that selection through cockroach sqlfmt --use-spaces --align --print-width=78 --no-simplify in my editor, it strips out my comments and results in:

SELECT count(*)
  FROM (
        SELECT users.name, users.address, rides.end_address
          FROM users JOIN rides ON users.id = rides.rider_id
         WHERE users.address LIKE '%NY%'
       )

I would like to set up my editor to autoformat SQL code on save, but I use comments for notes to myself, etc. Possible to leave comments alone as they pass through? Happy for an option (which I understand you may prefer less) or for ignoring comments to be the default.

WITH RECURSIVE not implemented

From the docs: https://www.postgresql.org/docs/9.1/queries-with.html

Trying to fumpt this:

WITH RECURSIVE included_parts(sub_part, part, quantity) AS (
    SELECT sub_part, part, quantity FROM parts WHERE part = 'our_product'
  UNION ALL
    SELECT p.sub_part, p.part, p.quantity
    FROM included_parts pr, parts p
    WHERE p.part = pr.sub_part
  )
SELECT sub_part, SUM(quantity) as total_quantity
FROM included_parts
GROUP BY sub_part

results in unimplemented at or near "select"

Removing RECURSIVE will let it format successfully.

License?

Permissive license would be super-nice!

New release?

Hi, I was hoping to use the --no-extra-line flag but it is not released yet.
Would it be possible to cut a new release? Thanks!

Statement Parameters are not handled correctly

The common ones that I can think of are:

  • ?
  • $0, $1 ...
  • %0, %1 ...

I guess, it's probably best to handle ?, $, % with and without numbers.

e.g.

SELECT * FROM pg_catalog.pg_foreign_table WHERE ftrelid = ?;

try to reduce binary size

https://github.com/jondot/goweight says:

  9.9 MB github.com/cockroachdb/cockroach/pkg/roachpb
  7.0 MB github.com/cockroachdb/cockroach/vendor/github.com/DataDog/zstd
  6.2 MB github.com/cockroachdb/cockroach/pkg/sql/sem/tree
  4.5 MB github.com/cockroachdb/cockroach/pkg/sql/sem/builtins
  4.2 MB github.com/cockroachdb/cockroach/pkg/sql/sqlbase
  3.4 MB github.com/cockroachdb/cockroach/pkg/sql/parser
  3.4 MB net/http
  3.2 MB github.com/cockroachdb/cockroach/vendor/github.com/Shopify/sarama
  3.0 MB runtime
  2.5 MB github.com/cockroachdb/cockroach/vendor/github.com/gogo/protobuf/proto
  1.8 MB github.com/cockroachdb/cockroach/vendor/github.com/gogo/protobuf/types
  1.7 MB github.com/cockroachdb/cockroach/vendor/golang.org/x/net/http2
  1.7 MB github.com/cockroachdb/cockroach/vendor/github.com/lightstep/lightstep-tracer-go/thrift_0_9_2/lib/go/thrift
  1.7 MB github.com/cockroachdb/cockroach/vendor/github.com/apache/thrift/lib/go/thrift
  1.7 MB net
  1.6 MB github.com/cockroachdb/cockroach/vendor/github.com/golang/protobuf/proto
  1.4 MB github.com/cockroachdb/cockroach/vendor/golang.org/x/text/collate
  1.4 MB github.com/cockroachdb/cockroach/vendor/github.com/aws/aws-sdk-go/aws/endpoints
  1.4 MB reflect
  1.2 MB github.com/cockroachdb/cockroach/vendor/golang.org/x/sys/unix
  1.2 MB github.com/cockroachdb/cockroach/vendor/google.golang.org/grpc
  1.1 MB github.com/cockroachdb/cockroach/pkg/internal/client
  1.0 MB github.com/spf13/pflag
  1.0 MB github.com/cockroachdb/cockroach/vendor/github.com/prometheus/client_golang/prometheus
  991 kB github.com/cockroachdb/cockroach/pkg/util/json
  975 kB github.com/cockroachdb/cockroach/vendor/gopkg.in/yaml.v2
...

switch to post

this will allow huge queries to not blindly fail.

also show errors when the request returns an error.

ugly equal sign

SELECT
  this_.studentid AS studenti1_26_0_,
  this_.name AS name2_26_0_,
  this_.address_city AS address_3_26_0_,
  this_.address_state AS address_4_26_0_,
  this_.preferredcoursecode AS preferre5_26_0_
FROM
  student AS this_
WHERE
  EXISTS(
    SELECT
      enrolment_.studentid AS y0_
    FROM
      enrolment AS enrolment_
    WHERE
      enrolment_.year
      = (
          SELECT
            max(maxstudentenrolment_.year) AS y0_
          FROM
            enrolment AS maxstudentenrolment_
          WHERE
            this_.preferredcoursecode = maxstudentenrolment_.coursecode
        )
  );

option for preceeding commas please

SELECT
	this_.person_id AS person_i1_2_0_,
	this_.version AS version2_2_0_,
	this_.name AS name3_2_0_,
	this_.sex AS sex4_2_0_,
	this_.height_centimeters / 2.54E0 AS height_c5_2_0_,
	this_.address AS address6_2_0_,
	this_.zip AS zip7_2_0_,
	this_.country AS country8_2_0_,
	this_1_.title AS title2_0_0_,
	this_1_.salary AS salary3_0_0_,
	this_1_.pwd_expiry_weeks * 7.0E0 AS pwd_expi4_0_0_,
	this_1_.manager AS manager5_0_0_,
	this_2_.comments AS comments2_1_0_,
	this_2_.salesperson AS salesper3_1_0_
FROM A as this_;

vs

SELECT this_.person_id AS person_i1_2_0_
      ,this_.version AS version2_2_0_,
      ,this_.name AS name3_2_0_,
      ,this_.sex AS sex4_2_0_
      ,this_.height_centimeters / 2.54E0 AS height_c5_2_0_
      ,this_.address AS address6_2_0_
      ,this_.zip AS zip7_2_0_
      ,this_.country AS country8_2_0_
      ,this_1_.title AS title2_0_0_
      ,this_1_.salary AS salary3_0_0_
      ,this_1_.pwd_expiry_weeks * 7.0E0 AS pwd_expi4_0_0_
      ,this_1_.manager AS manager5_0_0_
      ,this_2_.comments AS comments2_1_0_
      ,this_2_.salesperson AS salesper3_1_0_
FROM A as this_;

Great (horrible) test query

This query is broken, badly:

Here's my hand formatted version:

SELECT array_to_string(array_agg(sql), e'\\n\\n') AS sql 
FROM (
    SELECT (
             (
               (
                 (
                   (
                     (
                       (
                         (
                           (
                             (
                               (
                                 (
                                   (
                                     (
                                       (
                                         (
                                           (
                                             (
                                               (
                                                 (
                                                   (
                                                     CASE WHEN rolcanlogin 
                                                       THEN '-- User: ' 
                                                       ELSE '-- Role: ' 
                                                     END || quote_ident(rolname)
                                                   ) || e'\\n-- DROP '
                                                 ) || CASE WHEN rolcanlogin 
                                                        THEN 'USER ' 
                                                        ELSE 'ROLE ' 
                                                      END
                                               ) || quote_ident(rolname)
                                             ) || e';\\n\\nCREATE '
                                           ) || CASE WHEN rolcanlogin 
                                                  THEN 'USER ' 
                                                  ELSE 'ROLE ' 
                                                END
                                         ) || quote_ident(rolname)
                                       ) || e' WITH\\n  '
                                     ) || CASE WHEN rolcanlogin 
                                            THEN 'LOGIN' 
                                            ELSE 'NOLOGIN' 
                                          END
                                   ) || e'\\n  '
                                 ) || CASE WHEN rolcanlogin AND (rolpassword LIKE 'md5%') 
                                        THEN ('ENCRYPTED PASSWORD ' || quote_literal(rolpassword)) || e'\\n  ' 
                                        ELSE '' 
                                      END
                               ) || CASE WHEN rolsuper 
                                      THEN 'SUPERUSER' 
                                      ELSE 'NOSUPERUSER' 
                                    END
                             ) || e'\\n  '
                           ) || CASE WHEN rolinherit 
                                  THEN 'INHERIT' 
                                  ELSE 'NOINHERIT' 
                                END
                         ) || e'\\n  '
                       ) || CASE WHEN rolcreatedb 
                              THEN 'CREATEDB' 
                              ELSE 'NOCREATEDB' 
                            END
                     ) || e'\\n  '
                   ) || CASE WHEN rolcreaterole 
                          THEN 'CREATEROLE' 
                          ELSE 'NOCREATEROLE' 
                        END
                 ) || e'\\n  '
               ) || CASE WHEN rolreplication 
                      THEN 'REPLICATION' 
                      ELSE 'NOREPLICATION' 
                    END
             ) || CASE WHEN rolconnlimit > 0 
                    THEN e'\\n  CONNECTION LIMIT ' || rolconnlimit 
                    ELSE '' 
                  END
           ) || CASE WHEN rolvaliduntil IS NOT NULL 
                  THEN e'\\n  VALID UNTIL ' || quote_literal(rolvaliduntil::TEXT) 
                  ELSE ';' 
           END AS sql 
    FROM pg_roles AS r 
    WHERE r.oid = 823966177::OID 
  UNION ALL 
    (
      SELECT array_to_string(array_agg(sql), e'\\n') AS sql 
      FROM (
        SELECT (
                 (
                   (
                     'GRANT ' || array_to_string(array_agg(rolname), ', ')
                   ) || ' TO '
                 ) || pg_catalog.quote_ident(pg_get_userbyid(823966177::OID))
               ) || CASE WHEN admin_option 
                      THEN ' WITH ADMIN OPTION;' 
                      ELSE ';' 
                    END AS sql 
        FROM (
          SELECT quote_ident(r.rolname) AS rolname, 
                 m.admin_option AS admin_option 
          FROM pg_auth_members AS m 
          LEFT JOIN pg_roles AS r 
            ON (m.roleid = r.oid) 
          WHERE m.member = 823966177::OID 
          ORDER BY r.rolname
        ) AS a 
        GROUP BY admin_option
      ) AS s
    ) 
  UNION ALL 
    (
      SELECT array_to_string(array_agg(sql), e'\\n') AS sql 
      FROM (
        SELECT (
                 (
                   (
                     (
                       (
                         (
                           'ALTER ' || CASE WHEN rolcanlogin 
                                         THEN 'USER ' 
                                         ELSE 'ROLE ' 
                                       END
                         ) || pg_catalog.quote_ident(rolname)
                       ) || ' SET '
                     ) || param
                   ) || ' TO '
                 ) || CASE WHEN param IN ('search_path', 'temp_tablespaces') 
                        THEN value 
                        ELSE quote_literal(value) 
                     END
                 ) || ';' AS sql 
        FROM (
          SELECT rolcanlogin, 
                 rolname, 
                 split_part(rolconfig, '=', 1) AS param, 
                 replace(rolconfig, split_part(rolconfig, '=', 1) || '=', '') AS value 
          FROM (
            SELECT unnest(rolconfig) AS rolconfig, 
                   rolcanlogin, 
                   rolname 
            FROM pg_catalog.pg_roles 
            WHERE oid = 823966177::OID) AS r
        ) AS a
      ) AS b
    ) 
  UNION ALL 
    (
      SELECT array_to_string(array_agg(sql), e'\\n') AS sql 
      FROM (
        SELECT (
                 (
                   (
                     (
                       (
                         (
                           (
                             'ALTER ROLE ' || pg_catalog.quote_ident(pg_get_userbyid(823966177::OID))
                           ) || ' IN DATABASE '
                         ) || pg_catalog.quote_ident(datname)
                       ) || ' SET '
                     ) || param
                   ) || ' TO '
                 ) || CASE WHEN param IN ('search_path', 'temp_tablespaces') 
                        THEN value 
                        ELSE quote_literal(value) 
                     END
               ) || ';' AS sql 
        FROM (
          SELECT datname, 
                 split_part(rolconfig, '=', 1) AS param, 
                 replace(rolconfig, split_part(rolconfig, '=', 1) || '=', '') AS value 
          FROM (
            SELECT d.datname, 
                   unnest(c.setconfig) AS rolconfig 
            FROM (
              SELECT * 
              FROM pg_catalog.pg_db_role_setting AS dr 
              WHERE (dr.setrole = 823966177::OID) 
                AND (dr.setdatabase != 0)
            ) AS c 
            LEFT JOIN pg_catalog.pg_database AS d 
            ON (d.oid = c.setdatabase)
          ) AS a
        ) AS b
      ) AS d
    ) 
  UNION ALL 
    (
      SELECT (
               (
                 (
                   'COMMENT ON ROLE ' || pg_catalog.quote_ident(pg_get_userbyid(823966177::OID))
                 ) || ' IS '
               ) || pg_catalog.quote_literal(description)
             ) || ';' AS sql 
      FROM (
        SELECT pg_catalog.shobj_description(823966177::OID, 'pg_authid') AS description
      ) AS a 
      WHERE description IS NOT NULL
    ) 
  UNION ALL 
    (
      SELECT array_to_string(array_agg(sql), e'\\n') AS sql 
      FROM (
        SELECT (
          (
            (
              (
                (
                  'SECURITY LABEL FOR ' || provider
                ) || e'\\n  ON ROLE '
              ) || pg_catalog.quote_ident(rolname)
            ) || e'\\n  IS '
          ) || pg_catalog.quote_literal(label)
        ) || ';' AS sql 
        FROM (
          SELECT label, 
                 provider, 
                 rolname 
          FROM (
            SELECT * 
            FROM pg_shseclabel AS sl1 
            WHERE sl1.objoid = 823966177::OID
          ) AS s 
          LEFT JOIN pg_catalog.pg_roles AS r 
          ON (s.objoid = r.oid)
        ) AS a
      ) AS b
    )
  ) AS a

Here's the current output:

SELECT array_to_string(array_agg(sql), e'\\n\\n') AS sql
FROM
	(
		SELECT (((((((((((((((((((((CASE WHEN rolcanlogin THEN '-- User: ' ELSE '-- Role: ' END || quote_ident(rolname)) || e'\\n-- DROP ') || CASE WHEN rolcanlogin THEN 'USER ' ELSE 'ROLE ' END) || quote_ident(rolname)) || e';\\n\\nCREATE ') || CASE WHEN rolcanlogin THEN 'USER ' ELSE 'ROLE ' END) || quote_ident(rolname)) || e' WITH\\n  ') || CASE WHEN rolcanlogin THEN 'LOGIN' ELSE 'NOLOGIN' END) || e'\\n  ') || CASE WHEN rolcanlogin AND (rolpassword LIKE 'md5%') THEN ('ENCRYPTED PASSWORD ' || quote_literal(rolpassword)) || e'\\n  ' ELSE '' END) || CASE WHEN rolsuper THEN 'SUPERUSER' ELSE 'NOSUPERUSER' END) || e'\\n  ') || CASE WHEN rolinherit THEN 'INHERIT' ELSE 'NOINHERIT' END) || e'\\n  ') || CASE WHEN rolcreatedb THEN 'CREATEDB' ELSE 'NOCREATEDB' END) || e'\\n  ') || CASE WHEN rolcreaterole THEN 'CREATEROLE' ELSE 'NOCREATEROLE' END) || e'\\n  ') || CASE WHEN rolreplication THEN 'REPLICATION' ELSE 'NOREPLICATION' END) || CASE WHEN rolconnlimit > 0 THEN e'\\n  CONNECTION LIMIT ' || rolconnlimit ELSE '' END) || CASE WHEN rolvaliduntil IS NOT NULL THEN e'\\n  VALID UNTIL ' || quote_literal(rolvaliduntil::TEXT) ELSE ';' END AS sql FROM pg_roles AS r WHERE r.oid = 823966177::OID UNION ALL (SELECT array_to_string(array_agg(sql), e'\\n') AS sql FROM (SELECT ((('GRANT ' || array_to_string(array_agg(rolname), ', ')) || ' TO ') || pg_catalog.quote_ident(pg_get_userbyid(823966177::OID))) || CASE WHEN admin_option THEN ' WITH ADMIN OPTION;' ELSE ';' END AS sql FROM (SELECT quote_ident(r.rolname) AS rolname, m.admin_option AS admin_option FROM pg_auth_members AS m LEFT JOIN pg_roles AS r ON (m.roleid = r.oid) WHERE m.member = 823966177::OID ORDER BY r.rolname) AS a GROUP BY admin_option) AS s) UNION ALL (SELECT array_to_string(array_agg(sql), e'\\n') AS sql FROM (SELECT (((((('ALTER ' || CASE WHEN rolcanlogin THEN 'USER ' ELSE 'ROLE ' END) || pg_catalog.quote_ident(rolname)) || ' SET ') || param) || ' TO ') || CASE WHEN param IN ('search_path', 'temp_tablespaces') THEN value ELSE quote_literal(value) END) || ';' AS sql FROM (SELECT rolcanlogin, rolname, split_part(rolconfig, '=', 1) AS param, replace(rolconfig, split_part(rolconfig, '=', 1) || '=', '') AS value FROM (SELECT unnest(rolconfig) AS rolconfig, rolcanlogin, rolname FROM pg_catalog.pg_roles WHERE oid = 823966177::OID) AS r) AS a) AS b) UNION ALL (SELECT array_to_string(array_agg(sql), e'\\n') AS sql FROM (SELECT ((((((('ALTER ROLE ' || pg_catalog.quote_ident(pg_get_userbyid(823966177::OID))) || ' IN DATABASE ') || pg_catalog.quote_ident(datname)) || ' SET ') || param) || ' TO ') || CASE WHEN param IN ('search_path', 'temp_tablespaces') THEN value ELSE quote_literal(value) END) || ';' AS sql FROM (SELECT datname, split_part(rolconfig, '=', 1) AS param, replace(rolconfig, split_part(rolconfig, '=', 1) || '=', '') AS value FROM (SELECT d.datname, unnest(c.setconfig) AS rolconfig FROM (SELECT * FROM pg_catalog.pg_db_role_setting AS dr WHERE (dr.setrole = 823966177::OID) AND (dr.setdatabase != 0)) AS c LEFT JOIN pg_catalog.pg_database AS d ON (d.oid = c.setdatabase)) AS a) AS b) AS d) UNION ALL (SELECT ((('COMMENT ON ROLE ' || pg_catalog.quote_ident(pg_get_userbyid(823966177::OID))) || ' IS ') || pg_catalog.quote_literal(description)) || ';' AS sql FROM (SELECT pg_catalog.shobj_description(823966177::OID, 'pg_authid') AS description) AS a WHERE description IS NOT NULL) UNION ALL (SELECT array_to_string(array_agg(sql), e'\\n') AS sql FROM (SELECT ((((('SECURITY LABEL FOR ' || provider) || e'\\n  ON ROLE ') || pg_catalog.quote_ident(rolname)) || e'\\n  IS ') || pg_catalog.quote_literal(label)) || ';' AS sql FROM (SELECT label, provider, rolname FROM (SELECT * FROM pg_shseclabel AS sl1 WHERE sl1.objoid = 823966177::OID) AS s LEFT JOIN pg_catalog.pg_roles AS r ON (s.objoid = r.oid)) AS a) AS b)
	)
		AS a;

Taken from cockroachdb/cockroach#26584

SQL format failed

ALTER TABLE platform_game DROP COLUMN app_id, MODIFY COLUMN business_id int(10) NOT NULL DEFAULT 0

image

CREATE FUNCTION not implemented

It appears that functions are not implemented. I would think function would be pretty standard across dialects though from what I understand this is still a work in progress.

It would be nice to have a list of features that are not yet implemented.

fix this one

SELECT _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _ FROM ((SELECT _, _, _, _, _, _, _, _, _, _ FROM _._._ WHERE (_ = (-_)) AND (_ = _) ORDER BY _, _, _ LIMIT _) JOIN (SELECT _, _, _, _, _, _, _, _, _, _, _, _, _, _ FROM _._._ WHERE (_ = (-_)) AND (_ = _) ORDER BY _, _ LIMIT _) USING (_, _)) ORDER BY _, _, _

improve

SELECT ref0_.generationuser_id AS generati1_2_0_
      ,ref0_.ref_id AS ref_id2_2_0_
      ,(SELECT a13.age 
        FROM generationgroup AS a13 
        WHERE a13.id = ref0_.ref_id) AS formula131_0_
      ,(SELECT a15.culture 
        FROM generationgroup AS a15 
        WHERE a15.id = ref0_.ref_id) AS formula132_0_
      ,(SELECT a13.description
        FROM generationgroup AS a13
        WHERE a13.id = ref0_.ref_id) AS formula133_0_
      ,generation1_.id AS id1_0_1_
      ,generation1_.age AS age2_0_1_
      ,generation1_.culture AS culture3_0_1_
      ,generation1_.description AS descript4_0_1_
FROM generationuser_generationgroup AS ref0_
INNER JOIN generationgroup AS generation1_ 
  ON ref0_.ref_id = generation1_.id
WHERE ref0_.generationuser_id = 1;

The AS ref0_ inner join is really weirdly formatted. The AS should be indented, the inner join not, but the sub part of inner join should be indented.

go build fails with undefined yaccpar things

Trying to build the sqlfmt binary for local use.

Have $GOPATH/src/.../cockroach with master branch checked out (HEAD d404a3f64b)

sqlfmt HEAD is currently 8113004

$ go build -o sqlfmt
# github.com/cockroachdb/cockroach/pkg/sql/parser
yaccpar:624: undefined: tree.TestingRelocate
yaccpar:631: undefined: tree.TestingRelocate
yaccpar:2349: undefined: tree.SnapshotIsolation

Formatting JSON string

Hi,

Do you have any plans on pretty printing JSON values? For example, something like "INSERT INTO my_table (json_col) VALUES ('{ ... a long JSON document ... }');" prints the entire JSON on a single line.

current_timestamp -> current_timestamp() breaking postgres

Example

CREATE TABLE t (
  created_at TIMESTAMP DEFAULT current_timestamp NOT NULL
);

generates

CREATE TABLE t (
	created_at TIMESTAMP
	           DEFAULT current_timestamp()
	           NOT NULL
);

Note the () after current_timestamp, this is invalid syntax for postgres. I'm guessing you're normalizing to the built in function names as documented on https://www.cockroachlabs.com/docs/stable/functions-and-operators.html#special-syntax-forms

I know you're focused on cockroach syntax, but this formatting nit keeps your otherwise super useful utility from being useful for postgres too.

Have you considered a dialect option, or something else that would allow sqlfmt to work for non-cockroach dialects? I understand the maintenance burden on you that sort of option could entail, but this tool is the best sql formatter I've come across, so I thought I'd ask.

support CASE

SELECT
	this_.person_id AS person_i1_2_0_,
	this_.version AS version2_2_0_,
	this_.name AS name3_2_0_,
	this_.sex AS sex4_2_0_,
	this_.height_centimeters / 2.54E0 AS height_c5_2_0_,
	this_.address AS address6_2_0_,
	this_.zip AS zip7_2_0_,
	this_.country AS country8_2_0_,
	this_1_.title AS title2_0_0_,
	this_1_.salary AS salary3_0_0_,
	this_1_.pwd_expiry_weeks * 7.0E0 AS pwd_expi4_0_0_,
	this_1_.manager AS manager5_0_0_,
	this_2_.comments AS comments2_1_0_,
	this_2_.salesperson AS salesper3_1_0_,
	CASE WHEN this_1_.person_id IS NOT NULL THEN 1 WHEN this_2_.person_id IS NOT NULL THEN 2 WHEN this_.person_id IS NOT NULL THEN 0 END
		AS clazz_0_
FROM
	jperson AS this_ LEFT JOIN jemployee AS this_1_ ON this_.person_id = this_1_.person_id
		LEFT JOIN jmanager AS this_2_ ON this_.person_id = this_2_.person_id
WHERE (this_.address, this_.zip, this_.country) IN (($1, $2, $3), ($4, $5, $6));

Obviously the case looks bad, but did that cause the first LEFT JOIN to not be on the next line?

Missing dependency or improved docs?

I'm a Go noob, so I'm not quite certain where go to from here, and the docs on building are quite sparse at this point. Any clues on getting the following error set when trying to build?


/p/t/sqlfmt> sh build.sh
+ IMG=gcr.io/hots-cockroach/sqlfmt:latest
+ go build -o sqlfmt
# github.com/cockroachdb/cockroach/pkg/sql/lex
/Users/andrew/go/src/github.com/cockroachdb/cockroach/pkg/sql/lex/keywords.go:10:32: undefined: ABORT
/Users/andrew/go/src/github.com/cockroachdb/cockroach/pkg/sql/lex/keywords.go:11:32: undefined: ACTION
/Users/andrew/go/src/github.com/cockroachdb/cockroach/pkg/sql/lex/keywords.go:12:32: undefined: ADD
/Users/andrew/go/src/github.com/cockroachdb/cockroach/pkg/sql/lex/keywords.go:13:32: undefined: ADMIN
/Users/andrew/go/src/github.com/cockroachdb/cockroach/pkg/sql/lex/keywords.go:14:32: undefined: ALL
/Users/andrew/go/src/github.com/cockroachdb/cockroach/pkg/sql/lex/keywords.go:15:32: undefined: ALTER
/Users/andrew/go/src/github.com/cockroachdb/cockroach/pkg/sql/lex/keywords.go:16:32: undefined: ANALYSE
/Users/andrew/go/src/github.com/cockroachdb/cockroach/pkg/sql/lex/keywords.go:17:32: undefined: ANALYZE
/Users/andrew/go/src/github.com/cockroachdb/cockroach/pkg/sql/lex/keywords.go:18:32: undefined: AND
/Users/andrew/go/src/github.com/cockroachdb/cockroach/pkg/sql/lex/keywords.go:19:32: undefined: ANNOTATE_TYPE
/Users/andrew/go/src/github.com/cockroachdb/cockroach/pkg/sql/lex/keywords.go:19:32: too many errors

Broken interval for Postgres

Been using the website to help format some of my postgres queries. When I happen to use interval in my queries I end up getting an interval that doesn't work in postgres.

I get something like'36:00:00':::INTERVAL which should be '36:00:00'::INTERVAL for postgres. Looks like an extra : is being used when doing the cast.

Sample input:

select date_trunc('hour', time_column), count(*)
from import_table
where time_column > date_trunc('hour', now()) - interval '36 hours'
group by date_trunc('hour', time_column)
order by 1;

Sample output:

SELECT
	date_trunc('hour', time_column), count(*)
FROM
	import_table
WHERE
	time_column > date_trunc('hour', now()) - '36:00:00':::INTERVAL
GROUP BY
	date_trunc('hour', time_column)
ORDER BY
	1;

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.