Unify name and case of information_schema, per connection. Finally. Closes #855

This commit is contained in:
Ansgar Becker
2020-01-16 08:03:20 +01:00
parent 1c39075d7c
commit 340cd5066c
5 changed files with 32 additions and 25 deletions

View File

@ -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)
);

View File

@ -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+

View File

@ -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');

View File

@ -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)
);

View File

@ -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;