Passed
Pull Request — develop (#895)
by hung
04:46
created

processOrderByBracketExpression()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 4
c 1
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 - 2020 redWEB.dk. 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 processOrderByBracketExpression($parsed) {
190
		if ($parsed['expr_type'] !== 'bracket_expression') {
191
			return "";
192
		}
193
		$sql = $this->processSubTree($parsed, " ");
194
195
		return $sql;
196
	}
197
198
	protected function processLIMIT($parsed) {
199
		$sql = (!empty($parsed['offset']) ? $parsed['offset'] . ", " : "");
200
		$sql .= (!empty($parsed['rowcount']) ? $parsed['rowcount'] : "");
201
		if ($sql === "") {
202
			throw new RDatabaseSqlparserExceptioncreatesql('LIMIT', 'rowcount', $parsed, 'rowcount');
203
		}
204
		return "LIMIT " . $sql;
205
	}
206
207
	protected function processIndexHints($parsed)
208
	{
209
		if (!isset($parsed['index_hints']) || !$parsed['index_hints'])
210
		{
211
			return "";
212
		}
213
214
		if ($parsed['index_hints']['base_expr'] == "")
215
		{
216
			throw new RDatabaseSqlparserExceptioncreatesql('Index_Hints', 'USE', $parsed['index_hints'], 'expr_type');
217
		}
218
219
		return ' ' . $parsed['index_hints']['base_expr'];
220
	}
221
222
	protected function processGROUP($parsed) {
223
		$sql = "";
224
		foreach ($parsed as $k => $v) {
225
			$len = strlen($sql);
226
			$sql .= $this->processColRef($v);
227
			$sql .= $this->processPosition($v);
228
			$sql .= $this->processFunction($v);
229
			$sql .= $this->processGroupByAlias($v);
230
			$sql .= $this->processGroupByExpression($v);
231
232
			if ($len == strlen($sql)) {
233
				throw new RDatabaseSqlparserExceptioncreatesql('GROUP', $k, $v, 'expr_type');
234
			}
235
236
			$sql .= ",";
237
		}
238
		$sql = substr($sql, 0, -1);
239
		return "GROUP BY " . $sql;
240
	}
241
242
	protected function processGroupByAlias($parsed) {
243
		if ($parsed['expr_type'] !== 'alias') {
244
			return "";
245
		}
246
		return $parsed['base_expr'];
247
	}
248
249
	protected function processPosition($parsed) {
250
		if ($parsed['expr_type'] !== 'pos') {
251
			return "";
252
		}
253
		return $parsed['base_expr'];
254
	}
255
256
	protected function processRecord($parsed) {
257
		if ($parsed['expr_type'] !== 'record') {
258
			return "";
259
		}
260
		$sql = "";
261
		foreach ($parsed['data'] as $k => $v) {
262
			$len = strlen($sql);
263
			$sql .= $this->processConstant($v);
264
			$sql .= $this->processFunction($v);
265
			$sql .= $this->processOperator($v);
266
267
			if ($len == strlen($sql)) {
268
				throw new RDatabaseSqlparserExceptioncreatesql('record', $k, $v, 'expr_type');
269
			}
270
271
			$sql .= ",";
272
		}
273
		$sql = substr($sql, 0, -1);
274
		return "(" . $sql . ")";
275
276
	}
277
278
	protected function processVALUES($parsed) {
279
		$sql = "";
280
		foreach ($parsed as $k => $v) {
281
			$len = strlen($sql);
282
			$sql .= $this->processRecord($v);
283
284
			if ($len == strlen($sql)) {
285
				throw new RDatabaseSqlparserExceptioncreatesql('VALUES', $k, $v, 'expr_type');
286
			}
287
288
			$sql .= ",";
289
		}
290
		$sql = substr($sql, 0, -1);
291
		return "VALUES " . $sql;
292
	}
293
294
	protected function processINSERT($parsed) {
295
		$sql = "INSERT INTO " . $parsed['table'];
296
297
		if ($parsed['columns'] === false) {
298
			return $sql;
299
		}
300
301
		$columns = "";
302
		foreach ($parsed['columns'] as $k => $v) {
303
			$len = strlen($columns);
304
			$columns .= $this->processColRef($v);
305
306
			if ($len == strlen($columns)) {
307
				throw new RDatabaseSqlparserExceptioncreatesql('INSERT[columns]', $k, $v, 'expr_type');
308
			}
309
310
			$columns .= ",";
311
		}
312
313
		if ($columns !== "") {
314
			$columns = " (" . substr($columns, 0, -1) . ")";
315
		}
316
317
		$sql .= $columns;
318
		return $sql;
319
	}
320
321
	protected function processUPDATE($parsed) {
322
		return "UPDATE " . $parsed[0]['table'];
323
	}
324
325
	protected function processSetExpression($parsed) {
326
		if ($parsed['expr_type'] !== 'expression') {
327
			return "";
328
		}
329
		$sql = "";
330
		foreach ($parsed['sub_tree'] as $k => $v) {
331
			$len = strlen($sql);
332
			if (($this->isReserved($v) || $this->isOperator($v)) && !empty($sql) && substr($sql, -1) == ',')
333
			{
334
				$sql = substr($sql, 0, -1) . ' ';
335
			}
336
337
			$sql .= $this->processReserved($v);
338
			$sql .= $this->processColRef($v);
339
			$sql .= $this->processConstant($v);
340
			$sql .= $this->processOperator($v);
341
			$sql .= $this->processFunction($v);
342
343
			if ($len == strlen($sql)) {
344
				throw new RDatabaseSqlparserExceptioncreatesql('SET expression subtree', $k, $v, 'expr_type');
345
			}
346
347
			$sql .= " ";
348
		}
349
350
		$sql = substr($sql, 0, -1);
351
		return $sql;
352
	}
353
354
	protected function processSET($parsed) {
355
		$sql = "";
356
		foreach ($parsed as $k => $v) {
357
			$len = strlen($sql);
358
			$sql .= $this->processSetExpression($v);
359
360
			if ($len == strlen($sql)) {
361
				throw new RDatabaseSqlparserExceptioncreatesql('SET', $k, $v, 'expr_type');
362
			}
363
364
			$sql .= ",";
365
		}
366
		return "SET " . substr($sql, 0, -1);
367
	}
368
369
	protected function processWHERE($parsed) {
370
		$sql = "WHERE ";
371
		foreach ($parsed as $k => $v) {
372
			$len = strlen($sql);
373
374
			if (($this->isReserved($v) || $this->isOperator($v)) && !empty($sql) && substr($sql, -1) == ',')
375
			{
376
				$sql = substr($sql, 0, -1) . ' ';
377
			}
378
379
			$sql .= $this->processReserved($v);
380
			$sql .= $this->processOperator($v);
381
			$sql .= $this->processConstant($v);
382
			$sql .= $this->processColRef($v);
383
			$sql .= $this->processSubQuery($v);
384
			$sql .= $this->processInList($v);
385
			$sql .= $this->processFunction($v);
386
			$sql .= $this->processWhereExpression($v);
387
			$sql .= $this->processWhereBracketExpression($v);
388
389
			if (strlen($sql) == $len) {
390
				throw new RDatabaseSqlparserExceptioncreatesql('WHERE', $k, $v, 'expr_type');
391
			}
392
393
			$sql .= " ";
394
		}
395
		return substr($sql, 0, -1);
396
	}
397
398
	protected function processWhereExpression($parsed) {
399
		if (empty($parsed['expr_type']) || $parsed['expr_type'] !== 'expression') {
400
			return "";
401
		}
402
		$sql = "";
403
		foreach ($parsed['sub_tree'] as $k => $v) {
404
			$len = strlen($sql);
405
			if (($this->isReserved($v) || $this->isOperator($v)) && !empty($sql) && substr($sql, -1) == ',')
406
			{
407
				$sql = substr($sql, 0, -1) . ' ';
408
			}
409
410
			$sql .= $this->processReserved($v);
411
			$sql .= $this->processColRef($v);
412
			$sql .= $this->processConstant($v);
413
			$sql .= $this->processOperator($v);
414
			$sql .= $this->processInList($v);
415
			$sql .= $this->processFunction($v);
416
			$sql .= $this->processWhereExpression($v);
417
			$sql .= $this->processWhereBracketExpression($v);
418
			$sql .= $this->processSubQuery($v);
419
420
			if ($len == strlen($sql)) {
421
				throw new RDatabaseSqlparserExceptioncreatesql('WHERE expression subtree', $k, $v, 'expr_type');
422
			}
423
424
			$sql .= " ";
425
		}
426
427
		$sql = substr($sql, 0, -1);
428
		return $sql;
429
	}
430
431
	protected function processWhereBracketExpression($parsed) {
432
		if (empty($parsed['expr_type']) || $parsed['expr_type'] !== 'bracket_expression') {
433
			return "";
434
		}
435
		elseif (empty($parsed['sub_tree']))
436
		{
437
			return "()";
438
		}
439
		$sql = "";
440
		foreach ($parsed['sub_tree'] as $k => $v) {
441
			$len = strlen($sql);
442
			if (($this->isReserved($v) || $this->isOperator($v)) && !empty($sql) && substr($sql, -1) == ',')
443
			{
444
				$sql = substr($sql, 0, -1) . ' ';
445
			}
446
447
			$sql .= $this->processReserved($v);
448
			$sql .= $this->processColRef($v);
449
			$sql .= $this->processConstant($v);
450
			$sql .= $this->processOperator($v);
451
			$sql .= $this->processInList($v);
452
			$sql .= $this->processFunction($v);
453
			$sql .= $this->processWhereExpression($v);
454
			$sql .= $this->processWhereBracketExpression($v);
455
			$sql .= $this->processSubQuery($v);
456
457
			if ($len == strlen($sql)) {
458
				throw new RDatabaseSqlparserExceptioncreatesql('WHERE expression subtree', $k, $v, 'expr_type');
459
			}
460
461
			$sql .= " ";
462
		}
463
464
		$sql = "(" . substr($sql, 0, -1) . ")";
465
		return $sql;
466
	}
467
468
	protected function processOrderByAlias($parsed) {
469
		if ($parsed['expr_type'] !== 'alias') {
470
			return "";
471
		}
472
		return $parsed['base_expr'] . $this->processDirection($parsed['direction']);
473
	}
474
475
	protected function processLimitRowCount($key, $value) {
476
		if ($key != 'rowcount') {
477
			return "";
478
		}
479
		return $value;
480
	}
481
482
	protected function processLimitOffset($key, $value) {
483
		if ($key !== 'offset') {
484
			return "";
485
		}
486
		return $value;
487
	}
488
489
	protected function processFunction($parsed) {
490
		if (empty($parsed['expr_type']) || (($parsed['expr_type'] !== 'aggregate_function') && ($parsed['expr_type'] !== 'function'))) {
491
			return "";
492
		}
493
494
		if ($parsed['sub_tree'] === false) {
495
			return $parsed['base_expr'] . "()";
496
		}
497
498
		$sql = "";
499
500
		foreach ($parsed['sub_tree'] as $k => $v) {
501
			$len = strlen($sql);
502
503
			if (($this->isReserved($v) || $this->isOperator($v)) && !empty($sql) && substr($sql, -1) == ',')
504
			{
505
				$sql = substr($sql, 0, -1) . ' ';
506
			}
507
508
			$sql .= (!empty($this->processReserved($v))) ? ',' . $this->processReserved($v) : $this->processReserved($v);
509
			$sql .= $this->processFunction($v);
510
			$sql .= $this->processConstant($v);
511
			$sql .= $this->processOperator($v);
512
			$sql .= $this->processColRef($v);
513
			$sql .= $this->processInList($v);
514
			$sql .= $this->processSelectBracketExpression($v);
515
			$sql .= $this->processSelectExpression($v);
516
			$sql .= $this->processSubQuery($v);
517
518
			if ($len == strlen($sql)) {
519
				throw new RDatabaseSqlparserExceptioncreatesql('function subtree', $k, $v, 'expr_type');
520
			}
521
522
			$sql .= ($this->isReserved($v) || $this->isOperator($v) ? " " : ",");
523
		}
524
525
		$sql2 = $parsed['base_expr'] . "(" . substr($sql, 0, -1) . ")";
526
		$sql2 .= !empty($parsed['alias']) ? $this->processAlias($parsed['alias']) : '';
527
528
		return $sql2;
529
	}
530
531
	protected function processSelectExpression($parsed) {
532
		if ($parsed['expr_type'] !== 'expression') {
533
			return "";
534
		}
535
		$sql = $this->processSubTree($parsed, " ");
536
		$sql .= $this->processAlias($parsed['alias']);
537
		return $sql;
538
	}
539
540
	protected function processGroupByExpression($parsed) {
541
		if ($parsed['expr_type'] !== 'expression') {
542
			return "";
543
		}
544
		$sql = $this->processSubTree($parsed, " ");
545
		return $sql;
546
	}
547
548
	protected function processOrderByExpression($parsed) {
549
		if ($parsed['expr_type'] !== '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->processSign($v);
595
			$sql .= $this->processSelectBracketExpression($v);
596
			$sql .= $this->processSelectExpression($v);
597
			$sql .= $this->processSubQuery($v);
598
599
			// Always last since it will give alias if needed
600
			$sql .= $this->processColRef($v);
601
602
			if ($len == strlen($sql)) {
603
				throw new RDatabaseSqlparserExceptioncreatesql('expression subtree', $k, $v, 'expr_type');
604
			}
605
606
			$sql .= ($this->isReserved($v) || $this->isOperator($v) ? " " : $delim);
607
		}
608
609
		$sql = substr($sql, 0, -1);
610
611
		return $sql;
612
	}
613
614
	protected function processSign($parsed) {
615
		if (empty($parsed['expr_type']) || $parsed['expr_type'] === 'sign') {
616
			return $parsed['base_expr'];
617
		}
618
	}
619
620
	protected function processRefClause($parsed) {
621
		if ($parsed === false) {
622
			return "";
623
		}
624
625
		$sql = "";
626
		foreach ($parsed as $k => $v) {
627
			$len = strlen($sql);
628
629
			if (($this->isReserved($v) || $this->isOperator($v)) && !empty($sql) && substr($sql, -1) == ',')
630
			{
631
				$sql = substr($sql, 0, -1) . ' ';
632
			}
633
634
			$sql .= $this->processReserved($v);
635
			$sql .= $this->processColRef($v);
636
			$sql .= $this->processFunction($v);
637
			$sql .= $this->processOperator($v);
638
			$sql .= $this->processInList($v);
639
			$sql .= $this->processConstant($v);
640
			$sql .= $this->processSelectBracketExpression($v);
641
			$sql .= $this->processSelectExpression($v);
642
			$sql .= $this->processSubQuery($v);
643
644
			if ($len == strlen($sql)) {
645
				throw new RDatabaseSqlparserExceptioncreatesql('expression ref_clause', $k, $v, 'expr_type');
646
			}
647
648
			$sql .= " ";
649
		}
650
		return "(" . substr($sql, 0, -1) . ")";
651
	}
652
653
	protected function processAlias($parsed) {
654
		if ($parsed === false) {
655
			return "";
656
		}
657
		$sql = "";
658
		if (!empty($parsed['as'])) {
659
			$sql .= " as";
660
		}
661
		if (!empty($parsed['name'])) {
662
		$sql .= " " . $parsed['name'];
663
		}
664
665
		return $sql;
666
	}
667
668
	protected function processJoin($parsed) {
669
		if ($parsed === 'CROSS') {
670
			return ",";
671
		}
672
		if ($parsed === 'JOIN') {
673
			return "INNER JOIN";
674
		}
675
		if ($parsed === 'LEFT') {
676
			return "LEFT JOIN";
677
		}
678
		if ($parsed === 'RIGHT') {
679
			return "RIGHT JOIN";
680
		}
681
		// TODO: add more
682
		throw new Exception($parsed, 20);
683
	}
684
685
	protected function processRefType($parsed) {
686
		if ($parsed === false) {
687
			return "";
688
		}
689
		if ($parsed === 'ON') {
690
			return " ON ";
691
		}
692
		if ($parsed === 'USING') {
693
			return " USING ";
694
		}
695
		// TODO: add more
696
		throw new Exception($parsed, 20);
697
	}
698
699
	protected function processTable($parsed, $index) {
700
		if ($parsed['expr_type'] !== 'table') {
701
			return "";
702
		}
703
704
		$sql = $parsed['table'];
705
		$sql .= $this->processAlias($parsed['alias']);
706
707
		if ($index !== 0) {
708
			$sql = $this->processJoin($parsed['join_type']) . " " . $sql;
709
			$sql .= $this->processRefType($parsed['ref_type']);
710
			$sql .= $this->processRefClause($parsed['ref_clause']);
711
		}
712
		return $sql;
713
	}
714
715
	protected function processTableExpression($parsed, $index) {
716
		if ($parsed['expr_type'] !== 'table_expression') {
717
			return "";
718
		}
719
		$sql = substr($this->processFROM($parsed['sub_tree']), 5); // remove FROM keyword
720
		$sql = "(" . $sql . ")";
721
722
		if (isset($parsed['alias'])) {
723
			$sql .= $this->processAlias($parsed['alias']);
724
		}
725
726
		if ($index !== 0) {
727
			$sql = $this->processJoin($parsed['join_type']) . " " . $sql;
728
			$sql .= $this->processRefType($parsed['ref_type']);
729
			$sql .= $this->processRefClause($parsed['ref_clause']);
730
		}
731
		return $sql;
732
	}
733
734
	protected function processSubQuery($parsed, $index = 0)
735
	{
736
		if ($parsed['expr_type'] !== 'subquery')
737
		{
738
			return "";
739
		}
740
741
		// We handle subqueries in a loop in sqltranslation file
742
		$sql = $parsed['base_expr'];
743
		$sql = "(" . $sql . ")";
744
745
		if (isset($parsed['alias']))
746
		{
747
			$sql .= $this->processAlias($parsed['alias']);
748
		}
749
750
		if ($index !== 0)
751
		{
752
			$sql = $this->processJoin($parsed['join_type']) . " " . $sql;
753
			$sql .= $this->processRefType($parsed['ref_type']);
754
			$sql .= $this->processRefClause($parsed['ref_clause']);
755
		}
756
757
		return $sql;
758
	}
759
760
	protected function processOperator($parsed) {
761
		if (empty($parsed['expr_type']) || $parsed['expr_type'] !== 'operator') {
762
			return "";
763
		}
764
		return $parsed['base_expr'];
765
	}
766
767
	protected function processColRef($parsed) {
768
		if (empty($parsed['expr_type']) || $parsed['expr_type'] !== 'colref') {
769
			return "";
770
		}
771
		$sql = $parsed['base_expr'];
772
		if (isset($parsed['alias'])) {
773
			$sql .= $this->processAlias($parsed['alias']);
774
		}
775
		if (isset($parsed['direction'])) {
776
			$sql .= $this->processDirection($parsed['direction']);
777
		}
778
		return $sql;
779
	}
780
781
	protected function processDirection($parsed) {
782
		$sql = ($parsed ? " " . $parsed : "");
783
		return $sql;
784
	}
785
786
	protected function processReserved($parsed)
787
	{
788
		if (!$this->isReserved($parsed))
789
		{
790
			return "";
791
		}
792
793
		$sql = $parsed['base_expr'];
794
795
		if (isset($parsed['alias']))
796
		{
797
			$sql .= $this->processAlias($parsed['alias']);
798
		}
799
800
		return $sql;
801
	}
802
803
	protected function isReserved($parsed) {
804
		return (!empty($parsed['expr_type']) && $parsed['expr_type'] === 'reserved');
805
	}
806
807
	protected function isOperator($parsed) {
808
		return (!empty($parsed['expr_type']) && $parsed['expr_type'] === 'operator');
809
	}
810
811
	protected function processConstant($parsed) {
812
		if (empty($parsed['expr_type']) || $parsed['expr_type'] !== 'const') {
813
			return "";
814
		}
815
816
		$sql = $parsed['base_expr'];
817
818
		if (isset($parsed['alias'])) {
819
			$sql .= $this->processAlias($parsed['alias']);
820
		}
821
822
		return $sql;
823
	}
824
825
	protected function processUserVariable($parsed)
826
	{
827
		if (empty($parsed['expr_type']) || $parsed['expr_type'] !== 'user_variable')
828
		{
829
			return "";
830
		}
831
832
		$sql = $parsed['base_expr'];
833
834
		if (isset($parsed['alias']))
835
		{
836
			$sql .= $this->processAlias($parsed['alias']);
837
		}
838
839
		return $sql;
840
	}
841
842
	protected function processInList($parsed) {
843
		if (empty($parsed['expr_type']) || $parsed['expr_type'] !== 'in-list') {
844
			return "";
845
		}
846
		$sql = $this->processSubTree($parsed, ",");
847
		return "(" . $sql . ")";
848
	}
849
850
}
851