Fix non working addition of new columns in MySQL. See http://www.heidisql.com/forum.php?t=16948

PostgreSQL: Detect all array style types as unknown type, e.g. TEXT[].
This commit is contained in:
Ansgar Becker
2014-11-14 17:09:08 +00:00
parent 0d61d18261
commit aa6ed7d9dd
4 changed files with 80 additions and 55 deletions

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: HeidiSQL\n"
"POT-Creation-Date: 2012-11-05 21:40\n"
"PO-Revision-Date: 2014-11-13 19:40+0100\n"
"PO-Revision-Date: 2014-11-14 18:02+0100\n"
"Last-Translator: Ansgar Becker <anse@heidisql.com>\n"
"Language-Team: English (http://www.transifex.com/projects/p/heidisql/"
"language/en/)\n"
@ -5818,3 +5818,11 @@ msgstr "Unknown datatype oid #%d. Fall back to %s."
#. Error happening when facing unknown native data types, mainly in PostgreSQL tables and routines. Name of column or argument passed here as a hint for the user.
msgid "Unknown datatype oid #%d for \"%s\". Fall back to %s."
msgstr "Unknown datatype oid #%d for \"%s\". Fall back to %s."
#. Error happening when facing unknown named data types.
msgid "Unknown datatype \"%s\" for \"%s\". Fall back to %s."
msgstr "Unknown datatype \"%s\" for \"%s\". Fall back to %s."
#. Error happening when facing unknown named data types. Name of column or argument passed here as a hint for the user.
msgid "Unknown datatype \"%s\". Fall back to %s."
msgstr "Unknown datatype \"%s\". Fall back to %s."

View File

