Passed
Pull Request — develop (#879)
by Luis
12:38
created

RDatabaseSqlparserSqlcreator   F

Complexity

Total Complexity 196

Size/Duplication

Total Lines 791
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 196
eloc 427
c 2
b 0
f 0
dl 0
loc 791
rs 2

49 Methods

Rating   Name   Duplication   Size   Complexity  
A isOperator() 0 2 2
A processVALUES() 0 14 3
A processInsertStatement() 0 2 1
A processGroupByExpression() 0 6 2
A processFROM() 0 17 3
C processFunction() 0 40 15
A processColRef() 0 12 5
A processUPDATE() 0 2 1
A processINSERT() 0 25 5
B processWHERE() 0 27 7
A processDeleteStatement() 0 3 1
A processRefType() 0 12 4
A processGroupByAlias() 0 5 2
A processOperator() 0 5 3
A processIndexHints() 0 13 4
A processORDER() 0 18 3
A processSelectStatement() 0 17 5
A processDirection() 0 3 2
A processTable() 0 14 3
A processLimitRowCount() 0 5 2
A processOrderByExpression() 0 7 2
A processLIMIT() 0 7 4
A processAlias() 0 13 4
A processSelectExpression() 0 7 2
B processWhereExpression() 0 31 9
B processSubTree() 0 35 10
A processLimitOffset() 0 5 2
A processTableExpression() 0 17 4
A isReserved() 0 2 2
A processGROUP() 0 18 3
A processUserVariable() 0 15 4
A processOrderByAlias() 0 5 2
A processSubQuery() 0 24 4
A processReserved() 0 15 3
A processSELECT() 0 25 3
B processRefClause() 0 31 8
A __construct() 0 3 2
B processWhereBracketExpression() 0 35 10
A processInList() 0 6 3
A processPosition() 0 5 2
B create() 0 25 7
B processSetExpression() 0 27 8
A processSET() 0 13 3
A processRecord() 0 19 4
A processConstant() 0 12 4
A processUpdateStatement() 0 6 2
A processJoin() 0 15 5
A processDELETE() 0 6 2
A processSelectBracketExpression() 0 17 5

How to fix   Complexity   

Complex Class

Complex classes like RDatabaseSqlparserSqlcreator often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use RDatabaseSqlparserSqlcreator, and based on these observations, apply Extract Interface, too.

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