├── .gitignore ├── .npmignore ├── .travis.yml ├── Makefile ├── README.md ├── bin └── sqljs ├── doc └── ref │ ├── antlr │ ├── sql2003Lexer.g │ └── sql2003Parser.g │ └── savage │ ├── bnf2html.pl │ ├── bnf2yacc.pl │ ├── index.html │ ├── outer-joins.html │ ├── sql-2003-1.bnf │ ├── sql-2003-1.bnf.html │ ├── sql-2003-1.yacc │ ├── sql-2003-2.bnf │ ├── sql-2003-2.bnf.html │ ├── sql-2003-2.yacc │ ├── sql-2003-core-features.html │ ├── sql-2003-noncore-features.html │ ├── sql-92.bnf │ ├── sql-92.bnf.html │ ├── sql-92.yacc │ ├── sql-99.bnf │ ├── sql-99.bnf.html │ ├── sql-99.yacc │ └── sql-bnf.mk ├── examples └── browser │ ├── demo.browserified.js │ ├── demo.js │ └── index.html ├── grammar ├── 00-00-00-init-start.pegjs ├── 09-01-00-literal-value.pegjs ├── 09-01-01-string-literal.pegjs ├── 09-01-02-number-literal.pegjs ├── 09-01-05-boolean-literal.pegjs ├── 09-01-07-null.pegjs ├── 09-02-00-identifiers.pegjs ├── 09-05-00-expression.pegjs ├── 13-00-00-statement.pegjs ├── 13-01-00-data-definition.pegjs ├── 13-01-01-alter-database.pegjs ├── 13-01-06-alter-table.pegjs ├── 13-01-08-create-database.pegjs ├── 13-01-14-create-table.pegjs ├── 13-01-17-drop-database.pegjs ├── 13-02-00-data-manipulation.pegjs ├── 13-02-01-call.pegjs ├── 13-02-05-insert.pegjs ├── 13-02-09-select-statement.pegjs ├── 13-07-04-set.pegjs ├── 13-08-04-use.pegjs ├── 14-02-02-05-foreign-key.pegjs ├── 80-literal-datetime.pegjs └── 99-whitespace.pegjs ├── lib ├── error-formatter.js ├── parse-options.js ├── sqljs-cli.js ├── sqljs-parser.js └── sqljs.js ├── package.json └── tests └── parser ├── 09-01-01-string.js ├── 09-01-02-number.js ├── 09-02-00-identifiers.js ├── 09-05-00-expression.js ├── 13-01-08-create-database.js ├── 13-01-14-create-table.js └── common └── helper-rule-yields.js /.gitignore: -------------------------------------------------------------------------------- 1 | lib/sqljs-parser.pegjs 2 | 3 | lib-cov 4 | *.seed 5 | *.log 6 | *.csv 7 | *.dat 8 | *.out 9 | *.pid 10 | *.gz 11 | 12 | pids 13 | logs 14 | results 15 | 16 | node_modules 17 | npm-debug.log 18 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | node_modules 15 | npm-debug.log 16 | 17 | examples 18 | grammar 19 | *.pegjs 20 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.10 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | GRAMMAR_FILES = $(shell find ./grammar/*.pegjs | sort) 2 | 3 | CAT=cat 4 | RM=rm -f 5 | NODE=node 6 | PEGJS=./node_modules/.bin/pegjs --cache 7 | NODEUNIT=./node_modules/.bin/nodeunit 8 | BROWSERIFY=./node_modules/.bin/browserify 9 | 10 | all: lib examples 11 | 12 | lib: ./lib/sqljs-parser.pegjs ./lib/sqljs-parser.js 13 | 14 | clean: 15 | $(RM) ./lib/sqljs-parser.pegjs 16 | $(RM) ./lib/sqljs-parser.js 17 | $(RM) ./examples/browser/demo.browserified.js 18 | 19 | test: 20 | $(NODEUNIT) --reporter minimal ./tests/* 21 | 22 | ./lib/sqljs-parser.pegjs: $(GRAMMAR_FILES) 23 | $(CAT) $(GRAMMAR_FILES) > ./lib/sqljs-parser.pegjs || $(RM) ./lib/sqljs-parser.pegjs 24 | 25 | ./lib/sqljs-parser.js: ./lib/sqljs-parser.pegjs 26 | $(PEGJS) ./lib/sqljs-parser.pegjs ./lib/sqljs-parser.js || $(RM) ./lib/sqljs-parser.js 27 | 28 | examples: example-browser 29 | 30 | example-browser: examples/browser/demo.browserified.js lib 31 | 32 | examples/browser/demo.browserified.js: examples/browser/demo.js 33 | $(BROWSERIFY) ./examples/browser/demo.js -o ./examples/browser/demo.browserified.js 34 | 35 | .PHONY: all lib examples example-browser clean test 36 | 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | sqljs [![Build Status](https://secure.travis-ci.org/sqljs/node-sqljs.png?branch=master)](http://travis-ci.org/sqljs/node-sqljs) 2 | ===== 3 | 4 | [![Dependency Status](https://david-dm.org/sqljs/node-sqljs.png)](https://david-dm.org/sqljs/node-sqljs) [![devDependency Status](https://david-dm.org/sqljs/node-sqljs/dev-status.png)](https://david-dm.org/sqljs/node-sqljs#info=devDependencies) [![Gitter](https://badges.gitter.im/Join Chat.svg)](https://gitter.im/sqljs/node-sqljs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | [![Gitipay](https://img.shields.io/gratipay/langpavel.svg)](https://gratipay.com/langpavel/) 6 | 7 | 8 | SQL parser for node.js 9 | 10 | Synopsis 11 | ======== 12 | * SQL parser useful for database abstraction layers and analyzers 13 | * Freeform syntax - it should be compatible with various SQL dialects 14 | 15 | Instalation 16 | =========== 17 | 18 | Because sqljs is still under heavy development, installation is better over git. 19 | In fact, at npm repository this package is still empty. 20 | 21 | Instalation via git: 22 | -------- 23 | 24 | git clone git://github.com/langpavel/node-sqljs.git sqljs && cd sqljs && npm install && make 25 | 26 | and optionally 27 | 28 | sudo npm link 29 | 30 | Instalation via npm: 31 | -------- 32 | 33 | npm install git://github.com/langpavel/node-sqljs.git 34 | 35 | or globally 36 | 37 | npm install -g git://github.com/langpavel/node-sqljs.git 38 | 39 | 40 | -------------------------------------------------------------------------------- /bin/sqljs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require('../lib/sqljs-cli'); 4 | -------------------------------------------------------------------------------- /doc/ref/savage/bnf2html.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # 3 | # @(#)$Id: bnf2html.pl,v 3.7 2005/07/13 18:32:35 jleffler Exp $ 4 | # 5 | # Convert SQL-92, SQL-99 BNF plain text file into hyperlinked HTML. 6 | 7 | use strict; 8 | use POSIX qw(strftime); 9 | 10 | my(%rules); # Indexed by rule names w/o angle-brackets; each entry is a ref to a hash. 11 | my(%keywords); # Index by keywords; each entry is a ref to a hash. 12 | 13 | use constant debug => 0; 14 | 15 | sub top 16 | { 17 | print "

Top

\n\n"; 18 | } 19 | 20 | # Usage: add_entry(\%keywords, $keyword, $rule); 21 | # Usage: add_entry(\%rules, $rhs, $rule); 22 | sub add_entry 23 | { 24 | my($reflist, $lhs, $rhs) = @_; 25 | ${$reflist}{$lhs} = {} unless defined ${$reflist}{$lhs}; 26 | ${$reflist}{$lhs}{$rhs} = 1; 27 | } 28 | 29 | sub add_refs 30 | { 31 | my($def, $tail) = @_; 32 | print "\n\n" if debug; 33 | return if $tail =~ m/!!/; 34 | while ($tail) 35 | { 36 | $tail =~ s/^\s*//; 37 | if ($tail =~ m%^\<([-:/\w\s]+)\>%) 38 | { 39 | print "\n" if debug; 40 | add_entry(\%rules, $1, $def); 41 | $tail =~ s%^\<([-:/\w\s]+)\>%%; 42 | } 43 | elsif ($tail =~ m%^([-:/\w]+)%) 44 | { 45 | my($token) = $1; 46 | print "\n" if debug; 47 | add_entry(\%keywords, $token, $def) if $token =~ m%[[:alpha:]][[:alpha:]]% || $token eq 'C'; 48 | $tail =~ s%^[-:/\w]+%%; 49 | } 50 | else 51 | { 52 | # Otherwise, it is punctuation (such as the BNF metacharacters). 53 | $tail =~ s%^[^-:/\w]%%; 54 | } 55 | } 56 | } 57 | 58 | # NB: webcode replaces tabs with blanks! 59 | open WEBCODE, "webcode @ARGV |" or die "$!"; 60 | 61 | $_ = ; 62 | exit 0 unless defined($_); 63 | chomp; 64 | 65 | # Is it wicked to use double quoting with single quotes, as in qq'text'? 66 | # It is used quite extensively in this script - beware! 67 | print qq'\n'; 68 | print "\n"; 69 | print "\n\n"; 70 | print " $_ \n\n\n\n"; 71 | print "

$_

\n\n"; 72 | print qq' \n'; 73 | 74 | print "
\n"; 75 | print qq' Cross-Reference: rules \n'; 76 | print "
\n"; 77 | print qq' Cross-Reference: keywords \n'; 78 | print "
\n"; 79 | 80 | sub rcs_id 81 | { 82 | my($id) = @_; 83 | $id =~ s%^(@\(#\))?\$[I]d: %%o; 84 | $id =~ s% \$$%%o; 85 | $id =~ s%,v % %o; 86 | $id =~ s%\w+ Exp( \w+)?$%%o; 87 | my(@words) = split / /, $id; 88 | my($version) = "file $words[0] version $words[1] dated $words[2] $words[3]"; 89 | return $version; 90 | } 91 | 92 | sub iso8601_format 93 | { 94 | my($tm) = @_; 95 | my $today = strftime("%Y-%m-%d %H:%M:%S+00:00", gmtime($tm)); 96 | return($today); 97 | } 98 | 99 | 100 | # Print hrefs for non-terminals and keywords. 101 | # Also substitute /* Nothing */ for an absence of productions between alternatives. 102 | sub print_tail 103 | { 104 | my($tail, $tcount) = @_; 105 | while ($tail) 106 | { 107 | my($newtail); 108 | if ($tail =~ m%^\s+%) 109 | { 110 | my($spaces) = $&; 111 | $newtail = $'; 112 | print "\n" if debug; 113 | $spaces =~ s% {4,8}%    %g; 114 | print $spaces; 115 | # Spaces are not a token - don't count them! 116 | } 117 | elsif ($tail =~ m%^'[^']*'% || $tail =~ m%^"[^"]*"% || $tail =~ m%^!!.*$%) 118 | { 119 | # Quoted literal - print and ignore. 120 | # Or meta-expression... 121 | my($quote) = $&; 122 | $newtail = $'; 123 | print "\n" if debug; 124 | $quote =~ s%!!.*% $quote %; 125 | print $quote; 126 | $tcount++; 127 | } 128 | elsif ($tail =~ m%^\<([-:/\w\s]+)\>%) 129 | { 130 | my($nonterm) = $&; 131 | $newtail = $'; 132 | print "\n" if debug; 133 | $nonterm =~ s%\<([-:/\w\s]+)\>%\<$1\>%; 134 | print " $nonterm"; 135 | $tcount++; 136 | } 137 | elsif ($tail =~ m%^[\w_]+%) 138 | { 139 | # Keyword 140 | my($keyword) = $&; 141 | $newtail = $'; 142 | print "\n" if debug; 143 | print qq' $keyword '; 144 | $tcount++; 145 | } 146 | else 147 | { 148 | # Metacharacter, string literal, etc. 149 | $tail =~ m%\S+%; 150 | my($symbol) = $&; 151 | $newtail = $'; 152 | print "\n" if debug; 153 | if ($symbol eq '|') 154 | { 155 | print "/* Nothing */ " if $tcount == 0; 156 | $tcount = 0; 157 | } 158 | else 159 | { 160 | $symbol =~ s%...omitted...%/* $& */%i; 161 | $tcount++; 162 | } 163 | print " $symbol"; 164 | } 165 | $tail = $newtail; 166 | } 167 | return($tcount); 168 | } 169 | 170 | my $hr_count = 0; 171 | my $tcount = 0; # Ick! 172 | my $def; # Current rule 173 | 174 | # Don't forget - the input has been web-encoded! 175 | 176 | while () 177 | { 178 | chomp; 179 | next if /^===*$/o; 180 | s/\s+$//o; # Remove trailing white space 181 | if (/^[ ]*$/) 182 | { 183 | print "\n"; 184 | } 185 | elsif (/^---*$/) 186 | { 187 | print "
\n"; 188 | } 189 | elsif (/^@.#..Id:/) 190 | { 191 | # Convert what(1) string identifier into version information 192 | my $id = '$Id: bnf2html.pl,v 3.7 2005/07/13 18:32:35 jleffler Exp $'; 193 | my($v1) = rcs_id($_); 194 | my $v2 = rcs_id($id); 195 | print "

\n"; 196 | print "Derived from $v1\n"; 197 | my $today = iso8601_format(time); 198 | print "
\n"; 199 | print "Generated on $today by $v2\n"; 200 | print "

\n"; 201 | } 202 | elsif (/ ::=/) 203 | { 204 | # Definition line 205 | $def = $_; 206 | $def =~ s%\<([-:/()\w\s]+)\>.*%$1%; 207 | my($tail) = $_; 208 | $tail =~ s%.*::=\s*%%; 209 | print qq'

  \n'; 210 | print qq' <$def>    ::='; 211 | $tcount = 0; 212 | if ($tail) 213 | { 214 | add_refs($def, $tail); 215 | print "  "; 216 | $tcount = print_tail($tail, $tcount); 217 | } 218 | print "\n"; 219 | } 220 | elsif (/^\s/) 221 | { 222 | # Expansion line 223 | add_refs($def, $_); 224 | print "
"; 225 | $tcount = print_tail($_, $tcount); 226 | } 227 | elsif (m/^--[\/]?(\w+)/) 228 | { 229 | # Pseudo-directive line in lower-case 230 | # Print a 'Top' link before


tags except first. 231 | top if /--hr/ && $hr_count++ > 0; 232 | s%--(/?[a-z][a-z\d]*)%<$1>%; 233 | s%\<([-:/\w\s]+)\>%\<$1\>%g; 234 | print "$_\n"; 235 | } 236 | elsif (m%^--##%) 237 | { 238 | # Undo web-coding 239 | s%>%>%g; 240 | s%<%<%g; 241 | s%&%&%g; 242 | s%^--##\s*%%; 243 | print "$_\n"; 244 | } 245 | elsif (m/^--%start\s+(\w+)/) 246 | { 247 | # Designated start symbol 248 | my $start = $1; 249 | print qq'

Start symbol: $start

\n'; 250 | } 251 | else 252 | { 253 | # Anything unrecognized passed through unchanged! 254 | print "$_\n"; 255 | } 256 | } 257 | 258 | # Print index of initial letters for keywords. 259 | sub print_index_key 260 | { 261 | my($prefix, @keys) = @_; 262 | my %letters = (); 263 | foreach my $keyword (@keys) 264 | { 265 | my $initial = uc substr $keyword, 0, 1; 266 | $letters{$initial} = 1; 267 | } 268 | foreach my $letter ('A' .. 'Z') 269 | { 270 | if (defined($letters{$letter})) 271 | { 272 | print qq' $letter \n'; 273 | } 274 | else 275 | { 276 | print qq'$letter\n'; 277 | } 278 | } 279 | print "\n"; 280 | } 281 | 282 | ### Generate cross-reference tables 283 | 284 | { 285 | print "
\n\n"; 286 | print "
\n"; 287 | print qq'\n'; 288 | print "

Cross-Reference Table: Rules

\n"; 289 | 290 | print_index_key("rules", keys %rules); 291 | 292 | print "\n"; 293 | print "\n"; 294 | my %letters = (); 295 | 296 | foreach my $rule (sort { uc $a cmp uc $b } keys %rules) 297 | { 298 | my $initial = uc substr $rule, 0, 1; 299 | my $label = ""; 300 | if (!defined($letters{$initial})) 301 | { 302 | $letters{$initial} = 1; 303 | $label = qq' '; 304 | } 305 | print qq'\n \n\n"; 313 | } 314 | print "
Rule (non-terminal) Rules using it
$label $rule '; 306 | my $pad = ""; 307 | foreach my $ref (sort { uc $a cmp uc $b } keys %{$rules{$rule}}) 308 | { 309 | print qq'$pad <$ref> \n'; 310 | $pad = " "; 311 | } 312 | print "
\n"; 315 | print "
\n"; 316 | top; 317 | } 318 | 319 | { 320 | print "
\n"; 321 | print qq'\n'; 322 | print "

Cross-Reference Table: Keywords

\n"; 323 | 324 | print_index_key("keywords", keys %keywords); 325 | 326 | print "\n"; 327 | print "\n"; 328 | my %letters = (); 329 | foreach my $keyword (sort { uc $a cmp uc $b } keys %keywords) 330 | { 331 | my $initial = uc substr $keyword, 0, 1; 332 | my $label = ""; 333 | if (!defined($letters{$initial})) 334 | { 335 | $letters{$initial} = 1; 336 | $label = qq' '; 337 | } 338 | print qq'\n \n\n"; 346 | } 347 | print "
Keyword Rules using it
$label $keyword '; 339 | my $pad = ""; 340 | foreach my $ref (sort { uc $a cmp uc $b } keys %{$keywords{$keyword}}) 341 | { 342 | print qq'$pad <$ref> \n'; 343 | $pad = " "; 344 | } 345 | print "
\n"; 348 | print "
\n"; 349 | top; 350 | print "
\n"; 351 | } 352 | 353 | printf "%s\n", q'Please send feedback to Jonathan Leffler, variously:'; 354 | printf "%s\n", q' jleffler@us.ibm.com or'; 355 | printf "%s\n", q' jonathan.leffler@gmail.com .'; 356 | 357 | 358 | print "\n\n\n"; 359 | 360 | -------------------------------------------------------------------------------- /doc/ref/savage/bnf2yacc.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # 3 | # @(#)$Id: bnf2yacc.pl,v 1.12 2005/02/28 19:06:48 jleffler Exp $ 4 | # 5 | # Convert SQL-92, SQL-99 BNF plain text file into YACC grammar. 6 | 7 | use strict; 8 | $| = 1; 9 | 10 | use constant debug => 0; 11 | 12 | my $heading = ""; 13 | my %tokens; 14 | my %nonterminals; 15 | my %rules; 16 | my %used; 17 | my $start; 18 | my @grammar; 19 | 20 | my $nt_number = 0; 21 | 22 | # Generate a new non-terminal identifier 23 | sub new_non_terminal 24 | { 25 | my($prefix) = @_; 26 | $prefix = "" unless defined $prefix; 27 | return sprintf "${prefix}nt_%03d", ++$nt_number; 28 | } 29 | 30 | # map_non_terminal converts names that are not acceptable to Yacc into names that are. 31 | # Non-identifier characters are converted to underscores. 32 | # If the first character is not alphabetic, prefix 'j_'. 33 | # Case-convert to lower case. 34 | sub map_non_terminal 35 | { 36 | my($nt) = @_; 37 | $nt =~ s/\W+/_/go; 38 | $nt = "j_$nt" unless $nt =~ m/^[a-zA-Z]/o; 39 | $nt =~ tr/[A-Z]/[a-z]/; 40 | $nt =~ s/__+/_/go; 41 | return $nt; 42 | } 43 | 44 | # scan_rhs breaks up the RHS of a rule into a token stream 45 | # Keywords (terminals) are prefixed with a '#' marker. 46 | sub scan_rhs 47 | { 48 | my($tail) = @_; 49 | my(@rhs); 50 | while ($tail) 51 | { 52 | print "RHS: $tail\n" if debug; 53 | my $name; 54 | if ($tail =~ m%^(\s*<([-:/()_\w\s]+)>\s*)%o) 55 | { 56 | # Simpler regex for non-terminal: <[^>]+> 57 | # Non-terminal 58 | my $n = $2; 59 | print "N: $n\n" if debug; 60 | $tail = substr $tail, length($1); 61 | $name = map_non_terminal($n); 62 | $nonterminals{$name} = 1; 63 | $used{$name} = 1; 64 | push @rhs, $name; 65 | } 66 | elsif ($tail =~ m%^(\s*(\w[-\w\d_.]*)\s*)%o) 67 | { 68 | # Terminal (keyword) 69 | # Dot '.' is used in Interfaces.SQL in Ada syntax 70 | # Dash '-' is used in EXEC-SQL in the keywords. 71 | my $t = $2; 72 | print "T: $t\n" if debug; 73 | $tail = substr $tail, length($1); 74 | $name = $t; 75 | $tokens{$name} = 1; 76 | push @rhs, "#$name"; 77 | } 78 | elsif ($tail =~ m{^(\s*([][{}"'%&()*+,-./:;<=>?^_|])\s*)$}o) #'" (Vim palliative) 79 | { 80 | # Punctuation (non-metacharacters) 81 | # Note that none of '@', '~', '!' or '\' have any significance in SQL 82 | my $p = $2; 83 | print "P: $p\n" if debug; 84 | $tail = substr $tail, length($1); 85 | $p = "\\'" if $p eq "'"; 86 | $name = "'$p'"; 87 | push @rhs, $name; 88 | } 89 | elsif ($tail =~ m%^(\s*('[^']*'))\s*%o || 90 | $tail =~ m%^(\s*("[^"]*"))\s*%o) 91 | { 92 | # Terminal in quotes - single or double. 93 | # (Possibly a multi-character string). 94 | my $q = $2; 95 | print "Q: $q\n" if debug; 96 | $tail = substr $tail, length($1); 97 | $q =~ m%^(['"])(.+)['"]$%o; 98 | # Expand multi-character string constants. 99 | # into repeated single-character constants. 100 | my($o) = $1; 101 | my($l) = $2; 102 | while (length($l)) 103 | { 104 | my($c) = substr $l, 0, 1; 105 | $name = "$o$c$o"; 106 | $l = substr $l, 1, length($l)-1; 107 | push @rhs, $name; 108 | } 109 | } 110 | elsif ($tail =~ m%^(\s*([{}\|\[\]]|\.\.\.)\s*)%o) 111 | { 112 | # Punctuation (metacharacters) 113 | my $p = $2; 114 | print "M: $p\n" if debug; 115 | $tail = substr $tail, length($1); 116 | $name = $p; 117 | push @rhs, $name; 118 | } 119 | elsif ($tail =~ m%^\s*!!%o) 120 | { 121 | # Exhortation to see the syntax rules - usually. 122 | my $str = "/* $tail */"; 123 | push @rhs, $str; 124 | last; 125 | } 126 | else 127 | { 128 | # Unknown! 129 | print "/* UNK: $tail */\n"; 130 | print STDERR "UNK: $tail\n"; 131 | last; 132 | } 133 | } 134 | return(@rhs); 135 | } 136 | 137 | # Format a Yacc rule given LHS and RHS array 138 | sub record_rule 139 | { 140 | my($lhs, $comment, @rule) = @_; 141 | my($production) = ""; 142 | print "==>> record_rule ($lhs : @rule)\n" if debug; 143 | $production .= "/*\n" if $comment; 144 | $production .= "$lhs\n\t:\t"; 145 | my $pad = ""; 146 | my $br_count = 0; 147 | for (my $i = 0; $i <= $#rule; $i++) 148 | { 149 | my $item = $rule[$i]; 150 | print "==== item $item\n" if debug; 151 | if ($item eq "|" && $br_count == 0) 152 | { 153 | $production .= "\n\t|\t"; 154 | $pad = ""; 155 | } 156 | else 157 | { 158 | $production .= "$pad$item"; 159 | $pad = " "; 160 | $br_count++ if ($item eq '[' or $item eq '{'); 161 | $br_count-- if ($item eq ']' or $item eq '}'); 162 | } 163 | } 164 | $production .= "\n\t;\n"; 165 | $production .= "*/\n" if $comment; 166 | $production .= "\n"; 167 | print "$production" if debug; 168 | push @grammar, $production; 169 | print "<<== record_rule\n" if debug; 170 | } 171 | 172 | sub print_iterator 173 | { 174 | my($lhs,$rhs) = @_; 175 | my($production) = ""; 176 | print "==>> print_iterator ($lhs $rhs)\n" if debug; 177 | $production .= "$lhs\n\t:\t$rhs\n\t|\t$lhs $rhs\n\t;\n\n"; 178 | print "<<== print_iterator\n" if debug; 179 | push @grammar, $production; 180 | } 181 | 182 | # Process an optional item enclosed in square brackets 183 | sub find_balanced_bracket 184 | { 185 | my($lhs,@rhs) = @_; 186 | my(@rule) = ( "/* Nothing */", "|"); 187 | print "==>> find_balanced_bracket ($lhs : @rhs)\n" if debug; 188 | while (my $name = shift @rhs) 189 | { 190 | print " name = $name\n" if debug; 191 | if ($name eq ']') 192 | { 193 | # Found closing bracket 194 | # Terminate search 195 | last; 196 | } 197 | elsif ($name eq '[') 198 | { 199 | # Found nested optional clause 200 | my $tag = new_non_terminal('opt_'); 201 | @rhs = find_balanced_bracket($tag, @rhs); 202 | push @rule, $tag; 203 | } 204 | elsif ($name eq '{') 205 | { 206 | # Found start of sequence 207 | my $tag = new_non_terminal('seq_'); 208 | @rhs = find_balanced_brace($tag, @rhs); 209 | push @rule, $tag; 210 | } 211 | elsif ($name eq '}') 212 | { 213 | # Found unbalanced close brace. 214 | # Error! 215 | } 216 | elsif ($name eq '...') 217 | { 218 | # Found iteration. 219 | my $tag = new_non_terminal('lst_'); 220 | print "==== find_balanced_bracket: iterator (@rule)\n" if debug; 221 | my($old) = pop @rule; 222 | push @rule, $tag; 223 | print "==== find_balanced_bracket: iterator ($tag/$old - @rule)\n" if debug; 224 | print_iterator($tag, $old); 225 | } 226 | else 227 | { 228 | $name =~ s/^#//; 229 | push @rule, $name; 230 | $used{$name} = 1; 231 | } 232 | } 233 | record_rule($lhs, 0, @rule); 234 | print "<<== find_balanced_bracket: @rhs)\n" if debug; 235 | return(@rhs); 236 | } 237 | 238 | # Process an sequence item enclosed in curly braces 239 | sub find_balanced_brace 240 | { 241 | my($lhs,@rhs) = @_; 242 | my(@rule); 243 | print "==>> find_balanced_brace ($lhs : @rhs)\n" if debug; 244 | while (my $name = shift @rhs) 245 | { 246 | print " name = $name\n" if debug; 247 | if ($name eq '}') 248 | { 249 | # Found closing brace 250 | # Terminate search 251 | last; 252 | } 253 | elsif ($name eq '[') 254 | { 255 | # Found nested optional clause 256 | my $tag = new_non_terminal('opt_'); 257 | @rhs = find_balanced_bracket($tag, @rhs); 258 | push @rule, $tag; 259 | } 260 | elsif ($name eq '{') 261 | { 262 | # Found start of sequence 263 | my $tag = new_non_terminal('seq_'); 264 | @rhs = find_balanced_brace($tag, @rhs); 265 | push @rule, $tag; 266 | } 267 | elsif ($name eq ']') 268 | { 269 | # Found unbalanced close brace. 270 | # Error! 271 | } 272 | elsif ($name eq '...') 273 | { 274 | # Found iteration. 275 | my $tag = new_non_terminal('lst_'); 276 | print "==== find_balanced_brace: iterator (@rule)\n" if debug; 277 | my($old) = pop @rule; 278 | push @rule, $tag; 279 | print "==== find_balanced_brace: iterator ($tag/$old - @rule)\n" if debug; 280 | print_iterator($tag, $old); 281 | } 282 | else 283 | { 284 | $name =~ s/^#//; 285 | push @rule, $name; 286 | $used{$name} = 1; 287 | } 288 | } 289 | record_rule($lhs, 0, @rule); 290 | print "<<== find_balanced_brace: @rhs)\n" if debug; 291 | return(@rhs); 292 | } 293 | 294 | # Note that the [ and { parts are nice and easy because they are 295 | # balanced operators. The iteration operator ... is much harder to 296 | # process because it is a trailing modifier. When processing the list 297 | # of symbols, you need to establish whether there is a trailing iterator 298 | # after the current symbol, and modify the behaviour appropriately. 299 | sub process_rhs 300 | { 301 | my($lhs, $tail) = @_; 302 | my(@rhs) = scan_rhs($tail); 303 | print "==>> process_rhs ($lhs : @rhs)\n" if debug; 304 | # List parsed rule in output only if debugging. 305 | record_rule($lhs, 1, @rhs) if debug; 306 | my(@rule); 307 | while (my $name = shift @rhs) 308 | { 309 | print "name = $name\n" if debug; 310 | if ($name eq '[') 311 | { 312 | my $tag = new_non_terminal('opt_'); 313 | @rhs = find_balanced_bracket($tag, @rhs); 314 | push @rule, $tag; 315 | } 316 | elsif ($name eq ']') 317 | { 318 | # Found a close bracket for something unbalanced. 319 | # Error! 320 | } 321 | elsif ($name eq '{') 322 | { 323 | # Start of mandatory sequence of items, possibly containing alternatives. 324 | my $tag = new_non_terminal('seq_'); 325 | @rhs = find_balanced_brace($tag, @rhs); 326 | push @rule, $tag; 327 | } 328 | elsif ($name eq '}') 329 | { 330 | # Found a close brace for something unbalanced. 331 | # Error! 332 | } 333 | elsif ($name eq '|') 334 | { 335 | # End of one alternative and start of a new one. 336 | print "==== process_rhs: alternative $name\n" if debug; 337 | push @rule, $name; 338 | } 339 | elsif ($name eq '...') 340 | { 341 | # Found iteration. 342 | my $tag = new_non_terminal('lst_'); 343 | my($old) = pop @rule; 344 | push @rule, $tag; 345 | print "==== process_rhs: iterator\n" if debug; 346 | print_iterator($tag, $old); 347 | } 348 | elsif ($name =~ m/^#/) 349 | { 350 | # Keyword token 351 | print "==== process_rhs: token $name\n" if debug; 352 | $name =~ s/^#//; 353 | push @rule, $name; 354 | } 355 | else 356 | { 357 | # Non-terminal (or comment) 358 | print "==== process_rhs: non-terminal $name\n" if debug; 359 | push @rule, $name; 360 | } 361 | } 362 | print "==== process_rhs: @rule\n" if debug; 363 | record_rule($lhs, 0, @rule); 364 | print "<<== process_rhs\n" if debug; 365 | } 366 | 367 | sub count_unmatched_keys 368 | { 369 | my($ref1, $ref2) = @_; 370 | my(%keys) = %$ref1; 371 | my(%match) = %$ref2; 372 | my($count) = 0; 373 | foreach my $key (keys %keys) 374 | { 375 | $count++ unless defined $match{$key}; 376 | } 377 | return $count; 378 | } 379 | 380 | # ------------------------------------------------------------ 381 | 382 | open INPUT, "cat @ARGV |" or die "$!"; 383 | $_ = ; 384 | exit 0 unless defined($_); 385 | chomp; 386 | $heading = "%{\n/*\n** $_\n*/\n%}\n\n" unless m/^\s*$/; 387 | 388 | # Commentary appears in column 1. 389 | # Continuations of rules have a blank in column 1. 390 | # Blank lines, dash lines and equals lines separate rules (are not embedded within them).. 391 | 392 | while () 393 | { 394 | chomp; 395 | print "DBG: $_\n" if debug; 396 | next if /^===*$/o; 397 | next if /^\s*$/o; # Blank lines 398 | next if /^---*$/o; # Horizontal lines 399 | if (/^--/o) 400 | { 401 | # Various HTML pseudo-directives 402 | if (m%^--/?\w+\b%) 403 | { 404 | print "/* $' */\n" if $'; 405 | } 406 | elsif (/^--%start (\w+)/) 407 | { 408 | $start = $1; 409 | print "/* Start symbol - $start */\n"; 410 | } 411 | elsif (/^--##/) 412 | { 413 | print "/* $_ */\n"; 414 | } 415 | else 416 | { 417 | print "/* Unrecognized 2: $_ */\n"; 418 | } 419 | } 420 | elsif (/^@.#..Id:/) 421 | { 422 | # Convert what(1) string identifier into version information 423 | s%^@.#..Id: %%; 424 | s% \$$%%; 425 | s%,v % %; 426 | s%\w+ Exp( \w+)?$%%; 427 | my @words = split; 428 | print "/*\n"; 429 | print "** Derived from file $words[0] version $words[1] dated $words[2] $words[3]\n"; 430 | print "*/\n"; 431 | } 432 | elsif (/ ::=/) 433 | { 434 | # Definition line 435 | my $def = $_; 436 | $def =~ s%<([-:/()\w\s]+)>.*%$1%o; 437 | $def = map_non_terminal($def); 438 | $rules{$def} = 1; 439 | $nonterminals{$def} = 1; 440 | my $tail = $_; 441 | $tail =~ s%.*::=\s*%%; # Remove LHS of statement 442 | while () 443 | { 444 | chomp; 445 | last unless /^\s/; 446 | $tail .= $_; 447 | } 448 | process_rhs($def, $tail); 449 | } 450 | else 451 | { 452 | # Anything unrecognized passed through as a comment! 453 | print "/* $_ */\n"; 454 | } 455 | } 456 | 457 | close INPUT; 458 | 459 | print "==== End of input phase ====\n" if debug; 460 | 461 | print $heading if $heading; 462 | 463 | # List of tokens 464 | foreach my $token (sort keys %tokens) 465 | { 466 | print "\%token $token\n"; 467 | } 468 | print "\n"; 469 | 470 | # Undefined non-terminals might need to be treated as tokens 471 | if (count_unmatched_keys(\%nonterminals, \%rules) > 0) 472 | { 473 | print "/* The following non-terminals were not defined */\n"; 474 | foreach my $nt (sort keys %nonterminals) 475 | { 476 | print "%token $nt\n" unless defined $rules{$nt}; 477 | } 478 | print "/* End of undefined non-terminals */\n\n"; 479 | } 480 | 481 | # List the rules that are defined in the original grammar. 482 | # Do not list the rules defined by this conversion process. 483 | print "/*\n"; 484 | foreach my $nt (sort keys %nonterminals) 485 | { 486 | print "\%rule $nt\n"; 487 | } 488 | print "*/\n\n"; 489 | 490 | 491 | if (defined $start) 492 | { 493 | print "%start $start\n\n"; 494 | print "%%\n\n"; 495 | } 496 | else 497 | { 498 | # No start symbol defined - let's see if we can work out what to use. 499 | # If there's more than one unused non-terminal, then treat them 500 | # all as simple alternatives to a list of statements. 501 | my $count = count_unmatched_keys(\%nonterminals, \%used); 502 | 503 | if ($count > 1) 504 | { 505 | my $prog = "bnf_program"; 506 | my $stmt = "bnf_statement"; 507 | print "%start $prog\n\n"; 508 | print "%%\n\n"; 509 | print "$prog\n\t:\t$stmt\n\t|\t$prog $stmt\n\t;\n\n"; 510 | print "$stmt\n"; 511 | my $pad = "\t:\t"; 512 | foreach my $nt (sort keys %nonterminals) 513 | { 514 | unless (defined $used{$nt}) 515 | { 516 | print "$pad$nt\n"; 517 | $pad = "\t|\t"; 518 | } 519 | } 520 | print "\t;\n\n"; 521 | } 522 | elsif ($count == 1) 523 | { 524 | foreach my $nt (sort keys %nonterminals) 525 | { 526 | print "%start $nt" unless defined $used{$nt}; 527 | } 528 | print "%%\n\n"; 529 | } 530 | else 531 | { 532 | # No single start symbol - loop? 533 | # Error! 534 | print STDERR "$0: no start symbol recognized!\n"; 535 | print "%%\n\n"; 536 | } 537 | } 538 | 539 | # Output the complete grammar 540 | while (my $line = shift @grammar) 541 | { 542 | print $line; 543 | } 544 | 545 | print "\n%%\n\n"; 546 | 547 | __END__ 548 | 549 | =pod 550 | 551 | Given a rule: 552 | 553 | abc: def ghi jkl 554 | 555 | The Yacc output is: 556 | 557 | abc 558 | : def ghi jkl 559 | ; 560 | 561 | Given a rule: 562 | 563 | abc: def [ ghi ] jkl 564 | 565 | The Yacc output is: 566 | 567 | abc 568 | : def opt_nt_0001 jkl 569 | ; 570 | 571 | opt_nt_0001 572 | : /* Nothing */ 573 | | ghi 574 | ; 575 | 576 | Given a rule: 577 | 578 | abc: def { ghi } jkl 579 | 580 | The Yacc output is: 581 | 582 | abc 583 | : def seq_nt_0002 jkl 584 | ; 585 | 586 | seq_nt_0002 587 | : ghi 588 | ; 589 | 590 | Note that such rules are seldom used in isolation; either the contents 591 | of the '{' to '}' contains alternatives, or the construct as a whole is 592 | followed by a repetition. 593 | 594 | Given a rule: 595 | 596 | abc: def | ghi 597 | 598 | The Yacc output is: 599 | 600 | abc 601 | : def 602 | | ghi 603 | ; 604 | 605 | Given a rule: 606 | 607 | abc: def ghi... jkl 608 | 609 | The Yacc output is: 610 | 611 | abc 612 | : def lst_nt_0003 jkl 613 | ; 614 | 615 | lst_nt_0003 616 | : ghi 617 | | lst_nt_0003 ghi 618 | ; 619 | 620 | These rules can be, and often are, combined. The following examples 621 | come from the SQL-99 grammar which is the target of this effort. The 622 | target of this program is to produce Yacc rules equivalent to those 623 | which follow each fragment. Note that keywords (equivalently, 624 | terminals) are in upper case only; mixed case or lower case symbols are 625 | non-terminals. 626 | 627 | ::= 628 | 629 | 630 | 631 | [ ] 632 | [ ] 633 | [ ... ] 634 | ... 635 | 636 | SQL_client_module_definition 637 | : module_name_clause language_clause module_authorization_clause opt_nt_0001 opt_nt_0002 opt_nt_0003 lst_nt_0004 638 | ; 639 | opt_nt_0001 640 | : /* Nothing */ 641 | | module_path_specification 642 | ; 643 | opt_nt_0002 644 | : /* Nothing */ 645 | | module_transform_group_specification 646 | ; 647 | opt_nt_0003 648 | : /* Nothing */ 649 | | lst_nt_0005 650 | ; 651 | lst_nt_0004 652 | : module_contents 653 | | lst_nt_0004 module_contents 654 | ; 655 | lst_nt_0005 656 | : temporary_table_declaration 657 | | lst_nt_0005 temporary_table_declaration 658 | ; 659 | 660 | The next example is interesting - it is fairly typical of the grammar, 661 | but is not minimal. The rule could be written ' ::= 662 | [ ... ]' without altering the 663 | meaning. It is not clear whether this program should apply this 664 | transformation automatically. 665 | 666 | ::= [ { }... ] 667 | 668 | identifier_body 669 | : identifier_start opt_nt_0006 670 | ; 671 | opt_nt_0006 672 | : /* Nothing */ 673 | | lst_nt_0007 674 | ; 675 | lst_nt_0007 676 | : seq_nt_0008 677 | | lst_nt_0007 seq_nt_0008 678 | ; 679 | seq_nt_0008 680 | : identifier_part 681 | ; 682 | 683 | /* Optimized alternative to lst_nt_0007 */ 684 | lst_nt_0007 685 | : identifier_part 686 | | lst_nt_0007 identifier_part 687 | ; 688 | 689 | ::= 690 | [ { | }... ] 691 | 692 | sql_language_identifier 693 | : sql_language_identifier_start opt_nt_0009 694 | ; 695 | opt_nt_0009 696 | : /* Nothing */ 697 | | lst_nt_0010 698 | ; 699 | lst_nt_0010 700 | : seq_nt_0011 701 | | lst_nt_0010 seq_nt_0011 702 | ; 703 | seq_nt_0011 704 | : underscore 705 | | sql_language_identifier_part 706 | ; 707 | 708 | The next rule is the first example with keywords. 709 | 710 | ::= 711 | SCHEMA 712 | | AUTHORIZATION 713 | | SCHEMA AUTHORIZATION 714 | 715 | module_authorization_clause 716 | : SCHEMA schema_name 717 | | AUTHORIZATION module_authorization_identifier 718 | | SCHEMA schema_name AUTHORIZATION module_authorization_identifier 719 | ; 720 | 721 | ::= 722 | TRANSFORM GROUP { | } 723 | 724 | transform_group_specification 725 | : TRANSFORM GROUP seq_nt_0012 726 | ; 727 | seq_nt_0012 728 | : single_group_specification 729 | | multiple_group_specification 730 | ; 731 | 732 | ::= [ { }... ] 733 | 734 | multiple_group_specification 735 | : group_specification opt_nt_0013 736 | ; 737 | opt_nt_0013 738 | : /* Nothing */ 739 | | lst_nt_0014 740 | ; 741 | lst_nt_0014 742 | : seq_nt_0015 743 | | lst_nt_0014 seq_nt_0015 744 | ; 745 | seq_nt_0015 746 | : comma group_specification 747 | ; 748 | 749 | Except for the presence of a token () after the optional 750 | list, the next example is equivalent to the previous one. It does show, 751 | however, that there is an element of lookahead required to tell whether 752 | an optional item contains a list or a sequence or a simple list of 753 | terminals and non-terminals. 754 | 755 | ::= 756 |
[ {
}... ] 757 | 758 | table_element_list 759 | : left_paren table_element opt_nt_0016 right_paren 760 | ; 761 | opt_nt_0016 762 | : /* Nothing */ 763 | | lst_nt_0017 764 | ; 765 | lst_nt_0017 766 | : seq_nt_0018 767 | | lst_nt_0017 seq_nt_0018 768 | ; 769 | seq_nt_0018 770 | : comma table_element 771 | ; 772 | 773 | The next example is interesting because the sequence item contains 774 | alternatives with no optionality or iteration. It suggests that the 775 | term 'sequence' is not necessarily the 'mot juste'. 776 | 777 | ::= 778 | 779 | { | } 780 | [ ] 781 | [ ] 782 | [ ... ] 783 | [ ] 784 | 785 | column_definition 786 | : column_name seq_nt_0019 opt_nt_0020 opt_nt_0021 opt_nt_0022 opt_nt_0023 787 | ; 788 | seq_nt_0019 789 | : data_type 790 | | domain_name 791 | ; 792 | opt_nt_0020 793 | : /* Nothing */ 794 | | reference_scope_check 795 | ; 796 | opt_nt_0021 797 | : /* Nothing */ 798 | | default_clause 799 | ; 800 | opt_nt_0022 801 | : /* Nothing */ 802 | | lst_nt_0024 803 | ; 804 | opt_nt_0023 805 | : /* Nothing */ 806 | | collate_clause 807 | ; 808 | lst_nt_0024 809 | : column_constraint_definition 810 | | lst_nt_0024 column_constraint_definition 811 | ; 812 | 813 | 814 | [ {
203 | --## 204 | --## 205 | --## 206 | --## 207 | --## 208 | --## 209 | --## 210 | --## 211 | --## 212 | --##
1 PKG001 Enhanced datetime facilities
2 PKG002 Enhanced integrity management
3 PKG004 PSM
4 PKG005 CLI
5 PKG006 Basic object support
6 PKG007 Enhanced object support
7 PKG008 Active database
8 PKG009 SQL/MM support
9 PKG010 OLAP
213 | 214 | --hr 215 | --h2 B.1 Enhanced datetime facilities 216 | --/h2 217 | 218 | The package called "Enhanced datetime facilities" comprises the following features of the SQL 219 | language as specified in the SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. 220 | 221 | --p 222 | --## 223 | --## 224 | --## 225 | --## 226 | --##
Feature F052 Intervals and datetime arithmetic
Feature F411 Time zone specification
Feature F555 Enhanced seconds precision
227 | 228 | --hr 229 | --h2 230 | B.2 Enhanced integrity management 231 | --/h2 232 | The package called "Enhanced integrity management" comprises the following features of the SQL 233 | language as specified in the SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. 234 | 235 | --p 236 | --## 237 | --## 238 | --## 239 | --## 240 | --## 241 | --## 242 | --## 243 | --## 244 | --## 245 | --## 246 | --##
Feature F191 Referential delete actions
Feature F521 Assertions
Feature F701 Referential update actions
Feature F491 Constraint management
Feature F671 Subqueries in CHECK constraints
Feature T201 Comparable data types for referential constraints
Feature T211 Basic trigger capability
Feature T212 Enhanced trigger capability
Feature T191 Referential action RESTRICT
247 | 248 | --hr 249 | --h2 B.3 PSM 250 | --/h2 251 | 252 | The package called "PSM" comprises the following features of the SQL language as specified in the 253 | SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. 254 | 255 | --p 256 | --## 257 | --## 258 | --## 259 | --## 260 | --## 261 | --##
Feature T322 Overloading of SQL-invoked functions and SQL-invoked procedures
Feature P001 Stored modules
Feature P002 Computational completeness
Feature P003 Information Schema views
262 | 263 | --hr 264 | --h2 B.4 CLI 265 | --/h2 266 | The package called "CLI" comprises the following features of the SQL language as specified in the 267 | SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. 268 | 269 | --p 270 | --## 271 | --## 272 | --## 273 | --## 274 | --## 275 | --## 276 | --## 277 | --## 278 | --##
Feature C011 SQL/CLI
Feature C021 Automatic population of Implementation Parameter Descriptor
Feature C041 Information Schema data controlled by current privileges
Feature C051 GetData extensions
Feature C061 GetParamData extensions
Feature C071 Scroll Concurrency
Feature C081 Read-only data source
279 | 280 | --hr 281 | --h2 B.5 Basic object support 282 | --/h2 283 | The package called "basic object support" comprises the following features of the SQL language as 284 | specified in the SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. 285 | 286 | --p 287 | --## 288 | --## 289 | --## 290 | --## 291 | --## 292 | --## 293 | --##
Feature S023 Basic structured types
Feature S041 Basic reference types
Feature S051 Create table of type
Feature S151 Type predicate
Feature T041 Basic LOB data type support
294 | 295 | --hr 296 | --h2 B.6 Enhanced object support 297 | --/h2 298 | The package called "enhanced object support" comprises all of the features of the package called 299 | (Basic object support), plus the following features of the SQL language as specified in the SQL 300 | Feature Taxonomy Annex of the various parts of ISO/IEC 9075. 301 | 302 | --p 303 | --## 304 | --## 305 | --## 306 | --## 307 | --## 308 | --## 309 | --## 310 | --## 311 | --## 312 | --## 313 | --##
Feature S024 Enhanced structured types
Feature S043 Enhanced reference types
Feature S071 SQL-paths in function and type name resolution
Feature S081 Subtables
Feature S111 ONLY in query expressions
Feature S161 Subtype treatment
Feature S211 User-defined cast functions
Feature S231 Structured type locators
Feature S241 Transform functions
314 | 315 | --hr 316 | --h2 B.7 Active database 317 | --/h2 318 | The package called "Active database" comprises the following features of the SQL language as 319 | specified in the SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. 320 | 321 | --p 322 | --## 323 | --## 324 | --##
Feature T211 Basic trigger capability
325 | 326 | --hr 327 | --h2 B.8 OLAP 328 | --/h2 329 | The package called "OLAP" comprises the following features of the SQL language as specified in the 330 | SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. 331 | 332 | --p 333 | --## 334 | --## 335 | --## 336 | --##
Feature T431 Extended grouping capabilities
Feature T611 Elementary OLAP operators
337 | 338 | --hr 339 | --h2 END OF SQL-2003-1 GRAMMAR 340 | --/h2 341 | 342 | --hr 343 | 344 | -------------------------------------------------------------------------------- /doc/ref/savage/sql-2003-1.yacc: -------------------------------------------------------------------------------- 1 | /* 2 | ** Derived from file sql-2003-1.bnf version 1.2 dated 2004/10/27 00:26:59 3 | */ 4 | /* Information taken from the Final Committee Draft (FCD) of ISO/IEC 9075-1:2003. */ 5 | /* The plain text version of this grammar is */ 6 | /* --## sql-2003-1.bnf . */ 7 | /* Identifying the version of SQL in use */ 8 | /* This material (starting with ) is defined in */ 9 | /* section 6.3 "Object Identifier for Database Language SQL" of ISO/IEC */ 10 | /* 9075-1:1999 (SQL Framework). */ 11 | /* It is used to express the capabilities of an implementation. */ 12 | /* The package names are identifiers such as 'PKG001', equivalent to */ 13 | /* 'Enhanced datetime facilities', as defined in the informative Annex B to */ 14 | /* SQL Framework. */ 15 | /* Each such package identifies a number of features that are provided when */ 16 | /* the SQL object identifier claims to provide the package. */ 17 | /* 6.3 Object identifier for Database Language SQL */ 18 | /* Annex B (informative) SQL Packages: */ 19 | /* --## */ 20 | /* --## */ 21 | /* --## */ 22 | /* --## */ 23 | /* --## */ 24 | /* --## */ 25 | /* --## */ 26 | /* --## */ 27 | /* --## */ 28 | /* --## */ 29 | /* --##
1 PKG001 Enhanced datetime facilities
2 PKG002 Enhanced integrity management
3 PKG004 PSM
4 PKG005 CLI
5 PKG006 Basic object support
6 PKG007 Enhanced object support
7 PKG008 Active database
8 PKG009 SQL/MM support
9 PKG010 OLAP
*/ 30 | /* B.1 Enhanced datetime facilities */ 31 | /* The package called "Enhanced datetime facilities" comprises the following features of the SQL */ 32 | /* language as specified in the SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. */ 33 | /* --## */ 34 | /* --## */ 35 | /* --## */ 36 | /* --## */ 37 | /* --##
Feature F052 Intervals and datetime arithmetic
Feature F411 Time zone specification
Feature F555 Enhanced seconds precision
*/ 38 | /* B.2 Enhanced integrity management */ 39 | /* The package called "Enhanced integrity management" comprises the following features of the SQL */ 40 | /* language as specified in the SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. */ 41 | /* --## */ 42 | /* --## */ 43 | /* --## */ 44 | /* --## */ 45 | /* --## */ 46 | /* --## */ 47 | /* --## */ 48 | /* --## */ 49 | /* --## */ 50 | /* --## */ 51 | /* --##
Feature F191 Referential delete actions
Feature F521 Assertions
Feature F701 Referential update actions
Feature F491 Constraint management
Feature F671 Subqueries in CHECK constraints
Feature T201 Comparable data types for referential constraints
Feature T211 Basic trigger capability
Feature T212 Enhanced trigger capability
Feature T191 Referential action RESTRICT
*/ 52 | /* B.3 PSM */ 53 | /* The package called "PSM" comprises the following features of the SQL language as specified in the */ 54 | /* SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. */ 55 | /* --## */ 56 | /* --## */ 57 | /* --## */ 58 | /* --## */ 59 | /* --## */ 60 | /* --##
Feature T322 Overloading of SQL-invoked functions and SQL-invoked procedures
Feature P001 Stored modules
Feature P002 Computational completeness
Feature P003 Information Schema views
*/ 61 | /* B.4 CLI */ 62 | /* The package called "CLI" comprises the following features of the SQL language as specified in the */ 63 | /* SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. */ 64 | /* --## */ 65 | /* --## */ 66 | /* --## */ 67 | /* --## */ 68 | /* --## */ 69 | /* --## */ 70 | /* --## */ 71 | /* --## */ 72 | /* --##
Feature C011 SQL/CLI
Feature C021 Automatic population of Implementation Parameter Descriptor
Feature C041 Information Schema data controlled by current privileges
Feature C051 GetData extensions
Feature C061 GetParamData extensions
Feature C071 Scroll Concurrency
Feature C081 Read-only data source
*/ 73 | /* B.5 Basic object support */ 74 | /* The package called "basic object support" comprises the following features of the SQL language as */ 75 | /* specified in the SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. */ 76 | /* --## */ 77 | /* --## */ 78 | /* --## */ 79 | /* --## */ 80 | /* --## */ 81 | /* --## */ 82 | /* --##
Feature S023 Basic structured types
Feature S041 Basic reference types
Feature S051 Create table of type
Feature S151 Type predicate
Feature T041 Basic LOB data type support
*/ 83 | /* B.6 Enhanced object support */ 84 | /* The package called "enhanced object support" comprises all of the features of the package called */ 85 | /* (Basic object support), plus the following features of the SQL language as specified in the SQL */ 86 | /* Feature Taxonomy Annex of the various parts of ISO/IEC 9075. */ 87 | /* --## */ 88 | /* --## */ 89 | /* --## */ 90 | /* --## */ 91 | /* --## */ 92 | /* --## */ 93 | /* --## */ 94 | /* --## */ 95 | /* --## */ 96 | /* --## */ 97 | /* --##
Feature S024 Enhanced structured types
Feature S043 Enhanced reference types
Feature S071 SQL-paths in function and type name resolution
Feature S081 Subtables
Feature S111 ONLY in query expressions
Feature S161 Subtype treatment
Feature S211 User-defined cast functions
Feature S231 Structured type locators
Feature S241 Transform functions
*/ 98 | /* B.7 Active database */ 99 | /* The package called "Active database" comprises the following features of the SQL language as */ 100 | /* specified in the SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. */ 101 | /* --## */ 102 | /* --## */ 103 | /* --##
Feature T211 Basic trigger capability
*/ 104 | /* B.8 OLAP */ 105 | /* The package called "OLAP" comprises the following features of the SQL language as specified in the */ 106 | /* SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. */ 107 | /* --## */ 108 | /* --## */ 109 | /* --## */ 110 | /* --##
Feature T431 Extended grouping capabilities
Feature T611 Elementary OLAP operators
*/ 111 | /* END OF SQL-2003-1 GRAMMAR */ 112 | %{ 113 | /* 114 | ** BNF Grammar for ISO/IEC 9075-1:2003 SQL/Foundation - Database Language SQL (SQL-2003) 115 | */ 116 | %} 117 | 118 | %token 0 119 | %token 1 120 | %token 2 121 | %token 3 122 | %token 4 123 | %token 5 124 | %token 6 125 | %token 7 126 | %token 9075 127 | %token High 128 | %token IntegrityNo 129 | %token IntegrityYes 130 | %token Intermediate 131 | %token Low 132 | %token Part-nNo 133 | %token directno 134 | %token directyes 135 | %token edition1987 136 | %token edition1989 137 | %token edition1992 138 | %token edition1999 139 | %token edition2003 140 | %token embeddedAda 141 | %token embeddedC 142 | %token embeddedCOBOL 143 | %token embeddedFortran 144 | %token embeddedMUMPS 145 | %token embeddedPLI 146 | %token embeddedPascal 147 | %token invokedAda 148 | %token invokedC 149 | %token invokedCOBOL 150 | %token invokedFortran 151 | %token invokedMUMPS 152 | %token invokedPLI 153 | %token invokedPascal 154 | %token iso 155 | %token moduleAda 156 | %token moduleC 157 | %token moduleCOBOL 158 | %token moduleFortran 159 | %token moduleMUMPS 160 | %token modulePLI 161 | %token modulePascal 162 | %token standard 163 | 164 | /* The following non-terminals were not defined */ 165 | %token embedded_no 166 | %token j_200n 167 | %token left_paren 168 | %token module_no 169 | %token package_pkgino 170 | %token package_pkgiyes 171 | %token part_10 172 | %token part_11 173 | %token part_3 174 | %token part_4 175 | %token part_7 176 | %token part_9 177 | %token right_paren 178 | /* End of undefined non-terminals */ 179 | 180 | /* 181 | %rule arc1 182 | %rule arc2 183 | %rule arc3 184 | %rule bindings 185 | %rule direct 186 | %rule direct_no 187 | %rule direct_yes 188 | %rule embedded 189 | %rule embedded_ada 190 | %rule embedded_c 191 | %rule embedded_cobol 192 | %rule embedded_fortran 193 | %rule embedded_languages 194 | %rule embedded_mumps 195 | %rule embedded_no 196 | %rule embedded_pascal 197 | %rule embedded_pl_i 198 | %rule high 199 | %rule integrity_no 200 | %rule integrity_yes 201 | %rule intermediate 202 | %rule invoked_ada 203 | %rule invoked_c 204 | %rule invoked_cobol 205 | %rule invoked_fortran 206 | %rule invoked_mumps 207 | %rule invoked_pascal 208 | %rule invoked_pl_i 209 | %rule invoked_routine_languages 210 | %rule j_1987 211 | %rule j_1989 212 | %rule j_1989_base 213 | %rule j_1989_package 214 | %rule j_1992 215 | %rule j_1999 216 | %rule j_2003 217 | %rule j_200n 218 | %rule left_paren 219 | %rule level 220 | %rule low 221 | %rule module 222 | %rule module_ada 223 | %rule module_c 224 | %rule module_cobol 225 | %rule module_fortran 226 | %rule module_languages 227 | %rule module_mumps 228 | %rule module_no 229 | %rule module_pascal 230 | %rule module_pl_i 231 | %rule package_pkgi 232 | %rule package_pkgino 233 | %rule package_pkgiyes 234 | %rule packages 235 | %rule part_10 236 | %rule part_11 237 | %rule part_3 238 | %rule part_4 239 | %rule part_7 240 | %rule part_9 241 | %rule part_n 242 | %rule part_n_no 243 | %rule part_n_yes 244 | %rule parts 245 | %rule right_paren 246 | %rule sql_conformance 247 | %rule sql_edition 248 | %rule sql_object_identifier 249 | %rule sql_provenance 250 | %rule sql_variant 251 | */ 252 | 253 | %start bnf_program 254 | 255 | %% 256 | 257 | bnf_program 258 | : bnf_statement 259 | | bnf_program bnf_statement 260 | ; 261 | 262 | bnf_statement 263 | : j_2003 264 | | part_n 265 | | sql_object_identifier 266 | ; 267 | 268 | sql_object_identifier 269 | : sql_provenance sql_variant 270 | ; 271 | 272 | sql_provenance 273 | : arc1 arc2 arc3 274 | ; 275 | 276 | arc1 277 | : iso 278 | | 1 279 | | iso left_paren 1 right_paren 280 | ; 281 | 282 | arc2 283 | : standard 284 | | 0 285 | | standard left_paren 0 right_paren 286 | ; 287 | 288 | arc3 289 | : 9075 290 | ; 291 | 292 | sql_variant 293 | : sql_edition sql_conformance 294 | ; 295 | 296 | sql_edition 297 | : j_1987 298 | | j_1989 299 | | j_1992 300 | | j_1999 301 | | j_200n 302 | ; 303 | 304 | j_1987 305 | : 0 306 | | edition1987 left_paren 0 right_paren 307 | ; 308 | 309 | j_1989 310 | : j_1989_base j_1989_package 311 | ; 312 | 313 | j_1989_base 314 | : 1 315 | | edition1989 left_paren 1 right_paren 316 | ; 317 | 318 | j_1989_package 319 | : integrity_no 320 | | integrity_yes 321 | ; 322 | 323 | integrity_no 324 | : 0 325 | | IntegrityNo left_paren 0 right_paren 326 | ; 327 | 328 | integrity_yes 329 | : 1 330 | | IntegrityYes left_paren 1 right_paren 331 | ; 332 | 333 | j_1992 334 | : 2 335 | | edition1992 left_paren 2 right_paren 336 | ; 337 | 338 | sql_conformance 339 | : level bindings parts packages 340 | ; 341 | 342 | level 343 | : low 344 | | intermediate 345 | | high 346 | ; 347 | 348 | low 349 | : 0 350 | | Low left_paren 0 right_paren 351 | ; 352 | 353 | intermediate 354 | : 1 355 | | Intermediate left_paren 1 right_paren 356 | ; 357 | 358 | high 359 | : 2 360 | | High left_paren 2 right_paren 361 | ; 362 | 363 | j_1999 364 | : 3 365 | | edition1999 left_paren 3 right_paren 366 | ; 367 | 368 | j_2003 369 | : 4 370 | | edition2003 left_paren 4 right_paren 371 | ; 372 | 373 | bindings 374 | : module embedded direct invoked_routine_languages 375 | ; 376 | 377 | lst_nt_001 378 | : module_languages 379 | | lst_nt_001 module_languages 380 | ; 381 | 382 | module 383 | : module_no 384 | | lst_nt_001 385 | ; 386 | 387 | module_languages 388 | : module_ada 389 | | module_c 390 | | module_cobol 391 | | module_fortran 392 | | module_mumps 393 | | module_pascal 394 | | module_pl_i 395 | ; 396 | 397 | module_ada 398 | : 1 399 | | moduleAda left_paren 1 right_paren 400 | ; 401 | 402 | module_c 403 | : 2 404 | | moduleC left_paren 2 right_paren 405 | ; 406 | 407 | module_cobol 408 | : 3 409 | | moduleCOBOL left_paren 3 right_paren 410 | ; 411 | 412 | module_fortran 413 | : 4 414 | | moduleFortran left_paren 4 right_paren 415 | ; 416 | 417 | module_mumps 418 | : 5 419 | | moduleMUMPS left_paren 5 right_paren 420 | ; 421 | 422 | module_pascal 423 | : 6 424 | | modulePascal left_paren 6 right_paren 425 | ; 426 | 427 | module_pl_i 428 | : 7 429 | | modulePLI left_paren 7 right_paren 430 | ; 431 | 432 | lst_nt_002 433 | : embedded_languages 434 | | lst_nt_002 embedded_languages 435 | ; 436 | 437 | embedded 438 | : embedded_no 439 | | lst_nt_002 440 | ; 441 | 442 | embedded_languages 443 | : embedded_ada 444 | | embedded_c 445 | | embedded_cobol 446 | | embedded_fortran 447 | | embedded_mumps 448 | | embedded_pascal 449 | | embedded_pl_i 450 | ; 451 | 452 | embedded_ada 453 | : 1 454 | | embeddedAda left_paren 1 right_paren 455 | ; 456 | 457 | embedded_c 458 | : 2 459 | | embeddedC left_paren 2 right_paren 460 | ; 461 | 462 | embedded_cobol 463 | : 3 464 | | embeddedCOBOL left_paren 3 right_paren 465 | ; 466 | 467 | embedded_fortran 468 | : 4 469 | | embeddedFortran left_paren 4 right_paren 470 | ; 471 | 472 | embedded_mumps 473 | : 5 474 | | embeddedMUMPS left_paren 5 right_paren 475 | ; 476 | 477 | embedded_pascal 478 | : 6 479 | | embeddedPascal left_paren 6 right_paren 480 | ; 481 | 482 | embedded_pl_i 483 | : 7 484 | | embeddedPLI left_paren 7 right_paren 485 | ; 486 | 487 | direct 488 | : direct_yes 489 | | direct_no 490 | ; 491 | 492 | direct_yes 493 | : 1 494 | | directyes left_paren 1 right_paren 495 | ; 496 | 497 | direct_no 498 | : 0 499 | | directno left_paren 0 right_paren 500 | ; 501 | 502 | invoked_routine_languages 503 | : invoked_ada 504 | | invoked_c 505 | | invoked_cobol 506 | | invoked_fortran 507 | | invoked_mumps 508 | | invoked_pascal 509 | | invoked_pl_i 510 | ; 511 | 512 | invoked_ada 513 | : 1 514 | | invokedAda left_paren 1 right_paren 515 | ; 516 | 517 | invoked_c 518 | : 2 519 | | invokedC left_paren 2 right_paren 520 | ; 521 | 522 | invoked_cobol 523 | : 3 524 | | invokedCOBOL left_paren 3 right_paren 525 | ; 526 | 527 | invoked_fortran 528 | : 4 529 | | invokedFortran left_paren 4 right_paren 530 | ; 531 | 532 | invoked_mumps 533 | : 5 534 | | invokedMUMPS left_paren 5 right_paren 535 | ; 536 | 537 | invoked_pascal 538 | : 6 539 | | invokedPascal left_paren 6 right_paren 540 | ; 541 | 542 | invoked_pl_i 543 | : 7 544 | | invokedPLI left_paren 7 right_paren 545 | ; 546 | 547 | parts 548 | : part_3 part_4 part_7 part_9 part_10 part_11 549 | ; 550 | 551 | part_n 552 | : part_n_no 553 | | part_n_yes 554 | ; 555 | 556 | part_n_no 557 | : 0 558 | | Part-nNo left_paren 0 right_paren 559 | ; 560 | 561 | part_n_yes 562 | : /* !! as specified in ISO/IEC 9075-n */ 563 | ; 564 | 565 | lst_nt_003 566 | : package_pkgi 567 | | lst_nt_003 package_pkgi 568 | ; 569 | 570 | packages 571 | : lst_nt_003 572 | ; 573 | 574 | package_pkgi 575 | : package_pkgiyes 576 | | package_pkgino 577 | ; 578 | 579 | 580 | %% 581 | 582 | -------------------------------------------------------------------------------- /doc/ref/savage/sql-2003-2.bnf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqljs/node-sqljs/1537f00c2a94b3136ca60a1fea96547ec43d2498/doc/ref/savage/sql-2003-2.bnf -------------------------------------------------------------------------------- /doc/ref/savage/sql-2003-2.bnf.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqljs/node-sqljs/1537f00c2a94b3136ca60a1fea96547ec43d2498/doc/ref/savage/sql-2003-2.bnf.html -------------------------------------------------------------------------------- /doc/ref/savage/sql-2003-2.yacc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sqljs/node-sqljs/1537f00c2a94b3136ca60a1fea96547ec43d2498/doc/ref/savage/sql-2003-2.yacc -------------------------------------------------------------------------------- /doc/ref/savage/sql-2003-core-features.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | SQL 2003 Feature Taxonomy and Definition for Core SQL 4 | 5 | 6 | 7 |

SQL 2003 (Annex F, Table 34) Feature Taxonomy and Definition for Core SQL

8 | 9 | Derived from Final Committee Draft (FCD) of ISO/IEC 9075-2:2003. 10 |

11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 |
Number Feature ID Feature Name Feature Description
1 B011 Embedded Ada1 - Subclause 20.3, "<embedded SQL Ada program>"
2 B012 Embedded C1 - Subclause 20.4, "<embedded SQL C program>"
3 B013 Embedded COBOL1 - Subclause 20.5, "<embedded SQL COBOL program>"
4 B014 Embedded Fortran1 - Subclause 20.6, "<embedded SQL Fortran program>"
5 B015 Embedded MUMPS1 - Subclause 20.7, "<embedded SQL MUMPS program>"
6 B016 Embedded Pascal1 - Subclause 20.8, "<embedded SQL Pascal program>"
7 B017 Embedded PL/I1 - Subclause 20.9, "<embedded SQL PL/I program>"
1 A conforming SQL-implementation is required (by Clause 8, "Conformance", in ISO/IEC 9075-1) to support at least one embedded language or to support the SQL-client module binding for at least one host language.
8 E011 Numeric data types - Subclause 6.1, "<data type>", <numeric type>, including numeric expressions, numeric literals, numeric comparisons, and numeric assignments
9 E011-01 INTEGER and SMALLINT data types (including all spellings) - Subclause 5.2, "<token> and <separator>": The <reserved word>s INT, INTEGER, and SMALLINT
      - Subclause 5.3, "<literal>": [<sign>] <unsigned integer>
      - Subclause 6.1, "<data type>": The INTEGER and SMALLINT <exact numeric type>s
      - Subclause 13.6, "Data type correspondences": Type correspondences for INTEGER and SMALLINT for all supported languages
10 E011-02 REAL, DOUBLE PRECISON, and FLOAT data types - Subclause 5.2, "<token> and <separator>": The <reserved word>s REAL, DOUBLE, FLOAT, and PRECISION
      - Subclause 5.3, "<literal>": [<sign>] <approximate numeric literal>
      - Subclause 6.1, "<data type>": <approximate numeric type>
      - Subclause 13.6, "Data type correspondences": Type correspondences for REAL, DOUBLE PRECISION, and FLOAT for all supported languages
11 E011-03 DECIMAL and NUMERIC data types - Subclause 5.2, "<token> and <separator>": The <reserved word>s DEC, DECIMAL, and NUMERIC
      - Subclause 5.3, "<literal>": [<sign>] <exact numeric literal>
      - Subclause 6.1, "<data type>": The DECIMAL and NUMERIC <exact numeric type>s
      - Subclause 13.6, "Data type correspondences": Type correspondences for DECIMAL and NUMERIC for all supported languages
12 E011-04 Arithmetic operators - Subclause 6.26, "<numeric value expression>": When the <numeric primary> is a <value expression primary>
13 E011-05 Numeric comparison - Subclause 8.2, "<comparison predicate>": For the numeric data types, without support for <table subquery> and without support for Feature F131, "Grouped operations"
14 E011-06 Implicit casting among the numeric data types - Subclause 8.2, "<comparison predicate>": Values of any of the numeric data types can be compared to each other; such values are compared with respect to their algebraic values
      - Subclause 9.1, "Retrieval assignment", and Subclause 9.2, "Store assignment": Values of one numeric type can be assigned to another numeric type, subject to rounding, truncation, and out of range conditions
15 E021 Character data types - Subclause 6.1, "<data type>": <character string type>, including character expressions, character literals, character comparisons, character assignments, and other operations on character data
16 E021-01 CHARACTER data type (including all its spellings) - Subclause 5.2, "<token> and <separator>": The <reserved word>s CHAR and CHARACTER
      - Subclause 6.1, "<data type>": The CHARACTER <character string type>
      - Subclause 6.28, "<string value expression>": For values of type CHARACTER
      - Subclause 13.6, "Data type correspondences": Type correspondences for CHARACTER for all supported languages
17 E021-02 CHARACTER VARYING data type (including all its spellings) - Subclause 5.2, "<token> and <separator>": The <reserved word>s VARCHAR and VARYING
      - Subclause 6.1, "<data type>": The CHARACTER VARYING <character string type>
      - Subclause 6.28, "<string value expression>": For values of type CHARACTER VARYING
      - Subclause 13.6, "Data type correspondences": Type correspondences for CHARACTER VARYING for all supported languages
18 E021-03 Character literals - Subclause 5.3, "<literal>": <quote> [ <character representation>... ] <quote>
19 E021-04 CHARACTER_LENGTH function - Subclause 6.27, "<numeric value function>": The <char length expression>
20 E021-05 OCTET_LENGTH function - Subclause 6.27, "<numeric value function>": The <octet length expression>
21 E021-06 SUBSTRING function - Subclause 6.29, "<string value function>": The <character substring function>
22 E021-07 Character concatenation - Subclause 6.28, "<string value expression>": The <concatenation> expression
23 E021-08 UPPER and LOWER functions - Subclause 6.29, "<string value function>": The <fold> function
24 E021-09 TRIM function - Subclause 6.29, "<string value function>": The <trim function>
25 E021-10 Implicit casting among the character data types - Subclause 8.2, "<comparison predicate>": Values of either the CHARACTER or CHARACTER VARYING data types can be compared to each other
      - Subclause 9.1, "Retrieval assignment", and Subclause 9.2, "Store assignment": Values of either the CHARACTER or CHARACTER VARYING data type can be assigned to the other type, subject to truncation conditions
26 E021-11 POSITION function - Subclause 6.27, "<numeric value function>": The <position expression>
27 E021-12 Character comparison - Subclause 8.2, "<comparison predicate>": For the CHARACTER and CHARACTER VARYING data types, without support for <table subquery> and without support for Feature F131, "Grouped operations"
28 E031 Identifiers - Subclause 5.2, "<token> and <separator>": <regular identifier> and <delimited identifier>
29 E031-01 Delimited identifiers - Subclause 5.2, "<token> and <separator>": <delimited identifier>
30 E031-02 Lower case identifiers - Subclause 5.2, "<token> and <separator>": An alphabetic character in a <regular identifier> can be either lower case or upper case (meaning that non-delimited identifiers need not comprise only upper case letters)
31 E031-03 Trailing underscore - Subclause 5.2, "<token> and <separator>": The list <identifier part> in a <regular identifier> can be an <underscore>
32 E051 Basic query specification - Subclause 7.12, "<query specification>": When <table reference> is a <table or query name> that is a <table name>, without the support of Feature F131, "Grouped operations"
33 E051-01 SELECT DISTINCT - Subclause 7.12, "<query specification>": With a <set quantifier> of DISTINCT, but without subfeatures E051-02 through E051-09
34 E051-02 GROUP BY clause - Subclause 7.4, "<table expression>": <group by clause>, but without subfeatures E051-03 through E051-09
      - Subclause 7.9, "<group by clause>": With the restrictions that the <group by clause> must contain all non-aggregated columns in the <select list> and that any column in the <group by clause> must also appear in the <select list>
35 E051-04 GROUP BY can contain columns not in <select list> - Subclause 7.9, "<group by clause>": Without the restriction that any column in the <group by clause> must also appear in the <select list>
36 E051-05 Select list items can be renamed - Subclause 7.12, "<query specification>": <as clause>
37 E051-06 HAVING clause - Subclause 7.4, "<table expression>": <having clause>
      - Subclause 7.10, "<having clause>"
38 E051-07 Qualified * in select list - Subclause 7.12, "<query specification>": <qualified asterisk>
39 E051-08 Correlation names in the FROM clause - Subclause 7.6, "<table reference>": [ AS ] <correlation name>
40 E051-09 Rename columns in the FROM clause - Subclause 7.6, "<table reference>": [ AS ] <correlation name> [ <left paren> <derived column list> <right paren> ]
41 E061 Basic predicates and search conditions - Subclause 8.19, "<search condition>", and Subclause 8.1, "<predicate>"
42 E061-01 Comparison predicate - Subclause 8.2, "<comparison predicate>": For supported data types, without support for <table subquery>
43 E061-02 BETWEEN predicate - Subclause 8.3, "<between predicate>"
44 E061-03 IN predicate with list of values - Subclause 8.4, "<in predicate>": Without support for <table subquery>
45 E061-04 LIKE predicate - Subclause 8.5, "<like predicate>": Without [ ESCAPE <escape character> ]
46 E061-05 LIKE predicate: ESCAPE clause - Subclause 8.5, "<like predicate>": With [ ESCAPE <escape character> ]
47 E061-06 NULL predicate - Subclause 8.7, "<null predicate>": Without Feature F481, "Expanded NULL predicate"
48 E061-07 Quantified comparison predicate - Subclause 8.8, "<quantified comparison predicate>": Without support for <table subquery>
49 E061-08 EXISTS predicate - Subclause 8.9, "<exists predicate>"
50 E061-09 Subqueries in comparison predicate - Subclause 8.2, "<comparison predicate>": For supported data types, with support for <table subquery>
51 E061-11 Subqueries in IN predicate - Subclause 8.4, "<in predicate>": With support for <table subquery>
52 E061-12 Subqueries in quantified comparison predicate - Subclause 8.8, "<quantified comparison predicate>": With support for <table subquery>
53 E061-13 Correlated subqueries - Subclause 8.1, "<predicate>": When a <correlation name> can be used in a <table subquery> as a correlated reference to a column in the outer query
54 E061-14 Search condition - Subclause 8.19, "<search condition>"
55 E071 Basic query expressions - Subclause 7.13, "<query expression>"
56 E071-01 UNION DISTINCT table operator - Subclause 7.13, "<query expression>": With support for UNION [ DISTINCT ]
57 E071-02 UNION ALL table operator - Subclause 7.13, "<query expression>": With support for UNION ALL
58 E071-03 EXCEPT DISTINCT table operator - Subclause 7.13, "<query expression>": With support for EXCEPT [ DISTINCT ]
59 E071-05 Columns combined via table operators need not have exactly the same data type. - Subclause 7.13, "<query expression>": Columns combined via UNION and EXCEPT need not have exactly the same data type
60 E071-06 Table operators in subqueries - Subclause 7.13, "<query expression>": <table subquery>s can specify UNION and EXCEPT
61 E081 Basic Privileges - Subclause 12.3, "<privileges>"
62 E081-01 SELECT privilege - Subclause 12.3, "<privileges>": With <action> of SELECT
63 E081-02 DELETE privilege - Subclause 12.3, "<privileges>": With <action> of DELETE
64 E081-03 INSERT privilege at the table level - Subclause 12.3, "<privileges>": With <action> of INSERT without <privilege column list>
65 E081-04 UPDATE privilege at the table level - Subclause 12.3, "<privileges>": With <action> of UPDATE without <privilege column list>
66 E081-05 UPDATE privilege at the column level - Subclause 12.3, "<privileges>": With <action> of UPDATE <left paren> <privilege column list> <right paren>
67 E081-06 REFERENCES privilege at the table level - Subclause 12.3, "<privileges>": with <action> of REFERENCES without <privilege column list>
68 E081-07 REFERENCES privilege at the column level - Subclause 12.3, "<privileges>": With <action> of REFERENCES <left paren> <privilege column list> <right paren>
69 E081-08 WITH GRANT OPTION - Subclause 12.2, "<grant privilege statement>": WITH GRANT OPTION
70 E091 Set functions - Subclause 6.9, "<set function specification>"
71 E091-01 AVG - Subclause 6.9, "<set function specification>": With <computational operation> of AVG
72 E091-02 COUNT - Subclause 6.9, "<set function specification>": With <computational operation> of COUNT
73 E091-03 MAX - Subclause 6.9, "<set function specification>": With <computational operation> of MAX
74 E091-04 MIN - Subclause 6.9, "<set function specification>": With <computational operation> of MIN
75 E091-05 SUM - Subclause 6.9, "<set function specification>": With <computational operation> of SUM
76 E091-06 ALL quantifier - Subclause 6.9, "<set function specification>": With <set quantifier> of ALL
77 E091-07 DISTINCT quantifier - Subclause 6.9, "<set function specification>": With <set quantifier> of DISTINCT
78 E101 Basic data manipulation - Clause 14, "Data manipulation": <insert statement>, <delete statement: searched>, and <update statement: searched>
79 E101-01 INSERT statement - Subclause 14.8, "<insert statement>": When a <contextually typed table value constructor> can consist of no more than a single <contextually typed row value expression>
80 E101-03 Searched UPDATE statement - Subclause 14.11, "<update statement: searched>": But without support either of Feature E153, "Updatable tables with subqueries", or Feature F221, "Explicit defaults"
81 E101-04 Searched DELETE statement - Subclause 14.7, "<delete statement: searched>"
82 E111 Single row SELECT statement - Subclause 14.5, "<select statement: single row>": Without support of Feature F131, "Grouped operations"
83 E121 Basic cursor support - Clause 14, "Data manipulation": <declare cursor>, <open statement>, <fetch statement>, <close statement>, <delete statement: positioned>, and <update statement: positioned>
84 E121-01 DECLARE CURSOR - Subclause 14.1, "<declare cursor>": When each <value expression> in the <sort key> must be a <column reference> and that <column reference> must also be in the <select list>, and <cursor holdability> is not specified
85 E121-02 ORDER BY columns need not be in select list - Subclause 14.1, "<declare cursor>": Extend subfeature E121-01 so that <column reference> need not also be in the <select list>
86 E121-03 Value expressions in ORDER BY clause - Subclause 14.1, "<declare cursor>": Extend subfeature E121-01 so that the <value expression> in the <sort key> need not be a <column reference>
87 E121-04 OPEN statement - Subclause 14.2, "<open statement>"
88 E121-06 Positioned UPDATE statement - Subclause 14.10, "<update statement: positioned>": Without support of either Feature E153, "Updateable tables with subqueries" or Feature F221, "Explicit defaults"
89 E121-07 Positioned DELETE statement - Subclause 14.6, "<delete statement: positioned>"
90 E121-08 CLOSE statement - Subclause 14.4, "<close statement>"
91 E121-10 FETCH statement: implicit NEXT - Subclause 14.3, "<fetch statement>"
92 E121-17 WITH HOLD cursors - Subclause 14.1, "<declare cursor>": Where the <value expression> in the <sort key> need not be a <column reference> and need not be in the <select list>, and <cursor holdability> may be specified
93 E131 Null value support (nulls in lieu of values) - Subclause 4.14, "Columns, fields, and attributes": Nullability characteristic
      - Subclause 6.5, "<contextually typed value specification>": <null specification>
94 E141 Basic integrity constraints - Subclause 11.6, "<table constraint definition>": As specified by the subfeatures of this feature in this table
95 E141-01 NOT NULL constraints - Subclause 11.4, "<column definition>": With <column constraint> of NOT NULL
96 E141-02 UNIQUE constraints of NOT NULL columns - Subclause 11.4, "<column definition>": With <unique specification> of UNIQUE for columns specified as NOT NULL
      - Subclause 11.7, "<unique constraint definition>": With <unique specification> of UNIQUE
97 E141-03 PRIMARY KEY constraints - Subclause 11.4, "<column definition>": With <unique specification> of PRIMARY KEY for columns specified as NOT NULL
      - Subclause 11.7, "<unique constraint definition>": With <unique specification> of PRIMARY KEY
98 E141-04 Basic FOREIGN KEY constraint with the NO ACTION default for both referential delete action and referential update action. - Subclause 11.4, "<column definition>": With <column constraint> of <references specification>
      - Subclause 11.8, "<referential constraint definition>": Where the columns in the <column name list>, if specified, must be in the same order as the names in the <unique column list> of the applicable <unique constraint definition> and the <data type>s of the matching columns must be the same
99 E141-06 CHECK constraints - Subclause 11.4, "<column definition>": With <column constraint> of <check constraint definition>
      - Subclause 11.9, "<check constraint definition>"
100 E141-07 Column defaults - Subclause 11.4, "<column definition>": With <default clause>
101 E141-08 NOT NULL inferred on PRIMARY KEY - Subclause 11.4, "<column definition>", and Subclause 11.7, "<unique constraint definition>": Remove the restriction in subfeatures E141-02 and E141-03 that NOT NULL be specified along with every PRIMARY KEY and UNIQUE constraint
      - Subclause 11.4, "<column definition>": NOT NULL is implicit on PRIMARY KEY constraints
102 E141-10 Names in a foreign key can be specified in any order - Subclause 11.4, "<column definition>", and Subclause 11.8, "<referential constraint definition>": Extend subfeature E141-04 so that the columns in the <column name list>, if specified, need not be in the same order as the names in the <unique column list> of the applicable <unique constraint definition>
103 E141-11 Foreign key"s data types need not be the same as the primary key"s - Subclause 11.4, "<column definition>", and Subclause 11.8, "<referential constraint definition>": Extend subfeature E141-04 so that the data types of matching columns need not be the same.
104 E151 Transaction support - Clause 16, "Transaction management": <commit statement> and <rollback statement>
105 E151-01 COMMIT statement - Subclause 16.6, "<commit statement>"
106 E151-02 ROLLBACK statement - Subclause 16.7, "<rollback statement>"
107 E152 Basic SET TRANSACTION statement - Subclause 16.2, "<set transaction statement>"
108 E152-01 SET TRANSACTION statement: ISOLATION LEVEL SERIALIZABLE clause - Subclause 16.2, "<set transaction statement>": With <transaction mode> of ISOLATION LEVEL SERIALIZABLE clause
109 E152-02 SET TRANSACTION statement: READ ONLY and READ WRITE clauses - Subclause 16.2, "<set transaction statement>": with <transaction access mode> of READ ONLY or READ WRITE
110 E153 Updatable queries with subqueries - Subclause 7.13, "<query expression>": A <query expression> is updatable even though its <where clause> contains a <subquery>
111 E161 SQL comments using leading double minus - Subclause 5.2, "<token> and <separator>": <simple comment>
112 E171 SQLSTATE support - Subclause 23.1, "SQLSTATE"
113 E182 Module language - Clause 13, "SQL-client modules"
(NOTE 450 - An SQL-implementation is required to supply at least one binding to a standard host language using either module language, embedded SQL, or both.)
114 F031 Basic schema manipulation - Clause 11, "Schema definition and manipulation": Selected facilities as indicated by the subfeatures of this Feature
115 F031-01 CREATE TABLE statement to create persistent base tables - Subclause 11.3, "<table definition>": Not in the context of a <schema definition>
116 F031-02 CREATE VIEW statement - Subclause 11.22, "<view definition>": Not in the context of a <schema definition>, and without support of Feature F081, "UNION and EXCEPT in views"
117 F031-03 GRANT statement - Subclause 12.1, "<grant statement>": Not in the context of a <schema definition>
118 F031-04 ALTER TABLE statement: ADD COLUMN clause - Subclause 11.10, "<alter table statement>": The <add column definition> clause
      - Subclause 11.11, "<add column definition>"
119 F031-13 DROP TABLE statement: RESTRICT clause - Subclause 11.21, "<drop table statement>": With a <drop behavior> of RESTRICT
120 F031-16 DROP VIEW statement: RESTRICT clause - Subclause 11.23, "<drop view statement>": With a <drop behavior> of RESTRICT
121 F031-19 REVOKE statement: RESTRICT clause - Subclause 12.7, "<revoke statement>": With a <drop behavior> of RESTRICT, only where the use of this statement can be restricted to the owner of the table being dropped
122 F041 Basic joined table - Subclause 7.7, "<joined table>"
123 F041-01 Inner join (but not necessarily the INNER keyword) - Subclause 7.6, "<table reference>": The <joined table> clause, but without support for subfeatures F041-02 through F041-08
124 F041-02 INNER keyword - Subclause 7.7, "<joined table>": <join type> of INNER
125 F041-03 LEFT OUTER JOIN - Subclause 7.7, "<joined table>": <outer join type> of LEFT
126 F041-04 RIGHT OUTER JOIN - Subclause 7.7, "<joined table>": <outer join type> of RIGHT
127 F041-05 Outer joins can be nested - Subclause 7.7, "<joined table>": Subfeature F041-1 extended so that a <table reference> within the <joined table> can itself be a <joined table>
128 F041-07 The inner table in a left or right outer join can also be used in an inner join - Subclause 7.7, "<joined table>": Subfeature F041-1 extended so that a <table name> within a nested <joined table> can be the same as a <table name> in an outer <joined table>
129 F041-08 All comparison operators are supported (rather than just =) - Subclause 7.7, "<joined table>": Subfeature F041-1 extended so that the <join condition> is not limited to a <comparison predicate> with a <comp op> of <equals operator>
130 F051 Basic date and time - Subclause 6.1, "<data type>": <datetime type> including datetime literals, datetime comparisons, and datetime conversions
131 F051-01 DATE data type (including support of DATE literal) - Subclause 5.3, "<literal>": The <date literal> form of <datetime literal>
      - Subclause 6.1, "<data type>": The DATE <datetime type>
      - Subclause 6.30, "<datetime value expression>": For values of type DATE 132 F051-02 TIME data type (including support of TIME literal) with fractional seconds precision of at least 0.
      - Subclause 5.3, "<literal>": The <time literal> form of <datetime literal>, where the value of <unquoted time string> is simply <time value> that does not include the optional <time zone interval>
      - Subclause 6.1, "<data type>": The TIME <datetime type> without the <with or without timezone> clause
      - Subclause 6.30, "<datetime value expression>": For values of type TIME 133 F051-03 TIMESTAMP data type (including support of TIMESTAMP literal) with fractional seconds precision of at least 0 and 6.
      - Subclause 5.3, "<literal>": The <timestamp literal> form of <datetime literal>, where the value of <unquoted timestamp string> is simply <time value> that does not include the optional <time zone interval>
      - Subclause 6.1, "<data type>": The TIMESTAMP <datetime type> without the <with or without timezone> clause
      - Subclause 6.30, "<datetime value expression>": For values of type TIMESTAMP
134 F051-04 Comparison predicate on DATE, TIME, and TIMESTAMP data types - Subclause 8.2, "<comparison predicate>": For comparison between values of the following types: DATE and DATE, TIME and TIME, TIMESTAMP and TIMESTAMP, DATE and TIMESTAMP, and TIME and TIMESTAMP
135 F051-05 Explicit CAST between datetime types and character types - Subclause 6.12, "<cast specification>": If support for Feature F201, "CAST function" is available, then CASTing between the following types: from character string to DATE, TIME, and TIMESTAMP; from DATE to DATE, TIMESTAMP, and character string; from TIME to TIME, TIMESTAMP, and character string; from TIMESTAMP to DATE, TIME, TIMESTAMP, and character string
136 F051-06 CURRENT_DATE - Subclause 6.31, "<datetime value function>": The <current date value function>
      - Subclause 6.30, "<datetime value expression>": When the value is a <current date value function>
137 F051-07 LOCALTIME - Subclause 6.31, "<datetime value function>": The <current local time value function>
      - Subclause 6.30, "<datetime value expression>": When the value is a <current local time value function>
      - Subclause 11.5, "<default clause>": LOCALTIME option of <datetime value function>
138 F051-08 LOCALTIMESTAMP - Subclause 6.31, "<datetime value function>": The <current local timestamp value function>
      - Subclause 6.30, "<datetime value expression>": When the value is a <current local timestamp value function>
      - Subclause 11.5, "<default clause>": LOCALTIMESTAMP option of <datetime value function>
139 F081 UNION and EXCEPT in views - Subclause 11.22, "<view definition>": A <query expression> in a <view definition> may specify UNION DISTINCT, UNION ALL, EXCEPT, and/or EXCEPT ALL
140 F131 Grouped operations - A grouped view is a view whose <query expression> contains a <group by clause>
141 F131-01 WHERE, GROUP BY, and HAVING clauses supported in queries with grouped views - Subclause 7.4, "<table expression>": Even though a table in the <from clause> is a grouped view, the <where clause>, <group by clause>, and <having clause> may be specified
142 F131-02 Multiple tables supported in queries with grouped views - Subclause 7.5, "<from clause>": Even though a table in the <from clause> is a grouped view, the <from clause> may specify more than one <table reference>
143 F131-03 Set functions supported in queries with grouped views - Subclause 7.12, "<query specification>": Even though a table in the <from clause> is a grouped view, the <select list> may specify a <set function specification>
144 F131-04 Subqueries with GROUP BY and HAVING clauses and grouped views - Subclause 7.15, "<subquery>": A <subquery> in a <comparison predicate> is allowed to contain a <group by clause> and/or a <having clause and/or it may identify a grouped view
145 F131-05 Single row SELECT with GROUP BY and HAVING clauses and grouped views - Subclause 14.5, "<select statement: single row>": The table in a <from clause> can be a grouped view
      - Subclause 14.5, "<select statement: single row>": The <table expression> may specify a <group by clause and/or a <having clause
146 F181 Multiple module support
(NOTE 451 - The ability to associate multiple host compilation units with a single SQL-session at one time.)
- Subclause 13.1, "<SQL-client module definition>": An SQL-agent can be associated with more than one <SQL-client module definition>
(NOTE 452 - With this feature, it is possible to compile <SQL-client module definition>s or <embedded SQL host program>s separately and rely on the SQL-implementation to "link" the together properly at execution time. To ensure portability, applications should adhere to the following limitations:
  • Avoid linking modules having cursors with the same <cursor name>.
  • Avoid linking modules that prepare statements using the same <SQL statement name>.
  • Avoid linking modules that allocate descriptors with the same <descriptor name>.
  • Assume that the scope of an <embedded exception declaration> is a single compilation unit.
  • Assume that an <embedded variable name> can be referenced only in the same compilation unit in which it is declared.)
  • 147 F201 CAST function
    (NOTE 453 - This means the support of CAST, where relevant, among all supported data types.)
    - Subclause 6.12, "<cast specification>": For all supported data types
          - Subclause 6.25, "<value expression>": <cast specification>
    148 F221 Explicit defaults - Subclause 6.5, "<contextually typed value specification>": <default specification>
    (NOTE 454 - Including its use in UPDATE and INSERT statements.)
    149 F261 CASE expression - Subclause 6.25, "<value expression>": <case expression>
    150 F261-01 Simple CASE - Subclause 6.11, "<case expression>": The <simple case> variation
    151 F261-02 Searched CASE - Subclause 6.11, "<case expression>": The <searched case variation>
    152 F261-03 NULLIF - Subclause 6.11, "<case expression>": The NULLIF <case abbreviation
    153 F261-04 COALESCE - Subclause 6.11, "<case expression>": The COALESCE <case abbreviation
    154 F311 Schema definition statement - Subclause 11.1, "<schema definition>"
    155 F311-01 CREATE SCHEMA - Subclause 11.1, "<schema definition>": Support for circular references in that <referential constraint definition>s in two different <table definition>s may reference columns in the other table
    156 F311-02 CREATE TABLE for persistent base tables - Subclause 11.1, "<schema definition>": A <schema element> that is a <table definition>
          - Subclause 11.3, "<table definition>": In the context of a <schema definition>
    157 F311-03 CREATE VIEW - Subclause 11.1, "<schema definition>": A <schema element> that is a <view definition>
          - Subclause 11.22, "<view definition>": In the context of a <schema definition> without the WITH CHECK OPTION clause and without support of Feature F081, "UNION and EXCEPT in views"
    158 F311-04 CREATE VIEW: WITH CHECK OPTION - Subclause 11.22, "<view definition>": The WITH CHECK OPTION clause, in the context of a <schema definition>, but without support of Feature F081, "UNION and EXCEPT in views"
    159 F311-05 GRANT statement - Subclause 11.1, "<schema definition>": A <schema element> that is a <grant statement>
          - Subclause 12.1, "<grant statement>": In the context of a <schema definition>
    160 F471 Scalar subquery values - Subclause 6.25, "<value expression>": A <value expression primary> can be a <scalar subquery>
    161 F481 Expanded NULL predicate - Subclause 8.7, "<null predicate>": The <row value expression> can be something other than a <column reference>
    162 F812 Basic flagging - Part 1, Subclause 8.1.4, "SQL flagger": With "level of flagging" specified to be Core SQL Flagging and "extent of checking" specified to be Syntax Only
    (NOTE 455 - This form of flagging identifies vendor extensions and other non-standard SQL by checking syntax only without requiring access to the catalog information.)
    163 S011 Distinct data types - Subclause 11.41, "<user-defined type definition>": When <representation> is <predefined type>
    164 T321 Basic SQL-invoked routines - Subclause 11.50, "<SQL-invoked routine>"
          - If Feature T041, "Basic LOB data type support", is supported, then the <locator indication> clause must also be supported
    (NOTE 456 - "Routine" is the collective term for functions, methods, and procedures. This feature requires a conforming SQLimplementation to support both user-defined functions and user-defined procedures. An SQL-implementation that conforms to Core SQL must support at least one language for writing routines; that language may be SQL. If the language is SQL, then the basic specification capability in Core SQL is the ability to specify a one-statement routine. Support for overloaded functions and procedures is not part of Core SQL.)
    165 T321-01 User-defined functions with no overloading - Subclause 11.50, "<SQL-invoked routine>": With <function specification>
    166 T321-02 User-defined stored procedures with no overloading - Subclause 11.50, "<SQL-invoked routine>": With <SQL-invoked procedure>
    167 T321-03 Function invocation - Subclause 6.4, "<value specification> and <target specification>": With a <value expression primary> that is a <routine invocation>
          - Subclause 10.4, "<routine invocation>": For user-defined functions
    168 T321-04 CALL statement - Subclause 10.4, "<routine invocation>": Used by <call statement>s
          - Subclause 15.1, "<call statement>"
    169 T321-05 RETURN statement - Subclause 15.2, "<return statement>", if the SQL-implementation supports SQL routines
    248 | 249 |


    250 |

    251 | 252 |

    253 | @(#)$Id: sql-2003-core-features.html,v 1.1 2004/10/28 16:18:07 jleffler Exp $ 254 |

    255 | 256 | 257 | 258 | -------------------------------------------------------------------------------- /doc/ref/savage/sql-2003-noncore-features.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | SQL 2003 Feature Taxonomy for Features Outside Core SQL 5 | 6 | 7 | 8 |

    9 | SQL 2003 (Annex F, Table 35) Feature Taxonomy for Features Outside Core SQL 10 |

    11 | 12 | Derived from Final Committee Draft (FCD) of ISO/IEC 9075-2:2003. 13 |

    14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 |
    Number Feature ID Feature Name
    1 B021 Direct SQL
    2 B031 Basic dynamic SQL
    3 B032 Extended dynamic SQL
    4 B032-01 <describe input> statement
    5 B033 Untyped SQL-invoked function arguments
    6 B034 Dynamic specification of cursor attributes
    7 B041 Extensions to embedded SQL exception declarations
    8 B051 Enhanced execution rights
    9 F032 CASCADE drop behavior
    10 F033 ALTER TABLE statement: DROP COLUMN clause
    11 F034 Extended REVOKE statement
    12 F034-01 REVOKE statement performed by other than the owner of a schema object
    13 F034-02 REVOKE statement: GRANT OPTION FOR clause
    14 F034-03 REVOKE statement to revoke a privilege that the grantee has WITH GRANT OPTION
    15 F052 Intervals and datetime arithmetic
    16 F053 OVERLAPS predicate
    17 F111 Isolation levels other than SERIALIZABLE
    18 F111-01 READ UNCOMMITTED isolation level
    19 F111-02 READ COMMITTED isolation level
    20 F111-03 REPEATABLE READ isolation level
    21 F121 Basic diagnostics management
    22 F121-01 GET DIAGNOSTICS statement
    23 F121-02 SET TRANSACTION statement: DIAGNOSTICS SIZE clause
    24 F171 Multiple schemas per user
    25 F191 Referential delete actions
    26 F222 INSERT statement: DEFAULT VALUES clause
    27 F231 Privilege tables
    28 F231-01 TABLE_PRIVILEGES view
    29 F231-02 COLUMN_PRIVILEGES view
    30 F231-03 USAGE_PRIVILEGES view
    31 F251 Domain support
    32 F262 Extended CASE expression
    33 F271 Compound character literals
    34 F281 LIKE enhancements
    35 F291 UNIQUE predicate
    36 F301 CORRESPONDING in query expressions
    37 F302 INTERSECT table operator
    38 F302-01 INTERSECT DISTINCT table operator
    39 F302-02 INTERSECT ALL table operator
    40 F304 EXCEPT ALL table operator
    41 F312 MERGE statement
    42 F321 User authorization
    43 F341 Usage tables
    44 F361 Subprogram support
    45 F381 Extended schema manipulation
    46 F381-01 ALTER TABLE statement: ALTER COLUMN clause
    47 F381-02 ALTER TABLE statement: ADD CONSTRAINT clause
    48 F381-03 ALTER TABLE statement: DROP CONSTRAINT clause
    49 F391 Long identifiers
    50 F392 Unicode escapes in identifiers
    51 F393 Unicode escapes in literals
    52 F401 Extended joined table
    53 F401-01 NATURAL JOIN
    54 F401-02 FULL OUTER JOIN
    55 F401-03 UNION JOIN
    56 F401-04 CROSS JOIN
    57 F402 Named column joins for LOBs, arrays, and multisets
    58 F411 Time zone specification
    59 F421 National character
    60 F431 Read-only scrollable cursors
    61 F431-01 FETCH with explicit NEXT
    62 F431-02 FETCH FIRST
    63 F431-03 FETCH LAST
    64 F431-04 FETCH PRIOR
    65 F431-05 FETCH ABSOLUTE
    66 F431-06 FETCH RELATIVE
    67 F441 Extended set function support
    68 F442 Mixed column references in set functions
    69 F451 Character set definition
    70 F461 Named character sets
    71 F491 Constraint management
    72 F502 Enhanced documentation tables
    73 F502-01 SQL_SIZING_PROFILES view
    74 F502-02 SQL_IMPLEMENTATION_INFO view
    75 F502-03 SQL_PACKAGES view
    76 F521 Assertions
    77 F531 Temporary tables
    78 F555 Enhanced seconds precision
    79 F561 Full value expressions
    80 F571 Truth value tests
    81 F591 Derived tables
    82 F611 Indicator data types
    83 F641 Row and table constructors
    84 F651 Catalog name qualifiers
    85 F661 Simple tables
    86 F671 Subqueries in CHECK
    87 F672 Retrospective check constraints
    88 F691 Collation and translation
    89 F692 Enhanced collation support
    90 F693 SQL-session and client module collations
    91 F701 Referential update actions
    92 F711 ALTER domain
    93 F721 Deferrable constraints
    94 F731 INSERT column privileges
    95 F741 Referential MATCH types
    96 F751 View CHECK enhancements
    97 F761 Session management
    98 F771 Connection management
    99 F781 Self-referencing operations
    100 F791 Insensitive cursors
    101 F801 Full set function
    102 F813 Extended flagging - Part 1, Subclause 8.1.4, "SQL flagger": With 'level of flagging' specified to be Core SQL Flagging and 'extent of checking' specified to be Catalog Lookup
    103 F821 Local table references
    104 F831 Full cursor update
    105 F831-01 Updateable scrollable cursors
    106 F831-02 Updateable ordered cursors
    107 S023 Basic structured types
    108 S024 Enhanced structured types
    109 S025 Final structured types
    110 S026 Self-referencing structured types
    111 S027 Create method by specific method name
    112 S028 Permutable UDT options list
    113 S041 Basic reference types
    114 S043 Enhanced reference types
    115 S051 Create table of type
    116 S071 SQL paths in function and type name resolution
    117 S081 Subtables
    118 S091 Basic array support
    119 S091-01 Arrays of built-in data types
    120 S091-02 Arrays of distinct types
    121 S091-03 Array expressions
    122 S092 Arrays of user-defined types
    123 S094 Arrays of reference types
    124 S095 Array constructors by query
    125 S096 Optional array bounds
    126 S097 Array element assignment
    127 S111 ONLY in query expressions
    128 S151 Type predicate
    129 S161 Subtype treatment
    130 S162 Subtype treatment for references
    131 S201 SQL-invoked routines on arrays
    132 S201-01 Array parameters
    133 S201-02 Array as result type of functions
    134 S202 SQL-invoked routines on multisets
    135 S211 User-defined cast functions
    136 S231 Structured type locators
    137 S232 Array locators
    138 S233 Multiset locators
    139 S241 Transform functions
    140 S242 Alter transform statement
    141 S251 User-defined orderings
    142 S261 Specific type method
    143 S271 Basic multiset support
    144 S272 Multisets of user-defined types
    145 S274 Multisets of reference types
    146 S275 Advanced multiset support
    147 S281 Nested collection types
    148 T011 Timestamp in Information Schema
    149 T031 BOOLEAN data type
    150 T041 Basic LOB data type support
    151 T041-01 BLOB data type
        - Subclause 5.2, "<token> and <separator>": The <reserved word>s BINARY, BLOB, LARGE, and OBJECT
        - Subclause 5.3, "<literal>": <binary string literal>
        - Subclause 6.1, "<data type>": The BINARY LARGE OBJECT data type
        - Subclause 6.28, "<string value expression>": For values of type BINARY LARGE OBJECT
        - Subclause 13.6, "Data type correspondences": Type correspondences for BINARY LARGE OBJECT for all supported languages
    152 T041-02 CLOB data type
        - Subclause 5.2, "<token> and <separator>": The <reserved word>s CHARACTER, CLOB, LARGE, and OBJECT
        - Subclause 6.1, "<data type>": The CHARACTER LARGE OBJECT data type
        - Subclause 6.28, "<string value expression>": For values of type CHARACTER LARGE OBJECT
        - Subclause 13.6, "Data type correspondences": Type correspondences for CHARACTER LARGE OBJECT for all supported languages
        - The automatic casting among the character types supported by subfeature E021-11 is extended to support the CHARACTER LARGE OBJECT type
    153 T041-03 POSITION, LENGTH, LOWER, TRIM, UPPER, and SUBSTRING functions for LOB data types
        - Subclause 6.27, "<numeric value function>": The <position expression> for expressions of type BINARY LARGE OBJECT and CHARACTER LARGE OBJECT
        - Subclause 6.27, "<numeric value function>": The <char length function> for expressions of type CHARACTER LARGE OBJECT
        - Subclause 6.27, "<numeric value function>": The <octet length function> for expressions of type BINARY LARGE OBJECT and CHARACTER LARGE OBJECT
        - Subclause 6.29, "<string value function>": The <fold> function for expressions of type CHARACTER LARGE OBJECT
        - Subclause 6.29, "<string value function>": The <trim function> for expressions of type CHARACTER LARGE OBJECT
        - Subclause 6.29, "<string value function>": The <blob trim function>
        - Subclause 6.29, "<string value function>": The <character substring function> for expressions of type CHARACTER LARGE OBJECT
        - Subclause 6.29, "<string value function>": The <blob substring function>
    154 T041-04 Concatenation of LOB data types
        - Subclause 6.28, "<string value expression>": The <concatenation> expression for expressions of type CHARACTER LARGE OBJECT
        - Subclause 6.28, "<string value expression>": The <blob concatenation> expression
    155 T041-05 LOB locator: non-holdable
        - Subclause 13.3, "<externally-invoked procedure>": <locator indication>
        - Subclause 14.14, "<free locator statement>"
    156 T042 Extended LOB data type support
    157 T051 Row types
    158 T052 MAX and MIN for row types
    159 T053 Explicit aliases for <all fields reference>
    160 T061 UCS support
    161 T071 BIGINT data type
    162 T111 Updatable joins, unions, and columns
    163 T121 WITH (excluding RECURSIVE) in query expression
    164 T131 Recursive query
    165 T141 SIMILAR predicate
    166 T151 DISTINCT predicate
    167 T171 LIKE clause in table definition
    168 T172 AS subquery clause in table definition
    169 T173 Extended LIKE clause in table definition
    170 T174 Identity columns
    171 T175 Generated columns
    172 T176 Sequence generator support
    173 T191 Referential action RESTRICT
    174 T201 Comparable data types for referential constraints
    175 T211 Basic trigger capability
    176 T211-01 Triggers activated on UPDATE, INSERT, or DELETE of one base table.
    177 T211-02 BEFORE triggers
    178 T211-03 AFTER triggers
    179 T211-04 FOR EACH ROW triggers
    180 T211-05 Ability to specify a search condition that must be True before the trigger is invoked.
    181 T211-06 Support for run-time rules for the interaction of triggers and constraints.
    182 T211-07 TRIGGER privilege
    183 T211-08 Multiple triggers for the same the event are executed in the order in which they were created in the catalog.
    184 T212 Enhanced trigger capability
    185 T231 Sensitive cursors
    186 T241 START TRANSACTION statement
    187 T242 Optional transaction modes in START TRANSACTION
    188 T251 SET TRANSACTION statement: LOCAL option
    189 T261 Chained transactions
    190 T271 Savepoints
    191 T272 Enhanced savepoint management
    192 T281 SELECT privilege with column granularity
    193 T301 Functional dependencies
    194 T312 OVERLAY function
    195 T322 Overloading of SQL-invoked functions and procedures
    196 T323 Explicit security for external routines
    197 T324 Explicit security for SQL routines
    198 T325 Qualified SQL parameter references
    199 T326 Table functions
    200 T331 Basic roles
    201 T332 Extended roles
    202 T351 Bracketed SQL comments (/*...*/ comments)
    203 T431 Extended grouping capabilities
    204 T432 Nested and concatenated GROUPING SETS
    205 T433 Multiargument GROUPING function
    206 T434 GROUP BY DISINCT
    207 T441 ABS and MOD functions
    208 T461 Symmetric <between predicate>
    209 T471 Result sets return value
    210 T491 LATERAL derived table
    211 T501 Enhanced EXISTS predicate
    212 T511 Transaction counts
    213 T551 Optional key words for default syntax
    214 T561 Holdable locators
    215 T571 Array-returning external SQL-invoked functions
    216 T572 Multiset-returning external SQL-invoked functions
    217 T581 Regular expression substring function
    218 T591 UNIQUE constraints of possibly null columns
    219 T601 Local cursor references
    220 T611 Elementary OLAP operations
    221 T612 Advanced OLAP operations
    222 T613 Sampling
    223 T621 Enhanced numeric functions
    224 T631 IN predicate with one list element
    225 T641 Multiple column assignment
    226 T651 SQL-schema statements in SQL routines
    227 T652 SQL-dynamic statements in SQL routines
    279 | 280 |

    281 | @(#)$Id: sql-2003-noncore-features.html,v 1.1 2004/10/28 16:18:25 jleffler Exp $ 282 |

    283 | 284 | 285 | 286 | -------------------------------------------------------------------------------- /doc/ref/savage/sql-bnf.mk: -------------------------------------------------------------------------------- 1 | # @(#)$Id: sql-bnf.mk,v 1.13 2005/03/11 23:19:19 jleffler Exp $ 2 | # 3 | # Makefile for SQL-92, SQL-99 and SQL-2003 BNF and HTML files 4 | 5 | .NO_PENDING_GET: 6 | 7 | FILE1.bnf = sql-92.bnf 8 | FILE2.bnf = sql-99.bnf 9 | FILE3.bnf = sql-2003-1.bnf 10 | FILE4.bnf = sql-2003-2.bnf 11 | FILES.bnf = ${FILE1.bnf} ${FILE2.bnf} ${FILE3.bnf} ${FILE4.bnf} 12 | FILES.html = ${FILES.bnf:bnf=bnf.html} 13 | FILE1.aux = index.html 14 | FILE2.aux = outer-joins.html 15 | FILE3.aux = sql-2003-core-features.html 16 | FILE4.aux = sql-2003-noncore-features.html 17 | FILES.aux = ${FILE1.aux} ${FILE2.aux} ${FILE3.aux} ${FILE4.aux} 18 | FILE1.pl = bnf2html.pl 19 | FILE2.pl = bnf2yacc.pl 20 | FILES.pl = ${FILE1.pl} ${FILE2.pl} 21 | FILES.mk = sql-bnf.mk 22 | FILES.all = ${FILES.bnf} ${FILES.html} ${FILES.mk} ${FILES.pl} ${FILES.aux} 23 | 24 | FILES.tgz = sql-bnf.tgz 25 | RCSFILES.tgz = sql-bnf-rcs.tgz 26 | 27 | APACHE_HOME = /usr/apache/webserver 28 | APACHE_HTML = htdocs/SQL 29 | APACHE_DIR = ${APACHE_HOME}/${APACHE_HTML} 30 | 31 | TAR = tar 32 | TARFLAGS = -cvzf 33 | COPY = cp 34 | COPYFLAGS = -fp 35 | PERL = perl 36 | RM_F = rm -f 37 | CHMOD = chmod 38 | WEBPERMS = 444 39 | 40 | all: ${FILES.tgz} ${RCSFILES.tgz} 41 | 42 | ${FILES.tgz}: ${FILES.all} 43 | ${TAR} ${TARFLAGS} ${FILES.tgz} ${FILES.all} 44 | 45 | ${RCSFILES.tgz}: RCS 46 | ${TAR} ${TARFLAGS} ${RCSFILES.tgz} RCS 47 | 48 | ${FILES.html}: $${@:.html=} ${FILE1.pl} 49 | ${RM} $@ 50 | ${PERL} ${FILE1.pl} ${@:.html=} > $@ 51 | 52 | install: all 53 | ${COPY} ${COPYFLAGS} ${FILES.tgz} ${FILES.all} ${APACHE_DIR} 54 | cd ${APACHE_DIR}; ${CHMOD} ${WEBPERMS} ${FILES.tgz} ${FILES.all} 55 | -------------------------------------------------------------------------------- /examples/browser/demo.js: -------------------------------------------------------------------------------- 1 | var sqljs = window.sqljs = require('../../lib/sqljs'); 2 | 3 | var options = new sqljs.ParseOptions; 4 | 5 | function parseText(text) { 6 | try { 7 | var result = sqljs.parse(text, undefined, options); 8 | console && console.log && console.log(result); 9 | return result; 10 | } catch(err) { 11 | console && console.error && console.error(err); 12 | return err; 13 | } 14 | } 15 | 16 | 17 | function parseClick() { 18 | var text = document.getElementById('editor').value; 19 | var result = window.parseResult = parseText(text); 20 | document.getElementById('output').innerText = JSON.stringify(result, null, 2); 21 | }; 22 | 23 | 24 | window.onload = function() { 25 | console.log('Loaded!'); 26 | document.getElementById('parseButton').onclick = parseClick; 27 | }; 28 | -------------------------------------------------------------------------------- /examples/browser/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | sql-js example 4 | 5 | 6 | 7 |
    Input:
    8 | 9 |
    10 |

    Output:
    11 | 12 |
    13 | 14 | 15 | -------------------------------------------------------------------------------- /grammar/00-00-00-init-start.pegjs: -------------------------------------------------------------------------------- 1 | { 2 | var options = arguments[2]; 3 | if(!(options && options.isParseOptions)) 4 | throw new Error("Parser require ParseOptions instance as 3rd argument"); 5 | 6 | function safeMergeObject(target, src, resolveCallback) { 7 | for(var name in src) { 8 | if(typeof target[name] === 'undefined') { 9 | target[name] = src[name]; 10 | } else { 11 | var result; 12 | if(resolveCallback) { 13 | result = resolveCallback(name, target[name], src[name]); 14 | if(typeof result === 'undefined') 15 | throw new Error('Ambiguous property '+name); 16 | target[name] = result; 17 | } else { 18 | throw new Error('Ambiguous property '+name); 19 | } 20 | } 21 | } 22 | } 23 | 24 | function merge(dst, src) { 25 | if (dst == null) dst = {}; 26 | if (src == null) return dst; 27 | for (var k in src) { 28 | dst[k] = src[k]; 29 | } 30 | return dst; 31 | } 32 | 33 | } 34 | 35 | 36 | START 37 | = STATEMENTS 38 | 39 | -------------------------------------------------------------------------------- /grammar/09-01-00-literal-value.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 9.1. Literal Values 3 | // http://dev.mysql.com/doc/refman/5.7/en/literals.html 4 | 5 | 6 | -------------------------------------------------------------------------------- /grammar/09-01-01-string-literal.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 9.1.1. String Literals 3 | // http://dev.mysql.com/doc/refman/5.7/en/string-literals.html 4 | 5 | 6 | STRING "string" 7 | = str:SINGLE_STRING+ { return str.join(''); } 8 | 9 | 10 | SINGLE_STRING "string" 11 | = '"' chars:chars_no_quot '"' _ { return chars; } 12 | / "'" chars:chars_no_apos "'" _ { return chars; } 13 | 14 | 15 | chars_no_quot 16 | = chars:char_no_quot* { return chars.join(""); } 17 | 18 | chars_no_apos 19 | = chars:char_no_apos* { return chars.join(""); } 20 | 21 | char_no_quot 22 | = char_escape_sequence 23 | / '""' { return '"'; } 24 | / [^"] // originally [^"\\\0-\x1F\x7f] 25 | 26 | char_no_apos 27 | = char_escape_sequence 28 | / "''" { return "'"; } 29 | / [^'] 30 | 31 | 32 | char_escape_sequence 33 | = "\\\\" { return "\\"; } 34 | / "\\'" { return "'"; } 35 | / '\\"' { return '"'; } 36 | / "\\0" { return "\x00"; } 37 | / "\\/" { return "/"; } 38 | / "\\b" { return "\b"; } 39 | / "\\n" { return "\n"; } 40 | / "\\f" { return "\f"; } 41 | / "\\r" { return "\r"; } 42 | / "\\t" { return "\t"; } 43 | / "\\Z" { return "\x1a"; } 44 | / & { return options.STRING_HEX_ESCAPE } 45 | "\\x" h1:hexDigit h2:hexDigit { 46 | return String.fromCharCode(parseInt("0x" + h1 + h2)); 47 | } 48 | / & { return options.STRING_UNICODE_ESCAPE } 49 | "\\u" h1:hexDigit h2:hexDigit h3:hexDigit h4:hexDigit { 50 | return String.fromCharCode(parseInt("0x" + h1 + h2 + h3 + h4)); 51 | } 52 | / "\\" char:. { 53 | if(options.STRING_STRICT_ESCAPE) 54 | throw new SyntaxError("Unknown escape sequence: '\\"+char+"'"); 55 | 56 | if(options.STRING_INVALID_ESCAPE_STRIP_BACKSLASH) 57 | return char; 58 | 59 | return '\\'+char; 60 | } 61 | 62 | 63 | hexDigit 64 | = [0-9a-fA-F] 65 | 66 | -------------------------------------------------------------------------------- /grammar/09-01-02-number-literal.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 9.1.2. Number Literals 3 | // http://dev.mysql.com/doc/refman/5.7/en/number-literals.html 4 | 5 | 6 | SIGNED_NUMBER "number" 7 | = sign:NUMBER_SIGN val:POSITIVE_NUMBER { return val*sign; } 8 | 9 | 10 | NUMBER_SIGN 11 | = "-" _ { return -1; } 12 | / "+"? _ { return 1; } 13 | 14 | 15 | POSITIVE_NUMBER "number" 16 | = POSITIVE_FLOAT 17 | / POSITIVE_INTEGER 18 | 19 | 20 | POSITIVE_FLOAT "float" 21 | = val:FloatLiteral _ { return parseFloat(val); } 22 | 23 | 24 | POSITIVE_INTEGER "integer" 25 | = & { return options.ALLOW_OCTAL_NOTATION || options.OCTAL_AS_DECIMAL; } 26 | "0" octal:[0-7]+ _ { return parseInt('0'+octal.join(''), options.OCTAL_AS_DECIMAL ? 10 : 8); } 27 | / "0x"i hex:[0-9A-Fa-f]+ _ { return parseInt(hex.join(''), 16); } 28 | / "0b"i bin:[01]+ _ { return parseInt(bin.join(''), 2); } 29 | / dec:DecimalLiteral _ { return parseInt(dec, 10); } 30 | 31 | 32 | FloatLiteral 33 | = base:[0-9]+ 34 | frac:([\.] frac:[0-9]* {return '.'+ frac.join('')})? 35 | exp:([eE] sign:[+-]? exp:[0-9]+ { return 'e' + sign + exp.join(''); }) 36 | { 37 | return base.join('') + frac + exp; 38 | } 39 | / base:[0-9]+ 40 | [\.] frac:(frac:[0-9]* {return frac.join('')})? 41 | exp:([eE] sign:[+-]? exp:[0-9]+ { return 'e' + sign + exp.join(''); })? 42 | { 43 | return base.join('') + '.' + frac + exp; 44 | } 45 | / [\.] frac:[0-9]+ 46 | exp:([eE] sign:[+-]? exp:[0-9]+ { return 'e' + sign + exp.join(''); })? 47 | { 48 | return '0.' + frac.join('') + exp; 49 | } 50 | 51 | 52 | DecimalLiteral 53 | = first:[1-9] decimal:[0-9]* { return first+decimal.join(''); } 54 | / [0]+ { return "0"; } 55 | 56 | -------------------------------------------------------------------------------- /grammar/09-01-05-boolean-literal.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 9.1.5. Boolean Literals 3 | // http://dev.mysql.com/doc/refman/5.7/en/boolean-literals.html 4 | 5 | 6 | BOOLEAN "boolean" 7 | = 'TRUE'i _ { return options.createValueTrue(); } 8 | / 'FALSE'i _ { return options.createValueFalse(); } 9 | 10 | -------------------------------------------------------------------------------- /grammar/09-01-07-null.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 9.1.7. NULL Value 3 | // http://dev.mysql.com/doc/refman/5.7/en/null-values.html 4 | 5 | NULL "NULL" 6 | = ("NULL"i / "\N") _ { return options.createValueNull(); } 7 | 8 | -------------------------------------------------------------------------------- /grammar/09-02-00-identifiers.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 9.2. Schema Object Names 3 | // http://dev.mysql.com/doc/refman/5.6/en/identifiers.html 4 | 5 | 6 | ID_OR_STR "ID or STR" 7 | = ID 8 | / STRING 9 | 10 | 11 | DATABASE_NAME "database name" 12 | = schema:ID { return schema } 13 | 14 | 15 | TABLE_NAME "table name" 16 | = schema:ID_OR_STR '.' name:ID_OR_STR { 17 | return { schema: schema, table: name }; 18 | } 19 | / name:ID_OR_STR { return { table: name }; } 20 | 21 | 22 | COLUMN_NAME "column name" 23 | = schema:ID_OR_STR '.' table:ID_OR_STR '.' column:ID_OR_STR { 24 | return { schema: schema, table: table, column: column }; 25 | } 26 | / table:ID_OR_STR '.' column:ID_OR_STR { 27 | return { table: table, column: column }; 28 | } 29 | / column:ID_OR_STR { 30 | return { column: column }; 31 | } 32 | 33 | 34 | ID "identifier" 35 | = start:[A-Za-z$_] rest:[0-9A-Za-z$_]* { return start + rest.join(''); } 36 | / '`' name:([^`]/double_backtick_escape)+ '`' { return name.join(''); } 37 | 38 | 39 | double_backtick_escape 40 | = "``" { return "`"; } 41 | 42 | -------------------------------------------------------------------------------- /grammar/09-05-00-expression.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 9.5. Expression Syntax 3 | // http://dev.mysql.com/doc/refman/5.7/en/expressions.html 4 | 5 | // 12.3.1. Operator Precedence 6 | // http://dev.mysql.com/doc/refman/5.7/en/operator-precedence.html 7 | 8 | // this is actually an extension 9 | CONSTANT_EXPRESSION "constant expression" 10 | = expr:EXPRESSION { 11 | return options.resolveConstantExpression(expr); 12 | } 13 | 14 | 15 | EXPRESSION 16 | = _ expr:ASSIGN_EXPR _ { return options.expression(expr); } 17 | 18 | ASSIGN_EXPR // := assignment, can be simly '=' in some cases but here i avoid it 19 | = left:LOGICALOR_EXPR _ tail:( ':=' _ expr:LOGICALOR_EXPR { return expr; } )+ { 20 | tail.unshift(left); 21 | return { 22 | operator: ":=", 23 | expressions: tail 24 | }; 25 | } 26 | / LOGICALOR_EXPR 27 | 28 | LOGICALOR_EXPR // ||, OR 29 | = left:LOGICALXOR_EXPR _ 30 | tail:( op:('||'/'OR'i) _ expr:LOGICALXOR_EXPR { return [op, expr]; } )+ 31 | { 32 | var exprs = [left]; 33 | var operators = []; 34 | tail.forEach(function(val){ 35 | operators.push(val[0]); // operator 36 | exprs.push(val[1]); // expression 37 | }); 38 | return options.orExpression({ 39 | operators: operators, 40 | expressions: exprs 41 | }); 42 | } 43 | / LOGICALXOR_EXPR 44 | 45 | LOGICALXOR_EXPR // XOR 46 | = left:LOGICALAND_EXPR _ tail:( 'XOR'i _ expr:LOGICALXOR_EXPR { return expr; } )+ 47 | { 48 | tail.unshift(left); 49 | return options.xorExpression({ 50 | operator: "XOR", 51 | expressions: tail 52 | }); 53 | } 54 | / LOGICALAND_EXPR 55 | 56 | LOGICALAND_EXPR // &&, AND 57 | = left:LOGICALNOT_EXPR _ tail:( ('&&'/'AND'i) _ expr:LOGICALNOT_EXPR { return expr; } )+ 58 | { 59 | tail.unshift(left); 60 | return options.andExpression({ 61 | operator: "AND", 62 | expressions: tail 63 | }); 64 | } 65 | / LOGICALNOT_EXPR 66 | 67 | LOGICALNOT_EXPR // NOT 68 | = "NOT"i __ expr:COND_EXPR 69 | { 70 | return options.notExpression({ 71 | unary: "NOT", 72 | expression: expr 73 | }); 74 | } 75 | / COND_EXPR 76 | 77 | COND_EXPR 78 | // TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO 79 | // BETWEEN, CASE, WHEN, THEN, ELSE 80 | = COMPARISON_EXPR 81 | 82 | COMPARISON_EXPR // = (comparison), <=>, >=, >, <=, <, <>, !=, IS, LIKE, REGEXP, IN 83 | = expr:BITOR_EXPR _ "IS" _ 84 | not:"NOT"i? _ 85 | val:("TRUE"i / "FALSE"i / "UNKNOWN"i / "NULL"i) _ 86 | { 87 | return options.isExpression({ 88 | unary: 'IS', 89 | not: !!not, 90 | value: val.toUpperCase(), 91 | expression: expr 92 | }); 93 | } 94 | / left:BITOR_EXPR _ tail:( 95 | op:('='/'<=>'/'>='/'>'/'<='/'<'/'<>'/'!='/'LIKE'i/'REGEXP'i/'IN'i) _ 96 | val:BITOR_EXPR { return [op, val]; })+ 97 | { 98 | var exprs = [left]; 99 | var operators = []; 100 | tail.forEach(function(val){ 101 | operators.push(val[0]); // operator 102 | exprs.push(val[1]); // expression 103 | }); 104 | return options.comparisonExpression({ 105 | operators: operators, 106 | expressions: exprs 107 | }); 108 | } 109 | / BITOR_EXPR 110 | 111 | BITOR_EXPR // | 112 | = left:BITAND_EXPR _ tail:( '|' _ expr:BITAND_EXPR { return expr; } )+ { 113 | tail.unshift(left); 114 | return options.bitwiseOrExpression({ 115 | operator: "|", 116 | expressions: tail 117 | }); 118 | } 119 | / BITAND_EXPR 120 | 121 | BITAND_EXPR // & 122 | = left:BITSHIFT_EXPR _ tail:( '&' _ expr:BITSHIFT_EXPR { return expr; } )+ { 123 | tail.unshift(left); 124 | return options.bitwiseAndExpression({ 125 | operator: "&", 126 | expressions: tail 127 | }); 128 | } 129 | / BITSHIFT_EXPR 130 | 131 | BITSHIFT_EXPR // <<, >> 132 | = left:ADD_EXPR _ tail:( op:('<<'/'>>') _ val:ADD_EXPR { return [op, val]; } )+ { 133 | var exprs = [left]; 134 | var operators = []; 135 | tail.forEach(function(val){ 136 | operators.push(val[0]); // operator 137 | exprs.push(val[1]); // expression 138 | }); 139 | return options.bitShiftExpression({ 140 | operators: operators, 141 | expressions: exprs 142 | }); 143 | } 144 | / ADD_EXPR 145 | 146 | ADD_EXPR // +, - 147 | = left:MULT_EXPR _ tail:( op:('+'/'-') _ val:MULT_EXPR { return [op, val]; } )+ { 148 | var exprs = [left]; 149 | var operators = []; 150 | tail.forEach(function(val){ 151 | operators.push(val[0]); // operator 152 | exprs.push(val[1]); // expression 153 | }); 154 | return options.addExpression({ 155 | operators: operators, 156 | expressions: exprs 157 | }); 158 | } 159 | / MULT_EXPR 160 | 161 | MULT_EXPR // *, /, DIV, %, MOD 162 | = left:BITXOR_EXPR _ tail:( 163 | op:('*' / '/' / 'DIV'i / '%' / 'MOD'i) _ 164 | val:BITXOR_EXPR { return [op, val]; } )+ 165 | { 166 | var exprs = [left]; 167 | var operators = []; 168 | tail.forEach(function(val){ 169 | operators.push(val[0]); // operator 170 | exprs.push(val[1]); // expression 171 | }); 172 | return options.mulDivExpression({ 173 | operators: operators, 174 | expressions: exprs 175 | }); 176 | } 177 | / BITXOR_EXPR 178 | 179 | BITXOR_EXPR // ^ 180 | = left:UNARY_EXPR _ tail:( '^' _ expr:UNARY_EXPR { return expr; } )+ { 181 | tail.unshift(left); 182 | return options.bitwiseXorExpression({ 183 | operator: "^", 184 | expressions: tail 185 | }); 186 | } 187 | / UNARY_EXPR 188 | 189 | UNARY_EXPR // - (unary minus), ~ (unary bit inversion), + (unary plus) 190 | = op:('~' / '+' / '-') _ expr:UNARY_EXPR { 191 | return options.unaryExpression({ 192 | unary: op, 193 | expression: expr 194 | }); 195 | } 196 | / HIGH_NOT_EXPR 197 | 198 | HIGH_NOT_EXPR // ! 199 | = '!' _ expr:HIGH_NOT_EXPR { 200 | return options.notExpression({ 201 | unary: '!', 202 | expression: expr 203 | }); 204 | } 205 | / STRING_COLLATE_EXPR 206 | 207 | STRING_COLLATE_EXPR // COLLATE 208 | = expr:STRING_BINARY_EXPR _ "COLLATE"i _ collation:COLLATION_NAME { 209 | return options.collateExpression({ 210 | unary: 'COLLATE', 211 | collation: collation, 212 | expression: expr 213 | }); 214 | } 215 | / STRING_BINARY_EXPR 216 | 217 | 218 | COLLATION_NAME "collation name" 219 | = ID 220 | / STRING 221 | 222 | 223 | STRING_BINARY_EXPR // BINARY MODIFIER 224 | = "BINARY"i __ expr:INTERVAL_EXPR { 225 | return options.modifierBinaryExpression({ 226 | unary: 'BINARY', 227 | expression: expr 228 | }); 229 | } 230 | / INTERVAL_EXPR 231 | 232 | INTERVAL_EXPR 233 | // TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO TODO 234 | = PRIMARY_EXPR 235 | 236 | PRIMARY_EXPR 237 | = CONSTANT_VALUE 238 | / "(" expr:EXPRESSION ")" { return expr; } 239 | 240 | 241 | CONSTANT_VALUE 242 | = NULL 243 | / BOOLEAN 244 | / STRING 245 | / POSITIVE_NUMBER 246 | / CURRENT_TIMESTAMP -------------------------------------------------------------------------------- /grammar/13-00-00-statement.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // Chapter 13. SQL Statement Syntax 3 | // http://dev.mysql.com/doc/refman/5.7/en/sql-syntax.html 4 | 5 | 6 | STATEMENTS 7 | = _ (';' _)* first:STATEMENT _ statements:((';' _)+ stmt:STATEMENT _ { return stmt; })* _ (';' _)* { 8 | statements.unshift(first); return statements; 9 | } 10 | / _ { return []; } 11 | 12 | 13 | STATEMENT 14 | = DATA_DEFINITION_STATEMENT 15 | / DATA_MANIPULATION_STATEMENT 16 | / USE_STATEMENT 17 | -------------------------------------------------------------------------------- /grammar/13-01-00-data-definition.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 13.1. Data Definition Statements 3 | // http://dev.mysql.com/doc/refman/5.7/en/sql-syntax-data-definition.html 4 | 5 | DATA_DEFINITION_STATEMENT 6 | = SET_STATEMENT 7 | / CREATE_STATEMENT 8 | / ALTER_STATEMENT 9 | / DROP_STATEMENT 10 | 11 | 12 | /* === CREATE statement === */ 13 | 14 | CREATE_STATEMENT "CREATE" 15 | = CREATE_DATABASE 16 | / CREATE_TABLE 17 | 18 | 19 | ALTER_STATEMENT "ALTER" 20 | = ALTER_DATABASE 21 | / ALTER_TABLE 22 | -------------------------------------------------------------------------------- /grammar/13-01-01-alter-database.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 13.1.1. ALTER DATABASE Syntax 3 | // http://dev.mysql.com/doc/refman/5.7/en/alter-database.html 4 | 5 | 6 | ALTER_DATABASE 7 | = "ALTER"i __ what:("DATABASE"i / "SCHEMA"i) __ name:DATABASE_NAME { 8 | return { 9 | statement: "ALTER", 10 | what: what.toUpperCase() 11 | }; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /grammar/13-01-06-alter-table.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 13.1.6. ALTER TABLE Syntax 3 | // http://dev.mysql.com/doc/refman/5.7/en/alter-table.html 4 | 5 | 6 | ALTER_TABLE 7 | = "ALTER"i __ ignore:("IGNORE"i __)? "TABLE"i _ name:TABLE_NAME _ specifications:ALTER_TABLE_SPECIFICATIONS 8 | { 9 | return { 10 | statement: "ALTER", 11 | what: "TABLE", 12 | table: name.table, 13 | ignore: !!ignore, 14 | specifications:specifications 15 | }; 16 | } 17 | 18 | ALTER_TABLE_SPECIFICATIONS 19 | = first:ALTER_TABLE_SPECIFICATION _ tail:(',' _ spec:ALTER_TABLE_SPECIFICATION { return spec; })* 20 | { 21 | tail.unshift(first); 22 | return tail; 23 | } 24 | 25 | ALTER_TABLE_SPECIFICATION 26 | = "ADD"i _ column:CREATE_DEFINITION { 27 | column.alter_type = "ADD" 28 | return column; 29 | } 30 | -------------------------------------------------------------------------------- /grammar/13-01-08-create-database.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 13.1.8. CREATE DATABASE Syntax 3 | // http://dev.mysql.com/doc/refman/5.7/en/create-database.html 4 | 5 | 6 | CREATE_DATABASE "CREATE DATABASE" 7 | = "CREATE"i __ what:("SCHEMA"i/"DATABASE"i) _ exists:("IF"i _ "NOT"i _ "EXIST"i "S"i?)? _ name:ID _ props:SCHEMA_PROPERTIES { 8 | props.statement = 'CREATE'; 9 | props.what = what.toUpperCase(); 10 | props.database = name; 11 | if (exists.length > 0) props.ifNotExists = true; 12 | return props; 13 | } 14 | 15 | 16 | SCHEMA_PROPERTIES "schema properties" 17 | = ("DEFAULT"i __)? "CHAR"i "ACTER"i? (_/"_") "SET"i (_ "="? _ / __) 18 | charset:ID 19 | _ props:SCHEMA_PROPERTIES 20 | { 21 | props.charset = charset; 22 | return props; 23 | } 24 | / ("DEFAULT"i __)? "COLLAT"i ("E"i/"ION"i) (_ "=" _ / __) 25 | collate:COLLATION_NAME 26 | _ props:SCHEMA_PROPERTIES 27 | { 28 | props.collate = collate; 29 | return props; 30 | } 31 | / "COMMENT"i (_ "=" _ / __) comment:(ID/STRING) _ props:SCHEMA_PROPERTIES { 32 | props.comment = comment; 33 | return props; 34 | } 35 | / _ { return {}; } 36 | 37 | -------------------------------------------------------------------------------- /grammar/13-01-14-create-table.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 13.1.14. CREATE TABLE Syntax 3 | // http://dev.mysql.com/doc/refman/5.7/en/create-table.html 4 | 5 | CREATE_TABLE 6 | = ("CREATE"i __)? 7 | temp:("TEMP"i "ORARY"i? _)? "TABLE"i __ 8 | props1:TABLE_PROPERTIES 9 | table:TABLE_NAME _ 10 | props2:TABLE_PROPERTIES 11 | '(' columns:CREATE_DEFINITIONS ')' _ 12 | props:TABLE_PROPERTIES 13 | { 14 | safeMergeObject(props, props1); 15 | safeMergeObject(props, props2); 16 | props.statement = "CREATE"; 17 | props.what = "TABLE"; 18 | props.schema = table.schema; 19 | props.table = table.table; 20 | if(temp) props.temporary = true; 21 | props.definitions = columns; 22 | return props; 23 | } 24 | 25 | 26 | TABLE_PROPERTIES 27 | = ("DEFAULT"i __)? "CHAR"i "ACTER"i? (_/"_") "SET"i (_ "=" _ / __) 28 | charset:ID _ 29 | props:TABLE_PROPERTIES 30 | { 31 | props.charset = charset; 32 | return props; 33 | } 34 | / ("DEFAULT"i __)? "COLLAT"i ("E"i/"ION"i) (_ "=" _ / __) 35 | collate:COLLATION_NAME _ 36 | props:TABLE_PROPERTIES 37 | { 38 | props.collate = collate; 39 | return props; 40 | } 41 | / "COMMENT"i (_ "=" _ / __) comment:(ID/STRING) _ props:TABLE_PROPERTIES { 42 | props.comment = comment; 43 | return props; 44 | } 45 | / "IF"i _ "NOT"i _ "EXIST" "S"i? _ props:TABLE_PROPERTIES { 46 | props.ifNotExists = true; 47 | return props; 48 | } 49 | / "ENGINE"i (_ '=' _ / __) name:(ID/STRING) _ props:TABLE_PROPERTIES { 50 | props.engine = name; 51 | return props; 52 | } 53 | / "AUTO"i ("_"/_)? "INC"i "REMENT"i _ (_ '=' _ / __) value:CONSTANT_EXPRESSION _ props:TABLE_PROPERTIES { 54 | props.autoIncrement = value; 55 | return props; 56 | } 57 | / _ { return {}; } 58 | 59 | 60 | 61 | CREATE_DEFINITIONS 62 | = _ col:CREATE_DEFINITION cols:(_ ',' _ col:CREATE_DEFINITION { return col; })* _ (',' _)* 63 | { cols.unshift(col); return cols; } 64 | / _ { return []; } 65 | 66 | 67 | CREATE_DEFINITION "column create definition" 68 | = CREATE_DEFINITION_CONSTRAINT 69 | / name:ID_OR_STR _ props:COLUMN_TYPE_PROPERTIES { props.name = name; return props; } 70 | 71 | 72 | CREATE_DEFINITION_CONSTRAINT 73 | = constraint_name:CONSTRAINT_NAME_OPT "PRIMARY"i _ ("KEY"i _ )? 74 | "(" _ idlist:ID_LIST ")" _ 75 | { 76 | return { 77 | type: "CONSTRAINT", 78 | constraint: "PRIMARY KEY", 79 | constraintName:constraint_name, 80 | columns: idlist 81 | }; 82 | } 83 | / constraint_name:CONSTRAINT_NAME_OPT "FOREIGN"i _ ("KEY"i _ )? 84 | idx_name:(name:(ID/STRING) _ )? 85 | "(" _ idlist:ID_LIST ")" _ 86 | ref:REFERENCE_DEFINITION 87 | { 88 | return { 89 | type: "CONSTRAINT", 90 | constraint: "FOREIGN KEY", 91 | constraintName:constraint_name, 92 | indexName:idx_name, 93 | columns: idlist, 94 | references: ref 95 | }; 96 | } 97 | / "UNIQUE"i __ type:("KEY"i/"INDEX"i)? 98 | name:(__ name:(ID/STRING) {return name;})? _ "(" _ idlist:ID_LIST ")" _ 99 | { 100 | var key = { 101 | type: "CONSTRAINT", 102 | constraint: (type ? type.toUpperCase() : 'INDEX'), 103 | unique: true, 104 | columns: idlist 105 | }; 106 | if(name) 107 | key.name = name; 108 | return key; 109 | } 110 | / unique:("UNIQUE"i __)? type:("KEY"i/"INDEX"i) 111 | name:(__ name:(ID/STRING) {return name;})? _ "(" _ idlist:ID_LIST ")" _ 112 | { 113 | var key = { 114 | type: "CONSTRAINT", 115 | constraint: type.toUpperCase(), 116 | unique: !!unique, 117 | columns: idlist 118 | }; 119 | if(name) 120 | key.name = name; 121 | return key; 122 | } 123 | 124 | CONSTRAINT_NAME_OPT 125 | = "CONSTRAINT"i __ !("PRIMARY"i/"FOREIGN"i/"KEY"i/"INDEX"i/"UNIQUE"i) name:(ID/STRING) _ { return name; } 126 | / "CONSTRAINT"i __ { return true; } 127 | / { } 128 | 129 | /* 130 | | [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,...) 131 | [index_option] ... 132 | | {INDEX|KEY} [index_name] [index_type] (index_col_name,...) 133 | [index_option] ... 134 | | [CONSTRAINT [symbol]] UNIQUE [INDEX|KEY] 135 | [index_name] [index_type] (index_col_name,...) 136 | [index_option] ... 137 | | {FULLTEXT|SPATIAL} [INDEX|KEY] [index_name] (index_col_name,...) 138 | [index_option] ... 139 | | [CONSTRAINT [symbol]] FOREIGN KEY 140 | [index_name] (index_col_name,...) reference_definition 141 | | CHECK (expr) 142 | */ 143 | 144 | 145 | ID_LIST 146 | = id:ID _ rest:(',' _ id2:ID _ { return id2; })* { rest.unshift(id); return rest; } 147 | 148 | STRING_ID_LIST 149 | = id:(STRING/ID) _ rest:(',' _ id2:(STRING/ID) _ { return id2; })* { rest.unshift(id); return rest; } 150 | 151 | 152 | NUMERIC_TYPE_LENGTH 153 | = _ "(" _ length:POSITIVE_INTEGER _ "," _ decimals:POSITIVE_INTEGER _ ")" { 154 | return { length: length, decimals: decimals }; 155 | } 156 | / _ "(" _ length:POSITIVE_INTEGER _ ")" { 157 | return { length: length, decimals: 0 }; 158 | } 159 | / { return {}; } 160 | 161 | 162 | TYPE_LENGTH 163 | = _ "(" _ length:POSITIVE_INTEGER _ ")" { 164 | return length; 165 | } 166 | / { return; } 167 | 168 | 169 | COLUMN_TYPE_PROPERTIES "Column type properties" 170 | = _ prefix:("TINY"i/"SMALL"i/"MEDIUM"i/"BIG"i)? _ "INT"i "EGER"i? length:TYPE_LENGTH 171 | props:COLUMN_TYPE_PROPERTIES 172 | { 173 | if(props.type) 174 | throw new SyntaxError("Ambiguous type"); 175 | props.type = prefix ? prefix.toUpperCase()+'INT' : 'INT'; 176 | if(length) props.length = length; 177 | return props; 178 | } 179 | / _ ("NUM"i ("ERIC"i/"BER"i)? / "DEC"i "IMAL"i?) length:NUMERIC_TYPE_LENGTH props:COLUMN_TYPE_PROPERTIES { 180 | if(props.type) 181 | throw new SyntaxError("Ambiguous type"); 182 | props.type = 'DECIMAL'; 183 | if(length.length) props.length = length.length; 184 | if(length.decimals) props.decimals = length.decimals; 185 | return props; 186 | } 187 | / _ type:("DOUBLE"i / "FLOAT"i / "REAL"i) length:NUMERIC_TYPE_LENGTH props:COLUMN_TYPE_PROPERTIES { 188 | if(props.type) 189 | throw new SyntaxError("Ambiguous type"); 190 | props.type = type.toUpperCase(); 191 | if(length.length) props.length = length.length; 192 | if(length.decimals) props.decimals = length.decimals; 193 | return props; 194 | } 195 | / _ ("CHAR"i __ "BINARY"i) length:TYPE_LENGTH props:COLUMN_TYPE_PROPERTIES { 196 | if(props.type) 197 | throw new SyntaxError("Ambiguous type"); 198 | props.type = 'BINARY'; 199 | if(length) props.length = length; 200 | return props; 201 | } 202 | / _ ("VARBINARY"i/"VARCHAR"i __ "BINARY"i) length:TYPE_LENGTH props:COLUMN_TYPE_PROPERTIES { 203 | if(props.type) 204 | throw new SyntaxError("Ambiguous type"); 205 | props.type = 'VARBINARY'; 206 | if(length) props.length = length; 207 | return props; 208 | } 209 | / _ ("VARCHAR"i/"CHARACTER"i __ "VARYING"i) length:TYPE_LENGTH props:COLUMN_TYPE_PROPERTIES { 210 | if(props.type) 211 | throw new SyntaxError("Ambiguous type"); 212 | props.type = 'VARCHAR'; 213 | if(length) props.length = length; 214 | return props; 215 | } 216 | / _ ("CHAR"i/"CHARACTER"i) length:TYPE_LENGTH props:COLUMN_TYPE_PROPERTIES { 217 | if(props.type) 218 | throw new SyntaxError("Ambiguous type"); 219 | props.type = 'CHAR'; 220 | if(length) props.length = length; 221 | return props; 222 | } 223 | / _ (prefix:("TINY"i/"MEDIUM"i/"LONG"i)? _) "TEXT"i props:COLUMN_TYPE_PROPERTIES { 224 | if(props.type) 225 | throw new SyntaxError("Ambiguous type"); 226 | props.type = typeof prefix !== 'undefined' ? prefix.toUpperCase()+'TEXT' : 'TEXT'; 227 | return props; 228 | } 229 | / _ (prefix:("TINY"i/"MEDIUM"i/"LONG"i)? _) "BLOB"i props:COLUMN_TYPE_PROPERTIES { 230 | if(props.type) 231 | throw new SyntaxError("Ambiguous type"); 232 | props.type = typeof prefix !== 'undefined' ? prefix.toUpperCase()+'BLOB' : 'BLOB'; 233 | return props; 234 | } 235 | / _ type:("DATETIME"i/"DATE"i/"TIMESTAMP"i/"TIME"i/"YEAR"i) length:TYPE_LENGTH _ 236 | props:COLUMN_TYPE_PROPERTIES 237 | { 238 | if(props.type) 239 | throw new SyntaxError("Ambiguous type"); 240 | props.type = type.toUpperCase(); 241 | if(length) props.length = length; 242 | return props; 243 | } 244 | / _ "ENUM"i _ "(" values:STRING_ID_LIST ")" _ props:COLUMN_TYPE_PROPERTIES { 245 | if(props.type) 246 | throw new SyntaxError("Ambiguous type"); 247 | props.type = 'ENUM'; 248 | props.values = values; 249 | return props; 250 | } 251 | / _ "UNSIGNED"i _ props:COLUMN_TYPE_PROPERTIES { 252 | props.unsigned=true; 253 | return props; 254 | } 255 | / _ "SIGNED"i _ props:COLUMN_TYPE_PROPERTIES { 256 | props.signed=true; 257 | return props; 258 | } 259 | / _ "NOT"i _ "NULL"i _ props:COLUMN_TYPE_PROPERTIES { 260 | if(typeof props.notNull !== 'undefined') 261 | throw new Error('NULL or NOT NULL?'); 262 | props.notNull=true; 263 | return props; 264 | } 265 | / _ "NULL"i props:COLUMN_TYPE_PROPERTIES { 266 | if(typeof props.notNull !== 'undefined') 267 | throw new Error('NULL or NOT NULL?'); 268 | props.notNull=false; 269 | return props; 270 | } 271 | / _ "PRIMARY"i (_ "KEY"i)? _ props:COLUMN_TYPE_PROPERTIES { 272 | props.primaryKey=true; 273 | return props; 274 | } 275 | / _ "UNIQ"i "UE"i? _ props:COLUMN_TYPE_PROPERTIES { 276 | props.unique=true; 277 | return props; 278 | } 279 | / _ "AUTO"i ( "_" / _ )"INC"i "REMENT"i? _ props:COLUMN_TYPE_PROPERTIES { 280 | props.autoIncrement=true; 281 | return props; 282 | } 283 | / _ "COLLAT"i ("E"i/"ION"i) (_ "=" _ / __) 284 | collate:COLLATION_NAME _ props:COLUMN_TYPE_PROPERTIES 285 | { 286 | props.collate = collate; 287 | return props; 288 | } 289 | / _ "DEFAULT"i __ value:CONSTANT_EXPRESSION props:COLUMN_TYPE_PROPERTIES { 290 | props.default = value; 291 | return props; 292 | } 293 | / _ "DEFAULT"i __ CURRENT_TIMESTAMP props:COLUMN_TYPE_PROPERTIES { 294 | props.default = 'CURRENT_TIMESTAMP'; 295 | return props; 296 | } 297 | / _ "ON"i _ "UPDATE"i _ val:CURRENT_TIMESTAMP _ props:COLUMN_TYPE_PROPERTIES { 298 | props.onUpdate = val; 299 | return props; 300 | } 301 | / _ "COMMENT"i ( _ "=" _ / __ ) comment:STRING props:COLUMN_TYPE_PROPERTIES { 302 | props.comment = comment; 303 | return props; 304 | } 305 | / _ { return {}; } 306 | 307 | -------------------------------------------------------------------------------- /grammar/13-01-17-drop-database.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 13.1.17. DROP DATABASE Syntax 3 | // http://dev.mysql.com/doc/refman/5.7/en/drop-database.html 4 | 5 | DROP_STATEMENT "DROP" 6 | = "DROP"i __ ("DATABASE"i/"SCHEMA"i) __ name:ID { 7 | return { 8 | statement: "DROP DATABASE", 9 | database: name 10 | }; 11 | } 12 | / "DROP"i __ ("PROCEDURE"i) __ ifExists:IF_EXISTS_OPT _ name:ID { 13 | return { 14 | statement: "DROP PROCEDURE", 15 | database: name, 16 | ifExists: ifExists 17 | }; 18 | } 19 | / "DROP"i __ "TABLE"i __ name:TABLE_NAME { 20 | var res = { statement: "DROP TABLE" }; 21 | return merge(name, res); 22 | } 23 | 24 | IF_EXISTS_OPT 25 | = "IF"i _ "EXIST"i "S"i? { return true; } 26 | / { return false; } 27 | -------------------------------------------------------------------------------- /grammar/13-02-00-data-manipulation.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 13.2. Data Manipulation Statements 3 | // http://dev.mysql.com/doc/refman/5.7/en/sql-syntax-data-manipulation.html 4 | 5 | DATA_MANIPULATION_STATEMENT 6 | = CALL_STATEMENT 7 | / INSERT_STATEMENT 8 | 9 | // / DO_STATEMENT // 13.2.3. DO Syntax 10 | // / HANDLER_STATEMENT // 13.2.4. HANDLER Syntax 11 | // / INSERT_STATEMENT // 13.2.5. INSERT Syntax 12 | // / LOAD_DATA_INFILE_STATEMENT // 13.2.6. LOAD DATA INFILE Syntax 13 | // / LOAD_XML_STATEMENT // 13.2.7. LOAD XML Syntax 14 | // / REPLACE_STATEMENT // 13.2.8. REPLACE Syntax 15 | / SELECT_STATEMENT // 13.2.9. SELECT Syntax 16 | // / Subquery_STATEMENT // 13.2.10. Subquery Syntax 17 | // / UPDATE_STATEMENT // 13.2.11. UPDATE Syntax -------------------------------------------------------------------------------- /grammar/13-02-01-call.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 13.2.1. CALL Syntax 3 | // http://dev.mysql.com/doc/refman/5.6/en/call.html 4 | 5 | CALL_STATEMENT "CALL" 6 | = "CALL"i __ name:ID _ "(" params:CALL_PARAMETER_LIST ")" { 7 | return { 8 | statement: "CALL", 9 | name: name, 10 | params: params 11 | }; 12 | } 13 | / "CALL"i __ name:ID { 14 | return { 15 | statement: "CALL", 16 | name: name, 17 | params: [] 18 | }; 19 | } 20 | 21 | 22 | CALL_PARAMETER_LIST 23 | = _ param:CALL_PARAMETER _ (',' _)? list:CALL_PARAMETER_LIST { 24 | list.unshift(param); 25 | return list; 26 | } 27 | / _ { return []; } 28 | 29 | 30 | CALL_PARAMETER 31 | = EXPRESSION 32 | -------------------------------------------------------------------------------- /grammar/13-02-05-insert.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 13.2.5. INSERT Syntax 3 | // http://dev.mysql.com/doc/refman/5.6/en/insert.html 4 | 5 | // INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] 6 | // [INTO] tbl_name [PARTITION (partition_name,...)] 7 | // [(col_name,...)] 8 | // {VALUES | VALUE} ({expr | DEFAULT},...),(...),... 9 | // [ ON DUPLICATE KEY UPDATE 10 | // col_name=expr 11 | // [, col_name=expr] ... ] 12 | // Or: 13 | // 14 | // INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE] 15 | // [INTO] tbl_name [PARTITION (partition_name,...)] 16 | // SET col_name={expr | DEFAULT}, ... 17 | // [ ON DUPLICATE KEY UPDATE 18 | // col_name=expr 19 | // [, col_name=expr] ... ] 20 | // Or: 21 | // 22 | // INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE] 23 | // [INTO] tbl_name [PARTITION (partition_name,...)] 24 | // [(col_name,...)] 25 | // SELECT ... 26 | // [ ON DUPLICATE KEY UPDATE 27 | // col_name=expr 28 | // [, col_name=expr] ... ] 29 | 30 | 31 | INSERT_STATEMENT "INSERT" 32 | = "INSERT"i priority:INSERT_PRIORITY ignore:INSERT_IGNORE 33 | (__ "INTO"i )? __ table:TABLE_NAME /* [PARTITION (partition_name,...)] */ _ 34 | columns:INSERT_COLUMN_LIST 35 | "VALUE"i "S"i? _ rows:INSERT_ROWS 36 | { 37 | var insert = { 38 | statement: "INSERT", 39 | table: table, 40 | columns: columns, 41 | rows: rows 42 | }; 43 | 44 | if(priority) 45 | insert.priority = priority; 46 | 47 | if(ignore) 48 | insert.ignore = ignore; 49 | 50 | return insert; 51 | } 52 | 53 | INSERT_PRIORITY 54 | = __ "LOW"i ( "_" / _ ) "PRIORITY"i { return "LOW"; } 55 | / __ "DELAYED"i { return "DELAYED"; } 56 | / __ "HIGH"i ( "_" / _ ) "PRIORITY"i { return "HIGH"; } 57 | / { return false; } 58 | 59 | 60 | INSERT_IGNORE 61 | = __ "IGNORE"i { return true; } 62 | / { return false; } 63 | 64 | INSERT_COLUMN_LIST 65 | = "(" _ col:(ID/STRING) tail:(_ ',' _ col:(ID/STRING) {return col;})* _ ")" _ { 66 | tail.unshift(col); 67 | return tail; 68 | } 69 | / { return []; } 70 | 71 | INSERT_ROWS 72 | = first:INSERT_ROW rows:("," _ row:INSERT_ROW { return row; })* 73 | { 74 | rows.unshift(first); 75 | return rows; 76 | } 77 | 78 | INSERT_ROW 79 | = "(" _ first:EXPRESSION row:("," expr:EXPRESSION { return expr; })* ")" _ 80 | { 81 | row.unshift(first); 82 | return row; 83 | } -------------------------------------------------------------------------------- /grammar/13-02-09-select-statement.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 13.2.9. SELECT Syntax 3 | // http://dev.mysql.com/doc/refman/5.7/en/select.html 4 | 5 | // SELECT 6 | // [ALL | DISTINCT | DISTINCTROW ] 7 | // [HIGH_PRIORITY] 8 | // [STRAIGHT_JOIN] 9 | // [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT] 10 | // [SQL_CACHE | SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS] 11 | // select_expr [, select_expr ...] 12 | // [FROM table_references 13 | // [PARTITION partition_list] 14 | // [WHERE where_condition] 15 | // [GROUP BY {col_name | expr | position} 16 | // [ASC | DESC], ... [WITH ROLLUP]] 17 | // [HAVING where_condition] 18 | // [ORDER BY {col_name | expr | position} 19 | // [ASC | DESC], ...] 20 | // [LIMIT {[offset,] row_count | row_count OFFSET offset}] 21 | // [PROCEDURE procedure_name(argument_list)] 22 | // [INTO OUTFILE 'file_name' 23 | // [CHARACTER SET charset_name] 24 | // export_options 25 | // | INTO DUMPFILE 'file_name' 26 | // | INTO var_name [, var_name]] 27 | // [FOR UPDATE | LOCK IN SHARE MODE]] 28 | 29 | SELECT_STATEMENT "SELECT" 30 | = "SELECT"i __ 31 | (("ALL"i / "DISTINCTROW"i / "DISTINCT"i) __ )? 32 | ("HIGH_PRIORITY"i __)? 33 | ("STRAIGHT_JOIN"i __)? 34 | ("SQL_SMALL_RESULT"i __)? 35 | ("SQL_BIG_RESULT"i __)? 36 | ("SQL_BUFFER_RESULT"i __)? 37 | (("SQL_CACHE"i / "SQL_NO_CACHE"i) __)? 38 | "SQL_CALC_FOUND_ROWS"i? 39 | 40 | SELECT_EXPRESSION_LIST 41 | 42 | ("FROM"i __ FROM_TABLE_REFERENCES 43 | ("PARTITION"i __ ID (_ "," _ ID)?)? 44 | 45 | ("WHERE"i _ WHERE_CONDITION)? 46 | 47 | ("GROUP"i _ "BY"i ( ","? COLUMN_NAME 48 | ("ASC"i / "DESC"i)? )+ ("WITH"i ("_" / _) "ROLLUP"i)?)? 49 | 50 | ("HAVING"i _ WHERE_CONDITION)? 51 | 52 | ("ORDER"i _ "BY"i _ EXPRESSION)? 53 | 54 | ("LIMIT"i _ ((offset:POSITIVE_NUMBER)? / POSITIVE_NUMBER "OFFSET"i POSITIVE_NUMBER))? 55 | 56 | ("PROCEDURE"i ID(EXPRESSION))? 57 | 58 | ("INTO"i __ "OUTFILE"i outfile:(ID/STRING) 59 | ("CHARACTER"i __ "SET"i ID)? 60 | // export_options 61 | / "INTO"i "DUMPFILE"i 'file_name' 62 | / "INTO"i ID (_ "," _ ID)?)? 63 | 64 | ("FOR"i _ "UPDATE"i / "LOCK"i _ "IN"i _ "SHARE"i _ "MODE"i)?)? 65 | 66 | 67 | SELECT_EXPRESSION_LIST 68 | = "(" _ col:(ID/STRING) tail:(_ ',' _ col:(ID/STRING) {return col;})* _ ")" _ { 69 | tail.unshift(col); 70 | return tail; 71 | } 72 | / { return []; } 73 | 74 | 75 | FROM_TABLE_REFERENCES 76 | = "(" _ col:(ID/STRING) tail:(_ ',' _ col:(ID/STRING) {return col;})* _ ")" _ { 77 | tail.unshift(col); 78 | return tail; 79 | } 80 | 81 | WHERE_CONDITION 82 | = EXPRESSION -------------------------------------------------------------------------------- /grammar/13-07-04-set.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 13.7.4. SET Syntax 3 | // http://dev.mysql.com/doc/refman/5.6/en/set-statement.html 4 | 5 | // TODO: multiple set assignments 6 | 7 | SET_STATEMENT "SET" 8 | = "SET"i __ variable:ID ( _ "=" _ / __) value:(ID / STRING) { 9 | return { 10 | statement: "SET", 11 | variable: variable, 12 | value: value 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /grammar/13-08-04-use.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 13.8.4. USE Syntax 3 | // http://dev.mysql.com/doc/refman/5.6/en/use.html 4 | 5 | USE_STATEMENT "USE" 6 | = "USE"i __ ("DATABASE"i __)? name:ID { 7 | return { statement: "USE", database: name }; 8 | } 9 | -------------------------------------------------------------------------------- /grammar/14-02-02-05-foreign-key.pegjs: -------------------------------------------------------------------------------- 1 | 2 | // 14.2.2.5. FOREIGN KEY Constraints 3 | // http://dev.mysql.com/doc/refman/5.6/en/innodb-foreign-key-constraints.html 4 | 5 | 6 | REFERENCE_DEFINITION 7 | = ("REFERENCES"i/"TO"i) __ 8 | table:TABLE_NAME _ 9 | cols:( "(" _ cols:ID_LIST ")" _ { return cols; })? _ 10 | actions:REFERENCE_DEFINITION_ACTIONS 11 | { 12 | return { 13 | schema: table.schema, 14 | table: table.table, 15 | columns: cols, 16 | actions: actions 17 | }; 18 | } 19 | 20 | REFERENCE_DEFINITION_ACTIONS 21 | = "ON"i __ 22 | type:("DELETE"i/"UPDATE"i) __ 23 | action:REFERENCE_DEFINITION_ACTION_OPTION _ 24 | actions:REFERENCE_DEFINITION_ACTIONS 25 | { 26 | var name = "ON "+type.toUpperCase(); 27 | if(actions[name]) 28 | throw new Error('Trying to redefine reference action "'+name+'"'); 29 | actions[name] = action; 30 | return actions; 31 | } 32 | / { return {}; } 33 | 34 | REFERENCE_DEFINITION_ACTION_OPTION 35 | = "RESTRICT"i { return 'RESTRICT'; } 36 | / "CASCADE"i { return 'CASCADE'; } 37 | / "SET NULL"i { return 'SET NULL'; } 38 | / "NO ACTION"i { return 'NO ACTION'; } 39 | 40 | -------------------------------------------------------------------------------- /grammar/80-literal-datetime.pegjs: -------------------------------------------------------------------------------- 1 | 2 | /* === CURRENT_TIMESTAMP === */ 3 | 4 | CURRENT_TIMESTAMP 5 | = ( "CURRENT_TIMESTAMP"i 6 | / "CURRENT"i _ "TIMESTAMP"i 7 | / "NOW"i (_ "()" )? ) 8 | { 9 | return options.createValueCurrentTimestamp(); 10 | } 11 | 12 | -------------------------------------------------------------------------------- /grammar/99-whitespace.pegjs: -------------------------------------------------------------------------------- 1 | /* === Comments and whitespaces === */ 2 | 3 | comment 4 | = singleLineComment 5 | / multiLineComment 6 | 7 | singleLineComment 8 | = "--" (!eolChar .)* 9 | / "#" (!eolChar .)* 10 | / "//" (!eolChar .)* 11 | 12 | multiLineComment 13 | = "/*" (!"*/" .)* "*/" 14 | 15 | _ "whitespace" 16 | = (eol / whitespace / comment)* 17 | 18 | __ "whitespace" 19 | = (eol / whitespace / comment)+ 20 | 21 | eol 22 | = "\n" 23 | / "\r\n" 24 | / "\r" 25 | / "\u2028" 26 | / "\u2029" 27 | 28 | eolChar 29 | = [\n\r\u2028\u2029] 30 | 31 | whitespace "whitespace" 32 | = [ \t\v\f\r\n\u00A0\uFEFF\u1680\u180E\u2000-\u200A\u202F\u205F\u3000] 33 | -------------------------------------------------------------------------------- /lib/error-formatter.js: -------------------------------------------------------------------------------- 1 | 2 | var colors = require('colors'); 3 | 4 | 5 | 6 | // pretty print error 7 | module.exports = function(err, source_code, useColors) { 8 | 9 | var output = []; 10 | 11 | var k = function(a) { return a; }; 12 | var bold = k 13 | , yellow_bold = k 14 | , red_bold = k 15 | , underline = k 16 | , green = k 17 | ; 18 | 19 | if(useColors) { 20 | bold = function(str) { return colors.bold(str); } 21 | red_bold = function(str) { return colors.bold(colors.red(str)); } 22 | yellow_bold = function(str) { return colors.bold(colors.yellow(str)); } 23 | underline = function(str) { return colors.underline(str); } 24 | green = function(str) { return colors.green(str); } 25 | } 26 | 27 | output.push(red_bold(err.toString())); 28 | 29 | if(err.line) { 30 | output.push([ 31 | "At line ", bold(err.line), 32 | " column ", bold(err.column), 33 | " offset ", bold(err.offset), 34 | ].join('')); 35 | } 36 | if(err.expected) 37 | output.push("Expected one of:", yellow_bold(err.expected.join(' '))); 38 | 39 | if(source_code && err.line) { 40 | output.push(underline("Source listing:")); 41 | var lines = source_code.split('\n'); 42 | var start = Math.max(err.line-6, 0); 43 | lines = lines.slice(start, err.line+25); 44 | for(var i=0,l=lines.length; i> operators 87 | ParseOptions.prototype.bitShiftExpression = function(expr) { return expr; }; 88 | 89 | // handles binary + (addition) and - (subtraction) 90 | ParseOptions.prototype.addExpression = function(expr) { return expr; }; 91 | 92 | // handles binary operators: 93 | // - '*' - multiplication 94 | // - '/' - division 95 | // - 'DIV' - integer division 96 | // - '%' or 'MOD' - modulo - integer division remainder 97 | ParseOptions.prototype.mulDivExpression = function(expr) { return expr; }; 98 | 99 | ParseOptions.prototype.bitwiseXorExpression = function(expr) { return expr; }; 100 | ParseOptions.prototype.unaryExpression = function(expr) { return expr; }; 101 | 102 | // hadles IS [NOT] (NULL | TRUE | FALSE | UNKNOWN) 103 | ParseOptions.prototype.isExpression = function(expr) { return expr; }; 104 | 105 | // handles COLLATION 'name' 106 | ParseOptions.prototype.collateExpression = function(expr) { return expr; }; 107 | 108 | // handles BINARY modifier 109 | ParseOptions.prototype.modifierBinaryExpression = function(expr) { return expr; }; 110 | 111 | 112 | 113 | ParseOptions.prototype.resolveConstantExpressionObject = function(expr) { 114 | if(expr.constant) { 115 | return expr; 116 | } if(this.isNullValue(expr)) { 117 | return expr; 118 | } else if(expr.unary) { 119 | return this.resolveConstantExpressionUnary(expr); 120 | } else if(expr.operators) { 121 | return this.resolveConstantExpressionChain(expr); 122 | } else if(expr.binary) { 123 | return this.resolveConstantExpressionBinary(expr); 124 | } 125 | 126 | throw new Error("Cannot resolve expression as a constant: " + expr); 127 | }; 128 | 129 | 130 | ParseOptions.prototype.resolveConstantExpressionUnary = function(expr) { 131 | switch(expr.unary) { 132 | case '+': 133 | return + this.resolveConstantExpression(expr.expression); 134 | case '-': 135 | return - this.resolveConstantExpression(expr.expression); 136 | default: 137 | throw new Error("Cannot resolve expression as a constant: unary '"+expr.unary+"' operator"); 138 | } 139 | }; 140 | 141 | 142 | ParseOptions.prototype.resolveConstantExpressionBinary = function(expr) { 143 | var e1 = this.resolveConstantExpression(expr.expressions[0]); 144 | var e2 = this.resolveConstantExpression(expr.expressions[1]); 145 | switch(expr.binary) { 146 | case '+': 147 | return e1 + e2; 148 | case '-': 149 | return e1 - e2; 150 | case '*': 151 | return e1 * e2; 152 | case '/': 153 | return e1 / e2; 154 | case 'DIV': 155 | return Math.floor(e1 / e2); 156 | case '%': 157 | case 'MOD': 158 | return e1 % e2; 159 | default: 160 | throw new Error("Cannot resolve expression as a constant: unary '"+expr.unary+"' operator"); 161 | } 162 | throw new Error("Cannot resolve expression as a constant: binary '"+expr.binary+"' operator"); 163 | }; 164 | 165 | 166 | ParseOptions.prototype.getOperatorsAssociativity = function(operators) { 167 | if(ParseOptions.prototype.getOperatorsAssociativity.right.indexOf(operators[0]) >= 0) 168 | return 'right'; 169 | 170 | return 'left'; 171 | }; 172 | ParseOptions.prototype.getOperatorsAssociativity.right = [ ':=' ]; 173 | 174 | 175 | 176 | ParseOptions.prototype.resolveConstantExpressionChain = function(expr) { 177 | if(expr.operators.length === 1) { 178 | expr.binary = expr.operators[0]; 179 | delete expr.operators; 180 | return this.resolveConstantExpressionBinary(expr); 181 | } 182 | 183 | var operators = expr.operators; 184 | var expressions = expr.expressions; 185 | if(this.getOperatorsAssociativity(expr.operators) === 'right') { 186 | operators.reverse(); 187 | expressions.reverse(); 188 | } 189 | 190 | var result, i, l = operators.length; 191 | result = expressions.shift(); 192 | for(i=0; i', 'set input from argument instead of file or stdin') 16 | .option('-t, --ast [file]', 'output parsed abstract syntax tree as JSON') 17 | .option('--input-encoding ', 'input encoding (default utf8)') 18 | .option('--output-encoding ', 'output encoding (default utf8)') 19 | .option('--start-rule ', 'grammar start rule') 20 | .parse(process.argv); 21 | 22 | 23 | if(program.args.length === 0) { 24 | if(typeof program.eval !== 'undefined') { 25 | processInput(program.eval); 26 | } else { 27 | setInputStream(process.stdin); 28 | } 29 | } else if(program.args.length === 1) { 30 | processInput(fs.readFileSync(program.args[0], program.inputEncoding || 'utf8')); 31 | } else { 32 | console.error("Invalid arguments, see --help"); 33 | process.exit(1); 34 | } 35 | 36 | 37 | function setInputStream(stream) { 38 | var data = []; 39 | stream.setEncoding(program.inputEncoding || 'utf8'); 40 | stream.on('data', function (chunk) { 41 | data.push(chunk); 42 | }); 43 | stream.once('end', function () { 44 | processInput(data.join('')); 45 | }); 46 | stream.resume(); 47 | } 48 | 49 | 50 | 51 | function processInput(text) { 52 | 53 | try { 54 | var parsed = sqljs.parse(text, program.startRule, new sqljs.ParseOptions); 55 | if(typeof parsed === 'undefined') 56 | throw new Error('Output is empty'); 57 | } catch(err) { 58 | console.error(sqljs.prettyError(err, text, use_colors)); 59 | return process.exit(1); 60 | } 61 | 62 | if(program.ast) { 63 | var jsonfile = (program.ast === true) 64 | ? process.stdout 65 | : fs.createWriteStream(program.ast, { 66 | flags: 'w', 67 | encoding: program.outputEncoding || 'utf8' 68 | }); 69 | 70 | jsonfile.write(JSON.stringify(parsed, null, 2)); 71 | jsonfile.write('\n'); 72 | 73 | if(jsonfile !== process.stdout) 74 | jsonfile.end(); 75 | 76 | } 77 | 78 | // require('repl').start().context.p = program; 79 | } -------------------------------------------------------------------------------- /lib/sqljs.js: -------------------------------------------------------------------------------- 1 | 2 | var parser = exports.parser = require('./sqljs-parser'); 3 | 4 | 5 | exports.parse = parser.parse.bind(parser); 6 | 7 | 8 | exports.ParseOptions = require('./parse-options'); 9 | 10 | 11 | exports.ParserError = exports.parser.SyntaxError; 12 | 13 | 14 | exports.prettyError = require('./error-formatter'); 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sqljs", 3 | "version": "0.0.0-6", 4 | "description": "SQL parser", 5 | "keywords": [ 6 | "database", 7 | "sql" 8 | ], 9 | "author": "Pavel Lang (https://github.com/sqljs)", 10 | "homepage": "https://github.com/sqljs/node-sqljs", 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/sqljs/node-sqljs.git" 14 | }, 15 | "bugs": { 16 | "url": "https://github.com/sqljs/node-sqljs/issues" 17 | }, 18 | "main": "./lib/sqljs", 19 | "bin": { 20 | "sqljs": "./bin/sqljs" 21 | }, 22 | "scripts": { 23 | "test": "make test" 24 | }, 25 | "dependencies": { 26 | "colors": "^1.0.3", 27 | "commander": "^2.7.1" 28 | }, 29 | "devDependencies": { 30 | "browserify": "^10.2.4", 31 | "nodeunit": "^0.9.1", 32 | "pegjs": "^0.7.0" 33 | }, 34 | "optionalDependencies": {}, 35 | "engines": { 36 | "node": ">=0.6.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/parser/09-01-01-string.js: -------------------------------------------------------------------------------- 1 | 2 | var rule_yields = require('./common/helper-rule-yields'); 3 | 4 | 5 | 6 | exports['Grammar: STRING "String": valid input'] = rule_yields.bind(null, 7 | 'STRING', [ 8 | ['""', ''], 9 | ['"A"', 'A'], 10 | ["''", ''], 11 | ["'A'", 'A'], 12 | ['"ěščřžýáíé"', 'ěščřžýáíé'], 13 | ['"\\\\ \\r \\n "', '\\ \r \n '], 14 | ['"A" \'B\' "C"\'D\' ', 'ABCD'], 15 | ['"\\%\\_"', '\\%\\_'], 16 | 17 | ['""""', '"'], 18 | ["''''", "'"], 19 | ["'I''m lucky'", "I'm lucky"], 20 | 21 | ["'\\x20'", ' ', {'STRING_HEX_ESCAPE': true}], 22 | ["'\\u0020'", ' ', {'STRING_UNICODE_ESCAPE': true}], 23 | ["'\\Q'", '\\Q', {'STRING_STRICT_ESCAPE': false, STRING_INVALID_ESCAPE_STRIP_BACKSLASH: false}], 24 | ["'\\Q'", 'Q', {'STRING_STRICT_ESCAPE': false, STRING_INVALID_ESCAPE_STRIP_BACKSLASH: true}], 25 | ] 26 | ); 27 | 28 | 29 | 30 | exports['Grammar: STRING "String": invalid input'] = rule_yields.bind(null, 31 | 'STRING', [ 32 | ["'\\Q'", Error, {'STRING_STRICT_ESCAPE': true}], 33 | ["'\\x20'", Error, {'STRING_STRICT_ESCAPE': true}], 34 | ["'\\u0020'", Error, {'STRING_STRICT_ESCAPE': true}], 35 | ] 36 | ); 37 | -------------------------------------------------------------------------------- /tests/parser/09-01-02-number.js: -------------------------------------------------------------------------------- 1 | 2 | var rule_yields = require('./common/helper-rule-yields'); 3 | 4 | 5 | 6 | exports['Grammar: NUMBER: valid input'] = rule_yields.bind(null, 7 | 'SIGNED_NUMBER', [ 8 | ['0', 0], 9 | ['00', 0], 10 | ['000', 0], 11 | ['1', 1], 12 | ['10', 10], 13 | ['010', 8, {ALLOW_OCTAL_NOTATION: true}], 14 | ['010', 10, {OCTAL_AS_DECIMAL: true}], 15 | ['0xa', 10], 16 | ['0x10', 16], 17 | ['0xff', 255], 18 | ['0xFF', 255], 19 | ['0xfF', 255], 20 | ['0xabcdef', 0xabcdef], 21 | ['0xABCDEF', 0xabcdef], 22 | ['0b10', 2], 23 | ['0b00010000', 16], 24 | ['0b10000000000000000000000000000000000000000000000000000000000000000', 0x10000000000000000], 25 | 26 | ['+0', 0], 27 | ['+00', 0], 28 | ['+000', 0], 29 | ['+1', 1], 30 | ['+10', 10], 31 | ['+010', 8, {ALLOW_OCTAL_NOTATION: true}], 32 | ['+010', 10, {OCTAL_AS_DECIMAL: true}], 33 | ['+0xa', 10], 34 | ['+0x10', 16], 35 | ['+0xff', 255], 36 | ['+0xFF', 255], 37 | ['+0xfF', 255], 38 | ['+0xabcdef', 0xabcdef], 39 | ['+0xABCDEF', 0xabcdef], 40 | ['+0b10', 2], 41 | ['+0b00010000', 16], 42 | ['+0b10000000000000000000000000000000000000000000000000000000000000000', 0x10000000000000000], 43 | 44 | ['-0', 0], 45 | ['-00', 0], 46 | ['-000', 0], 47 | ['-1', -1], 48 | ['-10', -10], 49 | ['-010', -8, {ALLOW_OCTAL_NOTATION: true}], 50 | ['-010', -10, {OCTAL_AS_DECIMAL: true}], 51 | ['-0xa', -10], 52 | ['-0x10', -16], 53 | ['-0xff', -255], 54 | ['-0xFF', -255], 55 | ['-0xfF', -255], 56 | ['-0xabcdef', -0xabcdef], 57 | ['-0xABCDEF', -0xabcdef], 58 | ['-0b10', -2], 59 | ['-0b00010000', -16], 60 | ['-0b10000000000000000000000000000000000000000000000000000000000000000', -0x10000000000000000], 61 | 62 | ['0.', 0.], ['.0', .0], ['0.0', 0.0], 63 | ['1.', 1.], ['.2', .2], ['3.4', 3.4], 64 | ['1e1', 1e1], ['.2e1', .2e1], ['3.4e1', 3.4e1], 65 | ['1e+1', 1e+1], ['.2e+1', .2e+1], ['3.4e+1', 3.4e+1], 66 | ['1e-1', 1e-1], ['.2e-1', .2e-1], ['3.4e-1', 3.4e-1], 67 | ['1.e1', 1.e1], ['.2e1', .2e1], ['3.4e1', 3.4e1], 68 | ['1.e+1', 1.e+1], ['.2e+1', .2e+1], ['3.4e+1', 3.4e+1], 69 | ['1.e-1', 1.e-1], ['.2e-1', .2e-1], ['3.4e-1', 3.4e-1], 70 | 71 | ['02.', 2.], ['.0', .0], ['0.0', 0.0], 72 | ['12.', 12.], ['.12', .12], ['3.4', 3.4], 73 | ['12e13', 12e13], ['.12e13', .12e13], ['3.4e1', 3.4e1], 74 | ['12e+13', 12e+13], ['.12e+13', .12e+13], ['3.4e+1', 3.4e+1], 75 | ['12e-13', 12e-13], ['.12e-13', .12e-13], ['3.4e-1', 3.4e-1], 76 | ['12.e13', 12.e13], ['0.12e13', .12e13], 77 | ['12.e+13', 12.e+13], ['0.12e+13', .12e+13], 78 | ['12.e-13', 12.e-13], ['0.12e-13', .12e-13], 79 | ] 80 | ); 81 | 82 | 83 | 84 | exports['Grammar: NUMBER: invalid input'] = rule_yields.bind(null, 85 | 'SIGNED_NUMBER', [ 86 | ['08', Error], 87 | ['0x', Error], 88 | ['0b', Error], 89 | ['010', Error, {ALLOW_OCTAL_NOTATION: false}], 90 | ] 91 | ); 92 | 93 | -------------------------------------------------------------------------------- /tests/parser/09-02-00-identifiers.js: -------------------------------------------------------------------------------- 1 | 2 | var rule_yields = require('./common/helper-rule-yields'); 3 | 4 | 5 | 6 | exports['Grammar: ID "Identifier": valid input'] = rule_yields.bind(null, 7 | 'ID', [ 8 | 'a', 'aa', 'aaa', 9 | 'a1', '_1', 10 | '_$aaa', '$_aaa', 11 | ['`x-x-x`', 'x-x-x'], 12 | ['`ěščřžýáíé`', 'ěščřžýáíé'], 13 | ['`_``_`', '_`_'], 14 | ] 15 | ); 16 | -------------------------------------------------------------------------------- /tests/parser/09-05-00-expression.js: -------------------------------------------------------------------------------- 1 | 2 | var rule_yields = require('./common/helper-rule-yields'); 3 | 4 | 5 | 6 | exports['Grammar: Expression: literals: integer'] = rule_yields.bind(null, 7 | 'EXPRESSION', [ 8 | ['0', 0], 9 | ['1', 1], 10 | ['123', 123], 11 | ], 12 | 'deepEqual' 13 | ); 14 | 15 | 16 | 17 | exports['Grammar: Expression: literals: float'] = rule_yields.bind(null, 18 | 'EXPRESSION', [ 19 | ['0.0', 0.0], 20 | ['1.1', 1.1], 21 | ['.1', .1], 22 | ], 23 | 'deepEqual' 24 | ); 25 | 26 | 27 | 28 | exports['Grammar: Expression: add'] = rule_yields.bind(null, 29 | 'EXPRESSION', [ 30 | ['1+2', { operators: [ '+' ], expressions: [ 1, 2 ] }], 31 | ['1-2', { operators: [ '-' ], expressions: [ 1, 2 ] }], 32 | ['1+2+3+4', { operators: [ '+', '+', '+' ], expressions: [ 1, 2, 3, 4 ] }], 33 | ['1+2-3+4-5', { operators: [ '+', '-', '+', '-' ], expressions: [ 1, 2, 3, 4, 5 ] }], 34 | ['1+-2', { operators: [ '+' ], expressions: [ 1, { unary: '-', expression: 2 } ] }], 35 | ['1-+2', { operators: [ '-' ], expressions: [ 1, { unary: '+', expression: 2 } ] }], 36 | ['1++2', { operators: [ '+' ], expressions: [ 1, { unary: '+', expression: 2 } ] }], 37 | ['1- -2', { operators: [ '-' ], expressions: [ 1, { unary: '-', expression: 2 } ] }], 38 | [' 1 - - 2 ', { operators: [ '-' ], expressions: [ 1, { unary: '-', expression: 2 } ] }], 39 | ], 40 | 'deepEqual' 41 | ); 42 | -------------------------------------------------------------------------------- /tests/parser/13-01-08-create-database.js: -------------------------------------------------------------------------------- 1 | var rule_yields = require('./common/helper-rule-yields'); 2 | 3 | var result1 = [ 4 | { 5 | statement: 'CREATE', 6 | what: 'DATABASE', 7 | database: 'db' 8 | } 9 | ]; 10 | 11 | var result2 = [ 12 | { 13 | statement: 'CREATE', 14 | what: 'DATABASE', 15 | database: 'db', 16 | ifNotExists: true 17 | } 18 | ]; 19 | 20 | exports['Grammar: CREATE DATABASE: valid input'] = rule_yields.bind(null, 21 | undefined, [ 22 | [ 23 | 'CREATE DATABASE db', 24 | result1 25 | ], [ 26 | 'CREATE DATABASE db;', 27 | result1 28 | ], [ 29 | 'CREATE DATABASE IF NOT EXISTS db', 30 | result2 31 | ], [ 32 | 'CREATE DATABASE IF NOT EXISTS db;', 33 | result2 34 | ] 35 | ], 'deepEqual' 36 | ); 37 | -------------------------------------------------------------------------------- /tests/parser/13-01-14-create-table.js: -------------------------------------------------------------------------------- 1 | 2 | var rule_yields = require('./common/helper-rule-yields'); 3 | 4 | 5 | var result1 = [ 6 | { 7 | statement: 'CREATE', 8 | what: 'TABLE', 9 | schema: undefined, 10 | table: 'table', 11 | definitions: [] 12 | } 13 | ]; 14 | 15 | var result2 = [ 16 | { 17 | statement: 'CREATE', 18 | what: 'TABLE', 19 | schema: undefined, 20 | table: 'table', 21 | definitions: [ { name: 'col1' } ] 22 | } 23 | ]; 24 | 25 | var result3 = [ 26 | { 27 | statement: 'CREATE', 28 | what: 'TABLE', 29 | schema: undefined, 30 | table: 'table', 31 | definitions: [ { notNull: false, name: 'col1' } ] 32 | } 33 | ]; 34 | 35 | var result4 = [ 36 | { 37 | statement: 'CREATE', 38 | what: 'TABLE', 39 | schema: undefined, 40 | table: 'table', 41 | definitions: [ { notNull: true, name: 'col1' } ] 42 | } 43 | ]; 44 | 45 | var result5 = [ 46 | { 47 | statement: 'CREATE', 48 | what: 'TABLE', 49 | schema: undefined, 50 | table: 'table', 51 | definitions: [ { notNull: true, type: 'INT', name: 'col1' } ] 52 | } 53 | ]; 54 | 55 | var result6 = [ 56 | { 57 | statement: 'CREATE', 58 | what: 'TABLE', 59 | schema: 'schema', 60 | table: 'table', 61 | temporary: true, 62 | definitions: [] 63 | } 64 | ]; 65 | 66 | var result7 = [ 67 | { 68 | statement: 'CREATE', 69 | what: 'TABLE', 70 | schema: undefined, 71 | table: 'table', 72 | definitions: [ { type: 'INT', name: 'col1' } ] 73 | } 74 | ]; 75 | 76 | var result8 = [ 77 | { 78 | statement: 'CREATE', 79 | what: 'TABLE', 80 | schema: undefined, 81 | table: 'table', 82 | definitions: [ { type: 'INT', name: 'col1' } ] 83 | } 84 | ]; 85 | 86 | var result9 = [ 87 | { 88 | statement: 'CREATE', 89 | what: 'TABLE', 90 | schema: undefined, 91 | table: 'a b c', 92 | definitions: [ { type: 'INT', name: 'x y z' } ] 93 | } 94 | ]; 95 | 96 | exports['Grammar: CREATE TABLE: valid input'] = rule_yields.bind(null, 97 | undefined, [ 98 | [ 99 | 'CREATE TABLE table ()', 100 | result1 101 | ], [ 102 | 'CREATE TABLE table ();', 103 | result1 104 | ], [ 105 | 'CREATE TABLE table()', 106 | result1 107 | ], [ 108 | 'CREATE TABLE `table`()', 109 | result1 110 | ], [ 111 | 'CREATE TABLE table( )', 112 | result1 113 | ], [ 114 | 'CREATE TABLE table(col1)', 115 | result2 116 | ], [ 117 | 'CREATE TABLE table( col1)', 118 | result2 119 | ], [ 120 | 'CREATE TABLE table(col1 )', 121 | result2 122 | ], [ 123 | 'CREATE TABLE table( col1, )', 124 | result2 125 | ], [ 126 | 'CREATE TABLE table( col1 , )', 127 | result2 128 | ], [ 129 | 'CREATE TABLE table( col1 null, )', 130 | result3 131 | ], [ 132 | 'CREATE TABLE table( col1 null , )', 133 | result3 134 | ], [ 135 | 'CREATE TABLE table( col1 not null, )', 136 | result4 137 | ], [ 138 | 'CREATE TABLE table( col1 noTnUll, )', 139 | result4 140 | ], [ 141 | 'CREATE TABLE table( col1 int not null, )', 142 | result5 143 | ], [ 144 | 'CREATE TABLE table( col1 not null int, )', 145 | result5 146 | ], [ 147 | 'CREATE TEMP TABLE schema.table ()', 148 | result6 149 | ], [ 150 | 'CREATE TEMP TABLE schema.table IF NOT EXISTS ()', 151 | [{ 152 | statement: 'CREATE', 153 | what: 'TABLE', 154 | schema: 'schema', 155 | table: 'table', 156 | temporary: true, 157 | definitions: [], 158 | ifNotExists: true 159 | }] 160 | ], [ 161 | 'CREATE TABLE table ("col1" integer);', 162 | result7 163 | ], [ 164 | 'CREATE TABLE "table" (col1 integer)', 165 | result8 166 | ], [ 167 | 'CREATE TABLE "table" (col1 varbinary(16))', 168 | [{ 169 | statement: 'CREATE', 170 | what: 'TABLE', 171 | schema: undefined, 172 | table: 'table', 173 | definitions: [ { type: 'VARBINARY', length: 16, name: 'col1' } ] 174 | }] 175 | ], [ 176 | 'CREATE TABLE "table" (col1 char binary(16))', 177 | [{ 178 | statement: 'CREATE', 179 | what: 'TABLE', 180 | schema: undefined, 181 | table: 'table', 182 | definitions: [ { type: 'BINARY', length: 16, name: 'col1' } ] 183 | }] 184 | ], [ 185 | 'CREATE TABLE "table" (col1 mediumblob)', 186 | [{ 187 | statement: 'CREATE', 188 | what: 'TABLE', 189 | schema: undefined, 190 | table: 'table', 191 | definitions: [ { type: 'MEDIUMBLOB', name: 'col1' } ] 192 | }] 193 | ], [ 194 | 'CREATE TABLE "table" (col1 long text)', 195 | [{ 196 | statement: 'CREATE', 197 | what: 'TABLE', 198 | schema: undefined, 199 | table: 'table', 200 | definitions: [ { type: 'LONGTEXT', name: 'col1' } ] 201 | }] 202 | ], [ 203 | 'CREATE TABLE "table" (col1 text)', 204 | [{ 205 | statement: 'CREATE', 206 | what: 'TABLE', 207 | schema: undefined, 208 | table: 'table', 209 | definitions: [ { type: 'TEXT', name: 'col1' } ] 210 | }] 211 | ], [ 212 | 'ALTER TABLE `t` ADD PRIMARY KEY (`type`,`id`)', 213 | [{ 214 | statement: 'ALTER', 215 | what: 'TABLE', 216 | table: 't', 217 | ignore: false, 218 | specifications: [{ 219 | type: 'CONSTRAINT', 220 | constraint: 'PRIMARY KEY', 221 | constraintName: undefined, 222 | columns: [ 'type', 'id' ], 223 | alter_type: 'ADD' 224 | }] 225 | }] 226 | ], [ 227 | 'CREATE TABLE "a b c" ("x y z" integer)', 228 | result9 229 | ] 230 | ], 'deepEqual' 231 | ); 232 | -------------------------------------------------------------------------------- /tests/parser/common/helper-rule-yields.js: -------------------------------------------------------------------------------- 1 | 2 | var sqljs = require('../../../.'); 3 | 4 | 5 | module.exports = function(rule_name, values, test_method, test) { 6 | 7 | if(!test) { 8 | test = test_method; 9 | test_method = undefined; 10 | } 11 | 12 | if(!test_method) 13 | test_method = test.strictEqual; 14 | if(typeof test_method === 'string') 15 | test_method = test[test_method]; 16 | 17 | test.expect(values.length); 18 | values.forEach(function(vals){ 19 | var input, actual, expected, opts; 20 | 21 | opts = new sqljs.ParseOptions(); 22 | 23 | if(Array.isArray(vals)) { 24 | input = vals[0]; 25 | expected = vals[1]; 26 | if(vals[2]) { 27 | if(vals[2].isParseOptions) { 28 | opts = vals[2]; 29 | } else { 30 | for(var key in vals[2]) 31 | opts[key] = vals[2][key]; 32 | } 33 | } 34 | } else { 35 | input = expected = vals; 36 | } 37 | 38 | actual = null; 39 | 40 | if(expected === Error || expected === SyntaxError || expected === sqljs.SyntaxError) { 41 | test.throws(function() { 42 | actual = sqljs.parse(input, rule_name, opts); 43 | }, function(err) { 44 | return err instanceof expected; 45 | }, "Parser input: '"+input+"'"); 46 | } else { 47 | try { 48 | actual = sqljs.parse(input, rule_name, opts); 49 | test_method.call(test, actual, expected, "Parser input: '"+input+"'"); 50 | } catch(err) { 51 | test.ok(false, "Exception: " + sqljs.prettyError(err, input, true)); 52 | } 53 | } 54 | 55 | }); 56 | 57 | test.done(); 58 | }; 59 | 60 | --------------------------------------------------------------------------------