summaryrefslogtreecommitdiff
path: root/oslo_db/sqlalchemy/ndb.py
blob: 42b3189b4759dbfc4cd13c5e004f27253d37b3bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.
"""Core functions for MySQL Cluster (NDB) Support."""

import re

import debtcollector.removals
from sqlalchemy import event, schema
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.types import String as _String
from sqlalchemy.types import to_instance

from oslo_db.sqlalchemy.types import String


engine_regex = re.compile("engine=innodb", re.IGNORECASE)
trans_regex = re.compile("savepoint|rollback|release savepoint", re.IGNORECASE)


@debtcollector.removals.remove(
    message=(
        'Support for the MySQL NDB Cluster storage engine has been deprecated '
        'and will be removed in a future release.'
    ),
    version='12.1.0',
)
def enable_ndb_support(engine):
    """Enable NDB Support.

    Function to flag the MySQL engine dialect to support features specific
    to MySQL Cluster (NDB).
    """
    engine.dialect._oslodb_enable_ndb_support = True


def _ndb_status(engine_or_compiler):
    """Test if NDB Support is enabled.

    Function to test if NDB support is enabled or not.

    .. note::

        This is for internal use only while we deprecate and remove ndb
        support. **Do not use this outside of oslo.db!**
    """
    return getattr(
        engine_or_compiler.dialect,
        '_oslodb_enable_ndb_support',
        False,
    )


@debtcollector.removals.remove(
    message=(
        'Support for the MySQL NDB Cluster storage engine has been deprecated '
        'and will be removed in a future release.'
    ),
    version='12.1.0',
)
def ndb_status(engine_or_compiler):
    """Test if NDB Support is enabled.

    Function to test if NDB support is enabled or not.
    """
    return _ndb_status(engine_or_compiler)


@debtcollector.removals.remove(
    message=(
        'Support for the MySQL NDB Cluster storage engine has been deprecated '
        'and will be removed in a future release.'
    ),
    version='12.1.0',
)
def init_ndb_events(engine):
    """Initialize NDB Events.

    Function starts NDB specific events.
    """
    @event.listens_for(engine, "before_cursor_execute", retval=True)
    def before_cursor_execute(conn, cursor, statement, parameters, context,
                              executemany):
        """Listen for specific SQL strings and replace automatically.

        Function will intercept any raw execute calls and automatically
        convert InnoDB to NDBCLUSTER, drop SAVEPOINT requests, drop
        ROLLBACK requests, and drop RELEASE SAVEPOINT requests.
        """
        if _ndb_status(engine):
            statement = engine_regex.sub("ENGINE=NDBCLUSTER", statement)
            if re.match(trans_regex, statement):
                statement = "SET @oslo_db_ndb_savepoint_rollback_disabled = 0;"

        return statement, parameters


# TODO(stephenfin): This is effectively deprecated and should be removed when
# we remove the rest of this module since it'll be a no-op then.
@compiles(schema.CreateTable, "mysql")
def prefix_inserts(create_table, compiler, **kw):
    """Replace InnoDB with NDBCLUSTER automatically.

    Function will intercept CreateTable() calls and automatically
    convert InnoDB to NDBCLUSTER. Targets compiler events.
    """
    existing = compiler.visit_create_table(create_table, **kw)
    if _ndb_status(compiler):
        existing = engine_regex.sub("ENGINE=NDBCLUSTER", existing)

    return existing


# TODO(stephenfin): This is effectively deprecated and should be removed when
# we remove the rest of this module since it'll be a no-op then.
@compiles(String, "mysql")
def _compile_ndb_string(element, compiler, **kw):
    """Process ndb specific overrides for String.

    Function will intercept mysql_ndb_length and mysql_ndb_type
    arguments to adjust columns automatically.

    mysql_ndb_length argument will adjust the String length
    to the requested value.

    mysql_ndb_type will change the column type to the requested
    data type.
    """
    if not _ndb_status(compiler):
        return compiler.visit_string(element, **kw)

    if element.mysql_ndb_length:
        effective_type = element.adapt(
            _String, length=element.mysql_ndb_length)
        return compiler.visit_string(effective_type, **kw)
    elif element.mysql_ndb_type:
        effective_type = to_instance(element.mysql_ndb_type)
        return compiler.process(effective_type, **kw)
    else:
        return compiler.visit_string(element, **kw)