Skip to content

Commit b3fa484

Browse files
committed
feat: support invisible indexes on MySQL 8.0+ and ignored indexes on MariaDB 10.6+
Refs #1388
1 parent 9727d53 commit b3fa484

File tree

5 files changed

+115
-39
lines changed

5 files changed

+115
-39
lines changed

source/dbconnection.pas

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ TTableKey = class(TPersistent)
9090
Name, OldName: String;
9191
IndexType, OldIndexType, Algorithm, Comment: String;
9292
Columns, SubParts, Collations: TStringList;
93-
Modified, Added: Boolean;
93+
Modified, Added, Visible: Boolean;
9494
constructor Create(AOwner: TDBConnection);
9595
destructor Destroy; override;
9696
procedure Assign(Source: TPersistent); override;
@@ -6064,6 +6064,10 @@ function TMySQLConnection.GetTableKeys(Table: TDBObject): TTableKeyList;
60646064
if ExecRegExpr('(BTREE|HASH)', KeyQuery.Col('Index_type')) then
60656065
NewKey.Algorithm := KeyQuery.Col('Index_type');
60666066
NewKey.Comment := KeyQuery.Col('Index_comment', True);
6067+
if KeyQuery.ColumnExists('Visible') then // mysql 8
6068+
NewKey.Visible := SameText(KeyQuery.Col('Visible'), 'yes')
6069+
else if KeyQuery.ColumnExists('Ignored') then // mariadb 10.6
6070+
NewKey.Visible := SameText(KeyQuery.Col('Ignored'), 'NO');
60676071
end;
60686072
if KeyQuery.ColumnExists('Expression') and (not KeyQuery.IsNull('Expression')) then begin
60696073
// Functional key part: enclose expression within parentheses to distinguish them from columns (issue #1777)
@@ -10884,6 +10888,7 @@ constructor TTableKey.Create(AOwner: TDBConnection);
1088410888
Columns.OnChange := Modification;
1088510889
Subparts.OnChange := Modification;
1088610890
Collations.OnChange := Modification;
10891+
Visible := True;
1088710892
end;
1088810893

1088910894
destructor TTableKey.Destroy;
@@ -10906,6 +10911,7 @@ procedure TTableKey.Assign(Source: TPersistent);
1090610911
OldIndexType := s.OldIndexType;
1090710912
Algorithm := s.Algorithm;
1090810913
Comment := s.Comment;
10914+
Visible := s.Visible;
1090910915
Columns.Assign(s.Columns);
1091010916
SubParts.Assign(s.SubParts);
1091110917
Collations.Assign(s.Collations);
@@ -11023,6 +11029,7 @@ function TTableKey.SQLCode(TableName: String=''): String;
1102311029

1102411030
if not Comment.IsEmpty then
1102511031
Result := Result + ' COMMENT ' + FConnection.EscapeString(Comment);
11032+
1102611033
end
1102711034
else begin
1102811035
// SQLite syntax:

source/dbstructures.mysql.pas

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3402,6 +3402,24 @@ function TMySqlProvider.GetSql(AId: TQueryId): string;
34023402
qGrantRole: Result := 'GRANT %s TO %s%s';
34033403
qRevokeRole: Result := 'REVOKE %s FROM %s';
34043404
qSetDefaultRole: Result := 'SET DEFAULT ROLE %s FOR %s';
3405+
qIndexVisible: Result := IfThen(
3406+
FServerVersion >= 100600, // mariadb
3407+
'NOT IGNORED',
3408+
IfThen(
3409+
FServerVersion >= 80000, // mysql
3410+
'VISIBLE',
3411+
''
3412+
)
3413+
);
3414+
qIndexInvisible: Result := IfThen(
3415+
FServerVersion >= 100600, // mariadb
3416+
'IGNORED',
3417+
IfThen(
3418+
FServerVersion >= 80000, // mysql
3419+
'INVISIBLE',
3420+
''
3421+
)
3422+
);
34053423
else Result := inherited;
34063424
end;
34073425
end;

source/dbstructures.pas

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ interface
5050
qShowFunctionStatus, qShowProcedureStatus, qShowTriggers, qShowEvents, qShowCreateTrigger,
5151
qHelpKeyword, qShowWarnings, qGetEnumTypes,
5252
qDropUser, qCreateRole, qDropRole, qReloadPrivileges, qGrantRole, qRevokeRole, qSetDefaultRole,
53-
qAutoInc);
53+
qAutoInc, qIndexVisible, qIndexInvisible);
5454
TSqlProvider = class
5555
strict protected
5656
FNetType: TNetType;

