Support serial columns in Posgres, which is different from auto_increment on MySQL. Affects grid editing and table designer. Closes #279

This commit is contained in:
Ansgar Becker
2023-05-13 10:03:07 +02:00
parent ac9028c627
commit 7d9f59381f
4 changed files with 61 additions and 16 deletions

View File

@ -347,7 +347,7 @@ end;
procedure TCopyTableForm.btnOKClick(Sender: TObject); procedure TCopyTableForm.btnOKClick(Sender: TObject);
var var
CreateCode, InsertCode, TargetTable, DataCols, Msg: String; CreateCode, InsertCode, TargetTable, DataCols, Msg: String;
TableExistence: String; TableExistence, AutoIncName: String;
ParentNode, Node: PVirtualNode; ParentNode, Node: PVirtualNode;
DoData, AutoIncGetsKey, AutoIncRemoved, TableHasAutoInc: Boolean; DoData, AutoIncGetsKey, AutoIncRemoved, TableHasAutoInc: Boolean;
SelectedColumns: TTableColumnList; SelectedColumns: TTableColumnList;
@ -409,9 +409,11 @@ begin
// Columns code. Remove auto_increment attribute if pkey was unchecked, to overcome // Columns code. Remove auto_increment attribute if pkey was unchecked, to overcome
// "there can be only one auto column and it must be defined as a key" // "there can be only one auto column and it must be defined as a key"
AutoIncName := 'unknown';
for Column in SelectedColumns do begin for Column in SelectedColumns do begin
AutoIncGetsKey := False; AutoIncGetsKey := False;
AutoIncRemoved := False; AutoIncRemoved := False;
AutoIncName := Column.AutoIncName;
if Column.DefaultType = cdtAutoInc then begin if Column.DefaultType = cdtAutoInc then begin
for Key in SelectedKeys do begin for Key in SelectedKeys do begin
// Don't check index type, MySQL allows auto-increment columns on nearly all indexes // Don't check index type, MySQL allows auto-increment columns on nearly all indexes
@ -486,7 +488,7 @@ begin
Screen.Cursor := crDefault; Screen.Cursor := crDefault;
Msg := E.Message; Msg := E.Message;
if FConnection.LastErrorCode = ER_WRONG_AUTO_KEY then if FConnection.LastErrorCode = ER_WRONG_AUTO_KEY then
Msg := Msg + CRLF + CRLF + f_('Please select the required index for the %s flag.', ['auto_increment']); Msg := Msg + CRLF + CRLF + f_('Please select the required index for the %s flag.', [AutoIncName]);
ErrorDialog(Msg); ErrorDialog(Msg);
ModalResult := mrNone; ModalResult := mrNone;
end; end;

View File

