Sequence failure with MySQL/MariaDB in Transaction class
See original GitHub issueIn https://github.com/spiral-project/ihatemoney/ we still support MariaDB, and are trying to upgrade to SQLAlchemy 1.4 However, CI tests are failing with MariaDB 10.3 with the following log:
2022-01-25T21:52:21.9386170Z self = <sqlalchemy.engine.base.Connection object at 0x7fc169e3ded0>
2022-01-25T21:52:21.9387149Z dialect = <sqlalchemy.dialects.mysql.pymysql.MySQLDialect_pymysql object at 0x7fc16a315510>
2022-01-25T21:52:21.9388315Z constructor = <bound method DefaultExecutionContext._init_compiled of <class 'sqlalchemy.dialects.mysql.mysqldb.MySQLExecutionContext_mysqldb'>>
2022-01-25T21:52:21.9390210Z statement = <sqlalchemy.dialects.mysql.mysqldb.MySQLCompiler_mysqldb object at 0x7fc169e542d0>
2022-01-25T21:52:21.9390909Z parameters = [{'remote_addr': None}]
2022-01-25T21:52:21.9391974Z execution_options = immutabledict({'autocommit': True, 'compiled_cache': {(<sqlalchemy.dialects.mysql.pymysql.MySQLDialect_pymysql object ...emote_addr',), False, False), <sqlalchemy.dialects.mysql.mysqldb.MySQLCompiler_mysqldb object at 0x7fc169e542d0>, 1]}})
2022-01-25T21:52:21.9393494Z args = (<sqlalchemy.dialects.mysql.mysqldb.MySQLCompiler_mysqldb object at 0x7fc169e542d0>, [{'remote_addr': None}], <sqlalchemy.sql.dml.Insert object at 0x7fc169e54e50>, [])
2022-01-25T21:52:21.9394126Z kw = {'cache_hit': symbol('CACHE_MISS')}
2022-01-25T21:52:21.9394535Z branched = <sqlalchemy.engine.base.Connection object at 0x7fc169e3ded0>
2022-01-25T21:52:21.9395180Z conn = <sqlalchemy.pool.base._ConnectionFairy object at 0x7fc169e3db10>
2022-01-25T21:52:21.9395476Z
2022-01-25T21:52:21.9395922Z def _execute_context(
2022-01-25T21:52:21.9396227Z self,
2022-01-25T21:52:21.9396519Z dialect,
2022-01-25T21:52:21.9396797Z constructor,
2022-01-25T21:52:21.9397281Z statement,
2022-01-25T21:52:21.9397586Z parameters,
2022-01-25T21:52:21.9397914Z execution_options,
2022-01-25T21:52:21.9398223Z *args,
2022-01-25T21:52:21.9398836Z **kw
2022-01-25T21:52:21.9399283Z ):
2022-01-25T21:52:21.9399634Z """Create an :class:`.ExecutionContext` and execute, returning
2022-01-25T21:52:21.9400193Z a :class:`_engine.CursorResult`."""
2022-01-25T21:52:21.9400505Z
2022-01-25T21:52:21.9400767Z branched = self
2022-01-25T21:52:21.9401083Z if self.__branch_from:
2022-01-25T21:52:21.9401600Z # if this is a "branched" connection, do everything in terms
2022-01-25T21:52:21.9402033Z # of the "root" connection, *except* for .close(), which is
2022-01-25T21:52:21.9402597Z # the only feature that branching provides
2022-01-25T21:52:21.9402938Z self = self.__branch_from
2022-01-25T21:52:21.9403230Z
2022-01-25T21:52:21.9403630Z try:
2022-01-25T21:52:21.9403932Z conn = self._dbapi_connection
2022-01-25T21:52:21.9404245Z if conn is None:
2022-01-25T21:52:21.9404561Z conn = self._revalidate_connection()
2022-01-25T21:52:21.9405033Z
2022-01-25T21:52:21.9405470Z context = constructor(
2022-01-25T21:52:21.9406229Z > dialect, self, conn, execution_options, *args, **kw
2022-01-25T21:52:21.9408689Z )
2022-01-25T21:52:21.9408818Z
2022-01-25T21:52:21.9409299Z /home/runner/work/ihatemoney/ihatemoney/.tox/py/lib/python3.7/site-packages/sqlalchemy/engine/base.py:1703:
2022-01-25T21:52:21.9409652Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2022-01-25T21:52:21.9409794Z
2022-01-25T21:52:21.9410193Z cls = <class 'sqlalchemy.dialects.mysql.mysqldb.MySQLExecutionContext_mysqldb'>
2022-01-25T21:52:21.9410824Z dialect = <sqlalchemy.dialects.mysql.pymysql.MySQLDialect_pymysql object at 0x7fc16a315510>
2022-01-25T21:52:21.9411220Z connection = <sqlalchemy.engine.base.Connection object at 0x7fc169e3ded0>
2022-01-25T21:52:21.9411592Z dbapi_connection = <sqlalchemy.pool.base._ConnectionFairy object at 0x7fc169e3db10>
2022-01-25T21:52:21.9412843Z execution_options = immutabledict({'autocommit': True, 'compiled_cache': {(<sqlalchemy.dialects.mysql.pymysql.MySQLDialect_pymysql object ...emote_addr',), False, False), <sqlalchemy.dialects.mysql.mysqldb.MySQLCompiler_mysqldb object at 0x7fc169e542d0>, 1]}})
2022-01-25T21:52:21.9413991Z compiled = <sqlalchemy.dialects.mysql.mysqldb.MySQLCompiler_mysqldb object at 0x7fc169e542d0>
2022-01-25T21:52:21.9414437Z parameters = [{'remote_addr': None}]
2022-01-25T21:52:21.9414735Z invoked_statement = <sqlalchemy.sql.dml.Insert object at 0x7fc169e54e50>
2022-01-25T21:52:21.9415118Z extracted_parameters = [], cache_hit = symbol('CACHE_MISS')
2022-01-25T21:52:21.9415288Z
2022-01-25T21:52:21.9415458Z @classmethod
2022-01-25T21:52:21.9415641Z def _init_compiled(
2022-01-25T21:52:21.9415833Z cls,
2022-01-25T21:52:21.9415993Z dialect,
2022-01-25T21:52:21.9416183Z connection,
2022-01-25T21:52:21.9416364Z dbapi_connection,
2022-01-25T21:52:21.9416575Z execution_options,
2022-01-25T21:52:21.9416776Z compiled,
2022-01-25T21:52:21.9416946Z parameters,
2022-01-25T21:52:21.9417143Z invoked_statement,
2022-01-25T21:52:21.9417337Z extracted_parameters,
2022-01-25T21:52:21.9417561Z cache_hit=CACHING_DISABLED,
2022-01-25T21:52:21.9418124Z ):
2022-01-25T21:52:21.9418610Z """Initialize execution context for a Compiled construct."""
2022-01-25T21:52:21.9419033Z
2022-01-25T21:52:21.9419225Z self = cls.__new__(cls)
2022-01-25T21:52:21.9419484Z self.root_connection = connection
2022-01-25T21:52:21.9419755Z self._dbapi_connection = dbapi_connection
2022-01-25T21:52:21.9420049Z self.dialect = connection.dialect
2022-01-25T21:52:21.9420341Z self.extracted_parameters = extracted_parameters
2022-01-25T21:52:21.9420656Z self.invoked_statement = invoked_statement
2022-01-25T21:52:21.9420931Z self.compiled = compiled
2022-01-25T21:52:21.9421166Z self.cache_hit = cache_hit
2022-01-25T21:52:21.9421530Z
2022-01-25T21:52:21.9422118Z self.execution_options = execution_options
2022-01-25T21:52:21.9422407Z
2022-01-25T21:52:21.9422615Z self._is_future_result = (
2022-01-25T21:52:21.9422879Z connection._is_future
2022-01-25T21:52:21.9423202Z or self.execution_options.get("future_result", False)
2022-01-25T21:52:21.9423466Z )
2022-01-25T21:52:21.9423664Z
2022-01-25T21:52:21.9423891Z self.result_column_struct = (
2022-01-25T21:52:21.9424212Z compiled._result_columns,
2022-01-25T21:52:21.9424554Z compiled._ordered_columns,
2022-01-25T21:52:21.9424849Z compiled._textual_ordered_columns,
2022-01-25T21:52:21.9425384Z compiled._loose_column_name_matching,
2022-01-25T21:52:21.9425781Z )
2022-01-25T21:52:21.9426010Z self.isinsert = compiled.isinsert
2022-01-25T21:52:21.9426256Z self.isupdate = compiled.isupdate
2022-01-25T21:52:21.9426686Z self.isdelete = compiled.isdelete
2022-01-25T21:52:21.9426936Z self.is_text = compiled.isplaintext
2022-01-25T21:52:21.9427152Z
2022-01-25T21:52:21.9427393Z if self.isinsert or self.isupdate or self.isdelete:
2022-01-25T21:52:21.9427801Z self.is_crud = True
2022-01-25T21:52:21.9428103Z self._is_explicit_returning = bool(compiled.statement._returning)
2022-01-25T21:52:21.9428399Z self._is_implicit_returning = bool(
2022-01-25T21:52:21.9428711Z compiled.returning and not compiled.statement._returning
2022-01-25T21:52:21.9428974Z )
2022-01-25T21:52:21.9429137Z
2022-01-25T21:52:21.9429497Z if not parameters:
2022-01-25T21:52:21.9429715Z self.compiled_parameters = [
2022-01-25T21:52:21.9429966Z compiled.construct_params(
2022-01-25T21:52:21.9430229Z extracted_parameters=extracted_parameters
2022-01-25T21:52:21.9430459Z )
2022-01-25T21:52:21.9430639Z ]
2022-01-25T21:52:21.9430808Z else:
2022-01-25T21:52:21.9431025Z self.compiled_parameters = [
2022-01-25T21:52:21.9431262Z compiled.construct_params(
2022-01-25T21:52:21.9431482Z m,
2022-01-25T21:52:21.9431674Z _group_number=grp,
2022-01-25T21:52:21.9432020Z extracted_parameters=extracted_parameters,
2022-01-25T21:52:21.9432268Z )
2022-01-25T21:52:21.9432484Z for grp, m in enumerate(parameters)
2022-01-25T21:52:21.9432704Z ]
2022-01-25T21:52:21.9432862Z
2022-01-25T21:52:21.9433092Z self.executemany = len(parameters) > 1
2022-01-25T21:52:21.9433295Z
2022-01-25T21:52:21.9433537Z # this must occur before create_cursor() since the statement
2022-01-25T21:52:21.9433840Z # has to be regexed in some cases for server side cursor
2022-01-25T21:52:21.9434072Z if util.py2k:
2022-01-25T21:52:21.9434341Z self.unicode_statement = util.text_type(compiled.string)
2022-01-25T21:52:21.9434579Z else:
2022-01-25T21:52:21.9434818Z self.unicode_statement = compiled.string
2022-01-25T21:52:21.9435026Z
2022-01-25T21:52:21.9435238Z self.cursor = self.create_cursor()
2022-01-25T21:52:21.9435449Z
2022-01-25T21:52:21.9435707Z if self.compiled.insert_prefetch or self.compiled.update_prefetch:
2022-01-25T21:52:21.9436003Z if self.executemany:
2022-01-25T21:52:21.9436239Z self._process_executemany_defaults()
2022-01-25T21:52:21.9436462Z else:
2022-01-25T21:52:21.9436682Z > self._process_executesingle_defaults()
2022-01-25T21:52:21.9436844Z
2022-01-25T21:52:21.9437695Z /home/runner/work/ihatemoney/ihatemoney/.tox/py/lib/python3.7/site-packages/sqlalchemy/engine/default.py:1019:
2022-01-25T21:52:21.9438049Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2022-01-25T21:52:21.9438202Z
2022-01-25T21:52:21.9438661Z self = <sqlalchemy.dialects.mysql.mysqldb.MySQLExecutionContext_mysqldb object at 0x7fc169e5ed10>
2022-01-25T21:52:21.9438957Z
2022-01-25T21:52:21.9439175Z def _process_executesingle_defaults(self):
2022-01-25T21:52:21.9439668Z key_getter = self.compiled._key_getters_for_crud_column[2]
2022-01-25T21:52:21.9441522Z self.current_parameters = (
2022-01-25T21:52:21.9441790Z compiled_parameters
2022-01-25T21:52:21.9442068Z ) = self.compiled_parameters[0]
2022-01-25T21:52:21.9442296Z
2022-01-25T21:52:21.9442560Z for c in self.compiled.insert_prefetch:
2022-01-25T21:52:21.9442908Z if c.default and not c.default.is_sequence and c.default.is_scalar:
2022-01-25T21:52:21.9443232Z val = c.default.arg
2022-01-25T21:52:21.9443470Z else:
2022-01-25T21:52:21.9443714Z > val = self.get_insert_default(c)
2022-01-25T21:52:21.9443890Z
2022-01-25T21:52:21.9444751Z /home/runner/work/ihatemoney/ihatemoney/.tox/py/lib/python3.7/site-packages/sqlalchemy/engine/default.py:1892:
2022-01-25T21:52:21.9445506Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2022-01-25T21:52:21.9445662Z
2022-01-25T21:52:21.9446418Z self = <sqlalchemy.dialects.mysql.mysqldb.MySQLExecutionContext_mysqldb object at 0x7fc169e5ed10>
2022-01-25T21:52:21.9447095Z column = Column('id', BigInteger(), table=<transaction>, primary_key=True, nullable=False, default=Sequence('transaction_id_seq', metadata=MetaData()))
2022-01-25T21:52:21.9447380Z
2022-01-25T21:52:21.9447592Z def get_insert_default(self, column):
2022-01-25T21:52:21.9448080Z if column.default is None:
2022-01-25T21:52:21.9448321Z return None
2022-01-25T21:52:21.9448501Z else:
2022-01-25T21:52:21.9448771Z > return self._exec_default(column, column.default, column.type)
2022-01-25T21:52:21.9449126Z
2022-01-25T21:52:21.9449552Z /home/runner/work/ihatemoney/ihatemoney/.tox/py/lib/python3.7/site-packages/sqlalchemy/engine/default.py:1836:
2022-01-25T21:52:21.9450091Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2022-01-25T21:52:21.9450235Z
2022-01-25T21:52:21.9450564Z self = <sqlalchemy.dialects.mysql.mysqldb.MySQLExecutionContext_mysqldb object at 0x7fc169e5ed10>
2022-01-25T21:52:21.9451560Z column = Column('id', BigInteger(), table=<transaction>, primary_key=True, nullable=False, default=Sequence('transaction_id_seq', metadata=MetaData()))
2022-01-25T21:52:21.9452089Z default = Sequence('transaction_id_seq', metadata=MetaData())
2022-01-25T21:52:21.9452335Z type_ = BigInteger()
2022-01-25T21:52:21.9452466Z
2022-01-25T21:52:21.9452689Z def _exec_default(self, column, default, type_):
2022-01-25T21:52:21.9452927Z if default.is_sequence:
2022-01-25T21:52:21.9453186Z > return self.fire_sequence(default, type_)
2022-01-25T21:52:21.9453345Z
2022-01-25T21:52:21.9453918Z /home/runner/work/ihatemoney/ihatemoney/.tox/py/lib/python3.7/site-packages/sqlalchemy/engine/default.py:1697:
2022-01-25T21:52:21.9454282Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2022-01-25T21:52:21.9454427Z
2022-01-25T21:52:21.9454756Z self = <sqlalchemy.dialects.mysql.mysqldb.MySQLExecutionContext_mysqldb object at 0x7fc169e5ed10>
2022-01-25T21:52:21.9455299Z seq = Sequence('transaction_id_seq', metadata=MetaData()), type_ = BigInteger()
2022-01-25T21:52:21.9455502Z
2022-01-25T21:52:21.9455696Z def fire_sequence(self, seq, type_):
2022-01-25T21:52:21.9456103Z return self._execute_scalar(
2022-01-25T21:52:21.9456294Z (
2022-01-25T21:52:21.9456701Z "select nextval(%s)"
2022-01-25T21:52:21.9457148Z % self.identifier_preparer.format_sequence(seq)
2022-01-25T21:52:21.9457371Z ),
2022-01-25T21:52:21.9457554Z > type_,
2022-01-25T21:52:21.9457722Z )
2022-01-25T21:52:21.9457830Z
2022-01-25T21:52:21.9458386Z /home/runner/work/ihatemoney/ihatemoney/.tox/py/lib/python3.7/site-packages/sqlalchemy/dialects/mysql/base.py:1153:
2022-01-25T21:52:21.9459001Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2022-01-25T21:52:21.9459149Z
2022-01-25T21:52:21.9459495Z self = <sqlalchemy.dialects.mysql.mysqldb.MySQLExecutionContext_mysqldb object at 0x7fc169e5ed10>
2022-01-25T21:52:21.9459999Z stmt = 'select nextval(transaction_id_seq)', type_ = BigInteger()
2022-01-25T21:52:21.9460265Z parameters = {}
2022-01-25T21:52:21.9460400Z
2022-01-25T21:52:21.9460626Z def _execute_scalar(self, stmt, type_, parameters=None):
2022-01-25T21:52:21.9460951Z """Execute a string statement on the current cursor, returning a
2022-01-25T21:52:21.9461204Z scalar result.
2022-01-25T21:52:21.9461400Z
2022-01-25T21:52:21.9461664Z Used to fire off sequences, default phrases, and "select lastrowid"
2022-01-25T21:52:21.9462001Z types of statements individually or in the context of a parent INSERT
2022-01-25T21:52:21.9462289Z or UPDATE statement.
2022-01-25T21:52:21.9462475Z
2022-01-25T21:52:21.9462696Z """
2022-01-25T21:52:21.9462856Z
2022-01-25T21:52:21.9463058Z conn = self.root_connection
2022-01-25T21:52:21.9463270Z if (
2022-01-25T21:52:21.9463480Z isinstance(stmt, util.text_type)
2022-01-25T21:52:21.9463781Z and not self.dialect.supports_unicode_statements
2022-01-25T21:52:21.9464011Z ):
2022-01-25T21:52:21.9464240Z stmt = self.dialect._encoder(stmt)[0]
2022-01-25T21:52:21.9464445Z
2022-01-25T21:52:21.9464688Z if "schema_translate_map" in self.execution_options:
2022-01-25T21:52:21.9465000Z schema_translate_map = self.execution_options.get(
2022-01-25T21:52:21.9465263Z "schema_translate_map", {}
2022-01-25T21:52:21.9465479Z )
2022-01-25T21:52:21.9465639Z
2022-01-25T21:52:21.9465893Z rst = self.identifier_preparer._render_schema_translates
2022-01-25T21:52:21.9466195Z stmt = rst(stmt, schema_translate_map)
2022-01-25T21:52:21.9466407Z
2022-01-25T21:52:21.9466601Z if not parameters:
2022-01-25T21:52:21.9466830Z if self.dialect.positional:
2022-01-25T21:52:21.9467134Z parameters = self.dialect.execute_sequence_format()
2022-01-25T21:52:21.9467373Z else:
2022-01-25T21:52:21.9467662Z parameters = {}
2022-01-25T21:52:21.9467879Z
2022-01-25T21:52:21.9468124Z > conn._cursor_execute(self.cursor, stmt, parameters, context=self)
2022-01-25T21:52:21.9468321Z
2022-01-25T21:52:21.9468754Z /home/runner/work/ihatemoney/ihatemoney/.tox/py/lib/python3.7/site-packages/sqlalchemy/engine/default.py:1290:
2022-01-25T21:52:21.9469110Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2022-01-25T21:52:21.9469257Z
2022-01-25T21:52:21.9469529Z self = <sqlalchemy.engine.base.Connection object at 0x7fc169e3ded0>
2022-01-25T21:52:21.9470028Z cursor = <pymysql.cursors.Cursor object at 0x7fc169ed06d0>
2022-01-25T21:52:21.9470433Z statement = 'select nextval(transaction_id_seq)', parameters = {}
2022-01-25T21:52:21.9470840Z context = <sqlalchemy.dialects.mysql.mysqldb.MySQLExecutionContext_mysqldb object at 0x7fc169e5ed10>
2022-01-25T21:52:21.9471115Z
2022-01-25T21:52:21.9471370Z def _cursor_execute(self, cursor, statement, parameters, context=None):
2022-01-25T21:52:21.9471676Z """Execute a statement + params on the given cursor.
2022-01-25T21:52:21.9471903Z
2022-01-25T21:52:21.9472124Z Adds appropriate logging and exception handling.
2022-01-25T21:52:21.9472353Z
2022-01-25T21:52:21.9472677Z This method is used by DefaultDialect for special-case
2022-01-25T21:52:21.9472966Z executions, such as for sequences and column defaults.
2022-01-25T21:52:21.9473267Z The path of statement execution in the majority of cases
2022-01-25T21:52:21.9473526Z terminates at _execute_context().
2022-01-25T21:52:21.9473734Z
2022-01-25T21:52:21.9473906Z """
2022-01-25T21:52:21.9474218Z if self._has_events or self.engine._has_events:
2022-01-25T21:52:21.9474517Z for fn in self.dispatch.before_cursor_execute:
2022-01-25T21:52:21.9474817Z statement, parameters = fn(
2022-01-25T21:52:21.9475098Z > self, cursor, statement, parameters, context, False
2022-01-25T21:52:21.9475326Z )
2022-01-25T21:52:21.9475443Z
2022-01-25T21:52:21.9475874Z /home/runner/work/ihatemoney/ihatemoney/.tox/py/lib/python3.7/site-packages/sqlalchemy/engine/base.py:1865:
2022-01-25T21:52:21.9476210Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2022-01-25T21:52:21.9476334Z
2022-01-25T21:52:21.9476594Z conn = <sqlalchemy.engine.base.Connection object at 0x7fc169e3ded0>
2022-01-25T21:52:21.9476933Z cursor = <pymysql.cursors.Cursor object at 0x7fc169ed06d0>
2022-01-25T21:52:21.9477314Z statement = 'select nextval(transaction_id_seq)', parameters = {}
2022-01-25T21:52:21.9477734Z context = <sqlalchemy.dialects.mysql.mysqldb.MySQLExecutionContext_mysqldb object at 0x7fc169e5ed10>
2022-01-25T21:52:21.9478081Z executemany = False
2022-01-25T21:52:21.9478207Z
2022-01-25T21:52:21.9478403Z def wrap_before_cursor_execute(
2022-01-25T21:52:21.9478671Z conn, cursor, statement, parameters, context, executemany
2022-01-25T21:52:21.9478916Z ):
2022-01-25T21:52:21.9479075Z orig_fn(
2022-01-25T21:52:21.9479258Z conn,
2022-01-25T21:52:21.9479443Z cursor,
2022-01-25T21:52:21.9479617Z statement,
2022-01-25T21:52:21.9479817Z parameters,
2022-01-25T21:52:21.9479994Z context,
2022-01-25T21:52:21.9480189Z > executemany,
2022-01-25T21:52:21.9480358Z )
2022-01-25T21:52:21.9480466Z
2022-01-25T21:52:21.9480891Z /home/runner/work/ihatemoney/ihatemoney/.tox/py/lib/python3.7/site-packages/sqlalchemy/engine/events.py:134:
2022-01-25T21:52:21.9481218Z _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
2022-01-25T21:52:21.9481362Z
2022-01-25T21:52:21.9481672Z self = <ihatemoney.versioning.ConditionalVersioningManager object at 0x7fc16e1e63d0>
2022-01-25T21:52:21.9482066Z conn = <sqlalchemy.engine.base.Connection object at 0x7fc169e3ded0>
2022-01-25T21:52:21.9482400Z cursor = <pymysql.cursors.Cursor object at 0x7fc169ed06d0>
2022-01-25T21:52:21.9482884Z statement = 'select nextval(transaction_id_seq)', parameters = {}
2022-01-25T21:52:21.9483307Z context = <sqlalchemy.dialects.mysql.mysqldb.MySQLExecutionContext_mysqldb object at 0x7fc169e5ed10>
2022-01-25T21:52:21.9483665Z executemany = False
2022-01-25T21:52:21.9483793Z
2022-01-25T21:52:21.9483979Z def track_association_operations(
2022-01-25T21:52:21.9484273Z self, conn, cursor, statement, parameters, context, executemany
2022-01-25T21:52:21.9484502Z ):
2022-01-25T21:52:21.9484673Z """
2022-01-25T21:52:21.9484912Z Track association operations and adds the generated history
2022-01-25T21:52:21.9485223Z association operations to pending_statements list.
2022-01-25T21:52:21.9485468Z """
2022-01-25T21:52:21.9485629Z if (
2022-01-25T21:52:21.9485933Z not self.options['versioning'] and
2022-01-25T21:52:21.9486250Z not self.options['native_versioning']
2022-01-25T21:52:21.9486475Z ):
2022-01-25T21:52:21.9486642Z return
2022-01-25T21:52:21.9486818Z
2022-01-25T21:52:21.9486992Z op = None
2022-01-25T21:52:21.9487182Z if context.isinsert:
2022-01-25T21:52:21.9487411Z op = Operation.INSERT
2022-01-25T21:52:21.9487672Z elif context.isdelete:
2022-01-25T21:52:21.9488002Z op = Operation.DELETE
2022-01-25T21:52:21.9488192Z
2022-01-25T21:52:21.9488378Z if op is not None:
2022-01-25T21:52:21.9488700Z > table_name = statement.split(' ')[2]
2022-01-25T21:52:21.9488949Z E IndexError: list index out of range
2022-01-25T21:52:21.9489100Z
2022-01-25T21:52:21.9489554Z /home/runner/work/ihatemoney/ihatemoney/.tox/py/lib/python3.7/site-packages/sqlalchemy_continuum/manager.py:454: IndexError
The log is quite extensive, so I asked the question to the SQLAlchemy community on https://github.com/sqlalchemy/sqlalchemy/discussions/7649
The maintainer answer led me to https://github.com/kvesteri/sqlalchemy-continuum/blame/2e53b5f927c7b601c1dab02b2c91c4dbb3b9ed15/sqlalchemy_continuum/transaction.py#L125 (but there is also https://github.com/kvesteri/sqlalchemy-continuum/blame/2e53b5f927c7b601c1dab02b2c91c4dbb3b9ed15/sqlalchemy_continuum/plugins/activity.py#L204) were explicit Sequence()
are used, since the merge of https://github.com/kvesteri/sqlalchemy-continuum/commit/0bb36e02b9db7b65133c037ca993effbc78c299b. This was based on work in https://github.com/kvesteri/sqlalchemy-continuum/pull/118 that mentioned support for Oracle database.
According to the SQLAlchemy maintainer:
So somewhere you have a Sequence() object, if you aren’t supporting Oracle database, I’d take that out entirely (and if you are supporting Oracle, Id look into using IDENTITY for most databases anyway, which we now support).
I tried to set optional=True
as mentioned in https://github.com/kvesteri/sqlalchemy-continuum/pull/118#issuecomment-215553949 but this doesn’t solve the issue.
However, commenting the line solved this issue. So I have to request to change something here. Obviously the support for Oracle is needed, so maybe the sequence should be defined only when this backend is in use. I didn’t look (yet?) into IDENTITY
as mentioned, but I can’t test Oracle by myself, so if someone has a clue on this, I’ll be delighted.
In the meantime we may monkey-patch or use another transaction factory.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:5
Top GitHub Comments
Just to update here, substituting that line should be safe for typical uses, when the only table with a sequence is Continuum’s Transaction table. The scenarios that may not be safe are when an association table (one used in a relationship with
secondary
) has an explicit sequence or schema. I think I need to write a test around this before I’m comfortable committing it.Hey, I’m not sure what to do about this. Is it fixed? Needs some work? Thanks!