Modify identifier quoting logic:

- Move QuoteIdent() and DeQuoteIdent() out of TMySQLConnection, make them classless
- Remove TMainForm.mask(), instead always use QuoteIdent()
- Introduce a third parameter to QuoteIdent(): "AlwaysQuote" - setting this to false will quote only if required
- Set AlwaysQuote to false for all stuff which drops some code into the query editor, see http://www.heidisql.com/forum.php?t=6986
This commit is contained in:
Ansgar Becker
2010-11-24 23:12:13 +00:00
parent e4cc29df6b
commit 6f95a796e1
15 changed files with 195 additions and 187 deletions

View File

@ -355,3 +355,5 @@ const
HELPERNODE_SNIPPETS = 3;
HELPERNODE_PROFILE = 4;
// A set of characters which need not to be quoted
IDENTCHARS = ['A'..'z', '0'..'9'];

View File

@ -355,8 +355,8 @@ var
DoData: Boolean;
begin
// Compose and run CREATE query
TargetTable := Mainform.mask(comboDatabase.Text)+'.'+Mainform.mask(editNewTablename.Text);
TableExistance := MainForm.ActiveConnection.GetVar('SHOW TABLES FROM '+MainForm.mask(comboDatabase.Text)+' LIKE '+esc(editNewTablename.Text));
TargetTable := QuoteIdent(comboDatabase.Text)+'.'+QuoteIdent(editNewTablename.Text);
TableExistance := MainForm.ActiveConnection.GetVar('SHOW TABLES FROM '+QuoteIdent(comboDatabase.Text)+' LIKE '+esc(editNewTablename.Text));
if TableExistance <> '' then begin
if MessageDlg('Target table exists. Drop it and overwrite?', mtConfirmation, [mbYes, mbCancel], 0) = mrCancel then begin
ModalResult := mrNone;
@ -377,7 +377,7 @@ begin
case ParentNode.Index of
nColumns: begin
Clause := FColumns[Node.Index].SQLCode;
DataCols := DataCols + MainForm.mask(FColumns[Node.Index].Name) + ', ';
DataCols := DataCols + QuoteIdent(FColumns[Node.Index].Name) + ', ';
end;
nKeys: Clause := FKeys[Node.Index].SQLCode;
nForeignkeys: Clause := FForeignKeys[Node.Index].SQLCode(False);
@ -414,7 +414,7 @@ begin
if DoData and (DataCols <> '') then begin
DataCols := Trim(DataCols);
Delete(DataCols, Length(DataCols), 1);
InsertCode := 'INSERT INTO '+TargetTable+' ('+DataCols+') SELECT ' + DataCols + ' FROM ' + MainForm.mask(FDBObj.Name);
InsertCode := 'INSERT INTO '+TargetTable+' ('+DataCols+') SELECT ' + DataCols + ' FROM ' + QuoteIdent(FDBObj.Name);
if MemoFilter.GetTextLen > 0 then
InsertCode := InsertCode + ' WHERE ' + MemoFilter.Text;
end;

View File

@ -98,7 +98,7 @@ begin
editDBName.SelectAll;
// Detect current charset and collation to be able to preselect them in the pulldowns
sql_create := MainForm.ActiveConnection.GetVar('SHOW CREATE DATABASE '+Mainform.mask(modifyDB), 1);
sql_create := MainForm.ActiveConnection.GetVar('SHOW CREATE DATABASE '+QuoteIdent(modifyDB), 1);
currentCharset := Copy( sql_create, pos('CHARACTER SET', sql_create)+14, Length(sql_create));
currentCharset := GetFirstWord( currentCharset );
if currentCharset <> '' then
@ -192,7 +192,7 @@ begin
MessageDlg( 'Creating database "'+editDBName.Text+'" failed:'+CRLF+CRLF+E.Message, mtError, [mbOK], 0 );
// Keep form open
end else try
sql := 'ALTER DATABASE ' + Mainform.mask( modifyDB );
sql := 'ALTER DATABASE ' + QuoteIdent( modifyDB );
if comboCharset.Enabled and (comboCharset.Text <> '') then
begin
sql := sql + ' CHARACTER SET ' + comboCharset.Text;
@ -237,8 +237,8 @@ begin
// Move all tables, views and procedures to target db
sql := '';
for i:=0 to ObjectsInOldDb.Count-1 do begin
sql := sql + Mainform.mask(modifyDb)+'.'+Mainform.mask(ObjectsInOldDb[i].Name)+' TO '+
Mainform.mask(editDBName.Text)+'.'+Mainform.mask(ObjectsInOldDb[i].Name)+', ';
sql := sql + QuoteIdent(modifyDb)+'.'+QuoteIdent(ObjectsInOldDb[i].Name)+' TO '+
QuoteIdent(editDBName.Text)+'.'+QuoteIdent(ObjectsInOldDb[i].Name)+', ';
end;
if sql <> '' then begin
Delete(sql, Length(sql)-1, 2);
@ -250,7 +250,7 @@ begin
// Last check if old db is really empty, before we drop it.
ObjectsLeft := MainForm.ActiveConnection.GetDBObjects(modifyDB);
if ObjectsLeft.Count = 0 then begin
MainForm.ActiveConnection.Query('DROP DATABASE '+Mainform.mask(modifyDB));
MainForm.ActiveConnection.Query('DROP DATABASE '+QuoteIdent(modifyDB));
MainForm.RefreshTree;
end;
end;
@ -292,7 +292,7 @@ end;
}
function TCreateDatabaseForm.GetCreateStatement: String;
begin
Result := 'CREATE DATABASE ' + Mainform.mask( editDBName.Text );
Result := 'CREATE DATABASE ' + QuoteIdent( editDBName.Text );
if comboCharset.Enabled and (comboCharset.Text <> '') then
begin
Result := Result + ' /*!40100 CHARACTER SET ' + comboCharset.Text;

View File

@ -244,13 +244,13 @@ end;
function TfrmEventEditor.ComposeCreateStatement: String;
begin
Result := 'CREATE EVENT ' + Mainform.mask(editName.Text) + ' ' + ComposeBaseStatement;
Result := 'CREATE EVENT ' + QuoteIdent(editName.Text) + ' ' + ComposeBaseStatement;
end;
function TfrmEventEditor.ComposeAlterStatement: String;
begin
Result := 'ALTER EVENT ' + Mainform.mask(DBObject.Name) + ' ' + ComposeBaseStatement;
Result := 'ALTER EVENT ' + QuoteIdent(DBObject.Name) + ' ' + ComposeBaseStatement;
end;
@ -289,7 +289,7 @@ begin
else
Result := Result + #9 + 'ON COMPLETION PRESERVE';
if (DBObject.Name <> '') and (DBObject.Name <> editName.Text) then
Result := Result + CRLF + #9 + 'RENAME TO ' + MainForm.mask(editName.Text);
Result := Result + CRLF + #9 + 'RENAME TO ' + QuoteIdent(editName.Text);
Result := Result + CRLF + #9 + UpperCase(grpState.Items[grpState.ItemIndex]);
Result := Result + CRLF + #9 + 'COMMENT ' + esc(editComment.Text);
Result := Result + CRLF + #9 + 'DO ' + SynMemoBody.Text;

View File

@ -590,10 +590,10 @@ begin
efXML: tmp := #9'<row>' + CRLF;
efSQL: begin
tmp := 'INSERT INTO '+Mainform.Mask(Tablename)+' (';
tmp := 'INSERT INTO '+QuoteIdent(Tablename)+' (';
Col := Grid.Header.Columns.GetFirstVisibleColumn;
while Col > NoColumn do begin
tmp := tmp + Mainform.mask(Grid.Header.Columns[Col].Text)+', ';
tmp := tmp + QuoteIdent(Grid.Header.Columns[Col].Text)+', ';
Col := Grid.Header.Columns.GetNextVisibleColumn(Col);
end;
Delete(tmp, Length(tmp)-1, 2);
@ -1875,7 +1875,7 @@ begin
sort := TXT_ASC
else
sort := TXT_DESC;
result := result + Mainform.Mask( Cols[i].ColumnName ) + ' ' + sort;
result := result + QuoteIdent( Cols[i].ColumnName ) + ' ' + sort;
end;
end;
@ -2276,7 +2276,7 @@ end;
function TDBObjectEditor.GetDefiners: TStringList;
function q(s: String): String;
begin
Result := DBObject.Connection.QuoteIdent(s);
Result := QuoteIdent(s);
end;
begin
// For populating combobox items

View File

