Ensure creating an index that already exists is forgiving for postgresql (#46185)
Unlikely sqlite and mysql, postgresql throws ProgrammingError instead of InternalError or OperationalError when trying to create an index that already exists.
This commit is contained in:
parent
6b340415b2
commit
dc26fd5149
2 changed files with 36 additions and 10 deletions
|
@ -3,7 +3,12 @@ import logging
|
|||
|
||||
from sqlalchemy import ForeignKeyConstraint, MetaData, Table, text
|
||||
from sqlalchemy.engine import reflection
|
||||
from sqlalchemy.exc import InternalError, OperationalError, SQLAlchemyError
|
||||
from sqlalchemy.exc import (
|
||||
InternalError,
|
||||
OperationalError,
|
||||
ProgrammingError,
|
||||
SQLAlchemyError,
|
||||
)
|
||||
from sqlalchemy.schema import AddConstraint, DropConstraint
|
||||
|
||||
from .const import DOMAIN
|
||||
|
@ -69,7 +74,7 @@ def _create_index(engine, table_name, index_name):
|
|||
)
|
||||
try:
|
||||
index.create(engine)
|
||||
except OperationalError as err:
|
||||
except (InternalError, ProgrammingError, OperationalError) as err:
|
||||
lower_err_str = str(err).lower()
|
||||
|
||||
if "already exists" not in lower_err_str and "duplicate" not in lower_err_str:
|
||||
|
@ -78,13 +83,6 @@ def _create_index(engine, table_name, index_name):
|
|||
_LOGGER.warning(
|
||||
"Index %s already exists on %s, continuing", index_name, table_name
|
||||
)
|
||||
except InternalError as err:
|
||||
if "duplicate" not in str(err).lower():
|
||||
raise
|
||||
|
||||
_LOGGER.warning(
|
||||
"Index %s already exists on %s, continuing", index_name, table_name
|
||||
)
|
||||
|
||||
_LOGGER.debug("Finished creating %s", index_name)
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
"""The tests for the Recorder component."""
|
||||
# pylint: disable=protected-access
|
||||
from unittest.mock import call, patch
|
||||
from unittest.mock import Mock, PropertyMock, call, patch
|
||||
|
||||
import pytest
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.exc import InternalError, OperationalError, ProgrammingError
|
||||
from sqlalchemy.pool import StaticPool
|
||||
|
||||
from homeassistant.bootstrap import async_setup_component
|
||||
|
@ -79,3 +80,30 @@ def test_forgiving_add_index():
|
|||
engine = create_engine("sqlite://", poolclass=StaticPool)
|
||||
models.Base.metadata.create_all(engine)
|
||||
migration._create_index(engine, "states", "ix_states_context_id")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"exception_type", [OperationalError, ProgrammingError, InternalError]
|
||||
)
|
||||
def test_forgiving_add_index_with_other_db_types(caplog, exception_type):
|
||||
"""Test that add index will continue if index exists on mysql and postgres."""
|
||||
mocked_index = Mock()
|
||||
type(mocked_index).name = "ix_states_context_id"
|
||||
mocked_index.create = Mock(
|
||||
side_effect=exception_type(
|
||||
"CREATE INDEX ix_states_old_state_id ON states (old_state_id);",
|
||||
[],
|
||||
'relation "ix_states_old_state_id" already exists',
|
||||
)
|
||||
)
|
||||
|
||||
mocked_table = Mock()
|
||||
type(mocked_table).indexes = PropertyMock(return_value=[mocked_index])
|
||||
|
||||
with patch(
|
||||
"homeassistant.components.recorder.migration.Table", return_value=mocked_table
|
||||
):
|
||||
migration._create_index(Mock(), "states", "ix_states_context_id")
|
||||
|
||||
assert "already exists on states" in caplog.text
|
||||
assert "continuing" in caplog.text
|
||||
|
|
Loading…
Add table
Reference in a new issue