All Downloads are FREE. Search and download functionalities are using the official Maven repository.

xdev.db.hsql2.jdbc.HSQL2JDBCMetaData Maven / Gradle / Ivy

/*
 * SqlEngine Database Adapter HSQL2 - XAPI SqlEngine Database Adapter for HSQL2
 * Copyright © 2003 XDEV Software (https://xdev.software)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see .
 */
package xdev.db.hsql2.jdbc;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.hsqldb.jdbc.JDBCStatement;

import com.xdev.jadoth.sqlengine.interfaces.ConnectionProvider;

import xdev.db.ColumnMetaData;
import xdev.db.DBException;
import xdev.db.DataType;
import xdev.db.Index;
import xdev.db.Index.IndexType;
import xdev.db.Result;
import xdev.db.StoredProcedure;
import xdev.db.StoredProcedure.Param;
import xdev.db.StoredProcedure.ParamType;
import xdev.db.StoredProcedure.ReturnTypeFlavor;
import xdev.db.jdbc.JDBCConnection;
import xdev.db.jdbc.JDBCMetaData;
import xdev.db.sql.Functions;
import xdev.db.sql.SELECT;
import xdev.db.sql.Table;
import xdev.util.ProgressMonitor;
import xdev.vt.Cardinality;
import xdev.vt.EntityRelationship;
import xdev.vt.EntityRelationship.Entity;
import xdev.vt.EntityRelationshipModel;


public class HSQL2JDBCMetaData extends JDBCMetaData
{
	private static final long serialVersionUID = 2862594319338582561L;
	private final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
	private final DateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
	private final DateFormat timestampFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	
	public HSQL2JDBCMetaData(HSQL2JDBCDataSource dataSource) throws DBException
	{
		super(dataSource);
	}
	
	private static void addMetaDataToColumns(
		TableInfo table,
		Map autoIncrementMap,
		Result result,
		List columns) throws DBException
	{
		String columnName = result.getString("COLUMN_NAME");
		Object defaultValue = result.getObject("COLUMN_DEF");
		
		if("NULL".equals(defaultValue))
		{
			defaultValue = null;
		}
		
		columns.add(new ColumnMetaData(
			table.getName(),                                        // tableName
			columnName,                                             // columnName
			"",                                                     // caption
			DataType.get(result.getInt("DATA_TYPE")),       // type
			result.getInt("COLUMN_SIZE"),                   // length
			result.getInt("DECIMAL_DIGITS"),                // scale
			defaultValue,                                           // defaultValue
			"YES".equals(result.getString("IS_NULLABLE")),  // nullable
			Boolean.TRUE.equals(autoIncrementMap.get(columnName))   // autoIncrement
		));
	}
	
	/**
	 * Switches on {@link DataType}, to append the correct values to the {@link StringBuilder}
	 */
	private static void appendCorrectDataType(ColumnMetaData column, StringBuilder sb, DataType type)
	{
		switch(type)
		{
			case TINYINT:
			case SMALLINT:
			case INTEGER:
			case BIGINT:
			case REAL:
			case FLOAT:
			case DOUBLE:
			case DATE:
			case TIME:
			case TIMESTAMP:
			case BOOLEAN:
			case BINARY:
			case VARBINARY:
			case LONGVARCHAR:
			case LONGVARBINARY:
			{
				sb.append(type.name());
			}
			break;
			
			case NUMERIC:
			case DECIMAL:
			{
				sb.append(type.name());
				sb.append("(");
				sb.append(column.getLength());
				sb.append(",");
				sb.append(column.getScale());
				sb.append(")");
			}
			break;
			
			case CHAR:
			case VARCHAR:
			{
				sb.append(type.name());
				sb.append("(");
				sb.append(column.getLength());
				sb.append(")");
			}
			break;
			
			case CLOB:
			{
				sb.append("LONGVARCHAR");
			}
			break;
			
			case BLOB:
			{
				sb.append("BINARY");
			}
			break;
			
			default:
				break;
		}
	}
	
	private static void appendStringWithSurroundingBackslashes(StringBuilder sb, Object defaultValue)
	{
		sb.append('\'');
		for(char ch : defaultValue.toString().toCharArray())
		{
			if(ch == '\'')
			{
				sb.append('\'');
			}
			sb.append(ch);
		}
		sb.append('\'');
	}
	