@ -112,7 +112,7 @@ var
begin
setlength(cols, 0);
if ComboBoxTables.ItemIndex > -1 then begin
Results := MainForm.ActiveConnection.GetResults('SHOW FIELDS FROM '+mainform.mask(ComboBoxDBs.Text)+'.'+mainform.mask(ComboBoxTables.Text));
Results := MainForm.ActiveConnection.GetResults('SHOW FIELDS FROM '+QuoteIdent(ComboBoxDBs.Text)+'.'+QuoteIdent(ComboBoxTables.Text));
while not Results.Eof do begin
setlength(cols, length(cols)+1);
cols[length(cols)-1].Name := Results.Col(0);
@ -369,12 +369,12 @@ begin
ListViewFiles.Selected := ListViewFiles.ItemFocused;
ListViewFiles.ItemFocused.MakeVisible(False);
ListViewFiles.Repaint;
sql := 'INSERT INTO '+mainform.mask(ComboBoxDBs.Text)+'.'+mainform.mask(ComboBoxTables.Text) +
' (' + mainform.mask(ComboBoxColumns.Text);
sql := 'INSERT INTO '+QuoteIdent(ComboBoxDBs.Text)+'.'+QuoteIdent(ComboBoxTables.Text) +
' (' + QuoteIdent(ComboBoxColumns.Text);
for j:=0 to length(cols)-1 do begin
if cols[j].Name = ComboBoxColumns.Text then
Continue;
sql := sql + ', ' + mainform.mask(cols[j].Name);
sql := sql + ', ' + QuoteIdent(cols[j].Name);
end;
FileStream := TFileStream.Create( filename, fmShareDenyWrite );
try

View File

