diff options
| author | RamonWill <ramonwilliams@hotmail.co.uk> | 2020-08-24 20:17:19 -0400 |
|---|---|---|
| committer | Federico Caselli <cfederico87@gmail.com> | 2022-08-11 21:39:45 +0200 |
| commit | a134ec1760df6295d537ff63df7aee83d957bf6a (patch) | |
| tree | 2c69701259576dfa58e4ebe742f7272f66f0cfc5 /lib/sqlalchemy/dialects/mysql/reflection.py | |
| parent | 6f75807063771496a34b7725d2565acf2528d76f (diff) | |
| download | sqlalchemy-a134ec1760df6295d537ff63df7aee83d957bf6a.tar.gz | |
Add support for Partitioning and Sample pages on mysql
Add support for Partitioning and Sample pages on MySQL and MariaDB
reflected options.
The options are stored in the table dialect options dictionary, so
the following keyword need to be prefixed with ``mysql_`` or ``mariadb_``
depending on the backend.
Supported options are:
* ``stats_sample_pages``
* ``partition_by``
* ``partitions``
* ``subpartition_by``
These options are also reflected when loading a table from database,
and will populate the table :attr:`_schema.Table.dialect_options`.
Pull request courtesy of Ramon Will.
Fixes: #4038
Closes: #5536
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/5536
Pull-request-sha: f8852cabe15c9a91de85d27980988051f7a1306d
Change-Id: I69b60576532af04c725c998e9e8fec6e2040b149
Diffstat (limited to 'lib/sqlalchemy/dialects/mysql/reflection.py')
| -rw-r--r-- | lib/sqlalchemy/dialects/mysql/reflection.py | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/lib/sqlalchemy/dialects/mysql/reflection.py b/lib/sqlalchemy/dialects/mysql/reflection.py index 2ce8473d0..e7a6b157f 100644 --- a/lib/sqlalchemy/dialects/mysql/reflection.py +++ b/lib/sqlalchemy/dialects/mysql/reflection.py @@ -54,6 +54,8 @@ class MySQLTableDefinitionParser: pass elif line.startswith("CREATE "): self._parse_table_name(line, state) + elif "PARTITION" in line: + self._parse_partition_options(line, state) # Not present in real reflection, but may be if # loading from a file. elif not line: @@ -162,6 +164,62 @@ class MySQLTableDefinitionParser: for opt, val in options.items(): state.table_options["%s_%s" % (self.dialect.name, opt)] = val + def _parse_partition_options(self, line, state): + options = {} + new_line = line[:] + + while new_line.startswith("(") or new_line.startswith(" "): + new_line = new_line[1:] + + for regex, cleanup in self._pr_options: + m = regex.search(new_line) + if not m or "PARTITION" not in regex.pattern: + continue + + directive = m.group("directive") + directive = directive.lower() + is_subpartition = directive == "subpartition" + + if directive == "partition" or is_subpartition: + new_line = new_line.replace(") */", "") + new_line = new_line.replace(",", "") + if is_subpartition and new_line.endswith(")"): + new_line = new_line[:-1] + if self.dialect.name == "mariadb" and new_line.endswith(")"): + if ( + "MAXVALUE" in new_line + or "MINVALUE" in new_line + or "ENGINE" in new_line + ): + # final line of MariaDB partition endswith ")" + new_line = new_line[:-1] + + defs = "%s_%s_definitions" % (self.dialect.name, directive) + options[defs] = new_line + + else: + directive = directive.replace(" ", "_") + value = m.group("val") + if cleanup: + value = cleanup(value) + options[directive] = value + break + + for opt, val in options.items(): + part_def = "%s_partition_definitions" % (self.dialect.name) + subpart_def = "%s_subpartition_definitions" % (self.dialect.name) + if opt == part_def or opt == subpart_def: + # builds a string of definitions + if opt not in state.table_options: + state.table_options[opt] = val + else: + state.table_options[opt] = "%s, %s" % ( + state.table_options[opt], + val, + ) + else: + state.table_options["%s_%s" % (self.dialect.name, opt)] = val + def _parse_column(self, line, state): """Extract column details. @@ -489,9 +547,20 @@ class MySQLTableDefinitionParser: "PACK_KEYS", "ROW_FORMAT", "KEY_BLOCK_SIZE", + "STATS_SAMPLE_PAGES", ): self._add_option_word(option) + for option in ( + "PARTITION BY", + "SUBPARTITION BY", + "PARTITIONS", + "SUBPARTITIONS", + "PARTITION", + "SUBPARTITION", + ): + self._add_partition_option_word(option) + self._add_option_regex("UNION", r"\([^\)]+\)") self._add_option_regex("TABLESPACE", r".*? STORAGE DISK") self._add_option_regex( @@ -519,6 +588,21 @@ class MySQLTableDefinitionParser: ) self._pr_options.append(_pr_compile(regex)) + def _add_partition_option_word(self, directive): + if directive == "PARTITION BY" or directive == "SUBPARTITION BY": + regex = r"(?<!\S)(?P<directive>%s)%s" r"(?P<val>\w+.*)" % ( + re.escape(directive), + self._optional_equals, + ) + elif directive == "SUBPARTITIONS" or directive == "PARTITIONS": + regex = r"(?<!\S)(?P<directive>%s)%s" r"(?P<val>\d+)" % ( + re.escape(directive), + self._optional_equals, + ) + else: + regex = r"(?<!\S)(?P<directive>%s)(?!\S)" % (re.escape(directive),) + self._pr_options.append(_pr_compile(regex)) + def _add_option_regex(self, directive, regex): regex = r"(?P<directive>%s)%s" r"(?P<val>%s)" % ( re.escape(directive), |