	@Override
	public TableInfo[] getTableInfos(ProgressMonitor monitor, EnumSet types) throws DBException
	{
		monitor.beginTask("", ProgressMonitor.UNKNOWN);
		
		List list = new ArrayList<>();
		
		try(JDBCConnection jdbcConnection = (JDBCConnection)dataSource.openConnection())
		{
			String tableTypeStatement = getTableTypeStatement(types);
			Result result = jdbcConnection.query("SELECT TABLE_SCHEM, TABLE_NAME, TABLE_TYPE "
				+ "FROM INFORMATION_SCHEMA.SYSTEM_TABLES " + "WHERE TABLE_TYPE in "
				+ tableTypeStatement);
			
			while(result.next() && !monitor.isCanceled())
			{
				String tableType = result.getString("TABLE_TYPE");
				
				TableType type = null;
				if(tableType.equals("TABLE"))
				{
					type = TableType.TABLE;
				}
				else if(tableType.equals("VIEW"))
				{
					type = TableType.VIEW;
				}
				
				if(type != null && types.contains(type))
				{
					list.add(new TableInfo(type, result.getString("TABLE_SCHEM"), result
						.getString("TABLE_NAME")));
				}
			}
			
			result.close();
		}
		
		monitor.done();
		
		TableInfo[] tables = list.toArray(new TableInfo[list.size()]);
		Arrays.sort(tables);
		return tables;
	}
	
	@Override
	protected TableMetaData getTableMetaData(
		JDBCConnection jdbcConnection, DatabaseMetaData meta,
		int flags, TableInfo table) throws DBException, SQLException
	{
		String tableName = table.getName();
		Table tableIdentity = new Table(tableName);
		Map autoIncrementMap = new HashMap<>();
		SELECT select = new SELECT().FROM(tableIdentity).WHERE("1 = 0");
		Result result = jdbcConnection.query(select);
		int cc = result.getColumnCount();
		
		for(int i = 0; i < cc; i++)
		{
			ColumnMetaData cm = result.getMetadata(i);
			autoIncrementMap.put(cm.getName(), cm.isAutoIncrement());
		}
		result.close();
		
		result = jdbcConnection.query("SELECT * FROM INFORMATION_SCHEMA.SYSTEM_COLUMNS "
			+ "WHERE TABLE_NAME = ?", table.getName());
		
		List columns = new ArrayList<>();
		while(result.next())
		{
			addMetaDataToColumns(table, autoIncrementMap, result, columns);
		}
		result.close();
		
		Map> indexMap = new HashMap<>();
		Set primaryKeyColumns = new HashSet<>();
		String primaryKeyName = "PRIMARY_KEY";
		
		result = jdbcConnection.query("SELECT * FROM INFORMATION_SCHEMA.SYSTEM_PRIMARYKEYS "
			+ "WHERE TABLE_NAME = ?", table.getName());
		
		while(result.next())
		{
			primaryKeyColumns.add(result.getString("COLUMN_NAME"));
			primaryKeyName = result.getString("PK_NAME");
		}
		result.close();
		
		if((flags & INDICES) != 0)
		{
			if(!primaryKeyColumns.isEmpty())
			{
				indexMap.put(new IndexInfo(primaryKeyName, IndexType.PRIMARY_KEY), primaryKeyColumns);
			}
			
			result = jdbcConnection.query("SELECT * FROM INFORMATION_SCHEMA.SYSTEM_INDEXINFO "
				+ "WHERE TABLE_NAME = ?", table.getName());
			
			while(result.next())
			{
				String indexName = result.getString("INDEX_NAME");
				String columnName = result.getString("COLUMN_NAME");
				if(indexName != null
					&& columnName != null
					&& !primaryKeyColumns.contains(columnName))
				{
					boolean unique = !result.getBoolean("NON_UNIQUE");
					IndexInfo info = new IndexInfo(indexName, unique ? IndexType.UNIQUE : IndexType.NORMAL);
					Set columnNames = indexMap.get(info);
					if(columnNames == null)
					{
						columnNames = new HashSet<>();
						indexMap.put(info, columnNames);
					}
					columnNames.add(columnName);
				}
			}
			result.close();
		}
		
		Index[] indices = new Index[indexMap.size()];
		int i = 0;
		for(IndexInfo indexInfo : indexMap.keySet())
		{
			Set columnList = indexMap.get(indexInfo);
			String[] indexColumns = columnList.toArray(new String[columnList.size()]);
			indices[i++] = new Index(indexInfo.name, indexInfo.type, indexColumns);
		}
		
		int count = UNKNOWN_ROW_COUNT;
		
		if((flags & ROW_COUNT) != 0)
		{
			result = jdbcConnection.query(new SELECT().columns(Functions.COUNT()).FROM(
				tableIdentity));
			if(result.next())
			{
				count = result.getInt(0);
			}
			result.close();
		}
		
		return new TableMetaData(
			table,
			columns.toArray(new ColumnMetaData[columns.size()]),
			indices,
			count
		);
	}
	
