280 lines
16 KiB
JavaScript
280 lines
16 KiB
JavaScript
|
// CodeMirror, copyright (c) by Marijn Haverbeke and others
|
||
|
// Distributed under an MIT license: http://codemirror.net/LICENSE
|
||
|
|
||
|
/* eslint-disable */
|
||
|
module.exports = function(CodeMirror) {
|
||
|
"use strict";
|
||
|
|
||
|
CodeMirror.defineMode("sql", function(config, parserConfig) {
|
||
|
"use strict";
|
||
|
|
||
|
var client = parserConfig.client || {},
|
||
|
atoms = parserConfig.atoms || {"false": true, "true": true, "null": true},
|
||
|
builtin = parserConfig.builtin || {},
|
||
|
keywords = parserConfig.keywords || {},
|
||
|
operatorChars = parserConfig.operatorChars || /^[*+\-%<>!=&|~^]/,
|
||
|
support = parserConfig.support || {},
|
||
|
hooks = parserConfig.hooks || {},
|
||
|
dateSQL = parserConfig.dateSQL || {"date" : true, "time" : true, "timestamp" : true};
|
||
|
|
||
|
function tokenBase(stream, state) {
|
||
|
var ch = stream.next();
|
||
|
|
||
|
// call hooks from the mime type
|
||
|
if (hooks[ch]) {
|
||
|
var result = hooks[ch](stream, state);
|
||
|
if (result !== false) return result;
|
||
|
}
|
||
|
|
||
|
if (support.hexNumber == true &&
|
||
|
((ch == "0" && stream.match(/^[xX][0-9a-fA-F]+/))
|
||
|
|| (ch == "x" || ch == "X") && stream.match(/^'[0-9a-fA-F]+'/))) {
|
||
|
// hex
|
||
|
// ref: http://dev.mysql.com/doc/refman/5.5/en/hexadecimal-literals.html
|
||
|
return "number";
|
||
|
} else if (support.binaryNumber == true &&
|
||
|
(((ch == "b" || ch == "B") && stream.match(/^'[01]+'/))
|
||
|
|| (ch == "0" && stream.match(/^b[01]+/)))) {
|
||
|
// bitstring
|
||
|
// ref: http://dev.mysql.com/doc/refman/5.5/en/bit-field-literals.html
|
||
|
return "number";
|
||
|
} else if (ch.charCodeAt(0) > 47 && ch.charCodeAt(0) < 58) {
|
||
|
// numbers
|
||
|
// ref: http://dev.mysql.com/doc/refman/5.5/en/number-literals.html
|
||
|
stream.match(/^[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?/);
|
||
|
support.decimallessFloat == true && stream.eat('.');
|
||
|
return "number";
|
||
|
} else if (ch == "?" && (stream.eatSpace() || stream.eol() || stream.eat(";"))) {
|
||
|
// placeholders
|
||
|
return "variable-3";
|
||
|
} else if (ch == "'" || (ch == '"' && support.doubleQuote)) {
|
||
|
// strings
|
||
|
// ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html
|
||
|
state.tokenize = tokenLiteral(ch);
|
||
|
return state.tokenize(stream, state);
|
||
|
} else if ((((support.nCharCast == true && (ch == "n" || ch == "N"))
|
||
|
|| (support.charsetCast == true && ch == "_" && stream.match(/[a-z][a-z0-9]*/i)))
|
||
|
&& (stream.peek() == "'" || stream.peek() == '"'))) {
|
||
|
// charset casting: _utf8'str', N'str', n'str'
|
||
|
// ref: http://dev.mysql.com/doc/refman/5.5/en/string-literals.html
|
||
|
return "keyword";
|
||
|
} else if (/^[\(\),\;\[\]]/.test(ch)) {
|
||
|
// no highlighting
|
||
|
return null;
|
||
|
} else if (support.commentSlashSlash && ch == "/" && stream.eat("/")) {
|
||
|
// 1-line comment
|
||
|
stream.skipToEnd();
|
||
|
return "comment";
|
||
|
} else if ((support.commentHash && ch == "#")
|
||
|
|| (ch == "-" && stream.eat("-") && (!support.commentSpaceRequired || stream.eat(" ")))) {
|
||
|
// 1-line comments
|
||
|
// ref: https://kb.askmonty.org/en/comment-syntax/
|
||
|
stream.skipToEnd();
|
||
|
return "comment";
|
||
|
} else if (ch == "/" && stream.eat("*")) {
|
||
|
// multi-line comments
|
||
|
// ref: https://kb.askmonty.org/en/comment-syntax/
|
||
|
state.tokenize = tokenComment;
|
||
|
return state.tokenize(stream, state);
|
||
|
} else if (ch == ".") {
|
||
|
// .1 for 0.1
|
||
|
if (support.zerolessFloat == true && stream.match(/^(?:\d+(?:e[+-]?\d+)?)/i)) {
|
||
|
return "number";
|
||
|
}
|
||
|
// .table_name (ODBC)
|
||
|
// // ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html
|
||
|
if (support.ODBCdotTable == true && stream.match(/^[a-zA-Z_]+/)) {
|
||
|
return "variable-2";
|
||
|
}
|
||
|
} else if (operatorChars.test(ch)) {
|
||
|
// operators
|
||
|
stream.eatWhile(operatorChars);
|
||
|
return null;
|
||
|
} else if (ch == '{' &&
|
||
|
(stream.match(/^( )*(d|D|t|T|ts|TS)( )*'[^']*'( )*}/) || stream.match(/^( )*(d|D|t|T|ts|TS)( )*"[^"]*"( )*}/))) {
|
||
|
// dates (weird ODBC syntax)
|
||
|
// ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html
|
||
|
return "number";
|
||
|
} else {
|
||
|
stream.eatWhile(/^[_\w\d]/);
|
||
|
var word = stream.current().toLowerCase();
|
||
|
// dates (standard SQL syntax)
|
||
|
// ref: http://dev.mysql.com/doc/refman/5.5/en/date-and-time-literals.html
|
||
|
if (dateSQL.hasOwnProperty(word) && (stream.match(/^( )+'[^']*'/) || stream.match(/^( )+"[^"]*"/)))
|
||
|
return "number";
|
||
|
if (atoms.hasOwnProperty(word)) return "atom";
|
||
|
if (builtin.hasOwnProperty(word)) return "builtin";
|
||
|
if (keywords.hasOwnProperty(word)) return "keyword";
|
||
|
if (client.hasOwnProperty(word)) return "string-2";
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 'string', with char specified in quote escaped by '\'
|
||
|
function tokenLiteral(quote) {
|
||
|
return function(stream, state) {
|
||
|
var escaped = false, ch;
|
||
|
while ((ch = stream.next()) != null) {
|
||
|
if (ch == quote && !escaped) {
|
||
|
state.tokenize = tokenBase;
|
||
|
break;
|
||
|
}
|
||
|
escaped = !escaped && ch == "\\";
|
||
|
}
|
||
|
return "string";
|
||
|
};
|
||
|
}
|
||
|
function tokenComment(stream, state) {
|
||
|
while (true) {
|
||
|
if (stream.skipTo("*")) {
|
||
|
stream.next();
|
||
|
if (stream.eat("/")) {
|
||
|
state.tokenize = tokenBase;
|
||
|
break;
|
||
|
}
|
||
|
} else {
|
||
|
stream.skipToEnd();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return "comment";
|
||
|
}
|
||
|
|
||
|
function pushContext(stream, state, type) {
|
||
|
state.context = {
|
||
|
prev: state.context,
|
||
|
indent: stream.indentation(),
|
||
|
col: stream.column(),
|
||
|
type: type
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function popContext(state) {
|
||
|
state.indent = state.context.indent;
|
||
|
state.context = state.context.prev;
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
startState: function() {
|
||
|
return {tokenize: tokenBase, context: null};
|
||
|
},
|
||
|
|
||
|
token: function(stream, state) {
|
||
|
if (stream.sol()) {
|
||
|
if (state.context && state.context.align == null)
|
||
|
state.context.align = false;
|
||
|
}
|
||
|
if (stream.eatSpace()) return null;
|
||
|
|
||
|
var style = state.tokenize(stream, state);
|
||
|
if (style == "comment") return style;
|
||
|
|
||
|
if (state.context && state.context.align == null)
|
||
|
state.context.align = true;
|
||
|
|
||
|
var tok = stream.current();
|
||
|
if (tok == "(")
|
||
|
pushContext(stream, state, ")");
|
||
|
else if (tok == "[")
|
||
|
pushContext(stream, state, "]");
|
||
|
else if (state.context && state.context.type == tok)
|
||
|
popContext(state);
|
||
|
return style;
|
||
|
},
|
||
|
|
||
|
indent: function(state, textAfter) {
|
||
|
var cx = state.context;
|
||
|
if (!cx) return CodeMirror.Pass;
|
||
|
var closing = textAfter.charAt(0) == cx.type;
|
||
|
if (cx.align) return cx.col + (closing ? 0 : 1);
|
||
|
else return cx.indent + (closing ? 0 : config.indentUnit);
|
||
|
},
|
||
|
|
||
|
blockCommentStart: "/*",
|
||
|
blockCommentEnd: "*/",
|
||
|
lineComment: support.commentSlashSlash ? "//" : support.commentHash ? "#" : null
|
||
|
};
|
||
|
});
|
||
|
|
||
|
(function() {
|
||
|
"use strict";
|
||
|
|
||
|
// `identifier`
|
||
|
function hookIdentifier(stream) {
|
||
|
// MySQL/MariaDB identifiers
|
||
|
// ref: http://dev.mysql.com/doc/refman/5.6/en/identifier-qualifiers.html
|
||
|
var ch;
|
||
|
while ((ch = stream.next()) != null) {
|
||
|
if (ch == "`" && !stream.eat("`")) return "variable-2";
|
||
|
}
|
||
|
stream.backUp(stream.current().length - 1);
|
||
|
return stream.eatWhile(/\w/) ? "variable-2" : null;
|
||
|
}
|
||
|
|
||
|
// variable token
|
||
|
function hookVar(stream) {
|
||
|
// variables
|
||
|
// @@prefix.varName @varName
|
||
|
// varName can be quoted with ` or ' or "
|
||
|
// ref: http://dev.mysql.com/doc/refman/5.5/en/user-variables.html
|
||
|
if (stream.eat("@")) {
|
||
|
stream.match(/^session\./);
|
||
|
stream.match(/^local\./);
|
||
|
stream.match(/^global\./);
|
||
|
}
|
||
|
|
||
|
if (stream.eat("'")) {
|
||
|
stream.match(/^.*'/);
|
||
|
return "variable-2";
|
||
|
} else if (stream.eat('"')) {
|
||
|
stream.match(/^.*"/);
|
||
|
return "variable-2";
|
||
|
} else if (stream.eat("`")) {
|
||
|
stream.match(/^.*`/);
|
||
|
return "variable-2";
|
||
|
} else if (stream.match(/^[0-9a-zA-Z$\.\_]+/)) {
|
||
|
return "variable-2";
|
||
|
}
|
||
|
return null;
|
||
|
};
|
||
|
|
||
|
// short client keyword token
|
||
|
function hookClient(stream) {
|
||
|
// \N means NULL
|
||
|
// ref: http://dev.mysql.com/doc/refman/5.5/en/null-values.html
|
||
|
if (stream.eat("N")) {
|
||
|
return "atom";
|
||
|
}
|
||
|
// \g, etc
|
||
|
// ref: http://dev.mysql.com/doc/refman/5.5/en/mysql-commands.html
|
||
|
return stream.match(/^[a-zA-Z.#!?]/) ? "variable-2" : null;
|
||
|
}
|
||
|
|
||
|
// these keywords are used by all SQL dialects (however, a mode can still overwrite it)
|
||
|
var sqlKeywords = "alter and as asc between by count create delete desc distinct drop from group having in insert into is join like not on or order select set table union update values where limit ";
|
||
|
|
||
|
// turn a space-separated list into an array
|
||
|
function set(str) {
|
||
|
var obj = {}, words = str.split(" ");
|
||
|
for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
|
||
|
return obj;
|
||
|
}
|
||
|
|
||
|
CodeMirror.defineMIME("text/x-pgsql", {
|
||
|
name: "sql",
|
||
|
client: set("source"),
|
||
|
// http://www.postgresql.org/docs/9.5/static/sql-keywords-appendix.html
|
||
|
keywords: set(sqlKeywords + "a abort abs absent absolute access according action ada add admin after aggregate all allocate also always analyse analyze any are array array_agg array_max_cardinality asensitive assertion assignment asymmetric at atomic attribute attributes authorization avg backward base64 before begin begin_frame begin_partition bernoulli binary bit_length blob blocked bom both breadth c cache call called cardinality cascade cascaded case cast catalog catalog_name ceil ceiling chain characteristics characters character_length character_set_catalog character_set_name character_set_schema char_length check checkpoint class class_origin clob close cluster coalesce cobol collate collation collation_catalog collation_name collation_schema collect column columns column_name command_function command_function_code comment comments commit committed concurrently condition condition_number configuration conflict connect connection connection_name constraint constraints constraint_catalog constraint_name constraint_schema constructor contains content continue control conversion convert copy corr corresponding cost covar_pop covar_samp cross csv cube cume_dist current current_catalog current_date current_default_transform_group current_path current_role current_row current_schema current_time current_timestamp current_transform_group_for_type current_user cursor cursor_name cycle data database datalink datetime_interval_code datetime_interval_precision day db deallocate dec declare default defaults deferrable deferred defined definer degree delimiter delimiters dense_rank depth deref derived describe descriptor deterministic diagnostics dictionary disable discard disconnect dispatch dlnewcopy dlpreviouscopy dlurlcomplete dlurlcompleteonly dlurlcompletewrite dlurlpath dlurlpathonly dlurlpathwrite dlurlscheme dlurlserver dlvalue do document domain dynamic dynamic_function dynamic_function_code each element else empty enable encoding encrypted end end-exec end_frame end_partition enforced enum equals escape event every except exception exclude excluding exclusive exec execute exists exp explain expression extension external extract false family fetch file filter final first first_value flag float floor following for force foreign fortran forward found frame_row free freeze fs full function functions fusion g general generated get global go goto grant granted greatest grouping groups handler header hex hierarchy hold hour id identity if ignore ilike immediate immediately immutable implementation implicit import including increment indent index indexes indicator inherit inherits initially inline inner inout input insensitive instance instantiable instead integrity intersect intersection invoker isnull isolation k key key_member key_type label lag language large last last_value lateral lead leading leakproof least left length level library like_regex link listen ln load local localtime localtimestamp location locator lock locked logged lower m map mapping match matched materialized max maxvalue max_cardinality member merge message_length message_octet_length message_text method min minute minvalue mod mode modifies module month more move multiset mumps name names namespace national natural nchar nclob nesting new next nfc nfd nfkc nfkd nil no none normalize normalized nothing notify notnull nowait nth_value ntile null nullable nullif nulls number object occurrences_regex octets octet_length of off offset oids old only open operator option options ordering ordinality others out outer output over overlaps overlay overriding owned owner p pad parameter parameter_mode parameter_name parameter_ordinal_position parameter_specific_catalog parameter_specific_name parameter_specific_schema parser partial partition pascal passing passthrough password percent percentile_cont percentile_disc percent_rank period permission placing plans pli policy portion position position_regex power precedes preceding prepare prepared preserve primary prior privileges procedural procedure program public quote range rank read reads reassign rechec
|
||
|
// http://www.postgresql.org/docs/9.5/static/datatype.html
|
||
|
builtin: set("bigint int8 bigserial serial8 bit varying varbit boolean bool box bytea character char varchar cidr circle date double precision float8 inet integer int int4 interval json jsonb line lseg macaddr money numeric decimal path pg_lsn point polygon real float4 smallint int2 smallserial serial2 serial serial4 text time without zone with timetz timestamp timestamptz tsquery tsvector txid_snapshot uuid xml"),
|
||
|
atoms: set("false true null unknown"),
|
||
|
operatorChars: /^[*+\-%<>!=&|^]/,
|
||
|
dateSQL: set("date time timestamp"),
|
||
|
support: set("ODBCdotTable decimallessFloat zerolessFloat binaryNumber hexNumber nCharCast charsetCast commentHash commentSpaceRequired")
|
||
|
});
|
||
|
}());
|
||
|
|
||
|
};
|
||
|
|
||
|
/* eslint-enable */
|