source/table_editor.lfm

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -336,13 +336,13 @@ object frmTableEditor: TfrmTableEditor
336336
DragMode = dmAutomatic
337337
DragType = dtVCL
338338
EditDelay = 0
339-
Header.AutoSizeIndex = 0
339+
Header.AutoSizeIndex = -1
340340
Header.Columns = <
341341
item
342342
Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus]
343343
Position = 0
344344
Text = 'Name'
345-
Width = 241
345+
Width = 191
346346
end
347347
item
348348
Options = [coEnabled, coParentBidiMode, coParentColor, coResizable, coShowDropMark, coVisible, coAllowFocus]
@@ -364,6 +364,10 @@ object frmTableEditor: TfrmTableEditor
364364
Position = 4
365365
Text = 'Direction'
366366
Width = 80
367+
end
368+
item
369+
Position = 5
370+
Text = 'Visibility'
367371
end>
368372
Header.Options = [hoAutoResize, hoColumnResize, hoDrag, hoShowSortGlyphs, hoVisible, hoDisableAnimatedResize]
369373
Header.PopupMenu = MainForm.popupListHeader
@@ -372,7 +376,7 @@ object frmTableEditor: TfrmTableEditor
372376
TabOrder = 1
373377
TreeOptions.AutoOptions = [toAutoDropExpand, toAutoScrollOnExpand, toAutoTristateTracking, toAutoChangeScale]
374378
TreeOptions.MiscOptions = [toAcceptOLEDrop, toEditable, toFullRepaintOnResize, toGridExtensions, toInitOnSave, toToggleOnDblClick, toWheelPanning, toEditOnClick]
375-
TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toFullVertGridLines, toUseExplorerTheme, toHideTreeLinesIfThemed]
379+
TreeOptions.PaintOptions = [toHotTrack, toShowButtons, toShowDropmark, toShowRoot, toShowTreeLines, toThemeAware, toUseBlendedImages, toGhostedIfUnfocused, toFullVertGridLines, toUseExplorerTheme, toHideTreeLinesIfThemed]
376380
TreeOptions.SelectionOptions = [toExtendedFocus, toRightClickSelect]
377381
OnBeforePaint = treeIndexesBeforePaint
378382
OnClick = AnyTreeClick

source/table_editor.pas

Lines changed: 81 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,13 @@ TfrmTableEditor = class(TFrame)
242242
const ColNumInvisible = 13;
243243
const ColNumCompressed = 14;
244244
const ColNumsCheckboxes = [ColNumUnsigned, ColNumAllownull, ColNumZerofill, ColNumInvisible, ColNumCompressed];
245+
// Columns in index tree
246+
const IndexColNumName = 0;
247+
const IndexColNumType = 1;
248+
const IndexColNumAlgorithm = 2;
249+
const IndexColNumComment = 3;
250+
const IndexColNumDirection = 4;
251+
const IndexColNumVisibility = 5;
245252
procedure ValidateColumnControls;
246253
procedure ValidateIndexControls;
247254
procedure MoveFocusedIndexPart(NewIdx: Cardinal);
@@ -911,10 +918,27 @@ function TfrmTableEditor.ComposeAlterStatement: TSQLBatch;
911918
Specs.Add('ADD ' + Constraint.SQLCode);
912919
end;
913920

914-
915921
FinishSpecs;
916922

917-
// Separate queries from here on
923+
// Separate ALTER TABLE .. ALTER INDEX query for visible/invisible indexes features, which gets otherwise
924+
// ignored in MySQL and MariaDB when done by a drop + add combined query. See issue #1388
925+
if Conn.SqlProvider.Has(qIndexInvisible) then begin
926+
for i:=0 to FKeys.Count-1 do begin
927+
if FKeys[i].Modified then begin
928+
Specs.Add('ALTER INDEX ' + Conn.QuoteIdent(FKeys[i].Name) + ' ' +
929+
IfThen(
930+
FKeys[i].Visible,
931+
Conn.SqlProvider.GetSql(qIndexVisible),
932+
Conn.SqlProvider.GetSql(qIndexInvisible)
933+
)
934+
);
935+
end;
936+
end;
937+
FinishSpecs;
938+
end;
939+
940+
941+
// *** Separate queries from here on
918942