@ -158,7 +158,7 @@ begin
Charset := MainForm.GetCharsetByEncoding(Encoding);
// Detect db charset
DefCharset := 'Let server/database decide';
dbcreate := MainForm.ActiveConnection.GetVar('SHOW CREATE DATABASE '+Mainform.mask(comboDatabase.Text), 1);
dbcreate := MainForm.ActiveConnection.GetVar('SHOW CREATE DATABASE '+QuoteIdent(comboDatabase.Text), 1);
rx := TRegExpr.Create;
rx.ModifierG := True;
rx.Expression := 'CHARACTER SET (\w+)';
@ -325,7 +325,7 @@ begin
1: SQL := SQL + 'IGNORE ';
2: SQL := SQL + 'REPLACE ';
end;
SQL := SQL + 'INTO TABLE ' + Mainform.Mask(comboDatabase.Text) + '.' + Mainform.Mask(comboTable.Text) + ' ';
SQL := SQL + 'INTO TABLE ' + QuoteIdent(comboDatabase.Text) + '.' + QuoteIdent(comboTable.Text) + ' ';
if comboEncoding.ItemIndex > 0 then begin
MainForm.ActiveConnection.CharsetTable.RecNo := comboEncoding.ItemIndex-1;
@ -358,10 +358,10 @@ begin
if chklistColumns.Checked[i] then begin
if chkLocalNumbers.Checked and (Columns[i].DataType.Category in [dtcInteger, dtcReal]) then begin
SQL := SQL + '@ColVar' + IntToStr(i) + ', ';
SetColVars := SetColVars + Mainform.Mask(chklistColumns.Items[i]) +
SetColVars := SetColVars + QuoteIdent(chklistColumns.Items[i]) +
' = REPLACE(REPLACE(@ColVar' + IntToStr(i) + ', '+esc(ThousandSeparator)+', ''''), '+esc(DecimalSeparator)+', ''.''), ';
end else
SQL := SQL + Mainform.Mask(chklistColumns.Items[i]) + ', ';
SQL := SQL + QuoteIdent(chklistColumns.Items[i]) + ', ';
end;
end;
SetLength(SQL, Length(SQL)-2);
@ -434,10 +434,10 @@ const
1: SQL := 'INSERT '+LowPrio+'IGNORE ';
2: SQL := 'REPLACE '+LowPrio;
end;
SQL := SQL + 'INTO '+MainForm.mask(comboDatabase.Text)+'.'+MainForm.mask(comboTable.Text)+' (';
SQL := SQL + 'INTO '+QuoteIdent(comboDatabase.Text)+'.'+QuoteIdent(comboTable.Text)+' (';
for i:=0 to chkListColumns.Items.Count-1 do begin
if chkListColumns.Checked[i] then
SQL := SQL + MainForm.mask(chkListColumns.Items[i]) + ', ';
SQL := SQL + QuoteIdent(chkListColumns.Items[i]) + ', ';
end;
SetLength(SQL, Length(SQL)-2);
SQL := SQL + ') VALUES (';

View File

@ -528,7 +528,6 @@ type
procedure actPrintListExecute(Sender: TObject);
procedure actCopyTableExecute(Sender: TObject);
procedure ShowStatusMsg(Msg: String=''; PanelNr: Integer=6);
function mask(str: String; Glue: Char=#0) : String;
procedure actExecuteQueryExecute(Sender: TObject);
procedure actCreateDatabaseExecute(Sender: TObject);
procedure actDataCancelChangesExecute(Sender: TObject);
@ -2104,13 +2103,6 @@ begin
end;
// Escape database, table, field, index or key name.
function TMainform.mask(str: String; Glue: Char=#0) : String;
begin
result := ActiveConnection.QuoteIdent(str, Glue);
end;
procedure TMainForm.actExportSettingsExecute(Sender: TObject);
begin
// Export settings to .reg-file
@ -2625,7 +2617,7 @@ begin
db := Conn.Database;
Node := FindDBNode(DBtree, db);
SetActiveDatabase('', Conn);
Conn.Query('DROP DATABASE ' + mask(db));
Conn.Query('DROP DATABASE ' + QuoteIdent(db));
DBtree.DeleteNode(Node);
Conn.ClearDbObjects(db);
except
@ -2667,7 +2659,7 @@ begin
// Compose and run DROP [TABLE|VIEW|...] queries
Editor := ActiveObjectEditor;
for DBObject in ObjectList do begin
Conn.Query('DROP '+UpperCase(DBObject.ObjType)+' '+Mask(DBObject.Name));
Conn.Query('DROP '+UpperCase(DBObject.ObjType)+' '+QuoteIdent(DBObject.Name));
if Assigned(Editor) and Editor.Modified and Editor.DBObject.IsSameAs(DBObject) then
Editor.Modified := False;
end;
@ -2962,7 +2954,7 @@ begin
EnableProgressBar(Objects.Count);
try
for TableOrView in Objects do begin
ActiveConnection.Query('TRUNCATE ' + mask(TableOrView.Name));
ActiveConnection.Query('TRUNCATE ' + QuoteIdent(TableOrView.Name));
ProgressBarStatus.StepIt;
end;
actRefresh.Execute;
@ -3018,7 +3010,7 @@ begin
end;
Parameters := TRoutineParamList.Create;
Obj.Connection.ParseRoutineStructure(Obj.CreateCode, Parameters, DummyBool, DummyStr, DummyStr, DummyStr, DummyStr, DummyStr, DummyStr);
Query := Query + mask(Obj.Name);
Query := Query + QuoteIdent(Obj.Name);
ParamInput := '';
for i:=0 to Parameters.Count-1 do begin
if ParamInput <> '' then
@ -3925,9 +3917,9 @@ begin
and (not IsKeyColumn) // We need full length of any key column, so DataGridLoadFullRow() has the chance to fetch the right row
and ((ColLen > GRIDMAXDATA) or (ColLen = 0)) // No need to blow SQL with LEFT() if column is shorter anyway
then
Select := Select + ' LEFT(' + Mask(c.Name) + ', ' + IntToStr(GRIDMAXDATA) + '), '
Select := Select + ' LEFT(' + QuoteIdent(c.Name) + ', ' + IntToStr(GRIDMAXDATA) + '), '
else
Select := Select + ' ' + Mask(c.Name) + ', ';
Select := Select + ' ' + QuoteIdent(c.Name) + ', ';
WantedColumns.Add(c);
WantedColumnOrgnames.Add(c.Name);
end;
@ -3935,7 +3927,7 @@ begin
// Cut last comma
Delete(Select, Length(Select)-1, 2);
// Include db name for cases in which dbtree is switching databases and pending updates are in process
Select := Select + ' FROM '+mask(ActiveDatabase)+'.'+mask(ActiveDbObj.Name);
Select := Select + ' FROM '+QuoteIdent(ActiveDatabase)+'.'+QuoteIdent(ActiveDbObj.Name);
// Signal for the user if we hide some columns
if WantedColumns.Count = SelectedTableColumns.Count then
@ -4500,7 +4492,7 @@ var
dbname := Copy( tablename, 0, Pos( '.', tablename )-1 );
tablename := Copy( tablename, Pos( '.', tablename )+1, Length(tablename) );
end;
// Do not mask db and table name to avoid double masking.
// Do not quote db and table name to avoid double masking.
// Rely on what the user typed is already a valid masked/quoted identifier.
if dbname <> '' then
tablename := dbname + '.' + tablename;
@ -4783,7 +4775,7 @@ begin
// Try to rename, on any error abort and don't rename ListItem
try
// rename table
ActiveConnection.Query('RENAME TABLE ' + mask(Obj.Name) + ' TO ' + mask(NewText));
ActiveConnection.Query('RENAME TABLE ' + QuoteIdent(Obj.Name) + ' TO ' + QuoteIdent(NewText));
if SynSQLSyn1.TableNames.IndexOf( NewText ) = -1 then begin
SynSQLSyn1.TableNames.Add(NewText);
@ -4853,15 +4845,15 @@ begin
if Val = 'Value' then
Filter := ''
else if Item = QF8 then
Filter := mask(Col) + ' = ''' + Val + ''''
Filter := QuoteIdent(Col) + ' = ''' + Val + ''''
else if Item = QF9 then
Filter := mask(Col) + ' != ''' + Val + ''''
Filter := QuoteIdent(Col) + ' != ''' + Val + ''''
else if Item = QF10 then
Filter := mask(Col) + ' > ''' + Val + ''''
Filter := QuoteIdent(Col) + ' > ''' + Val + ''''
else if Item = QF11 then
Filter := mask(Col) + ' < ''' + Val + ''''
Filter := QuoteIdent(Col) + ' < ''' + Val + ''''
else if Item = QF12 then
Filter := mask(Col) + ' LIKE ''%' + Val + '%''';
Filter := QuoteIdent(Col) + ' LIKE ''%' + Val + '%''';
end else
Filter := Item.Hint;
@ -4949,11 +4941,11 @@ begin
if src = DBtree then begin
// Insert table or database name. If a table is dropped and Shift is pressed, prepend the db name.
case ActiveDbObj.NodeType of
lntDb: Text := mask(ActiveDbObj.Database);
lntDb: Text := QuoteIdent(ActiveDbObj.Database, False);
lntTable..lntEvent: begin
if ShiftPressed then
Text := mask(ActiveDbObj.Database) + '.';
Text := Text + mask(ActiveDbObj.Name);
Text := QuoteIdent(ActiveDbObj.Database, False) + '.';
Text := Text + QuoteIdent(ActiveDbObj.Name, False);
end;
end;
end else if src = Tree then begin
@ -4967,7 +4959,7 @@ begin
if Tree.Selected[Node] then begin
ItemText := Tree.Text[Node, 0];
if Node.Parent.Index = HELPERNODE_COLUMNS then
ItemText := mask(ItemText); // Quote column names
ItemText := QuoteIdent(ItemText, False); // Quote column names
if ShiftPressed then
Text := Text + ItemText + ',' + CRLF
else
@ -5346,7 +5338,7 @@ begin
AnyGridEnsureFullRow(Grid, Grid.FocusedNode);
RowNumber := Grid.GetNodeData(Grid.FocusedNode);
Results.RecNo := RowNumber^;
Col := mask(Results.ColumnOrgNames[Grid.FocusedColumn]);
Col := QuoteIdent(Results.ColumnOrgNames[Grid.FocusedColumn]);
// 1. block: include selected columnname and value from datagrid in caption
if Results.IsNull(Grid.FocusedColumn) then begin
QF1.Hint := Col + ' IS NULL';
@ -5425,8 +5417,8 @@ begin
Exit;
Col := DataGridResult.ColumnOrgNames[DataGrid.FocusedColumn];
ShowStatusMsg('Fetching distinct values ...');
Data := ActiveConnection.GetResults('SELECT '+mask(Col)+', COUNT(*) AS c FROM '+mask(ActiveDbObj.Name)+
' GROUP BY '+mask(Col)+' ORDER BY c DESC, '+mask(Col)+' LIMIT 30');
Data := ActiveConnection.GetResults('SELECT '+QuoteIdent(Col)+', COUNT(*) AS c FROM '+QuoteIdent(ActiveDbObj.Name)+
' GROUP BY '+QuoteIdent(Col)+' ORDER BY c DESC, '+QuoteIdent(Col)+' LIMIT 30');
for i:=0 to Data.RecordCount-1 do begin
if QFvalues.Count > i then
Item := QFvalues[i]
@ -5434,7 +5426,7 @@ begin
Item := TMenuItem.Create(QFvalues);
QFvalues.Add(Item);
end;
Item.Hint := mask(Col)+'='+esc(Data.Col(Col));
Item.Hint := QuoteIdent(Col)+'='+esc(Data.Col(Col));
Item.Caption := sstr(Item.Hint, 100) + ' (' + FormatNumber(Data.Col('c')) + ')';
Item.OnClick := QuickFilterClick;
Data.Next;
@ -7011,7 +7003,7 @@ begin
for i:=0 to SelectedTableColumns.Count-1 do begin
if i > 0 then
Clause := Clause + ' OR ';
Clause := Clause + mask(SelectedTableColumns[i].Name) + ' LIKE ' + esc('%'+ed.Text+'%');
Clause := Clause + QuoteIdent(SelectedTableColumns[i].Name) + ' LIKE ' + esc('%'+ed.Text+'%');
end;
end;
// Add linebreaks at near right window edge
@ -7379,7 +7371,7 @@ begin
idx := ForeignKey.Columns.IndexOf(DataGrid.Header.Columns[Column].Text);
if idx > -1 then begin
// Find the first text column if available and use that for displaying in the pulldown instead of using meaningless id numbers
CreateTable := ActiveConnection.GetVar('SHOW CREATE TABLE '+Mask(ForeignKey.ReferenceTable, '.'), 1);
CreateTable := ActiveConnection.GetVar('SHOW CREATE TABLE '+QuoteIdent(ForeignKey.ReferenceTable, True, '.'), 1);
Columns := TTableColumnList.Create;
Keys := nil;
ForeignKeys := nil;
@ -7392,11 +7384,11 @@ begin
end;
end;
KeyCol := Mask(ForeignKey.ForeignColumns[idx]);
KeyCol := QuoteIdent(ForeignKey.ForeignColumns[idx]);
SQL := 'SELECT '+KeyCol;
if TextCol <> '' then SQL := SQL + ', LEFT(' + Mask(TextCol) + ', 256)';
SQL := SQL + ' FROM '+Mask(ForeignKey.ReferenceTable, '.')+' GROUP BY '+KeyCol+' ORDER BY ';
if TextCol <> '' then SQL := SQL + Mask(TextCol) else SQL := SQL + KeyCol;
if TextCol <> '' then SQL := SQL + ', LEFT(' + QuoteIdent(TextCol) + ', 256)';
SQL := SQL + ' FROM '+QuoteIdent(ForeignKey.ReferenceTable, True, '.')+' GROUP BY '+KeyCol+' ORDER BY ';
if TextCol <> '' then SQL := SQL + QuoteIdent(TextCol) else SQL := SQL + KeyCol;
SQL := SQL + ' LIMIT 1000';
ForeignResults := ActiveConnection.GetResults(SQL);
@ -7577,7 +7569,7 @@ begin
DataGridFocusedCell := TStringList.Create;
// Remember focused node and column for selected table
if Assigned(DataGrid.FocusedNode) then begin
KeyName := Mask(DataGridDB)+'.'+Mask(DataGridTable);
KeyName := QuoteIdent(DataGridDB)+'.'+QuoteIdent(DataGridTable);
FocusedCol := '';
if DataGrid.FocusedColumn > NoColumn then
FocusedCol := DataGrid.Header.Columns[DataGrid.FocusedColumn].Text;
@ -7585,7 +7577,7 @@ begin
end;
DataGridFocusedNodeIndex := 0;
DataGridFocusedColumnName := '';
KeyName := Mask(ActiveDbObj.Database)+'.'+Mask(ActiveDbObj.Name);
KeyName := QuoteIdent(ActiveDbObj.Database)+'.'+QuoteIdent(ActiveDbObj.Name);
CellFocus := DataGridFocusedCell.Values[KeyName];
if CellFocus <> '' then begin
DataGridFocusedNodeIndex := MakeInt(Explode(DELIM, CellFocus)[0]);
@ -7745,7 +7737,7 @@ begin
vt.Clear;
try
if ActiveConnection.InformationSchemaObjects.IndexOf('SCHEMATA') > -1 then
AllDatabasesDetails := ActiveConnection.GetResults('SELECT * FROM '+mask(DBNAME_INFORMATION_SCHEMA)+'.'+mask('SCHEMATA'));
AllDatabasesDetails := ActiveConnection.GetResults('SELECT * FROM '+QuoteIdent(DBNAME_INFORMATION_SCHEMA)+'.'+QuoteIdent('SCHEMATA'));
except
on E:EDatabaseError do
LogSQL(E.Message, lcError);
@ -8006,9 +7998,9 @@ begin
vt.Clear;
if ActiveConnection.InformationSchemaObjects.IndexOf('PROCESSLIST') > -1 then begin
// Minimize network traffic on newer servers by fetching only first KB of SQL query in "Info" column
Results := ActiveConnection.GetResults('SELECT '+mask('ID')+', '+mask('USER')+', '+mask('HOST')+', '+mask('DB')+', '
+ mask('COMMAND')+', '+mask('TIME')+', '+mask('STATE')+', LEFT('+mask('INFO')+', '+IntToStr(InfoLen)+') AS '+mask('Info')
+ ' FROM '+mask(DBNAME_INFORMATION_SCHEMA)+'.'+mask('PROCESSLIST'));
Results := ActiveConnection.GetResults('SELECT '+QuoteIdent('ID')+', '+QuoteIdent('USER')+', '+QuoteIdent('HOST')+', '+QuoteIdent('DB')+', '
+ QuoteIdent('COMMAND')+', '+QuoteIdent('TIME')+', '+QuoteIdent('STATE')+', LEFT('+QuoteIdent('INFO')+', '+IntToStr(InfoLen)+') AS '+QuoteIdent('Info')
+ ' FROM '+QuoteIdent(DBNAME_INFORMATION_SCHEMA)+'.'+QuoteIdent('PROCESSLIST'));
end else begin
// Older servers fetch the whole query length, but at least we cut them off below, so a high memory usage is just a peak
Results := ActiveConnection.GetResults('SHOW FULL PROCESSLIST');
@ -9329,7 +9321,7 @@ begin
Node := Tree.GetFirstChild(FindNode(Tree, HELPERNODE_COLUMNS, nil));
while Assigned(Node) do begin
if Tree.Selected[Node] then begin
ColumnNames.Add(mask(Tree.Text[Node, 0]));
ColumnNames.Add(QuoteIdent(Tree.Text[Node, 0], False));
Column := SelectedTableColumns[Node.Index];
case Column.DataType.Category of
dtcInteger, dtcReal: Val := '0';
@ -9352,21 +9344,21 @@ begin
KeyColumns := ActiveConnection.GetKeyColumns(SelectedTableColumns, SelectedTableKeys);
WhereClause := '';
for i:=0 to KeyColumns.Count-1 do begin
idx := ColumnNames.IndexOf(mask(KeyColumns[i]));
idx := ColumnNames.IndexOf(QuoteIdent(KeyColumns[i], False));
if idx > -1 then begin
if WhereClause <> '' then
WhereClause := WhereClause + ' AND ';
WhereClause := WhereClause + mask(KeyColumns[i])+'='+DefaultValues[idx];
WhereClause := WhereClause + QuoteIdent(KeyColumns[i], False)+'='+DefaultValues[idx];
end;
end;
if MenuItem = menuQueryHelpersGenerateInsert then begin
sql := 'INSERT INTO '+mask(ActiveDbObj.Name)+CRLF+
sql := 'INSERT INTO '+QuoteIdent(ActiveDbObj.Name, False)+CRLF+
#9'('+ImplodeStr(', ', ColumnNames)+')'+CRLF+
#9'VALUES ('+ImplodeStr(', ', DefaultValues)+')';
end else if MenuItem = menuQueryHelpersGenerateUpdate then begin
sql := 'UPDATE '+mask(ActiveDbObj.Name)+CRLF+#9'SET'+CRLF;
sql := 'UPDATE '+QuoteIdent(ActiveDbObj.Name, False)+CRLF+#9'SET'+CRLF;
if ColumnNames.Count > 0 then begin
for i:=0 to ColumnNames.Count-1 do begin
sql := sql + #9#9 + ColumnNames[i] + '=' + DefaultValues[i] + ',' + CRLF;
@ -9377,7 +9369,7 @@ begin
sql := sql + #9'WHERE ' + WhereClause;
end else if MenuItem = menuQueryHelpersGenerateDelete then begin
sql := 'DELETE FROM '+mask(ActiveDbObj.Name)+' WHERE ' + WhereClause;
sql := 'DELETE FROM '+QuoteIdent(ActiveDbObj.Name, False)+' WHERE ' + WhereClause;
end;
ActiveQueryMemo.UndoList.AddGroupBreak;
@ -9487,7 +9479,7 @@ begin
// Click on "Explain" link label, in process viewer
actNewQueryTabExecute(Sender);
Tab := QueryTabs[QueryTabs.Count-1];
Tab.Memo.Text := 'USE '+mask(listProcesses.Text[listProcesses.FocusedNode, 3])+';'+CRLF+
Tab.Memo.Text := 'USE '+QuoteIdent(listProcesses.Text[listProcesses.FocusedNode, 3])+';'+CRLF+
'EXPLAIN'+CRLF+SynMemoProcessView.Text;
Tab.TabSheet.Show;
actExecuteQueryExecute(Sender);