	@Override
	public StoredProcedure[] getStoredProcedures(ProgressMonitor monitor) throws DBException
	{
		monitor.beginTask("", ProgressMonitor.UNKNOWN);
		
		List list = new ArrayList<>();
		
		try
		{
			ConnectionProvider connectionProvider = dataSource.getConnectionProvider();
			
			try(Connection connection = connectionProvider.getConnection())
			{
				DatabaseMetaData meta = connection.getMetaData();
				
				ResultSet rs = getProcedures(connection);
				
				while(rs.next() && !monitor.isCanceled())
				{
					ReturnTypeFlavor returnTypeFlavor;
					DataType returnType = null;
					String name = rs.getString("PROCEDURE_NAME");
					String description = rs.getString("REMARKS");
					int procedureType = rs.getInt("PROCEDURE_TYPE");
					
					switch(procedureType)
					{
						case DatabaseMetaData.procedureNoResult:
							returnTypeFlavor = ReturnTypeFlavor.VOID;
							break;
						
						case DatabaseMetaData.procedureReturnsResult:
							String dataType = rs.getString("DATA_TYPE");
							String[] split = dataType.split(",");
							if(split.length > 1)
							{
								returnTypeFlavor = ReturnTypeFlavor.RESULT_SET;
							}
							else
							{
								dataType = convDataTypeString(dataType);
								
								returnType = DataType.valueOf(dataType);
								returnTypeFlavor = ReturnTypeFlavor.TYPE;
							}
							
							break;
						default:
							returnTypeFlavor = ReturnTypeFlavor.UNKNOWN;
					}
					
					List params = new ArrayList<>();
					ResultSet rsp = meta.getProcedureColumns(null, "PUBLIC", null, name);
					
					while(rsp.next())
					{
						DataType dataType = DataType.get(rsp.getInt("DATA_TYPE"));
						String columnName = rsp.getString("COLUMN_NAME");
						switch(rsp.getInt("COLUMN_TYPE"))
						{
							case DatabaseMetaData.procedureColumnReturn:
								returnTypeFlavor = ReturnTypeFlavor.TYPE;
								returnType = dataType;
								break;
							
							case DatabaseMetaData.procedureColumnResult:
								returnTypeFlavor = ReturnTypeFlavor.RESULT_SET;
								break;
							
							case DatabaseMetaData.procedureColumnIn:
								params.add(new Param(ParamType.IN, columnName, dataType));
								break;
							
							case DatabaseMetaData.procedureColumnOut:
								params.add(new Param(ParamType.OUT, columnName, dataType));
								break;
							
							case DatabaseMetaData.procedureColumnInOut:
								params.add(new Param(ParamType.IN_OUT, columnName, dataType));
								break;
							
							default:
								break;
						}
					}
					rsp.close();
					
					list.add(new StoredProcedure(returnTypeFlavor, returnType, name, description,
						params.toArray(new Param[params.size()])));
				}
				rs.close();
			}
		}
		catch(SQLException e)
		{
			throw new DBException(dataSource, e);
		}
		
		monitor.done();
		
		return list.toArray(new StoredProcedure[list.size()]);
	}
	
	private String convDataTypeString(String dataType)
	{
		if(dataType.equalsIgnoreCase("character"))
		{
			dataType = "CHAR";
		}
		else if(dataType.equalsIgnoreCase("bit"))
		{
			dataType = "BOOLEAN";
		}
		else if(dataType.equalsIgnoreCase("other"))
		{
			dataType = "OBJECT";
		}
		else if(dataType.equalsIgnoreCase("datetime"))
		{
			dataType = "TIMESTAMP";
		}
		else if(dataType.equalsIgnoreCase("int"))
		{
			dataType = "INTEGER";
		}
		return dataType;
	}
	
