diff --git a/SQL/MySQL.sublime-syntax b/SQL/MySQL.sublime-syntax index ec91fe4e0d..26dae9b7cd 100644 --- a/SQL/MySQL.sublime-syntax +++ b/SQL/MySQL.sublime-syntax @@ -5,6 +5,21 @@ scope: source.sql.mysql version: 2 extends: Packages/SQL/SQL (basic).sublime-syntax +variables: + simple_types: |- + (?xi: + \b + (?:bigint|bigserial|bit|bool|boolean|box|bytea|cidr|circle|date|datetime|double\s+precision|enum|inet|int|integer| + line|longtext|lseg|macaddr|money|ntext|oid|path|point|polygon|real|serial|smallint|sysdate|sysname|text|tinytext) + \b + ) + types_with_optional_number: |- + (?xi: + \b + (?:bit\s+varying|character\s+(?:varying)?|tinyint|var\schar|float|interval|numeric|decimal|times?|timestamp(?:s|tz)?) + \b + ) + contexts: main: - meta_append: true @@ -84,41 +99,9 @@ contexts: scope: keyword.operator.concatenation.sql types: - - match: |- - (?xi) - # normal stuff, capture 1 - \b(bigint|bigserial|bit|bool|boolean|box|bytea|cidr|circle|date|datetime|double\s+precision|enum|inet|int|integer|line|longtext|lseg|macaddr|money|ntext|oid|path|point|polygon|real|serial|smallint|sysdate|sysname|text|tinytext)\b - - # numeric suffix, capture 2 + 3i - |\b(bit\svarying|character\s+(?:varying)?|tinyint|var\schar|float|interval)\((\d+)\) - - # optional numeric suffix, capture 4 + 5i - |\b(char|number|nvarchar|varbinary|varchar\d?)\b(?:\((\d+)\))? - - # special case, capture 6 + 7i + 8i - |\b(numeric|decimal)\b(?:\((\d+),(\d+)\))? - - # special case, captures 9, 10i, 11 - |\b(times?)\b(?:\((\d+)\))?(\swith(?:out)?\s+time\s+zone\b)? - - # special case, captures 12, 13, 14i, 15 - |\b(timestamp)(?:(s|tz))?\b(?:\((\d+)\))?(\s(with|without)\s+time\s+zone\b)? - captures: - 1: storage.type.sql - 2: storage.type.sql - 3: constant.numeric.sql - 4: storage.type.sql - 5: constant.numeric.sql - 6: storage.type.sql - 7: constant.numeric.sql - 8: constant.numeric.sql - 9: storage.type.sql - 10: constant.numeric.sql - 11: storage.type.sql - 12: storage.type.sql - 13: storage.type.sql - 14: constant.numeric.sql - 15: storage.type.sql + - meta_append: true + - match: (?i:\bwith(?:out)?\s+time\s+zone\b) + scope: storage.type.sql inside-number-sign-comment: - meta_include_prototype: false diff --git a/SQL/SQL (basic).sublime-syntax b/SQL/SQL (basic).sublime-syntax index 3288fbf560..c5fc17e3a4 100644 --- a/SQL/SQL (basic).sublime-syntax +++ b/SQL/SQL (basic).sublime-syntax @@ -8,8 +8,10 @@ version: 2 variables: string_escape: (?:\\.) simple_identifier: (?:\w+) - reserved: (?i:\b(?:from|order|group|select|where|inner|outer|left|right|join|on|set|;|union|insert|delete|truncate|create|alter|drop)\b) - additional_reserved: '' + reserved: (?i:;|\b(?:from|order|group|select|where|inner|outer|left|right|join|on|set|union|insert|delete|truncate|create|alter|drop)\b) + additional_reserved: (?!) + simple_types: (?i:\b(?:bit|bool|boolean|datetime|int)\b) + types_with_optional_number: (?i:\b(?:char|number|nvarchar|varbinary|varchar)\b) contexts: prototype: @@ -20,7 +22,7 @@ contexts: - match: ';' scope: punctuation.terminator.statement.sql - include: types - - include: expressions + - include: expressions-or-column-name comments: - meta_include_prototype: false @@ -85,10 +87,15 @@ contexts: set: single-identifier single-identifier: + - include: pop-on-top-level-reserved-word - match: '' set: [maybe-identifier-accessor, identifier-part] maybe-identifier-accessor: + - match: \s*(\.)(?=\s*\*) + captures: + 1: punctuation.accessor.dot.sql + pop: true - match: \s*(\.) captures: 1: punctuation.accessor.dot.sql @@ -154,12 +161,22 @@ contexts: - include: logical-operators types: - - match: \b(?i:bit|bool|boolean|datetime|int)\b + - match: '{{simple_types}}' scope: storage.type.sql - - match: \b(?i:char|number|nvarchar|varbinary|varchar)\b(?:\s*\((\d+)\))? + - match: |- + (?xi) + {{types_with_optional_number}} + (?:\s*\((\d+)(?:\s*(,)\s*(\d+))?\))? scope: storage.type.sql captures: 1: constant.numeric.sql + 2: punctuation.separator.sequence.sql + 3: constant.numeric.sql + + expressions-or-column-name: + - include: expressions + - match: (?=\S) + push: [column-name, single-identifier] expressions: - match: (?i)\bas\b @@ -190,8 +207,6 @@ contexts: scope: punctuation.separator.sequence.sql - match: (?=;) pop: true - - match: (?=\S) - push: [column-alias, single-identifier] inside-case-expression: - meta_scope: meta.statement.conditional.case.sql @@ -208,7 +223,7 @@ contexts: scope: keyword.control.conditional.then.sql - match: \b(?i:else)\b scope: keyword.control.conditional.else.sql - - include: expressions + - include: expressions-or-column-name built-in-aggregate-function-calls: # List of SQL99 built-in functions from http://www.oreilly.com/catalog/sqlnut/chapter/ch04.html @@ -242,8 +257,8 @@ contexts: pop: true - match: ',' scope: punctuation.separator.argument.sql - - include: expressions - include: distinct + - include: expressions-or-column-name inside-group: - meta_scope: meta.group.sql @@ -317,10 +332,7 @@ contexts: - match: \b(?i:add(?:\s+column)?|alter\s+column)\b scope: keyword.other.ddl.sql - include: ddl-alter-common - # - include: pop-on-top-level-reserved-word - - include: expressions - # - match: (?=\S) - # pop: true + - include: expressions-or-column-name ddl-alter-target: - meta_scope: meta.alter.sql @@ -365,15 +377,20 @@ contexts: scope: keyword.other.DML.sql joins: - - match: (?i)\b(?:inner|(?:full|left\s+)?outer|cross|left|right)\s+join\b + - match: (?i)\b(?:(?:inner|(?:full|left\s+)?outer|cross|left|right)\s+)?join\b scope: keyword.other.DML.sql push: [join-on, table-name-or-subquery] - column-alias: + column-name: - meta_content_scope: meta.column-name.sql constant.other.placeholder.sql - match: '' pop: true + column-alias: + - meta_content_scope: meta.column-alias.sql constant.other.placeholder.sql + - match: '' + pop: true + database-name: - meta_content_scope: meta.database-name.sql constant.other.placeholder.sql - match: '' @@ -384,6 +401,11 @@ contexts: - match: '' pop: true + procedure-name: + - meta_content_scope: meta.procedure-name.sql constant.other.placeholder.sql + - match: '' + pop: true + subquery: - match: \( scope: punctuation.section.group.begin.sql @@ -421,3 +443,7 @@ contexts: pop: true - match: (?=\)) pop: true + + assignment-operator: + - match: '=' + scope: keyword.operator.assignment.sql diff --git a/SQL/TSQL.sublime-syntax b/SQL/TSQL.sublime-syntax index 9dbb888b0a..47c6880fc5 100644 --- a/SQL/TSQL.sublime-syntax +++ b/SQL/TSQL.sublime-syntax @@ -8,7 +8,12 @@ extends: Packages/SQL/SQL (basic).sublime-syntax variables: string_escape: (?:'') #(?:\\[tnr]) simple_identifier: (?:(?:(?:##?)?|@)?\w+) # (one or two hashes OR an ampersand OR nothing) followed by a word - additional_reserved: (?i:\b(?:if|while|declare|with|for|begin|end|else|print|use|raiserror|merge)\b) + additional_reserved: (?i:\b(?:if|while|declare|with|for|begin|end|else|print|use|raiserror|merge|backup|exec)\b) + enclosed_type_begin: (?:\[) + enclosed_type_end: (?:\]) + simple_types: (?i:\b(?:bit|bool|boolean|datetime|int|smallint|sysname|uniqueidentifier|text)\b) + types_with_optional_number: (?i:\b(?:n?char|numeric|n?varchar|varbinary|decimal|money)\b) + contexts: identifier-part: - meta_prepend: true @@ -163,8 +168,23 @@ contexts: types: - meta_append: true - - match: (?i:\b(?:smallint|sysname|uniqueidentifier|decimal)\b) + - match: |- + (?xi) + {{enclosed_type_begin}}? + {{simple_types}} + {{enclosed_type_end}}? scope: storage.type.sql + - match: |- + (?xi) + {{enclosed_type_begin}}? + {{types_with_optional_number}} + {{enclosed_type_end}}? + (?:\s*\((\d+)(?:\s*(,)\s*(\d+))?\))? + scope: storage.type.sql + captures: + 1: constant.numeric.sql + 2: punctuation.separator.sequence.sql + 3: constant.numeric.sql statements: - meta_append: true @@ -179,6 +199,7 @@ contexts: push: [label-name, single-identifier-after-whitespace] - match: \b(?i:exec)\b scope: keyword.control.flow.tsql + push: [expect-procedure-name, exec] - match: \b(?i:begin)\b scope: keyword.control.flow.begin.tsql - match: \b(?i:end)\b @@ -188,6 +209,12 @@ contexts: - match: \b(?i:use)\b scope: keyword.context.tsql push: [database-name, single-identifier-after-whitespace] + - match: \b(?i:backup(?:\s+database)?)\b # https://docs.microsoft.com/en-us/sql/t-sql/statements/backup-transact-sql?view=sql-server-ver15 + scope: keyword.other.tsql + - match: \b(?i:to)\b + scope: keyword.other.tsql + - match: \b(?i:disk|tape|url)\b + scope: keyword.other.tsql - match: \b(\w+)(:) captures: 1: entity.name.label.tsql @@ -210,9 +237,13 @@ contexts: push: cast - include: variables - include: with - - match: \b(?i:output|over|partition\s+by)\b + - match: \b(?i:output)\b + scope: storage.modifier.output.tsql + - match: \b(?i:over|partition\s+by)\b scope: keyword.other.sql - - match: \b(?i:cursor\s+for|open|fetch(?:(?:\s+next)?\s+from)?|close|deallocate)\b + - match: \b(?i:cursor\s+for)\b + scope: keyword.other.sql + - match: \b(?i:open|fetch(?:(?:\s+next)?\s+from)?|close|deallocate)\b scope: keyword.other.sql push: [cursor-name, single-identifier-after-whitespace] - match: \b(?i:collate)\b @@ -250,7 +281,7 @@ contexts: - match: (?i:\bas\b) scope: keyword.context.block.sql pop: true - - include: expressions + - include: expressions-or-column-name built-in-scalar-function-calls: - meta_append: true @@ -337,7 +368,7 @@ contexts: pop: true - match: \b(?i:as)\b scope: keyword.operator.assignment.tsql - - include: expressions + - include: expressions-or-column-name collation: - match: \w+ @@ -345,3 +376,20 @@ contexts: pop: true - match: (?=\S) pop: true + + joins: + - meta_append: true + - match: (?i)\b(?:cross\s+)?apply\b + scope: keyword.other.DML.sql + push: table-name-or-subquery + + exec: + - include: assignment-operator + - include: pop-on-top-level-reserved-word + - include: expressions + - match: (?=\S) + pop: true + + expect-procedure-name: + - match: '' + set: [procedure-name, single-identifier-after-whitespace] diff --git a/SQL/syntax_test_mysql.sql b/SQL/syntax_test_mysql.sql index b71957d513..680ec5cf37 100644 --- a/SQL/syntax_test_mysql.sql +++ b/SQL/syntax_test_mysql.sql @@ -91,8 +91,10 @@ create table fancy_table ( mycount double precision DEFAULT 1, -- ^^^^^^^^^^^^^^^^^ storage.type.sql fancy_column character varying(42) DEFAULT 'nice'::character varying, --- ^^^^^^^^^^^^^^^^^^ storage.type.sql +-- ^^^^^^^^^^^^^^^^^^^^^^ storage.type.sql mytime timestamp(3) without time zone DEFAULT now(), +-- ^^^^^^^^^^^^ storage.type.sql +-- ^ constant.numeric -- ^^^^^^^^^^^^^^^^^ storage.type.sql -- ^^^^^^^ storage.modifier -- ^^^ meta.function-call support.function @@ -101,12 +103,24 @@ create table fancy_table ( -- ^ punctuation.separator.sequence mytime2 timestamp(3) without time zone DEFAULT '2008-01-18 00:00:00'::timestamp(3) without time zone, -- ^^^^^^^^^^^^^^^^^^^ storage.type.sql + some_number numeric(5, 2) DEFAULT 0, +-- ^^^^^^^^^^^ meta.column-name constant.other.placeholder +-- ^^^^^^^^^^^^^ storage.type +-- ^ constant.numeric +-- ^ punctuation.separator.sequence +-- ^ constant.numeric +-- ^^^^^^^ storage.modifier +-- ^ meta.number.integer.decimal constant.numeric.value primary key (id), -- ^^^^^^^^^^^ storage.modifier.sql UNIQUE (foreign_id), CONSTRAINT fancy_table_valid1 CHECK (id <> foreign_id) -- ^^^^^^^^^^ storage.modifier.sql -- ^^^^^ storage.modifier.sql +-- ^^^^^^^^^^^^^^^^^^ meta.group meta.group +-- ^^ meta.column-name constant.other.placeholder +-- ^^ keyword.operator.comparison +-- ^^^^^^^^^^ meta.column-name constant.other.placeholder ); CREATE INDEX ON fancy_table(mytime); @@ -201,7 +215,7 @@ SELECT *, -- ^ variable.language.wildcard.asterisk.sql f.id AS database_id -- ^^ keyword.operator.assignment.alias.sql --- ^^^^^^^^^^^ meta.column-name constant.other.placeholder +-- ^^^^^^^^^^^ meta.column-alias constant.other.placeholder FROM foo WHERE f.a IS NULL -- ^^ keyword.other.DML.sql diff --git a/SQL/syntax_test_tsql.sql b/SQL/syntax_test_tsql.sql index 366955aa45..4c6ca06035 100644 --- a/SQL/syntax_test_tsql.sql +++ b/SQL/syntax_test_tsql.sql @@ -223,13 +223,18 @@ DECLARE db_cursor CURSOR FOR -- ^^^^ keyword.declaration.variable -- ^^^^^^^^^ meta.cursor-name constant.other.placeholder -- ^^^^^^^^^^ keyword.other - -SELECT name -FROM MASTER.dbo.sysdatabases --- ^ keyword.other.DML --- ^^^^^^^^^^^^^^^^^^^^^^^ meta.table-name constant.other.placeholder -WHERE name NOT IN ('master','model','msdb','tempdb') --- ^^ keyword.other.DML + SELECT name +-- ^^^^^^ keyword.other.DML +-- ^^^^ meta.column-name constant.other.placeholder + FROM MASTER.dbo.sysdatabases + -- ^ keyword.other.DML + -- ^^^^^^^^^^^^^^^^^^^^^^^ meta.table-name constant.other.placeholder + WHERE name NOT IN ('master','model','msdb','tempdb') + -- ^^ keyword.other.DML + -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ meta.group + -- ^^^^^^^^ string.quoted.single + -- ^ punctuation.separator.sequence + -- ^^^^^^^ string.quoted.single OPEN db_cursor -- ^ keyword.other @@ -251,6 +256,11 @@ BEGIN -- ^^ keyword.control.flow.begin SET @fileName = @path + @name + '_' + @fileDate + '.BAK' BACKUP DATABASE @name TO DISK = @fileName +-- ^^^^^^^^^^^^^^^ keyword.other +-- ^^^^^ variable.other.readwrite +-- ^^ keyword.other +-- ^^^^ keyword.other +-- ^ keyword.operator FETCH NEXT FROM db_cursor INTO @name END @@ -272,7 +282,11 @@ SET NOCOUNT ON -- ^^ constant.language.boolean EXEC master.dbo.xp_fileexist @FromFile, @FileExists OUTPUT -- ^ keyword.control.flow --- ^^^^^^ keyword.other +-- ^^^^^^^^^^^^^^^^^^^^^^^ meta.procedure-name constant.other.placeholder +-- ^^^^^^^^^ variable.other.readwrite +-- ^ punctuation.separator.sequence +-- ^^^^^^^^^^^ variable.other.readwrite +-- ^^^^^^ storage.modifier.output SET NOCOUNT OFF --^ keyword.other.DML -- ^^^^^^^ constant.language.switch @@ -314,6 +328,10 @@ IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback -- ^^^^ keyword.control.flow -- ^^^^^^^^^^^^^^^^ meta.label-name constant.other.placeholder EXEC @ReturnCode = msdb.dbo.sp_add_jobserver @job_id = @jobId, @server_name = N'(local)' +-- ^ keyword.control.flow +-- ^^^^^^^^^^^ variable.other.readwrite +-- ^ keyword.operator.assignment +-- ^^^^^^^^^^^^^^^^^^^^^^^^^ meta.procedure-name constant.other.placeholder IF (@@ERROR <> 0 OR @ReturnCode <> 0) GOTO QuitWithRollback COMMIT TRANSACTION -- ^^^^^^^^^^^^^^^ keyword.context @@ -345,17 +363,20 @@ VALUES (2, 'two'), -SELECT foo, COUNT(*) AS tally +SELECT foo AS foobar, COUNT(*) AS tally -- ^^^ keyword.other.DML --- ^ punctuation.separator.sequence --- ^^^^^^^^ meta.function-call --- ^^^^^ support.function.aggregate --- ^^^ meta.group --- ^ punctuation.section.parens.begin --- ^ variable.language.wildcard.asterisk --- ^ punctuation.section.parens.end --- ^^ keyword.operator.assignment.alias --- ^^^^^ meta.column-name constant.other.placeholder +-- ^^^ meta.column-name constant.other.placeholder +-- ^^ keyword.operator.assignment.alias +-- ^^^^^^ meta.column-alias constant.other.placeholder +-- ^ punctuation.separator.sequence +-- ^^^^^^^^ meta.function-call +-- ^^^^^ support.function.aggregate +-- ^^^ meta.group +-- ^ punctuation.section.parens.begin +-- ^ variable.language.wildcard.asterisk +-- ^ punctuation.section.parens.end +-- ^^ keyword.operator.assignment.alias +-- ^^^^^ meta.column-alias constant.other.placeholder FROM bar -- ^ keyword.other.DML -- ^^^ meta.table-name constant.other.placeholder @@ -472,7 +493,7 @@ SELECT i.ProductID, p.Name, i.LocationID, i.Quantity -- ^^^^^^^^ meta.group keyword.other.DML -- ^^^^ meta.group keyword.other.order -- ^^ keyword.operator.assignment.alias --- ^^^^ meta.column-name constant.other.placeholder +-- ^^^^ meta.column-alias constant.other.placeholder FROM Production.ProductInventory AS i INNER JOIN Production.Product AS p ON i.ProductID = p.ProductID @@ -552,7 +573,7 @@ CREATE OR ALTER PROC CreateOrAlterDemo -- <- punctuation.separator.sequence --^^^^^ variable.other.readwrite -- ^^^ storage.type --- ^^^^^^ keyword.other +-- ^^^^^^ storage.modifier.output AS -- <- keyword.context.block BEGIN @@ -584,6 +605,11 @@ select A.A , CASE WHEN B.B IS NOT NULL THEN B.B ELSE DATEADD(d, 1 - DATEPART(d, GETDATE()), DATEADD(m, B.MonthsInFuture, DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0))) END AS FirstDayOfFutureMonth -- ^ punctuation.separator.sequence -- ^^^^ keyword.control.conditional.case + , B.* +-- ^ punctuation.separator.sequence +-- ^^ meta.column-name constant.other.placeholder +-- ^ punctuation.accessor.dot +-- ^ variable.language.wildcard.asterisk into #temp -- ^ keyword.other.DML -- ^^^^^ meta.table-name constant.other.placeholder @@ -663,3 +689,22 @@ SELECT ManagerID, EmployeeID, Title, EmployeeLevel FROM DirectReports ORDER BY ManagerID OPTION (MAXRECURSION 3) + +CREATE TABLE foo (id [int] PRIMARY KEY, [test me] [varchar] (5)); +-- ^^^ keyword.other.ddl +-- ^^^^^ keyword.other +-- ^^^ meta.toc-list.full-identifier entity.name.function +-- ^ punctuation.section.group.begin +-- ^^ meta.column-name constant.other.placeholder +-- ^^^^^ storage.type +-- ^^^^^^^^^^^ storage.modifier +-- ^ punctuation.separator.sequence +-- ^^^^^^^^^ meta.column-name constant.other.placeholder +-- ^^^^^^^^^^^^^ storage.type +-- ^ constant.numeric +-- ^ punctuation.section.group.end +-- ^ punctuation.terminator.statement + +CREATE TABLE foo ([int] [int] PRIMARY KEY, [test'hello¬world'@"me"] [varchar] (5)); +-- ^^^^^ storage.type +-- ^^^^^^^^^^^^^^^^^^^^^^^^ meta.column-name constant.other.placeholder