1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9/**
10 * 2016 Martin Kersten
11 *
12 * The SQL syntax help synopsis.
13 */
14
15/* produce a synposis of the SQL syntax, inspired by a competing product.
16 * Use the conventional grammar constructs:
17 * [ A | B ] token A or B or none
18 * { A | B } exactly one of the options A or B should be chosen
19 * A [',' ...] a comma separated list of A elements
20 * { A | B } ... a series of A and B's
21 * { A B } [',' ...] a series of A B,A B,A B,A B
22 *
23 * Ideally each major command line should point into the website for
24 * more details and variations not covered here.
25 * */
26
27#include "monetdb_config.h"
28#include <ctype.h>
29#include <string.h>
30#ifdef HAVE_STRINGS_H
31#include <strings.h> /* for strncasecmp */
32#endif
33#include "stream.h"
34#include "mhelp.h"
35
36typedef struct {
37 const char *command;
38 const char *synopsis;
39 const char *syntax;
40 const char *rules;
41 const char *comments;
42} SQLhelp;
43
44SQLhelp sqlhelp1[] = {
45 // major commands
46 {"ALTER TABLE",
47 "",
48 "ALTER TABLE [ IF EXISTS ] qname ADD [ COLUMN ] { column_def | table_constraint }\n"
49 "ALTER TABLE [ IF EXISTS ] qname ALTER [ COLUMN ] ident SET DEFAULT value\n"
50 "ALTER TABLE [ IF EXISTS ] qname ALTER [ COLUMN ] ident SET [NOT] NULL\n"
51 "ALTER TABLE [ IF EXISTS ] qname ALTER [ COLUMN ] ident DROP DEFAULT\n"
52 "ALTER TABLE [ IF EXISTS ] qname ALTER [ COLUMN ] ident SET STORAGE {string | NULL}\n"
53 "ALTER TABLE [ IF EXISTS ] qname RENAME [ COLUMN ] ident TO ident\n"
54 "ALTER TABLE [ IF EXISTS ] qname DROP [ COLUMN ] ident [ RESTRICT | CASCADE ]\n"
55 "ALTER TABLE [ IF EXISTS ] qname DROP CONSTRAINT ident [ RESTRICT | CASCADE ]\n"
56 "ALTER TABLE [ IF EXISTS ] qname RENAME TO ident\n"
57 "ALTER TABLE [ IF EXISTS ] qname SET { { READ | INSERT } ONLY | READ WRITE }\n"
58 "ALTER TABLE [ IF EXISTS ] qname SET SCHEMA ident",
59 "qname,column_def,table_constraint,ident",
60 "See also https://www.monetdb.org/Documentation/SQLreference/Alter"},
61 {"ALTER MERGE TABLE",
62 "",
63 "ALTER TABLE [ IF EXISTS ] qname ADD TABLE qname [ AS PARTITION partition_spec ]\n"
64 "ALTER TABLE [ IF EXISTS ] qname DROP TABLE qname [ RESTRICT | CASCADE ]\n"
65 "ALTER TABLE [ IF EXISTS ] qname SET TABLE qname AS PARTITION partition_spec",
66 "qname,partition_spec",
67 "See also https://www.monetdb.org/Documentation/Cookbooks/SQLrecipes/DataPartitioning"},
68 {"ALTER SCHEMA",
69 "",
70 "ALTER SCHEMA [ IF EXISTS ] ident RENAME TO ident",
71 "ident",
72 "See also https://www.monetdb.org/Documentation/SQLreference/Alter"},
73 {"ALTER SEQUENCE",
74 "",
75 "ALTER SEQUENCE ident [ AS data_type] [ RESTART [WITH start]] [INCREMENT BY increment]\n"
76 "[MINVALUE minvalue | NO MINVALUE] [MAXVALUE maxvalue | NO MAXVALUE] [CACHE cachevalue] [[NO] CYCLE]",
77 "ident,data_type",
78 "See also https://www.monetdb.org/Documentation/Manuals/SQLreference/SerialTypes"},
79 {"ALTER USER",
80 "Change a user's login name or password or default schema",
81 "ALTER USER ident RENAME TO ident\n"
82 "ALTER USER SET [ENCRYPTED | UNENCRYPTED] PASSWORD string USING OLD PASSWORD string\n"
83 "ALTER USER ident WITH [ENCRYPTED | UNENCRYPTED] PASSWORD string\n"
84 "ALTER USER ident [ WITH [ENCRYPTED | UNENCRYPTED] PASSWORD string ] SET SCHEMA ident",
85 "ident",
86 "See also https://www.monetdb.org/Documentation/SQLreference/Users"},
87 {"ANALYZE",
88 "Collect column/table/schema data statistics for analysis and optimizer usage",
89 "ANALYZE ident [ . ident [ column_list ] ] [SAMPLE size] [MINMAX]",
90 "ident,column_list",
91 "See also https://www.monetdb.org/Documentation/Cookbooks/SQLrecipes/statistics"},
92 {"CALL",
93 "",
94 "CALL qname '(' [ scalar_expression [',' ...] ] ')' | CALL ident '.' ident",
95 NULL,
96 NULL},
97 {"CASE",
98 "Case statement for procedures/functions",
99 "CASE scalar_expression [ when_statement ...] [ELSE procedure_statement ... ] END CASE",
100 NULL,
101 "See also https://www.monetdb.org/Documentation/SQLreference/Flowofcontrol"},
102 {"COMMENT",
103 "Add, update or remove a comment or description for a database object",
104 "COMMENT ON { SCHEMA | TABLE | VIEW | COLUMN | INDEX | SEQUENCE |\n"
105 " FUNCTION | PROCEDURE | AGGREGATE | FILTER FUNCTION | LOADER }\n"
106 " qname IS { 'my description text' | NULL | '' }",
107 "qname",
108 NULL},
109 {"COMMIT",
110 "Commit the current transaction",
111 "COMMIT [ WORK ] [ AND CHAIN | AND NO CHAIN ]",
112 NULL,
113 NULL},
114 {"COPY BINARY",
115 "Append binary representations into a table",
116 "COPY [nrofrecords] BINARY INTO qname [column_list] FROM string [',' ...] [ON { CLIENT | SERVER }] [NO CONSTRAINT]",
117 "nrofrecords,qname,column_list",
118 "See also https://www.monetdb.org/Documentation/Cookbooks/SQLrecipes/BinaryBulkLoad"},
119 {"COPY INTO",
120 "Parse a csv file into a table or write a query result to a csv file",
121 "COPY [nrofrecords] INTO qname [column_list] FROM string [',' ...] [headerlist] [ON { CLIENT | SERVER }] [ separators]\n"
122 " [NULL [AS] string] [LOCKED] [BEST EFFORT] [NO CONSTRAINT] [FWF '(' integer [',' ...] ')'\n"
123 "COPY [nrofrecords] INTO qname [column_list] FROM STDIN [headerlist] [ separators]\n"
124 " [NULL [AS] string] [LOCKED] [BEST EFFORT] [NO CONSTRAINT]\n"
125 "COPY query_expression INTO [STDOUT | string [ON { CLIENT | SERVER }]] [separators] [NULL [AS] string]",
126 "nrofrecords,qname,column_list,headerlist,separators",
127 "See also https://www.monetdb.org/Documentation/Cookbooks/SQLrecipes/LoadingBulkData"},
128 {"COPY LOADER",
129 "Copy into using a user supplied parsing function",
130 "COPY LOADER INTO qname FROM qname '(' [ scalar_expression ... ] ')'",
131 "qname,scalar_expression",
132 NULL},
133 {"CREATE AGGREGATE",
134 "Create a user-defined aggregate function. The body of the aggregate function\n"
135 "can also be defined in other programming languages such as Python, R, C or CPP.",
136 "CREATE [ OR REPLACE ] AGGREGATE qname '(' { '*' | [ param [',' ...]] } ')'\n"
137 " RETURNS { data_type | TABLE '(' function_return [',' ...] ')' }\n"
138 " EXTERNAL NAME ident ',' ident\n"
139 "CREATE [ OR REPLACE ] AGGREGATE qname '(' { '*' | [ param [',' ...]] } ')'\n"
140 " RETURNS { data_type | TABLE '(' function_return [',' ...] ')' }\n"
141 " LANGUAGE language_keyword external_code",
142 "qname,param,data_type,function_return,ident,language_keyword,external_code",
143 "See also https://www.monetdb.org/Documentation/Manuals/SQLreference/Functions"},
144 {"CREATE FILTER FUNCTION",
145 "",
146 "CREATE [ OR REPLACE ] FILTER FUNCTION qname '(' { '*' | [ param [',' ...]] } ')'\n"
147 " RETURNS { data_type | TABLE '(' function_return [',' ...] ')' }\n"
148 " EXTERNAL NAME ident ',' ident",
149 "qname,param,data_type,function_return,ident",
150 "See also https://www.monetdb.org/Documentation/Manuals/SQLreference/Functions"},
151 {"CREATE FUNCTION",
152 "Create a user-defined function. Besides standard SQL the body of the function\n"
153 "can also be defined in other programming languages such as Python, R, C or CPP.",
154 "CREATE [ OR REPLACE ] FUNCTION qname '(' { '*' | [ param [',' ...]] } ')'\n"
155 " RETURNS { data_type | TABLE '(' function_return [',' ...] ')' }\n"
156 " BEGIN [ ATOMIC ] statement [ ';' ...] END\n"
157 "CREATE [ OR REPLACE ] FUNCTION qname '(' { '*' | [ param [',' ...]] } ')'\n"
158 " RETURNS { data_type | TABLE '(' function_return [',' ...] ')' }\n"
159 " EXTERNAL NAME ident ',' ident\n"
160 "CREATE [ OR REPLACE ] FUNCTION qname '(' { '*' | [ param [',' ...]] } ')'\n"
161 " RETURNS { data_type | TABLE '(' function_return [',' ...] ')' }\n"
162 " LANGUAGE language_keyword external_code",
163 "qname,param,data_type,function_return,statement,ident,language_keyword,external_code",
164 "See also https://www.monetdb.org/Documentation/Manuals/SQLreference/Functions"},
165 {"CREATE INDEX",
166 "Create a hint for a secondary index on a column or set of columns of a table",
167 "CREATE [ UNIQUE | ORDERED | IMPRINTS ] INDEX ident ON qname '(' ident_list ')'",
168 NULL,
169 "See also https://www.monetdb.org/Documentation/Manuals/SQLreference/Indices"},
170 {"CREATE PROCEDURE",
171 "Create a user-defined procedure",
172 "CREATE [ OR REPLACE ] PROCEDURE qname '(' { '*' | [ param [',' ...]] } ')'\n"
173 " BEGIN [ ATOMIC ] procedure_statement [ ';' ...] END\n"
174 "CREATE [ OR REPLACE ] PROCEDURE qname '(' { '*' | [ param [',' ...]] } ')'\n"
175 " EXTERNAL NAME ident ',' ident",
176 "qname,param,procedure_statement,ident",
177 "See also https://www.monetdb.org/Documentation/Manuals/SQLreference/Procedures"},
178 {"CREATE LOADER",
179 "Create a custom (external) data loader function. The body is defined in Python language",
180 "CREATE [ OR REPLACE ] LOADER qname '(' [ param [',' ...]] ')'\n"
181 " LANGUAGE PYTHON external_code",
182 "qname,param,external_code",
183 "See also https://www.monetdb.org/blog/monetdbpython-loader-functions"},
184 {"CREATE MERGE TABLE",
185 "",
186 "CREATE MERGE TABLE [ IF NOT EXISTS ] qname table_source [ partition_by ]",
187 "table_source,partition_by",
188 "See also https://www.monetdb.org/Documentation/Cookbooks/SQLrecipes/DataPartitioning"},
189 {"CREATE REMOTE TABLE",
190 "",
191 "CREATE REMOTE TABLE [ IF NOT EXISTS ] qname ON string [WITH [USER 'username'] [[ENCRYPTED] PASSWORD 'password']]",
192 NULL,
193 "remote name should match mapi:monetdb://host:port/database[/schema[/table]]"},
194 {"CREATE REPLICA TABLE",
195 "",
196 "CREATE REPLICA TABLE [ IF NOT EXISTS ] qname table_source",
197 NULL,
198 "See also https://www.monetdb.org/Documentation/Cookbooks/SQLrecipes/TransactionReplication"},
199 {"CREATE ROLE",
200 "Create a new role. You can grant privileges to a role and next\n"
201 "grant a role (or multiple roles) to specific users",
202 "CREATE ROLE ident [ WITH ADMIN { CURRENT_USER | CURRENT_ROLE } ]",
203 "ident",
204 "See also https://www.monetdb.org/Documentation/SQLreference/Roles"},
205 {"CREATE SCHEMA",
206 "Create a new schema",
207 "CREATE SCHEMA [ IF NOT EXISTS ] schema_name [default_char_set] [path_spec] [schema_element]",
208 "schema_name,default_char_set,path_spec,schema_element",
209 "See also https://www.monetdb.org/Documentation/SQLreference/Schema"},
210 {"CREATE SEQUENCE",
211 "Define a new integer number sequence generator",
212 "CREATE SEQUENCE ident [ AS data_type] [ START [WITH start]] [INCREMENT BY increment]\n"
213 "[MINVALUE minvalue | NO MINVALUE] [MAXVALUE maxvalue | NO MAXVALUE] [CACHE cachevalue] [[NO] CYCLE]",
214 "ident,data_type",
215 "See also https://www.monetdb.org/Documentation/Manuals/SQLreference/SerialTypes"},
216 {"CREATE STREAM TABLE",
217 "Temporary table, locked during updates/ continues query processing",
218 "CREATE STREAM TABLE [ IF NOT EXISTS ] qname table_source\n",
219 "table_source",
220 NULL},
221 {"CREATE TABLE",
222 "Create a new table",
223 "CREATE TABLE [ IF NOT EXISTS ] qname table_source [STORAGE ident string]\n"
224 "CREATE TABLE [ IF NOT EXISTS ] qname FROM LOADER function_ref\n"
225 "CREATE [ LOCAL | GLOBAL ] { TEMPORARY | TEMP } TABLE [ IF NOT EXISTS ] qname table_source [on_commit]",
226 "table_source,on_commit,function_ref",
227 "See also https://www.monetdb.org/Documentation/Manuals/SQLreference/Tables"},
228 {"CREATE TRIGGER",
229 "Define a triggered action for a table data update event",
230 "CREATE [ OR REPLACE ] TRIGGER qname { BEFORE | AFTER }\n"
231 " { INSERT | DELETE | TRUNCATE | UPDATE [ OF ident_list ] }\n"
232 " ON qname [ REFERENCING trigger_reference [...] ] triggered_action",
233 "qname,ident_list,trigger_reference,triggered_action",
234 "See also https://www.monetdb.org/Documentation/SQLreference/Triggers"},
235 {"CREATE TYPE",
236 "Add user defined type to the type system ",
237 "CREATE TYPE qname EXTERNAL NAME ident",
238 NULL,
239 NULL},
240 {"CREATE USER",
241 "Create a new database user",
242 "CREATE USER ident WITH [ENCRYPTED | UNENCRYPTED] PASSWORD string NAME string SCHEMA ident",
243 "ident",
244 "See also https://www.monetdb.org/Documentation/SQLreference/Users"},
245 {"CREATE VIEW",
246 "Create a new view",
247 "CREATE [ OR REPLACE ] VIEW qname [ column_list ] AS { query_expression | '(' query_expression ')' }\n"
248 "[ WITH CHECK OPTION ]",
249 "qname,column_list,query_expression",
250 "See also https://www.monetdb.org/Documentation/Manuals/SQLreference/Views"},
251 {"CURRENT_DATE",
252 "Pseudo column or function to get the current date",
253 "CURRENT_DATE [ '(' ')' ]",
254 NULL,
255 NULL},
256 {"CURRENT_ROLE",
257 "Pseudo column to get the current role name",
258 "CURRENT_ROLE",
259 NULL,
260 NULL},
261 {"CURRENT_SCHEMA",
262 "Pseudo column to get the current schema name",
263 "CURRENT_SCHEMA",
264 NULL,
265 NULL},
266 {"CURRENT_TIME",
267 "Pseudo column or function to get the current time including timezone",
268 "CURRENT_TIME [ '(' ')' ]",
269 NULL,
270 NULL},
271 {"CURRENT_TIMESTAMP",
272 "Pseudo column or function to get the current timestamp including timezone",
273 "CURRENT_TIMESTAMP [ '(' ')' ] | NOW [ '(' ')' ]",
274 NULL,
275 NULL},
276 {"CURRENT_USER",
277 "Pseudo column to get the current user name",
278 "CURRENT_USER | USER",
279 NULL,
280 NULL},
281 {"EXPLAIN",
282 "Give execution plan details",
283 "EXPLAIN statement",
284 NULL,
285 "See also https://www.monetdb.org/Documentation/Manuals/SQLreference/Explain"},
286 {"LOCALTIME",
287 "Pseudo column or function to get the current client time excluding timezone",
288 "LOCALTIME [ '(' ')' ]",
289 NULL,
290 NULL},
291 {"LOCALTIMESTAMP",
292 "Pseudo column or function to get the current client timestamp excluding timezone",
293 "LOCALTIMESTAMP [ '(' ')' ]",
294 NULL,
295 NULL},
296 {"EXTRACT",
297 "Built-in function",
298 "EXTRACT '(' { YEAR | MONTH | DAY | HOUR | MINUTE | SECOND } FROM scalar_expression ')'",
299 NULL,
300 NULL},
301 {"DECLARE",
302 "Define a local variable",
303 "DECLARE ident_list data_type",
304 "ident_list,data_type",
305 NULL},
306 {"DELETE",
307 "",
308 "[ WITH cte_list ] DELETE FROM qname [ [AS] ident ] [ WHERE search_condition ]",
309 "cte_list,search_condition",
310 NULL},
311 {"DROP AGGREGATE",
312 "",
313 "DROP ALL AGGREGATE qname [ RESTRICT | CASCADE ]\n"
314 "DROP AGGREGATE [ IF EXISTS ] qname [ '(' [ param [',' ...]] ')' ] [ RESTRICT | CASCADE ]",
315 "param",
316 NULL},
317 {"DROP FUNCTION",
318 "",
319 "DROP ALL [FILTER] FUNCTION qname [ RESTRICT | CASCADE ]\n"
320 "DROP [FILTER] FUNCTION [ IF EXISTS ] qname [ '(' [ param [',' ...]] ')' ] [ RESTRICT | CASCADE ]",
321 "param",
322 NULL},
323 {"DROP INDEX",
324 "",
325 "DROP INDEX qname",
326 NULL,
327 NULL},
328 {"DROP LOADER",
329 "",
330 "DROP ALL LOADER qname [ RESTRICT | CASCADE ]\n"
331 "DROP LOADER [ IF EXISTS ] qname [ '(' [ param [',' ...]] ')' ] [ RESTRICT | CASCADE ]",
332 "param",
333 NULL},
334 {"DROP PROCEDURE",
335 "",
336 "DROP ALL PROCEDURE qname [ RESTRICT | CASCADE ]\n"
337 "DROP PROCEDURE [ IF EXISTS ] qname [ '(' [ param [',' ...]] ')' ] [ RESTRICT | CASCADE ]",
338 "param",
339 NULL},
340 {"DROP ROLE",
341 "",
342 "DROP ROLE ident",
343 NULL,
344 NULL},
345 {"DROP SCHEMA",
346 "",
347 "DROP SCHEMA [ IF EXISTS ] qname [ RESTRICT | CASCADE ]",
348 NULL,
349 NULL},
350 {"DROP SEQUENCE",
351 "",
352 "DROP SEQUENCE qname",
353 NULL,
354 NULL},
355 {"DROP TABLE",
356 "",
357 "DROP TABLE [ IF EXISTS ] qname [ RESTRICT | CASCADE ]",
358 NULL,
359 NULL},
360 {"DROP TRIGGER",
361 "",
362 "DROP TRIGGER [ IF EXISTS ] qname",
363 NULL,
364 NULL},
365 {"DROP TYPE",
366 "",
367 "DROP TYPE qname [ RESTRICT | CASCADE ]",
368 NULL,
369 NULL},
370 {"DROP USER",
371 "",
372 "DROP USER ident",
373 NULL,
374 NULL},
375 {"DROP VIEW",
376 "",
377 "DROP VIEW [ IF EXISTS ] qname [ RESTRICT | CASCADE ]",
378 NULL,
379 NULL},
380 {"IF",
381 "",
382 "IF search_condition THEN procedure_statement ...\n"
383 "[ELSE IF search_condition THEN procedure_statement ... ]...\n"
384 "[ ELSE procedure_statement ... ] END IF",
385 "search_condition,procedure_statement",
386 "See also https://www.monetdb.org/Documentation/SQLreference/Flowofcontrol"},
387 {"INSERT",
388 "",
389 "[ WITH cte_list ] INSERT INTO qname [ column_list ] [ { DEFAULT VALUES | VALUES row_values | query_expression } ]",
390 "cte_list,column_list,row_values,query_expression",
391 "See also https://www.monetdb.org/Documentation/SQLreference/Updates"},
392 {"GRANT",
393 "Define access privileges",
394 "GRANT privileges TO grantee [',' ...] [ WITH GRANT OPTION ]\n"
395 "GRANT role [',' ...] TO grantee [',' ...] [ WITH ADMIN OPTION]",
396 "privileges,table_privileges,global_privileges,role,grantee",
397 "See also https://www.monetdb.org/Documentation/SQLreference/Permissions"},
398 {"MERGE",
399 "",
400 "[ WITH cte_list ] MERGE INTO qname [ [AS] ident ] USING table_ref [ [AS] ident ] ON search_condition merge_list",
401 "cte_list,table_ref,search_condition,merge_list",
402 "See also: https://www.monetdb.org/blog/sql2003_merge_statements_now_supported"},
403 {"RELEASE SAVEPOINT",
404 "",
405 "RELEASE SAVEPOINT ident",
406 NULL,
407 NULL},
408 {"RETURN",
409 "",
410 "RETURN { query_expression | search_condition | TABLE '(' query_expression ')'",
411 "query_expression,search_condition",
412 NULL},
413 {"REVOKE",
414 "Remove some privileges",
415 "REVOKE [GRANT OPTION FOR] privileges FROM { grantee [',' ...] | CURRENT_USER | CURRENT_ROLE }\n"
416 "REVOKE [ADMIN OPTION FOR] role [',' ...] FROM { grantee [',' ...] | CURRENT_USER | CURRENT_ROLE }",
417 "privileges,table_privileges,global_privileges,grantee,role",
418 "See also https://www.monetdb.org/Documentation/SQLreference/Permissions"},
419 {"ROLLBACK",
420 "Rollback the current transaction",
421 "ROLLBACK [WORK] [ AND CHAIN | AND NO CHAIN ] [TO SAVEPOINT ident]",
422 NULL,
423 NULL},
424 {"SAVEPOINT",
425 NULL,
426 "SAVEPOINT ident",
427 NULL,
428 NULL},
429 {"SELECT",
430 "",
431 "[ WITH cte_list ]\n"
432 "SELECT [ ALL | DISTINCT [ ON { expression [',' ...] } ] ]\n"
433 "[ '*' | expression [ [ AS ] output_name ] [',' ...] ]\n"
434 "[ FROM from_item [',' ...] ]\n"
435 "[ WINDOW window_definition [',' ...] ]\n"
436 "[ WHERE condition ]\n"
437 "[ GROUP BY expression [',' ...] ]\n"
438 "[ HAVING condition [',' ...] ]\n"
439 "[ { UNION | INTERSECT | EXCEPT } [ ALL | DISTINCT ] [ CORRESPONDING ] select ]\n"
440 "[ ORDER BY expression [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [',' ...] ]\n"
441 "[ LIMIT { count | param } ]\n"
442 "[ OFFSET { count | param } ]\n"
443 "[ SAMPLE size [ SEED size ] ]",
444 "cte_list,expression,window_definition",
445 "See also https://www.monetdb.org/Documentation/SQLreference/TableExpressions"},
446 {"SET",
447 "Assign a value to a variable or column",
448 "SET ident '=' simple_atom",
449 "simple_atom",
450 "See also https://www.monetdb.org/Documentation/Manuals/SQLreference/Variables"},
451 {"SET LOCAL TRANSACTION",
452 "",
453 "START LOCAL TRANSACTION transactionmode",
454 "transactionmode,isolevel",
455 "DIAGNOSTICS is not yet supported"},
456 {"SET ROLE",
457 "",
458 "SET ROLE ident",
459 NULL,
460 NULL},
461 {"SET SCHEMA",
462 "",
463 "SET SCHEMA ident",
464 NULL,
465 NULL},
466 {"SET SESSION AUTHORIZATION",
467 "",
468 "SET SESSION AUTHORIZATION ident",
469 NULL,
470 NULL},
471 {"SET TIME ZONE",
472 NULL,
473 "SET TIME ZONE interval",
474 "interval",
475 NULL},
476 {"SET TIME ZONE LOCAL",
477 NULL,
478 "SET TIME ZONE LOCAL",
479 NULL,
480 NULL},
481 {"SET TRANSACTION",
482 "",
483 "SET TRANSACTION transactionmode",
484 "transactionmode,isolevel",
485 "DIAGNOSTICS is not yet supported"},
486 {"START TRANSACTION",
487 "",
488 "START TRANSACTION transactionmode",
489 "transactionmode,isolevel",
490 "DIAGNOSTICS is not yet supported"},
491 {"SET USER",
492 "",
493 "SET USER '=' ident",
494 NULL,
495 NULL},
496 {"TABLE JOINS",
497 "",
498 "'(' joined_table ') |\n"
499 "table_ref CROSS JOIN table_ref ')' |\n"
500 "table_ref NATURAL [ INNER | LEFT | RIGHT | FULL ] JOIN table_ref |\n"
501 "table_ref UNION JOIN table_ref { ON search_condition | USING column_list } |\n"
502 "table_ref [ INNER | LEFT | RIGHT | FULL ] JOIN table_ref { ON search_condition | USING column_list }",
503 "table_ref,search_condition,column_list",
504 "See also https://www.monetdb.org/Documentation/SQLreference/TableExpressions"},
505 {"TRACE",
506 "Give execution trace",
507 "TRACE statement",
508 NULL,
509 NULL},
510 {"TRUNCATE",
511 "",
512 "TRUNCATE [ TABLE ] qname [ CONTINUE IDENTITY | RESTART IDENTITY ] [ CASCADE | RESTRICT ]",
513 "",
514 NULL},
515 {"UPDATE",
516 "",
517 "[ WITH cte_list ] UPDATE qname [ [AS] ident ] SET assignment_list [ FROM from_item ] [ WHERE search_condition ]",
518 "cte_list,assignment_list,search_condition",
519 NULL},
520 {"VALUES",
521 "",
522 "VALUES row_values",
523 "row_values",
524 NULL},
525 {"WHILE",
526 "",
527 "[ident ':'] WHILE search_condition DO procedure_statement ... END WHILE [ident]",
528 "search_condition,procedure_statement",
529 "See also https://www.monetdb.org/Documentation/SQLreference/Flowofcontrol"},
530 {"WINDOW FUNCTIONS",
531 "",
532 "{ window_aggregate_function | window_rank_function } OVER { ident | '(' window_specification ')' }",
533 "window_aggregate_function,window_rank_function,window_specification",
534 "See also https://www.monetdb.org/Documentation/Manuals/SQLreference/WindowFunctions"},
535 {NULL, NULL, NULL, NULL, NULL} /* End of list marker */
536};
537SQLhelp sqlhelp2[] = {
538// The subgrammar rules
539 {"assignment_list",
540 NULL,
541 "column '=' DEFAULT | column '=' search_condition | '(' column [',' ...] ')' '=' subquery",
542 "search_condition,column,subquery",
543 NULL},
544 {"authid",
545 NULL,
546 "restricted ident",
547 NULL,
548 NULL},
549 {"column_def",
550 NULL,
551 "COLUMN { data_type [ column_option ... ] | SERIAL | BIGSERIAL }",
552 "data_type,column_option",
553 NULL},
554 {"column_list",
555 NULL,
556 "'(' ident [',' ...] ')'",
557 NULL,
558 NULL},
559 {"column_option",
560 NULL,
561 "DEFAULT value | column_constraint | generated_column",
562 "column_constraint,generated_column",
563 NULL},
564 {"column_option_list",
565 NULL,
566 "ident WITH OPTIONS '(' column_constraint ')' [',' ...]",
567 "column_constraint",
568 NULL},
569 {"column_constraint",
570 NULL,
571 "[ CONSTRAINT ident ] { NOT NULL | NULL | UNIQUE | PRIMARY KEY | CHECK '(' search_condition ')' |\n"
572 " REFERENCES qname [ column_list ] [ match_options ] [ reference_action ] }\n",
573 "column_list,search_condition,match_options,reference_action",
574 "See also https://www.monetdb.org/Documentation/SQLreference/TableIdentityColumn"},
575 {"control_statement",
576 NULL,
577 "call_procedure | while_statement | if_statement | case_statement | return_statement",
578 "call_procedure | while_statement | if_statement | case_statement | return_statement",
579 NULL},
580 {"datetime_type",
581 NULL,
582 "DATE | TIME [ time_precision ] [ WITH TIME ZONE ] |\n"
583 " TIMESTAMP [ timestamp_precision ] [ WITH TIME ZONE ]",
584 "time_precision,timestamp_precision",
585 "See also https://www.monetdb.org/Documentation/SQLreference/Temporal"},
586 {"data_type",
587 NULL,
588 "BOOLEAN | BOOL | TINYINT | SMALLINT | INT | INTEGER | BIGINT | HUGEINT |\n"
589 " { DECIMAL | DEC | NUMERIC | FLOAT } [ '(' nonzero [',' nonzero ] ')' ] |\n"
590 " REAL | DOUBLE [ PRECISION ] |\n"
591 " { VARCHAR | CHARACTER VARYING } '(' nonzero ')' |\n"
592 " { CHAR | CHARACTER [ LARGE OBJECT ] | CLOB | TEXT | STRING | JSON | URL } [ '(' nonzero ')' ] |\n"
593 " { BINARY LARGE OBJECT | BLOB } [ '(' nonzero ')' ] |\n"
594 " UUID | INET | datetime_type | interval_type | geometry_type",
595 "datetime_type,interval_type,geometry_type",
596 "See also https://www.monetdb.org/Documentation/Manuals/SQLreference/Datatypes"},
597 {"default_char_set",
598 NULL,
599 "DEFAULT CHARACTER SET ident",
600 NULL,
601 NULL},
602 {"drop_table_element",
603 NULL,
604 "{ CONSTRAINT | TABLE | COLUMN } ident [ RESTRICT | CASCADE ]",
605 NULL,
606 NULL},
607 {"end_time",
608 NULL,
609 "SECOND timestamp_precision\n,timestamp_precision",
610 NULL,
611 NULL},
612 {"function_return",
613 NULL,
614 "ident data_type",
615 NULL,
616 NULL},
617 {"generated_column",
618 NULL,
619 "AUTO_INCREMENT | GENERATED ALWAYS AS IDENTITY [ '(' [ AS data_type] [ START [WITH start]] [INCREMENT BY increment]\n"
620 "[MINVALUE minvalue | NO MINVALUE] [MAXVALUE maxvalue | NO MAXVALUE] [CACHE cachevalue] [[NO] CYCLE] ')' ] ",
621 "data_type",
622 "See also https://www.monetdb.org/Documentation/Manuals/SQLreference/SerialTypes"},
623 {"global_privileges",
624 NULL,
625 "{ COPY FROM | COPY INTO } [',' ...]",
626 NULL,
627 NULL},
628 {"grantee",
629 NULL,
630 "{ PUBLIC | authid } ",
631 "authid",
632 NULL},
633 {"headerlist",
634 NULL,
635 "'(' { ident [string] } [',' ...] ')'",
636 NULL,
637 NULL},
638 {"ident",
639 "An identifier. Use double quote's around the identifier name to include\n"
640 " mixed/upper case letters and/or special characters",
641 NULL,
642 NULL,
643 NULL},
644 {"ident_list",
645 NULL,
646 "ident [',' ...]",
647 "ident",
648 NULL},
649 {"interval",
650 NULL,
651 "INTERVAL [ '+' | '-' ] string start_field TO end_field",
652 "start_field,end_field",
653 NULL},
654 {"interval_type",
655 NULL,
656 "INTERVAL { YEAR | MONTH | DAY | HOUR | MINUTE | SECOND [time_precision] | start_field TO end_field }",
657 "time_precision,start_field,end_field",
658 NULL},
659 {"intval",
660 "Integer value",
661 NULL,
662 NULL,
663 NULL},
664 {"isolevel",
665 NULL,
666 "READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE",
667 NULL,
668 NULL},
669 {"language_keyword",
670 NULL,
671 "C | CPP | R | PYTHON | PYTHON_MAP | PYTHON2 | PYTHON2_MAP | PYTHON3 | PYTHON3_MAP",
672 NULL,
673 NULL},
674 {"match_options",
675 NULL,
676 "MATCH { FULL | PARTIAL | SIMPLE }",
677 NULL,
678 NULL},
679 {"merge_list",
680 NULL,
681 "merge_clause [ merge_clause ]",
682 "merge_clause",
683 NULL},
684 {"merge_clause",
685 NULL,
686 "{ WHEN NOT MATCHED THEN INSERT [ column_list ] [ { VALUES row_values | DEFAULT VALUES } ]\n"
687 "| WHEN MATCHED THEN { UPDATE SET assignment_list | DELETE } }",
688 "column_list,row_values,assignment_list",
689 NULL},
690 {"nrofrecords",
691 "",
692 "OFFSET integer | integer RECORDS | integer OFFSET integer RECORDS | integer RECORDS OFFSET integer",
693 NULL,
694 NULL},
695 {"on_commit",
696 NULL,
697 "ON COMMIT { DELETE ROWS | PRESERVE ROWS | DROP }",
698 NULL,
699 NULL},
700 {"partition_by",
701 NULL,
702 "PARTITION BY { RANGE | VALUES } { ON '(' ident ')' | USING '(' query_expression ')' }",
703 "query_expression",
704 "See also: https://www.monetdb.org/blog/updatable-merge-tables"},
705 {"partition_spec",
706 NULL,
707 "{ IN '(' partition_list ')' [ WITH NULL VALUES ]\n"
708 "| FROM partition_range_from TO partition_range_to [ WITH NULL VALUES ]\n"
709 "| FOR NULL VALUES }",
710 "partition_list,partition_range_from,partition_range_to",
711 "See also: https://www.monetdb.org/blog/updatable-merge-tables"},
712 {"param",
713 NULL,
714 "ident data_type",
715 NULL,
716 NULL},
717 {"partition_list",
718 NULL,
719 "query_expression [ ',' ... ]",
720 "query_expression",
721 NULL},
722 {"partition_range_from",
723 NULL,
724 "{ RANGE MINVALUE | query_expression }",
725 "query_expression",
726 NULL},
727 {"partition_range_to",
728 NULL,
729 "{ RANGE MAXVALUE | query_expression }",
730 "query_expression",
731 NULL},
732 {"privileges",
733 NULL,
734 "table_privileges | EXECUTE ON [ FUNCTION | AGGREGATE ] qname | global_privileges",
735 "table_privileges,global_privileges",
736 NULL},
737 {"procedure_statement",
738 NULL,
739 "{ transaction_statement | update_statement | grant | revoke |\n"
740 " declare | set_statement | control_statement | select_single_row } ';'",
741 "transaction_statement,update_statement,grant,revoke,declare,set_statement,control_statement,select_single_row",
742 NULL},
743 {"select_single_row",
744 NULL,
745 "SELECT [ ALL | DISTINCT ] column_exp_commalist INTO select_target_list [ from_clause ] [ window_clause ] [ where_clause ] [ group_by_clause ] [ having_clause ]",
746 "column_exp_commalist,select_target_list,from_clause,window_clause,where_clause,group_by_clause,having_clause",
747 NULL},
748 {"query_expression",
749 NULL,
750 "select_no_parens [ order_by_clause ] [ limit_clause ] [ offset_clause ] [ sample_clause ]",
751 "select_no_parens,order_by_clause,limit_clause,offset_clause,sample_clause",
752 NULL},
753 {"select_no_parens",
754 NULL,
755 "{ SELECT [ ALL | DISTINCT ] column_exp_commalist [ from_clause ] [ window_clause ] [ where_clause ] [ group_by_clause ] [ having_clause ]\n"
756 "| select_no_parens { UNION | EXCEPT | INTERSECT } [ ALL | DISTINCT ] [ corresponding ] select_no_parens\n"
757 "| '(' select_no_parens ')' }",
758 "column_exp_commalist,from_clause,window_clause,where_clause,group_by_clause,having_clause,corresponding",
759 NULL},
760 {"corresponding",
761 NULL,
762 "{ CORRESPONDING | CORRESPONDING BY '(' column_ref_commalist ')' }",
763 "column_ref_commalist",
764 NULL},
765 {"qname",
766 NULL,
767 "ident [ '.' ident ['.' ident]]",
768 NULL,
769 NULL},
770 {"reference_action",
771 NULL,
772 "ON { UPDATE | DELETE } { NO ACTION | CASCADE | RESTRICT | SET NULL | SET DEFAULT }",
773 NULL,
774 NULL},
775 {"row_values",
776 NULL,
777 "'(' atom [ ',' atom ]... ')' [ ',' row_values ] ...",
778 "atom",
779 NULL},
780 {"schema_name",
781 NULL,
782 "ident | [ident] AUTHORIZATION authorization_ident",
783 NULL,
784 NULL},
785 {"schema_element",
786 NULL,
787 "grant | revoke | create_statement | drop_statement | alter_statement",
788 NULL,
789 NULL},
790 {"separators",
791 NULL,
792 "[USING] DELIMITERS field_sep_string [',' record_sep_string [',' quote_string]]",
793 NULL,
794 NULL},
795 {"split_part",
796 NULL,
797 "SPLIT_PART '(' string ',' delimiter_string ',' field_index ')'",
798 NULL,
799 NULL,},
800 {"table_constraint",
801 NULL,
802 "[ CONSTRAINT ident ] { PRIMARY KEY column_list | UNIQUE column_list |\n"
803 " FOREIGN KEY column_list REFERENCES qname [ column_list ] [ match_options ] [ reference_action ] }",
804 "column_list,match_options,reference_action",
805 "See also https://www.monetdb.org/Documentation/SQLreference/TableIdentityColumn"},
806 {"table_element",
807 NULL,
808 "column_def | table_constraint | column_option_list | LIKE qname",
809 "column_def,table_constraint,column_option_list",
810 NULL},
811 {"table_name",
812 NULL,
813 "[AS] ident ['(' name [',' ...] ')' ]",
814 NULL,
815 NULL},
816 {"table_privileges",
817 NULL,
818 "{ ALL [ PRIVILEGES ] | INSERT | DELETE | TRUNCATE\n"
819 "| { SELECT | UPDATE | REFERENCES } [ column_list ] } [',' ...] ON [ TABLE ] qname",
820 "column_list",
821 NULL},
822 {"table_ref",
823 NULL,
824 "[LATERAL] func_ref [table_name] | [LATERAL] subquery | joined_table",
825 "table_name,subquery",
826 NULL},
827 {"table_source",
828 NULL,
829 "'(' table_element [',' ...] ')' | column_list AS query_expression [ WITH [NO] DATA ] ",
830 "table_element,column_list,query_expression",
831 NULL},
832 {"transaction_statement",
833 NULL,
834 "commit | savepoint | release | rollback | start transaction | set local transaction",
835 "commit,savepoint,release,rollback,start transaction,set local transaction",
836 NULL},
837 {"time_precision",
838 NULL,
839 "'(' integer ')'",
840 NULL,
841 NULL},
842 {"timestamp_precision",
843 NULL,
844 "'(' integer ')'",
845 NULL,
846 NULL},
847 {"transactionmode",
848 NULL,
849 "{ READ ONLY | READ WRITE | ISOLATION LEVEL isolevel | DIAGNOSTICS intval } [ , ... ]",
850 "isolevel",
851 NULL},
852 {"trigger_reference",
853 NULL,
854 "{ OLD | NEW } { [ROW] | TABLE } [AS] ident",
855 NULL,
856 NULL},
857 {"update_statement",
858 NULL,
859 "delete_stmt | truncate_stmt | insert_stmt | update_stmt | merge_stmt | copyfrom_stmt",
860 "delete_stmt,truncate_stmt,insert_stmt,update_stmt,merge_stmt,copyfrom_stmt",
861 NULL},
862 {"triggered_action",
863 NULL,
864 "[ FOR [EACH] { ROW | STATEMENT } ]\n"
865 "[ WHEN '(' search_condition ')' ]\n"
866 "{ trigger_statement | BEGIN ATOMIC trigger_statement [ ; ... ] END }",
867 "trigger_statement,search_condition",
868 NULL},
869 {"trigger_statement",
870 NULL,
871 "transaction_statement | update_statement | grant | revoke | declare_statement |\n"
872 " set_statement | control_statement | select_single_row",
873 "transaction_statement,update_statement,grant,revoke,declare_statement,set_statement,control_statement,select_single_row",
874 NULL},
875 {"when_statement",
876 NULL,
877 "WHEN scalar_expression THEN procedure_statement ...",
878 "procedure_statement",
879 NULL},
880 {"window_aggregate_function",
881 NULL,
882 "{ AVG '(' query_expression ')' | COUNT '(' { '*' | query_expression } ')' | MAX '(' query_expression ')'\n"
883 "| MIN '(' query_expression ')' | PROD '(' query_expression ')' | SUM '(' query_expression ')' }",
884 "query_expression",
885 NULL},
886 {"window_bound",
887 NULL,
888 "{ UNBOUNDED FOLLOWING | query_expression FOLLOWING | UNBOUNDED PRECEDING | query_expression PRECEDING | CURRENT ROW }",
889 "query_expression",
890 NULL},
891 {"window_definition",
892 NULL,
893 "ident AS '(' window_specification ')'",
894 "window_specification",
895 NULL},
896 {"window_frame_start",
897 NULL,
898 "{ UNBOUNDED PRECEDING | query_expression PRECEDING | CURRENT ROW }",
899 "query_expression",
900 NULL},
901 {"window_rank_function",
902 NULL,
903 "{ CUME_DIST '(' ')' | DENSE_RANK '(' ')' | FIRST_VALUE '(' query_expression ')'\n"
904 "| LAG '(' query_expression [ ',' query_expression [ ',' query_expression ] ] ')' | LAST_VALUE '(' query_expression ')'\n"
905 "| LEAD '(' query_expression [ ',' query_expression [ ',' query_expression ] ] ')'\n"
906 "| NTH_VALUE '(' query_expression ',' query_expression ')' | NTILE '(' query_expression ')'\n"
907 "| PERCENT_RANK '(' ')' | RANK '(' ')' | ROW_NUMBER '(' ')' }",
908 "query_expression",
909 NULL},
910 {"window_specification",
911 NULL,
912 "[ ident ]\n"
913 "[ PARTITION BY expression [ ',' ... ] ]\n"
914 "[ ORDER BY expression [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [ ',' ... ] ]\n"
915 "[ { ROWS | RANGE | GROUPS } { window_frame_start | BETWEEN window_bound AND window_bound }\n"
916 " [ EXCLUDING { CURRENT ROW | GROUP | TIES | NO OTHERS } ] ]",
917 "window_bound,window_frame_start",
918 NULL},
919 {"cte_list",
920 NULL,
921 "ident [ column_list ] AS query_expression [ ',' cte_list ] ...",
922 "column_list,query_expression",
923 NULL},
924 {NULL, NULL, NULL, NULL, NULL} /* End of list marker */
925};
926
927#ifndef HAVE_STRNCASECMP
928static int
929strncasecmp(const char *s1, const char *s2, size_t n)
930{
931 int c1, c2;
932
933 while (n > 0) {
934 c1 = (unsigned char) *s1++;
935 c2 = (unsigned char) *s2++;
936 if (c1 == 0)
937 return -c2;
938 if (c2 == 0)
939 return c1;
940 if (c1 != c2 && tolower(c1) != tolower(c2))
941 return tolower(c1) - tolower(c2);
942 n--;
943 }
944 return 0;
945}
946#endif
947
948static const char *
949sql_grammar_rule(const char *word, stream *toConsole)
950{
951 char buf[65], *s = buf;
952 int i;
953 while (s < buf + 64 && *word != ',' && *word && !isspace((unsigned char) *word))
954 *s++ = *word++;
955 *s = 0;
956
957 for (i = 0; sqlhelp2[i].command; i++) {
958 if (strcasecmp(sqlhelp2[i].command, buf) == 0) {
959 if (sqlhelp2[i].syntax) {
960 mnstr_printf(toConsole, "%s : %s\n", buf, sqlhelp2[i].syntax);
961 if (sqlhelp2[i].synopsis)
962 mnstr_printf(toConsole, "%.*s %s\n", (int) (s - buf), "", sqlhelp2[i].synopsis);
963 } else if (sqlhelp2[i].synopsis)
964 mnstr_printf(toConsole, "%s : %s\n", buf, sqlhelp2[i].synopsis);
965 }
966 }
967 while (*word && (isalnum((unsigned char) *word || *word == '_')))
968 word++;
969 while (*word && isspace((unsigned char) *word))
970 word++;
971 return *word == ',' ? word + 1 : NULL;
972}
973
974static void
975sql_grammar(SQLhelp *sqlhelp, stream *toConsole)
976{
977 const char *t1;
978 if (sqlhelp->synopsis == NULL) {
979 mnstr_printf(toConsole, "%s : %s\n", sqlhelp->command, sqlhelp->syntax);
980 if (sqlhelp->comments)
981 mnstr_printf(toConsole, "%s\n", sqlhelp->comments);
982 t1 = sqlhelp->rules;
983 if (t1 && *t1)
984 do
985 t1 = sql_grammar_rule(t1, toConsole);
986 while (t1);
987 return;
988 }
989 if (sqlhelp->command)
990 mnstr_printf(toConsole, "command : %s\n", sqlhelp->command);
991 if (sqlhelp->synopsis && *sqlhelp->synopsis)
992 mnstr_printf(toConsole, "synopsis : %s\n", sqlhelp->synopsis);
993 if (sqlhelp->syntax && *sqlhelp->syntax) {
994 mnstr_printf(toConsole, "syntax : ");
995 for (t1 = sqlhelp->syntax; *t1; t1++) {
996 if (*t1 == '\n')
997 mnstr_printf(toConsole, "\n ");
998 else
999 mnstr_printf(toConsole, "%c", *t1);
1000 }
1001 mnstr_printf(toConsole, "\n");
1002 t1 = sqlhelp->rules;
1003 if (t1 && *t1)
1004 do
1005 t1 = sql_grammar_rule(t1, toConsole);
1006 while (t1);
1007 }
1008 if (sqlhelp->comments)
1009 mnstr_printf(toConsole, "%s\n", sqlhelp->comments);
1010}
1011
1012static void
1013sql_word(const char *word, size_t maxlen, stream *toConsole)
1014{
1015 size_t i;
1016
1017 mnstr_printf(toConsole, "%s", word);
1018 for (i = strlen(word); i <= maxlen; i++)
1019 mnstr_printf(toConsole, " ");
1020}
1021
1022void
1023sql_help(const char *pattern, stream *toConsole, int pagewidth)
1024{
1025 size_t maxlen = 1, len;
1026 int i, step, ncolumns, total = 0;
1027
1028 if (*pattern == '\\')
1029 pattern++;
1030 while (*pattern && !isspace((unsigned char) *pattern)) {
1031 pattern++;
1032 }
1033 while (*pattern && isspace((unsigned char) *pattern)) {
1034 pattern++;
1035 }
1036
1037 if (*pattern && *pattern != '*') {
1038 bool first = true;
1039 size_t patlen = strlen(pattern);
1040 /* ignore possible final newline in pattern */
1041 if (pattern[patlen - 1] == '\n')
1042 patlen--;
1043 for (i = 0; sqlhelp1[i].command; i++)
1044 if (strncasecmp(sqlhelp1[i].command, pattern, patlen) == 0) {
1045 if (!first)
1046 mnstr_printf(toConsole, "\n");
1047 sql_grammar(&sqlhelp1[i], toConsole);
1048 first = false;
1049 }
1050 for (i = 0; sqlhelp2[i].command; i++)
1051 if (strncasecmp(sqlhelp2[i].command, pattern, patlen) == 0) {
1052 if (!first)
1053 mnstr_printf(toConsole, "\n");
1054 sql_grammar(&sqlhelp2[i], toConsole);
1055 first = false;
1056 }
1057 return;
1058 }
1059 // collect the major topics
1060 for (i = 0; sqlhelp1[i].command; i++) {
1061 total++;
1062 if ((len = strlen(sqlhelp1[i].command)) > maxlen)
1063 maxlen = len;
1064 }
1065 if (*pattern == '*') {
1066 for (i = 0; sqlhelp2[i].command; i++) {
1067 total++;
1068 if ((len = strlen(sqlhelp2[i].command)) > maxlen)
1069 maxlen = len;
1070 }
1071 }
1072
1073 // provide summary of all major topics (=search terms)
1074 ncolumns = (int) maxlen > pagewidth ? 1 : (int) (pagewidth / maxlen);
1075 if (ncolumns > 1 && ncolumns * (int) maxlen + ncolumns - 1 > pagewidth)
1076 ncolumns--;
1077 step = total / ncolumns;
1078 if(total % ncolumns) {
1079 step++;
1080 }
1081 for (i = 0; i < step; i++) {
1082 for (int j = 0; j < ncolumns; j++) {
1083 size_t nextNum = i + j * step;
1084 if(nextNum < sizeof(sqlhelp1)/sizeof(sqlhelp1[0]) - 1) {
1085 sql_word(sqlhelp1[nextNum].command, j < ncolumns - 1 ? maxlen : 0, toConsole);
1086 }
1087 }
1088 mnstr_printf(toConsole, "\n");
1089 }
1090 mnstr_printf(toConsole,
1091 "Using the conventional grammar constructs:\n"
1092 "[ A | B ] token A or B or none\n"
1093 "{ A | B } exactly one of the options A or B should be chosen\n"
1094 "A [',' ...] a comma separated list of A elements\n"
1095 "{ A | B } ... a series of A and B's\n"
1096 "{ A B } [',' ...] a series of A B,A B,A B,A B\n"
1097 "For more search terms type: \\help *\n"
1098 "See also https://www.monetdb.org/Documentation/SQLreference\n");
1099}
1100