	private ResultSet getProcedures(Connection connection) throws SQLException
	{
		String sql =
			"SELECT PROCEDURE_NAME,REMARKS, DATA_TYPE, PROCEDURE_TYPE FROM INFORMATION_SCHEMA.SYSTEM_PROCEDURES, "
				+ "INFORMATION_SCHEMA.ROUTINES WHERE INFORMATION_SCHEMA.SYSTEM_PROCEDURES.SPECIFIC_NAME LIKE "
				+ "INFORMATION_SCHEMA.ROUTINES.SPECIFIC_NAME AND PROCEDURE_SCHEM LIKE 'PUBLIC'";
		
		JDBCStatement localJDBCStatement;
		ResultSet executeQuery = null;
		try
		{
			localJDBCStatement = (JDBCStatement)connection.createStatement(1004, 1007);
			executeQuery = localJDBCStatement.executeQuery(sql);
		}
		catch(SQLException e)
		{
			throw new SQLException("SqlStatement: " + sql);
		}
		return executeQuery;
	}
	
	@Override
	public EntityRelationshipModel getEntityRelationshipModel(
		ProgressMonitor monitor,
		TableInfo... tableInfos) throws DBException
	{
		monitor.beginTask("", tableInfos.length);
		
		EntityRelationshipModel model = new EntityRelationshipModel();
		
		try
		{
			List tables = new ArrayList<>();
			for(TableInfo table : tableInfos)
			{
				if(table.getType() == TableType.TABLE)
				{
					tables.add(table.getName());
				}
			}
			Collections.sort(tables);
			
			try(Connection connection = dataSource.getConnectionProvider().getConnection())
			{
				DatabaseMetaData meta = connection.getMetaData();
				int done = 0;
				
				for(String table : tables)
				{
					if(monitor.isCanceled())
					{
						break;
					}
					
					monitor.setTaskName(table);
					
					ResultSet rs = meta.getExportedKeys(null, null, table);
					try
					{
						String pkTable = null;
						String fkTable = null;
						List pkColumns = new ArrayList();
						List fkColumns = new ArrayList();
						
						while(rs.next())
						{
							short keySeq = rs.getShort("KEY_SEQ");
							
							if(keySeq == 1 && pkColumns.size() > 0)
							{
								addNewEntityRelationshipToModel(model, tables, pkTable, fkTable, pkColumns, fkColumns);
							}
							
							pkTable = rs.getString("PKTABLE_NAME");
							fkTable = rs.getString("FKTABLE_NAME");
							
							pkColumns.add(rs.getString("PKCOLUMN_NAME"));
							fkColumns.add(rs.getString("FKCOLUMN_NAME"));
						}
						
						if(pkColumns.size() > 0)
						{
							addNewEntityRelationshipToModel(model, tables, pkTable, fkTable, pkColumns, fkColumns);
						}
					}
					finally
					{
						rs.close();
					}
					
					monitor.worked(++done);
				}
			}
		}
		catch(SQLException e)
		{
			throw new DBException(dataSource, e);
		}
		
		monitor.done();
		
		return model;
	}
	
	/**
	 * Checks if the table contains PK and FK. If true, than it adds a new One-To-Many-Relationship to the model
	 */
	private void addNewEntityRelationshipToModel(
		EntityRelationshipModel model,
		List tables,
		String pkTable,
		String fkTable,
		List pkColumns,
		List fkColumns)
	{
		if(tables.contains(pkTable) && tables.contains(fkTable))
		{
			model.add(new EntityRelationship(
				new Entity(
					pkTable,
					pkColumns.toArray(new String[pkColumns.size()]),
					Cardinality.ONE),
				new Entity(
					fkTable,
					fkColumns.toArray(new String[fkColumns.size()]),
					Cardinality.MANY)
			));
			pkColumns.clear();
			fkColumns.clear();
		}
	}
	
	@SuppressWarnings("incomplete-switch")
	@Override
	public boolean equalsType(ColumnMetaData clientColumn, ColumnMetaData dbColumn)
	{
		DataType clientType = clientColumn.getType();
		DataType dbType = dbColumn.getType();
		
		if(clientType == dbType)
		{
			switch(clientType)
			{
				case TINYINT:
				case SMALLINT:
				case INTEGER:
				case BIGINT:
				case REAL:
				case FLOAT:
				case DOUBLE:
				case DATE:
				case TIME:
				case TIMESTAMP:
				case BOOLEAN:
				case BINARY:
				case VARBINARY:
				case LONGVARCHAR:
				case LONGVARBINARY:
				case CLOB:
				case BLOB:
				{
					return true;
				}
				
				case NUMERIC:
				case DECIMAL:
				{
					return clientColumn.getLength() == dbColumn.getLength()
						&& clientColumn.getScale() == dbColumn.getScale();
				}
				
				case CHAR:
				case VARCHAR:
				{
					return clientColumn.getLength() == dbColumn.getLength();
				}
			}
		}
		
		Boolean match = getTypeMatch(clientColumn, dbColumn);
		if(match != null)
		{
			return match;
		}
		
		match = getTypeMatch(dbColumn, clientColumn);
		if(match != null)
		{
			return match;
		}
		
		return false;
	}
	
