From 340cd5066cb2bc2001d142f504bd46f2b66d9223 Mon Sep 17 00:00:00 2001 From: Ansgar Becker Date: Thu, 16 Jan 2020 08:03:20 +0100 Subject: [PATCH] Unify name and case of information_schema, per connection. Finally. Closes #855 --- source/copytable.pas | 2 +- source/dbconnection.pas | 47 ++++++++++++++++++++++----------------- source/main.pas | 4 ++-- source/routine_editor.pas | 2 +- source/tabletools.pas | 2 +- 5 files changed, 32 insertions(+), 25 deletions(-) diff --git a/source/copytable.pas b/source/copytable.pas index 3b2fa59c..59a6bdeb 100644 --- a/source/copytable.pas +++ b/source/copytable.pas @@ -377,7 +377,7 @@ begin // Watch out if target table exists TableExistence := FConnection.GetVar('SELECT '+FConnection.QuoteIdent('table_name')+ - ' FROM '+FConnection.QuoteIdent('information_schema')+'.'+FConnection.QuoteIdent('tables')+ + ' FROM '+FConnection.QuoteIdent(FConnection.InfSch)+'.'+FConnection.QuoteIdent('tables')+ ' WHERE '+FConnection.QuoteIdent(FConnection.GetSQLSpecifity(spISTableSchemaCol))+'='+FConnection.EscapeString(comboDatabase.Text)+ ' AND '+FConnection.QuoteIdent('table_name')+'='+FConnection.EscapeString(editNewTablename.Text) ); diff --git a/source/dbconnection.pas b/source/dbconnection.pas index 2ecb8dd9..7f51abbc 100644 --- a/source/dbconnection.pas +++ b/source/dbconnection.pas @@ -378,6 +378,7 @@ type FFavorites: TStringList; FPrefetchResults: TDBQueryList; FForeignKeyQueriesFailed: Boolean; + FInfSch: String; procedure SetActive(Value: Boolean); virtual; abstract; procedure DoBeforeConnect; virtual; procedure DoAfterConnect; virtual; @@ -489,6 +490,7 @@ type property LockedByThread: TThread read FLockedByThread write SetLockedByThread; property Datatypes: TDBDataTypeArray read FDatatypes; property Favorites: TStringList read FFavorites; + property InfSch: String read FInfSch; function GetLockedTableCount(db: String): Integer; function IdentifierEquals(Ident1, Ident2: String): Boolean; function GetTableColumns(Table: TDBObject): TTableColumnList; virtual; @@ -1701,6 +1703,8 @@ begin FKeepAliveTimer := TTimer.Create(Self); FFavorites := TStringList.Create; FForeignKeyQueriesFailed := False; + // System database/schema, should be uppercase on MSSQL only, see #855 + FInfSch := 'information_schema'; end; @@ -1730,6 +1734,7 @@ begin SetLength(FDatatypes, Length(MSSQLDatatypes)); for i:=0 to High(MSSQLDatatypes) do FDatatypes[i] := MSSQLDatatypes[i]; + FInfSch := 'INFORMATION_SCHEMA'; end; @@ -1758,6 +1763,8 @@ begin SetLength(FDatatypes, Length(SQLiteDatatypes)); for i:=0 to High(SQLiteDatatypes) do FDatatypes[i] := SQLiteDatatypes[i]; + // SQLite does not have IS: + FInfSch := ''; end; @@ -3194,7 +3201,7 @@ begin Result := GetVar('SHOW CREATE VIEW '+QuoteIdent(Database)+'.'+QuoteIdent(Name), 1); except on E:EDbError do begin - ViewIS := GetResults('SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE '+ + ViewIS := GetResults('SELECT * FROM '+InfSch+'.VIEWS WHERE '+ 'TABLE_SCHEMA='+EscapeString(Database)+' AND TABLE_NAME='+EscapeString(Name)); Result := 'CREATE '; if ViewIS.Col('DEFINER') <> '' then @@ -3314,7 +3321,7 @@ begin end; else begin Result := GetVar('SELECT VIEW_DEFINITION'+ - ' FROM INFORMATION_SCHEMA.VIEWS'+ + ' FROM '+InfSch+'.VIEWS'+ ' WHERE TABLE_NAME='+EscapeString(Obj.Name)+ ' AND '+SchemaClauseIS('TABLE') ); @@ -3367,7 +3374,7 @@ begin end; else begin Result := GetVar('SELECT ROUTINE_DEFINITION'+ - ' FROM INFORMATION_SCHEMA.ROUTINES'+ + ' FROM '+InfSch+'.ROUTINES'+ ' WHERE ROUTINE_NAME='+EscapeString(Obj.Name)+ ' AND ROUTINE_TYPE='+EscapeString('FUNCTION')+ ' AND '+SchemaClauseIS('ROUTINE') @@ -3389,7 +3396,7 @@ begin end; else begin Result := GetVar('SELECT ROUTINE_DEFINITION'+ - ' FROM INFORMATION_SCHEMA.ROUTINES'+ + ' FROM '+InfSch+'.ROUTINES'+ ' WHERE ROUTINE_NAME='+EscapeString(Obj.Name)+ ' AND ROUTINE_TYPE='+EscapeString('PROCEDURE')+ ' AND '+SchemaClauseIS('ROUTINE') @@ -3819,7 +3826,7 @@ begin FAllDatabases := GetCol('SHOW DATABASES'); except on E:EDbError do try - FAllDatabases := GetCol('SELECT '+QuoteIdent('SCHEMA_NAME')+' FROM '+QuoteIdent('information_schema')+'.'+QuoteIdent('SCHEMATA')+' ORDER BY '+QuoteIdent('SCHEMA_NAME')); + FAllDatabases := GetCol('SELECT '+QuoteIdent('SCHEMA_NAME')+' FROM '+QuoteIdent(InfSch)+'.'+QuoteIdent('SCHEMATA')+' ORDER BY '+QuoteIdent('SCHEMA_NAME')); except on E:EDbError do begin FAllDatabases := TStringList.Create; @@ -3860,7 +3867,7 @@ begin ' FROM '+QuoteIdent('pg_catalog')+'.'+QuoteIdent('pg_namespace'); if Parameters.IsRedshift then begin DbQuery := DbQuery + ' WHERE '+QuoteIdent('nspowner')+' != 1'+ - ' OR '+QuoteIdent('nspname')+' IN ('+EscapeString('pg_catalog')+', '+EscapeString('information_schema')+')'; + ' OR '+QuoteIdent('nspname')+' IN ('+EscapeString('pg_catalog')+', '+EscapeString(InfSch)+')'; end; DbQuery := DbQuery + ' ORDER BY '+QuoteIdent('nspname'); FAllDatabases := GetCol(DbQuery); @@ -4556,7 +4563,7 @@ begin SchemaClause := 'TABLE_SCHEMA='+EscapeString(Table.Schema) else SchemaClause := GetSQLSpecifity(spISTableSchemaCol)+'='+EscapeString(Table.Database); - ColQuery := GetResults('SELECT * FROM '+QuoteIdent('information_schema')+'.'+QuoteIdent(InformationSchemaObjects[TableIdx])+ + ColQuery := GetResults('SELECT * FROM '+QuoteIdent(InfSch)+'.'+QuoteIdent(InformationSchemaObjects[TableIdx])+ ' WHERE '+SchemaClause+' AND TABLE_NAME='+EscapeString(Table.Name)+ ' ORDER BY ORDINAL_POSITION'); while not ColQuery.Eof do begin @@ -4733,8 +4740,8 @@ begin ColTableIdx := InformationSchemaObjects.IndexOf('KEY_COLUMN_USAGE'); ConTableIdx := InformationSchemaObjects.IndexOf('TABLE_CONSTRAINTS'); KeyQuery := GetResults('SELECT * FROM '+ - QuoteIdent('information_schema')+'.'+QuoteIdent(InformationSchemaObjects[ColTableIdx])+' AS col'+ - ', '+QuoteIdent('information_schema')+'.'+QuoteIdent(InformationSchemaObjects[ConTableIdx])+' AS con'+ + QuoteIdent(InfSch)+'.'+QuoteIdent(InformationSchemaObjects[ColTableIdx])+' AS col'+ + ', '+QuoteIdent(InfSch)+'.'+QuoteIdent(InformationSchemaObjects[ConTableIdx])+' AS con'+ ' WHERE col.TABLE_SCHEMA='+EscapeString(Database)+ ' AND col.TABLE_NAME='+EscapeString(Table.Name)+ ' AND col.TABLE_SCHEMA=con.TABLE_SCHEMA'+ @@ -4924,14 +4931,14 @@ begin try // Combine two IS tables by hand, not by JOIN, as this is too slow. See #852 ForeignQuery := GetResults('SELECT *'+ - ' FROM information_schema.REFERENTIAL_CONSTRAINTS'+ + ' FROM '+InfSch+'.REFERENTIAL_CONSTRAINTS'+ ' WHERE'+ ' CONSTRAINT_SCHEMA='+EscapeString(Table.Database)+ ' AND TABLE_NAME='+EscapeString(Table.Name)+ ' AND REFERENCED_TABLE_NAME IS NOT NULL' ); ColQuery := GetResults('SELECT *'+ - ' FROM information_schema.KEY_COLUMN_USAGE'+ + ' FROM '+InfSch+'.KEY_COLUMN_USAGE'+ ' WHERE'+ ' CONSTRAINT_SCHEMA='+EscapeString(Table.Database)+ ' AND TABLE_NAME='+EscapeString(Table.Name)+ @@ -5100,15 +5107,15 @@ var Objects: TDBObjectList; Obj: TDBObject; begin - Log(lcDebug, 'Fetching objects in information_schema db ...'); + Log(lcDebug, 'Fetching objects in '+InfSch+' db ...'); Ping(True); if not Assigned(FInformationSchemaObjects) then begin FInformationSchemaObjects := TStringList.Create; // Need to find strings case insensitively: FInformationSchemaObjects.CaseSensitive := False; // Gracefully return an empty list on old servers - if AllDatabases.IndexOf('information_schema') > -1 then begin - Objects := GetDBObjects('information_schema'); + if AllDatabases.IndexOf(InfSch) > -1 then begin + Objects := GetDBObjects(InfSch); for Obj in Objects do FInformationSchemaObjects.Add(Obj.Name); end; @@ -5433,7 +5440,7 @@ begin // Return a db's table list try Cache.FCollation := GetVar('SELECT '+QuoteIdent('DEFAULT_COLLATION_NAME')+ - ' FROM '+QuoteIdent('information_schema')+'.'+QuoteIdent('SCHEMATA')+ + ' FROM '+QuoteIdent(InfSch)+'.'+QuoteIdent('SCHEMATA')+ ' WHERE '+QuoteIdent('SCHEMA_NAME')+'='+EscapeString(db)); except Cache.FCollation := ''; @@ -5444,7 +5451,7 @@ begin // Tables and views Results := nil; try - if Parameters.FullTableStatus or (UpperCase(db) = 'INFORMATION_SCHEMA') then begin + if Parameters.FullTableStatus or (UpperCase(db) = UpperCase(InfSch)) then begin Results := GetResults('SHOW TABLE STATUS FROM '+QuoteIdent(db)); end else begin Results := GetResults('SELECT '+ @@ -5466,7 +5473,7 @@ begin 'NULL AS '+QuoteIdent('Check_time')+', '+ 'NULL AS '+QuoteIdent('Checksum')+', '+ 'NULL AS '+QuoteIdent('Create_options')+ - ' FROM INFORMATION_SCHEMA.TABLES'+ + ' FROM '+InfSch+'.TABLES'+ ' WHERE TABLE_SCHEMA='+EscapeString(db)+' AND TABLE_TYPE IN('+EscapeString('BASE TABLE')+', '+EscapeString('VIEW')+')' ); end; @@ -5581,7 +5588,7 @@ begin if ServerVersionInt >= 50100 then try if InformationSchemaObjects.IndexOf('EVENTS') > -1 then Results := GetResults('SELECT *, EVENT_SCHEMA AS '+QuoteIdent('Db')+', EVENT_NAME AS '+QuoteIdent('Name')+ - ' FROM information_schema.'+QuoteIdent('EVENTS')+' WHERE '+QuoteIdent('EVENT_SCHEMA')+'='+EscapeString(db)) + ' FROM '+InfSch+'.'+QuoteIdent('EVENTS')+' WHERE '+QuoteIdent('EVENT_SCHEMA')+'='+EscapeString(db)) else Results := GetResults('SHOW EVENTS FROM '+QuoteIdent(db)); except @@ -5683,7 +5690,7 @@ begin ' '+DataLenClause+' AS data_length,'+ ' '+IndexLenClause+' AS index_length,'+ ' c.reltuples, obj_description(c.oid) AS comment'+ - ' FROM '+QuoteIdent('information_schema')+'.'+QuoteIdent('tables')+' AS t'+ + ' FROM '+QuoteIdent(InfSch)+'.'+QuoteIdent('tables')+' AS t'+ ' LEFT JOIN '+QuoteIdent('pg_namespace')+' n ON t.table_schema = n.nspname'+ ' LEFT JOIN '+QuoteIdent('pg_class')+' c ON n.oid = c.relnamespace AND c.relname=t.table_name'+ ' WHERE t.'+QuoteIdent('table_schema')+'='+EscapeString(db) // Use table_schema when using schemata @@ -6267,7 +6274,7 @@ begin else SchemaClause := 'AND '+GetSQLSpecifity(spISTableSchemaCol)+'='+EscapeString(DBObj.Database); Results := GetResults('SELECT * '+ - 'FROM INFORMATION_SCHEMA.COLUMNS '+ + 'FROM '+InfSch+'.COLUMNS '+ 'WHERE '+ ' TABLE_NAME='+EscapeString(DBObj.Name)+' '+ SchemaClause+ diff --git a/source/main.pas b/source/main.pas index 753bf603..edb49c32 100644 --- a/source/main.pas +++ b/source/main.pas @@ -10204,7 +10204,7 @@ begin Conn.QuoteIdent('STATE')+', '+ 'LEFT('+Conn.QuoteIdent('INFO')+', '+IntToStr(SIZE_KB*50)+') AS '+Conn.QuoteIdent('Info'); // Get additional column names into SELECT query and ListProcesses tree - IS_objects := Conn.GetDBObjects('information_schema'); + IS_objects := Conn.GetDBObjects(Conn.InfSch); for Obj in IS_objects do begin if Obj.Name = 'PROCESSLIST' then begin ProcessColumns := Obj.TableColumns; @@ -10225,7 +10225,7 @@ begin end; end; Results := Conn.GetResults('SELECT '+Columns+' FROM '+ - Conn.QuoteIdent('information_schema')+'.'+Conn.QuoteIdent('PROCESSLIST')); + Conn.QuoteIdent(Conn.InfSch)+'.'+Conn.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 := Conn.GetResults('SHOW FULL PROCESSLIST'); diff --git a/source/routine_editor.pas b/source/routine_editor.pas index 2b342ada..33e98940 100644 --- a/source/routine_editor.pas +++ b/source/routine_editor.pas @@ -482,7 +482,7 @@ begin if DBObject.Name <> '' then begin // Create temp name i := 0; - allRoutineNames := DBObject.Connection.GetCol('SELECT ROUTINE_NAME FROM '+DBObject.Connection.QuoteIdent('information_schema')+'.'+DBObject.Connection.QuoteIdent('ROUTINES')+ + allRoutineNames := DBObject.Connection.GetCol('SELECT ROUTINE_NAME FROM '+DBObject.Connection.QuoteIdent(DBObject.Connection.InfSch)+'.'+DBObject.Connection.QuoteIdent('ROUTINES')+ ' WHERE ROUTINE_SCHEMA = '+esc(Mainform.ActiveDatabase)+ ' AND ROUTINE_TYPE = '+esc(ProcOrFunc) ); diff --git a/source/tabletools.pas b/source/tabletools.pas index 1f7025f8..05cb6e2f 100644 --- a/source/tabletools.pas +++ b/source/tabletools.pas @@ -961,7 +961,7 @@ begin esc(DBObj.Name)+' AS '+DBObj.Connection.QuoteIdent('Table')+', '+ DBObj.Connection.GetSQLSpecifity(spFuncCeil)+'(('+DBObj.Connection.GetSQLSpecifity(spFuncLength)+'('+RoutineDefinitionColumn+') - '+DBObj.Connection.GetSQLSpecifity(spFuncLength)+'(REPLACE('+RoutineDefinitionColumn+', '+esc(FindText)+', '+esc('')+'))) / '+DBObj.Connection.GetSQLSpecifity(spFuncLength)+'('+esc(FindText)+')) AS '+DBObj.Connection.QuoteIdent('Found rows')+', '+ '0 AS '+DBObj.Connection.QuoteIdent('Relevance')+ - 'FROM '+DBObj.Connection.QuoteIdent('information_schema')+'.'+DBObj.Connection.QuoteIdent('routines')+' '+ + 'FROM '+DBObj.Connection.QuoteIdent(DBObj.Connection.InfSch)+'.'+DBObj.Connection.QuoteIdent('routines')+' '+ 'WHERE '+DBObj.Connection.QuoteIdent(RoutineSchemaColumn)+'='+esc(DBObj.Database)+' AND '+DBObj.Connection.QuoteIdent('routine_name')+'='+esc(DBObj.Name); AddResults(SQL, DBObj.Connection); end;