├── LICENSE ├── README.md ├── Syntax.rules.txt ├── _config.yml ├── bnf2html.perl.txt ├── bnf2html.pl ├── bnf2yacc.perl.txt ├── bnf2yacc.pl ├── index.html ├── outer-joins.html ├── sql-2003-1.bnf ├── sql-2003-1.bnf.html ├── sql-2003-2.bnf ├── sql-2003-2.bnf.html ├── sql-2003-2.ebnf ├── sql-2003-2.ebnf.readme ├── sql-2003-core-features.html ├── sql-2003-noncore-features.html ├── sql-2016.ebnf ├── sql-2016.ebnf.readme ├── sql-92.bnf ├── sql-92.bnf.html ├── sql-99.bnf ├── sql-99.bnf.html ├── sql-bnf.mk └── webcode-1.09.tgz /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ron Savage 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BNF Grammars for SQL-92, SQL-99 and SQL-2003 2 | 3 | This repository contains the BNF (Backus-Naur Form) grammars for three versions of standard SQL — SQL-92, SQL-99 and SQL-2003. 4 | 5 | You should be able to find a version of this site with 'active HTML' at: 6 | 7 | * https://ronsavage.github.io/SQL/ 8 | 9 | It may not be the most recent release, but the technical content is mostly valid. 10 | The download link is not functional — you can obtain the material for the latest 11 | release from https://github.com/ronsavage/SQL/releases/latest. 12 | 13 | ** !! Syntax Rules 14 | 15 | Regarding the text '!! See the Syntax Rules': That is literally what it says in the PDF 16 | containing the standard. 17 | 18 | For an extract of the standard about these rules see the file 'Syntax.rules.txt'. 19 | 20 | *This project is still in transition to GitHub. 21 | The links in this README.md file lead to the pages in the GitHub source tree. 22 | Most of them will display the HTML source — not a rendered HTML image. 23 | There probably are ways around that; we're learning GitHub as we go.* 24 | 25 | For a long time, this material was hosted by Ron Savage at 26 | [http://savage.net.au/SQL](http://savage.net.au) — many thanks, Ron! — 27 | but that site now points to here. 28 | 29 | At the moment, the suggested method of operation is: 30 | 31 | * Clone this repository to your machine — e.g. into the `/home/somebody/SQL` directory 32 | * Point your browser to `file:///home/somebody/SQL/index.html`. 33 | 34 | This should give you full HTML access to the material. 35 | Alternatively, you can download the latest release of this material 36 | (instead of cloning the repo), and then extract that into a directory 37 | and point your browser to the `index.html` file in that directory. 38 | 39 | Yes: it is sub-optimal. 40 | Yes: we'll fix it when we know how to fix it. 41 | 42 | ## SQL-92 43 | 44 | The file [`sql-92.bnf.html`](sql-92.bnf.html) is a heavily hyperlinked HTML 45 | version of the BNF grammar for SQL-92 (ISO/IEC 9075:1992 - Database Language - 46 | SQL). 47 | 48 | The plain text file [`sql-92.bnf`](sql-92.bnf), from which it was 49 | automatically converted, is more useful (read legible) for reading 50 | without a browser. 51 | 52 | ## SQL-99 53 | 54 | The file [`sql-99.bnf.html`](sql-99.bnf.html) is a heavily hyperlinked HTML 55 | version of the BNF grammar for SQL-99 (ISO/IEC 9075-2:1999 - Database 56 | Languages - SQL - Part 2: Foundation (SQL/Foundation)). 57 | 58 | The plain text file [`sql-99.bnf`](sql-99.bnf), from which it was 59 | automatically converted, is more useful (read legible) for reading 60 | without a browser. 61 | 62 | ## SQL-2003 63 | 64 | The file [`sql-2003-2.bnf.html`](sql-2003-2.bnf.html) is a heavily hyperlinked HTML 65 | version of the BNF grammar for SQL-2003 (ISO/IEC 9075-2:2003 - Database 66 | Languages - SQL - Part 2: Foundation (SQL/Foundation)). 67 | 68 | The plain text file [`sql-2003-2.bnf`](sql-2003-2.bnf), from which it was 69 | automatically converted, is more useful (read legible) for reading 70 | without a browser. 71 | 72 | 73 | There is a separate file [`sql-2003-1.bnf.html`](sql-2003-1.bnf.html) for 74 | the information from ISO/IEC 9075-1:2003 - Database Languages - SQL - Part 75 | 1: Framework (SQL/Framework). 76 | 77 | It was automatically converted from the plain text file [`sql-2003-1.bnf`](sql-2003-1.bnf), 78 | which is more useful (read legible) for reading without a browser. 79 | 80 | 81 | Also available: 82 | 83 |
  • SQL 2003 Core Features
  • 84 |
  • SQL 2003 Non-Core Features
  • 85 |
    86 | 87 | ## Informix OUTER Join Syntax 88 | 89 | The file [`outer-joins.html`](outer-joins.html) is an explanation of the 90 | non-standard Informix OUTER join syntax and semantics. 91 | 92 | ## Conversion tools 93 | 94 | 95 | The plain text was converted to HTML by the Perl script 96 | [`bnf2html`](bnf2html.perl.txt) which you may use if you wish. 97 | The `bnf2html` script also uses the C program 98 | WEBCODE version 1.09 99 | which you can download as a [gzipped tar file](webcode-1.09.tgz). 100 | 101 | See also [`bnf2yacc`](bnf2yacc.perl.txt), an experimental 102 | script to convert BNF into an outline Yacc grammar. 103 | The generated grammar typically includes some unacceptable tokens, such 104 | as _`%token 0`_, that should be handled by the lexical analyzer 105 | rather than the grammar. 106 | The SQL standard includes such rules as grammar rules; consequently, you won't 107 | get a clean Yacc grammar from the SQL BNF files. 108 | 109 | _(The Perl scripts should normally be renamed after downloading.)_ 110 | 111 | ## Download 112 | 113 | You should be able to get the downloadable version of the latest release of this 114 | repository from the releases area: 115 | 116 | * https://github.com/ronsavage/SQL/releases/latest 117 | 118 | ## SQL 2016 Released 119 | 120 | [ISO/IEC JTC 1/SC 32 Publishes Updated SQL Database Language Standard](https://www.ansi.org/news_publications/news_story?menuid=7&articleid=753a952d-1244-415b-bb92-0010750bb8cd) — SQL 2016. 121 | 122 | 123 |
    124 | Please send feedback to Jonathan Leffler 125 | ( jonathan.leffler@gmail.com ) _and_ 126 | Ron Savage ( ron@savage.net.au ). 127 | 128 | Last modified: 129 | 13th March 2017 130 | -------------------------------------------------------------------------------- /Syntax.rules.txt: -------------------------------------------------------------------------------- 1 | That (!! See the Syntax Rules) is literally what it says in the PDF 2 | containing the standard. And the Syntax Rules are one part of the verbiage 3 | in the standard supporting the grammar — specifying what it means. The 4 | first such place where it occurs is: 5 | 6 | <#xref-space> ::= !! See the Syntax Rules. 7 | 8 | And if I go to the full pDF, I find 5.1 says: 9 | 10 | Information technology — Database languages — SQL — Part 2: Foundation 11 | (SQL/Foundation) 12 | 13 | Syntax Rules 14 | 15 | 1) Every character set shall contain a character that is equivalent 16 | to U+0020. 17 | 18 | Access Rules 19 | 20 | None. 21 | 22 | General Rules 23 | 24 | 1) There is a one-to-one correspondence between the symbols contained in 25 | and the symbols contained in such that, for all i, the symbol defined as the i-th 27 | alternative for corresponds to the symbol 28 | defined as the i-th alternative for . 29 | 30 | Conformance Rules 31 | 32 | None. 33 | And, in this case, that's all it has to say. Each section of the standard 34 | has sub-headings 'Function', 'Format' (containing the BNF), 'Syntax Rules', 35 | 'Access Rules', 'General Rules' (usually the biggest section), and 36 | 'Conformance Rules'. The next pair of occurrences are: 37 | 38 | ::= 39 | 40 | 41 | 42 | | 43 | 44 | ::= !! See the Syntax Rules 45 | 46 | ::= !! See the Syntax Rules 47 | 48 | 49 | 50 | That's pulled from the PDF, not the HTML. This time, we find: 51 | 52 | Syntax Rules 53 | 54 | 1) An is any character in the Unicode General Category 55 | classes "Lu", "Ll", "Lt", "Lm", 56 | 57 | "Lo", or "Nl". 58 | 59 | NOTE 58 — The Unicode General Category classes "Lu", "Ll", "Lt", "Lm", 60 | "Lo", and "Nl" are assigned to Unicode characters 61 | 62 | that are, respectively, upper-case letters, lower-case letters, title-case 63 | letters, modifier letters, other letters, and letter numbers. 64 | 65 | 2) An is U+00B7, "Middle Dot", or any character in the 66 | Unicode General Category classes 67 | 68 | "Mn", "Mc", "Nd", "Pc", or "Cf". 69 | 70 | NOTE 59 — The Unicode General Category classes "Mn", "Mc", "Nd", "Pc", and 71 | "Cf" are assigned to Unicode characters that 72 | 73 | are, respectively, nonspacing marks, spacing combining marks, decimal 74 | numbers, connector punctuations, and formatting codes. 75 | 76 | Very detailed specification stuff — but not something you can easily put 77 | into the BNF. It belongs in the lexical analyzer, probably. 78 | 79 | Another example — not to do with characters this time: 80 | <#xref-preparable 81 | implementation-defined statement> ::= !! See the Syntax Rules. 82 | 83 | Here the further information is: 84 | 85 | 3) The Format and Syntax Rules for are implementation-defined. 87 | 88 | And another pair of them: 89 | 90 | <#xref-SQLSTATE class value> ::= 91 | <#SQLSTATE char> <#SQLSTATE char> !! See the Syntax Rules. 92 | 93 | <#xref-SQLSTATE subclass value> ::= <#SQLSTATE char> <#SQLSTATE char> 95 | <#SQLSTATE char> !! See the Syntax Rules. 96 | The Syntax Rules say: 97 | 98 | 3) In the values of and , 99 | there shall be no 100 | 101 | between the s. 102 | 103 | 4) The values of and shall 104 | correspond to class values 105 | 106 | and subclass values, respectively, specified in Table 32, "SQLSTATE class 107 | and subclass values". 108 | 109 | Expanding on this last example, here is the copy'n'paste of the Syntax 110 | Rules through the end of the section: 111 | 112 | Syntax Rules 113 | 114 | 1) SQLWARNING, NOT FOUND, and SQLEXCEPTION correspond to SQLSTATE class 115 | values corresponding 116 | 117 | to categories W, N, and X in Table 32, "SQLSTATE class and subclass values", 118 | respectively. 119 | 120 | ©ISO/IEC 2003 – All rights reserved Embedded SQL 1001 121 | 122 | ISO/IEC 9075-2:2003 (E) 123 | 124 | 20.2 125 | 126 | 2) An contained in an applies to an contained in that if and 130 | only if the appears after the that has 133 | condition C in the text sequence 134 | 135 | of the and no other E that satisfies one 137 | 138 | of the following conditions appears between the and the in the text sequence of the . 142 | 143 | Let D be the contained in E. 144 | 145 | a) D is the same as C. 146 | 147 | b) D is a and belongs to the same class to which C belongs. 148 | 149 | c) D contains an , but does not contain an , and 151 | 152 | E contains the same that C contains. 153 | 154 | d) D contains the that corresponds to integrity 155 | constraint violation and C 156 | 157 | contains CONSTRAINT. 158 | 159 | 3) In the values of and , 160 | there shall be no 161 | 162 | between the s. 163 | 164 | 4) The values of and shall 165 | correspond to class values 166 | 167 | and subclass values, respectively, specified in Table 32, "SQLSTATE class 168 | and subclass values". 169 | 170 | 5) If an specifies a , then the 171 | , , or of the shall be such that a 174 | host language GO TO statement 175 | 176 | specifying that , , or 177 | is valid at every 178 | 179 | to which the 180 | applies. 181 | 182 | NOTE 445 — 183 | 184 | If an is contained in an , then the of a should specify a that is a label_name in the 188 | containing . 189 | 190 | If an is contained in an , then the of a 192 | 193 | should specify a that is a label in the containing 194 | . 195 | 196 | If an is contained in an , then the of a 198 | 199 | should specify a that is a section-name or 200 | an unqualified paragraph-name in the containing 201 | 202 | . 203 | 204 | If an is contained in an , then the of a should be an that is the statement label of an 208 | executable statement that appears in the same program 209 | 210 | unit as the . 211 | 212 | If an is contained in an , then the of a 214 | 215 | should be a gotoargument that is the statement label of an 216 | executable statement that appears in the same . 219 | 220 | If an is contained in an , then the of a should be an that is a label. 224 | 225 | If an is contained in an , then the of a should specify either a or a . 230 | 231 | Case: 232 | 233 | — If is specified, then the 234 | should be a label constant in the containing 235 | 236 | . 237 | 238 | ISO/IEC 9075-2:2003 (E) 239 | 240 | 20.2 241 | 242 | 1002 Foundation (SQL/Foundation) ©ISO/IEC 2003 – All rights reserved 243 | 244 | — If is specified, then the should be a PL/I label variable declared in 246 | 247 | the containing . 248 | 249 | Access Rules 250 | 251 | None. 252 | 253 | General Rules 254 | 255 | 1) Immediately after the execution of an STMT in 256 | an 257 | 258 | that returns an SQLSTATE value other than successful completion: 259 | 260 | a) Let E be the set of s that are contained 261 | in the containing STMT, that applies to STMT, and that specifies a 264 | that is . 267 | 268 | b) Let CV and SCV be respectively the values of the class and subclass of 269 | the SQLSTATE value that 270 | 271 | indicates the result of the . 272 | 273 | c) If the execution of the caused the violation 274 | of one or more constraints or 275 | 276 | assertions, then: 277 | 278 | i) Let ECN be the set of s in E that 279 | specify CONSTRAINT and 280 | 281 | the of a constraint that was violated by execution of 282 | STMT. 283 | 284 | ii) If ECN contains more than one , then an 285 | implementationdependent 286 | 287 | is chosen from ECN; otherwise, the single 288 | 289 | in ECN is chosen. 290 | 291 | iii) A GO TO statement of the host language is performed, specifying the 292 | , 293 | 294 | , or of the specified 295 | in the chosen from ECN. 298 | 299 | d) Otherwise: 300 | 301 | i) Let ECS be the set of s in E that 302 | specify SQLSTATE, an 303 | 304 | , and an . 305 | 306 | ii) If ECS contains an EY that specifies 307 | an identical to CV and an identical to SCV, 310 | then a GO TO 311 | 312 | statement of the host language is performed, specifying the , , or of the specified in the 316 | EY. 319 | 320 | iii) Otherwise: 321 | 322 | 1) Let EC be the set of s in E that specify 323 | SQLSTATE and 324 | 325 | an without an . 326 | 327 | 2) If EC contains an EY that specifies an 328 | identical to CV, then a GO TO statement of the host language 331 | is performed, 332 | 333 | ©ISO/IEC 2003 – All rights reserved Embedded SQL 1003 334 | 335 | ISO/IEC 9075-2:2003 (E) 336 | 337 | 20.2 338 | 339 | specifying the , , or 340 | of 341 | 342 | the specified in the EY. 343 | 344 | 3) Otherwise: 345 | 346 | A) Let EX be the set of s in E that specify 347 | SQLEXCEPTION. 348 | 349 | B) If EX contains an EY and CV belongs to 350 | Category 351 | 352 | X in Table 32, "SQLSTATE class and subclass values", then a GO TO statement 353 | of the 354 | 355 | host language is performed, specifying the , , or of the specified in the EY. 362 | 363 | C) Otherwise: 364 | 365 | I) Let EW be the set of s in E that specify 366 | SQLWARNING. 367 | 368 | II) If EW contains an EY and CV belongs to 369 | 370 | Category W in Table 32, "SQLSTATE class and subclass values", then a GO 371 | 372 | TO statement of the host language is performed, specifying the , , or of the 376 | 377 | specified in the EY. 378 | 379 | III) Otherwise, let ENF be the set of s in 380 | E that 381 | 382 | specify NOT FOUND. If ENF contains an 383 | 384 | EY and CV belongs to Category N in Table 32, "SQLSTATE class and subclass 385 | 386 | values", then a GO TO statement of the host language is performed, 387 | specifying 388 | 389 | the , , or of 391 | 392 | the specified in the EY. 393 | 394 | Conformance Rules 395 | 396 | 1) Without Feature B041, "Extensions to embedded SQL exception 397 | declarations", conforming SQL language 398 | 399 | shall not contain an that contains either SQLSTATE or 400 | CONSTRAINT. 401 | 402 | 2) Without Feature F491, "Constraint management", conforming SQL language 403 | shall not contain an that contains a . 406 | 407 | ISO/IEC 9075-2:2003 (E) 408 | 409 | 20.2 410 | 411 | 1004 412 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-merlot -------------------------------------------------------------------------------- /bnf2html.perl.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | # 3 | # @(#)$Id: bnf2html.pl,v 3.16 2017/11/14 06:53:22 jleffler Exp $ 4 | # 5 | # Convert SQL-92, SQL-99 BNF plain text file into hyperlinked HTML. 6 | 7 | use strict; 8 | use warnings; 9 | use POSIX qw(strftime); 10 | #use Data::Dumper; 11 | 12 | use constant debug => 0; 13 | 14 | my(%rules); # Indexed by rule names w/o angle-brackets; each entry is a ref to a hash. 15 | my(%keywords); # Index by keywords; each entry is a ref to a hash. 16 | my(%names); # Indexed by rule names w/o angle-brackets; each entry is a ref to an array of line numbers 17 | 18 | sub top 19 | { 20 | print "

    Top

    \n\n"; 21 | } 22 | 23 | # Usage: add_rule_name(\%names, $rulename, $.); 24 | sub add_rule_name 25 | { 26 | my($reflist, $lhs, $line) = @_; 27 | #print "\nrulename = $lhs; line = $line\n"; 28 | if (defined ${$reflist}{$lhs}) 29 | { 30 | #print Data::Dumper->Dump([ ${$reflist}{$lhs} ], qw[ ${$reflist}{$lhs} ]); 31 | #print Data::Dumper->Dump([ \@{${$reflist}{$lhs}} ], qw[ \@{${$reflist}{$lhs}} ]); 32 | my @lines = @{${$reflist}{$lhs}}; 33 | print STDERR "\n$0: Rule <$lhs> at line $line already seen at line(s) ", join(", ", @lines), "\n\n"; 34 | } 35 | else 36 | { 37 | ${$reflist}{$lhs} = []; 38 | } 39 | push @{${$reflist}{$lhs}}, $line; 40 | } 41 | 42 | # Usage: add_entry(\%keywords, $keyword, $rule); 43 | # Usage: add_entry(\%rules, $rhs, $rule); 44 | sub add_entry 45 | { 46 | my($reflist, $lhs, $rhs) = @_; 47 | ${$reflist}{$lhs} = {} unless defined ${$reflist}{$lhs}; 48 | ${$reflist}{$lhs}{$rhs} = 1; 49 | } 50 | 51 | sub add_refs 52 | { 53 | my($def, $tail) = @_; 54 | print "\n\n" if debug; 55 | return if $tail =~ m/^!!/; 56 | return if $tail =~ m/^&(?:lt|gt|amp);$/; 57 | while ($tail) 58 | { 59 | $tail =~ s/^\s*//; 60 | if ($tail =~ m%^\<([-:/\w\s]+)\>%) 61 | { 62 | print "\n" if debug; 63 | add_entry(\%rules, $1, $def); 64 | $tail =~ s%^\<([-:/\w\s]+)\>%%; 65 | } 66 | elsif ($tail =~ m%^([-:/\w]+)%) 67 | { 68 | my($token) = $1; 69 | print "\n" if debug; 70 | add_entry(\%keywords, $token, $def) if $token =~ m%[[:alpha:]][[:alpha:]]% || $token eq 'C'; 71 | $tail =~ s%^[-:/\w]+%%; 72 | } 73 | else 74 | { 75 | # Otherwise, it is punctuation (such as the BNF metacharacters). 76 | $tail =~ s%^[^-:/\w]%%; 77 | } 78 | } 79 | } 80 | 81 | # NB: webcode replaces tabs with blanks! 82 | open( my $WEBCODE, "-|", "webcode @ARGV") or die "$!"; 83 | 84 | # Read first line of file - use as title in head and in H1 heading in body 85 | $_ = <$WEBCODE>; 86 | exit 0 unless defined($_); 87 | chomp; 88 | 89 | # Is it wicked to use double quoting with single quotes, as in qq'text'? 90 | # It is used quite extensively in this script - beware! 91 | print qq'\n'; 92 | print "\n"; 93 | print "\n\n"; 94 | print " $_ \n\n\n\n"; 95 | print "

    $_

    \n\n"; 96 | print qq' \n'; 97 | 98 | print "
    \n"; 99 | print qq' Cross-Reference: rules \n'; 100 | print "
    \n"; 101 | print qq' Cross-Reference: keywords \n'; 102 | print "
    \n"; 103 | 104 | sub rcs_id 105 | { 106 | my($id) = @_; 107 | $id =~ s%^(@\(#\))?\$[I]d: %%o; 108 | $id =~ s% \$$%%o; 109 | $id =~ s%,v % %o; 110 | $id =~ s%\w+ Exp( \w+)?$%%o; 111 | my(@words) = split / /, $id; 112 | my($version) = "file $words[0] version $words[1] dated $words[2] $words[3]"; 113 | return $version; 114 | } 115 | 116 | sub iso8601_format 117 | { 118 | my($tm) = @_; 119 | my $today = strftime("%Y-%m-%d %H:%M:%S+00:00", gmtime($tm)); 120 | return($today); 121 | } 122 | 123 | # Print hrefs for non-terminals and keywords. 124 | # Also substitute /* Nothing */ for an absence of productions between alternatives. 125 | sub print_tail 126 | { 127 | my($tail, $tcount) = @_; 128 | while ($tail) 129 | { 130 | my($newtail); 131 | if ($tail =~ m%^\s+%) 132 | { 133 | my($spaces) = $&; 134 | $newtail = $'; 135 | print "\n" if debug; 136 | $spaces =~ s% {4,8}%    %g; 137 | print $spaces; 138 | # Spaces are not a token - don't count them! 139 | } 140 | elsif ($tail =~ m%^'[^']*'% || $tail =~ m%^"[^"]*"% || $tail =~ m%^!!.*$%) 141 | { 142 | # Quoted literal - print and ignore. 143 | # Or meta-expression... 144 | my($quote) = $&; 145 | $newtail = $'; 146 | print "\n" if debug; 147 | $quote =~ s%!!.*% $quote %; 148 | print $quote; 149 | $tcount++; 150 | } 151 | elsif ($tail =~ m%^\<([-:/\w\s]+)\>%) 152 | { 153 | my($nonterm) = $&; 154 | $newtail = $'; 155 | print "\n" if debug; 156 | $nonterm =~ s%\<([-:/\w\s]+)\>%\<$1\>%; 157 | print " $nonterm"; 158 | $tcount++; 159 | } 160 | elsif ($tail =~ m%^[\w_]([-._\w]*[\w_])?%) 161 | { 162 | # Keyword 163 | my($keyword) = $&; 164 | $newtail = $'; 165 | print "\n" if debug; 166 | print(($keyword =~ m/^\d\d+$/) ? $keyword : qq' $keyword '); 167 | $tcount++; 168 | } 169 | else 170 | { 171 | # Metacharacter, string literal, etc. 172 | $tail =~ m%\S+%; 173 | my($symbol) = $&; 174 | $newtail = $'; 175 | print "\n" if debug; 176 | if ($symbol eq '|') 177 | { 178 | print "/* Nothing */ " if $tcount == 0; 179 | $tcount = 0; 180 | } 181 | else 182 | { 183 | $symbol =~ s%...omitted...%/* $& */%i; 184 | $tcount++; 185 | } 186 | print " $symbol"; 187 | } 188 | $tail = $newtail; 189 | } 190 | return($tcount); 191 | } 192 | 193 | sub undo_web_coding 194 | { 195 | my($line) = @_; 196 | $line =~ s%>%>%g; 197 | $line =~ s%<%<%g; 198 | $line =~ s%&%&%g; 199 | return $line; 200 | } 201 | 202 | my $hr_count = 0; 203 | my $tcount = 0; # Ick! 204 | my $def; # Current rule 205 | 206 | # Don't forget - the input has been web-encoded! 207 | 208 | while (<$WEBCODE>) 209 | { 210 | chomp; 211 | next if /^===*$/o; 212 | s/\s+$//o; # Remove trailing white space 213 | if (/^$/) 214 | { 215 | print "\n"; 216 | } 217 | elsif (/^---*$/) 218 | { 219 | print "
    \n"; 220 | } 221 | elsif (/^--@@\s*(.*)$/) 222 | { 223 | my $comment = undo_web_coding($1); 224 | print "\n"; 225 | } 226 | elsif (/^@.#..Id:/) 227 | { 228 | # Convert what(1) string identifier into version information 229 | my $id = '$Id: bnf2html.pl,v 3.16 2017/11/14 06:53:22 jleffler Exp $'; 230 | my($v1) = rcs_id($_); 231 | my $v2 = rcs_id($id); 232 | print "

    \n"; 233 | print "Derived from $v1\n"; 234 | my $today = iso8601_format(time); 235 | print "
    \n"; 236 | print "Generated on $today by $v2\n"; 237 | print "

    \n"; 238 | } 239 | elsif (/\s+::=/) 240 | { 241 | # Definition line 242 | $def = $_; 243 | $def =~ s%\<([-:/()\w\s]+)\>.*%$1%; 244 | my($tail) = $_; 245 | $tail =~ s%.*::=\s*%%; 246 | print qq'

    <$def>    ::='; 247 | $tcount = 0; 248 | add_rule_name(\%names, $def, $.); 249 | if ($def eq "vertical bar") 250 | { 251 | # Needs special case attention to avoid a /* Nothing */ comment appearing. 252 | # Problem pointed out by Jens Odborg (jho1965us@gmail.com) 2016-04-14. 253 | # This builds knowledge of the SQL language definition into this script; 254 | # ugly, but trying to fix it in the print_tail function is probably worse. 255 | print "  |"; 256 | } 257 | elsif ($tail) 258 | { 259 | add_refs($def, $tail); 260 | print "  "; 261 | $tcount = print_tail($tail, $tcount); 262 | } 263 | print "\n"; 264 | } 265 | elsif (/^\s/) 266 | { 267 | # Expansion line 268 | add_refs($def, $_); 269 | print "
    "; 270 | $tcount = print_tail($_, $tcount); 271 | } 272 | elsif (m/^--[\/]?(\w+)/) 273 | { 274 | # Pseudo-directive line in lower-case 275 | # Print a 'Top' link before


    tags except first. 276 | top if /--hr/ && $hr_count++ > 0; 277 | s%--(/?[a-z][a-z\d]*)%<$1>%; 278 | s%\<([-:/\w\s]+)\>%\<$1\>%g; 279 | print "$_\n"; 280 | } 281 | elsif (m%^--##%) 282 | { 283 | $_ = undo_web_coding($_); 284 | s%^--##\s*%%; 285 | print "$_\n"; 286 | } 287 | elsif (m/^--%start\s+(\w+)/) 288 | { 289 | # Designated start symbol 290 | my $start = $1; 291 | print qq'

    Start symbol: $start

    \n'; 292 | } 293 | else 294 | { 295 | # Anything unrecognized passed through unchanged! 296 | print "$_\n"; 297 | } 298 | } 299 | 300 | close $WEBCODE; 301 | 302 | # Print index of initial letters for keywords. 303 | sub print_index_key 304 | { 305 | my($prefix, @keys) = @_; 306 | my %letters = (); 307 | foreach my $keyword (@keys) 308 | { 309 | my $initial = uc substr $keyword, 0, 1; 310 | $letters{$initial} = 1; 311 | } 312 | foreach my $letter ('A' .. 'Z') 313 | { 314 | if (defined($letters{$letter})) 315 | { 316 | print qq' $letter \n'; 317 | } 318 | else 319 | { 320 | print qq'$letter\n'; 321 | } 322 | } 323 | print "\n"; 324 | } 325 | 326 | ### Generate cross-reference tables 327 | 328 | { 329 | print "
    \n\n"; 330 | print "
    \n"; 331 | print qq'\n'; 332 | print "

    Cross-Reference Table: Rules

    \n"; 333 | 334 | print_index_key("rules", keys %rules); 335 | 336 | print "\n"; 337 | print "\n"; 338 | my %letters = (); 339 | 340 | foreach my $rule (sort { uc $a cmp uc $b } keys %rules) 341 | { 342 | my $initial = uc substr $rule, 0, 1; 343 | my $label = ""; 344 | if (!defined($letters{$initial})) 345 | { 346 | $letters{$initial} = 1; 347 | $label = qq' '; 348 | } 349 | print qq'\n \n\n"; 357 | } 358 | print "
    Rule (non-terminal) Rules using it
    $label $rule '; 350 | my $pad = ""; 351 | foreach my $ref (sort { uc $a cmp uc $b } keys %{$rules{$rule}}) 352 | { 353 | print qq'$pad <$ref> \n'; 354 | $pad = " "; 355 | } 356 | print "
    \n"; 359 | print "
    \n"; 360 | top; 361 | } 362 | 363 | { 364 | print "
    \n"; 365 | print qq'\n'; 366 | print "

    Cross-Reference Table: Keywords

    \n"; 367 | 368 | print_index_key("keywords", keys %keywords); 369 | 370 | print "\n"; 371 | print "\n"; 372 | my %letters = (); 373 | foreach my $keyword (sort { uc $a cmp uc $b } keys %keywords) 374 | { 375 | my $initial = uc substr $keyword, 0, 1; 376 | my $label = ""; 377 | if (!defined($letters{$initial})) 378 | { 379 | $letters{$initial} = 1; 380 | $label = qq' '; 381 | } 382 | print qq'\n \n\n"; 390 | } 391 | print "
    Keyword Rules using it
    $label $keyword '; 383 | my $pad = ""; 384 | foreach my $ref (sort { uc $a cmp uc $b } keys %{$keywords{$keyword}}) 385 | { 386 | print qq'$pad <$ref> \n'; 387 | $pad = " "; 388 | } 389 | print "
    \n"; 392 | print "
    \n"; 393 | top; 394 | print "
    \n"; 395 | } 396 | 397 | printf "%s\n", q'Please send feedback to Jonathan Leffler:'; 398 | printf "%s\n", q' jonathan.leffler@gmail.com .'; 399 | 400 | print "\n\n\n"; 401 | 402 | __END__ 403 | 404 | =pod 405 | 406 | =head1 PROGRAM 407 | 408 | bnf2html - Convert (ISO SQL) BNF Notation to Hyperlinked HTML 409 | 410 | =head1 SYNTAX 411 | 412 | bnf2html [file ...] 413 | 414 | =head1 DESCRIPTION 415 | 416 | The bnf2html filters the annotated BNF (Backus-Naur Form) from its input 417 | files and converts it into HTML on standard output. 418 | 419 | The HTML is heavily hyperlinked. 420 | Each rule (LHS) links to a table of other rules where it is used on the 421 | RHS. 422 | Similarly, each symbol on the RHS is linked to the rule that defines it. 423 | Thus, it is possible to find where items are used and defined quite 424 | easily. 425 | 426 | =head1 INPUT FORMAT 427 | 428 | This script is adapted to the BNF notation using in the SQL standard 429 | (ISO/IEC 9075:2003, for example). 430 | It also takes various forms of annotations. 431 | 432 | The first line of the file is used as the title in the head section. 433 | It is also used as the text for a H1 header at the top of the body. 434 | 435 | Lines consisting of two or more equal signs are ignored. 436 | 437 | Lines consisting of two or more dashes are converted to a horizontal 438 | rule. 439 | 440 | Lines starting with the SCCS identification string '@(#)' are used to 441 | print version information about the file converted and the script doing 442 | the converting. 443 | 444 | Lines containing space, colon, colon, equals are treated as rules. 445 | 446 | Lines starting with white space are treated as continuations of a rule. 447 | 448 | Lines starting dash, dash, (optionally a slash) and then one or more tag 449 | letters are converted into an HTML start or end tag. 450 | 451 | Any line starting dash, dash, hash, hash has any HTML entities 452 | introduced by the WEBCODE program removed. 453 | 454 | The should be at most one line starting '--%start'; this indicates the 455 | start symbol for the bnf2yacc converter, but is effectively ignored by 456 | bnf2html. 457 | 458 | Any other line is passed through verbatim. 459 | 460 | =head1 AUTHOR 461 | 462 | Jonathan Leffler 463 | 464 | =cut 465 | -------------------------------------------------------------------------------- /bnf2html.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | # 3 | # @(#)$Id: bnf2html.pl,v 3.16 2017/11/14 06:53:22 jleffler Exp $ 4 | # 5 | # Convert SQL-92, SQL-99 BNF plain text file into hyperlinked HTML. 6 | 7 | use strict; 8 | use warnings; 9 | use POSIX qw(strftime); 10 | #use Data::Dumper; 11 | 12 | use constant debug => 0; 13 | 14 | my(%rules); # Indexed by rule names w/o angle-brackets; each entry is a ref to a hash. 15 | my(%keywords); # Index by keywords; each entry is a ref to a hash. 16 | my(%names); # Indexed by rule names w/o angle-brackets; each entry is a ref to an array of line numbers 17 | 18 | sub top 19 | { 20 | print "

    Top

    \n\n"; 21 | } 22 | 23 | # Usage: add_rule_name(\%names, $rulename, $.); 24 | sub add_rule_name 25 | { 26 | my($reflist, $lhs, $line) = @_; 27 | #print "\nrulename = $lhs; line = $line\n"; 28 | if (defined ${$reflist}{$lhs}) 29 | { 30 | #print Data::Dumper->Dump([ ${$reflist}{$lhs} ], qw[ ${$reflist}{$lhs} ]); 31 | #print Data::Dumper->Dump([ \@{${$reflist}{$lhs}} ], qw[ \@{${$reflist}{$lhs}} ]); 32 | my @lines = @{${$reflist}{$lhs}}; 33 | print STDERR "\n$0: Rule <$lhs> at line $line already seen at line(s) ", join(", ", @lines), "\n\n"; 34 | } 35 | else 36 | { 37 | ${$reflist}{$lhs} = []; 38 | } 39 | push @{${$reflist}{$lhs}}, $line; 40 | } 41 | 42 | # Usage: add_entry(\%keywords, $keyword, $rule); 43 | # Usage: add_entry(\%rules, $rhs, $rule); 44 | sub add_entry 45 | { 46 | my($reflist, $lhs, $rhs) = @_; 47 | ${$reflist}{$lhs} = {} unless defined ${$reflist}{$lhs}; 48 | ${$reflist}{$lhs}{$rhs} = 1; 49 | } 50 | 51 | sub add_refs 52 | { 53 | my($def, $tail) = @_; 54 | print "\n\n" if debug; 55 | return if $tail =~ m/^!!/; 56 | return if $tail =~ m/^&(?:lt|gt|amp);$/; 57 | while ($tail) 58 | { 59 | $tail =~ s/^\s*//; 60 | if ($tail =~ m%^\<([-:/\w\s]+)\>%) 61 | { 62 | print "\n" if debug; 63 | add_entry(\%rules, $1, $def); 64 | $tail =~ s%^\<([-:/\w\s]+)\>%%; 65 | } 66 | elsif ($tail =~ m%^([-:/\w]+)%) 67 | { 68 | my($token) = $1; 69 | print "\n" if debug; 70 | add_entry(\%keywords, $token, $def) if $token =~ m%[[:alpha:]][[:alpha:]]% || $token eq 'C'; 71 | $tail =~ s%^[-:/\w]+%%; 72 | } 73 | else 74 | { 75 | # Otherwise, it is punctuation (such as the BNF metacharacters). 76 | $tail =~ s%^[^-:/\w]%%; 77 | } 78 | } 79 | } 80 | 81 | # NB: webcode replaces tabs with blanks! 82 | open( my $WEBCODE, "-|", "webcode @ARGV") or die "$!"; 83 | 84 | # Read first line of file - use as title in head and in H1 heading in body 85 | $_ = <$WEBCODE>; 86 | exit 0 unless defined($_); 87 | chomp; 88 | 89 | # Is it wicked to use double quoting with single quotes, as in qq'text'? 90 | # It is used quite extensively in this script - beware! 91 | print qq'\n'; 92 | print "\n"; 93 | print "\n\n"; 94 | print " $_ \n\n\n\n"; 95 | print "

    $_

    \n\n"; 96 | print qq' \n'; 97 | 98 | print "
    \n"; 99 | print qq' Cross-Reference: rules \n'; 100 | print "
    \n"; 101 | print qq' Cross-Reference: keywords \n'; 102 | print "
    \n"; 103 | 104 | sub rcs_id 105 | { 106 | my($id) = @_; 107 | $id =~ s%^(@\(#\))?\$[I]d: %%o; 108 | $id =~ s% \$$%%o; 109 | $id =~ s%,v % %o; 110 | $id =~ s%\w+ Exp( \w+)?$%%o; 111 | my(@words) = split / /, $id; 112 | my($version) = "file $words[0] version $words[1] dated $words[2] $words[3]"; 113 | return $version; 114 | } 115 | 116 | sub iso8601_format 117 | { 118 | my($tm) = @_; 119 | my $today = strftime("%Y-%m-%d %H:%M:%S+00:00", gmtime($tm)); 120 | return($today); 121 | } 122 | 123 | # Print hrefs for non-terminals and keywords. 124 | # Also substitute /* Nothing */ for an absence of productions between alternatives. 125 | sub print_tail 126 | { 127 | my($tail, $tcount) = @_; 128 | while ($tail) 129 | { 130 | my($newtail); 131 | if ($tail =~ m%^\s+%) 132 | { 133 | my($spaces) = $&; 134 | $newtail = $'; 135 | print "\n" if debug; 136 | $spaces =~ s% {4,8}%    %g; 137 | print $spaces; 138 | # Spaces are not a token - don't count them! 139 | } 140 | elsif ($tail =~ m%^'[^']*'% || $tail =~ m%^"[^"]*"% || $tail =~ m%^!!.*$%) 141 | { 142 | # Quoted literal - print and ignore. 143 | # Or meta-expression... 144 | my($quote) = $&; 145 | $newtail = $'; 146 | print "\n" if debug; 147 | $quote =~ s%!!.*% $quote %; 148 | print $quote; 149 | $tcount++; 150 | } 151 | elsif ($tail =~ m%^\<([-:/\w\s]+)\>%) 152 | { 153 | my($nonterm) = $&; 154 | $newtail = $'; 155 | print "\n" if debug; 156 | $nonterm =~ s%\<([-:/\w\s]+)\>%\<$1\>%; 157 | print " $nonterm"; 158 | $tcount++; 159 | } 160 | elsif ($tail =~ m%^[\w_]([-._\w]*[\w_])?%) 161 | { 162 | # Keyword 163 | my($keyword) = $&; 164 | $newtail = $'; 165 | print "\n" if debug; 166 | print(($keyword =~ m/^\d\d+$/) ? $keyword : qq' $keyword '); 167 | $tcount++; 168 | } 169 | else 170 | { 171 | # Metacharacter, string literal, etc. 172 | $tail =~ m%\S+%; 173 | my($symbol) = $&; 174 | $newtail = $'; 175 | print "\n" if debug; 176 | if ($symbol eq '|') 177 | { 178 | print "/* Nothing */ " if $tcount == 0; 179 | $tcount = 0; 180 | } 181 | else 182 | { 183 | $symbol =~ s%...omitted...%/* $& */%i; 184 | $tcount++; 185 | } 186 | print " $symbol"; 187 | } 188 | $tail = $newtail; 189 | } 190 | return($tcount); 191 | } 192 | 193 | sub undo_web_coding 194 | { 195 | my($line) = @_; 196 | $line =~ s%>%>%g; 197 | $line =~ s%<%<%g; 198 | $line =~ s%&%&%g; 199 | return $line; 200 | } 201 | 202 | my $hr_count = 0; 203 | my $tcount = 0; # Ick! 204 | my $def; # Current rule 205 | 206 | # Don't forget - the input has been web-encoded! 207 | 208 | while (<$WEBCODE>) 209 | { 210 | chomp; 211 | next if /^===*$/o; 212 | s/\s+$//o; # Remove trailing white space 213 | if (/^$/) 214 | { 215 | print "\n"; 216 | } 217 | elsif (/^---*$/) 218 | { 219 | print "
    \n"; 220 | } 221 | elsif (/^--@@\s*(.*)$/) 222 | { 223 | my $comment = undo_web_coding($1); 224 | print "\n"; 225 | } 226 | elsif (/^@.#..Id:/) 227 | { 228 | # Convert what(1) string identifier into version information 229 | my $id = '$Id: bnf2html.pl,v 3.16 2017/11/14 06:53:22 jleffler Exp $'; 230 | my($v1) = rcs_id($_); 231 | my $v2 = rcs_id($id); 232 | print "

    \n"; 233 | print "Derived from $v1\n"; 234 | my $today = iso8601_format(time); 235 | print "
    \n"; 236 | print "Generated on $today by $v2\n"; 237 | print "

    \n"; 238 | } 239 | elsif (/\s+::=/) 240 | { 241 | # Definition line 242 | $def = $_; 243 | $def =~ s%\<([-:/()\w\s]+)\>.*%$1%; 244 | my($tail) = $_; 245 | $tail =~ s%.*::=\s*%%; 246 | print qq'

    <$def>    ::='; 247 | $tcount = 0; 248 | add_rule_name(\%names, $def, $.); 249 | if ($def eq "vertical bar") 250 | { 251 | # Needs special case attention to avoid a /* Nothing */ comment appearing. 252 | # Problem pointed out by Jens Odborg (jho1965us@gmail.com) 2016-04-14. 253 | # This builds knowledge of the SQL language definition into this script; 254 | # ugly, but trying to fix it in the print_tail function is probably worse. 255 | print "  |"; 256 | } 257 | elsif ($tail) 258 | { 259 | add_refs($def, $tail); 260 | print "  "; 261 | $tcount = print_tail($tail, $tcount); 262 | } 263 | print "\n"; 264 | } 265 | elsif (/^\s/) 266 | { 267 | # Expansion line 268 | add_refs($def, $_); 269 | print "
    "; 270 | $tcount = print_tail($_, $tcount); 271 | } 272 | elsif (m/^--[\/]?(\w+)/) 273 | { 274 | # Pseudo-directive line in lower-case 275 | # Print a 'Top' link before


    tags except first. 276 | top if /--hr/ && $hr_count++ > 0; 277 | s%--(/?[a-z][a-z\d]*)%<$1>%; 278 | s%\<([-:/\w\s]+)\>%\<$1\>%g; 279 | print "$_\n"; 280 | } 281 | elsif (m%^--##%) 282 | { 283 | $_ = undo_web_coding($_); 284 | s%^--##\s*%%; 285 | print "$_\n"; 286 | } 287 | elsif (m/^--%start\s+(\w+)/) 288 | { 289 | # Designated start symbol 290 | my $start = $1; 291 | print qq'

    Start symbol: $start

    \n'; 292 | } 293 | else 294 | { 295 | # Anything unrecognized passed through unchanged! 296 | print "$_\n"; 297 | } 298 | } 299 | 300 | close $WEBCODE; 301 | 302 | # Print index of initial letters for keywords. 303 | sub print_index_key 304 | { 305 | my($prefix, @keys) = @_; 306 | my %letters = (); 307 | foreach my $keyword (@keys) 308 | { 309 | my $initial = uc substr $keyword, 0, 1; 310 | $letters{$initial} = 1; 311 | } 312 | foreach my $letter ('A' .. 'Z') 313 | { 314 | if (defined($letters{$letter})) 315 | { 316 | print qq' $letter \n'; 317 | } 318 | else 319 | { 320 | print qq'$letter\n'; 321 | } 322 | } 323 | print "\n"; 324 | } 325 | 326 | ### Generate cross-reference tables 327 | 328 | { 329 | print "
    \n\n"; 330 | print "
    \n"; 331 | print qq'\n'; 332 | print "

    Cross-Reference Table: Rules

    \n"; 333 | 334 | print_index_key("rules", keys %rules); 335 | 336 | print "\n"; 337 | print "\n"; 338 | my %letters = (); 339 | 340 | foreach my $rule (sort { uc $a cmp uc $b } keys %rules) 341 | { 342 | my $initial = uc substr $rule, 0, 1; 343 | my $label = ""; 344 | if (!defined($letters{$initial})) 345 | { 346 | $letters{$initial} = 1; 347 | $label = qq' '; 348 | } 349 | print qq'\n \n\n"; 357 | } 358 | print "
    Rule (non-terminal) Rules using it
    $label $rule '; 350 | my $pad = ""; 351 | foreach my $ref (sort { uc $a cmp uc $b } keys %{$rules{$rule}}) 352 | { 353 | print qq'$pad <$ref> \n'; 354 | $pad = " "; 355 | } 356 | print "
    \n"; 359 | print "
    \n"; 360 | top; 361 | } 362 | 363 | { 364 | print "
    \n"; 365 | print qq'\n'; 366 | print "

    Cross-Reference Table: Keywords

    \n"; 367 | 368 | print_index_key("keywords", keys %keywords); 369 | 370 | print "\n"; 371 | print "\n"; 372 | my %letters = (); 373 | foreach my $keyword (sort { uc $a cmp uc $b } keys %keywords) 374 | { 375 | my $initial = uc substr $keyword, 0, 1; 376 | my $label = ""; 377 | if (!defined($letters{$initial})) 378 | { 379 | $letters{$initial} = 1; 380 | $label = qq' '; 381 | } 382 | print qq'\n \n\n"; 390 | } 391 | print "
    Keyword Rules using it
    $label $keyword '; 383 | my $pad = ""; 384 | foreach my $ref (sort { uc $a cmp uc $b } keys %{$keywords{$keyword}}) 385 | { 386 | print qq'$pad <$ref> \n'; 387 | $pad = " "; 388 | } 389 | print "
    \n"; 392 | print "
    \n"; 393 | top; 394 | print "
    \n"; 395 | } 396 | 397 | printf "%s\n", q'Please send feedback to Jonathan Leffler:'; 398 | printf "%s\n", q' jonathan.leffler@gmail.com .'; 399 | 400 | print "\n\n\n"; 401 | 402 | __END__ 403 | 404 | =pod 405 | 406 | =head1 PROGRAM 407 | 408 | bnf2html - Convert (ISO SQL) BNF Notation to Hyperlinked HTML 409 | 410 | =head1 SYNTAX 411 | 412 | bnf2html [file ...] 413 | 414 | =head1 DESCRIPTION 415 | 416 | The bnf2html filters the annotated BNF (Backus-Naur Form) from its input 417 | files and converts it into HTML on standard output. 418 | 419 | The HTML is heavily hyperlinked. 420 | Each rule (LHS) links to a table of other rules where it is used on the 421 | RHS. 422 | Similarly, each symbol on the RHS is linked to the rule that defines it. 423 | Thus, it is possible to find where items are used and defined quite 424 | easily. 425 | 426 | =head1 INPUT FORMAT 427 | 428 | This script is adapted to the BNF notation using in the SQL standard 429 | (ISO/IEC 9075:2003, for example). 430 | It also takes various forms of annotations. 431 | 432 | The first line of the file is used as the title in the head section. 433 | It is also used as the text for a H1 header at the top of the body. 434 | 435 | Lines consisting of two or more equal signs are ignored. 436 | 437 | Lines consisting of two or more dashes are converted to a horizontal 438 | rule. 439 | 440 | Lines starting with the SCCS identification string '@(#)' are used to 441 | print version information about the file converted and the script doing 442 | the converting. 443 | 444 | Lines containing space, colon, colon, equals are treated as rules. 445 | 446 | Lines starting with white space are treated as continuations of a rule. 447 | 448 | Lines starting dash, dash, (optionally a slash) and then one or more tag 449 | letters are converted into an HTML start or end tag. 450 | 451 | Any line starting dash, dash, hash, hash has any HTML entities 452 | introduced by the WEBCODE program removed. 453 | 454 | The should be at most one line starting '--%start'; this indicates the 455 | start symbol for the bnf2yacc converter, but is effectively ignored by 456 | bnf2html. 457 | 458 | Any other line is passed through verbatim. 459 | 460 | =head1 AUTHOR 461 | 462 | Jonathan Leffler 463 | 464 | =cut 465 | -------------------------------------------------------------------------------- /bnf2yacc.perl.txt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | # 3 | # @(#)$Id: bnf2yacc.pl,v 1.16 2017/11/14 06:53:22 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*(\.\.\.omitted\.\.\.)\s*%o) 79 | { 80 | # Something omitted from the grammar. 81 | # Triple punctuation detected before double. 82 | my $str = "/* $1 */"; 83 | push @rhs, $str; 84 | last; 85 | } 86 | elsif ($tail =~ m{^(\s*([-.<=>|]{2})\s*)$}o) 87 | { 88 | # Double-punctuation (non-metacharacters) 89 | # .., <=, >=, <>, ||, -> 90 | my $p = $2; 91 | print "DP: $p\n" if debug; 92 | $tail = substr $tail, length($1); 93 | $name = "'$p'"; 94 | push @rhs, $name; 95 | } 96 | elsif ($tail =~ m{^(\s*([][{}"'%&()*+,-./:;<=>?^_|])\s*)$}o) 97 | { 98 | # Punctuation (non-metacharacters) 99 | # Note that none of '@', '~', '!' or '\' have any significance in SQL 100 | my $p = $2; 101 | print "P: $p\n" if debug; 102 | $tail = substr $tail, length($1); 103 | $p = "\\'" if $p eq "'"; 104 | $name = "'$p'"; 105 | push @rhs, $name; 106 | } 107 | elsif ($tail =~ m%^(\s*('[^']*'))\s*%o || 108 | $tail =~ m%^(\s*("[^"]*"))\s*%o) 109 | { 110 | # Terminal in quotes - single or double. 111 | # (Possibly a multi-character string). 112 | my $q = $2; 113 | print "Q: $q\n" if debug; 114 | $tail = substr $tail, length($1); 115 | $q =~ m%^(['"])(.+)['"]$%o; 116 | # Expand multi-character string constants. 117 | # into repeated single-character constants. 118 | my($o) = $1; 119 | my($l) = $2; 120 | while (length($l)) 121 | { 122 | my($c) = substr $l, 0, 1; 123 | $name = "$o$c$o"; 124 | $l = substr $l, 1, length($l)-1; 125 | push @rhs, $name; 126 | } 127 | } 128 | elsif ($tail =~ m%^(\s*([{}\|\[\]]|\.\.\.)\s*)%o) 129 | { 130 | # Punctuation (metacharacters) 131 | my $p = $2; 132 | print "M: $p\n" if debug; 133 | $tail = substr $tail, length($1); 134 | $name = $p; 135 | push @rhs, $name; 136 | } 137 | elsif ($tail =~ m%^\s*!!%o) 138 | { 139 | # Exhortation to see the syntax rules - usually. 140 | my $str = "/* $tail */"; 141 | push @rhs, $str; 142 | last; 143 | } 144 | else 145 | { 146 | # Unknown! 147 | print "/* UNK: $tail */\n"; 148 | print STDERR "UNK:$.: $tail\n"; 149 | last; 150 | } 151 | } 152 | return(@rhs); 153 | } 154 | 155 | # Format a Yacc rule given LHS and RHS array 156 | sub record_rule 157 | { 158 | my($lhs, $comment, @rule) = @_; 159 | my($production) = ""; 160 | print "==>> record_rule ($lhs : @rule)\n" if debug; 161 | $production .= "/*\n" if $comment; 162 | $production .= "$lhs\n\t:\t"; 163 | my $pad = ""; 164 | my $br_count = 0; 165 | for (my $i = 0; $i <= $#rule; $i++) 166 | { 167 | my $item = $rule[$i]; 168 | print "==== item $item\n" if debug; 169 | if ($item eq "|" && $br_count == 0) 170 | { 171 | $production .= "\n\t|\t"; 172 | $pad = ""; 173 | } 174 | else 175 | { 176 | $production .= "$pad$item"; 177 | $pad = " "; 178 | $br_count++ if ($item eq '[' or $item eq '{'); 179 | $br_count-- if ($item eq ']' or $item eq '}'); 180 | } 181 | } 182 | $production .= "\n\t;\n"; 183 | $production .= "*/\n" if $comment; 184 | $production .= "\n"; 185 | print "$production" if debug; 186 | push @grammar, $production; 187 | print "<<== record_rule\n" if debug; 188 | } 189 | 190 | sub print_iterator 191 | { 192 | my($lhs,$rhs) = @_; 193 | my($production) = ""; 194 | print "==>> print_iterator ($lhs $rhs)\n" if debug; 195 | $production .= "$lhs\n\t:\t$rhs\n\t|\t$lhs $rhs\n\t;\n\n"; 196 | print "<<== print_iterator\n" if debug; 197 | push @grammar, $production; 198 | } 199 | 200 | # Process an optional item enclosed in square brackets 201 | sub find_balanced_bracket 202 | { 203 | my($lhs,@rhs) = @_; 204 | my(@rule) = ( "/* Nothing */", "|"); 205 | print "==>> find_balanced_bracket ($lhs : @rhs)\n" if debug; 206 | while (my $name = shift @rhs) 207 | { 208 | print " name = $name\n" if debug; 209 | if ($name eq ']') 210 | { 211 | # Found closing bracket 212 | # Terminate search 213 | last; 214 | } 215 | elsif ($name eq '[') 216 | { 217 | # Found nested optional clause 218 | my $tag = new_non_terminal('opt_'); 219 | @rhs = find_balanced_bracket($tag, @rhs); 220 | push @rule, $tag; 221 | } 222 | elsif ($name eq '{') 223 | { 224 | # Found start of sequence 225 | my $tag = new_non_terminal('seq_'); 226 | @rhs = find_balanced_brace($tag, @rhs); 227 | push @rule, $tag; 228 | } 229 | elsif ($name eq '}') 230 | { 231 | # Found unbalanced close brace. 232 | # Error! 233 | } 234 | elsif ($name eq '...') 235 | { 236 | # Found iteration. 237 | my $tag = new_non_terminal('lst_'); 238 | print "==== find_balanced_bracket: iterator (@rule)\n" if debug; 239 | my($old) = pop @rule; 240 | push @rule, $tag; 241 | print "==== find_balanced_bracket: iterator ($tag/$old - @rule)\n" if debug; 242 | print_iterator($tag, $old); 243 | } 244 | else 245 | { 246 | $name =~ s/^#//; 247 | push @rule, $name; 248 | $used{$name} = 1; 249 | } 250 | } 251 | record_rule($lhs, 0, @rule); 252 | print "<<== find_balanced_bracket: @rhs)\n" if debug; 253 | return(@rhs); 254 | } 255 | 256 | # Process an sequence item enclosed in curly braces 257 | sub find_balanced_brace 258 | { 259 | my($lhs,@rhs) = @_; 260 | my(@rule); 261 | print "==>> find_balanced_brace ($lhs : @rhs)\n" if debug; 262 | while (my $name = shift @rhs) 263 | { 264 | print " name = $name\n" if debug; 265 | if ($name eq '}') 266 | { 267 | # Found closing brace 268 | # Terminate search 269 | last; 270 | } 271 | elsif ($name eq '[') 272 | { 273 | # Found nested optional clause 274 | my $tag = new_non_terminal('opt_'); 275 | @rhs = find_balanced_bracket($tag, @rhs); 276 | push @rule, $tag; 277 | } 278 | elsif ($name eq '{') 279 | { 280 | # Found start of sequence 281 | my $tag = new_non_terminal('seq_'); 282 | @rhs = find_balanced_brace($tag, @rhs); 283 | push @rule, $tag; 284 | } 285 | elsif ($name eq ']') 286 | { 287 | # Found unbalanced close brace. 288 | # Error! 289 | } 290 | elsif ($name eq '...') 291 | { 292 | # Found iteration. 293 | my $tag = new_non_terminal('lst_'); 294 | print "==== find_balanced_brace: iterator (@rule)\n" if debug; 295 | my($old) = pop @rule; 296 | push @rule, $tag; 297 | print "==== find_balanced_brace: iterator ($tag/$old - @rule)\n" if debug; 298 | print_iterator($tag, $old); 299 | } 300 | else 301 | { 302 | $name =~ s/^#//; 303 | push @rule, $name; 304 | $used{$name} = 1; 305 | } 306 | } 307 | record_rule($lhs, 0, @rule); 308 | print "<<== find_balanced_brace: @rhs)\n" if debug; 309 | return(@rhs); 310 | } 311 | 312 | # Note that the [ and { parts are nice and easy because they are 313 | # balanced operators. The iteration operator ... is much harder to 314 | # process because it is a trailing modifier. When processing the list 315 | # of symbols, you need to establish whether there is a trailing iterator 316 | # after the current symbol, and modify the behaviour appropriately. 317 | sub process_rhs 318 | { 319 | my($lhs, $tail) = @_; 320 | my(@rhs) = scan_rhs($tail); 321 | print "==>> process_rhs ($lhs : @rhs)\n" if debug; 322 | # List parsed rule in output only if debugging. 323 | record_rule($lhs, 1, @rhs) if debug; 324 | my(@rule); 325 | while (my $name = shift @rhs) 326 | { 327 | print "name = $name\n" if debug; 328 | if ($name eq '[') 329 | { 330 | my $tag = new_non_terminal('opt_'); 331 | @rhs = find_balanced_bracket($tag, @rhs); 332 | push @rule, $tag; 333 | } 334 | elsif ($name eq ']') 335 | { 336 | # Found a close bracket for something unbalanced. 337 | # Error! 338 | } 339 | elsif ($name eq '{') 340 | { 341 | # Start of mandatory sequence of items, possibly containing alternatives. 342 | my $tag = new_non_terminal('seq_'); 343 | @rhs = find_balanced_brace($tag, @rhs); 344 | push @rule, $tag; 345 | } 346 | elsif ($name eq '}') 347 | { 348 | # Found a close brace for something unbalanced. 349 | # Error! 350 | } 351 | elsif ($name eq '|') 352 | { 353 | # End of one alternative and start of a new one. 354 | print "==== process_rhs: alternative $name\n" if debug; 355 | push @rule, $name; 356 | } 357 | elsif ($name eq '...') 358 | { 359 | # Found iteration. 360 | my $tag = new_non_terminal('lst_'); 361 | my($old) = pop @rule; 362 | push @rule, $tag; 363 | print "==== process_rhs: iterator\n" if debug; 364 | print_iterator($tag, $old); 365 | } 366 | elsif ($name =~ m/^#/) 367 | { 368 | # Keyword token 369 | print "==== process_rhs: token $name\n" if debug; 370 | $name =~ s/^#//; 371 | push @rule, $name; 372 | } 373 | else 374 | { 375 | # Non-terminal (or comment) 376 | print "==== process_rhs: non-terminal $name\n" if debug; 377 | push @rule, $name; 378 | } 379 | } 380 | print "==== process_rhs: @rule\n" if debug; 381 | record_rule($lhs, 0, @rule); 382 | print "<<== process_rhs\n" if debug; 383 | } 384 | 385 | sub count_unmatched_keys 386 | { 387 | my($ref1, $ref2) = @_; 388 | my(%keys) = %$ref1; 389 | my(%match) = %$ref2; 390 | my($count) = 0; 391 | foreach my $key (keys %keys) 392 | { 393 | $count++ unless defined $match{$key}; 394 | } 395 | return $count; 396 | } 397 | 398 | # ------------------------------------------------------------ 399 | 400 | open INPUT, "cat @ARGV |" or die "$!"; 401 | $_ = ; 402 | exit 0 unless defined($_); 403 | chomp; 404 | $heading = "%{\n/*\n** $_\n*/\n%}\n\n" unless m/^\s*$/; 405 | 406 | # Commentary appears in column 1. 407 | # Continuations of rules have a blank in column 1. 408 | # Blank lines, dash lines and equals lines separate rules (are not embedded within them).. 409 | 410 | while () 411 | { 412 | chomp; 413 | print "DBG:$.: $_\n" if debug; 414 | next if /^===*$/o; 415 | next if /^\s*$/o; # Blank lines 416 | next if /^---*$/o; # Horizontal lines 417 | if (/^--/o) 418 | { 419 | # Various HTML pseudo-directives 420 | if (m%^--/?\w+\b%) 421 | { 422 | print "/* $' */\n" if $'; 423 | } 424 | elsif (/^--%start (\w+)/) 425 | { 426 | $start = $1; 427 | print "/* Start symbol - $start */\n"; 428 | } 429 | elsif (/^--##/) 430 | { 431 | print "/* $_ */\n"; 432 | } 433 | else 434 | { 435 | print "/* Unrecognized 2: $_ */\n"; 436 | } 437 | } 438 | elsif (/^@.#..Id:/) 439 | { 440 | # Convert what(1) string identifier into version information 441 | s%^@.#..Id: %%; 442 | s% \$$%%; 443 | s%,v % %; 444 | s%\w+ Exp( \w+)?$%%; 445 | my @words = split; 446 | print "/*\n"; 447 | print "** Derived from file $words[0] version $words[1] dated $words[2] $words[3]\n"; 448 | print "*/\n"; 449 | } 450 | elsif (/ ::=/) 451 | { 452 | # Definition line 453 | my $def = $_; 454 | $def =~ s%<([-:/()\w\s]+)>.*%$1%o; 455 | $def = map_non_terminal($def); 456 | $rules{$def} = 1; 457 | $nonterminals{$def} = 1; 458 | my $tail = $_; 459 | $tail =~ s%.*::=\s*%%; # Remove LHS of statement 460 | while () 461 | { 462 | chomp; 463 | last unless /^\s/; 464 | $tail .= $_; 465 | } 466 | process_rhs($def, $tail); 467 | } 468 | else 469 | { 470 | # Anything unrecognized passed through as a comment! 471 | print "/* $_ */\n"; 472 | } 473 | } 474 | 475 | close INPUT; 476 | 477 | print "==== End of input phase ====\n" if debug; 478 | 479 | print $heading if $heading; 480 | 481 | # List of tokens 482 | foreach my $token (sort keys %tokens) 483 | { 484 | print "\%token $token\n"; 485 | } 486 | print "\n"; 487 | 488 | # Undefined non-terminals might need to be treated as tokens 489 | if (count_unmatched_keys(\%nonterminals, \%rules) > 0) 490 | { 491 | print "/* The following non-terminals were not defined */\n"; 492 | foreach my $nt (sort keys %nonterminals) 493 | { 494 | print "%token $nt\n" unless defined $rules{$nt}; 495 | } 496 | print "/* End of undefined non-terminals */\n\n"; 497 | } 498 | 499 | # List the rules that are defined in the original grammar. 500 | # Do not list the rules defined by this conversion process. 501 | print "/*\n"; 502 | foreach my $nt (sort keys %nonterminals) 503 | { 504 | print "\%rule $nt\n"; 505 | } 506 | print "*/\n\n"; 507 | 508 | 509 | if (defined $start) 510 | { 511 | print "%start $start\n\n"; 512 | print "%%\n\n"; 513 | } 514 | else 515 | { 516 | # No start symbol defined - let's see if we can work out what to use. 517 | # If there's more than one unused non-terminal, then treat them 518 | # all as simple alternatives to a list of statements. 519 | my $count = count_unmatched_keys(\%nonterminals, \%used); 520 | 521 | if ($count > 1) 522 | { 523 | my $prog = "bnf_program"; 524 | my $stmt = "bnf_statement"; 525 | print "%start $prog\n\n"; 526 | print "%%\n\n"; 527 | print "$prog\n\t:\t$stmt\n\t|\t$prog $stmt\n\t;\n\n"; 528 | print "$stmt\n"; 529 | my $pad = "\t:\t"; 530 | foreach my $nt (sort keys %nonterminals) 531 | { 532 | unless (defined $used{$nt}) 533 | { 534 | print "$pad$nt\n"; 535 | $pad = "\t|\t"; 536 | } 537 | } 538 | print "\t;\n\n"; 539 | } 540 | elsif ($count == 1) 541 | { 542 | foreach my $nt (sort keys %nonterminals) 543 | { 544 | print "%start $nt" unless defined $used{$nt}; 545 | } 546 | print "%%\n\n"; 547 | } 548 | else 549 | { 550 | # No single start symbol - loop? 551 | # Error! 552 | print STDERR "$0: no start symbol recognized!\n"; 553 | print "%%\n\n"; 554 | } 555 | } 556 | 557 | # Output the complete grammar 558 | while (my $line = shift @grammar) 559 | { 560 | print $line; 561 | } 562 | 563 | print "\n%%\n\n"; 564 | 565 | __END__ 566 | 567 | =pod 568 | 569 | Given a rule: 570 | 571 | abc: def ghi jkl 572 | 573 | The Yacc output is: 574 | 575 | abc 576 | : def ghi jkl 577 | ; 578 | 579 | Given a rule: 580 | 581 | abc: def [ ghi ] jkl 582 | 583 | The Yacc output is: 584 | 585 | abc 586 | : def opt_nt_0001 jkl 587 | ; 588 | 589 | opt_nt_0001 590 | : /* Nothing */ 591 | | ghi 592 | ; 593 | 594 | Given a rule: 595 | 596 | abc: def { ghi } jkl 597 | 598 | The Yacc output is: 599 | 600 | abc 601 | : def seq_nt_0002 jkl 602 | ; 603 | 604 | seq_nt_0002 605 | : ghi 606 | ; 607 | 608 | Note that such rules are seldom used in isolation; either the contents 609 | of the '{' to '}' contains alternatives, or the construct as a whole is 610 | followed by a repetition. 611 | 612 | Given a rule: 613 | 614 | abc: def | ghi 615 | 616 | The Yacc output is: 617 | 618 | abc 619 | : def 620 | | ghi 621 | ; 622 | 623 | Given a rule: 624 | 625 | abc: def ghi... jkl 626 | 627 | The Yacc output is: 628 | 629 | abc 630 | : def lst_nt_0003 jkl 631 | ; 632 | 633 | lst_nt_0003 634 | : ghi 635 | | lst_nt_0003 ghi 636 | ; 637 | 638 | These rules can be, and often are, combined. The following examples 639 | come from the SQL-99 grammar which is the target of this effort. The 640 | target of this program is to produce Yacc rules equivalent to those 641 | which follow each fragment. Note that keywords (equivalently, 642 | terminals) are in upper case only; mixed case or lower case symbols are 643 | non-terminals. 644 | 645 | ::= 646 | 647 | 648 | 649 | [ ] 650 | [ ] 651 | [ ... ] 652 | ... 653 | 654 | SQL_client_module_definition 655 | : module_name_clause language_clause module_authorization_clause opt_nt_0001 opt_nt_0002 opt_nt_0003 lst_nt_0004 656 | ; 657 | opt_nt_0001 658 | : /* Nothing */ 659 | | module_path_specification 660 | ; 661 | opt_nt_0002 662 | : /* Nothing */ 663 | | module_transform_group_specification 664 | ; 665 | opt_nt_0003 666 | : /* Nothing */ 667 | | lst_nt_0005 668 | ; 669 | lst_nt_0004 670 | : module_contents 671 | | lst_nt_0004 module_contents 672 | ; 673 | lst_nt_0005 674 | : temporary_table_declaration 675 | | lst_nt_0005 temporary_table_declaration 676 | ; 677 | 678 | The next example is interesting - it is fairly typical of the grammar, 679 | but is not minimal. The rule could be written ' ::= 680 | [ ... ]' without altering the 681 | meaning. It is not clear whether this program should apply this 682 | transformation automatically. 683 | 684 | ::= [ { }... ] 685 | 686 | identifier_body 687 | : identifier_start opt_nt_0006 688 | ; 689 | opt_nt_0006 690 | : /* Nothing */ 691 | | lst_nt_0007 692 | ; 693 | lst_nt_0007 694 | : seq_nt_0008 695 | | lst_nt_0007 seq_nt_0008 696 | ; 697 | seq_nt_0008 698 | : identifier_part 699 | ; 700 | 701 | /* Optimized alternative to lst_nt_0007 */ 702 | lst_nt_0007 703 | : identifier_part 704 | | lst_nt_0007 identifier_part 705 | ; 706 | 707 | ::= 708 | [ { | }... ] 709 | 710 | sql_language_identifier 711 | : sql_language_identifier_start opt_nt_0009 712 | ; 713 | opt_nt_0009 714 | : /* Nothing */ 715 | | lst_nt_0010 716 | ; 717 | lst_nt_0010 718 | : seq_nt_0011 719 | | lst_nt_0010 seq_nt_0011 720 | ; 721 | seq_nt_0011 722 | : underscore 723 | | sql_language_identifier_part 724 | ; 725 | 726 | The next rule is the first example with keywords. 727 | 728 | ::= 729 | SCHEMA 730 | | AUTHORIZATION 731 | | SCHEMA AUTHORIZATION 732 | 733 | module_authorization_clause 734 | : SCHEMA schema_name 735 | | AUTHORIZATION module_authorization_identifier 736 | | SCHEMA schema_name AUTHORIZATION module_authorization_identifier 737 | ; 738 | 739 | ::= 740 | TRANSFORM GROUP { | } 741 | 742 | transform_group_specification 743 | : TRANSFORM GROUP seq_nt_0012 744 | ; 745 | seq_nt_0012 746 | : single_group_specification 747 | | multiple_group_specification 748 | ; 749 | 750 | ::= [ { }... ] 751 | 752 | multiple_group_specification 753 | : group_specification opt_nt_0013 754 | ; 755 | opt_nt_0013 756 | : /* Nothing */ 757 | | lst_nt_0014 758 | ; 759 | lst_nt_0014 760 | : seq_nt_0015 761 | | lst_nt_0014 seq_nt_0015 762 | ; 763 | seq_nt_0015 764 | : comma group_specification 765 | ; 766 | 767 | Except for the presence of a token () after the optional 768 | list, the next example is equivalent to the previous one. It does show, 769 | however, that there is an element of lookahead required to tell whether 770 | an optional item contains a list or a sequence or a simple list of 771 | terminals and non-terminals. 772 | 773 | ::= 774 |
    [ {
    }... ] 775 | 776 | table_element_list 777 | : left_paren table_element opt_nt_0016 right_paren 778 | ; 779 | opt_nt_0016 780 | : /* Nothing */ 781 | | lst_nt_0017 782 | ; 783 | lst_nt_0017 784 | : seq_nt_0018 785 | | lst_nt_0017 seq_nt_0018 786 | ; 787 | seq_nt_0018 788 | : comma table_element 789 | ; 790 | 791 | The next example is interesting because the sequence item contains 792 | alternatives with no optionality or iteration. It suggests that the 793 | term 'sequence' is not necessarily the 'mot juste'. 794 | 795 | ::= 796 | 797 | { | } 798 | [ ] 799 | [ ] 800 | [ ... ] 801 | [ ] 802 | 803 | column_definition 804 | : column_name seq_nt_0019 opt_nt_0020 opt_nt_0021 opt_nt_0022 opt_nt_0023 805 | ; 806 | seq_nt_0019 807 | : data_type 808 | | domain_name 809 | ; 810 | opt_nt_0020 811 | : /* Nothing */ 812 | | reference_scope_check 813 | ; 814 | opt_nt_0021 815 | : /* Nothing */ 816 | | default_clause 817 | ; 818 | opt_nt_0022 819 | : /* Nothing */ 820 | | lst_nt_0024 821 | ; 822 | opt_nt_0023 823 | : /* Nothing */ 824 | | collate_clause 825 | ; 826 | lst_nt_0024 827 | : column_constraint_definition 828 | | lst_nt_0024 column_constraint_definition 829 | ; 830 | 831 | 832 | [ { ; 402 | exit 0 unless defined($_); 403 | chomp; 404 | $heading = "%{\n/*\n** $_\n*/\n%}\n\n" unless m/^\s*$/; 405 | 406 | # Commentary appears in column 1. 407 | # Continuations of rules have a blank in column 1. 408 | # Blank lines, dash lines and equals lines separate rules (are not embedded within them).. 409 | 410 | while () 411 | { 412 | chomp; 413 | print "DBG:$.: $_\n" if debug; 414 | next if /^===*$/o; 415 | next if /^\s*$/o; # Blank lines 416 | next if /^---*$/o; # Horizontal lines 417 | if (/^--/o) 418 | { 419 | # Various HTML pseudo-directives 420 | if (m%^--/?\w+\b%) 421 | { 422 | print "/* $' */\n" if $'; 423 | } 424 | elsif (/^--%start (\w+)/) 425 | { 426 | $start = $1; 427 | print "/* Start symbol - $start */\n"; 428 | } 429 | elsif (/^--##/) 430 | { 431 | print "/* $_ */\n"; 432 | } 433 | else 434 | { 435 | print "/* Unrecognized 2: $_ */\n"; 436 | } 437 | } 438 | elsif (/^@.#..Id:/) 439 | { 440 | # Convert what(1) string identifier into version information 441 | s%^@.#..Id: %%; 442 | s% \$$%%; 443 | s%,v % %; 444 | s%\w+ Exp( \w+)?$%%; 445 | my @words = split; 446 | print "/*\n"; 447 | print "** Derived from file $words[0] version $words[1] dated $words[2] $words[3]\n"; 448 | print "*/\n"; 449 | } 450 | elsif (/ ::=/) 451 | { 452 | # Definition line 453 | my $def = $_; 454 | $def =~ s%<([-:/()\w\s]+)>.*%$1%o; 455 | $def = map_non_terminal($def); 456 | $rules{$def} = 1; 457 | $nonterminals{$def} = 1; 458 | my $tail = $_; 459 | $tail =~ s%.*::=\s*%%; # Remove LHS of statement 460 | while () 461 | { 462 | chomp; 463 | last unless /^\s/; 464 | $tail .= $_; 465 | } 466 | process_rhs($def, $tail); 467 | } 468 | else 469 | { 470 | # Anything unrecognized passed through as a comment! 471 | print "/* $_ */\n"; 472 | } 473 | } 474 | 475 | close INPUT; 476 | 477 | print "==== End of input phase ====\n" if debug; 478 | 479 | print $heading if $heading; 480 | 481 | # List of tokens 482 | foreach my $token (sort keys %tokens) 483 | { 484 | print "\%token $token\n"; 485 | } 486 | print "\n"; 487 | 488 | # Undefined non-terminals might need to be treated as tokens 489 | if (count_unmatched_keys(\%nonterminals, \%rules) > 0) 490 | { 491 | print "/* The following non-terminals were not defined */\n"; 492 | foreach my $nt (sort keys %nonterminals) 493 | { 494 | print "%token $nt\n" unless defined $rules{$nt}; 495 | } 496 | print "/* End of undefined non-terminals */\n\n"; 497 | } 498 | 499 | # List the rules that are defined in the original grammar. 500 | # Do not list the rules defined by this conversion process. 501 | print "/*\n"; 502 | foreach my $nt (sort keys %nonterminals) 503 | { 504 | print "\%rule $nt\n"; 505 | } 506 | print "*/\n\n"; 507 | 508 | 509 | if (defined $start) 510 | { 511 | print "%start $start\n\n"; 512 | print "%%\n\n"; 513 | } 514 | else 515 | { 516 | # No start symbol defined - let's see if we can work out what to use. 517 | # If there's more than one unused non-terminal, then treat them 518 | # all as simple alternatives to a list of statements. 519 | my $count = count_unmatched_keys(\%nonterminals, \%used); 520 | 521 | if ($count > 1) 522 | { 523 | my $prog = "bnf_program"; 524 | my $stmt = "bnf_statement"; 525 | print "%start $prog\n\n"; 526 | print "%%\n\n"; 527 | print "$prog\n\t:\t$stmt\n\t|\t$prog $stmt\n\t;\n\n"; 528 | print "$stmt\n"; 529 | my $pad = "\t:\t"; 530 | foreach my $nt (sort keys %nonterminals) 531 | { 532 | unless (defined $used{$nt}) 533 | { 534 | print "$pad$nt\n"; 535 | $pad = "\t|\t"; 536 | } 537 | } 538 | print "\t;\n\n"; 539 | } 540 | elsif ($count == 1) 541 | { 542 | foreach my $nt (sort keys %nonterminals) 543 | { 544 | print "%start $nt" unless defined $used{$nt}; 545 | } 546 | print "%%\n\n"; 547 | } 548 | else 549 | { 550 | # No single start symbol - loop? 551 | # Error! 552 | print STDERR "$0: no start symbol recognized!\n"; 553 | print "%%\n\n"; 554 | } 555 | } 556 | 557 | # Output the complete grammar 558 | while (my $line = shift @grammar) 559 | { 560 | print $line; 561 | } 562 | 563 | print "\n%%\n\n"; 564 | 565 | __END__ 566 | 567 | =pod 568 | 569 | Given a rule: 570 | 571 | abc: def ghi jkl 572 | 573 | The Yacc output is: 574 | 575 | abc 576 | : def ghi jkl 577 | ; 578 | 579 | Given a rule: 580 | 581 | abc: def [ ghi ] jkl 582 | 583 | The Yacc output is: 584 | 585 | abc 586 | : def opt_nt_0001 jkl 587 | ; 588 | 589 | opt_nt_0001 590 | : /* Nothing */ 591 | | ghi 592 | ; 593 | 594 | Given a rule: 595 | 596 | abc: def { ghi } jkl 597 | 598 | The Yacc output is: 599 | 600 | abc 601 | : def seq_nt_0002 jkl 602 | ; 603 | 604 | seq_nt_0002 605 | : ghi 606 | ; 607 | 608 | Note that such rules are seldom used in isolation; either the contents 609 | of the '{' to '}' contains alternatives, or the construct as a whole is 610 | followed by a repetition. 611 | 612 | Given a rule: 613 | 614 | abc: def | ghi 615 | 616 | The Yacc output is: 617 | 618 | abc 619 | : def 620 | | ghi 621 | ; 622 | 623 | Given a rule: 624 | 625 | abc: def ghi... jkl 626 | 627 | The Yacc output is: 628 | 629 | abc 630 | : def lst_nt_0003 jkl 631 | ; 632 | 633 | lst_nt_0003 634 | : ghi 635 | | lst_nt_0003 ghi 636 | ; 637 | 638 | These rules can be, and often are, combined. The following examples 639 | come from the SQL-99 grammar which is the target of this effort. The 640 | target of this program is to produce Yacc rules equivalent to those 641 | which follow each fragment. Note that keywords (equivalently, 642 | terminals) are in upper case only; mixed case or lower case symbols are 643 | non-terminals. 644 | 645 | ::= 646 | 647 | 648 | 649 | [ ] 650 | [ ] 651 | [ ... ] 652 | ... 653 | 654 | SQL_client_module_definition 655 | : module_name_clause language_clause module_authorization_clause opt_nt_0001 opt_nt_0002 opt_nt_0003 lst_nt_0004 656 | ; 657 | opt_nt_0001 658 | : /* Nothing */ 659 | | module_path_specification 660 | ; 661 | opt_nt_0002 662 | : /* Nothing */ 663 | | module_transform_group_specification 664 | ; 665 | opt_nt_0003 666 | : /* Nothing */ 667 | | lst_nt_0005 668 | ; 669 | lst_nt_0004 670 | : module_contents 671 | | lst_nt_0004 module_contents 672 | ; 673 | lst_nt_0005 674 | : temporary_table_declaration 675 | | lst_nt_0005 temporary_table_declaration 676 | ; 677 | 678 | The next example is interesting - it is fairly typical of the grammar, 679 | but is not minimal. The rule could be written ' ::= 680 | [ ... ]' without altering the 681 | meaning. It is not clear whether this program should apply this 682 | transformation automatically. 683 | 684 | ::= [ { }... ] 685 | 686 | identifier_body 687 | : identifier_start opt_nt_0006 688 | ; 689 | opt_nt_0006 690 | : /* Nothing */ 691 | | lst_nt_0007 692 | ; 693 | lst_nt_0007 694 | : seq_nt_0008 695 | | lst_nt_0007 seq_nt_0008 696 | ; 697 | seq_nt_0008 698 | : identifier_part 699 | ; 700 | 701 | /* Optimized alternative to lst_nt_0007 */ 702 | lst_nt_0007 703 | : identifier_part 704 | | lst_nt_0007 identifier_part 705 | ; 706 | 707 | ::= 708 | [ { | }... ] 709 | 710 | sql_language_identifier 711 | : sql_language_identifier_start opt_nt_0009 712 | ; 713 | opt_nt_0009 714 | : /* Nothing */ 715 | | lst_nt_0010 716 | ; 717 | lst_nt_0010 718 | : seq_nt_0011 719 | | lst_nt_0010 seq_nt_0011 720 | ; 721 | seq_nt_0011 722 | : underscore 723 | | sql_language_identifier_part 724 | ; 725 | 726 | The next rule is the first example with keywords. 727 | 728 | ::= 729 | SCHEMA 730 | | AUTHORIZATION 731 | | SCHEMA AUTHORIZATION 732 | 733 | module_authorization_clause 734 | : SCHEMA schema_name 735 | | AUTHORIZATION module_authorization_identifier 736 | | SCHEMA schema_name AUTHORIZATION module_authorization_identifier 737 | ; 738 | 739 | ::= 740 | TRANSFORM GROUP { | } 741 | 742 | transform_group_specification 743 | : TRANSFORM GROUP seq_nt_0012 744 | ; 745 | seq_nt_0012 746 | : single_group_specification 747 | | multiple_group_specification 748 | ; 749 | 750 | ::= [ { }... ] 751 | 752 | multiple_group_specification 753 | : group_specification opt_nt_0013 754 | ; 755 | opt_nt_0013 756 | : /* Nothing */ 757 | | lst_nt_0014 758 | ; 759 | lst_nt_0014 760 | : seq_nt_0015 761 | | lst_nt_0014 seq_nt_0015 762 | ; 763 | seq_nt_0015 764 | : comma group_specification 765 | ; 766 | 767 | Except for the presence of a token () after the optional 768 | list, the next example is equivalent to the previous one. It does show, 769 | however, that there is an element of lookahead required to tell whether 770 | an optional item contains a list or a sequence or a simple list of 771 | terminals and non-terminals. 772 | 773 |
    ::= 774 |
    [ {
    }... ] 775 | 776 | table_element_list 777 | : left_paren table_element opt_nt_0016 right_paren 778 | ; 779 | opt_nt_0016 780 | : /* Nothing */ 781 | | lst_nt_0017 782 | ; 783 | lst_nt_0017 784 | : seq_nt_0018 785 | | lst_nt_0017 seq_nt_0018 786 | ; 787 | seq_nt_0018 788 | : comma table_element 789 | ; 790 | 791 | The next example is interesting because the sequence item contains 792 | alternatives with no optionality or iteration. It suggests that the 793 | term 'sequence' is not necessarily the 'mot juste'. 794 | 795 | ::= 796 | 797 | { | } 798 | [ ] 799 | [ ] 800 | [ ... ] 801 | [ ] 802 | 803 | column_definition 804 | : column_name seq_nt_0019 opt_nt_0020 opt_nt_0021 opt_nt_0022 opt_nt_0023 805 | ; 806 | seq_nt_0019 807 | : data_type 808 | | domain_name 809 | ; 810 | opt_nt_0020 811 | : /* Nothing */ 812 | | reference_scope_check 813 | ; 814 | opt_nt_0021 815 | : /* Nothing */ 816 | | default_clause 817 | ; 818 | opt_nt_0022 819 | : /* Nothing */ 820 | | lst_nt_0024 821 | ; 822 | opt_nt_0023 823 | : /* Nothing */ 824 | | collate_clause 825 | ; 826 | lst_nt_0024 827 | : column_constraint_definition 828 | | lst_nt_0024 column_constraint_definition 829 | ; 830 | 831 | 832 | [ {
    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 | --p 219 | The package called "Enhanced datetime facilities" comprises the following features of the SQL 220 | language as specified in the SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. 221 | --/p 222 | 223 | --p 224 | --## 225 | --## 226 | --## 227 | --## 228 | --##
    Feature F052 Intervals and datetime arithmetic
    Feature F411 Time zone specification
    Feature F555 Enhanced seconds precision
    229 | --/p 230 | 231 | --hr 232 | --h2 233 | B.2 Enhanced integrity management 234 | --/h2 235 | 236 | --p 237 | The package called "Enhanced integrity management" comprises the following features of the SQL 238 | language as specified in the SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. 239 | --/p 240 | 241 | --p 242 | --## 243 | --## 244 | --## 245 | --## 246 | --## 247 | --## 248 | --## 249 | --## 250 | --## 251 | --## 252 | --##
    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
    253 | --/p 254 | 255 | --hr 256 | --h2 B.3 PSM 257 | --/h2 258 | 259 | --p 260 | The package called "PSM" comprises the following features of the SQL language as specified in the 261 | SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. 262 | --/p 263 | 264 | --p 265 | --## 266 | --## 267 | --## 268 | --## 269 | --## 270 | --##
    Feature T322 Overloading of SQL-invoked functions and SQL-invoked procedures
    Feature P001 Stored modules
    Feature P002 Computational completeness
    Feature P003 Information Schema views
    271 | --/p 272 | 273 | --hr 274 | --h2 B.4 CLI 275 | --/h2 276 | 277 | --p 278 | The package called "CLI" comprises the following features of the SQL language as specified in the 279 | SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. 280 | --/p 281 | 282 | --p 283 | --## 284 | --## 285 | --## 286 | --## 287 | --## 288 | --## 289 | --## 290 | --## 291 | --##
    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
    292 | --/p 293 | 294 | --hr 295 | --h2 B.5 Basic object support 296 | --/h2 297 | 298 | --p 299 | The package called "basic object support" comprises the following features of the SQL language as 300 | specified in the SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. 301 | --/p 302 | 303 | --p 304 | --## 305 | --## 306 | --## 307 | --## 308 | --## 309 | --## 310 | --##
    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
    311 | --/p 312 | 313 | --hr 314 | --h2 B.6 Enhanced object support 315 | --/h2 316 | 317 | --p 318 | The package called "enhanced object support" comprises all of the features of the package called 319 | (Basic object support), plus the following features of the SQL language as specified in the SQL 320 | Feature Taxonomy Annex of the various parts of ISO/IEC 9075. 321 | --/p 322 | 323 | --p 324 | --## 325 | --## 326 | --## 327 | --## 328 | --## 329 | --## 330 | --## 331 | --## 332 | --## 333 | --## 334 | --##
    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
    335 | --/p 336 | 337 | --hr 338 | --h2 B.7 Active database 339 | --/h2 340 | 341 | --p 342 | The package called "Active database" comprises the following features of the SQL language as 343 | specified in the SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. 344 | --/p 345 | 346 | --p 347 | --## 348 | --## 349 | --##
    Feature T211 Basic trigger capability
    350 | --/p 351 | 352 | --hr 353 | --h2 B.8 OLAP 354 | --/h2 355 | 356 | --p 357 | The package called "OLAP" comprises the following features of the SQL language as specified in the 358 | SQL Feature Taxonomy Annex of the various parts of ISO/IEC 9075. 359 | --/p 360 | 361 | --p 362 | --## 363 | --## 364 | --## 365 | --##
    Feature T431 Extended grouping capabilities
    Feature T611 Elementary OLAP operators
    366 | --/p 367 | 368 | --hr 369 | --h2 END OF SQL-2003-1 GRAMMAR 370 | --/h2 371 | 372 | --hr 373 | 374 | -------------------------------------------------------------------------------- /sql-2003-2.ebnf.readme: -------------------------------------------------------------------------------- 1 | How to use sql-2003-2.ebnf 2 | ========================== 3 | This file was extracted manually from sql-2003-2.bnf by Domingo Alvarez Duarte. 4 | Many thanx Domingo! 5 | 6 | It is the latter file as pure ebnf, i.e. with the original markup stripped. 7 | 8 | The corresponding XHTML + SVG file is sql-2003-2-railroad-diagrams.xhtml. 9 | 10 | The grammar can be rendered as railroad diagrams on the website https://www.bottlecaps.de/rr/ui. 11 | Just copy it into the Edit Grammar tab, and click View Diagram. Then wait a moment :-). 12 | 13 | Domingo notes: 14 | 1. Non reserved words appear with * as suffix, ex: SUBSTRING -> SUBSTRING*. 15 | 16 | 2. You can navigate through the railroad's grammar by clicking the rectangular boxes. 17 | 18 | Finally, you can download the rendered railroad as either XHTML + SVG or HTML + PNG. 19 | -------------------------------------------------------------------------------- /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 | Please send feedback to Jonathan Leffler: 252 | jonathan.leffler@gmail.com . 253 |

    254 | 255 |

    256 | @(#)$Id: sql-2003-core-features.html,v 1.3 2017/11/13 20:45:42 jleffler Exp $ 257 |

    258 | 259 | 260 | 261 | -------------------------------------------------------------------------------- /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 DISTINCT
    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 |

    282 | Please send feedback to Jonathan Leffler: 283 | jonathan.leffler@gmail.com . 284 |

    285 | 286 |

    287 | @(#)$Id: sql-2003-noncore-features.html,v 1.3 2017/11/13 20:45:42 jleffler Exp $ 288 |

    289 | 290 | 291 | 292 | -------------------------------------------------------------------------------- /sql-2016.ebnf.readme: -------------------------------------------------------------------------------- 1 | How to use sql-2016.ebnf 2 | ======================== 3 | This file was created manually by Domingo Alvarez Duarte. 4 | Many thanx Domingo! 5 | 6 | The corresponding XHTML + SVG file is sql-2016-railroad-diagrams.xhtml. 7 | 8 | The grammar can be rendered as railroad diagrams on the website https://www.bottlecaps.de/rr/ui. 9 | Just copy it into the Edit Grammar tab, and click View Diagram. Then wait a good minute or so :-). 10 | 11 | Domingo notes: 12 | 1. Non reserved words appear with * as suffix, ex: SUBSTRING -> SUBSTRING*. 13 | 14 | 2. You can navigate through the railroad's grammar by clicking the rectangular boxes. 15 | 16 | Finally, you can download the rendered railroad as either XHTML + SVG or HTML + PNG. 17 | -------------------------------------------------------------------------------- /sql-bnf.mk: -------------------------------------------------------------------------------- 1 | # @(#)$Id: sql-bnf.mk,v 1.18 2017/01/21 16:29:04 jleffler Exp $ 2 | # 3 | # Makefile for SQL-92, SQL-99 and SQL-2003 BNF and HTML files 4 | 5 | .NO_PENDING_GET: 6 | 7 | WEBCODE.tgz = webcode-1.09.tgz 8 | FILE1.bnf = sql-92.bnf 9 | FILE2.bnf = sql-99.bnf 10 | FILE3.bnf = sql-2003-1.bnf 11 | FILE4.bnf = sql-2003-2.bnf 12 | FILES.bnf = ${FILE1.bnf} ${FILE2.bnf} ${FILE3.bnf} ${FILE4.bnf} 13 | FILES.html = ${FILES.bnf:bnf=bnf.html} 14 | FILE1.aux = index.html 15 | FILE2.aux = outer-joins.html 16 | FILE3.aux = sql-2003-core-features.html 17 | FILE4.aux = sql-2003-noncore-features.html 18 | FILES.aux = ${FILE1.aux} ${FILE2.aux} ${FILE3.aux} ${FILE4.aux} 19 | FILE1.pl = bnf2html.pl 20 | FILE2.pl = bnf2yacc.pl 21 | FILES.pl = ${FILE1.pl} ${FILE2.pl} 22 | FILE1.txt = bnf2html.perl.txt 23 | FILE2.txt = bnf2yacc.perl.txt 24 | FILES.txt = ${FILE1.txt} ${FILE2.txt} 25 | FILES.mk = sql-bnf.mk 26 | FILES.all = ${FILES.bnf} ${FILES.html} ${FILES.mk} ${FILES.pl} ${FILES.txt} \ 27 | ${FILES.aux} ${WEBCODE.tgz} 28 | 29 | # Dummy datestamp - just in case. 30 | VERNUM = 00000000 31 | VRSNFILE.tgz = sql-bnf-${VERNUM}.tgz 32 | DISTFILE.tgz = sql-bnf.tgz 33 | RCSFILES.tgz = sql-bnf-rcs-${VERNUM}.tgz 34 | 35 | APACHE_HOME = /opt/apache/webserver 36 | APACHE_HTML = htdocs/SQL 37 | APACHE_DIR = ${APACHE_HOME}/${APACHE_HTML} 38 | 39 | TAR = tar 40 | TARFLAGS = -cvzf 41 | COPY = cp 42 | COPYFLAGS = -fp 43 | PERL = perl 44 | RM_F = rm -f 45 | CHMOD = chmod 46 | WEBPERMS = 444 47 | LN = ln 48 | MKPATH = mkdir -p 49 | 50 | all: 51 | ${MAKE} VERNUM=`date +'%Y''%m''%d'` all-vrsn 52 | 53 | all-vrsn: ${VRSNFILE.tgz} ${RCSFILES.tgz} 54 | 55 | ${VRSNFILE.tgz}: ${FILES.all} 56 | ${TAR} ${TARFLAGS} ${VRSNFILE.tgz} ${FILES.all} 57 | ${RM_F} ${DISTFILE.tgz} 58 | ${LN} ${VRSNFILE.tgz} ${DISTFILE.tgz} 59 | 60 | ${RCSFILES.tgz}: RCS 61 | ${TAR} ${TARFLAGS} ${RCSFILES.tgz} RCS 62 | 63 | ${FILES.html}: $${@:.html=} ${FILE1.pl} 64 | ${RM_F} $@ 65 | ${PERL} ${FILE1.pl} ${@:.html=} > $@ 66 | 67 | ${FILES.txt}: $${@:.perl.txt=.pl} 68 | ${RM_F} $@ 69 | ${LN} $? $@ 70 | 71 | install: all 72 | ${MKPATH} ${APACHE_DIR} 73 | ${COPY} ${COPYFLAGS} ${DISTFILE.tgz} ${FILES.all} ${WEBCODE.tgz} ${APACHE_DIR} 74 | cd ${APACHE_DIR}; ${CHMOD} ${WEBPERMS} ${DISTFILE.tgz} ${WEBCODE.tgz} ${FILES.all} 75 | -------------------------------------------------------------------------------- /webcode-1.09.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ronsavage/SQL/19215adc8639d031a44acad7873c209444b71f1f/webcode-1.09.tgz --------------------------------------------------------------------------------