Add a toolbar button which, when pressed, allows BLOBs to be displayed as text. Explicitly ignoring weird effects in grid updates/inserts. Fixes issue #1624.

This commit is contained in:
Ansgar Becker
2010-01-30 07:57:07 +00:00
parent 7d98420602
commit efbf7a0b98
6 changed files with 102 additions and 28 deletions

View File

@ -99,6 +99,8 @@ const
REGNAME_QUERYHELPERSWIDTH = 'queryhelperswidth';
REGNAME_STOPONERRORSINBATCH = 'StopOnErrorsInBatchMode';
DEFAULT_STOPONERRORSINBATCH = True;
REGNAME_BLOBASTEXT = 'DisplayBLOBsAsText';
DEFAULT_BLOBASTEXT = False;
REGNAME_EDITOR_WIDTH = 'MemoEditorWidth';
DEFAULT_EDITOR_WIDTH = 100;
REGNAME_EDITOR_HEIGHT = 'MemoEditorHeight';

View File

@ -986,7 +986,8 @@ begin
Continue;
Data := GridData.Columns[i].Name;
// Alter column name in header if data is not raw.
if GridData.Columns[i].DatatypeCat = dtcBinary then Data := 'HEX(' + Data + ')';
if (GridData.Columns[i].DatatypeCat = dtcBinary) and (not Mainform.actBlobAsText.Checked) then
Data := 'HEX(' + Data + ')';
// Add header item.
if tmp <> '' then tmp := tmp + Separator;
tmp := tmp + Encloser + Data + Encloser;
@ -1010,7 +1011,8 @@ begin
Continue;
Data := Grid.Text[Node, i];
// Remove 0x.
if GridData.Columns[i].DatatypeCat = dtcBinary then Delete(Data, 1, 2);
if (GridData.Columns[i].DatatypeCat = dtcBinary) and (not Mainform.actBlobAsText.Checked) then
Delete(Data, 1, 2);
// Unformat numeric values
if (GridData.Columns[i].DatatypeCat in [dtcInteger, dtcReal]) and (not Mainform.prefExportLocaleNumbers) then
Data := UnformatNumber(Data);
@ -1093,11 +1095,13 @@ begin
tmp := tmp + #9#9'<' + Grid.Header.Columns[i].Text;
if GridData.Rows[Node.Index].Cells[i].IsNull then tmp := tmp + ' isnull="true" />' + CRLF
else begin
if GridData.Columns[i].DatatypeCat = dtcBinary then tmp := tmp + ' format="hex"';
if (GridData.Columns[i].DatatypeCat = dtcBinary) and (not Mainform.actBlobAsText.Checked) then
tmp := tmp + ' format="hex"';
tmp := tmp + '>';
Data := Grid.Text[Node, i];
// Remove 0x.
if GridData.Columns[i].DatatypeCat = dtcBinary then Delete(Data, 1, 2);
if (GridData.Columns[i].DatatypeCat = dtcBinary) and (not Mainform.actBlobAsText.Checked) then
Delete(Data, 1, 2);
// Unformat numeric values
if (GridData.Columns[i].DatatypeCat in [dtcInteger, dtcReal]) and (not Mainform.prefExportLocaleNumbers) then
Data := UnformatNumber(Data);
@ -1184,7 +1188,8 @@ begin
else begin
Data := Grid.Text[Node, i];
// Remove 0x.
if GridData.Columns[i].DatatypeCat = dtcBinary then Delete(Data, 1, 2);
if (GridData.Columns[i].DatatypeCat = dtcBinary) and (not Mainform.actBlobAsText.Checked) then
Delete(Data, 1, 2);
// Unformat numeric values
if GridData.Columns[i].DatatypeCat in [dtcInteger, dtcReal] then
tmp := tmp + UnformatNumber(Data)

View File

