diff --git a/source/const.inc b/source/const.inc index d5037e74..7eff1f0f 100644 --- a/source/const.inc +++ b/source/const.inc @@ -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']; diff --git a/source/copytable.pas b/source/copytable.pas index b176c511..f0db6f3c 100644 --- a/source/copytable.pas +++ b/source/copytable.pas @@ -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; diff --git a/source/createdatabase.pas b/source/createdatabase.pas index 6cef8a5f..a1d79dc8 100644 --- a/source/createdatabase.pas +++ b/source/createdatabase.pas @@ -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; diff --git a/source/event_editor.pas b/source/event_editor.pas index 9b7039b7..3a1b7235 100644 --- a/source/event_editor.pas +++ b/source/event_editor.pas @@ -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; diff --git a/source/helpers.pas b/source/helpers.pas index f5c9befb..233995bd 100644 --- a/source/helpers.pas +++ b/source/helpers.pas @@ -590,10 +590,10 @@ begin efXML: tmp := #9'' + 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 diff --git a/source/insertfiles.pas b/source/insertfiles.pas index bc25d3c3..a4ee2a21 100644 --- a/source/insertfiles.pas +++ b/source/insertfiles.pas @@ -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 diff --git a/source/loaddata.pas b/source/loaddata.pas index 3274faa9..a282c04a 100644 --- a/source/loaddata.pas +++ b/source/loaddata.pas @@ -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 ('; diff --git a/source/main.pas b/source/main.pas index 0eac3908..23c414fe 100644 --- a/source/main.pas +++ b/source/main.pas @@ -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); diff --git a/source/mysql_connection.pas b/source/mysql_connection.pas index a878b72d..4ef6fd66 100644 --- a/source/mysql_connection.pas +++ b/source/mysql_connection.pas @@ -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; - Result := StringReplace(Result, '`', '``', [rfReplaceAll]); - if Glue <> #0 then - Result := StringReplace(Result, Glue, '`'+Glue+'`', [rfReplaceAll]); - Result := '`' + Result + '`'; + 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]); + 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 diff --git a/source/routine_editor.pas b/source/routine_editor.pas index e8cbe248..29e2e2c9 100644 --- a/source/routine_editor.pas +++ b/source/routine_editor.pas @@ -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; diff --git a/source/table_editor.pas b/source/table_editor.pas index 7a1e9f78..27e1b157 100644 --- a/source/table_editor.pas +++ b/source/table_editor.pas @@ -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 diff --git a/source/tabletools.pas b/source/tabletools.pas index 83eb29a3..9e8e09fa 100644 --- a/source/tabletools.pas +++ b/source/tabletools.pas @@ -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 diff --git a/source/trigger_editor.pas b/source/trigger_editor.pas index 2f098444..75825d8e 100644 --- a/source/trigger_editor.pas +++ b/source/trigger_editor.pas @@ -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')]) ); diff --git a/source/usermanager.pas b/source/usermanager.pas index 3bd74e5e..23a4671d 100644 --- a/source/usermanager.pas +++ b/source/usermanager.pas @@ -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) ); diff --git a/source/view.pas b/source/view.pas index d35e8e6c..8629684a 100644 --- a/source/view.pas +++ b/source/view.pas @@ -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;