1 %{
2 #if USE_WINDOWS
3 #pragma warning(push,1)
4 #pragma warning(disable:4702) // unreachable code
5 #endif
6 %}
7 
8 %lex-param		{ SqlParser_c * pParser }
9 %parse-param	{ SqlParser_c * pParser }
10 %pure-parser
11 %error-verbose
12 
13 %token	TOK_IDENT
14 %token	TOK_ATIDENT
15 %token	TOK_CONST_INT
16 %token	TOK_CONST_FLOAT
17 %token	TOK_CONST_MVA
18 %token	TOK_QUOTED_STRING
19 %token	TOK_USERVAR
20 %token	TOK_SYSVAR
21 %token	TOK_CONST_STRINGS
22 %token	TOK_BAD_NUMERIC
23 %token	TOK_SUBKEY
24 %token	TOK_DOT_NUMBER
25 
26 %token	TOK_ADD
27 %token	TOK_AGENT
28 %token	TOK_ALTER
29 %token	TOK_AS
30 %token	TOK_ASC
31 %token	TOK_ATTACH
32 %token	TOK_ATTRIBUTES
33 %token	TOK_AVG
34 %token	TOK_BEGIN
35 %token	TOK_BETWEEN
36 %token	TOK_BIGINT
37 %token	TOK_BOOL
38 %token	TOK_BY
39 %token	TOK_CALL
40 %token	TOK_CHARACTER
41 %token	TOK_CHUNK
42 %token	TOK_COLLATION
43 %token	TOK_COLUMN
44 %token	TOK_COMMIT
45 %token	TOK_COMMITTED
46 %token	TOK_COUNT
47 %token	TOK_CREATE
48 %token	TOK_DATABASES
49 %token	TOK_DELETE
50 %token	TOK_DESC
51 %token	TOK_DESCRIBE
52 %token	TOK_DISTINCT
53 %token	TOK_DIV
54 %token	TOK_DOUBLE
55 %token	TOK_DROP
56 %token	TOK_FACET
57 %token	TOK_FALSE
58 %token	TOK_FLOAT
59 %token	TOK_FLUSH
60 %token	TOK_FOR
61 %token	TOK_FROM
62 %token	TOK_FUNCTION
63 %token	TOK_GLOBAL
64 %token	TOK_GROUP
65 %token	TOK_GROUPBY
66 %token	TOK_GROUP_CONCAT
67 %token	TOK_HAVING
68 %token	TOK_ID
69 %token	TOK_IN
70 %token	TOK_INDEX
71 %token	TOK_INSERT
72 %token	TOK_INT
73 %token	TOK_INTEGER
74 %token	TOK_INTO
75 %token	TOK_IS
76 %token	TOK_ISOLATION
77 %token	TOK_JSON
78 %token	TOK_LEVEL
79 %token	TOK_LIKE
80 %token	TOK_LIMIT
81 %token	TOK_MATCH
82 %token	TOK_MAX
83 %token	TOK_META
84 %token	TOK_MIN
85 %token	TOK_MOD
86 %token	TOK_MULTI
87 %token	TOK_MULTI64
88 %token	TOK_NAMES
89 %token	TOK_NULL
90 %token	TOK_OPTION
91 %token	TOK_ORDER
92 %token	TOK_OPTIMIZE
93 %token	TOK_PLAN
94 %token	TOK_PLUGIN
95 %token	TOK_PLUGINS
96 %token	TOK_PROFILE
97 %token	TOK_RAND
98 %token	TOK_RAMCHUNK
99 %token	TOK_READ
100 %token	TOK_RECONFIGURE
101 %token	TOK_REPEATABLE
102 %token	TOK_REPLACE
103 %token	TOK_REMAP
104 %token	TOK_RETURNS
105 %token	TOK_ROLLBACK
106 %token	TOK_RTINDEX
107 %token	TOK_SELECT
108 %token	TOK_SERIALIZABLE
109 %token	TOK_SET
110 %token	TOK_SETTINGS
111 %token	TOK_SESSION
112 %token	TOK_SHOW
113 %token	TOK_SONAME
114 %token	TOK_START
115 %token	TOK_STATUS
116 %token	TOK_STRING
117 %token	TOK_SUM
118 %token	TOK_TABLE
119 %token	TOK_TABLES
120 %token	TOK_THREADS
121 %token	TOK_TO
122 %token	TOK_TRANSACTION
123 %token	TOK_TRUE
124 %token	TOK_TRUNCATE
125 %token	TOK_TYPE
126 %token	TOK_UNCOMMITTED
127 %token	TOK_UPDATE
128 %token	TOK_VALUES
129 %token	TOK_VARIABLES
130 %token	TOK_WARNINGS
131 %token	TOK_WEIGHT
132 %token	TOK_WHERE
133 %token	TOK_WITHIN
134 
135 %left TOK_OR
136 %left TOK_AND
137 %left '|'
138 %left '&'
139 %left '=' TOK_NE
140 %left '<' '>' TOK_LTE TOK_GTE
141 %left '+' '-'
142 %left '*' '/' '%' TOK_DIV TOK_MOD
143 %nonassoc TOK_NOT
144 %nonassoc TOK_NEG
145 
146 %{
147 
148 // some helpers
149 #include <float.h> // for FLT_MAX
150 
AddInsval(SqlParser_c * pParser,CSphVector<SqlInsert_t> & dVec,const SqlNode_t & tNode)151 static void AddInsval ( SqlParser_c * pParser, CSphVector<SqlInsert_t> & dVec, const SqlNode_t & tNode )
152 {
153 	SqlInsert_t & tIns = dVec.Add();
154 	tIns.m_iType = tNode.m_iType;
155 	tIns.m_iVal = tNode.m_iValue; // OPTIMIZE? copy conditionally based on type?
156 	tIns.m_fVal = tNode.m_fValue;
157 	if ( tIns.m_iType==TOK_QUOTED_STRING )
158 		pParser->ToStringUnescape ( tIns.m_sVal, tNode );
159 	tIns.m_pVals = tNode.m_pValues;
160 }
161 
162 #define TRACK_BOUNDS(_res,_left,_right) \
163 	_res = _left; \
164 	if ( _res.m_iStart>0 && pParser->m_pBuf[_res.m_iStart-1]=='`' ) \
165 		_res.m_iStart--; \
166 	_res.m_iEnd = _right.m_iEnd; \
167 	_res.m_iType = 0;
168 
169 %}
170 
171 %%
172 
173 request:
174 	statement							{ pParser->PushQuery(); }
175 	| multi_stmt_list
176 	| multi_stmt_list ';'
177 	;
178 
179 statement:
180 	insert_into
181 	| delete_from
182 	| set_global_stmt
183 	| transact_op
184 	| call_proc
185 	| describe
186 	| show_tables
187 	| show_databases
188 	| update
189 	| show_variables
190 	| show_collation
191 	| show_character_set
192 	| create_function
193 	| drop_function
194 	| attach_index
195 	| flush_rtindex
196 	| flush_ramchunk
197 	| flush_index
198 	| set_transaction
199 	| select_sysvar
200 	| select_dual
201 	| truncate
202 	| optimize_index
203 	| alter
204 	| create_plugin
205 	| drop_plugin
206 	;
207 
208 //////////////////////////////////////////////////////////////////////////
209 
210 // many known keywords are also allowed as column or index names
211 //
212 // FROM conflicts with select_expr opt_alias
213 // NAMES, TRANSACTION conflicts with SET
214 //
215 // more known conflicts (but rather crappy ideas for a name anyway) are:
216 // AND, AS, BY, DIV, FACET, FALSE, ID, IN, IS, LIMIT, MOD, NOT, NULL,
217 // OR, ORDER, SELECT, TRUE
218 
219 ident_set:
220 	TOK_IDENT
221 	| TOK_ADD | TOK_AGENT | TOK_ALTER | TOK_ASC | TOK_ATTACH | TOK_ATTRIBUTES
222 	| TOK_AVG | TOK_BEGIN | TOK_BETWEEN | TOK_BIGINT | TOK_BOOL| TOK_CALL
223 	| TOK_CHARACTER | TOK_CHUNK | TOK_COLLATION | TOK_COLUMN | TOK_COMMIT
224 	| TOK_COMMITTED | TOK_COUNT | TOK_CREATE | TOK_DATABASES | TOK_DELETE
225 	| TOK_DESC | TOK_DESCRIBE  | TOK_DISTINCT  | TOK_DOUBLE | TOK_DROP
226 	| TOK_FLOAT | TOK_FLUSH | TOK_FOR| TOK_FUNCTION | TOK_GLOBAL | TOK_GROUP
227 	| TOK_GROUP_CONCAT | TOK_GROUPBY | TOK_HAVING  | TOK_INDEX | TOK_INSERT
228 	| TOK_INT | TOK_INTEGER | TOK_INTO | TOK_ISOLATION | TOK_JSON | TOK_LEVEL
229 	| TOK_LIKE | TOK_MATCH | TOK_MAX | TOK_META | TOK_MIN | TOK_MULTI
230 	| TOK_MULTI64 | TOK_OPTIMIZE | TOK_OPTION | TOK_PLAN | TOK_PLUGIN
231 	| TOK_PLUGINS | TOK_PROFILE | TOK_RAMCHUNK | TOK_RAND | TOK_READ
232 	| TOK_RECONFIGURE | TOK_REMAP | TOK_REPEATABLE | TOK_REPLACE | TOK_RETURNS
233 	| TOK_ROLLBACK | TOK_RTINDEX | TOK_SERIALIZABLE | TOK_SESSION | TOK_SET
234 	| TOK_SETTINGS | TOK_SHOW | TOK_SONAME | TOK_START | TOK_STATUS | TOK_STRING
235 	| TOK_SUM | TOK_TABLE | TOK_TABLES | TOK_THREADS | TOK_TO | TOK_TRUNCATE
236 	| TOK_TYPE | TOK_UNCOMMITTED | TOK_UPDATE | TOK_VALUES | TOK_VARIABLES
237 	| TOK_WARNINGS | TOK_WEIGHT | TOK_WHERE | TOK_WITHIN
238 	;
239 
240 ident:
241 	ident_set | TOK_NAMES | TOK_TRANSACTION
242 	;
243 
244 //////////////////////////////////////////////////////////////////////////
245 
246 multi_stmt_list:
247 	multi_stmt							{ pParser->PushQuery(); }
248 	| multi_stmt_list ';' multi_stmt	{ pParser->PushQuery(); }
249 	| multi_stmt_list facet_stmt		{ pParser->PushQuery(); }
250 	;
251 
252 multi_stmt:
253 	select
254 	| show_stmt
255 	| set_stmt
256 	;
257 
258 select:
259 	select1
260 	| TOK_SELECT TOK_IDENT '(' '(' select1 ')' opt_tablefunc_args ')'
261 		{
262 			assert ( pParser->m_pStmt->m_eStmt==STMT_SELECT ); // set by table argument
263 			pParser->ToString ( pParser->m_pStmt->m_sTableFunc, $2 );
264 		}
265 	;
266 
267 select1:
268 	select_from
269 	| TOK_SELECT select_items_list TOK_FROM '(' subselect_start select_from ')'
270 		opt_outer_order opt_outer_limit
271 		{
272 			assert ( pParser->m_pStmt->m_eStmt==STMT_SELECT ); // set by subselect
273 		}
274 	;
275 
276 opt_tablefunc_args:
277 	// nothing
278 	| ',' tablefunc_args_list
279 	;
280 
281 tablefunc_args_list:
282 	tablefunc_arg
283 		{
284 			pParser->ToString ( pParser->m_pStmt->m_dTableFuncArgs.Add(), $1 );
285 		}
286 	| tablefunc_args_list ',' tablefunc_arg
287 		{
288 			pParser->ToString ( pParser->m_pStmt->m_dTableFuncArgs.Add(), $3 );
289 		}
290 	;
291 
292 tablefunc_arg:
293 	ident
294 	| TOK_CONST_INT
295 	| TOK_ID
296 	;
297 
298 subselect_start:
299 	{
300 		CSphVector<CSphQueryItem> & dItems = pParser->m_pQuery->m_dItems;
301 		if ( dItems.GetLength()!=1 || dItems[0].m_sExpr!="*" )
302 		{
303 			yyerror ( pParser, "outer select list must be a single star" );
304 			YYERROR;
305 		}
306 		dItems.Reset();
307 		pParser->ResetSelect();
308 	};
309 
310 
311 opt_outer_order:
312 	TOK_ORDER TOK_BY order_items_list
313 		{
314 			pParser->ToString ( pParser->m_pQuery->m_sOuterOrderBy, $3 );
315 			pParser->m_pQuery->m_bHasOuter = true;
316 		}
317 	;
318 
319 opt_outer_limit:
320 	// nothing
321 	| TOK_LIMIT TOK_CONST_INT
322 		{
323 			pParser->m_pQuery->m_iOuterLimit = $2.m_iValue;
324 			pParser->m_pQuery->m_bHasOuter = true;
325 		}
326 	| TOK_LIMIT TOK_CONST_INT ',' TOK_CONST_INT
327 		{
328 			pParser->m_pQuery->m_iOuterOffset = $2.m_iValue;
329 			pParser->m_pQuery->m_iOuterLimit = $4.m_iValue;
330 			pParser->m_pQuery->m_bHasOuter = true;
331 		}
332 	;
333 
334 select_from:
335 	TOK_SELECT select_items_list
336 	TOK_FROM ident_list
337 	opt_where_clause
338 	opt_group_clause
339 	opt_group_order_clause
340 	opt_having_clause
341 	opt_order_clause
342 	opt_limit_clause
343 	opt_option_clause
344 		{
345 			pParser->m_pStmt->m_eStmt = STMT_SELECT;
346 			pParser->ToString ( pParser->m_pQuery->m_sIndexes, $4 );
347 		}
348 	;
349 
350 select_items_list:
351 	select_item
352 	| select_items_list ',' select_item
353 	;
354 
355 select_item:
356 	'*'									{ pParser->AddItem ( &$1 ); }
357 	| select_expr opt_alias
358 	;
359 
360 opt_alias:
361 	// empty
362 	| ident								{ pParser->AliasLastItem ( &$1 ); }
363 	| TOK_AS ident						{ pParser->AliasLastItem ( &$2 ); }
364 	;
365 
366 select_expr:
367 	expr								{ pParser->AddItem ( &$1 ); }
368 	| TOK_AVG '(' expr ')'				{ pParser->AddItem ( &$3, SPH_AGGR_AVG, &$1, &$4 ); }
369 	| TOK_MAX '(' expr ')'				{ pParser->AddItem ( &$3, SPH_AGGR_MAX, &$1, &$4 ); }
370 	| TOK_MIN '(' expr ')'				{ pParser->AddItem ( &$3, SPH_AGGR_MIN, &$1, &$4 ); }
371 	| TOK_SUM '(' expr ')'				{ pParser->AddItem ( &$3, SPH_AGGR_SUM, &$1, &$4 ); }
372 	| TOK_GROUP_CONCAT '(' expr ')'		{ pParser->AddItem ( &$3, SPH_AGGR_CAT, &$1, &$4 ); }
373 	| TOK_COUNT '(' '*' ')'				{ if ( !pParser->AddItem ( "count(*)", &$1, &$4 ) ) YYERROR; }
374 	| TOK_GROUPBY '(' ')'				{ if ( !pParser->AddItem ( "groupby()", &$1, &$3 ) ) YYERROR; }
375 	| TOK_COUNT '(' TOK_DISTINCT ident')' 	{ if ( !pParser->AddDistinct ( &$4, &$1, &$5 ) ) YYERROR; }
376 	;
377 
378 ident_list:
379 	ident
380 	| ident_list ',' ident				{ TRACK_BOUNDS ( $$, $1, $3 ); }
381 	;
382 
383 opt_where_clause:
384 	// empty
385 	| where_clause
386 	;
387 
388 where_clause:
389 	TOK_WHERE where_expr
390 	;
391 
392 where_expr:
393 	where_item
394 	| where_expr TOK_AND where_expr
395 	| '(' where_expr ')'
396 	;
397 
398 where_item:
399 	TOK_MATCH '(' TOK_QUOTED_STRING ')'
400 		{
401 			if ( !pParser->SetMatch($3) )
402 				YYERROR;
403 		}
404 	| filter_item
405 	;
406 
407 filter_item:
408 	expr_ident '=' const_int
409 		{
410 			CSphFilterSettings * pFilter = pParser->AddValuesFilter ( $1 );
411 			if ( !pFilter )
412 				YYERROR;
413 			pFilter->m_dValues.Add ( $3.m_iValue );
414 		}
415 	| expr_ident TOK_NE const_int
416 		{
417 			CSphFilterSettings * pFilter = pParser->AddValuesFilter ( $1 );
418 			if ( !pFilter )
419 				YYERROR;
420 			pFilter->m_dValues.Add ( $3.m_iValue );
421 			pFilter->m_bExclude = true;
422 		}
423 	| expr_ident TOK_IN '(' const_list ')'
424 		{
425 			CSphFilterSettings * pFilter = pParser->AddValuesFilter ( $1 );
426 			if ( !pFilter )
427 				YYERROR;
428 			pFilter->m_dValues = *$4.m_pValues.Ptr();
429 			pFilter->m_dValues.Uniq();
430 		}
431 	| expr_ident TOK_NOT TOK_IN '(' const_list ')'
432 		{
433 			CSphFilterSettings * pFilter = pParser->AddValuesFilter ( $1 );
434 			if ( !pFilter )
435 				YYERROR;
436 			pFilter->m_dValues = *$5.m_pValues.Ptr();
437 			pFilter->m_dValues.Uniq();
438 			pFilter->m_bExclude = true;
439 		}
440 	| expr_ident TOK_IN '(' string_list ')'
441 		{
442 			if ( !pParser->AddStringListFilter ( $1, $4, false ) )
443 				YYERROR;
444 		}
445 	| expr_ident TOK_NOT TOK_IN '(' string_list ')'
446 		{
447 			if ( !pParser->AddStringListFilter ( $1, $5, true ) )
448 				YYERROR;
449 		}
450 	| expr_ident TOK_IN TOK_USERVAR
451 		{
452 			if ( !pParser->AddUservarFilter ( $1, $3, false ) )
453 				YYERROR;
454 		}
455 	| expr_ident TOK_NOT TOK_IN TOK_USERVAR
456 		{
457 			if ( !pParser->AddUservarFilter ( $1, $4, true ) )
458 				YYERROR;
459 		}
460 	| expr_ident TOK_BETWEEN const_int TOK_AND const_int
461 		{
462 			if ( !pParser->AddIntRangeFilter ( $1, $3.m_iValue, $5.m_iValue ) )
463 				YYERROR;
464 		}
465 	| expr_ident '>' const_int
466 		{
467 			if ( !pParser->AddIntFilterGreater ( $1, $3.m_iValue, false ) )
468 				YYERROR;
469 		}
470 	| expr_ident '<' const_int
471 		{
472 			if ( !pParser->AddIntFilterLesser ( $1, $3.m_iValue, false ) )
473 				YYERROR;
474 		}
475 	| expr_ident TOK_GTE const_int
476 		{
477 			if ( !pParser->AddIntFilterGreater ( $1, $3.m_iValue, true ) )
478 				YYERROR;
479 		}
480 	| expr_ident TOK_LTE const_int
481 		{
482 			if ( !pParser->AddIntFilterLesser ( $1, $3.m_iValue, true ) )
483 				YYERROR;
484 		}
485 	| expr_ident '=' const_float
486 		{
487 			if ( !pParser->AddFloatRangeFilter ( $1, $3.m_fValue, $3.m_fValue, true ) )
488 				YYERROR;
489 		}
490 	| expr_ident TOK_NE const_float
491 		{
492 			if ( !pParser->AddFloatRangeFilter ( $1, $3.m_fValue, $3.m_fValue, true, true ) )
493 				YYERROR;
494 		}
495 	| expr_ident TOK_BETWEEN const_float TOK_AND const_float
496 		{
497 			if ( !pParser->AddFloatRangeFilter ( $1, $3.m_fValue, $5.m_fValue, true ) )
498 				YYERROR;
499 		}
500 	| expr_ident TOK_BETWEEN const_int TOK_AND const_float
501 		{
502 			if ( !pParser->AddFloatRangeFilter ( $1, $3.m_iValue, $5.m_fValue, true ) )
503 				YYERROR;
504 		}
505 	| expr_ident TOK_BETWEEN const_float TOK_AND const_int
506 		{
507 			if ( !pParser->AddFloatRangeFilter ( $1, $3.m_fValue, $5.m_iValue, true ) )
508 				YYERROR;
509 		}
510 	| expr_ident '>' const_float
511 		{
512 			if ( !pParser->AddFloatRangeFilter ( $1, $3.m_fValue, FLT_MAX, false ) )
513 				YYERROR;
514 		}
515 	| expr_ident '<' const_float
516 		{
517 			if ( !pParser->AddFloatRangeFilter ( $1, -FLT_MAX, $3.m_fValue, false ) )
518 				YYERROR;
519 		}
520 	| expr_ident TOK_GTE const_float
521 		{
522 			if ( !pParser->AddFloatRangeFilter ( $1, $3.m_fValue, FLT_MAX, true ) )
523 				YYERROR;
524 		}
525 	| expr_ident TOK_LTE const_float
526 		{
527 			if ( !pParser->AddFloatRangeFilter ( $1, -FLT_MAX, $3.m_fValue, true ) )
528 				YYERROR;
529 		}
530 	| expr_ident '=' TOK_QUOTED_STRING
531 		{
532 			if ( !pParser->AddStringFilter ( $1, $3, false ) )
533 				YYERROR;
534 		}
535 	| expr_ident TOK_NE TOK_QUOTED_STRING
536 		{
537 			if ( !pParser->AddStringFilter ( $1, $3, true ) )
538 				YYERROR;
539 		}
540 	| expr_ident TOK_IS TOK_NULL
541 		{
542 			if ( !pParser->AddNullFilter ( $1, true ) )
543 				YYERROR;
544 		}
545 	| expr_ident TOK_IS TOK_NOT TOK_NULL
546 		{
547 			if ( !pParser->AddNullFilter ( $1, false ) )
548 				YYERROR;
549 		}
550 	;
551 
552 expr_ident:
553 	ident
554 	| TOK_ATIDENT
555 		{
556 			if ( !pParser->SetOldSyntax() )
557 				YYERROR;
558 		}
559 	| TOK_COUNT '(' '*' ')'
560 		{
561 			$$.m_iType = SPHINXQL_TOK_COUNT;
562 			if ( !pParser->SetNewSyntax() )
563 				YYERROR;
564 		}
565 	| TOK_GROUPBY '(' ')'
566 		{
567 			$$.m_iType = SPHINXQL_TOK_GROUPBY;
568 			if ( !pParser->SetNewSyntax() )
569 				YYERROR;
570 		}
571 	| TOK_WEIGHT '(' ')'
572 		{
573 			$$.m_iType = SPHINXQL_TOK_WEIGHT;
574 			if ( !pParser->SetNewSyntax() )
575 				YYERROR;
576 		}
577 	| TOK_ID
578 		{
579 			$$.m_iType = SPHINXQL_TOK_ID;
580 			if ( !pParser->SetNewSyntax() )
581 				YYERROR;
582 		}
583 	| json_expr
584 	| TOK_INTEGER '(' json_expr ')'
585 	| TOK_DOUBLE '(' json_expr ')'
586 	| TOK_BIGINT '(' json_expr ')'
587 	| TOK_FACET '(' ')'
588 	;
589 
590 const_int:
591 	TOK_CONST_INT			{ $$.m_iType = TOK_CONST_INT; $$.m_iValue = $1.m_iValue; }
592 	| '-' TOK_CONST_INT
593 		{
594 			$$.m_iType = TOK_CONST_INT;
595 			if ( (uint64_t)$2.m_iValue > (uint64_t)LLONG_MAX )
596 				$$.m_iValue = LLONG_MIN;
597 			else
598 				$$.m_iValue = -$2.m_iValue;
599 		}
600 	;
601 
602 const_float:
603 	TOK_CONST_FLOAT			{ $$.m_iType = TOK_CONST_FLOAT; $$.m_fValue = $1.m_fValue; }
604 	| '-' TOK_CONST_FLOAT	{ $$.m_iType = TOK_CONST_FLOAT; $$.m_fValue = -$2.m_fValue; }
605 	| TOK_DOT_NUMBER		{ $$.m_iType = TOK_CONST_FLOAT; $$.m_fValue = $1.m_fValue; }
606 	;
607 
608 const_list:
609 	const_int
610 		{
611 			assert ( !$$.m_pValues.Ptr() );
612 			$$.m_pValues = new RefcountedVector_c<SphAttr_t> ();
613 			$$.m_pValues->Add ( $1.m_iValue );
614 		}
615 	| const_list ',' const_int
616 		{
617 			$$.m_pValues->Add ( $3.m_iValue );
618 		}
619 	;
620 
621 string_list:
622 	TOK_QUOTED_STRING
623 		{
624 			assert ( !$$.m_pValues.Ptr() );
625 			$$.m_pValues = new RefcountedVector_c<SphAttr_t> ();
626 			$$.m_pValues->Add ( $1.m_iValue );
627 		}
628 	| string_list ',' TOK_QUOTED_STRING
629 		{
630 			$$.m_pValues->Add ( $3.m_iValue );
631 		}
632 	;
633 
634 opt_group_clause:
635 	// empty
636 	| TOK_GROUP opt_int TOK_BY group_items_list
637 	;
638 
639 opt_int:
640 	// empty
641 	| TOK_CONST_INT
642 		{
643 			pParser->SetGroupbyLimit ( $1.m_iValue );
644 		}
645 	;
646 
647 group_items_list:
648 	expr_ident
649 		{
650 			pParser->AddGroupBy ( $1 );
651 		}
652 	| group_items_list ',' expr_ident
653 		{
654 			pParser->AddGroupBy ( $3 );
655 		}
656 	;
657 
658 opt_having_clause:
659 	// empty
660 	| TOK_HAVING filter_item
661 		{
662 			pParser->AddHaving();
663 		}
664 	;
665 
666 opt_group_order_clause:
667 	// empty
668 	| group_order_clause
669 	;
670 
671 group_order_clause:
672 	TOK_WITHIN TOK_GROUP TOK_ORDER TOK_BY order_items_list
673 		{
674 			if ( pParser->m_pQuery->m_sGroupBy.IsEmpty() )
675 			{
676 				yyerror ( pParser, "you must specify GROUP BY element in order to use WITHIN GROUP ORDER BY clause" );
677 				YYERROR;
678 			}
679 			pParser->ToString ( pParser->m_pQuery->m_sSortBy, $5 );
680 		}
681 	;
682 
683 opt_order_clause:
684 	// empty
685 	| order_clause
686 	;
687 
688 order_clause:
689 	TOK_ORDER TOK_BY order_items_list
690 		{
691 			pParser->ToString ( pParser->m_pQuery->m_sOrderBy, $3 );
692 		}
693 	| TOK_ORDER TOK_BY TOK_RAND '(' ')'
694 		{
695 			pParser->m_pQuery->m_sOrderBy = "@random";
696 		}
697 	;
698 
699 order_items_list:
700 	order_item
701 	| order_items_list ',' order_item	{ TRACK_BOUNDS ( $$, $1, $3 ); }
702 	;
703 
704 order_item:
705 	expr_ident
706 	| expr_ident TOK_ASC				{ TRACK_BOUNDS ( $$, $1, $2 ); }
707 	| expr_ident TOK_DESC				{ TRACK_BOUNDS ( $$, $1, $2 ); }
708 	;
709 
710 opt_limit_clause:
711 	// empty
712 	| limit_clause
713 	;
714 
715 limit_clause:
716 	TOK_LIMIT TOK_CONST_INT
717 		{
718 			pParser->m_pQuery->m_iOffset = 0;
719 			pParser->m_pQuery->m_iLimit = $2.m_iValue;
720 		}
721 	| TOK_LIMIT TOK_CONST_INT ',' TOK_CONST_INT
722 		{
723 			pParser->m_pQuery->m_iOffset = $2.m_iValue;
724 			pParser->m_pQuery->m_iLimit = $4.m_iValue;
725 		}
726 	;
727 
728 opt_option_clause:
729 	// empty
730 	| option_clause
731 	;
732 
733 option_clause:
734 	TOK_OPTION option_list
735 	;
736 
737 option_list:
738 	option_item
739 	| option_list ',' option_item
740 	;
741 
742 option_item:
743 	ident '=' ident
744 		{
745 			if ( !pParser->AddOption ( $1, $3 ) )
746 				YYERROR;
747 		}
748 	| ident '=' TOK_CONST_INT
749 		{
750 			if ( !pParser->AddOption ( $1, $3 ) )
751 				YYERROR;
752 		}
753 	| ident '=' '(' named_const_list ')'
754 		{
755 			if ( !pParser->AddOption ( $1, pParser->GetNamedVec ( $4.m_iValue ) ) )
756 				YYERROR;
757 			pParser->FreeNamedVec ( $4.m_iValue );
758 		}
759 	| ident '=' ident '(' TOK_QUOTED_STRING ')'
760 		{
761 			if ( !pParser->AddOption ( $1, $3, $5 ) )
762 				YYERROR;
763 		}
764 	| ident '=' TOK_QUOTED_STRING
765 		{
766 			if ( !pParser->AddOption ( $1, $3 ) )
767 				YYERROR;
768 		}
769 	;
770 
771 named_const_list:
772 	named_const
773 		{
774 			$$.m_iValue = pParser->AllocNamedVec ();
775 			pParser->AddConst ( $$.m_iValue, $1 );
776 		}
777 	| named_const_list ',' named_const
778 		{
779 			pParser->AddConst( $$.m_iValue, $3 );
780 		}
781 	;
782 
783 named_const:
784 	ident '=' const_int
785 		{
786 			$$ = $1;
787 			$$.m_iValue = $3.m_iValue;
788 		}
789 	;
790 
791 //////////////////////////////////////////////////////////////////////////
792 
793 expr:
794 	ident
795 	| TOK_ATIDENT				{ if ( !pParser->SetOldSyntax() ) YYERROR; }
796 	| TOK_ID					{ if ( !pParser->SetNewSyntax() ) YYERROR; }
797 	| TOK_CONST_INT
798 	| TOK_CONST_FLOAT
799 	| TOK_DOT_NUMBER
800 	| TOK_USERVAR
801 	| '-' expr %prec TOK_NEG	{ TRACK_BOUNDS ( $$, $1, $2 ); }
802 	| TOK_NOT expr				{ TRACK_BOUNDS ( $$, $1, $2 ); }
803 
804 	| expr '+' expr				{ TRACK_BOUNDS ( $$, $1, $3 ); }
805 	| expr '-' expr				{ TRACK_BOUNDS ( $$, $1, $3 ); }
806 	| expr '*' expr				{ TRACK_BOUNDS ( $$, $1, $3 ); }
807 	| expr '/' expr				{ TRACK_BOUNDS ( $$, $1, $3 ); }
808 	| expr '<' expr				{ TRACK_BOUNDS ( $$, $1, $3 ); }
809 	| expr '>' expr				{ TRACK_BOUNDS ( $$, $1, $3 ); }
810 	| expr '&' expr				{ TRACK_BOUNDS ( $$, $1, $3 ); }
811 	| expr '|' expr				{ TRACK_BOUNDS ( $$, $1, $3 ); }
812 	| expr '%' expr				{ TRACK_BOUNDS ( $$, $1, $3 ); }
813 	| expr TOK_DIV expr			{ TRACK_BOUNDS ( $$, $1, $3 ); }
814 	| expr TOK_MOD expr			{ TRACK_BOUNDS ( $$, $1, $3 ); }
815 	| expr TOK_LTE expr			{ TRACK_BOUNDS ( $$, $1, $3 ); }
816 	| expr TOK_GTE expr			{ TRACK_BOUNDS ( $$, $1, $3 ); }
817 	| expr '=' expr				{ TRACK_BOUNDS ( $$, $1, $3 ); }
818 	| expr TOK_NE expr			{ TRACK_BOUNDS ( $$, $1, $3 ); }
819 	| expr TOK_AND expr			{ TRACK_BOUNDS ( $$, $1, $3 ); }
820 	| expr TOK_OR expr			{ TRACK_BOUNDS ( $$, $1, $3 ); }
821 	| '(' expr ')'				{ TRACK_BOUNDS ( $$, $1, $3 ); }
822 	| '{' consthash '}'			{ TRACK_BOUNDS ( $$, $1, $3 ); }
823 	| function
824 	| json_expr
825 	| streq
826 	| json_field TOK_IS TOK_NULL			{ TRACK_BOUNDS ( $$, $1, $3 ); }
827 	| json_field TOK_IS TOK_NOT TOK_NULL	{ TRACK_BOUNDS ( $$, $1, $4 ); }
828 	;
829 
830 function:
831 	TOK_IDENT '(' arglist ')'		{ TRACK_BOUNDS ( $$, $1, $4 ); }
832 	| TOK_IN '(' arglist ')'		{ TRACK_BOUNDS ( $$, $1, $4 ); } // handle exception from 'ident' rule
833 	| TOK_INTEGER '(' arglist ')'	{ TRACK_BOUNDS ( $$, $1, $4 ); }
834 	| TOK_BIGINT '(' arglist ')'	{ TRACK_BOUNDS ( $$, $1, $4 ); }
835 	| TOK_FLOAT '(' arglist ')'		{ TRACK_BOUNDS ( $$, $1, $4 ); }
836 	| TOK_DOUBLE '(' arglist ')'	{ TRACK_BOUNDS ( $$, $1, $4 ); }
837 	| TOK_IDENT '(' ')'				{ TRACK_BOUNDS ( $$, $1, $3 ); }
838 	| TOK_MIN '(' expr ',' expr ')'	{ TRACK_BOUNDS ( $$, $1, $6 ); } // handle clash with aggregate functions
839 	| TOK_MAX '(' expr ',' expr ')'	{ TRACK_BOUNDS ( $$, $1, $6 ); }
840 	| TOK_WEIGHT '(' ')'			{ TRACK_BOUNDS ( $$, $1, $3 ); }
841 	| TOK_IDENT '(' expr TOK_FOR ident TOK_IN json_field ')' { TRACK_BOUNDS ( $$, $1, $8 ); }
842 	| TOK_REMAP '(' expr ',' expr ',' '(' arglist ')' ',' '(' arglist ')' ')' { TRACK_BOUNDS ( $$, $1, $14 ); }
843 	;
844 
845 arglist:
846 	arg
847 	| arglist ',' arg
848 	;
849 
850 arg:
851 	expr
852 	| TOK_QUOTED_STRING
853 	;
854 
855 consthash:
856 	hash_key '=' hash_val					{ TRACK_BOUNDS ( $$, $1, $3 ); }
857 	| consthash ',' hash_key '=' hash_val	{ TRACK_BOUNDS ( $$, $1, $5 ); }
858 	;
859 
860 hash_key:
861 	ident
862 	| TOK_IN
863 	;
864 
865 hash_val:
866 	const_int
867 	| ident
868 	;
869 
870 //////////////////////////////////////////////////////////////////////////
871 
872 show_stmt:
873 	TOK_SHOW show_what
874 	;
875 
876 like_filter:
877 	// empty
878 	| TOK_LIKE TOK_QUOTED_STRING		{ pParser->ToStringUnescape ( pParser->m_pStmt->m_sStringParam, $2 ); }
879 	;
880 
881 show_what:
882 	TOK_WARNINGS						{ pParser->m_pStmt->m_eStmt = STMT_SHOW_WARNINGS; }
883 	| TOK_STATUS like_filter			{ pParser->m_pStmt->m_eStmt = STMT_SHOW_STATUS; }
884 	| TOK_META like_filter				{ pParser->m_pStmt->m_eStmt = STMT_SHOW_META; }
885 	| TOK_AGENT TOK_STATUS like_filter	{ pParser->m_pStmt->m_eStmt = STMT_SHOW_AGENT_STATUS; }
886 	| TOK_PROFILE						{ pParser->m_pStmt->m_eStmt = STMT_SHOW_PROFILE; }
887 	| TOK_PLAN							{ pParser->m_pStmt->m_eStmt = STMT_SHOW_PLAN; }
888 	| TOK_PLUGINS						{ pParser->m_pStmt->m_eStmt = STMT_SHOW_PLUGINS; }
889 	| TOK_THREADS opt_option_clause		{ pParser->m_pStmt->m_eStmt = STMT_SHOW_THREADS; }
890 	| TOK_AGENT TOK_QUOTED_STRING TOK_STATUS like_filter
891 		{
892 			pParser->m_pStmt->m_eStmt = STMT_SHOW_AGENT_STATUS;
893 			pParser->ToStringUnescape ( pParser->m_pStmt->m_sIndex, $2 );
894 		}
895 	| TOK_AGENT ident TOK_STATUS like_filter
896 		{
897 			pParser->m_pStmt->m_eStmt = STMT_SHOW_AGENT_STATUS;
898 			pParser->ToString ( pParser->m_pStmt->m_sIndex, $2 );
899 		}
900 	| index_or_table ident TOK_STATUS
901 		{
902 			pParser->m_pStmt->m_eStmt = STMT_SHOW_INDEX_STATUS;
903 			pParser->ToString ( pParser->m_pStmt->m_sIndex, $2 );
904 		}
905 	| index_or_table ident opt_chunk TOK_SETTINGS
906 		{
907 			pParser->m_pStmt->m_eStmt = STMT_SHOW_INDEX_SETTINGS;
908 			pParser->ToString ( pParser->m_pStmt->m_sIndex, $2 );
909 		}
910 	| index_or_table ident TOK_DOT_NUMBER TOK_SETTINGS
911 		{
912 			pParser->m_pStmt->m_eStmt = STMT_SHOW_INDEX_SETTINGS;
913 			pParser->ToString ( pParser->m_pStmt->m_sIndex, $2 );
914 			pParser->m_pStmt->m_iIntParam = int($3.m_fValue*10);
915 		}
916 	;
917 
918 index_or_table:
919 	TOK_INDEX
920 	| TOK_TABLE
921 	;
922 
923 opt_chunk:
924 	// empty
925 	| TOK_CHUNK TOK_CONST_INT
926 		{
927 			pParser->m_pStmt->m_iIntParam = $2.m_iValue;
928 		};
929 
930 //////////////////////////////////////////////////////////////////////////
931 
932 set_stmt:
933 	TOK_SET ident_set '=' boolean_value
934 		{
935 			pParser->SetStatement ( $2, SET_LOCAL );
936 			pParser->m_pStmt->m_iSetValue = $4.m_iValue;
937 		}
938 	| TOK_SET ident_set '=' set_string_value
939 		{
940 			pParser->SetStatement ( $2, SET_LOCAL );
941 			pParser->ToString ( pParser->m_pStmt->m_sSetValue, $4 );
942 		}
943 	| TOK_SET ident_set '=' TOK_NULL
944 		{
945 			pParser->SetStatement ( $2, SET_LOCAL );
946 			pParser->m_pStmt->m_bSetNull = true;
947 		}
948 	| TOK_SET TOK_NAMES set_value		{ pParser->m_pStmt->m_eStmt = STMT_DUMMY; }
949 	| TOK_SET TOK_SYSVAR '=' set_value	{ pParser->m_pStmt->m_eStmt = STMT_DUMMY; }
950 	| TOK_SET TOK_CHARACTER TOK_SET set_value { pParser->m_pStmt->m_eStmt = STMT_DUMMY; }
951 	;
952 
953 set_global_stmt:
954 	TOK_SET TOK_GLOBAL TOK_USERVAR '=' '(' const_list ')'
955 		{
956 			pParser->SetStatement ( $3, SET_GLOBAL_UVAR );
957 			pParser->m_pStmt->m_dSetValues = *$6.m_pValues.Ptr();
958 		}
959 	| TOK_SET TOK_GLOBAL ident_set '=' set_string_value
960 		{
961 			pParser->SetStatement ( $3, SET_GLOBAL_SVAR );
962 			pParser->ToString ( pParser->m_pStmt->m_sSetValue, $5 ).Unquote();
963 		}
964 	| TOK_SET TOK_GLOBAL ident_set '=' TOK_CONST_INT
965 		{
966 			pParser->SetStatement ( $3, SET_GLOBAL_SVAR );
967 			pParser->m_pStmt->m_iSetValue = $5.m_iValue;
968 		}
969 	| TOK_SET TOK_INDEX ident TOK_GLOBAL TOK_USERVAR '=' '(' const_list ')'
970 		{
971 			pParser->SetStatement ( $5, SET_INDEX_UVAR );
972 			pParser->m_pStmt->m_dSetValues = *$8.m_pValues.Ptr();
973 			pParser->ToString ( pParser->m_pStmt->m_sIndex, $3 );
974 		}
975 	;
976 
977 set_string_value:
978 	ident
979 	| TOK_QUOTED_STRING
980 	;
981 
982 boolean_value:
983 	TOK_TRUE			{ $$.m_iValue = 1; }
984 	| TOK_FALSE			{ $$.m_iValue = 0; }
985 	| const_int
986 		{
987 			$$.m_iValue = $1.m_iValue;
988 			if ( $$.m_iValue!=0 && $$.m_iValue!=1 )
989 			{
990 				yyerror ( pParser, "only 0 and 1 could be used as boolean values" );
991 				YYERROR;
992 			}
993 		}
994 	;
995 
996 set_value:
997 	simple_set_value
998 	| set_value '-' simple_set_value
999 	;
1000 
1001 simple_set_value:
1002 	ident
1003 	| TOK_NULL
1004 	| TOK_QUOTED_STRING
1005 	| TOK_CONST_INT
1006 	| TOK_CONST_FLOAT
1007 	;
1008 
1009 
1010 //////////////////////////////////////////////////////////////////////////
1011 
1012 transact_op:
1013 	TOK_COMMIT			{ pParser->m_pStmt->m_eStmt = STMT_COMMIT; }
1014 	| TOK_ROLLBACK			{ pParser->m_pStmt->m_eStmt = STMT_ROLLBACK; }
1015 	| start_transaction		{ pParser->m_pStmt->m_eStmt = STMT_BEGIN; }
1016 	;
1017 
1018 start_transaction:
1019 	TOK_BEGIN
1020 	| TOK_START TOK_TRANSACTION
1021 	;
1022 
1023 //////////////////////////////////////////////////////////////////////////
1024 
1025 insert_into:
1026 	insert_or_replace TOK_INTO ident opt_column_list TOK_VALUES insert_rows_list opt_insert_options
1027 		{
1028 			// everything else is pushed directly into parser within the rules
1029 			pParser->ToString ( pParser->m_pStmt->m_sIndex, $3 );
1030 		}
1031 	;
1032 
1033 insert_or_replace:
1034 	TOK_INSERT		{ pParser->m_pStmt->m_eStmt = STMT_INSERT; }
1035 	| TOK_REPLACE	{ pParser->m_pStmt->m_eStmt = STMT_REPLACE; }
1036 	;
1037 
1038 opt_column_list:
1039 	// empty
1040 	| '(' column_list ')'
1041 	;
1042 
1043 column_ident:
1044 	ident
1045 	| TOK_ID
1046 	;
1047 
1048 column_list:
1049 	column_ident					{ if ( !pParser->AddSchemaItem ( &$1 ) ) { yyerror ( pParser, "unknown field" ); YYERROR; } }
1050 	| column_list ',' column_ident	{ if ( !pParser->AddSchemaItem ( &$3 ) ) { yyerror ( pParser, "unknown field" ); YYERROR; } }
1051 	;
1052 
1053 insert_rows_list:
1054 	insert_row
1055 	| insert_rows_list ',' insert_row
1056 	;
1057 
1058 insert_row:
1059 	'(' insert_vals_list ')'			{ if ( !pParser->m_pStmt->CheckInsertIntegrity() ) { yyerror ( pParser, "wrong number of values here" ); YYERROR; } }
1060 	;
1061 
1062 insert_vals_list:
1063 	insert_val							{ AddInsval ( pParser, pParser->m_pStmt->m_dInsertValues, $1 ); }
1064 	| insert_vals_list ',' insert_val	{ AddInsval ( pParser, pParser->m_pStmt->m_dInsertValues, $3 ); }
1065 	;
1066 
1067 insert_val:
1068 	const_int				{ $$.m_iType = TOK_CONST_INT; $$.m_iValue = $1.m_iValue; }
1069 	| const_float			{ $$.m_iType = TOK_CONST_FLOAT; $$.m_fValue = $1.m_fValue; }
1070 	| TOK_QUOTED_STRING		{ $$.m_iType = TOK_QUOTED_STRING; $$.m_iStart = $1.m_iStart; $$.m_iEnd = $1.m_iEnd; }
1071 	| '(' const_list ')'	{ $$.m_iType = TOK_CONST_MVA; $$.m_pValues = $2.m_pValues; }
1072 	| '(' ')'				{ $$.m_iType = TOK_CONST_MVA; }
1073 	;
1074 
1075 opt_insert_options:
1076 	| TOK_OPTION insert_options_list
1077 	;
1078 
1079 insert_options_list:
1080 	insert_option
1081 	| insert_options_list ',' insert_option
1082 	;
1083 
1084 insert_option:
1085 	TOK_IDENT '=' TOK_QUOTED_STRING		{ if ( !pParser->AddInsertOption ( $1, $3 ) ) YYERROR; }
1086 	;
1087 
1088 //////////////////////////////////////////////////////////////////////////
1089 
1090 delete_from:
1091 	TOK_DELETE TOK_FROM ident_list where_clause
1092 	{
1093 		if ( !pParser->DeleteStatement ( &$3 ) )
1094 			YYERROR;
1095 	}
1096 	;
1097 
1098 //////////////////////////////////////////////////////////////////////////
1099 
1100 call_proc:
1101 	TOK_CALL ident '(' call_args_list opt_call_opts_list ')'
1102 		{
1103 			pParser->m_pStmt->m_eStmt = STMT_CALL;
1104 			pParser->ToString ( pParser->m_pStmt->m_sCallProc, $2 );
1105 		}
1106 	;
1107 
1108 call_args_list:
1109 	call_arg
1110 		{
1111 			AddInsval ( pParser, pParser->m_pStmt->m_dInsertValues, $1 );
1112 		}
1113 	| call_args_list ',' call_arg
1114 		{
1115 			AddInsval ( pParser, pParser->m_pStmt->m_dInsertValues, $3 );
1116 		}
1117 	;
1118 
1119 call_arg:
1120 	insert_val
1121 	| '(' const_string_list ')'
1122 		{
1123 			$$.m_iType = TOK_CONST_STRINGS;
1124 		}
1125 	;
1126 
1127 const_string_list:
1128 	TOK_QUOTED_STRING
1129 		{
1130 			// FIXME? for now, one such array per CALL statement, tops
1131 			if ( pParser->m_pStmt->m_dCallStrings.GetLength() )
1132 			{
1133 				yyerror ( pParser, "unexpected constant string list" );
1134 				YYERROR;
1135 			}
1136 			pParser->ToStringUnescape ( pParser->m_pStmt->m_dCallStrings.Add(), $1 );
1137 		}
1138 	| const_string_list ',' TOK_QUOTED_STRING
1139 		{
1140 			pParser->ToStringUnescape ( pParser->m_pStmt->m_dCallStrings.Add(), $3 );
1141 		}
1142 	;
1143 
1144 opt_call_opts_list:
1145 	// empty
1146 	| ',' call_opts_list
1147 	;
1148 
1149 call_opts_list:
1150 	call_opt
1151 		{
1152 			assert ( pParser->m_pStmt->m_dCallOptNames.GetLength()==1 );
1153 			assert ( pParser->m_pStmt->m_dCallOptValues.GetLength()==1 );
1154 		}
1155 	| call_opts_list ',' call_opt
1156 	;
1157 
1158 call_opt:
1159 	insert_val opt_as call_opt_name
1160 		{
1161 			pParser->ToString ( pParser->m_pStmt->m_dCallOptNames.Add(), $3 );
1162 			AddInsval ( pParser, pParser->m_pStmt->m_dCallOptValues, $1 );
1163 		}
1164 	;
1165 
1166 opt_as:
1167 	// empty
1168 	| TOK_AS
1169 	;
1170 
1171 call_opt_name:
1172 	ident
1173 	| TOK_LIMIT
1174 	;
1175 
1176 //////////////////////////////////////////////////////////////////////////
1177 
1178 describe:
1179 	describe_tok ident like_filter
1180 		{
1181 			pParser->m_pStmt->m_eStmt = STMT_DESCRIBE;
1182 			pParser->ToString ( pParser->m_pStmt->m_sIndex, $2 );
1183 		}
1184 	;
1185 
1186 describe_tok:
1187 	TOK_DESCRIBE
1188 	| TOK_DESC
1189 	;
1190 
1191 //////////////////////////////////////////////////////////////////////////
1192 
1193 show_tables:
1194 	TOK_SHOW TOK_TABLES like_filter		{ pParser->m_pStmt->m_eStmt = STMT_SHOW_TABLES; }
1195 	;
1196 
1197 show_databases:
1198 	TOK_SHOW TOK_DATABASES like_filter { pParser->m_pStmt->m_eStmt = STMT_SHOW_DATABASES; }
1199 	;
1200 
1201 //////////////////////////////////////////////////////////////////////////
1202 
1203 update:
1204 	TOK_UPDATE ident_list TOK_SET update_items_list where_clause opt_option_clause
1205 		{
1206 			if ( !pParser->UpdateStatement ( &$2 ) )
1207 				YYERROR;
1208 		}
1209 	;
1210 
1211 update_items_list:
1212 	update_item
1213 	| update_items_list ',' update_item
1214 	;
1215 
1216 update_item:
1217 	ident '=' const_int
1218 		{
1219 			// it is performance-critical to forcibly inline this
1220 			pParser->m_pStmt->m_tUpdate.m_dPool.Add ( (DWORD)$3.m_iValue );
1221 			DWORD uHi = (DWORD)( $3.m_iValue>>32 );
1222 			if ( uHi )
1223 			{
1224 				pParser->m_pStmt->m_tUpdate.m_dPool.Add ( uHi );
1225 				pParser->AddUpdatedAttr ( $1, SPH_ATTR_BIGINT );
1226 			} else
1227 			{
1228 				pParser->AddUpdatedAttr ( $1, SPH_ATTR_INTEGER );
1229 			}
1230 		}
1231 	| ident '=' const_float
1232 		{
1233 			// it is performance-critical to forcibly inline this
1234 			pParser->m_pStmt->m_tUpdate.m_dPool.Add ( sphF2DW ( $3.m_fValue ) );
1235 			pParser->AddUpdatedAttr ( $1, SPH_ATTR_FLOAT );
1236 		}
1237 	| ident '=' '(' const_list ')'
1238 		{
1239 			pParser->UpdateMVAAttr ( $1, $4 );
1240 		}
1241 	| ident '=' '(' ')' // special case () means delete mva
1242 		{
1243 			SqlNode_t tNoValues;
1244 			pParser->UpdateMVAAttr ( $1, tNoValues );
1245 		}
1246 	| json_expr '=' const_int // duplicate ident code (avoiding s/r conflict)
1247 		{
1248 			// it is performance-critical to forcibly inline this
1249 			pParser->m_pStmt->m_tUpdate.m_dPool.Add ( (DWORD)$3.m_iValue );
1250 			DWORD uHi = (DWORD)( $3.m_iValue>>32 );
1251 			if ( uHi )
1252 			{
1253 				pParser->m_pStmt->m_tUpdate.m_dPool.Add ( uHi );
1254 				pParser->AddUpdatedAttr ( $1, SPH_ATTR_BIGINT );
1255 			} else
1256 			{
1257 				pParser->AddUpdatedAttr ( $1, SPH_ATTR_INTEGER );
1258 			}
1259 		}
1260 	| json_expr '=' const_float
1261 		{
1262 			// it is performance-critical to forcibly inline this
1263 			pParser->m_pStmt->m_tUpdate.m_dPool.Add ( sphF2DW ( $3.m_fValue ) );
1264 			pParser->AddUpdatedAttr ( $1, SPH_ATTR_FLOAT );
1265 		}
1266 	;
1267 
1268 //////////////////////////////////////////////////////////////////////////
1269 
1270 alter_col_type:
1271 	TOK_INTEGER 	{ $$.m_iValue = SPH_ATTR_INTEGER; }
1272 	| TOK_BIGINT	{ $$.m_iValue = SPH_ATTR_BIGINT; }
1273 	| TOK_FLOAT		{ $$.m_iValue = SPH_ATTR_FLOAT; }
1274 	| TOK_BOOL		{ $$.m_iValue = SPH_ATTR_BOOL; }
1275 	| TOK_MULTI		{ $$.m_iValue = SPH_ATTR_UINT32SET; }
1276 	| TOK_MULTI64	{ $$.m_iValue = SPH_ATTR_INT64SET; }
1277 	| TOK_JSON		{ $$.m_iValue = SPH_ATTR_JSON; }
1278 	| TOK_STRING	{ $$.m_iValue = SPH_ATTR_STRING; }
1279 	| TOK_INT		{ $$.m_iValue = SPH_ATTR_INTEGER; }
1280 	;
1281 
1282 alter:
1283 	TOK_ALTER TOK_TABLE ident TOK_ADD TOK_COLUMN ident alter_col_type
1284 		{
1285 			SqlStmt_t & tStmt = *pParser->m_pStmt;
1286 			tStmt.m_eStmt = STMT_ALTER_ADD;
1287 			pParser->ToString ( tStmt.m_sIndex, $3 );
1288 			pParser->ToString ( tStmt.m_sAlterAttr, $6 );
1289 			tStmt.m_eAlterColType = (ESphAttr)$7.m_iValue;
1290 		}
1291 	| TOK_ALTER TOK_TABLE ident TOK_DROP TOK_COLUMN ident
1292 		{
1293 			SqlStmt_t & tStmt = *pParser->m_pStmt;
1294 			tStmt.m_eStmt = STMT_ALTER_DROP;
1295 			pParser->ToString ( tStmt.m_sIndex, $3 );
1296 			pParser->ToString ( tStmt.m_sAlterAttr, $6 );
1297 		}
1298 	| TOK_ALTER TOK_RTINDEX ident TOK_RECONFIGURE
1299 		{
1300 			SqlStmt_t & tStmt = *pParser->m_pStmt;
1301 			tStmt.m_eStmt = STMT_ALTER_RECONFIGURE;
1302 			pParser->ToString ( tStmt.m_sIndex, $3 );
1303 		}
1304 	;
1305 
1306 //////////////////////////////////////////////////////////////////////////
1307 
1308 show_variables:
1309 	TOK_SHOW opt_scope TOK_VARIABLES opt_show_variables_where
1310 		{
1311 			pParser->m_pStmt->m_eStmt = STMT_SHOW_VARIABLES;
1312 		}
1313 	| TOK_SHOW opt_scope TOK_VARIABLES TOK_LIKE TOK_QUOTED_STRING
1314 		{
1315 			pParser->m_pStmt->m_eStmt = STMT_SHOW_VARIABLES;
1316 			pParser->ToStringUnescape ( pParser->m_pStmt->m_sStringParam, $5 );
1317 		}
1318 	;
1319 
1320 opt_show_variables_where:
1321 	| show_variables_where
1322 	;
1323 
1324 show_variables_where:
1325 	TOK_WHERE show_variables_where_list
1326 	;
1327 
1328 show_variables_where_list:
1329 	show_variables_where_entry
1330 	| show_variables_where_list TOK_OR show_variables_where_entry
1331 	;
1332 
1333 show_variables_where_entry:
1334 	ident '=' TOK_QUOTED_STRING // for example, Variable_name = 'character_set'
1335 	;
1336 
1337 show_collation:
1338 	TOK_SHOW TOK_COLLATION
1339 		{
1340 			pParser->m_pStmt->m_eStmt = STMT_SHOW_COLLATION;
1341 		}
1342 	;
1343 
1344 show_character_set:
1345 	TOK_SHOW TOK_CHARACTER TOK_SET
1346 		{
1347 			pParser->m_pStmt->m_eStmt = STMT_SHOW_CHARACTER_SET;
1348 		}
1349 	;
1350 
1351 set_transaction:
1352 	TOK_SET opt_scope TOK_TRANSACTION TOK_ISOLATION TOK_LEVEL isolation_level
1353 		{
1354 			pParser->m_pStmt->m_eStmt = STMT_DUMMY;
1355 		}
1356 	;
1357 
1358 opt_scope:
1359 	| TOK_GLOBAL
1360 	| TOK_SESSION
1361 	;
1362 
1363 isolation_level:
1364 	TOK_READ TOK_UNCOMMITTED
1365 	| TOK_READ TOK_COMMITTED
1366 	| TOK_REPEATABLE TOK_READ
1367 	| TOK_SERIALIZABLE
1368 	;
1369 
1370 //////////////////////////////////////////////////////////////////////////
1371 
1372 create_function:
1373 	TOK_CREATE TOK_FUNCTION ident TOK_RETURNS udf_type TOK_SONAME TOK_QUOTED_STRING
1374 		{
1375 			SqlStmt_t & tStmt = *pParser->m_pStmt;
1376 			tStmt.m_eStmt = STMT_CREATE_FUNCTION;
1377 			pParser->ToString ( tStmt.m_sUdfName, $3 );
1378 			pParser->ToStringUnescape ( tStmt.m_sUdfLib, $7 );
1379 			tStmt.m_eUdfType = (ESphAttr) $5.m_iValue;
1380 		}
1381 	;
1382 
1383 udf_type:
1384 	TOK_INT			{ $$.m_iValue = SPH_ATTR_INTEGER; }
1385 	| TOK_BIGINT	{ $$.m_iValue = SPH_ATTR_BIGINT; }
1386 	| TOK_FLOAT		{ $$.m_iValue = SPH_ATTR_FLOAT; }
1387 	| TOK_STRING	{ $$.m_iValue = SPH_ATTR_STRINGPTR; }
1388 	| TOK_INTEGER	{ $$.m_iValue = SPH_ATTR_INTEGER; }
1389 	;
1390 
1391 
1392 drop_function:
1393 	TOK_DROP TOK_FUNCTION ident
1394 		{
1395 			SqlStmt_t & tStmt = *pParser->m_pStmt;
1396 			tStmt.m_eStmt = STMT_DROP_FUNCTION;
1397 			pParser->ToString ( tStmt.m_sUdfName, $3 );
1398 		}
1399 	;
1400 
1401 ////////////////////////////////////////////////////////////
1402 
1403 attach_index:
1404 	TOK_ATTACH TOK_INDEX ident TOK_TO TOK_RTINDEX ident
1405 		{
1406 			SqlStmt_t & tStmt = *pParser->m_pStmt;
1407 			tStmt.m_eStmt = STMT_ATTACH_INDEX;
1408 			pParser->ToString ( tStmt.m_sIndex, $3 );
1409 			pParser->ToString ( tStmt.m_sStringParam, $6 );
1410 		}
1411 	;
1412 
1413 //////////////////////////////////////////////////////////////////////////
1414 
1415 flush_rtindex:
1416 	TOK_FLUSH TOK_RTINDEX ident
1417 		{
1418 			SqlStmt_t & tStmt = *pParser->m_pStmt;
1419 			tStmt.m_eStmt = STMT_FLUSH_RTINDEX;
1420 			pParser->ToString ( tStmt.m_sIndex, $3 );
1421 		}
1422 	;
1423 
1424 flush_ramchunk:
1425 	TOK_FLUSH TOK_RAMCHUNK ident
1426 		{
1427 			SqlStmt_t & tStmt = *pParser->m_pStmt;
1428 			tStmt.m_eStmt = STMT_FLUSH_RAMCHUNK;
1429 			pParser->ToString ( tStmt.m_sIndex, $3 );
1430 		}
1431 	;
1432 
1433 flush_index:
1434 	TOK_FLUSH TOK_ATTRIBUTES
1435 		{
1436 			SqlStmt_t & tStmt = *pParser->m_pStmt;
1437 			tStmt.m_eStmt = STMT_FLUSH_INDEX;
1438 		}
1439 	;
1440 
1441 //////////////////////////////////////////////////////////////////////////
1442 
1443 select_sysvar:
1444 	TOK_SELECT sysvar_list opt_limit_clause
1445 		{
1446 			pParser->m_pStmt->m_eStmt = STMT_SELECT_SYSVAR;
1447 			pParser->ToString ( pParser->m_pStmt->m_tQuery.m_sQuery, $2 );
1448 		}
1449 	;
1450 
1451 sysvar_list:
1452 	sysvar_item
1453 	| sysvar_list ',' sysvar_item
1454 	;
1455 
1456 sysvar_item:
1457 	sysvar_name opt_alias
1458 	;
1459 
1460 sysvar_name:
1461 	TOK_SYSVAR { pParser->AddItem ( &$1 ); }
1462 	;
1463 
1464 select_dual:
1465 	TOK_SELECT expr
1466 		{
1467 			pParser->m_pStmt->m_eStmt = STMT_SELECT_DUAL;
1468 			pParser->ToString ( pParser->m_pStmt->m_tQuery.m_sQuery, $2 );
1469 		}
1470 	;
1471 
1472 //////////////////////////////////////////////////////////////////////////
1473 
1474 truncate:
1475 	TOK_TRUNCATE TOK_RTINDEX ident
1476 		{
1477 			SqlStmt_t & tStmt = *pParser->m_pStmt;
1478 			tStmt.m_eStmt = STMT_TRUNCATE_RTINDEX;
1479 			pParser->ToString ( tStmt.m_sIndex, $3 );
1480 		}
1481 	;
1482 
1483 //////////////////////////////////////////////////////////////////////////
1484 
1485 optimize_index:
1486 	TOK_OPTIMIZE TOK_INDEX ident
1487 		{
1488 			SqlStmt_t & tStmt = *pParser->m_pStmt;
1489 			tStmt.m_eStmt = STMT_OPTIMIZE_INDEX;
1490 			pParser->ToString ( tStmt.m_sIndex, $3 );
1491 		}
1492 	;
1493 
1494 //////////////////////////////////////////////////////////////////////////
1495 
1496 create_plugin:
1497 	TOK_CREATE TOK_PLUGIN ident TOK_TYPE TOK_QUOTED_STRING TOK_SONAME TOK_QUOTED_STRING
1498 		{
1499 			SqlStmt_t & s = *pParser->m_pStmt;
1500 			s.m_eStmt = STMT_CREATE_PLUGIN;
1501 			pParser->ToString ( s.m_sUdfName, $3 );
1502 			pParser->ToStringUnescape ( s.m_sStringParam, $5 );
1503 			pParser->ToStringUnescape ( s.m_sUdfLib, $7 );
1504 		}
1505 	;
1506 
1507 drop_plugin:
1508 	TOK_DROP TOK_PLUGIN ident TOK_TYPE TOK_QUOTED_STRING
1509 		{
1510 			SqlStmt_t & s = *pParser->m_pStmt;
1511 			s.m_eStmt = STMT_DROP_PLUGIN;
1512 			pParser->ToString ( s.m_sUdfName, $3 );
1513 			pParser->ToStringUnescape ( s.m_sStringParam, $5 );
1514 		}
1515 	;
1516 //////////////////////////////////////////////////////////////////////////
1517 
1518 json_field:
1519 	json_expr
1520 	| ident
1521 	;
1522 
1523 json_expr:
1524 	ident subscript				{ $$ = $1; $$.m_iEnd = $2.m_iEnd; }
1525 
1526 subscript:
1527 	subkey
1528 	| subscript subkey			{ $$ = $1; $$.m_iEnd = $2.m_iEnd; }
1529 	;
1530 
1531 subkey:
1532 	TOK_SUBKEY					{ $$ = $1; $$.m_iEnd = $1.m_iEnd; }
1533 	| TOK_DOT_NUMBER			{ $$ = $1; $$.m_iEnd = $1.m_iEnd; }
1534 	| '[' expr ']'				{ $$ = $1; $$.m_iEnd = $3.m_iEnd; }
1535 	| '[' TOK_QUOTED_STRING ']'	{ $$ = $1; $$.m_iEnd = $3.m_iEnd; }
1536 	;
1537 
1538 streq:
1539 	expr '=' strval				{ TRACK_BOUNDS ( $$, $1, $3 ); }
1540 	| strval '=' expr			{ TRACK_BOUNDS ( $$, $1, $3 ); }
1541 	;
1542 
1543 strval:
1544 	TOK_QUOTED_STRING
1545 	;
1546 
1547 //////////////////////////////////////////////////////////////////////////
1548 
1549 opt_facet_by_items_list:
1550 	// empty
1551 	| facet_by facet_items_list
1552 	;
1553 
1554 facet_by:
1555 	TOK_BY
1556 		{
1557 			pParser->m_pQuery->m_sFacetBy = pParser->m_pQuery->m_sGroupBy;
1558 			pParser->m_pQuery->m_sGroupBy = "";
1559 			pParser->AddCount ();
1560 		}
1561 	;
1562 
1563 facet_item:
1564 	facet_expr opt_alias
1565 	;
1566 
1567 facet_expr:
1568 	expr
1569 		{
1570 			pParser->AddItem ( &$1 );
1571 			pParser->AddGroupBy ( $1 );
1572 		}
1573 	;
1574 
1575 facet_items_list:
1576 	facet_item
1577 	| facet_items_list ',' facet_item
1578 	;
1579 
1580 facet_stmt:
1581 	TOK_FACET facet_items_list opt_facet_by_items_list opt_order_clause opt_limit_clause
1582 		{
1583 			pParser->m_pStmt->m_eStmt = STMT_FACET;
1584 			if ( pParser->m_pQuery->m_sFacetBy.IsEmpty() )
1585 			{
1586 				pParser->m_pQuery->m_sFacetBy = pParser->m_pQuery->m_sGroupBy;
1587 				pParser->AddCount ();
1588 			}
1589 		}
1590 	;
1591 
1592 %%
1593 
1594 #if USE_WINDOWS
1595 #pragma warning(pop)
1596 #endif
1597