Skip to content

Commit 7242100

Browse files
committed
Initial support for partitions.
1 parent 09a7047 commit 7242100

7 files changed

Lines changed: 135 additions & 18 deletions

File tree

src/Components/ArrayObj.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ public function __construct(array $raw = array(), array $values = array())
5656
* @param TokensList $list The list of tokens that are being parsed.
5757
* @param array $options Parameters for parsing.
5858
*
59-
* @return ArrayObj
59+
* @return mixed
6060
*/
6161
public static function parse(Parser $parser, TokensList $list, array $options = array())
6262
{
63-
$ret = new ArrayObj();
63+
$ret = empty($options['type']) ? new ArrayObj() : array();
6464

6565
/**
6666
* The state of the parser.
@@ -109,8 +109,12 @@ public static function parse(Parser $parser, TokensList $list, array $options =
109109
// Empty array.
110110
break;
111111
}
112-
$ret->values[] = $token->value;
113-
$ret->raw[] = $token->token;
112+
if (empty($options['type'])) {
113+
$ret->values[] = $token->value;
114+
$ret->raw[] = $token->token;
115+
} else {
116+
$ret[] = $options['type']::parse($parser, $list);
117+
}
114118
$state = 2;
115119
} elseif ($state === 2) {
116120
if (($token->type !== Token::TYPE_OPERATOR) || (($token->value !== ',') && ($token->value !== ')'))) {

src/Contexts/ContextMySql50000.php

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,16 @@ class ContextMySql50000 extends Context
7777
'VARIABLES' => 1,
7878
'BERKELEYDB' => 1, 'COMPRESSED' => 1, 'CONCURRENT' => 1, 'CONNECTION' => 1,
7979
'CONSISTENT' => 1, 'DEALLOCATE' => 1, 'IDENTIFIED' => 1, 'MASTER_SSL' => 1,
80-
'NDBCLUSTER' => 1, 'PERSISTENT' => 1, 'PRIVILEGES' => 1, 'REPEATABLE' => 1,
81-
'ROW_FORMAT' => 1, 'SQL_THREAD' => 1, 'TABLESPACE' => 1,
80+
'NDBCLUSTER' => 1, 'PARTITIONS' => 1, 'PERSISTENT' => 1, 'PRIVILEGES' => 1,
81+
'REPEATABLE' => 1, 'ROW_FORMAT' => 1, 'SQL_THREAD' => 1, 'TABLESPACE' => 1,
8282
'FRAC_SECOND' => 1, 'MASTER_HOST' => 1, 'MASTER_PORT' => 1, 'MASTER_USER' => 1,
8383
'PROCESSLIST' => 1, 'RAID_CHUNKS' => 1, 'REPLICATION' => 1, 'SQL_TSI_DAY' => 1,
8484
'TRANSACTION' => 1, 'UNCOMMITTED' => 1,
8585
'DES_KEY_FILE' => 1, 'RELAY_THREAD' => 1, 'SERIALIZABLE' => 1,
8686
'SQL_NO_CACHE' => 1, 'SQL_TSI_HOUR' => 1, 'SQL_TSI_WEEK' => 1,
8787
'SQL_TSI_YEAR' => 1,
8888
'INSERT_METHOD' => 1, 'MASTER_SSL_CA' => 1, 'RELAY_LOG_POS' => 1,
89-
'SQL_TSI_MONTH' => 1,
89+
'SQL_TSI_MONTH' => 1, 'SUBPARTITIONS' => 1,
9090
'AUTO_INCREMENT' => 1, 'AVG_ROW_LENGTH' => 1, 'MASTER_LOG_POS' => 1,
9191
'MASTER_SSL_KEY' => 1, 'RAID_CHUNKSIZE' => 1, 'RELAY_LOG_FILE' => 1,
9292
'SQL_TSI_MINUTE' => 1, 'SQL_TSI_SECOND' => 1, 'USER_RESOURCES' => 1,
@@ -145,12 +145,14 @@ class ContextMySql50000 extends Context
145145

146146
'GROUP BY' => 7, 'NOT NULL' => 7, 'ORDER BY' => 7, 'SET NULL' => 7,
147147
'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7,
148-
'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
148+
'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
149149
'INNER JOIN' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
150-
'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'SQL SECURITY' => 7,
150+
'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'PARTITION BY' => 7,
151+
'SQL SECURITY' => 7,
151152
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
152153
'DATA DIRECTORY' => 7,
153154
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'INDEX DIRECTORY' => 7,
155+
'SUBPARTITION BY' => 7,
154156
'GENERATED ALWAYS' => 7,
155157
'START TRANSACTION' => 7,
156158
'SELECT TRANSACTION' => 7,

src/Contexts/ContextMySql50100.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,12 +157,14 @@ class ContextMySql50100 extends Context
157157

158158
'GROUP BY' => 7, 'NOT NULL' => 7, 'ORDER BY' => 7, 'SET NULL' => 7,
159159
'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7,
160-
'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
160+
'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
161161
'INNER JOIN' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
162-
'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'SQL SECURITY' => 7,
162+
'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'PARTITION BY' => 7,
163+
'SQL SECURITY' => 7,
163164
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
164165
'DATA DIRECTORY' => 7,
165166
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'INDEX DIRECTORY' => 7,
167+
'SUBPARTITION BY' => 7,
166168
'GENERATED ALWAYS' => 7,
167169
'START TRANSACTION' => 7,
168170
'SELECT TRANSACTION' => 7,

src/Contexts/ContextMySql50500.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,12 +162,14 @@ class ContextMySql50500 extends Context
162162

163163
'GROUP BY' => 7, 'NOT NULL' => 7, 'ORDER BY' => 7, 'SET NULL' => 7,
164164
'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7,
165-
'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
165+
'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
166166
'INNER JOIN' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
167-
'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'SQL SECURITY' => 7,
167+
'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'PARTITION BY' => 7,
168+
'SQL SECURITY' => 7,
168169
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
169170
'DATA DIRECTORY' => 7,
170171
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'INDEX DIRECTORY' => 7,
172+
'SUBPARTITION BY' => 7,
171173
'GENERATED ALWAYS' => 7,
172174
'START TRANSACTION' => 7,
173175
'SELECT TRANSACTION' => 7,

src/Contexts/ContextMySql50600.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,12 +167,14 @@ class ContextMySql50600 extends Context
167167

168168
'GROUP BY' => 7, 'NOT NULL' => 7, 'ORDER BY' => 7, 'SET NULL' => 7,
169169
'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7,
170-
'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
170+
'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
171171
'INNER JOIN' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
172-
'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'SQL SECURITY' => 7,
172+
'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'PARTITION BY' => 7,
173+
'SQL SECURITY' => 7,
173174
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
174175
'DATA DIRECTORY' => 7,
175176
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'INDEX DIRECTORY' => 7,
177+
'SUBPARTITION BY' => 7,
176178
'GENERATED ALWAYS' => 7,
177179
'START TRANSACTION' => 7,
178180
'SELECT TRANSACTION' => 7,

src/Contexts/ContextMySql50700.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,14 @@ class ContextMySql50700 extends Context
175175

176176
'GROUP BY' => 7, 'NOT NULL' => 7, 'ORDER BY' => 7, 'SET NULL' => 7,
177177
'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7,
178-
'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
178+
'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7,
179179
'INNER JOIN' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7,
180-
'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'SQL SECURITY' => 7,
180+
'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'PARTITION BY' => 7,
181+
'SQL SECURITY' => 7,
181182
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
182183
'DATA DIRECTORY' => 7,
183184
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'INDEX DIRECTORY' => 7,
185+
'SUBPARTITION BY' => 7,
184186
'GENERATED ALWAYS' => 7,
185187
'START TRANSACTION' => 7,
186188
'SELECT TRANSACTION' => 7,

src/Statements/CreateStatement.php

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,11 +229,27 @@ public function build()
229229
. Expression::build($this->name) . ' '
230230
. OptionsArray::build($this->entityOptions);
231231
} elseif ($this->options->has('TABLE')) {
232+
$partition = '';
233+
234+
if (!empty($this->partitionBy)) {
235+
$partition .= ' PARTITION BY ' . $this->partitionBy;
236+
}
237+
if (!empty($this->partitionsNum)) {
238+
$partition .= ' PARTITIONS ' . $this->partitionsNum;
239+
}
240+
if (!empty($this->subpartitionBy)) {
241+
$partition .= ' SUBPARTITION BY ' . $this->subpartitionBy;
242+
}
243+
if (!empty($this->subpartitionsNum)) {
244+
$partition .= ' SUBPARTITIONS ' . $this->subpartitionsNum;
245+
}
246+
232247
return 'CREATE '
233248
. OptionsArray::build($this->options) . ' '
234249
. Expression::build($this->name) . ' '
235250
. $fields
236-
. OptionsArray::build($this->entityOptions);
251+
. OptionsArray::build($this->entityOptions)
252+
. $partition;
237253
} elseif ($this->options->has('VIEW')) {
238254
return 'CREATE '
239255
. OptionsArray::build($this->options) . ' '
@@ -318,6 +334,93 @@ public function parse(Parser $parser, TokensList $list)
318334
$list,
319335
static::$TABLE_OPTIONS
320336
);
337+
338+
/**
339+
* The field that is being filled (`partitionBy` or
340+
* `subpartitionBy`).
341+
*
342+
* @var string $field
343+
*/
344+
$field = null;
345+
346+
/**
347+
* The number of brackets. `false` means no bracket was found
348+
* previously. At least one bracket is required to validate the
349+
* expression.
350+
*
351+
* @var int|bool
352+
*/
353+
$brackets = false;
354+
355+
/*
356+
* Handles partitions.
357+
*/
358+
for (; $list->idx < $list->count; ++$list->idx) {
359+
360+
/**
361+
* Token parsed at this moment.
362+
* @var Token $token
363+
*/
364+
$token = $list->tokens[$list->idx];
365+
366+
// End of statement.
367+
if ($token->type === Token::TYPE_DELIMITER) {
368+
break;
369+
}
370+
371+
// Skipping comments.
372+
if ($token->type === Token::TYPE_COMMENT) {
373+
continue;
374+
}
375+
376+
if (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'PARTITION BY')) {
377+
$field = 'partitionBy';
378+
$brackets = false;
379+
} elseif (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'SUBPARTITION BY')) {
380+
$field = 'subpartitionBy';
381+
$brackets = false;
382+
} elseif (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'PARTITIONS')) {
383+
$token = $list->getNextOfType(Token::TYPE_NUMBER);
384+
$this->partitionsNum = $token->value;
385+
} elseif (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'SUBPARTITIONS')) {
386+
$token = $list->getNextOfType(Token::TYPE_NUMBER);
387+
$this->subpartitionsNum = $token->value;
388+
} elseif (!empty($field)) {
389+
390+
/*
391+
* Handling the content of `PARTITION BY` and `SUBPARTITION BY`.
392+
*/
393+
394+
// Counting brackets.
395+
if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
396+
// This is used instead of `++$brackets` because,
397+
// initially, `$brackets` is `false` cannot be
398+
// incremented.
399+
$brackets = $brackets + 1;
400+
} elseif (($token->type === Token::TYPE_OPERATOR) && ($token->value === ')')) {
401+
--$brackets;
402+
}
403+
404+
// Building the expression used for partitioning.
405+
$this->$field .= ($token->type === Token::TYPE_WHITESPACE) ? ' ' : $token->token;
406+
407+
// Last bracket was read, the expression ended.
408+
// Comparing with `0` and not `false`, because `false` means
409+
// that no bracket was found and at least one must is
410+
// required.
411+
if ($brackets === 0) {
412+
$this->$field = trim($this->$field);
413+
$field = null;
414+
}
415+
} elseif (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
416+
$this->partitions = ArrayObj::parse(
417+
$parser,
418+
$list,
419+
array('type' => 'SqlParser\Components\PartitionDefinition')
420+
);
421+
break;
422+
}
423+
}
321424
} elseif (($this->options->has('PROCEDURE'))
322425
|| ($this->options->has('FUNCTION'))
323426
) {

0 commit comments

Comments
 (0)