View File

@ -261,8 +261,6 @@ type
function EscapeString(Text: String; ProcessJokerChars: Boolean=False): String;
function escChars(const Text: String; EscChar, Char1, Char2, Char3, Char4: Char): String;
function UnescapeString(Text: String): String;
class function QuoteIdent(Identifier: String; Glue: Char=#0): String;
function DeQuoteIdent(Identifier: String; Glue: Char=#0): String;
function ConvertServerVersion(Version: Integer): String;
function GetResults(SQL: String): TMySQLQuery;
function GetCol(SQL: String; Column: Integer=0): TStringList;
@ -399,6 +397,8 @@ type
end;
PMySQLQuery = ^TMySQLQuery;
function QuoteIdent(Identifier: String; AlwaysQuote: Boolean=True; Glue: Char=#0): String;
function DeQuoteIdent(Identifier: String; Glue: Char=#0): String;
implementation
@ -1047,17 +1047,37 @@ end;
Add backticks to identifier
Todo: Support ANSI style
}
class function TMySQLConnection.QuoteIdent(Identifier: String; Glue: Char=#0): String;
function QuoteIdent(Identifier: String; AlwaysQuote: Boolean=True; Glue: Char=#0): String;
var
GluePos, i: Integer;
begin
Result := Identifier;
GluePos := 0;
if Glue <> #0 then begin
GluePos := Pos(Glue, Result);
if GluePos > 0 then
Result := QuoteIdent(Copy(Result, 1, GluePos-1)) + Glue + QuoteIdent(Copy(Result, GluePos+1, MaxInt));
end;
if GluePos = 0 then begin
if not AlwaysQuote then begin
if MySQLKeywords.IndexOf(Result) > -1 then
AlwaysQuote := True
else for i:=1 to Length(Result) do begin
if not CharInSet(Result[i], IDENTCHARS) then begin
AlwaysQuote := True;
break;
end;
end;
end;
if AlwaysQuote then begin
Result := StringReplace(Result, '`', '``', [rfReplaceAll]);
if Glue <> #0 then
Result := StringReplace(Result, Glue, '`'+Glue+'`', [rfReplaceAll]);
Result := '`' + Result + '`';
end;
end;
end;
function TMySQLConnection.DeQuoteIdent(Identifier: String; Glue: Char=#0): String;
function DeQuoteIdent(Identifier: String; Glue: Char=#0): String;
begin
Result := Identifier;
if (Result[1] = '`') and (Result[Length(Identifier)] = '`') then
@ -2509,7 +2529,7 @@ begin
for i:=0 to FColumnOrgNames.Count-1 do begin
if sql <> '' then
sql := sql + ', ';
sql := sql + Connection.QuoteIdent(FColumnOrgNames[i]);
sql := sql + QuoteIdent(FColumnOrgNames[i]);
end;
Data := Connection.GetResults('SELECT '+sql+' FROM '+QuotedDbAndTableName+' WHERE '+GetWhereClause+' LIMIT 1');
Result := Data.RecordCount = 1;
@ -2584,8 +2604,8 @@ begin
dtcInteger, dtcReal: Val := Cell.NewText;
else Val := Connection.EscapeString(Cell.NewText);
end;
sqlUpdate := sqlUpdate + Connection.QuoteIdent(FColumnOrgNames[i]) + '=' + Val;
sqlInsertColumns := sqlInsertColumns + Connection.QuoteIdent(FColumnOrgNames[i]);
sqlUpdate := sqlUpdate + QuoteIdent(FColumnOrgNames[i]) + '=' + Val;
sqlInsertColumns := sqlInsertColumns + QuoteIdent(FColumnOrgNames[i]);
sqlInsertValues := sqlInsertValues + Val;
end;
@ -2748,8 +2768,8 @@ begin
// Return `db`.`table` if necessairy, otherwise `table`
db := DatabaseName;
if Connection.Database <> db then
Result := Connection.QuoteIdent(db)+'.';
Result := Result + Connection.QuoteIdent(TableName);
Result := QuoteIdent(db)+'.';
Result := Result + QuoteIdent(TableName);
end;
@ -2805,7 +2825,7 @@ begin
raise EDatabaseError.Create('Cannot compose WHERE clause - column missing: '+NeededCols[i]);
if Result <> '' then
Result := Result + ' AND';
Result := Result + ' ' + Connection.QuoteIdent(FColumnOrgNames[j]);
Result := Result + ' ' + QuoteIdent(FColumnOrgNames[j]);
if Modified(j) then begin
ColVal := FCurrentUpdateRow[j].OldText;
ColIsNull := FCurrentUpdateRow[j].OldIsNull;
@ -2978,7 +2998,7 @@ begin
else Exception.Create('Unhandled list node type in '+ClassName+'.GetCreateCode');
end;
if not FCreateCodeFetched then try
FCreateCode := FConnection.GetVar('SHOW CREATE '+UpperCase(ObjType)+' '+FConnection.QuoteIdent(Database)+'.'+FConnection.QuoteIdent(Name), Column)
FCreateCode := FConnection.GetVar('SHOW CREATE '+UpperCase(ObjType)+' '+QuoteIdent(Database)+'.'+QuoteIdent(Name), Column)
except
end;
FCreateCodeFetched := True;
@ -3017,7 +3037,7 @@ end;
function TTableColumn.SQLCode: String;
begin
Result := TMySQLConnection.QuoteIdent(Name) + ' ' +DataType.Name;
Result := QuoteIdent(Name) + ' ' +DataType.Name;
if LengthSet <> '' then
Result := Result + '(' + LengthSet + ')';
if (DataType.Category in [dtcInteger, dtcReal]) and Unsigned then
@ -3076,11 +3096,11 @@ begin
else begin
if IndexType <> KEY then
Result := Result + IndexType + ' ';
Result := Result + 'INDEX ' + TMySQLConnection.QuoteIdent(Name) + ' ';
Result := Result + 'INDEX ' + QuoteIdent(Name) + ' ';
end;
Result := Result + '(';
for i:=0 to Columns.Count-1 do begin
Result := Result + TMySQLConnection.QuoteIdent(Columns[i]);
Result := Result + QuoteIdent(Columns[i]);
if SubParts[i] <> '' then
Result := Result + '(' + SubParts[i] + ')';
Result := Result + ', ';
@ -3120,14 +3140,14 @@ begin
Result := '';
// Symbol names are unique in a db. In order to autocreate a valid name we leave the constraint clause away.
if IncludeSymbolName then
Result := 'CONSTRAINT '+TMySQLConnection.QuoteIdent(KeyName)+' ';
Result := 'CONSTRAINT '+QuoteIdent(KeyName)+' ';
Result := Result + 'FOREIGN KEY (';
for i:=0 to Columns.Count-1 do
Result := Result + TMySQLConnection.QuoteIdent(Columns[i]) + ', ';
Result := Result + QuoteIdent(Columns[i]) + ', ';
if Columns.Count > 0 then Delete(Result, Length(Result)-1, 2);
Result := Result + ') REFERENCES ' + TMySQLConnection.QuoteIdent(ReferenceTable, '.') + ' (';
Result := Result + ') REFERENCES ' + QuoteIdent(ReferenceTable, True, '.') + ' (';
for i:=0 to ForeignColumns.Count-1 do
Result := Result + TMySQLConnection.QuoteIdent(ForeignColumns[i]) + ', ';
Result := Result + QuoteIdent(ForeignColumns[i]) + ', ';
if ForeignColumns.Count > 0 then Delete(Result, Length(Result)-1, 2);
Result := Result + ')';
if OnUpdate <> '' then

View File

@ -440,7 +440,7 @@ begin
if DBObject.Name <> '' then begin
// Create temp name
i := 0;
allRoutineNames := MainForm.ActiveConnection.GetCol('SELECT ROUTINE_NAME FROM '+Mainform.mask(DBNAME_INFORMATION_SCHEMA)+'.'+Mainform.mask('ROUTINES')+
allRoutineNames := MainForm.ActiveConnection.GetCol('SELECT ROUTINE_NAME FROM '+QuoteIdent(DBNAME_INFORMATION_SCHEMA)+'.'+QuoteIdent('ROUTINES')+
' WHERE ROUTINE_SCHEMA = '+esc(Mainform.ActiveDatabase)+
' AND ROUTINE_TYPE = '+esc(ProcOrFunc)
);
@ -460,12 +460,12 @@ begin
end;
MainForm.ActiveConnection.Query(ComposeCreateStatement(tempName));
// Drop temporary routine, used for syntax checking
MainForm.ActiveConnection.Query('DROP '+ProcOrFunc+' IF EXISTS '+Mainform.mask(TempName));
MainForm.ActiveConnection.Query('DROP '+ProcOrFunc+' IF EXISTS '+QuoteIdent(TempName));
// Drop edited routine
MainForm.ActiveConnection.Query('DROP '+FAlterRoutineType+' IF EXISTS '+Mainform.mask(DBObject.Name));
MainForm.ActiveConnection.Query('DROP '+FAlterRoutineType+' IF EXISTS '+QuoteIdent(DBObject.Name));
if TargetExists then begin
// Drop target routine - overwriting has been confirmed, see above
MainForm.ActiveConnection.Query('DROP '+ProcOrFunc+' IF EXISTS '+Mainform.mask(editName.Text));
MainForm.ActiveConnection.Query('DROP '+ProcOrFunc+' IF EXISTS '+QuoteIdent(editName.Text));
end;
end;
MainForm.ActiveConnection.Query(ComposeCreateStatement(editName.Text));
@ -498,12 +498,12 @@ begin
ProcOrFunc := UpperCase(GetFirstWord(comboType.Text));
Result := 'CREATE ';
if comboDefiner.Text <> '' then
Result := Result + 'DEFINER='+DBObject.Connection.QuoteIdent(comboDefiner.Text, '@')+' ';
Result := Result + ProcOrFunc+' '+Mainform.mask(NameOfObject)+'(';
Result := Result + 'DEFINER='+QuoteIdent(comboDefiner.Text, True, '@')+' ';
Result := Result + ProcOrFunc+' '+QuoteIdent(NameOfObject)+'(';
for i:=0 to Parameters.Count-1 do begin
if ProcOrFunc = 'PROCEDURE' then
Result := Result + Parameters[i].Context + ' ';
Result := Result + Mainform.Mask(Parameters[i].Name) + ' ' + Parameters[i].Datatype;
Result := Result + QuoteIdent(Parameters[i].Name) + ' ' + Parameters[i].Datatype;
if i < Parameters.Count-1 then
Result := Result + ', ';
end;

View File

@ -379,12 +379,12 @@ begin
// ALTER TABLE statement. Separate statements are required."
for i:=0 to FForeignKeys.Count-1 do begin
if FForeignKeys[i].Modified and (not FForeignKeys[i].Added) then
Specs.Add('DROP FOREIGN KEY '+Mainform.mask(FForeignKeys[i].OldKeyName));
Specs.Add('DROP FOREIGN KEY '+QuoteIdent(FForeignKeys[i].OldKeyName));
end;
end;
try
if Specs.Count > 0 then
MainForm.ActiveConnection.Query('ALTER TABLE '+Mainform.mask(DBObject.Name)+' '+ImplodeStr(', ', Specs));
MainForm.ActiveConnection.Query('ALTER TABLE '+QuoteIdent(DBObject.Name)+' '+ImplodeStr(', ', Specs));
MainForm.ActiveConnection.Query(sql);
tabALTERcode.TabVisible := DBObject.Name <> '';
if chkCharsetConvert.Checked then begin
@ -467,7 +467,7 @@ begin
Screen.Cursor := crHourglass;
Specs := TStringList.Create;
if editName.Text <> DBObject.Name then
Specs.Add('RENAME TO ' + Mainform.mask(editName.Text));
Specs.Add('RENAME TO ' + QuoteIdent(editName.Text));
if memoComment.Tag = ModifiedFlag then
Specs.Add('COMMENT=' + esc(memoComment.Text));
if (comboCollation.Tag = ModifiedFlag) or (chkCharsetConvert.Checked) then
@ -511,7 +511,7 @@ begin
Mainform.ProgressBarStatus.StepIt;
Col := listColumns.GetNodeData(Node);
if Col.Status <> esUntouched then begin
ColSpec := Mainform.mask(Col.Name);
ColSpec := QuoteIdent(Col.Name);
ColSpec := ColSpec + ' ' + Col.DataType.Name;
if Col.LengthSet <> '' then
ColSpec := ColSpec + '(' + Col.LengthSet + ')';
@ -540,10 +540,10 @@ begin
if PreviousCol = nil then
ColSpec := ColSpec + ' FIRST'
else
ColSpec := ColSpec + ' AFTER '+Mainform.mask(PreviousCol.Name);
ColSpec := ColSpec + ' AFTER '+QuoteIdent(PreviousCol.Name);
end;
if Col.Status = esModified then
Specs.Add('CHANGE COLUMN '+Mainform.mask(Col.OldName) + ' ' + ColSpec)
Specs.Add('CHANGE COLUMN '+QuoteIdent(Col.OldName) + ' ' + ColSpec)
else if Col.Status in [esAddedUntouched, esAddedModified] then
Specs.Add('ADD COLUMN ' + ColSpec);
end;
@ -554,7 +554,7 @@ begin
// Deleted columns, not available as Node in above loop
for i:=0 to FColumns.Count-1 do begin
if FColumns[i].Status = esDeleted then
Specs.Add('DROP COLUMN '+Mainform.mask(FColumns[i].OldName));
Specs.Add('DROP COLUMN '+QuoteIdent(FColumns[i].OldName));
end;
// Drop indexes, also changed indexes, which will be readded below
@ -563,7 +563,7 @@ begin
if DeletedKeys[i] = PKEY then
IndexSQL := 'PRIMARY KEY'
else
IndexSQL := 'INDEX ' + Mainform.Mask(DeletedKeys[i]);
IndexSQL := 'INDEX ' + QuoteIdent(DeletedKeys[i]);
Specs.Add('DROP '+IndexSQL);
end;
// Add changed or added indexes
@ -573,7 +573,7 @@ begin
if FKeys[i].OldIndexType = PKEY then
IndexSQL := 'PRIMARY KEY'
else
IndexSQL := 'INDEX ' + Mainform.Mask(FKeys[i].OldName);
IndexSQL := 'INDEX ' + QuoteIdent(FKeys[i].OldName);
Specs.Add('DROP '+IndexSQL);
end;
if FKeys[i].Added or FKeys[i].Modified then
@ -581,13 +581,13 @@ begin
end;
for i:=0 to DeletedForeignKeys.Count-1 do
Specs.Add('DROP FOREIGN KEY '+Mainform.mask(DeletedForeignKeys[i]));
Specs.Add('DROP FOREIGN KEY '+QuoteIdent(DeletedForeignKeys[i]));
for i:=0 to FForeignKeys.Count-1 do begin
if FForeignKeys[i].Added or FForeignKeys[i].Modified then
Specs.Add('ADD '+FForeignKeys[i].SQLCode(True));
end;
Result := 'ALTER TABLE '+Mainform.mask(DBObject.Name) + CRLF + #9 + ImplodeStr(',' + CRLF + #9, Specs);
Result := 'ALTER TABLE '+QuoteIdent(DBObject.Name) + CRLF + #9 + ImplodeStr(',' + CRLF + #9, Specs);
Result := Trim(Result);
FreeAndNil(Specs);
Mainform.ShowStatusMsg;
@ -604,7 +604,7 @@ var
tmp: String;
begin
// Compose CREATE query, called by buttons and for SQL code tab
Result := 'CREATE TABLE '+Mainform.mask(editName.Text)+' ('+CRLF;
Result := 'CREATE TABLE '+QuoteIdent(editName.Text)+' ('+CRLF;
Node := listColumns.GetFirst;
while Assigned(Node) do begin
Col := listColumns.GetNodeData(Node);
@ -1933,7 +1933,7 @@ begin
MessageDlg('Please select a reference table before selecting foreign columns.', mtError, [mbOk], 0)
else begin
try
MainForm.ActiveConnection.GetVar('SELECT 1 FROM '+Mainform.Mask(Key.ReferenceTable, '.'));
MainForm.ActiveConnection.GetVar('SELECT 1 FROM '+QuoteIdent(Key.ReferenceTable, True, '.'));
Allowed := True;
except
// Leave Allowed = False
@ -1985,7 +1985,7 @@ begin
3: begin
Key := FForeignKeys[Node.Index];
SetEditor := TSetEditorLink.Create(VT);
SetEditor.ValueList := MainForm.ActiveConnection.GetCol('SHOW COLUMNS FROM '+Mainform.Mask(Key.ReferenceTable, '.'));
SetEditor.ValueList := MainForm.ActiveConnection.GetCol('SHOW COLUMNS FROM '+QuoteIdent(Key.ReferenceTable, True, '.'));
EditLink := SetEditor;
end;
4, 5: begin

View File

@ -551,7 +551,7 @@ begin
AddNotes(DBObj.Database, DBObj.Name, STRSKIPPED+'a '+LowerCase(DBObj.ObjType)+' cannot be maintained.', '');
Exit;
end;
SQL := UpperCase(comboOperation.Text) + ' TABLE ' + Mainform.mask(DBObj.Database) + '.' + Mainform.mask(DBObj.Name);
SQL := UpperCase(comboOperation.Text) + ' TABLE ' + QuoteIdent(DBObj.Database) + '.' + QuoteIdent(DBObj.Name);
if chkQuick.Enabled and chkQuick.Checked then SQL := SQL + ' QUICK';
if chkFast.Enabled and chkFast.Checked then SQL := SQL + ' FAST';
if chkMedium.Enabled and chkMedium.Checked then SQL := SQL + ' MEDIUM';
@ -580,16 +580,16 @@ begin
for Col in Columns do begin
if (comboDatatypes.ItemIndex = 0) or (Integer(Col.DataType.Category) = comboDatatypes.ItemIndex-1) then begin
if chkCaseSensitive.Checked then
SQL := SQL + Mainform.mask(Col.Name) + ' LIKE BINARY ' + esc('%'+memoFindText.Text+'%') + ' OR '
SQL := SQL + QuoteIdent(Col.Name) + ' LIKE BINARY ' + esc('%'+memoFindText.Text+'%') + ' OR '
else
SQL := SQL + 'LOWER(CONVERT('+Mainform.mask(Col.Name)+' USING '+DBObj.Connection.CharacterSet+')) LIKE ' + esc('%'+LowerCase(memoFindText.Text)+'%') + ' OR '
SQL := SQL + 'LOWER(CONVERT('+QuoteIdent(Col.Name)+' USING '+DBObj.Connection.CharacterSet+')) LIKE ' + esc('%'+LowerCase(memoFindText.Text)+'%') + ' OR '
end;
end;
if SQL <> '' then begin
Delete(SQL, Length(SQL)-3, 3);
FFindSeeResultSQL[FFindSeeResultSQL.Count-1] := 'SELECT * FROM '+Mainform.mask(DBObj.Database)+'.'+Mainform.mask(DBObj.Name)+' WHERE ' + SQL;
FFindSeeResultSQL[FFindSeeResultSQL.Count-1] := 'SELECT * FROM '+QuoteIdent(DBObj.Database)+'.'+QuoteIdent(DBObj.Name)+' WHERE ' + SQL;
SQL := 'SELECT '''+DBObj.Database+''' AS `Database`, '''+DBObj.Name+''' AS `Table`, COUNT(*) AS `Found rows`, '
+ 'CONCAT(ROUND(100 / '+IntToStr(Max(DBObj.Rows,1))+' * COUNT(*), 1), ''%'') AS `Relevance` FROM '+Mainform.mask(DBObj.Database)+'.'+Mainform.mask(DBObj.Name)+' WHERE '
+ 'CONCAT(ROUND(100 / '+IntToStr(Max(DBObj.Rows,1))+' * COUNT(*), 1), ''%'') AS `Relevance` FROM '+QuoteIdent(DBObj.Database)+'.'+QuoteIdent(DBObj.Name)+' WHERE '
+ SQL;
AddResults(SQL);
end else
@ -1002,12 +1002,6 @@ var
const
TempDelim = '//';
// Short version of Mainform.Mask()
function m(s: String): String;
begin
Result := Mainform.mask(s);
end;
procedure LogStatistic(RowsDone: Int64);
var
LogRow: TStringlist;
@ -1022,10 +1016,10 @@ const
begin
// Handle one table, view or whatever in SQL export mode
AddResults('SELECT '+esc(DBObj.Database)+' AS '+Mainform.mask('Database')+', ' +
esc(DBObj.Name)+' AS '+Mainform.mask('Table')+', ' +
IntToStr(DBObj.Rows)+' AS '+Mainform.mask('Rows')+', '+
'0 AS '+Mainform.mask('Duration')
AddResults('SELECT '+esc(DBObj.Database)+' AS '+QuoteIdent('Database')+', ' +
esc(DBObj.Name)+' AS '+QuoteIdent('Table')+', ' +
IntToStr(DBObj.Rows)+' AS '+QuoteIdent('Rows')+', '+
'0 AS '+QuoteIdent('Duration')
);
ToFile := comboExportOutputType.Text = OUTPUT_FILE;
ToDir := comboExportOutputType.Text = OUTPUT_DIR;
@ -1076,23 +1070,23 @@ begin
if chkExportDatabasesDrop.Checked or chkExportDatabasesCreate.Checked then begin
Output(CRLF+CRLF+'# Dumping database structure for '+DBObj.Database+CRLF, False, NeedsDBStructure, False, False, False);
if chkExportDatabasesDrop.Checked and chkExportDatabasesDrop.Enabled then
Output('DROP DATABASE IF EXISTS '+m(FinalDbName), True, NeedsDBStructure, False, False, NeedsDBStructure);
Output('DROP DATABASE IF EXISTS '+QuoteIdent(FinalDbName), True, NeedsDBStructure, False, False, NeedsDBStructure);
if chkExportDatabasesCreate.Checked and chkExportDatabasesCreate.Enabled then begin
if MainForm.ActiveConnection.ServerVersionInt >= 40100 then begin
Struc := MainForm.ActiveConnection.GetVar('SHOW CREATE DATABASE '+m(DBObj.Database), 1);
Struc := MainForm.ActiveConnection.GetVar('SHOW CREATE DATABASE '+QuoteIdent(DBObj.Database), 1);
// Gracefully ignore it when target database exists, important in server mode
Insert('IF NOT EXISTS ', Struc, Pos('DATABASE', Struc) + 9);
// Create the right dbname
Struc := StringReplace(Struc, DBObj.Database, FinalDbName, []);
end else
Struc := 'CREATE DATABASE IF NOT EXISTS '+m(FinalDbName);
Struc := 'CREATE DATABASE IF NOT EXISTS '+QuoteIdent(FinalDbName);
Output(Struc, True, NeedsDBStructure, False, False, NeedsDBStructure);
Output('USE '+m(FinalDbName), True, NeedsDBStructure, False, False, NeedsDBStructure);
Output('USE '+QuoteIdent(FinalDbName), True, NeedsDBStructure, False, False, NeedsDBStructure);
end;
end;
if ToServer and (not chkExportDatabasesCreate.Checked) then begin
// Export to server without "CREATE/USE dbname" and "Same dbs as on source server" - needs a "USE dbname"
Output('USE '+m(FinalDbName), True, False, False, False, NeedsDBStructure);
Output('USE '+QuoteIdent(FinalDbName), True, False, False, False, NeedsDBStructure);
end;
// Table structure
@ -1101,8 +1095,8 @@ begin
if chkExportTablesDrop.Checked then begin
Struc := 'DROP '+UpperCase(DBObj.ObjType)+' IF EXISTS ';
if ToDb then
Struc := Struc + m(FinalDbName)+'.';
Struc := Struc + m(DBObj.Name);
Struc := Struc + QuoteIdent(FinalDbName)+'.';
Struc := Struc + QuoteIdent(DBObj.Name);
Output(Struc, True, True, True, True, True);
end;
if chkExportTablesCreate.Checked then begin
@ -1120,7 +1114,7 @@ begin
end;
Insert('IF NOT EXISTS ', Struc, Pos('TABLE', Struc) + 6);
if ToDb then
Insert(m(FinalDbName)+'.', Struc, Pos('EXISTS', Struc) + 7 )
Insert(QuoteIdent(FinalDbName)+'.', Struc, Pos('EXISTS', Struc) + 7 )
end;
lntView: begin
@ -1131,8 +1125,8 @@ begin
Struc := '# Creating temporary table to overcome VIEW dependency errors'+CRLF+
'CREATE TABLE ';
if ToDb then
Struc := Struc + m(FinalDbName) + '.';
Struc := Struc + m(DBObj.Name)+' (';
Struc := Struc + QuoteIdent(FinalDbName) + '.';
Struc := Struc + QuoteIdent(DBObj.Name)+' (';
for Column in ColumnList do
Struc := Struc + CRLF + #9 + Column.SQLCode + ',';
Delete(Struc, Length(Struc), 1);
@ -1142,21 +1136,21 @@ begin
Struc := '# Removing temporary table and create final VIEW structure'+CRLF+
'DROP TABLE IF EXISTS ';
if ToDb then
Struc := Struc + m(FinalDbName)+'.';
Struc := Struc + m(DBObj.Name);
Struc := Struc + QuoteIdent(FinalDbName)+'.';
Struc := Struc + QuoteIdent(DBObj.Name);
Output(Struc, True, True, True, True, True);
Struc := DBObj.CreateCode;
if ToDb then
Insert(m(FinalDbName)+'.', Struc, Pos('VIEW', Struc) + 5 );
Insert(QuoteIdent(FinalDbName)+'.', Struc, Pos('VIEW', Struc) + 5 );
end;
end;
lntTrigger: begin
StrucResult := MainForm.ActiveConnection.GetResults('SHOW TRIGGERS FROM '+m(DBObj.Database)+' WHERE `Trigger`='+esc(DBObj.Name));
Struc := 'CREATE '+UpperCase(DBObj.ObjType)+' '+m(DBObj.Name)+' '+StrucResult.Col('Timing')+' '+StrucResult.Col('Event')+
' ON '+m(StrucResult.Col('Table'))+' FOR EACH ROW '+StrucResult.Col('Statement');
StrucResult := MainForm.ActiveConnection.GetResults('SHOW TRIGGERS FROM '+QuoteIdent(DBObj.Database)+' WHERE `Trigger`='+esc(DBObj.Name));
Struc := 'CREATE '+UpperCase(DBObj.ObjType)+' '+QuoteIdent(DBObj.Name)+' '+StrucResult.Col('Timing')+' '+StrucResult.Col('Event')+
' ON '+QuoteIdent(StrucResult.Col('Table'))+' FOR EACH ROW '+StrucResult.Col('Statement');
if ToDb then
Insert(m(FinalDbName)+'.', Struc, Pos('TRIGGER', Struc) + 8 );
Insert(QuoteIdent(FinalDbName)+'.', Struc, Pos('TRIGGER', Struc) + 8 );
if ToFile or ToClipboard or ToDir then begin
Struc := 'SET SESSION SQL_MODE=' + esc(StrucResult.Col('sql_mode')) + ';' + CRLF +
'DELIMITER ' + TempDelim + CRLF +
@ -1170,9 +1164,9 @@ begin
Struc := DBObj.CreateCode;
if ToDb then begin
if DBObj.NodeType = lntProcedure then
Insert(m(FinalDbName)+'.', Struc, Pos('PROCEDURE', Struc) + 10 )
Insert(QuoteIdent(FinalDbName)+'.', Struc, Pos('PROCEDURE', Struc) + 10 )
else if DBObj.NodeType = lntFunction then
Insert(m(FinalDbName)+'.', Struc, Pos('FUNCTION', Struc) + 9 );
Insert(QuoteIdent(FinalDbName)+'.', Struc, Pos('FUNCTION', Struc) + 9 );
end;
// Change delimiter for file output, so readers split queries at the right string position
if ToFile or ToDir or ToClipboard then
@ -1182,7 +1176,7 @@ begin
lntEvent: begin
Struc := DBObj.CreateCode;
if ToDb then
Insert(m(FinalDbName)+'.', Struc, Pos('EVENT', Struc) + 6 );
Insert(QuoteIdent(FinalDbName)+'.', Struc, Pos('EVENT', Struc) + 6 );
if ToFile or ToDir or ToClipboard then
Struc := 'DELIMITER ' + TempDelim + CRLF + Struc + TempDelim + CRLF + 'DELIMITER ';
end;
@ -1208,9 +1202,9 @@ begin
if LowerCase(DBObj.Engine) = 'innodb' then
tmp := '~'+tmp+' (approximately)';
Output(CRLF+'# Dumping data for table '+DBObj.Database+'.'+DBObj.Name+': '+tmp+CRLF, False, True, True, False, False);
TargetDbAndObject := m(DBObj.Name);
TargetDbAndObject := QuoteIdent(DBObj.Name);
if ToDb then
TargetDbAndObject := m(FinalDbName) + '.' + TargetDbAndObject;
TargetDbAndObject := QuoteIdent(FinalDbName) + '.' + TargetDbAndObject;
Offset := 0;
RowCount := 0;
// Calculate limit so we select ~100MB per loop
@ -1219,7 +1213,7 @@ begin
Output('DELETE FROM '+TargetDbAndObject, True, True, True, True, True);
Output('/*!40000 ALTER TABLE '+TargetDbAndObject+' DISABLE KEYS */', True, True, True, True, True);
while true do begin
Data := MainForm.ActiveConnection.GetResults('SELECT * FROM '+m(DBObj.Database)+'.'+m(DBObj.Name)+' LIMIT '+IntToStr(Offset)+', '+IntToStr(Limit));
Data := MainForm.ActiveConnection.GetResults('SELECT * FROM '+QuoteIdent(DBObj.Database)+'.'+QuoteIdent(DBObj.Name)+' LIMIT '+IntToStr(Offset)+', '+IntToStr(Limit));
Inc(Offset, Limit);
if Data.RecordCount = 0 then
break;
@ -1230,7 +1224,7 @@ begin
BaseInsert := 'REPLACE INTO ';
BaseInsert := BaseInsert + TargetDbAndObject + ' (';
for i:=0 to Data.ColumnCount-1 do
BaseInsert := BaseInsert + m(Data.ColumnNames[i]) + ', ';
BaseInsert := BaseInsert + QuoteIdent(Data.ColumnNames[i]) + ', ';
Delete(BaseInsert, Length(BaseInsert)-1, 2);
BaseInsert := BaseInsert + ') VALUES'+CRLF+#9+'(';
while true do begin
@ -1316,15 +1310,15 @@ var
rx: TRegExpr;
HasCharsetClause: Boolean;
begin
AddResults('SELECT '+esc(DBObj.Database)+' AS '+Mainform.mask('Database')+', ' +
esc(DBObj.Name)+' AS '+Mainform.mask('Table')+', ' +
esc('Updating...')+' AS '+Mainform.mask('Operation')+', '+
''''' AS '+Mainform.mask('Result')
AddResults('SELECT '+esc(DBObj.Database)+' AS '+QuoteIdent('Database')+', ' +
esc(DBObj.Name)+' AS '+QuoteIdent('Table')+', ' +
esc('Updating...')+' AS '+QuoteIdent('Operation')+', '+
''''' AS '+QuoteIdent('Result')
);
Specs := TStringList.Create;
if chkBulkTableEditDatabase.Checked and (comboBulkTableEditDatabase.Text <> DBObj.Database) then begin
case DBObj.NodeType of
lntTable: Specs.Add('RENAME ' + Mainform.mask(comboBulkTableEditDatabase.Text)+'.'+Mainform.mask(DBObj.Name));
lntTable: Specs.Add('RENAME ' + QuoteIdent(comboBulkTableEditDatabase.Text)+'.'+QuoteIdent(DBObj.Name));
lntView: begin
// Although RENAME works for views, that does not work for moving to another database without getting
// a "Changing schema from x to y is not allowed". Instead, recreate them manually
@ -1333,13 +1327,13 @@ begin
rx.ModifierI := True;
// Replace old database references in VIEW body
rx.Expression := '(["`])'+QuoteRegExprMetaChars(DBObj.Database)+'(["`])';
CreateView := rx.Replace(CreateView, Mainform.mask(comboBulkTableEditDatabase.Text), false);
CreateView := rx.Replace(CreateView, QuoteIdent(comboBulkTableEditDatabase.Text), false);
rx.Free;
// Temporarily switch to new database for VIEW creation, so the database references are correct
DBObj.Connection.Database := comboBulkTableEditDatabase.Text;
DBObj.Connection.Query(CreateView);
DBObj.Connection.Database := DBObj.Database;
DBObj.Connection.Query('DROP VIEW '+Mainform.mask(DBObj.Name));
DBObj.Connection.Query('DROP VIEW '+QuoteIdent(DBObj.Name));
end;
end;
FModifiedDbs.Add(DBObj.Database);
@ -1370,7 +1364,7 @@ begin
LogRow := FResults.Last;
if Specs.Count > 0 then begin
DBObj.Connection.Query('ALTER TABLE ' + Mainform.mask(DBObj.Database) + '.' + Mainform.mask(DBObj.Name) + ' ' + ImplodeStr(', ', Specs));
DBObj.Connection.Query('ALTER TABLE ' + QuoteIdent(DBObj.Database) + '.' + QuoteIdent(DBObj.Name) + ' ' + ImplodeStr(', ', Specs));
LogRow[2] := 'Done';
LogRow[3] := 'Success';
end else begin

View File

@ -101,7 +101,7 @@ begin
if DBObject.Name <> '' then begin
// Edit mode
editName.Text := DBObject.Name;
Definitions := MainForm.ActiveConnection.GetResults('SHOW TRIGGERS FROM '+Mainform.mask(Mainform.ActiveDatabase));
Definitions := MainForm.ActiveConnection.GetResults('SHOW TRIGGERS FROM '+QuoteIdent(Mainform.ActiveDatabase));
Found := False;
while not Definitions.Eof do begin
if Definitions.Col('Trigger') = DBObject.Name then begin
@ -175,7 +175,7 @@ begin
// his statement. The user must fix such errors and re-press "Save" while we have them in memory,
// otherwise the trigger attributes are lost forever.
if DBObject.Name <> '' then try
MainForm.ActiveConnection.Query('DROP TRIGGER '+Mainform.mask(DBObject.Name));
MainForm.ActiveConnection.Query('DROP TRIGGER '+QuoteIdent(DBObject.Name));
except
end;
// CREATE
@ -184,10 +184,10 @@ begin
// ON tbl_name FOR EACH ROW trigger_stmt
sql := 'CREATE ';
if comboDefiner.Text <> '' then
sql := sql + 'DEFINER='+DBObject.Connection.QuoteIdent(comboDefiner.Text, '@')+' ';
sql := sql + 'TRIGGER '+Mainform.mask(editName.Text)+' '+
sql := sql + 'DEFINER='+QuoteIdent(comboDefiner.Text, True, '@')+' ';
sql := sql + 'TRIGGER '+QuoteIdent(editName.Text)+' '+
comboTiming.Items[comboTiming.ItemIndex]+' '+comboEvent.Items[comboEvent.ItemIndex]+
' ON '+Mainform.mask(comboTable.Text)+
' ON '+QuoteIdent(comboTable.Text)+
' FOR EACH ROW '+SynMemoStatement.Text;
MainForm.ActiveConnection.Query(sql);
DBObject.Name := editName.Text;
@ -222,7 +222,7 @@ begin
if comboTable.Text = '' then
CanExecute := False
else try
Columns := MainForm.ActiveConnection.GetResults('SHOW COLUMNS FROM '+Mainform.mask(comboTable.Text));
Columns := MainForm.ActiveConnection.GetResults('SHOW COLUMNS FROM '+QuoteIdent(comboTable.Text));
while not Columns.Eof do begin
Proposal.InsertList.Add(Columns.Col('Field'));
Proposal.ItemList.Add(Format(SYNCOMPLETION_PATTERN, [ICONINDEX_FIELD, GetFirstWord(Columns.Col('Type')), Columns.Col('Field')]) );

View File

@ -230,10 +230,10 @@ begin
// Load user@host list
try
FUsers := MainForm.ActiveConnection.GetCol(
'SELECT CONCAT('+MainForm.mask('user')+', '+esc('@')+', '+MainForm.mask('host')+') '+
'FROM '+MainForm.mask('mysql')+'.'+MainForm.mask('user')+' '+
'WHERE '+MainForm.mask('Password')+'!='+esc('!')+' '+
'ORDER BY LOWER('+MainForm.mask('user')+'), LOWER('+MainForm.mask('host')+')');
'SELECT CONCAT('+QuoteIdent('user')+', '+esc('@')+', '+QuoteIdent('host')+') '+
'FROM '+QuoteIdent('mysql')+'.'+QuoteIdent('user')+' '+
'WHERE '+QuoteIdent('Password')+'!='+esc('!')+' '+
'ORDER BY LOWER('+QuoteIdent('user')+'), LOWER('+QuoteIdent('host')+')');
InvalidateVT(listUsers, VTREE_NOTLOADED, False);
FPrivObjects := TPrivObjList.Create(TPrivComparer.Create, True);
Modified := False;
@ -475,8 +475,8 @@ begin
for Ptmp in FPrivObjects do begin
if Ptmp.DBObj.NodeType = lntColumn then begin
Ptmp.GrantCode := 'GRANT ' + Copy(Ptmp.GrantCode, 1, Length(Ptmp.GrantCode)-2) + ' ON ' +
MainForm.mask(Ptmp.DBObj.Database) + '.' +
MainForm.mask(Ptmp.DBObj.Name) +
QuoteIdent(Ptmp.DBObj.Database) + '.' +
QuoteIdent(Ptmp.DBObj.Name) +
' TO ' + UserHost;
end;
// Flag all privs as added, so "Save" action applies them
@ -819,11 +819,11 @@ begin
lntNone:
OnObj := '*.*';
lntDb:
OnObj := Mainform.mask(P.DBObj.Database) + '.*';
OnObj := QuoteIdent(P.DBObj.Database) + '.*';
lntTable, lntFunction, lntProcedure:
OnObj := UpperCase(P.DBObj.ObjType) + ' ' + Mainform.mask(P.DBObj.Database) + '.' + Mainform.mask(P.DBObj.Name);
OnObj := UpperCase(P.DBObj.ObjType) + ' ' + QuoteIdent(P.DBObj.Database) + '.' + QuoteIdent(P.DBObj.Name);
lntColumn:
OnObj := 'TABLE ' + Mainform.mask(P.DBObj.Database) + '.' + Mainform.mask(P.DBObj.Name);
OnObj := 'TABLE ' + QuoteIdent(P.DBObj.Database) + '.' + QuoteIdent(P.DBObj.Name);
else
raise Exception.Create('Unhandled privilege object: '+P.DBObj.ObjType);
end;
@ -836,7 +836,7 @@ begin
if P.DeletedPrivs[i] = 'GRANT' then
Revoke := Revoke + ' OPTION';
if P.DBObj.NodeType = lntColumn then
Revoke := Revoke + '('+Mainform.mask(P.DBObj.Column)+')';
Revoke := Revoke + '('+QuoteIdent(P.DBObj.Column)+')';
Revoke := Revoke + ', ';
end;
Delete(Revoke, Length(Revoke)-1, 1);
@ -852,7 +852,7 @@ begin
Continue;
Grant := Grant + P.AddedPrivs[i];
if P.DBObj.NodeType = lntColumn then
Grant := Grant + '('+Mainform.mask(P.DBObj.Column)+')';
Grant := Grant + '('+QuoteIdent(P.DBObj.Column)+')';
Grant := Grant + ', ';
end;
Delete(Grant, Length(Grant)-1, 1);
@ -877,7 +877,7 @@ begin
else begin
Tables := Explode(',', 'user,db,tables_priv,columns_priv');
for Table in Tables do begin
Conn.Query('UPDATE '+Mainform.mask('mysql')+'.'+Mainform.mask(Table)+
Conn.Query('UPDATE '+QuoteIdent('mysql')+'.'+QuoteIdent(Table)+
' SET User='+esc(editUsername.Text)+', Host='+esc(editFromHost.Text)+
' WHERE User='+esc(OrgUsername)+' AND Host='+esc(OrgFromHost)
);

View File

@ -155,11 +155,11 @@ begin
sql := 'ALTER ';
viewname := DBObject.Name;
end;
viewname := Mainform.mask(viewname);
viewname := QuoteIdent(viewname);
if rgAlgorithm.Enabled and (rgAlgorithm.ItemIndex > -1) then
sql := sql + 'ALGORITHM = '+Uppercase(rgAlgorithm.Items[rgAlgorithm.ItemIndex])+' ';
if comboDefiner.Text <> '' then
sql := sql + 'DEFINER='+DBObject.Connection.QuoteIdent(comboDefiner.Text, '@')+' ';
sql := sql + 'DEFINER='+QuoteIdent(comboDefiner.Text, True, '@')+' ';
sql := sql + 'VIEW ' + viewname+' AS '+SynMemoSelect.Text+' ';
if rgCheck.Enabled and (rgCheck.ItemIndex > 0) then
sql := sql + 'WITH '+Uppercase(rgCheck.Items[rgCheck.ItemIndex])+' CHECK OPTION';
@ -168,7 +168,7 @@ begin
MainForm.ActiveConnection.Query(sql);
// Probably rename view
if (DBObject.Name <> '') and (DBObject.Name <> editName.Text) then begin
renamed := Mainform.mask(editName.Text);
renamed := QuoteIdent(editName.Text);
MainForm.ActiveConnection.Query('RENAME TABLE '+viewname + ' TO '+renamed);
end;
DBObject.Name := editName.Text;