919943
// Drop indexes, also changed indexes, which will be readded below
920944
for i:=0 to FDeletedKeys.Count-1 do begin
@@ -2081,10 +2105,15 @@ procedure TfrmTableEditor.treeIndexesGetImageIndex(Sender: TBaseVirtualTree;
20812105
begin
20822106
// Icon image showing type of index
20832107
VT := Sender as TLazVirtualStringTree;
2084-
if Column <> 0 then Exit;
2085-
if not (Kind in [ikNormal, ikSelected]) then Exit;
2108+
if Column <> IndexColNumName then
2109+
Exit;
2110+
if not (Kind in [ikNormal, ikSelected]) then
2111+
Exit;
20862112
case VT.GetNodeLevel(Node) of
2087-
0: ImageIndex := FKeys[Node.Index].ImageIndex;
2113+
0: begin
2114+
ImageIndex := FKeys[Node.Index].ImageIndex;
2115+
Ghosted := not FKeys[Node.Index].Visible;
2116+
end;
20882117
1: begin
20892118
TblKey := FKeys[Node.Parent.Index];
20902119
if TblKey.IsExpression(Node.Index) then
@@ -2107,27 +2136,33 @@ procedure TfrmTableEditor.treeIndexesGetText(Sender: TBaseVirtualTree;
21072136
0: begin
21082137
TblKey := FKeys[Node.Index];
21092138
case Column of
2110-
0: if TblKey.IsPrimary then
2139+
IndexColNumName: if TblKey.IsPrimary then
21112140
CellText := TblKey.IndexType + ' KEY' // Fixed name "PRIMARY KEY", cannot be changed
21122141
else
21132142
CellText := TblKey.Name;
2114-
1: CellText := TblKey.IndexType;
2115-
2: CellText := TblKey.Algorithm;
2116-
3: CellText := TblKey.Comment;
2117-
4: CellText := ''; // Column collation
2143+
IndexColNumType: CellText := TblKey.IndexType;
2144+
IndexColNumAlgorithm: CellText := TblKey.Algorithm;
2145+
IndexColNumComment: CellText := TblKey.Comment;
2146+
IndexColNumDirection: CellText := ''; // Column collation
2147+
IndexColNumVisibility: CellText := IfThen(
2148+
TblKey.Visible,
2149+
DBObject.Connection.SqlProvider.GetSql(qIndexVisible),
2150+
DBObject.Connection.SqlProvider.GetSql(qIndexInvisible)
2151+
);
21182152
end;
21192153
end;
21202154
1: begin
21212155
TblKey := FKeys[Node.Parent.Index];
21222156
case Column of
2123-
0: CellText := TblKey.Columns[Node.Index];
2124-
1: CellText := TblKey.SubParts[Node.Index];
2125-
2: CellText := ''; // Index algorithm
2126-
3: CellText := ''; // Index comment
2127-
4: begin
2157+
IndexColNumName: CellText := TblKey.Columns[Node.Index];
2158+
IndexColNumType: CellText := TblKey.SubParts[Node.Index];
2159+
IndexColNumAlgorithm: CellText := ''; // Index algorithm
2160+
IndexColNumComment: CellText := ''; // Index comment
2161+
IndexColNumDirection: begin
21282162
CellText := TblKey.Collations[Node.Index];
21292163
CellText := IfThen(CellText.ToLower = 'a', 'ASC', 'DESC');
21302164
end;
2165+
IndexColNumVisibility: CellText := '';
21312166
end;
21322167
end;
21332168
end;
@@ -2346,13 +2381,17 @@ procedure TfrmTableEditor.treeIndexesEditing(Sender: TBaseVirtualTree;
23462381
Allowed := False;
23472382
if VT.GetNodeLevel(Node) = 0 then begin
23482383
// Disallow renaming primary key, and direction/collation of key node level
2349-
if (Column = 0) and (VT.Text[Node, 1] <> TTableKey.PRIMARY) then
2350-
Allowed := True
2351-
else
2352-
Allowed := Column in [1,2,3];
2353-
end else case Column of
2354-
0: Allowed := True;
2355-
1: begin
2384+
case Column of
2385+
IndexColNumName: Allowed := (VT.Text[Node, 1] <> TTableKey.PRIMARY);
2386+
IndexColNumType: Allowed := True;
2387+
IndexColNumAlgorithm: Allowed := True;
2388+
IndexColNumComment: Allowed := True;
2389+
IndexColNumVisibility: Allowed := DBObject.Connection.SqlProvider.Has(qIndexInvisible);
2390+
end;
2391+
end
2392+
else case Column of
2393+
IndexColNumName: Allowed := True;
2394+
IndexColNumType: begin
23562395
// Column length is allowed for (var)char/text types only, even mandantory for text and blobs
23572396
IndexedColName := VT.Text[Node, 0];
23582397
for i:=0 to FColumns.Count-1 do begin
@@ -2362,7 +2401,7 @@ procedure TfrmTableEditor.treeIndexesEditing(Sender: TBaseVirtualTree;
23622401
end;
23632402
end;
23642403
end;
2365-
4: Allowed := True; // Collation
2404+
IndexColNumDirection: Allowed := True; // Collation
23662405
end;
23672406
end;
23682407

@@ -2379,18 +2418,25 @@ procedure TfrmTableEditor.treeIndexesCreateEditor(Sender: TBaseVirtualTree;
23792418
// Start cell editor
23802419
VT := Sender as TLazVirtualStringTree;
23812420
Level := (Sender as TLazVirtualStringTree).GetNodeLevel(Node);
2382-
if (Level = 0) and (Column = 1) then begin
2421+
if (Level = 0) and (Column = IndexColNumType) then begin
23832422
// Index type pulldown
23842423
EnumEditor := TEnumEditorLink.Create(VT, True, nil);
23852424
EnumEditor.ValueList := TStringList.Create;
23862425
EnumEditor.ValueList.CommaText := TTableKey.PRIMARY +','+ TTableKey.KEY +','+ TTableKey.UNIQUE +','+ TTableKey.FULLTEXT +','+ TTableKey.SPATIAL;
23872426
EditLink := EnumEditor;
2388-
end else if (Level = 0) and (Column = 2) then begin
2427+
end else if (Level = 0) and (Column = IndexColNumAlgorithm) then begin
23892428
// Algorithm pulldown
23902429
EnumEditor := TEnumEditorLink.Create(VT, True, nil);
23912430
EnumEditor.ValueList := Explode(',', ',BTREE,HASH,RTREE');
23922431
EditLink := EnumEditor;
2393-
end else if (Level = 1) and (Column = 0) then begin
2432+
end else if (Level = 0) and (Column = IndexColNumVisibility) then begin
2433+
// Visibility pulldown
2434+
EnumEditor := TEnumEditorLink.Create(VT, True, nil);
2435+
EnumEditor.ValueList.Add('');
2436+
EnumEditor.ValueList.Add(DBObject.Connection.SqlProvider.GetSql(qIndexVisible));
2437+
EnumEditor.ValueList.Add(DBObject.Connection.SqlProvider.GetSql(qIndexInvisible));
2438+
EditLink := EnumEditor;
2439+
end else if (Level = 1) and (Column = IndexColNumName) then begin
23942440
// Column names pulldown
23952441
EnumEditor := TEnumEditorLink.Create(VT, True, nil);
23962442
ColNode := listColumns.GetFirst;
@@ -2401,7 +2447,7 @@ procedure TfrmTableEditor.treeIndexesCreateEditor(Sender: TBaseVirtualTree;
24012447
end;
24022448
EnumEditor.AllowCustomText := True; // Allows adding a subpart in index parts: "TextCol(20)"
24032449
EditLink := EnumEditor;
2404-
end else if (Level = 1) and (Column = 4) then begin
2450+
end else if (Level = 1) and (Column = IndexColNumDirection) then begin
24052451
EnumEditor := TEnumEditorLink.Create(VT, True, nil);
24062452
EnumEditor.ValueList := Explode(',', ',ASC,DESC');
24072453
EditLink := EnumEditor;
@@ -2423,22 +2469,23 @@ procedure TfrmTableEditor.treeIndexesNewText(Sender: TBaseVirtualTree;
24232469
0: begin
24242470
TblKey := FKeys[Node.Index];
24252471
case Column of
2426-
0: TblKey.Name := NewText;
2427-
1: begin
2472+
IndexColNumName: TblKey.Name := NewText;
2473+
IndexColNumType: begin
24282474
TblKey.IndexType := NewText;
24292475
if NewText = TTableKey.PRIMARY then
24302476
TblKey.Name := TTableKey.PRIMARY;
24312477
end;
2432-
2: TblKey.Algorithm := NewText;
2433-
3: TblKey.Comment := NewText;
2478+
IndexColNumAlgorithm: TblKey.Algorithm := NewText;
2479+
IndexColNumComment: TblKey.Comment := NewText;
2480+
IndexColNumVisibility: TblKey.Visible := SameText(NewText, DBObject.Connection.SqlProvider.GetSql(qIndexVisible));
24342481
end;
24352482
// Needs to be called manually for Name and IndexType properties:
24362483
TblKey.Modification(Sender);
24372484
end;
24382485
1: begin
24392486
TblKey := FKeys[Node.Parent.Index];
24402487
case Column of
2441-
0: begin
2488+
IndexColNumName: begin
24422489
// Detect input of "col(123)" and move "123" into subpart
24432490
rx := TRegExpr.Create;
24442491
rx.Expression := '.+\((\d+)\)';
@@ -2448,8 +2495,8 @@ procedure TfrmTableEditor.treeIndexesNewText(Sender: TBaseVirtualTree;
24482495
end else
24492496
TblKey.Columns[Node.Index] := NewText;
24502497
end;
2451-
1: TblKey.SubParts[Node.Index] := NewText;
2452-
4: begin
2498+
IndexColNumType: TblKey.SubParts[Node.Index] := NewText;
2499+
IndexColNumDirection: begin
24532500
if NewText.ToLower = 'asc' then
24542501
TblKey.Collations[Node.Index] := 'A'
24552502
else

0 commit comments

Comments
 (0)