@ -347,7 +347,6 @@ type
function ExtractIdentifier(var SQL: String): String;
procedure ClearCache(IncludeDBObjects: Boolean);
procedure FetchDbObjects(db: String; var Cache: TDBObjectList); virtual; abstract;
function NativeToNamedColumnType(NativeType: Integer; Identifier: String=''): TDBDatatype;
procedure SetObjectNamesInSelectedDB;
procedure SetLockedByThread(Value: TThread); virtual;
procedure KeepAliveTimerEvent(Sender: TObject);
@ -387,7 +386,8 @@ type
procedure ParseViewStructure(CreateCode: String; DBObj: TDBObject; Columns: TTableColumnList;
var Algorithm, Definer, SQLSecurity, CheckOption, SelectCode: String);
procedure ParseRoutineStructure(Obj: TDBObject; Parameters: TRoutineParamList);
function GetDatatypeByName(var DataType: String; DeleteFromSource: Boolean): TDBDatatype;
function GetDatatypeByName(var DataType: String; DeleteFromSource: Boolean; Identifier: String=''): TDBDatatype;
function GetDatatypeByNativeType(NativeType: Integer; Identifier: String=''): TDBDatatype;
function ApplyLimitClause(QueryType, QueryBody: String; Limit, Offset: Int64): String;
function LikeClauseTail: String;
property Parameters: TConnectionParameters read FParameters write FParameters;
@ -1428,12 +1428,12 @@ begin
end;
function TDBConnection.GetDatatypeByName(var DataType: String; DeleteFromSource: Boolean): TDBDatatype;
function TDBConnection.GetDatatypeByName(var DataType: String; DeleteFromSource: Boolean; Identifier: String=''): TDBDatatype;
var
i: Integer;
Match: Boolean;
rx: TRegExpr;
Types: String;
Types, tmp: String;
begin
rx := TRegExpr.Create;
rx.ModifierI := True;
@ -1442,18 +1442,62 @@ begin
Types := FDatatypes[i].Name;
if FDatatypes[i].Names <> '' then
Types := Types + '|' + FDatatypes[i].Names;
rx.Expression := '^(\"?)('+Types+')(\"?)(\s|\()';
Match := rx.Exec(Datatype);
rx.Expression := '^('+Types+')\b(\[\])?';
Match := rx.Exec(DataType);
if Match then begin
if (FParameters.NetTypeGroup = ngPgSQL) and (rx.MatchLen[2] > 0) then begin
// TODO: detect array style datatypes, e.g. TEXT[]
end else begin
if DeleteFromSource then
Delete(DataType, 1, rx.MatchLen[1]+rx.MatchLen[2]+rx.MatchLen[3]);
Delete(DataType, 1, rx.MatchLen[1]);
Result := FDatatypes[i];
break;
end;
end;
end;
if (not Match) and (FParameters.NetTypeGroup = ngPgSQL) then begin
// Fall back to unknown type
Result := Datatypes[0];
rx.Expression := '^(\S+)';
if rx.Exec(DataType) then
tmp := rx.Match[1]
else
tmp := DataType;
if Identifier <> '' then
Log(lcError, f_('Unknown datatype "%s" for "%s". Fall back to %s.', [tmp, Identifier, Result.Name]))
else
Log(lcError, f_('Unknown datatype "%s". Fall back to %s.', [tmp, Result.Name]));
end;
rx.Free;
if (not Match) and (FParameters.NetTypeGroup = ngPgSQL) then
Result := FDatatypes[0];
end;
function TDBConnection.GetDatatypeByNativeType(NativeType: Integer; Identifier: String=''): TDBDatatype;
var
i: Integer;
rx: TRegExpr;
TypeFound: Boolean;
begin
rx := TRegExpr.Create;
TypeFound := False;
for i:=0 to High(Datatypes) do begin
if Datatypes[i].NativeTypes = '' then
Continue;
rx.Expression := '\b('+Datatypes[i].NativeTypes+')\b';
if rx.Exec(IntToStr(NativeType)) then begin
Result := Datatypes[i];
TypeFound := True;
break;
end;
end;
if not TypeFound then begin
// Fall back to unknown type
Result := Datatypes[0];
if Identifier <> '' then
Log(lcError, f_('Unknown datatype oid #%d for "%s". Fall back to %s.', [NativeType, Identifier, Result.Name]))
else
Log(lcError, f_('Unknown datatype oid #%d. Fall back to %s.', [NativeType, Result.Name]));
end;
end;
@ -2537,7 +2581,7 @@ end;
function TDBConnection.GetCreateCode(Database, Schema, Name: String; NodeType: TListNodeType): String;
var
Cols, Keys, ProcDetails: TDBQuery;
ConstraintName, MaxLen, ArgDataType: String;
ConstraintName, MaxLen, DataType: String;
ColNames, ArgNames, ArgTypes, Arguments: TStringList;
Rows: TStringList;
i: Integer;
@ -2563,7 +2607,7 @@ begin
Cols := GetResults('SELECT '+
' DISTINCT a.attname AS column_name, '+
' a.attnum, '+
' a.atttypid, '+ // Data type oid. See NativeToNamedColumnType()
' a.atttypid, '+ // Data type oid. See GetDatatypeByNativeType()
' FORMAT_TYPE(a.atttypid, a.atttypmod) AS data_type, '+
' CASE a.attnotnull WHEN false THEN '+EscapeString('YES')+' ELSE '+EscapeString('NO')+' END AS IS_NULLABLE, '+
' com.description AS column_comment, '+
@ -2592,7 +2636,9 @@ begin
while not Cols.Eof do begin
if Cols.ColExists('atttypid') then
Log(lcDebug, 'Column "'+Cols.Col('COLUMN_NAME')+'" => oid #'+Cols.Col('atttypid'));
Result := Result + CRLF + #9 + QuoteIdent(Cols.Col('COLUMN_NAME')) + ' ' + UpperCase(Cols.Col('DATA_TYPE'));
DataType := Cols.Col('DATA_TYPE');
DataType := DataType.ToUpper.DeQuotedString('"');
Result := Result + CRLF + #9 + QuoteIdent(Cols.Col('COLUMN_NAME')) + ' ' + DataType;
if not Cols.IsNull('CHARACTER_MAXIMUM_LENGTH') then begin
MaxLen := Cols.Col('CHARACTER_MAXIMUM_LENGTH');
if MaxLen = '-1' then
@ -2724,13 +2770,13 @@ begin
Arguments := TStringList.Create;
for i:=0 to ArgNames.Count-1 do begin
if ArgTypes.Count > i then
ArgDataType := NativeToNamedColumnType(MakeInt(ArgTypes[i]), ArgNames[i]).Name
DataType := GetDatatypeByNativeType(MakeInt(ArgTypes[i]), ArgNames[i]).Name
else
ArgDataType := '';
Arguments.Add(ArgNames[i] + ' ' + ArgDataType);
DataType := '';
Arguments.Add(ArgNames[i] + ' ' + DataType);
end;
Result := Result + '(' + implodestr(', ', Arguments) + ') '+
'RETURNS '+NativeToNamedColumnType(MakeInt(ProcDetails.Col('prorettype'))).Name+' '+
'RETURNS '+GetDatatypeByNativeType(MakeInt(ProcDetails.Col('prorettype'))).Name+' '+
'AS $$ '+ProcDetails.Col('prosrc')+' $$'
// TODO: 'LANGUAGE SQL IMMUTABLE STRICT'
;
@ -4246,35 +4292,6 @@ begin
end;
function TDBConnection.NativeToNamedColumnType(NativeType: Integer; Identifier: String=''): TDBDatatype;
var
i: Integer;
rx: TRegExpr;
TypeFound: Boolean;
begin
rx := TRegExpr.Create;
TypeFound := False;
for i:=0 to High(Datatypes) do begin
if Datatypes[i].NativeTypes = '' then
Continue;
rx.Expression := '\b('+Datatypes[i].NativeTypes+')\b';
if rx.Exec(IntToStr(NativeType)) then begin
Result := Datatypes[i];
TypeFound := True;
break;
end;
end;
if not TypeFound then begin
// Fall back to unknown type
Result := Datatypes[0];
if Identifier <> '' then
Log(lcError, f_('Unknown datatype oid #%d for "%s". Fall back to %s.', [NativeType, Identifier, Result.Name]))
else
Log(lcError, f_('Unknown datatype oid #%d. Fall back to %s.', [NativeType, Result.Name]));
end;
end;
procedure TDBConnection.SetObjectNamesInSelectedDB;
var
i: Integer;
@ -4476,7 +4493,7 @@ begin
Col.LengthCustomized := False;
// Datatype
Col.DataType := GetDatatypeByName(ColSpec, True);
Col.DataType := GetDatatypeByName(ColSpec, True, Col.Name);
Col.OldDataType := Col.DataType;
// Length / Set
@ -4726,7 +4743,7 @@ begin
Col.Name := Results.Col('COLUMN_NAME');
Col.AllowNull := UpperCase(Results.Col('IS_NULLABLE')) = 'YES';
DataType := Results.Col('DATA_TYPE');
Col.DataType := GetDatatypeByName(DataType, False);
Col.DataType := GetDatatypeByName(DataType, False, Col.Name);
if Results.ColExists('COLUMN_TYPE') then begin
// Use MySQL's proprietary column_type - the only way to get SET and ENUM values
if rx.Exec(Results.Col('COLUMN_TYPE')) then begin
@ -5241,7 +5258,7 @@ begin
FColumnOrgNames.Add(FColumnNames[FColumnNames.Count-1]);
FieldTypeOID := PQftype(LastResult, i);
TypeFound := False;
FColumnTypes[i] := FConnection.NativeToNamedColumnType(FieldTypeOID, FColumnNames[FColumnNames.Count-1]);
FColumnTypes[i] := FConnection.GetDatatypeByNativeType(FieldTypeOID, FColumnNames[FColumnNames.Count-1]);
end;
rx.Free;
FRecNo := -1;

View File

@ -1505,7 +1505,7 @@ begin
FTreeSelect.Font.Size := FCellFont.Size;
// Find and select current datatype in tree
dt := FTableColumn.Connection.GetDataTypeByName(FCellText, False);
dt := FTableColumn.Connection.GetDataTypeByName(FCellText, False, FTableColumn.Name);
CatNode := FTreeSelect.GetFirst;
while Assigned(CatNode) do begin
// Since recent update to VT 5.2.1 we need to initialize root nodes by hand for some reason:
@ -1629,7 +1629,7 @@ begin
FMemoHelp.Width := Min(250, FTreeSelect.Left);
FMemoHelp.Left := FTreeSelect.Left - FMemoHelp.Width + (Integer(FTreeSelect.Indent) Div 2);
FMemoHelp.Top := FTreeSelect.Top + R.Top + 3;
FMemoHelp.Text := FTableColumn.Connection.GetDatatypeByName(NodeText, False).Description;
FMemoHelp.Text := FTableColumn.Connection.GetDatatypeByName(NodeText, False, FTableColumn.Name).Description;
// Calc height of memo
bmp := TBitMap.Create;
bmp.Canvas.Font.Assign(FMemoHelp.Font);

View File

@ -1190,7 +1190,7 @@ begin
Col.Name := NewText;
end;
2: begin // Data type
Col.DataType := DBObject.Connection.GetDatatypeByName(NewText, False);
Col.DataType := DBObject.Connection.GetDatatypeByName(NewText, False, Col.Name);
// Reset length/set for column types which don't support that
if not Col.DataType.HasLength then
Col.LengthSet := '';