Completed
Pull Request — develop (#875)
by hung
05:57
created

RDatabaseSqlparserSqlcreator::processOrderByBracketExpression()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 7
rs 10
cc 2
nc 2
nop 1
1
<?php
2
/**
3
 * @package     Redcore
4
 * @subpackage  Exception
5
 *
6
 * @copyright   Copyright (C) 2008 - 2016 redCOMPONENT.com. All rights reserved.
7
 * @license     GNU General Public License version 2 or later, see LICENSE.
8
 */
9
10
defined('JPATH_REDCORE') or die;
11
12
/**
13
 * A pure PHP SQL creator, which generates SQL from the output of RDatabaseSqlparserSqlparser.
14
 * 
15
 * Copyright (c) 2012, André Rothe <[email protected], [email protected]>
16
 * 
17
 * All rights reserved.
18
 *
19
 * Redistribution and use in source and binary forms, with or without modification, 
20
 * are permitted provided that the following conditions are met:
21
 *
22
 *   * Redistributions of source code must retain the above copyright notice, 
23
 *     this list of conditions and the following disclaimer.
24
 *   * Redistributions in binary form must reproduce the above copyright notice, 
25
 *     this list of conditions and the following disclaimer in the documentation 
26
 *     and/or other materials provided with the distribution.
27
 *
28
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
29
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
30
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
31
 * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
32
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
33
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
34
 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
35
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
36
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
37
 * DAMAGE.
38
 */
39
40
class RDatabaseSqlparserSqlcreator {
41
42
	public $created;
43
44
	public function __construct($parsed = null) {
45
		if ($parsed) {
46
			$this->create($parsed);
47
		}
48
	}
49
50
	public function create($parsed) {
51
		$k = key($parsed);
52
		switch ($k) {
53
54
		case "UNION":
55
		case "UNION ALL":
56
			throw new Exception($k . " not implemented.", 20);
57
			break;
58
		case "SELECT":
59
			$this->created = $this->processSelectStatement($parsed);
60
			break;
61
		case "INSERT":
62
			$this->created = $this->processInsertStatement($parsed);
63
			break;
64
		case "DELETE":
65
			$this->created = $this->processDeleteStatement($parsed);
66
			break;
67
		case "UPDATE":
68
			$this->created = $this->processUpdateStatement($parsed);
69
			break;
70
		default:
71
			throw new Exception($k . " not implemented.", 20);
72
			break;
73
		}
74
		return $this->created;
75
	}
76
77
	protected function processSelectStatement($parsed)
78
	{
79
80
		$sql = $this->processSELECT($parsed['SELECT']) . " " . $this->processFROM($parsed['FROM']);
81
		if (isset($parsed['WHERE'])) {
82
			$sql .= " " . $this->processWHERE($parsed['WHERE']);
83
		}
84
		if (isset($parsed['GROUP'])) {
85
			$sql .= " " . $this->processGROUP($parsed['GROUP']);
86
		}
87
		if (isset($parsed['ORDER'])) {
88
			$sql .= " " . $this->processORDER($parsed['ORDER']);
89
		}
90
		if (isset($parsed['LIMIT'])) {
91
			$sql .= " " . $this->processLIMIT($parsed['LIMIT']);
92
		}
93
		return $sql;
94
	}
95
96
	protected function processInsertStatement($parsed) {
97
		return $this->processINSERT($parsed['INSERT']) . " " . $this->processVALUES($parsed['VALUES']);
98
		// TODO: subquery?
99
	}
100
101
	protected function processDeleteStatement($parsed) {
102
		return $this->processDELETE($parsed['DELETE']) . " " . $this->processFROM($parsed['FROM']) . " "
103
				. $this->processWHERE($parsed['WHERE']);
104
	}
105
106
	protected function processUpdateStatement($parsed) {
107
		$sql = $this->processUPDATE($parsed['UPDATE']) . " " . $this->processSET($parsed['SET']);
108
		if (isset($parsed['WHERE'])) {
109
			$sql .= " " . $this->processWHERE($parsed['WHERE']);
110
		}
111
		return $sql;
112
	}
113
114
	protected function processDELETE($parsed) {
115
		$sql = "DELETE";
116
		foreach ($parsed['TABLES'] as $v) {
117
			$sql .= $v . ",";
118
		}
119
		return substr($sql, 0, -1);
120
	}
121
122
	protected function processSELECT($parsed)
123
	{
124
		$sql = "";
125
126
		foreach ($parsed as $k => $v)
127
		{
128
			$len = strlen($sql);
129
			$sql .= $this->processReserved($v);
130
			$sql .= $this->processColRef($v);
131
			$sql .= $this->processSelectExpression($v);
132
			$sql .= $this->processFunction($v);
133
			$sql .= $this->processConstant($v);
134
			$sql .= $this->processSelectBracketExpression($v);
135
136
			if ($len == strlen($sql))
137
			{
138
				throw new RDatabaseSqlparserExceptioncreatesql('SELECT', $k, $v, 'expr_type');
139
			}
140
141
			$sql .= ",";
142
		}
143
144
		$sql = substr($sql, 0, -1);
145
146
		return "SELECT " . $sql;
147
	}
148
149
	protected function processFROM($parsed) {
150
		$sql = "";
151
		foreach ($parsed as $k => $v) {
152
			$len = strlen($sql);
153
			$sql .= $this->processTable($v, $k);
154
			$sql .= $this->processTableExpression($v, $k);
155
			$sql .= $this->processSubQuery($v, $k);
156
			$sql .= $this->processConstant($v);
157
			$sql .= $this->processIndexHints($v);
158
159
			if ($len == strlen($sql)) {
160
				throw new RDatabaseSqlparserExceptioncreatesql('FROM', $k, $v, 'expr_type');
161
			}
162
163
			$sql .= " ";
164
		}
165
		return "FROM " . substr($sql, 0, -1);
166
	}
167
168
	protected function processORDER($parsed) {
169
		$sql = "";
170
		foreach ($parsed as $k => $v) {
171
			$len = strlen($sql);
172
			$sql .= $this->processOrderByAlias($v);
173
			$sql .= $this->processColRef($v);
174
			$sql .= $this->processConstant($v);
175
			$sql .= $this->processFunction($v);
176
			$sql .= $this->processOrderByExpression($v);
177
			$sql .= $this->processOrderByBracketExpression($v);
178
179
			if ($len == strlen($sql)) {
180
				throw new RDatabaseSqlparserExceptioncreatesql('ORDER', $k, $v, 'expr_type');
181
			}
182
183
			$sql .= ",";
184
		}
185
		$sql = substr($sql, 0, -1);
186
		return "ORDER BY " . $sql;
187
	}
188
189
	protected function processLIMIT($parsed) {
190
		$sql = (!empty($parsed['offset']) ? $parsed['offset'] . ", " : "");
191
		$sql .= (!empty($parsed['rowcount']) ? $parsed['rowcount'] : "");
192
		if ($sql === "") {
193
			throw new RDatabaseSqlparserExceptioncreatesql('LIMIT', 'rowcount', $parsed, 'rowcount');
194
		}
195
		return "LIMIT " . $sql;
196
	}
197
198
	protected function processIndexHints($parsed)
199
	{
200
		if (!isset($parsed['index_hints']) || !$parsed['index_hints'])
201
		{
202
			return "";
203
		}
204
205
		if ($parsed['index_hints']['base_expr'] == "")
206
		{
207
			throw new RDatabaseSqlparserExceptioncreatesql('Index_Hints', 'USE', $parsed['index_hints'], 'expr_type');
208
		}
209
210
		return ' ' . $parsed['index_hints']['base_expr'];
211
	}
212
213
	protected function processGROUP($parsed) {
214
		$sql = "";
215
		foreach ($parsed as $k => $v) {
216
			$len = strlen($sql);
217
			$sql .= $this->processColRef($v);
218
			$sql .= $this->processPosition($v);
219
			$sql .= $this->processFunction($v);
220
			$sql .= $this->processGroupByAlias($v);
221
			$sql .= $this->processGroupByExpression($v);
222
223
			if ($len == strlen($sql)) {
224
				throw new RDatabaseSqlparserExceptioncreatesql('GROUP', $k, $v, 'expr_type');
225
			}
226
227
			$sql .= ",";
228
		}
229
		$sql = substr($sql, 0, -1);
230
		return "GROUP BY " . $sql;
231
	}
232
233
	protected function processGroupByAlias($parsed) {
234
		if ($parsed['expr_type'] !== 'alias') {
235
			return "";
236
		}
237
		return $parsed['base_expr'];
238
	}
239
240
	protected function processPosition($parsed) {
241
		if ($parsed['expr_type'] !== 'pos') {
242
			return "";
243
		}
244
		return $parsed['base_expr'];
245
	}
246
247
	protected function processRecord($parsed) {
248
		if ($parsed['expr_type'] !== 'record') {
249
			return "";
250
		}
251
		$sql = "";
252
		foreach ($parsed['data'] as $k => $v) {
253
			$len = strlen($sql);
254
			$sql .= $this->processConstant($v);
255
			$sql .= $this->processFunction($v);
256
			$sql .= $this->processOperator($v);
257
258
			if ($len == strlen($sql)) {
259
				throw new RDatabaseSqlparserExceptioncreatesql('record', $k, $v, 'expr_type');
260
			}
261
262
			$sql .= ",";
263
		}
264
		$sql = substr($sql, 0, -1);
265
		return "(" . $sql . ")";
266
267
	}
268
269
	protected function processVALUES($parsed) {
270
		$sql = "";
271
		foreach ($parsed as $k => $v) {
272
			$len = strlen($sql);
273
			$sql .= $this->processRecord($v);
274
275
			if ($len == strlen($sql)) {
276
				throw new RDatabaseSqlparserExceptioncreatesql('VALUES', $k, $v, 'expr_type');
277
			}
278
279
			$sql .= ",";
280
		}
281
		$sql = substr($sql, 0, -1);
282
		return "VALUES " . $sql;
283
	}
284
285
	protected function processINSERT($parsed) {
286
		$sql = "INSERT INTO " . $parsed['table'];
287
288
		if ($parsed['columns'] === false) {
289
			return $sql;
290
		}
291
292
		$columns = "";
293
		foreach ($parsed['columns'] as $k => $v) {
294
			$len = strlen($columns);
295
			$columns .= $this->processColRef($v);
296
297
			if ($len == strlen($columns)) {
298
				throw new RDatabaseSqlparserExceptioncreatesql('INSERT[columns]', $k, $v, 'expr_type');
299
			}
300
301
			$columns .= ",";
302
		}
303
304
		if ($columns !== "") {
305
			$columns = " (" . substr($columns, 0, -1) . ")";
306
		}
307
308
		$sql .= $columns;
309
		return $sql;
310
	}
311
312
	protected function processUPDATE($parsed) {
313
		return "UPDATE " . $parsed[0]['table'];
314
	}
315
316
	protected function processSetExpression($parsed) {
317
		if ($parsed['expr_type'] !== 'expression') {
318
			return "";
319
		}
320
		$sql = "";
321
		foreach ($parsed['sub_tree'] as $k => $v) {
322
			$len = strlen($sql);
323
			if (($this->isReserved($v) || $this->isOperator($v)) && !empty($sql) && substr($sql, -1) == ',')
324
			{
325
				$sql = substr($sql, 0, -1) . ' ';
326
			}
327
328
			$sql .= $this->processReserved($v);
329
			$sql .= $this->processColRef($v);
330
			$sql .= $this->processConstant($v);
331
			$sql .= $this->processOperator($v);
332
			$sql .= $this->processFunction($v);
333
334
			if ($len == strlen($sql)) {
335
				throw new RDatabaseSqlparserExceptioncreatesql('SET expression subtree', $k, $v, 'expr_type');
336
			}
337
338
			$sql .= " ";
339
		}
340
341
		$sql = substr($sql, 0, -1);
342
		return $sql;
343
	}
344
345
	protected function processSET($parsed) {
346
		$sql = "";
347
		foreach ($parsed as $k => $v) {
348
			$len = strlen($sql);
349
			$sql .= $this->processSetExpression($v);
350
351
			if ($len == strlen($sql)) {
352
				throw new RDatabaseSqlparserExceptioncreatesql('SET', $k, $v, 'expr_type');
353
			}
354
355
			$sql .= ",";
356
		}
357
		return "SET " . substr($sql, 0, -1);
358
	}
359
360
	protected function processWHERE($parsed) {
361
		$sql = "WHERE ";
362
		foreach ($parsed as $k => $v) {
363
			$len = strlen($sql);
364
365
			if (($this->isReserved($v) || $this->isOperator($v)) && !empty($sql) && substr($sql, -1) == ',')
366
			{
367
				$sql = substr($sql, 0, -1) . ' ';
368
			}
369
370
			$sql .= $this->processReserved($v);
371
			$sql .= $this->processOperator($v);
372
			$sql .= $this->processConstant($v);
373
			$sql .= $this->processColRef($v);
374
			$sql .= $this->processSubQuery($v);
375
			$sql .= $this->processInList($v);
376
			$sql .= $this->processFunction($v);
377
			$sql .= $this->processWhereExpression($v);
378
			$sql .= $this->processWhereBracketExpression($v);
379
380
			if (strlen($sql) == $len) {
381
				throw new RDatabaseSqlparserExceptioncreatesql('WHERE', $k, $v, 'expr_type');
382
			}
383
384
			$sql .= " ";
385
		}
386
		return substr($sql, 0, -1);
387
	}
388
389
	protected function processWhereExpression($parsed) {
390
		if (empty($parsed['expr_type']) || $parsed['expr_type'] !== 'expression') {
391
			return "";
392
		}
393
		$sql = "";
394
		foreach ($parsed['sub_tree'] as $k => $v) {
395
			$len = strlen($sql);
396
			if (($this->isReserved($v) || $this->isOperator($v)) && !empty($sql) && substr($sql, -1) == ',')
397
			{
398
				$sql = substr($sql, 0, -1) . ' ';
399
			}
400
401
			$sql .= $this->processReserved($v);
402
			$sql .= $this->processColRef($v);
403
			$sql .= $this->processConstant($v);
404
			$sql .= $this->processOperator($v);
405
			$sql .= $this->processInList($v);
406
			$sql .= $this->processFunction($v);
407
			$sql .= $this->processWhereExpression($v);
408
			$sql .= $this->processWhereBracketExpression($v);
409
			$sql .= $this->processSubQuery($v);
410
411
			if ($len == strlen($sql)) {
412
				throw new RDatabaseSqlparserExceptioncreatesql('WHERE expression subtree', $k, $v, 'expr_type');
413
			}
414
415
			$sql .= " ";
416
		}
417
418
		$sql = substr($sql, 0, -1);
419
		return $sql;
420
	}
421
422
	protected function processWhereBracketExpression($parsed) {
423
		if (empty($parsed['expr_type']) || $parsed['expr_type'] !== 'bracket_expression') {
424
			return "";
425
		}
426
		elseif (empty($parsed['sub_tree']))
427
		{
428
			return "()";
429
		}
430
		$sql = "";
431
		foreach ($parsed['sub_tree'] as $k => $v) {
432
			$len = strlen($sql);
433
			if (($this->isReserved($v) || $this->isOperator($v)) && !empty($sql) && substr($sql, -1) == ',')
434
			{
435
				$sql = substr($sql, 0, -1) . ' ';
436
			}
437
438
			$sql .= $this->processReserved($v);
439
			$sql .= $this->processColRef($v);
440
			$sql .= $this->processConstant($v);
441
			$sql .= $this->processOperator($v);
442
			$sql .= $this->processInList($v);
443
			$sql .= $this->processFunction($v);
444
			$sql .= $this->processWhereExpression($v);
445
			$sql .= $this->processWhereBracketExpression($v);
446
			$sql .= $this->processSubQuery($v);
447
448
			if ($len == strlen($sql)) {
449
				throw new RDatabaseSqlparserExceptioncreatesql('WHERE expression subtree', $k, $v, 'expr_type');
450
			}
451
452
			$sql .= " ";
453
		}
454
455
		$sql = "(" . substr($sql, 0, -1) . ")";
456
		return $sql;
457
	}
458
459
	protected function processOrderByAlias($parsed) {
460
		if ($parsed['expr_type'] !== 'alias') {
461
			return "";
462
		}
463
		return $parsed['base_expr'] . $this->processDirection($parsed['direction']);
464
	}
465
466
	protected function processLimitRowCount($key, $value) {
467
		if ($key != 'rowcount') {
468
			return "";
469
		}
470
		return $value;
471
	}
472
473
	protected function processLimitOffset($key, $value) {
474
		if ($key !== 'offset') {
475
			return "";
476
		}
477
		return $value;
478
	}
479
480
	protected function processFunction($parsed) {
481
		if (empty($parsed['expr_type']) || (($parsed['expr_type'] !== 'aggregate_function') && ($parsed['expr_type'] !== 'function'))) {
482
			return "";
483
		}
484
485
		if ($parsed['sub_tree'] === false) {
486
			return $parsed['base_expr'] . "()";
487
		}
488
489
		$sql = "";
490
491
		foreach ($parsed['sub_tree'] as $k => $v) {
492
			$len = strlen($sql);
493
494
			if (($this->isReserved($v) || $this->isOperator($v)) && !empty($sql) && substr($sql, -1) == ',')
495
			{
496
				$sql = substr($sql, 0, -1) . ' ';
497
			}
498
499
			$sql .= (!empty($this->processReserved($v))) ? ',' . $this->processReserved($v) : $this->processReserved($v);
500
			$sql .= $this->processFunction($v);
501
			$sql .= $this->processConstant($v);
502
			$sql .= $this->processOperator($v);
503
			$sql .= $this->processColRef($v);
504
			$sql .= $this->processInList($v);
505
			$sql .= $this->processSelectBracketExpression($v);
506
			$sql .= $this->processSelectExpression($v);
507
			$sql .= $this->processSubQuery($v);
508
509
			if ($len == strlen($sql)) {
510
				throw new RDatabaseSqlparserExceptioncreatesql('function subtree', $k, $v, 'expr_type');
511
			}
512
513
			$sql .= ($this->isReserved($v) || $this->isOperator($v) ? " " : ",");
514
		}
515
516
		$sql2 = $parsed['base_expr'] . "(" . substr($sql, 0, -1) . ")";
517
		$sql2 .= !empty($parsed['alias']) ? $this->processAlias($parsed['alias']) : '';
518
519
		return $sql2;
520
	}
521
522
	protected function processSelectExpression($parsed) {
523
		if ($parsed['expr_type'] !== 'expression') {
524
			return "";
525
		}
526
		$sql = $this->processSubTree($parsed, " ");
527
		$sql .= $this->processAlias($parsed['alias']);
528
		return $sql;
529
	}
530
531
	protected function processGroupByExpression($parsed) {
532
		if ($parsed['expr_type'] !== 'expression') {
533
			return "";
534
		}
535
		$sql = $this->processSubTree($parsed, " ");
536
		return $sql;
537
	}
538
539
	protected function processOrderByExpression($parsed) {
540
		if ($parsed['expr_type'] !== 'expression') {
541
			return "";
542
		}
543
		$sql = $this->processSubTree($parsed, " ");
544
545
		return $sql;
546
	}
547
548
	protected function processOrderByBracketExpression($parsed) {
549
		if ($parsed['expr_type'] !== 'bracket_expression') {
550
			return "";
551
		}
552
		$sql = $this->processSubTree($parsed, " ");
553
554
		return $sql;
555
	}
556
557
	protected function processSelectBracketExpression($parsed)
558
	{
559
		if (empty($parsed['expr_type']) || $parsed['expr_type'] !== 'bracket_expression')
560
		{
561
			return "";
562
		}
563
		elseif (empty($parsed['sub_tree']))
564
		{
565
			return "";
566
		}
567
568
		$sql = $this->processSubTree($parsed, " ");
569
		$sql .= $this->processColRef($parsed);
570
		$sql = "(" . $sql . ")";
571
		$sql .= !empty($parsed['alias']) ? $this->processAlias($parsed['alias']) : '';
572
573
		return $sql;
574
	}
575
576
	protected function processSubTree($parsed, $delim = " ") {
577
		if ($parsed['sub_tree'] === '') {
578
			return "";
579
		}
580
		$sql = "";
581
		foreach ($parsed['sub_tree'] as $k => $v) {
582
			$len = strlen($sql);
583
584
			if (($this->isReserved($v) || $this->isOperator($v)) && !empty($sql) && substr($sql, -1) == ',')
585
			{
586
				$sql = substr($sql, 0, -1) . ' ';
587
			}
588
589
			$sql .= $this->processReserved($v);
590
			$sql .= $this->processFunction($v);
591
			$sql .= $this->processOperator($v);
592
			$sql .= $this->processConstant($v);
593
			$sql .= $this->processUserVariable($v);
594
			$sql .= $this->processSelectBracketExpression($v);
595
			$sql .= $this->processSelectExpression($v);
596
			$sql .= $this->processSubQuery($v);
597
598
			// Always last since it will give alias if needed
599
			$sql .= $this->processColRef($v);
600
601
			if ($len == strlen($sql)) {
602
				throw new RDatabaseSqlparserExceptioncreatesql('expression subtree', $k, $v, 'expr_type');
603
			}
604
605
			$sql .= ($this->isReserved($v) || $this->isOperator($v) ? " " : $delim);
606
		}
607
608
		$sql = substr($sql, 0, -1);
609
610
		return $sql;
611
	}
612
613
	protected function processRefClause($parsed) {
614
		if ($parsed === false) {
615
			return "";
616
		}
617
618
		$sql = "";
619
		foreach ($parsed as $k => $v) {
620
			$len = strlen($sql);
621
622
			if (($this->isReserved($v) || $this->isOperator($v)) && !empty($sql) && substr($sql, -1) == ',')
623
			{
624
				$sql = substr($sql, 0, -1) . ' ';
625
			}
626
627
			$sql .= $this->processReserved($v);
628
			$sql .= $this->processColRef($v);
629
			$sql .= $this->processFunction($v);
630
			$sql .= $this->processOperator($v);
631
			$sql .= $this->processInList($v);
632
			$sql .= $this->processConstant($v);
633
			$sql .= $this->processSelectBracketExpression($v);
634
			$sql .= $this->processSelectExpression($v);
635
			$sql .= $this->processSubQuery($v);
636
637
			if ($len == strlen($sql)) {
638
				throw new RDatabaseSqlparserExceptioncreatesql('expression ref_clause', $k, $v, 'expr_type');
639
			}
640
641
			$sql .= " ";
642
		}
643
		return "(" . substr($sql, 0, -1) . ")";
644
	}
645
646
	protected function processAlias($parsed) {
647
		if ($parsed === false) {
648
			return "";
649
		}
650
		$sql = "";
651
		if (!empty($parsed['as'])) {
652
			$sql .= " as";
653
		}
654
		if (!empty($parsed['name'])) {
655
		$sql .= " " . $parsed['name'];
656
		}
657
658
		return $sql;
659
	}
660
661
	protected function processJoin($parsed) {
662
		if ($parsed === 'CROSS') {
663
			return ",";
664
		}
665
		if ($parsed === 'JOIN') {
666
			return "INNER JOIN";
667
		}
668
		if ($parsed === 'LEFT') {
669
			return "LEFT JOIN";
670
		}
671
		if ($parsed === 'RIGHT') {
672
			return "RIGHT JOIN";
673
		}
674
		// TODO: add more
675
		throw new Exception($parsed, 20);
676
	}
677
678
	protected function processRefType($parsed) {
679
		if ($parsed === false) {
680
			return "";
681
		}
682
		if ($parsed === 'ON') {
683
			return " ON ";
684
		}
685
		if ($parsed === 'USING') {
686
			return " USING ";
687
		}
688
		// TODO: add more
689
		throw new Exception($parsed, 20);
690
	}
691
692
	protected function processTable($parsed, $index) {
693
		if ($parsed['expr_type'] !== 'table') {
694
			return "";
695
		}
696
697
		$sql = $parsed['table'];
698
		$sql .= $this->processAlias($parsed['alias']);
699
700
		if ($index !== 0) {
701
			$sql = $this->processJoin($parsed['join_type']) . " " . $sql;
702
			$sql .= $this->processRefType($parsed['ref_type']);
703
			$sql .= $this->processRefClause($parsed['ref_clause']);
704
		}
705
		return $sql;
706
	}
707
708
	protected function processTableExpression($parsed, $index) {
709
		if ($parsed['expr_type'] !== 'table_expression') {
710
			return "";
711
		}
712
		$sql = substr($this->processFROM($parsed['sub_tree']), 5); // remove FROM keyword
713
		$sql = "(" . $sql . ")";
714
715
		if (isset($parsed['alias'])) {
716
			$sql .= $this->processAlias($parsed['alias']);
717
		}
718
719
		if ($index !== 0) {
720
			$sql = $this->processJoin($parsed['join_type']) . " " . $sql;
721
			$sql .= $this->processRefType($parsed['ref_type']);
722
			$sql .= $this->processRefClause($parsed['ref_clause']);
723
		}
724
		return $sql;
725
	}
726
727
	protected function processSubQuery($parsed, $index = 0)
728
	{
729
		if ($parsed['expr_type'] !== 'subquery')
730
		{
731
			return "";
732
		}
733
734
		// We handle subqueries in a loop in sqltranslation file
735
		$sql = $parsed['base_expr'];
736
		$sql = "(" . $sql . ")";
737
738
		if (isset($parsed['alias']))
739
		{
740
			$sql .= $this->processAlias($parsed['alias']);
741
		}
742
743
		if ($index !== 0)
744
		{
745
			$sql = $this->processJoin($parsed['join_type']) . " " . $sql;
746
			$sql .= $this->processRefType($parsed['ref_type']);
747
			$sql .= $this->processRefClause($parsed['ref_clause']);
748
		}
749
750
		return $sql;
751
	}
752
753
	protected function processOperator($parsed) {
754
		if (empty($parsed['expr_type']) || $parsed['expr_type'] !== 'operator') {
755
			return "";
756
		}
757
		return $parsed['base_expr'];
758
	}
759
760
	protected function processColRef($parsed) {
761
		if (empty($parsed['expr_type']) || $parsed['expr_type'] !== 'colref') {
762
			return "";
763
		}
764
		$sql = $parsed['base_expr'];
765
		if (isset($parsed['alias'])) {
766
			$sql .= $this->processAlias($parsed['alias']);
767
		}
768
		if (isset($parsed['direction'])) {
769
			$sql .= $this->processDirection($parsed['direction']);
770
		}
771
		return $sql;
772
	}
773
774
	protected function processDirection($parsed) {
775
		$sql = ($parsed ? " " . $parsed : "");
776
		return $sql;
777
	}
778
779
	protected function processReserved($parsed)
780
	{
781
		if (!$this->isReserved($parsed))
782
		{
783
			return "";
784
		}
785
786
		$sql = $parsed['base_expr'];
787
788
		if (isset($parsed['alias']))
789
		{
790
			$sql .= $this->processAlias($parsed['alias']);
791
		}
792
793
		return $sql;
794
	}
795
796
	protected function isReserved($parsed) {
797
		return (!empty($parsed['expr_type']) && $parsed['expr_type'] === 'reserved');
798
	}
799
800
	protected function isOperator($parsed) {
801
		return (!empty($parsed['expr_type']) && $parsed['expr_type'] === 'operator');
802
	}
803
804
	protected function processConstant($parsed) {
805
		if (empty($parsed['expr_type']) || $parsed['expr_type'] !== 'const') {
806
			return "";
807
		}
808
809
		$sql = $parsed['base_expr'];
810
811
		if (isset($parsed['alias'])) {
812
			$sql .= $this->processAlias($parsed['alias']);
813
		}
814
815
		return $sql;
816
	}
817
818
	protected function processUserVariable($parsed)
819
	{
820
		if (empty($parsed['expr_type']) || $parsed['expr_type'] !== 'user_variable')
821
		{
822
			return "";
823
		}
824
825
		$sql = $parsed['base_expr'];
826
827
		if (isset($parsed['alias']))
828
		{
829
			$sql .= $this->processAlias($parsed['alias']);
830
		}
831
832
		return $sql;
833
	}
834
835
	protected function processInList($parsed) {
836
		if (empty($parsed['expr_type']) || $parsed['expr_type'] !== 'in-list') {
837
			return "";
838
		}
839
		$sql = $this->processSubTree($parsed, ",");
840
		return "(" . $sql . ")";
841
	}
842
843
}
844