blob: 3b9c92ac9731d9840af7f8bdf352e05909e72356 [file] [log] [blame]
/*
* Copyright (c) 2005. IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* IBM Corporation - initial API and implementation
*/
package org.eclipse.datatools.sqltools.sqleditor.internal.sql;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.datatools.modelbase.sql.constraints.Index;
import org.eclipse.datatools.modelbase.sql.routines.Function;
import org.eclipse.datatools.modelbase.sql.routines.Procedure;
import org.eclipse.datatools.modelbase.sql.schema.Catalog;
import org.eclipse.datatools.modelbase.sql.schema.Database;
import org.eclipse.datatools.modelbase.sql.schema.Event;
import org.eclipse.datatools.modelbase.sql.schema.Schema;
import org.eclipse.datatools.modelbase.sql.tables.Column;
import org.eclipse.datatools.modelbase.sql.tables.Table;
import org.eclipse.datatools.modelbase.sql.tables.Trigger;
import org.eclipse.datatools.modelbase.sql.tables.ViewTable;
import org.eclipse.datatools.sqltools.core.DatabaseIdentifier;
import org.eclipse.datatools.sqltools.editor.contentassist.ISQLDBProposalsService;
import org.eclipse.datatools.sqltools.editor.contentassist.SQLDBProposalsRequest;
import org.eclipse.datatools.sqltools.editor.core.connection.ISQLEditorConnectionInfo;
import org.eclipse.datatools.sqltools.sql.parser.SQLParserConstants;
import org.eclipse.datatools.sqltools.sql.reference.ITable;
import org.eclipse.datatools.sqltools.sql.util.ModelUtil;
import org.eclipse.emf.common.util.EList;
/**
* Provides database identifier proposal services for the editor, to support
* code completion. These are services to construct and return a list of
* proposals of database objects (tables, columns) based on a given database
* connection.
*
* This class implements the <code>ISQLDBProposalsService</code> interface.
*
* @author Hetty Dougherty
* @author bgp
*/
public class SQLDBProposalsService implements ISQLDBProposalsService {
private ISQLEditorConnectionInfo fConnInfo;
private List fDBProposalList;
private SQLDBProposalsRequest fRequest;
/**
* Constructs an instance of this class with the given
* <code>ISQLEditorConnectionInfo</code> object.
*
* @param connInfo
* the <code>ISQLEditorConnectionInfo</code> object to use
*/
public SQLDBProposalsService(ISQLEditorConnectionInfo connInfo) {
super();
fConnInfo = connInfo;
fDBProposalList = new ArrayList();
fRequest = null;
}
//
// /**
// * Returns a value indicating whether tables only, columns only, or both
// * tables and columns are needed for the proposal list by examining the
// * given list of tokens indicating the start of the expression for which
// * DB proposals are wanted. The returned value contains the constants
// * PROPOSAL_TYPE_TABLES and PROPOSAL_TYPE_COLUMNS either alone or "ORed"
// * together, or PROPOSAL_TYPE_INVALID.
// *
// * @param tokenList list of tokens indicating the start of the expression
// for
// * which the user wants DB proposals
// * @return
// */
// protected int determineProposalType( SQLDBProposalsRequest request ) {
// int proposalType = request.getScope();
// //try to determine a scope
// if (proposalType == SQLParserConstants.SCOPE_DEFAULT || proposalType ==
// SQLParserConstants.SCOPE_COLUMNS)
// {
// if (request.get) {
// if (this.fConnInfo.getDefaultSchemaName() == null) {
// proposalType = SQLParserConstants.SCOPE_TABLES;
// } else {
// proposalType = SQLParserConstants.SCOPE_TABLES |
// SQLParserConstants.SCOPE_COLUMNS;
// }
// } else if (tokenList.size() == 2) {
// proposalType = SQLParserConstants.SCOPE_COLUMNS;
// }
// }else if ( proposalType == SQLParserConstants.SCOPE_TRIGGERS)
// {
// if (tokenList.size() == 1) {
// if (this.fConnInfo.getDefaultSchemaName() == null) {
// proposalType = SQLParserConstants.SCOPE_TABLES;
// } else {
// proposalType = SQLParserConstants.SCOPE_TABLES |
// SQLParserConstants.SCOPE_TRIGGERS;
// }
// }
// }
//
// return proposalType;
// }
/**
* Gets the <code>ISQLEditorConnectionInfo</code> used to provide content
* assist. Implements <code>ISQLDBProposalsService</code> interface.
*
* @return the current <code>ISQLEditorConnectionInfo</code> object
* @see ISQLDBProposalsService#getConnectionInfo()
*/
public ISQLEditorConnectionInfo getConnectionInfo() {
return fConnInfo;
}
/**
* Gets the list of <code>SQLDBProposal</code> objects for the content
* assist proposals. Implements <code>ISQLDBProposalsService</code>
* interface.
*
* @return the list of proposals
* @see ISQLDBProposalsService#getDBProposals()
*/
public List getDBProposals() {
return fDBProposalList;
}
/**
* Gets a <code>Schema</code> object with the given name from the given
* the database.
*
* @param database
* the database to search for the named schema
* @param schemaName
* the name of the schema to find
* @return the <code>Schema</code> object with the given name
*/
protected Schema getSchema(Database database, String catalogName, String schemaName) {
EList schemaList = ModelUtil.getSchemas(database, catalogName);
Schema schema = null;
for (int i = 0; i < schemaList.size(); i++) {
Schema thisSchema = (Schema) schemaList.get(i);
if (thisSchema.getName().equalsIgnoreCase(schemaName)) {
schema = thisSchema;
break;
}
}
return schema;
}
/**
* Gets a <code>Schema</code> object with the given name from the given
* the database.
*
* @param database
* the database to search for the named schema
* @param schemaName
* the name of the schema to find
* @return the <code>Schema</code> object with the given name
*/
protected void loadSchemas(Database database, String catalogName, boolean clear) {
if (clear) {
fDBProposalList.clear();
}
EList schemaList = ModelUtil.getSchemas(database,catalogName);
for (int i = 0; i < schemaList.size(); i++) {
Schema thisSchema = (Schema) schemaList.get(i);
fDBProposalList.add(new SQLDBProposal(thisSchema));
}
}
/**
* Gets a <code>Schema</code> object with the given name from the given
* the database.
*
* @param database
* the database to search for the named schema
* @param schemaName
* the name of the schema to find
* @return the <code>Schema</code> object with the given name
*/
protected void loadCatalogs(Database database, boolean clear) {
if (clear) {
fDBProposalList.clear();
}
EList catalogsList = database.getCatalogs();
for (int i = 0; i < catalogsList.size(); i++) {
Catalog thisCatalog = (Catalog) catalogsList.get(i);
fDBProposalList.add(new SQLDBProposal(thisCatalog));
}
}
/**
* Gets the content assist request for database meta objects.
*
* @return the request
*/
public SQLDBProposalsRequest getSQLDBProposalRequest() {
return fRequest;
}
/**
* Creates and stores a list of <code>SQLDBProposal</code> objects for
* each column in the given table. Retrieve the list using getDBProposals().
* The current list of proposals, if any, is cleared.
*
* @param table
* the <code>Table</code> object for which columns are needed
*/
protected void loadColumns(Table table) {
loadColumns(table, true, table.getName());
}
/**
* Creates and stores a list of <code>SQLDBProposal</code> objects for
* each column in the given table. Retrieve the list using getDBProposals().
*
* @param table
* the <code>Table</code> object for which columns are needed
* @param clear
* when true, clear the existing list of proposals before loading
*/
protected void loadColumns(Table table, boolean clear, String alias) {
if (table != null) {
if (clear) {
fDBProposalList.clear();
}
EList columns = table.getColumns();
for (int j = 0; j < columns.size(); j++) {
Column column = (Column) columns.get(j);
fDBProposalList.add(new SQLDBProposal(column, alias));
}
}
}
/**
* Creates and stores a list of <code>SQLDBProposal</code> objects for the
* available schemas, tables, and columns of the currently connected
* database. Retrieve the list using getDBProposals(). The current list of
* proposals, if any, is cleared.
*
* @param tokenList
* list of strings indicating the start of the expression for
* which the user wants DB proposals
*/
protected void loadDBProposals(SQLDBProposalsRequest request) {
fDBProposalList.clear();
Database database = this.fConnInfo.getDatabase();
String fImpliedSchemaName = this.fConnInfo.getDefaultSchemaName();
if (database != null) {
int proposalsType = request.getScope();
if ((proposalsType & SQLParserConstants.SCOPE_CATALOGS) == SQLParserConstants.SCOPE_CATALOGS) {
loadCatalogs(database, false);
return;
}
if ((proposalsType & SQLParserConstants.SCOPE_SCHEMAS) == SQLParserConstants.SCOPE_SCHEMAS) {
loadSchemas(database, request.getDatabase(), false);
return;
}
if ((proposalsType & SQLParserConstants.SCOPE_EVENTS) == SQLParserConstants.SCOPE_EVENTS) {
loadEvents(database, false);
return;
}
Schema schema = getSchema(database, fConnInfo.getDatabaseName(), request.getSchema());
if (request.getDatabase() != null)
{
schema = getSchema(database, request.getDatabase(), request.getSchema());
}
if ((proposalsType & SQLParserConstants.SCOPE_TABLES) == SQLParserConstants.SCOPE_TABLES) {
loadTables(schema, false);
createAliasTableProposals(request, false);
}
if ((proposalsType & SQLParserConstants.SCOPE_FUNCTIONS) == SQLParserConstants.SCOPE_FUNCTIONS) {
loadFunctions(schema, false);
}
if ((proposalsType & SQLParserConstants.SCOPE_STORED_PROCEDURES) == SQLParserConstants.SCOPE_STORED_PROCEDURES) {
loadProcedures(schema, false);
}
if ((proposalsType & SQLParserConstants.SCOPE_TRIGGERS) == SQLParserConstants.SCOPE_TRIGGERS) {
loadTriggers(schema, false);
}
if ((proposalsType & SQLParserConstants.SCOPE_VIEWS) == SQLParserConstants.SCOPE_VIEWS) {
loadViews(schema, false);
}
if ((proposalsType & SQLParserConstants.SCOPE_INDEXES) == SQLParserConstants.SCOPE_INDEXES) {
loadIndexes(schema, false);
}
if ((proposalsType & SQLParserConstants.SCOPE_SEGMENT) == SQLParserConstants.SCOPE_SEGMENT) {
loadSegments(schema, false);
}
if ((proposalsType & SQLParserConstants.SCOPE_COLUMNS) == SQLParserConstants.SCOPE_COLUMNS
|| (proposalsType & SQLParserConstants.SCOPE_WITHOUT_TABLE) == SQLParserConstants.SCOPE_WITHOUT_TABLE) {
String realTableName = request.getRealTable();
// get table prefix first, then get context tables
if (realTableName != null && realTableName.trim().length() > 0) {
Table table = null;
if (schema == null)
{
return;
}
EList tables = schema.getTables();
for (int i = 0; i < tables.size(); i++) {
table = (Table) tables.get(i);
if (table.getName().equals(realTableName)) {
loadColumns(table, false, request.getTable());
break;
}
}
} else {
List ctxTables = request.getContextTables();
if (!ctxTables.isEmpty()) {
for (Iterator iter = ctxTables.iterator(); iter
.hasNext();) {
org.eclipse.datatools.sqltools.sql.reference.ITable ref = (org.eclipse.datatools.sqltools.sql.reference.ITable) iter
.next();
Schema ctxSchema = schema;
if (ref.getOwner() != null)
{
ctxSchema = getSchema(database, fConnInfo.getDatabaseName(), ref.getOwner());
if (ctxSchema == null)
{
continue;
}
EList tables = ctxSchema.getTables();
for (int i = 0; i < tables.size(); i++)
{
Table table = (Table) tables.get(i);
if (table.getName().equals(ref.getName()))
{
loadColumns(table, false, ref.getAliasName());
break;
}
}
}
else
{
DatabaseIdentifier databaseIdentifier = new DatabaseIdentifier(fConnInfo
.getConnectionProfileName(), fConnInfo.getDatabaseName());
// find table with default schema in current catalog
Table table = ModelUtil.findTableObject(databaseIdentifier,
fConnInfo.getDatabaseName(), ctxSchema.getName(), ref.getName(), false, true,
false);
if (table == null)
{
// without table owner, find table in all schemas
table = ModelUtil.findTableInAllSchemas(databaseIdentifier, fConnInfo
.getDatabaseName(), ref.getName(), true, false);
}
if (table != null)
{
loadColumns(table, false, ref.getAliasName());
}
}
}
}
}
}
}
}
/**
* Creates and stores a list of <code>SQLDBProposal</code> objects for
* each table associated with the given schema. Retrieve the list using
* getDBProposals(). The current list of proposals, if any, is cleared.
*
* @param schema
* the <code>Schema</code> object for which tables are needed
*/
protected void loadTables(Schema schema) {
loadTables(schema, true);
}
/**
* Creates and stores a list of <code>SQLDBProposal</code> objects for
* each table associated with the given schema. Retrieve the list using
* getDBProposals().
*
* @param schema
* the <code>Schema</code> object for which tables are needed
* @param clear
* when true, clear the existing list of proposals before loading
*/
protected void loadTables(Schema schema, boolean clear) {
if (schema != null) {
if (clear) {
fDBProposalList.clear();
}
EList tables = schema.getTables();
for (int i = 0; i < tables.size(); i++) {
Table table = (Table) tables.get(i);
fDBProposalList.add(new SQLDBProposal(table));
}
}
}
/**
* Creates and stores a list of <code>SQLDBProposal</code> objects for
* each alias table associated with the current statement. Retrieve the list using
* getDBProposals().
*
* @param clear
* when true, clear the existing list of proposals before loading
*/
protected void createAliasTableProposals(SQLDBProposalsRequest request, boolean clear) {
if (clear) {
fDBProposalList.clear();
}
List tables = request.getContextTables();
for (int i = 0; i < tables.size(); i++) {
ITable table = (ITable) tables.get(i);
fDBProposalList.add(new SQLDBProposal(table.getAliasName()));
}
}
/**
* Creates and stores a list of <code>SQLDBProposal</code> objects for
* each stored procedure associated with the given schema. Retrieve the list
* using getDBProposals().
*
* @param schema
* the <code>Schema</code> object for which stored procedures
* are needed
* @param clear
* when true, clear the existing list of proposals before loading
*/
protected void loadProcedures(Schema schema, boolean clear) {
if (schema != null) {
if (clear) {
fDBProposalList.clear();
}
EList procedures = schema.getProcedures();
for (int i = 0; i < procedures.size(); i++) {
Procedure proc = (Procedure) procedures.get(i);
fDBProposalList.add(new SQLDBProposal(proc));
}
}
}
/**
* Creates and stores a list of <code>SQLDBProposal</code> objects for
* each user defined functions associated with the given schema. Retrieve
* the list using getDBProposals().
*
* @param schema
* the <code>Schema</code> object for which user defined
* functions are needed
* @param clear
* when true, clear the existing list of proposals before loading
*/
protected void loadFunctions(Schema schema, boolean clear) {
if (schema != null) {
if (clear) {
fDBProposalList.clear();
}
EList funcs = schema.getUDFs();
for (int i = 0; i < funcs.size(); i++) {
Function func = (Function) funcs.get(i);
fDBProposalList.add(new SQLDBProposal(func));
}
}
}
/**
* Creates and stores a list of <code>SQLDBProposal</code> objects for
* each triggers associated with the given schema. Retrieve the list using
* getDBProposals().
*
* @param schema
* the <code>Schema</code> object for which triggers are needed
* @param clear
* when true, clear the existing list of proposals before loading
*/
protected void loadTriggers(Schema schema, boolean clear) {
if (schema != null) {
if (clear) {
fDBProposalList.clear();
}
EList triggers = schema.getTriggers();
for (int i = 0; i < triggers.size(); i++) {
Trigger trigger = (Trigger) triggers.get(i);
fDBProposalList.add(new SQLDBProposal(trigger));
}
}
}
/**
* Creates and stores a list of <code>SQLDBProposal</code> objects for
* each events associated with the given schema. Retrieve the list using
* getDBProposals().
*
* @param database
* the <code>Schema</code> object for which events are needed
* @param clear
* when true, clear the existing list of proposals before loading
*/
protected void loadEvents(Database database, boolean clear) {
if (database != null) {
if (clear) {
fDBProposalList.clear();
}
EList events = database.getEvents();
for (int i = 0; i < events.size(); i++) {
Event event = (Event) events.get(i);
fDBProposalList.add(new SQLDBProposal(event));
}
}
}
/**
* Populates the list database of database object proposals (schemas,
* tables, columns) using given list of tokens (DB identifiers) indicating
* the start of the expression for which the user wants DB proposals. For
* example, if the user provides the list (MYSCHEMA, TABLE1), the list of
* proposals will be the columns of table MYSCHEMA.TABLE1. Retrieve the list
* using getDBProposals(). Implements <code>ISQLDBProposalsService</code>
* interface.
*
* @param tokenList
* list of strings indicating the start of the expression for
* which the user wants DB proposals
* @return true if database objects were loaded, for example as a result of
* reestablishing a connection
* @see ISQLDBProposalsService#populate()
*/
public boolean populate(final SQLDBProposalsRequest request) {
boolean loaded = false;
if (request != null) {
/* Connect or reconnect to DB Server if necessary. */
ISQLEditorConnectionInfo connInfo = getConnectionInfo();
boolean connected = false;
if (connInfo != null && connInfo.getConnectionProfile() != null) {
connected = connInfo.getConnectionProfile().isConnected();
}
if (connected == true) {
loaded = true;
/* Get the proposals from the connected database. */
loadDBProposals(request);
}
}
return loaded;
}
/**
* Creates and stores a list of <code>SQLDBProposal</code> objects for
* each views associated with the given schema. Retrieve the list using
* getDBProposals().
*
* @param schema
* the <code>Schema</code> object for which views are needed
* @param clear
* when true, clear the existing list of proposals before loading
*/
protected void loadViews(Schema schema, boolean clear) {
if (schema != null) {
if (clear) {
fDBProposalList.clear();
}
EList tables = schema.getTables();
for (int i = 0; i < tables.size(); i++) {
Table table = (Table) tables.get(i);
if (table instanceof ViewTable) {
fDBProposalList.add(new SQLDBProposal(table));
}
}
}
}
/**
* Creates and stores a list of <code>SQLDBProposal</code> objects for
* each index associated with the given schema. Retrieve the list using
* getDBProposals().
*
* @param schema
* the <code>Schema</code> object for which indexes are needed
* @param clear
* when true, clear the existing list of proposals before loading
*/
protected void loadIndexes(Schema schema, boolean clear) {
if (schema != null) {
if (clear) {
fDBProposalList.clear();
}
EList indexes = schema.getIndices();
for (int i = 0; i < indexes.size(); i++) {
Index index = (Index) indexes.get(i);
fDBProposalList.add(new SQLDBProposal(index));
}
}
}
/**
* Creates and stores a list of <code>SQLDBProposal</code> objects for
* each segment associated with the given schema. Retrieve the list using
* getDBProposals().
*
* @param schema
* the <code>Schema</code> object for which segments are needed
* @param clear
* when true, clear the existing list of proposals before loading
*/
protected void loadSegments(Schema schema, boolean clear) {
// It will be implemented in derived classes.
}
public ISQLEditorConnectionInfo getSQLEditorConnectionInfo() {
return fConnInfo;
}
public void setSQLEditorConnectionInfo(ISQLEditorConnectionInfo connectionInfo) {
fConnInfo = connectionInfo;
}
}