@ -252,7 +252,7 @@ object MainForm: TMainForm
object ToolBarQuery: TToolBar
Left = 494
Top = 2
Width = 243
Width = 268
Height = 22
Align = alNone
AutoSize = True
@ -304,13 +304,18 @@ object MainForm: TMainForm
Top = 0
Action = actQueryStopOnErrors
end
object btnBlobAsText: TToolButton
Left = 199
Top = 0
Action = actBlobAsText
end
object btnQueryWordwrap: TToolButton
Left = 197
Left = 222
Top = 0
Action = actQueryWordWrap
end
object btnSetDelimiter: TToolButton
Left = 220
Left = 245
Top = 0
Action = actSetDelimiter
end
@ -2290,6 +2295,14 @@ object MainForm: TMainForm
ShortCut = 16503
OnExecute = actReformatSQLExecute
end
object actBlobAsText: TAction
Category = 'Data'
AutoCheck = True
Caption = 'View binary data as text (instead of HEX)'
Hint = 'View binary data as text (instead of HEX)'
ImageIndex = 141
OnExecute = actBlobAsTextExecute
end
end
object SaveDialog2: TSaveDialog
DefaultExt = 'reg'
@ -6196,6 +6209,28 @@ object MainForm: TMainForm
D071B9192663E11631D90D5EAFD79F208009C672CFAAF24282114419A248F75E
2627C13AF8E0CC1BFB6BEBD07FAE35DDF92001CCFD01229E70157CD3A2DA0000
000049454E44AE426082}
end
item
Background = clWindow
Name = 'page_white_text_hex'
PngImage.Data = {
89504E470D0A1A0A0000000D49484452000000100000001008060000001FF3FF
610000001974455874536F667477617265005061696E742E4E45542076332E35
2E32D7EE6943000001BF4944415478DA85934D48025110C7673F72430841C12E
75EA5474CABE5B254FD1AD4B089E8A0E520A1174EAE35479953C75B08B201481
509708F2D0E75A128174C953D62DEFA1BBBAF6E6B56F59C1B5816186B7F3FFCD
BCDD1D0EFEAC8F782F71013ADB37F14FE23A3BE08CE8AB56AB3941107A388EE3
DB29EBF53AA452A9642C164B58210C30AE699A52ABD578026811E9BA0EAAAA82
C7E3814AA502D96C36198D464D086740C648F1138100CFF354C4008D468302DC
6E378DF82C93C924239108423E5A0058AC280A2D444720F35028D47225511427
4828B4009ACD26B02B608E40749C0421D81D73AFD7DB1E80C242A1408BB110A7
60D740474030180497CB650F60B627CED0B8A3DD9B628C3899D3E9B407148B45
381F5985B9C704155CFB3721908B53214264590687C3D17902ECBE5B7F30739C
62BF4B86ADDA2DC4A5007D660B28954A703AB40C0BAF47B4E3856F0DE6F38770
39B94EA7BA9ADEE80CB07645C3CEDBEA1DCD0F1C7E9AE3BF620B2897CB901E08
43F83D4D2738195C82C5B763381B5E31A3DD0479CBAF6D7E05EBBBC0DC883A01
4C91E3672618257B704396A99BE46D97C9623AF93A3F9224CD92FC8501FA8D75
FE4FCCAC61ACF6D72F62B02F294EFE3B9F0000000049454E44AE426082}
end>
PngOptions = [pngBlendOnDisabled, pngGrayscaleOnDisabled]
Left = 104

View File