	@SuppressWarnings("incomplete-switch")
	private Boolean getTypeMatch(ColumnMetaData thisColumn, ColumnMetaData thatColumn)
	{
		DataType thisType = thisColumn.getType();
		DataType thatType = thatColumn.getType();
		
		switch(thisType)
		{
			case CLOB:
			{
				return thatType == DataType.LONGVARCHAR;
			}
			
			case LONGVARCHAR:
			{
				return thatType == DataType.CLOB;
			}
			
			case BLOB:
			{
				return thatType == DataType.BINARY;
			}
			
			case BINARY:
			{
				return thatType == DataType.BLOB;
			}
			
			case BOOLEAN:
			{
				return thatType == DataType.TINYINT && thatColumn.getLength() == 1;
			}
			
			case TINYINT:
			{
				return thatType == DataType.BOOLEAN && thisColumn.getLength() == 1;
			}
			
			default:
				return null;
		}
	}
	
	@Override
	protected void createTable(JDBCConnection jdbcConnection, TableMetaData table)
		throws DBException, SQLException
	{
		StringBuilder sb = new StringBuilder();
		sb.append("CREATE CACHED TABLE ");
		appendEscapedName(table.getTableInfo().getName(), sb);
		sb.append(" (");
		
		ColumnMetaData[] columns = table.getColumns();
		for(int i = 0; i < columns.length; i++)
		{
			if(i > 0)
			{
				sb.append(", ");
			}
			
			ColumnMetaData column = columns[i];
			appendEscapedName(column.getName(), sb);
			sb.append(" ");
			appendColumnDefinition(column, sb);
		}
		
		for(Index index : table.getIndices())
		{
			if(isSupported(index))
			{
				sb.append(", ");
				appendIndexDefinition(index, sb);
			}
		}
		
		sb.append(")");
		
		jdbcConnection.write(
			sb.toString(),
			false,
			new ArrayList<>().toArray()
		);
	}
	
	@Override
	protected void addColumn(
		JDBCConnection jdbcConnection, TableMetaData table,
		ColumnMetaData column, ColumnMetaData columnBefore, ColumnMetaData columnAfter)
		throws DBException, SQLException
	{
		StringBuilder sb = new StringBuilder();
		sb.append("ALTER TABLE ");
		appendEscapedName(table.getTableInfo().getName(), sb);
		sb.append(" ADD COLUMN ");
		appendEscapedName(column.getName(), sb);
		sb.append(" ");
		appendColumnDefinition(column, sb);
		if(columnAfter != null)
		{
			sb.append(" BEFORE ");
			appendEscapedName(columnBefore.getName(), sb);
		}
		
		jdbcConnection.write(
			sb.toString(),
			false,
			new ArrayList<>().toArray()
		);
	}
	
	@Override
	protected void alterColumn(
		JDBCConnection jdbcConnection, TableMetaData table,
		ColumnMetaData column, ColumnMetaData existing) throws DBException, SQLException
	{
		StringBuilder sb = new StringBuilder();
		sb.append("ALTER TABLE ");
		appendEscapedName(table.getTableInfo().getName(), sb);
		sb.append(" ALTER COLUMN ");
		appendEscapedName(existing.getName(), sb);
		sb.append(" ");
		appendColumnDefinition(column, sb);
		
		jdbcConnection.write(
			sb.toString(),
			false,
			new ArrayList<>().toArray()
		);
	}
	
