Hi, Aleksey,

On Jun 27, Aleksey Midenkov wrote:
> revision-id: 59aafa4ee46 (mariadb-10.6.22-50-g59aafa4ee46)
> parent(s): 1221f49f312
> author: Aleksey Midenkov
> committer: Aleksey Midenkov
> timestamp: 2025-06-04 23:42:36 +0300
> message:
> 
> MDEV-33633 Trigger tries to access already dropped view
> 
> diff --git a/mysql-test/main/ps_ddl.result b/mysql-test/main/ps_ddl.result
> index 35998c05dc9..ceb85835623 100644
> --- a/mysql-test/main/ps_ddl.result
> +++ b/mysql-test/main/ps_ddl.result
> @@ -333,7 +333,7 @@ a
>  drop view v1;
>  create view v1 as select a from t3;
>  insert into t1 (a) values (6);
> -ERROR 42S02: Table 'test.t2' doesn't exist
> +ERROR HY000: Table definition has changed, please retry transaction

Is it possible to the fallback and reopen here? This is a rather
unexpected error, particularly when no transactions are involved.

> diff --git a/sql/sql_base.cc b/sql/sql_base.cc
> index 1a4fa315c3c..c89e88d0f03 100644
> --- a/sql/sql_base.cc
> +++ b/sql/sql_base.cc
> @@ -1737,6 +1737,18 @@ bool is_locked_view(THD *thd, TABLE_LIST *t)
>          DBUG_RETURN(FALSE);
>        }
>  
> +      Reprepare_observer reprepare_observer;
> +      auto scope_exit= make_scope_exit(
> +        [thd]() mutable { thd->m_reprepare_observer= NULL; },
> +        false);
> +      if (!thd->m_reprepare_observer)
> +      {
> +        reprepare_observer.reset_reprepare_observer();
> +        reprepare_observer.error_code= ER_TABLE_DEF_CHANGED;
> +        thd->m_reprepare_observer= &reprepare_observer;
> +        scope_exit.engage();
> +      }

And you didn't use SCOPE_EXIT to use a manual engage?
Would be clearer, I'd say, to use SCOPE_EXIT and have an if() inside,
like if (m_reprepare_observer == &reprepare_observer).

But ok, as you like.

>        if (!tdc_open_view(thd, t, CHECK_METADATA_VERSION))
>        {
>          DBUG_ASSERT(t->view != 0);
> @@ -3059,9 +3071,7 @@ bool tdc_open_view(THD *thd, TABLE_LIST *table_list, 
> uint flags)
>  
>    DBUG_ASSERT(share->is_view);
>  
> -  err= mysql_make_view(thd, share, table_list, (flags & OPEN_VIEW_NO_PARSE));
> -
> -  if (!err && (flags & CHECK_METADATA_VERSION))
> +  if (flags & CHECK_METADATA_VERSION)
>    {
>      /*
>        Check TABLE_SHARE-version of view only if we have been instructed to do
> @@ -3076,6 +3086,8 @@ bool tdc_open_view(THD *thd, TABLE_LIST *table_list, 
> uint flags)
>        goto ret;
>    }
>  
> +  err= mysql_make_view(thd, share, table_list, (flags & OPEN_VIEW_NO_PARSE));

But this one - I don't understand how it works.
mysql_make_view() reads the view frm which contains versions that are
checked by check_and_update_table_version(). How can
check_and_update_table_version() work before mysql_make_view()?

>  ret:
>    tdc_release_share(share);
>  
> diff --git a/sql/table.cc b/sql/table.cc
> index 9bbc29d4ecf..6d2a80aeace 100644
> --- a/sql/table.cc
> +++ b/sql/table.cc
> @@ -5799,6 +5799,12 @@ void TABLE::init(THD *thd, TABLE_LIST *tl)
>    DBUG_ASSERT(!auto_increment_field_not_null);
>    auto_increment_field_not_null= FALSE;
>  
> +  tl->view= NULL;
> +  tl->derived= NULL;
> +  tl->derived_type= VIEW_ALGORITHM_UNDEFINED;
> +  tl->updatable= true;
> +  tl->effective_with_check= VIEW_CHECK_NONE;
> +

I agree it's conceptually correct and for the new table these fields
should be reset. But it's rather unexpected that TABLE::init() modifies
its arguments. Could this reinitialization be done somewhere else?
 
Regards,
Sergei
Chief Architect, MariaDB Server
and secur...@mariadb.org
_______________________________________________
developers mailing list -- developers@lists.mariadb.org
To unsubscribe send an email to developers-le...@lists.mariadb.org

Reply via email to