@ -61,6 +61,7 @@ type
function CastAsText: String; function CastAsText: String;
property Status: TEditingStatus read FStatus write SetStatus; property Status: TEditingStatus read FStatus write SetStatus;
property Connection: TDBConnection read FConnection; property Connection: TDBConnection read FConnection;
function AutoIncName: String;
end; end;
PTableColumn = ^TTableColumn; PTableColumn = ^TTableColumn;
TTableColumnList = class(TObjectList<TTableColumn>) TTableColumnList = class(TObjectList<TTableColumn>)
@ -425,7 +426,7 @@ type
spGlobalStatus, spCommandsCounters, spSessionVariables, spGlobalVariables, spGlobalStatus, spCommandsCounters, spSessionVariables, spGlobalVariables,
spISSchemaCol, spISSchemaCol,
spUSEQuery, spKillQuery, spKillProcess, spUSEQuery, spKillQuery, spKillProcess,
spFuncLength, spFuncCeil, spFuncLeft, spFuncNow, spFuncLength, spFuncCeil, spFuncLeft, spFuncNow, spFuncLastAutoIncNumber,
spLockedTables, spDisableForeignKeyChecks, spEnableForeignKeyChecks, spLockedTables, spDisableForeignKeyChecks, spEnableForeignKeyChecks,
spOrderAsc, spOrderDesc); spOrderAsc, spOrderDesc);
@ -3071,6 +3072,7 @@ begin
FSQLSpecifities[spFuncCeil] := 'CEIL'; FSQLSpecifities[spFuncCeil] := 'CEIL';
FSQLSpecifities[spFuncLeft] := IfThen(Parameters.IsProxySQLAdmin, 'SUBSTR(%s, 1, %d)', 'LEFT(%s, %d)'); FSQLSpecifities[spFuncLeft] := IfThen(Parameters.IsProxySQLAdmin, 'SUBSTR(%s, 1, %d)', 'LEFT(%s, %d)');
FSQLSpecifities[spFuncNow] := IfThen(Parameters.IsProxySQLAdmin, 'CURRENT_TIMESTAMP', 'NOW()'); FSQLSpecifities[spFuncNow] := IfThen(Parameters.IsProxySQLAdmin, 'CURRENT_TIMESTAMP', 'NOW()');
FSQLSpecifities[spFuncLastAutoIncNumber] := 'LAST_INSERT_ID()';
FSQLSpecifities[spLockedTables] := ''; FSQLSpecifities[spLockedTables] := '';
FSQLSpecifities[spDisableForeignKeyChecks] := 'SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0'; FSQLSpecifities[spDisableForeignKeyChecks] := 'SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0';
FSQLSpecifities[spEnableForeignKeyChecks] := 'SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1)'; FSQLSpecifities[spEnableForeignKeyChecks] := 'SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1)';
@ -3094,6 +3096,7 @@ begin
FSQLSpecifities[spFuncCeil] := 'CEILING'; FSQLSpecifities[spFuncCeil] := 'CEILING';
FSQLSpecifities[spFuncLeft] := 'LEFT(%s, %d)'; FSQLSpecifities[spFuncLeft] := 'LEFT(%s, %d)';
FSQLSpecifities[spFuncNow] := 'GETDATE()'; FSQLSpecifities[spFuncNow] := 'GETDATE()';
FSQLSpecifities[spFuncLastAutoIncNumber] := 'LAST_INSERT_ID()';
FSQLSpecifities[spLockedTables] := ''; FSQLSpecifities[spLockedTables] := '';
FSQLSpecifities[spDisableForeignKeyChecks] := ''; FSQLSpecifities[spDisableForeignKeyChecks] := '';
FSQLSpecifities[spEnableForeignKeyChecks] := ''; FSQLSpecifities[spEnableForeignKeyChecks] := '';
@ -3119,6 +3122,7 @@ begin
FSQLSpecifities[spFuncCeil] := 'CEIL'; FSQLSpecifities[spFuncCeil] := 'CEIL';
FSQLSpecifities[spFuncLeft] := 'SUBSTRING(%s, 1, %d)'; FSQLSpecifities[spFuncLeft] := 'SUBSTRING(%s, 1, %d)';
FSQLSpecifities[spFuncNow] := 'NOW()'; FSQLSpecifities[spFuncNow] := 'NOW()';
FSQLSpecifities[spFuncLastAutoIncNumber] := 'LASTVAL()';
FSQLSpecifities[spLockedTables] := ''; FSQLSpecifities[spLockedTables] := '';
FSQLSpecifities[spDisableForeignKeyChecks] := ''; FSQLSpecifities[spDisableForeignKeyChecks] := '';
FSQLSpecifities[spEnableForeignKeyChecks] := ''; FSQLSpecifities[spEnableForeignKeyChecks] := '';
@ -3143,6 +3147,7 @@ begin
FSQLSpecifities[spFuncCeil] := 'CEIL'; FSQLSpecifities[spFuncCeil] := 'CEIL';
FSQLSpecifities[spFuncLeft] := 'SUBSTR(%s, 1, %d)'; FSQLSpecifities[spFuncLeft] := 'SUBSTR(%s, 1, %d)';
FSQLSpecifities[spFuncNow] := 'DATETIME()'; FSQLSpecifities[spFuncNow] := 'DATETIME()';
FSQLSpecifities[spFuncLastAutoIncNumber] := 'LAST_INSERT_ID()';
FSQLSpecifities[spLockedTables] := ''; FSQLSpecifities[spLockedTables] := '';
FSQLSpecifities[spDisableForeignKeyChecks] := ''; FSQLSpecifities[spDisableForeignKeyChecks] := '';
FSQLSpecifities[spEnableForeignKeyChecks] := ''; FSQLSpecifities[spEnableForeignKeyChecks] := '';
@ -3170,6 +3175,7 @@ begin
FSQLSpecifities[spFuncCeil] := 'CEIL'; FSQLSpecifities[spFuncCeil] := 'CEIL';
FSQLSpecifities[spFuncLeft] := 'SUBSTR(%s, 1, %d)'; FSQLSpecifities[spFuncLeft] := 'SUBSTR(%s, 1, %d)';
FSQLSpecifities[spFuncNow] := ' cast(''now'' as timestamp) from rdb$database'; FSQLSpecifities[spFuncNow] := ' cast(''now'' as timestamp) from rdb$database';
FSQLSpecifities[spFuncLastAutoIncNumber] := 'LAST_INSERT_ID()';
FSQLSpecifities[spLockedTables] := ''; FSQLSpecifities[spLockedTables] := '';
FSQLSpecifities[spDisableForeignKeyChecks] := ''; FSQLSpecifities[spDisableForeignKeyChecks] := '';
FSQLSpecifities[spEnableForeignKeyChecks] := ''; FSQLSpecifities[spEnableForeignKeyChecks] := '';
@ -5605,6 +5611,9 @@ begin
// from an expression: // from an expression:
Result := not Value.Contains('('); Result := not Value.Contains('(');
end; end;
end else if FParameters.IsAnyPostgreSQL then begin
// text only if starting with '
Result := Value.StartsWith('''');
end else begin end else begin
// MS SQL, PG and SQLite: // MS SQL, PG and SQLite:
Result := True; Result := True;
@ -5684,20 +5693,30 @@ begin
DefText := ColQuery.Col('COLUMN_DEFAULT'); DefText := ColQuery.Col('COLUMN_DEFAULT');
Col.OnUpdateType := cdtNothing; Col.OnUpdateType := cdtNothing;
if ExecRegExpr('\bauto_increment\b', ExtraText.ToLowerInvariant) then begin if ColQuery.Col('COLUMN_DEFAULT').StartsWith('nextval(', True) then begin
// PG auto increment
Col.DefaultType := cdtAutoInc; Col.DefaultType := cdtAutoInc;
Col.DefaultText := 'AUTO_INCREMENT'; Col.DefaultText := ColQuery.Col('COLUMN_DEFAULT');
end else if DefText.ToLowerInvariant = 'null' then begin end
else if ExecRegExpr('\bauto_increment\b', ExtraText.ToLowerInvariant) then begin
// MySQL auto increment
Col.DefaultType := cdtAutoInc;
Col.DefaultText := Col.AutoIncName;
end
else if DefText.ToLowerInvariant = 'null' then begin
Col.DefaultType := cdtNull; Col.DefaultType := cdtNull;
end else if ColQuery.IsNull('COLUMN_DEFAULT') then begin end
else if ColQuery.IsNull('COLUMN_DEFAULT') then begin
if Col.AllowNull then if Col.AllowNull then
Col.DefaultType := cdtNull Col.DefaultType := cdtNull
else else
Col.DefaultType := cdtNothing; Col.DefaultType := cdtNothing;
end else if IsTextDefault(DefText, Col.DataType) then begin end
else if IsTextDefault(DefText, Col.DataType) then begin
Col.DefaultType := cdtText; Col.DefaultType := cdtText;
Col.DefaultText := IfThen(DefText.StartsWith(''''), ExtractLiteral(DefText, ''), DefText); Col.DefaultText := IfThen(DefText.StartsWith(''''), ExtractLiteral(DefText, ''), DefText);
end else begin end
else begin
Col.DefaultType := cdtExpression; Col.DefaultType := cdtExpression;
Col.DefaultText := DefText; Col.DefaultText := DefText;
end; end;
@ -5770,7 +5789,7 @@ begin
Col.OnUpdateType := cdtNothing; Col.OnUpdateType := cdtNothing;
if ExecRegExpr('^auto_increment$', ExtraText.ToLowerInvariant) then begin if ExecRegExpr('^auto_increment$', ExtraText.ToLowerInvariant) then begin
Col.DefaultType := cdtAutoInc; Col.DefaultType := cdtAutoInc;
Col.DefaultText := 'AUTO_INCREMENT'; Col.DefaultText := Col.AutoIncName;
end else if ColQuery.IsNull('Default') then begin end else if ColQuery.IsNull('Default') then begin
Col.DefaultType := cdtNothing; Col.DefaultType := cdtNothing;
end else if IsTextDefault(DefText, Col.DataType) then begin end else if IsTextDefault(DefText, Col.DataType) then begin
@ -9545,7 +9564,7 @@ begin
if Assigned(ColAttr) and (ColAttr.DefaultType = cdtAutoInc) then begin if Assigned(ColAttr) and (ColAttr.DefaultType = cdtAutoInc) then begin
Row[i].NewText := UnformatNumber(Row[i].NewText); Row[i].NewText := UnformatNumber(Row[i].NewText);
if Row[i].NewText = '0' then if Row[i].NewText = '0' then
Row[i].NewText := Connection.GetVar('SELECT LAST_INSERT_ID()'); Row[i].NewText := Connection.GetVar('SELECT ' + Connection.GetSQLSpecifity(spFuncLastAutoIncNumber));
Row[i].NewIsNull := False; Row[i].NewIsNull := False;
break; break;
end; end;
@ -10500,7 +10519,16 @@ begin
end; end;
if InParts(cpType) then begin if InParts(cpType) then begin
Result := Result + DataType.Name; case FConnection.Parameters.NetTypeGroup of
ngPgSQL: begin
if DefaultType = cdtAutoInc then
Result := Result + 'SERIAL'
else
Result := Result + DataType.Name;
end;
else Result := Result + DataType.Name;
end;
if (LengthSet <> '') and DataType.HasLength then if (LengthSet <> '') and DataType.HasLength then
Result := Result + '(' + LengthSet + ')'; Result := Result + '(' + LengthSet + ')';
if (DataType.Category in [dtcInteger, dtcReal]) and Unsigned then if (DataType.Category in [dtcInteger, dtcReal]) and Unsigned then
@ -10523,7 +10551,12 @@ begin
// cdtNothing: leave out whole clause // cdtNothing: leave out whole clause
cdtText: Result := Result + 'DEFAULT '+FConnection.EscapeString(DefaultText); cdtText: Result := Result + 'DEFAULT '+FConnection.EscapeString(DefaultText);
cdtNull: Result := Result + 'DEFAULT NULL'; cdtNull: Result := Result + 'DEFAULT NULL';
cdtAutoInc: Result := Result + 'AUTO_INCREMENT'; cdtAutoInc: begin
case FConnection.Parameters.NetTypeGroup of
ngPgSQL:;
else Result := Result + AutoIncName;
end;
end;
cdtExpression: begin cdtExpression: begin
if FConnection.Parameters.IsMySQL(True) and (FConnection.ServerVersionInt >= 80013) then if FConnection.Parameters.IsMySQL(True) and (FConnection.ServerVersionInt >= 80013) then
Result := Result + 'DEFAULT ('+DefaultText+')' Result := Result + 'DEFAULT ('+DefaultText+')'
@ -10631,6 +10664,16 @@ begin
end; end;
end; end;
function TTableColumn.AutoIncName: String;
begin
case FConnection.Parameters.NetTypeGroup of
ngPgSQL: Result := 'SERIAL';
else Result := 'AUTO_INCREMENT';
end;
end;
procedure TTableColumnList.Assign(Source: TTableColumnList); procedure TTableColumnList.Assign(Source: TTableColumnList);
var var
Item, ItemCopy: TTableColumn; Item, ItemCopy: TTableColumn;

View File

@ -1358,7 +1358,7 @@ begin
FRadioAutoInc.Width := FRadioAutoInc.Parent.Width - 2 * FRadioAutoInc.Left; FRadioAutoInc.Width := FRadioAutoInc.Parent.Width - 2 * FRadioAutoInc.Left;
FRadioAutoInc.OnClick := RadioClick; FRadioAutoInc.OnClick := RadioClick;
FRadioAutoInc.OnKeyDown := DoKeyDown; FRadioAutoInc.OnKeyDown := DoKeyDown;
FRadioAutoInc.Caption := 'AUTO_INCREMENT'; FRadioAutoInc.Caption := Col.AutoIncName;
FBtnOk := TButton.Create(FPanel); FBtnOk := TButton.Create(FPanel);
FBtnOk.Parent := FPanel; FBtnOk.Parent := FPanel;
@ -1522,7 +1522,7 @@ begin
cdtText: Col.DefaultText := FTextEdit.Text; cdtText: Col.DefaultText := FTextEdit.Text;
cdtNull: Col.DefaultText := 'NULL'; cdtNull: Col.DefaultText := 'NULL';
cdtExpression: Col.DefaultText := FExpressionEdit.Text; cdtExpression: Col.DefaultText := FExpressionEdit.Text;
cdtAutoInc: Col.DefaultText := 'AUTO_INCREMENT'; cdtAutoInc: Col.DefaultText := Col.AutoIncName;
end; end;
if FOnUpdateEdit.Text <> '' then if FOnUpdateEdit.Text <> '' then

View File

@ -1297,7 +1297,7 @@ begin
cdtText: CellText := Col.Connection.EscapeString(Col.DefaultText); cdtText: CellText := Col.Connection.EscapeString(Col.DefaultText);
cdtNull: CellText := 'NULL'; cdtNull: CellText := 'NULL';
cdtExpression: CellText := Col.DefaultText; cdtExpression: CellText := Col.DefaultText;
cdtAutoInc: CellText := 'AUTO_INCREMENT'; cdtAutoInc: CellText := Col.AutoIncName;
end; end;
case Col.OnUpdateType of case Col.OnUpdateType of
// cdtNothing: leave clause away // cdtNothing: leave clause away