	@SuppressWarnings("incomplete-switch")
	private void appendColumnDefinition(ColumnMetaData column, StringBuilder sb)
	{
		DataType type = column.getType();
		appendCorrectDataType(column, sb, type);
		
		if(column.isAutoIncrement())
		{
			sb.append(" GENERATED BY DEFAULT AS IDENTITY");
		}
		else
		{
			Object defaultValue = column.getDefaultValue();
			if(!(defaultValue == null && !column.isNullable()))
			{
				sb.append(" DEFAULT ");
				if(defaultValue == null)
				{
					sb.append("NULL");
				}
				else if(defaultValue instanceof String)
				{
					appendStringWithSurroundingBackslashes(sb, defaultValue);
				}
				else if(defaultValue instanceof Date)
				{
					appendCorrectDateFormat(sb, type, (Date)defaultValue);
				}
				else
				{
					sb.append(defaultValue);
				}
			}
		}
		
		if(column.isNullable())
		{
			sb.append(" NULL");
		}
		else
		{
			sb.append(" NOT NULL");
		}
	}
	
	/**
	 * Switches on {@link DataType} to append the corret {@link DateFormat} to the {@link StringBuilder}
	 */
	private void appendCorrectDateFormat(StringBuilder sb, DataType type, Date defaultValue)
	{
		DateFormat format = null;
		switch(type)
		{
			case DATE:
				format = dateFormat;
				break;
			case TIME:
				format = timeFormat;
				break;
			case TIMESTAMP:
				format = timestampFormat;
				break;
			default:
				break;
		}
		
		if(format != null)
		{
			sb.append('\'');
			sb.append(format.format(defaultValue));
			sb.append('\'');
		}
	}
	
	@Override
	protected void dropColumn(
		JDBCConnection jdbcConnection, TableMetaData table,
		ColumnMetaData column) throws DBException, SQLException
	{
		StringBuilder sb = new StringBuilder();
		sb.append("ALTER TABLE ");
		appendEscapedName(table.getTableInfo().getName(), sb);
		sb.append(" DROP COLUMN ");
		appendEscapedName(column.getName(), sb);
		
		jdbcConnection.write(sb.toString());
	}
	
	@Override
	protected void createIndex(JDBCConnection jdbcConnection, TableMetaData table, Index index)
		throws DBException, SQLException
	{
		if(!isSupported(index))
		{
			return;
		}
		
		StringBuilder sb = new StringBuilder();
		sb.append("ALTER TABLE ");
		appendEscapedName(table.getTableInfo().getName(), sb);
		sb.append(" ADD ");
		appendIndexDefinition(index, sb);
		
		jdbcConnection.write(sb.toString());
	}
	
	private boolean isSupported(Index index)
	{
		return index.getType() != IndexType.NORMAL;
	}
	
	private void appendIndexDefinition(Index index, StringBuilder sb) throws DBException
	{
		switch(index.getType())
		{
			case PRIMARY_KEY:
			{
				sb.append("PRIMARY KEY");
			}
			break;
			
			case UNIQUE:
			{
				sb.append("UNIQUE");
			}
			break;
			
			default:
			{
				throw new DBException(
					dataSource,
					"Only primary keys and unique indices are supported.");
			}
		}
		
		sb.append(" (");
		String[] columns = index.getColumns();
		for(int i = 0; i < columns.length; i++)
		{
			if(i > 0)
			{
				sb.append(", ");
			}
			appendEscapedName(columns[i], sb);
		}
		sb.append(")");
	}
	
	@Override
	protected void dropIndex(JDBCConnection jdbcConnection, TableMetaData table, Index index)
		throws DBException, SQLException
	{
		StringBuilder sb = new StringBuilder();
		sb.append("ALTER TABLE ");
		appendEscapedName(table.getTableInfo().getName(), sb);
		
		sb.append(" DROP CONSTRAINT ");
		appendEscapedName(getValidIndexName(index), sb);
		
		jdbcConnection.write(sb.toString());
	}
	
	private String getValidIndexName(Index index)
	{
		String name = index.getName();
		if(name.equals("PRIMARY_KEY"))
		{
			name = "PK";
		}
		return name;
	}
	
	private String getTableTypeStatement(EnumSet types)
	{
		if(types == null || types.isEmpty())
		{
			return "";
		}
		
		String tableStatement = "(";
		
		if(types.contains(TableType.TABLE))
		{
			tableStatement += "'TABLE'";
		}
		
		if(types.contains(TableType.TABLE) && types.contains(TableType.VIEW))
		{
			tableStatement += " , ";
		}
		
		if(types.contains(TableType.VIEW))
		{
			tableStatement += "'VIEW'";
		}
		
		tableStatement += ")";
		
		return tableStatement;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy