← Back to team overview

maria-developers team mailing list archive

Re: d08031dfae2: MDEV-17376 Server fails to set ADD_PK_INDEX, DROP_PK_INDEX if unique index nominated as PK

 

Hi, Marko!

On Jan 17, Marko Mäkelä wrote:
> Hi Sergei,
> 
> On January 16, 2019, Sergei Golubchik wrote:
> > On Jan 16, Thirunarayanan Balathandayuthapani wrote:
> > > revision-id: d08031dfae2 (mariadb-10.0.37-45-gd08031dfae2)
> > > parent(s): 12f362c3338
> > > author: Thirunarayanan Balathandayuthapani <thiru@xxxxxxxxxxx>
> > > committer: Thirunarayanan Balathandayuthapani <thiru@xxxxxxxxxxx>
> > > timestamp: 2019-01-16 15:46:28 +0530
> > > message:
> > >
> > > MDEV-17376 Server fails to set ADD_PK_INDEX, DROP_PK_INDEX if unique index nominated as PK
> >
> > Sorry, that's way too complex. I mean the original code with
> > candidate_key_count, is_candidate_key, and all that.
> > And you're making it more complex.
> 
> Yes, it is complex, but this patch already went through some rounds of
> my review, and this was the best we could come up without a major
> refactoring.

I didn't mean the the patch was complex, it only builds on top of the
existing code. I found the existing logic around "candidate keys" quite
convoluted and completely unnecessary.

> > If a unique key is promoted to a primary key, this unique key is
> > always be the first key in the table.
> 
> According to some comments in InnoDB, this might not have been the
> case in tables that were created in MySQL 3.23. But that would not be
> the first time when a comment in InnoDB source code has been
> inaccurate or incorrect.
> As far as we can tell, table->s->primary_key is always either 0 or
> MAX_KEY. Do you know if this has ever been different earlier?

I'm not sure. I see that even 3.23 sorted unique indexes first.  But
later it uses a loop to find table->s->primary_key. Which doesn't mean
anything, because even now in 10.4 there's lots of code redundant like

  if (table->s->primary_key >= MAX_KEY)

while one primary_key can only be 0 or MAX_KEY.
I cannot say whether that loop in 3.23 is needed or yet another case of
primary_key redundancy.

> > So what you need to check is
> >   * if the old table didn't have a primary key and the new table has it,
> >     then a primary key was added. As easy as
> >
> >       if (table->s->primary_key >= MAX_KEY &&
> >           altered_table->s->primary_key != MAX_KEY)
> 
> It would be as easy as that if altered_table had already been
> constructed. But it seems to me that it would be constructed based on
> the output of this function.
> Perhaps we should set the flags somewhat later based on comparing
> table and altered_table?

altered_table is opened (a TABLE object is created) after
fill_alter_inplace_info() and it doesn't use the result of
fill_alter_inplace_info().

But the frm file is created before. In create_table_impl().

There are three options to do what I suggested
* move this check for a changed primary key out of
  fill_alter_inplace_info(), after altered_table is opened
* open altered_table before fill_alter_inplace_info
* don't use altered_table->s->primary_key, but derive it from
  key_info[] array (which shows keys as written in the new frm file). So
  instead of altered_table->s->primary_key one would use

   (key_info->flags & HA_NOSAME && !(key_info->flags & HA_NULL_PART_KEY)
     && !(key_info->flags & HA_KEY_HAS_PART_KEY_SEG)) ? 0 : MAX_KEY

  again, just as that if() with altered_table->s->primary_key, this
  expression is only to explain the idea, not something that should be
  copy-pasted verbatim into the patch :)

I think, out of the three options above, the third one is the best

Regards,
Sergei
Chief Architect MariaDB
and security@xxxxxxxxxxx


References