@ -452,6 +452,8 @@ type
ReformatSQL2: TMenuItem;
menuQueryInsertFunction: TMenuItem;
menuFilterInsertFunction: TMenuItem;
actBlobAsText: TAction;
btnBlobAsText: TToolButton;
procedure refreshMonitorConfig;
procedure loadWindowConfig;
procedure saveWindowConfig;
@ -719,6 +721,7 @@ type
procedure DBtreeFocusChanging(Sender: TBaseVirtualTree; OldNode,
NewNode: PVirtualNode; OldColumn, NewColumn: TColumnIndex;
var Allowed: Boolean);
procedure actBlobAsTextExecute(Sender: TObject);
private
ReachedEOT: Boolean;
FDelimiter: String;
@ -755,6 +758,7 @@ type
procedure SaveQueryMemo(Tab: TQueryTab; Filename: String; OnlySelection: Boolean);
procedure UpdateFilterPanel(Sender: TObject);
procedure DatabaseChanged(Database: String);
function GetBlobContent(Results: TMySQLQuery; Column: Integer): String;
public
Connection: TMySQLConnection;
SessionName: String;
@ -1100,6 +1104,7 @@ begin
MainReg.WriteInteger(REGNAME_TOOLBARQUERYLEFT, ToolBarQuery.Left);
MainReg.WriteInteger(REGNAME_TOOLBARQUERYTOP, ToolBarQuery.Top);
MainReg.WriteBool(REGNAME_STOPONERRORSINBATCH, actQueryStopOnErrors.Checked);
MainReg.WriteBool(REGNAME_BLOBASTEXT, actBlobAsText.Checked);
// Save delimiter
MainReg.WriteString( REGNAME_DELIMITER, Delimiter );
@ -1241,6 +1246,7 @@ begin
ToolBarQuery.Left := GetRegValue(REGNAME_TOOLBARQUERYLEFT, ToolBarQuery.Left);
ToolBarQuery.Top := GetRegValue(REGNAME_TOOLBARQUERYTOP, ToolBarQuery.Top);
actQueryStopOnErrors.Checked := GetRegValue(REGNAME_STOPONERRORSINBATCH, DEFAULT_STOPONERRORSINBATCH);
actBlobAsText.Checked := GetRegValue(REGNAME_BLOBASTEXT, DEFAULT_BLOBASTEXT);
pnlQueryMemo.Height := GetRegValue(REGNAME_QUERYMEMOHEIGHT, pnlQueryMemo.Height);
pnlQueryHelpers.Width := GetRegValue(REGNAME_QUERYHELPERSWIDTH, pnlQueryHelpers.Width);
@ -3935,7 +3941,7 @@ begin
for j:=0 to Results.ColumnCount-1 do begin
case ActiveGridResult.Columns[j].DatatypeCat of
dtcInteger, dtcReal: ActiveGridResult.Rows[i].Cells[j].Text := FormatNumber(Results.Col(j), False);
dtcBinary: ActiveGridResult.Rows[i].Cells[j].Text := '0x' + Results.BinColAsHex(j);
dtcBinary: ActiveGridResult.Rows[i].Cells[j].Text := GetBlobContent(Results, j);
else ActiveGridResult.Rows[i].Cells[j].Text := Results.Col(j);
end;
ActiveGridResult.Rows[i].Cells[j].IsNull := Results.IsNull(j);
@ -6443,7 +6449,7 @@ begin
for j := 0 to Results.ColumnCount - 1 do begin
case res.Columns[j].DatatypeCat of
dtcInteger, dtcReal: res.Rows[i].Cells[j].Text := FormatNumber(Results.Col(j), False);
dtcBinary: res.Rows[i].Cells[j].Text := '0x' + Results.BinColAsHex(j);
dtcBinary: res.Rows[i].Cells[j].Text := GetBlobContent(Results, j);
else res.Rows[i].Cells[j].Text := Results.Col(j);
end;
res.Rows[i].Cells[j].IsNull := Results.IsNull(j);
@ -6519,7 +6525,7 @@ begin
for j:=0 to Results.ColumnCount-1 do begin
case res.Columns[j].DatatypeCat of
dtcInteger, dtcReal: res.Rows[i].Cells[j].Text := FormatNumber(Results.Col(j), False);
dtcBinary: res.Rows[i].Cells[j].Text := '0x' + Results.BinColAsHex(j);
dtcBinary: res.Rows[i].Cells[j].Text := GetBlobContent(Results, j);
else res.Rows[i].Cells[j].Text := Results.Col(j);
end;
res.Rows[i].Cells[j].IsNull := Results.IsNull(j);
@ -6812,8 +6818,13 @@ begin
case DataGridResult.Columns[i].DatatypeCat of
dtcInteger, dtcReal: Val := UnformatNumber(Val);
dtcBinary: begin
CheckHex(Copy(Val, 3), 'Invalid hexadecimal string given in field "' + DataGridResult.Columns[i].Name + '".');
if Val = '0x' then Val := esc('');
if actBlobAsText.Checked then
Val := esc(Val)
else begin
CheckHex(Copy(Val, 3), 'Invalid hexadecimal string given in field "' + DataGridResult.Columns[i].Name + '".');
if Val = '0x' then
Val := esc('');
end;
end;
else Val := esc(Val);
end;
@ -6901,7 +6912,12 @@ begin
// Quote if needed
case DataGridResult.Columns[j].DatatypeCat of
dtcInteger, dtcReal: KeyVal := UnformatNumber(KeyVal);
dtcBinary: if KeyVal = '0x' then KeyVal := esc('');
dtcBinary: begin
if actBlobAsText.Checked then
KeyVal := esc(KeyVal)
else if KeyVal = '0x' then
KeyVal := esc('');
end
else KeyVal := esc(KeyVal);
end;
@ -7022,9 +7038,13 @@ begin
case DataGridResult.Columns[i].DatatypeCat of
dtcInteger, dtcReal: Val := UnformatNumber(Val);
dtcBinary: begin
CheckHex(Copy(Val, 3), 'Invalid hexadecimal string given in field "' + DataGridResult.Columns[i].Name + '".');
if Val = '0x' then
Val := esc('');
if actBlobAsText.Checked then
Val := esc(Val)
else begin
CheckHex(Copy(Val, 3), 'Invalid hexadecimal string given in field "' + DataGridResult.Columns[i].Name + '".');
if Val = '0x' then
Val := esc('');
end;
end;
else Val := esc(Val);
end;
@ -7209,7 +7229,7 @@ begin
Cell := @DataGridResult.Rows[Node.Index].Cells[Column];
len := Length(Cell.Text);
// Recalculate due to textual formatting of raw binary data.
if (Col.DatatypeCat = dtcBinary) and (len > 2) then len := (len - 2) div 2;
if (Col.DatatypeCat = dtcBinary) and (not actBlobAsText.Checked) and (len > 2) then len := (len - 2) div 2;
// Assume width limit in effect if data exactly at limit threshold.
if len = GridMaxData then begin
if CheckUniqueKeyClause then begin
@ -7221,7 +7241,7 @@ begin
Results := Connection.GetResults(sql);
case Col.DatatypeCat of
dtcInteger, dtcReal: Cell.Text := FormatNumber(Results.Col(0), False);
dtcBinary: Cell.Text := '0x' + Results.BinColAsHex(0);
dtcBinary: Cell.Text := GetBlobContent(Results, 0);
else Cell.Text := Results.Col(0);
end;
Cell.IsNull := Results.IsNull(0);
@ -7275,7 +7295,7 @@ var
begin
VT := Sender as TVirtualStringTree;
TypeCat := DataGridResult.Columns[Column].DatatypeCat;
if TypeCat = dtcText then begin
if (TypeCat = dtcText) or ((TypeCat = dtcBinary) and actBlobAsText.Checked) then begin
InplaceEditor := TInplaceEditorLink.Create(VT);
InplaceEditor.DataType := DataGridResult.Columns[Column].Datatype;
InplaceEditor.MaxLength := DataGridResult.Columns[Column].MaxLength;
@ -9111,5 +9131,21 @@ begin
end;
procedure TMainForm.actBlobAsTextExecute(Sender: TObject);
begin
// Activate displaying BLOBs as text data, ignoring possible weird effects in grid updates/inserts
if PageControlMain.ActivePage = tabData then
viewdata(Sender);
end;
function TMainForm.GetBlobContent(Results: TMySQLQuery; Column: Integer): String;
begin
if actBlobAsText.Checked then
Result := Results.Col(Column)
else
Result := '0x' + Results.BinColAsHex(Column);
end;
end.

View File

@ -1199,14 +1199,10 @@ end;
function TMySQLQuery.Col(Column: Integer; IgnoreErrors: Boolean=False): String;
begin
if (Column > -1) and (Column < ColumnCount) then begin
if FDatatypes[Column].Category = dtcBinary then
Raise Exception.CreateFmt('Column "%s" has binary collation. Please use BinColAsHex() instead Col().', [FColumnNames[Column]])
else begin
if Connection.IsUnicode then
Result := UTF8ToString(FCurrentRow[Column])
else
Result := String(FCurrentRow[Column]);
end;
if Connection.IsUnicode then
Result := UTF8ToString(FCurrentRow[Column])
else
Result := String(FCurrentRow[Column]);
end else if not IgnoreErrors then
Raise Exception.CreateFmt('Column #%d not available. Query returned %d columns and %d rows.', [Column, ColumnCount, RecordCount]);
end;