/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jkiss.dbeaver.ext.postgresql.model;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.ext.postgresql.PostgreConstants;
import org.jkiss.dbeaver.ext.postgresql.PostgreUtils;
import org.jkiss.dbeaver.model.*;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCPreparedStatement;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCResultSet;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCSession;
import org.jkiss.dbeaver.model.exec.jdbc.JDBCStatement;
import org.jkiss.dbeaver.model.impl.jdbc.JDBCUtils;
import org.jkiss.dbeaver.model.impl.jdbc.cache.JDBCCompositeCache;
import org.jkiss.dbeaver.model.impl.jdbc.cache.JDBCObjectCache;
import org.jkiss.dbeaver.model.impl.jdbc.cache.JDBCObjectLookupCache;
import org.jkiss.dbeaver.model.impl.jdbc.cache.JDBCStructLookupCache;
import org.jkiss.dbeaver.model.meta.Association;
import org.jkiss.dbeaver.model.meta.Property;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.struct.DBSDataType;
import org.jkiss.dbeaver.model.struct.DBSEntity;
import org.jkiss.dbeaver.model.struct.DBSEntityConstraintType;
import org.jkiss.dbeaver.model.struct.DBSObject;
import org.jkiss.dbeaver.model.struct.rdb.DBSProcedureContainer;
import org.jkiss.dbeaver.model.struct.rdb.DBSSchema;
import java.lang.reflect.Array;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* PostgreSchema
*/
public class PostgreSchema implements DBSSchema, DBPNamedObject2, DBPSaveableObject, DBPRefreshableObject, DBPSystemObject, DBSProcedureContainer, PostgreObject {
private static final Log log = Log.getLog(PostgreSchema.class);
private PostgreDatabase database;
private long oid;
private String name;
private String description;
private long ownerId;
private boolean persisted;
public final CollationCache collationCache = new CollationCache();
public final ExtensionCache extensionCache = new ExtensionCache();
public final TableCache tableCache = new TableCache();
public final ConstraintCache constraintCache = new ConstraintCache();
public final ProceduresCache proceduresCache = new ProceduresCache();
public final IndexCache indexCache = new IndexCache();
public final PostgreDataTypeCache dataTypeCache = new PostgreDataTypeCache();
public PostgreSchema(PostgreDatabase database, String name, ResultSet dbResult)
throws SQLException
{
this.database = database;
this.name = name;
this.loadInfo(dbResult);
}
public PostgreSchema(PostgreDatabase database, String name, PostgreRole owner)
{
this.database = database;
this.name = name;
this.ownerId = owner == null ? 0 : owner.getObjectId();
}
private void loadInfo(ResultSet dbResult)
throws SQLException
{
this.oid = JDBCUtils.safeGetLong(dbResult, "oid");
this.ownerId = JDBCUtils.safeGetLong(dbResult, "nspowner");
this.description = JDBCUtils.safeGetString(dbResult, "description");
this.persisted = true;
}
@NotNull
@Property(viewable = true, order = 1)
public PostgreDatabase getDatabase() {
return database;
}
@NotNull
@Override
@Property(viewable = true, order = 2)
public String getName()
{
return name;
}
@Override
public void setName(String newName) {
this.name = newName;
}
@Override
public long getObjectId() {
return this.oid;
}
@Property(order = 4)
public PostgreRole getOwner(DBRProgressMonitor monitor) throws DBException {
return PostgreUtils.getObjectById(monitor, database.roleCache, database, ownerId);
}
@Property(viewable = true, order = 100)
@Nullable
@Override
public String getDescription() {
return description;
}
@Override
public PostgreDatabase getParentObject()
{
return database;
}
@NotNull
@Override
public PostgreDataSource getDataSource() {
return database.getDataSource();
}
@Override
public boolean isPersisted() {
return persisted;
}
@Override
public void setPersisted(boolean persisted) {
this.persisted = persisted;
}
@Association
public Collection<PostgreCollation> getCollations(DBRProgressMonitor monitor)
throws DBException
{
return collationCache.getAllObjects(monitor, this);
}
@Association
public Collection<PostgreExtension> getExtensions(DBRProgressMonitor monitor)
throws DBException
{
return extensionCache.getAllObjects(monitor, this);
}
@Association
public Collection<PostgreIndex> getIndexes(DBRProgressMonitor monitor)
throws DBException
{
return indexCache.getObjects(monitor, this, null);
}
public PostgreTableBase getTable(DBRProgressMonitor monitor, long tableId)
throws DBException
{
for (PostgreClass table : tableCache.getAllObjects(monitor, this)) {
if (table.getObjectId() == tableId) {
return (PostgreTableBase) table;
}
}
return null;
}
@Association
public Collection<PostgreTable> getTables(DBRProgressMonitor monitor)
throws DBException
{
return tableCache.getTypedObjects(monitor, this, PostgreTable.class);
}
@Association
public Collection<PostgreView> getViews(DBRProgressMonitor monitor)
throws DBException
{
return tableCache.getTypedObjects(monitor, this, PostgreView.class);
}
@Association
public Collection<PostgreMaterializedView> getMaterializedViews(DBRProgressMonitor monitor)
throws DBException
{
return tableCache.getTypedObjects(monitor, this, PostgreMaterializedView.class);
}
@Association
public Collection<PostgreSequence> getSequences(DBRProgressMonitor monitor)
throws DBException
{
return tableCache.getTypedObjects(monitor, this, PostgreSequence.class);
}
public PostgreSequence getSequence(DBRProgressMonitor monitor, String name)
throws DBException
{
return tableCache.getObject(monitor, this, name, PostgreSequence.class);
}
@Association
public Collection<PostgreProcedure> getProcedures(DBRProgressMonitor monitor)
throws DBException
{
return proceduresCache.getAllObjects(monitor, this);
}
public PostgreProcedure getProcedure(DBRProgressMonitor monitor, String procName)
throws DBException
{
return proceduresCache.getObject(monitor, this, procName);
}
public PostgreProcedure getProcedure(DBRProgressMonitor monitor, long oid)
throws DBException
{
for (PostgreProcedure proc : proceduresCache.getAllObjects(monitor, this)) {
if (proc.getObjectId() == oid) {
return proc;
}
}
return null;
}
@Override
public Collection<PostgreTableBase> getChildren(@NotNull DBRProgressMonitor monitor)
throws DBException
{
return tableCache.getAllObjects(monitor, this);
}
@Override
public PostgreTableBase getChild(@NotNull DBRProgressMonitor monitor, @NotNull String childName)
throws DBException
{
return tableCache.getObject(monitor, this, childName);
}
@Override
public Class<? extends DBSEntity> getChildType(@NotNull DBRProgressMonitor monitor)
throws DBException
{
return PostgreTableBase.class;
}
@Override
public synchronized void cacheStructure(@NotNull DBRProgressMonitor monitor, int scope)
throws DBException
{
monitor.subTask("Cache tables");
tableCache.getAllObjects(monitor, this);
if ((scope & STRUCT_ATTRIBUTES) != 0) {
monitor.subTask("Cache table columns");
tableCache.loadChildren(monitor, this, null);
}
if ((scope & STRUCT_ASSOCIATIONS) != 0) {
monitor.subTask("Cache constraints");
constraintCache.getAllObjects(monitor, this);
indexCache.getAllObjects(monitor, this);
}
}
@Override
public synchronized DBSObject refreshObject(@NotNull DBRProgressMonitor monitor)
throws DBException
{
return database.schemaCache.refreshObject(monitor, database, this);
}
@Override
public boolean isSystem()
{
return
PostgreConstants.INFO_SCHEMA_NAME.equalsIgnoreCase(name) ||
PostgreConstants.CATALOG_SCHEMA_NAME.equalsIgnoreCase(name) ||
name.startsWith(PostgreConstants.TOAST_SCHEMA_PREFIX) ||
name.startsWith(PostgreConstants.TEMP_SCHEMA_PREFIX);
}
public boolean isUtility()
{
return isUtilitySchema(name);
}
public static boolean isUtilitySchema(String schema)
{
return schema.startsWith(PostgreConstants.TOAST_SCHEMA_PREFIX) ||
schema.startsWith(PostgreConstants.TEMP_SCHEMA_PREFIX);
}
//@Property
public Collection<? extends DBSDataType> getDataTypes(DBRProgressMonitor monitor) throws DBException {
List<PostgreDataType> types = new ArrayList<>();
for (PostgreDataType dt : dataTypeCache.getAllObjects(monitor, this)) {
if (dt.getParentObject() == this) {
types.add(dt);
}
}
if (PostgreConstants.CATALOG_SCHEMA_NAME.equals(this.getName())) {
// Add serial data types
for (Map.Entry<String,String> serialMapping : PostgreConstants.SERIAL_TYPES.entrySet()) {
PostgreDataType realType = dataTypeCache.getCachedObject(serialMapping.getValue());
if (realType != null) {
PostgreDataType serialType = new PostgreDataType(realType, serialMapping.getKey());
dataTypeCache.cacheObject(serialType);
}
}
}
DBUtils.orderObjects(types);
return types;
}
@Override
public String toString() {
return name;
}
class CollationCache extends JDBCObjectCache<PostgreSchema, PostgreCollation> {
@Override
protected JDBCStatement prepareObjectsStatement(@NotNull JDBCSession session, @NotNull PostgreSchema owner)
throws SQLException
{
final JDBCPreparedStatement dbStat = session.prepareStatement(
"SELECT c.oid,c.* FROM pg_catalog.pg_collation c " +
"\nWHERE c.collnamespace=?" +
"\nORDER BY c.oid"
);
dbStat.setLong(1, PostgreSchema.this.getObjectId());
return dbStat;
}
@Override
protected PostgreCollation fetchObject(@NotNull JDBCSession session, @NotNull PostgreSchema owner, @NotNull JDBCResultSet dbResult)
throws SQLException, DBException
{
return new PostgreCollation(owner, dbResult);
}
}
class ExtensionCache extends JDBCObjectCache<PostgreSchema, PostgreExtension> {
@Override
protected JDBCStatement prepareObjectsStatement(@NotNull JDBCSession session, @NotNull PostgreSchema owner)
throws SQLException
{
final JDBCPreparedStatement dbStat = session.prepareStatement(
"SELECT e.oid,e.* FROM pg_catalog.pg_extension e " +
"\nWHERE e.extnamespace=?" +
"\nORDER BY e.oid"
);
dbStat.setLong(1, PostgreSchema.this.getObjectId());
return dbStat;
}
@Override
protected PostgreExtension fetchObject(@NotNull JDBCSession session, @NotNull PostgreSchema owner, @NotNull JDBCResultSet dbResult)
throws SQLException, DBException
{
return new PostgreExtension(owner, dbResult);
}
}
public class TableCache extends JDBCStructLookupCache<PostgreSchema, PostgreTableBase, PostgreTableColumn> {
protected TableCache()
{
super("relname");
setListOrderComparator(DBUtils.<PostgreTableBase>nameComparator());
}
@NotNull
@Override
public JDBCStatement prepareLookupStatement(@NotNull JDBCSession session, @NotNull PostgreSchema postgreSchema, @Nullable PostgreTableBase object, @Nullable String objectName) throws SQLException {
final JDBCPreparedStatement dbStat = session.prepareStatement(
"SELECT c.oid,c.*,d.description FROM pg_catalog.pg_class c\n" +
"LEFT OUTER JOIN pg_catalog.pg_description d ON d.objoid=c.oid AND d.objsubid=0\n" +
"WHERE c.relnamespace=? AND c.relkind not in ('i','c')" +
(object == null && objectName == null ? "" : " AND relname=?")
);
dbStat.setLong(1, getObjectId());
if (object != null || objectName != null) dbStat.setString(2, object != null ? object.getName() : objectName);
return dbStat;
}
@Override
protected PostgreTableBase fetchObject(@NotNull JDBCSession session, @NotNull PostgreSchema owner, @NotNull JDBCResultSet dbResult)
throws SQLException, DBException
{
final String kindString = JDBCUtils.safeGetString(dbResult, "relkind");
PostgreClass.RelKind kind;
try {
kind = PostgreClass.RelKind.valueOf(kindString);
} catch (Throwable e) {
log.warn("Unexpected class '" + kindString + "'", e);
return null;
}
switch (kind) {
case r:
return new PostgreTableRegular(PostgreSchema.this, dbResult);
case v:
return new PostgreView(PostgreSchema.this, dbResult);
case m:
return new PostgreMaterializedView(PostgreSchema.this, dbResult);
case f:
return new PostgreTableForeign(PostgreSchema.this, dbResult);
case S:
return new PostgreSequence(PostgreSchema.this, dbResult);
case t:
return new PostgreTableRegular(PostgreSchema.this, dbResult);
default:
log.warn("Unsupported PostgreClass '" + kind + "'");
return null;
}
}
@Override
protected JDBCStatement prepareChildrenStatement(@NotNull JDBCSession session, @NotNull PostgreSchema owner, @Nullable PostgreTableBase forTable)
throws SQLException
{
StringBuilder sql = new StringBuilder();
sql.append("SELECT c.relname,a.*,pg_catalog.pg_get_expr(ad.adbin, ad.adrelid, true) as def_value,dsc.description" +
"\nFROM pg_catalog.pg_attribute a" +
"\nINNER JOIN pg_catalog.pg_class c ON (a.attrelid=c.oid)" +
"\nLEFT OUTER JOIN pg_catalog.pg_attrdef ad ON (a.attrelid=ad.adrelid AND a.attnum = ad.adnum)" +
"\nLEFT OUTER JOIN pg_catalog.pg_description dsc ON (c.oid=dsc.objoid AND a.attnum = dsc.objsubid)" +
"\nWHERE NOT a.attisdropped");
if (forTable != null) {
sql.append(" AND c.oid=?");
} else {
sql.append(" AND c.relnamespace=? AND c.relkind not in ('i','c')");
}
sql.append(" ORDER BY a.attnum");
JDBCPreparedStatement dbStat = session.prepareStatement(sql.toString());
if (forTable != null) {
dbStat.setLong(1, forTable.getObjectId());
} else {
dbStat.setLong(1, PostgreSchema.this.getObjectId());
}
return dbStat;
}
@Override
protected PostgreTableColumn fetchChild(@NotNull JDBCSession session, @NotNull PostgreSchema owner, @NotNull PostgreTableBase table, @NotNull JDBCResultSet dbResult)
throws SQLException, DBException
{
try {
return new PostgreTableColumn(table, dbResult);
} catch (DBException e) {
log.warn("Error reading attribute info", e);
return null;
}
}
}
/**
* Constraint cache implementation
*/
class ConstraintCache extends JDBCCompositeCache<PostgreSchema, PostgreTableBase, PostgreTableConstraintBase, PostgreTableConstraintColumn> {
protected ConstraintCache() {
super(tableCache, PostgreTableBase.class, "tabrelname", "conname");
}
@NotNull
@Override
protected JDBCStatement prepareObjectsStatement(JDBCSession session, PostgreSchema schema, PostgreTableBase forParent) throws SQLException {
StringBuilder sql = new StringBuilder(
"SELECT c.oid,c.*,t.relname as tabrelname,rt.relnamespace as refnamespace" +
"\nFROM pg_catalog.pg_constraint c" +
"\nINNER JOIN pg_catalog.pg_class t ON t.oid=c.conrelid" +
"\nLEFT OUTER JOIN pg_catalog.pg_class rt ON rt.oid=c.confrelid" +
"\nWHERE ");
if (forParent == null) {
sql.append("t.relnamespace=?");
} else {
sql.append("c.conrelid=?");
}
sql.append("\nORDER BY c.oid");
JDBCPreparedStatement dbStat = session.prepareStatement(sql.toString());
if (forParent == null) {
dbStat.setLong(1, schema.getObjectId());
} else {
dbStat.setLong(1, forParent.getObjectId());
}
return dbStat;
}
@Nullable
@Override
protected PostgreTableConstraintBase fetchObject(JDBCSession session, PostgreSchema schema, PostgreTableBase table, String childName, JDBCResultSet resultSet) throws SQLException, DBException {
String name = JDBCUtils.safeGetString(resultSet, "conname");
String type = JDBCUtils.safeGetString(resultSet, "contype");
if (type == null) {
log.warn("Null constraint type");
return null;
}
DBSEntityConstraintType constraintType;
switch (type) {
case "c": constraintType = DBSEntityConstraintType.CHECK; break;
case "f": constraintType = DBSEntityConstraintType.FOREIGN_KEY; break;
case "p": constraintType = DBSEntityConstraintType.PRIMARY_KEY; break;
case "u": constraintType = DBSEntityConstraintType.UNIQUE_KEY; break;
case "t": constraintType = PostgreConstants.CONSTRAINT_TRIGGER; break;
case "x": constraintType = PostgreConstants.CONSTRAINT_EXCLUSIVE; break;
default:
log.warn("Unsupported PG constraint type: " + type);
return null;
}
try {
if (constraintType == DBSEntityConstraintType.FOREIGN_KEY) {
return new PostgreTableForeignKey(table, name, resultSet);
} else {
return new PostgreTableConstraint(table, name, constraintType, resultSet);
}
} catch (DBException e) {
log.error(e);
return null;
}
}
@Nullable
@Override
protected PostgreTableConstraintColumn[] fetchObjectRow(JDBCSession session, PostgreTableBase table, PostgreTableConstraintBase constraint, JDBCResultSet resultSet)
throws SQLException, DBException
{
Object keyNumbers = JDBCUtils.safeGetArray(resultSet, "conkey");
if (keyNumbers == null) {
return null;
}
final DBRProgressMonitor monitor = resultSet.getSession().getProgressMonitor();
if (constraint instanceof PostgreTableForeignKey) {
final PostgreTableForeignKey foreignKey = (PostgreTableForeignKey) constraint;
final PostgreTableBase refTable = foreignKey.getAssociatedEntity();
if (refTable == null) {
log.warn("Unresolved reference table of '" + foreignKey.getName() + "'");
return null;
}
Object keyRefNumbers = JDBCUtils.safeGetArray(resultSet, "confkey");
Collection<PostgreTableColumn> attributes = table.getAttributes(monitor);
Collection<PostgreTableColumn> refAttributes = refTable.getAttributes(monitor);
assert attributes != null && refAttributes != null;
int colCount = Array.getLength(keyNumbers);
PostgreTableForeignKeyColumn[] fkCols = new PostgreTableForeignKeyColumn[colCount];
for (int i = 0; i < colCount; i++) {
Number colNumber = (Number) Array.get(keyNumbers, i); // Column number - 1-based
Number colRefNumber = (Number) Array.get(keyRefNumbers, i);
final PostgreTableColumn attr = PostgreUtils.getAttributeByNum(attributes, colNumber.intValue());
final PostgreTableColumn refAttr = PostgreUtils.getAttributeByNum(refAttributes, colRefNumber.intValue());
if (attr == null) {
log.warn("Bad foreign key attribute index: " + colNumber);
continue;
}
if (refAttr == null) {
log.warn("Bad reference table '" + refTable + "' attribute index: " + colNumber);
continue;
}
PostgreTableForeignKeyColumn cCol = new PostgreTableForeignKeyColumn(foreignKey, attr, i, refAttr);
fkCols[i] = cCol;
}
return fkCols;
} else {
Collection<PostgreTableColumn> attributes = table.getAttributes(monitor);
assert attributes != null;
int colCount = Array.getLength(keyNumbers);
PostgreTableConstraintColumn[] cols = new PostgreTableConstraintColumn[colCount];
for (int i = 0; i < colCount; i++) {
Number colNumber = (Number) Array.get(keyNumbers, i); // Column number - 1-based
final PostgreAttribute attr = PostgreUtils.getAttributeByNum(attributes, colNumber.intValue());
if (attr == null) {
log.warn("Bad constraint attribute index: " + colNumber);
continue;
}
PostgreTableConstraintColumn cCol = new PostgreTableConstraintColumn(constraint, attr, i);
cols[i] = cCol;
}
return cols;
}
}
@Override
protected void cacheChildren(DBRProgressMonitor monitor, PostgreTableConstraintBase object, List<PostgreTableConstraintColumn> children) {
object.cacheAttributes(monitor, children, false);
}
@Override
protected void cacheChildren2(DBRProgressMonitor monitor, PostgreTableConstraintBase object, List<PostgreTableConstraintColumn> children) {
object.cacheAttributes(monitor, children, true);
}
}
/**
* Index cache implementation
*/
class IndexCache extends JDBCCompositeCache<PostgreSchema, PostgreTableBase, PostgreIndex, PostgreIndexColumn> {
protected IndexCache()
{
super(tableCache, PostgreTableBase.class, "tabrelname", "relname");
}
@NotNull
@Override
protected JDBCStatement prepareObjectsStatement(JDBCSession session, PostgreSchema owner, PostgreTableBase forTable)
throws SQLException
{
boolean supportsExprIndex = getDataSource().isServerVersionAtLeast(7, 4);
StringBuilder sql = new StringBuilder();
sql.append(
"SELECT i.*,i.indkey as keys,c.relname,c.relnamespace,c.relam,tc.relname as tabrelname,dsc.description");
if (supportsExprIndex) {
sql.append(",pg_catalog.pg_get_expr(i.indexprs, i.indrelid, true) as expr");
}
sql.append(
"\nFROM pg_catalog.pg_index i" +
"\nINNER JOIN pg_catalog.pg_class c ON c.oid=i.indexrelid" +
"\nINNER JOIN pg_catalog.pg_class tc ON tc.oid=i.indrelid" +
"\nLEFT OUTER JOIN pg_catalog.pg_description dsc ON i.indexrelid=dsc.objoid" +
"\nWHERE ");
if (forTable != null) {
sql.append(" i.indrelid=?");
} else {
sql.append(" c.relnamespace=?");
}
//sql.append(" AND NOT i.indisprimary");
sql.append(" ORDER BY c.relname");
JDBCPreparedStatement dbStat = session.prepareStatement(sql.toString());
if (forTable != null) {
dbStat.setLong(1, forTable.getObjectId());
} else {
dbStat.setLong(1, PostgreSchema.this.getObjectId());
}
return dbStat;
}
@Nullable
@Override
protected PostgreIndex fetchObject(JDBCSession session, PostgreSchema owner, PostgreTableBase parent, String indexName, JDBCResultSet dbResult)
throws SQLException, DBException
{
return new PostgreIndex(
session.getProgressMonitor(),
parent,
indexName,
dbResult);
}
@Nullable
@Override
protected PostgreIndexColumn[] fetchObjectRow(
JDBCSession session,
PostgreTableBase parent, PostgreIndex object, JDBCResultSet dbResult)
throws SQLException, DBException
{
long[] keyNumbers = PostgreUtils.getIdVector(JDBCUtils.safeGetObject(dbResult, "keys"));
if (keyNumbers == null) {
return null;
}
int[] keyOptions = PostgreUtils.getIntVector(JDBCUtils.safeGetObject(dbResult, "indoption"));
String expr = JDBCUtils.safeGetString(dbResult, "expr");
Collection<PostgreTableColumn> attributes = parent.getAttributes(dbResult.getSession().getProgressMonitor());
assert attributes != null;
PostgreIndexColumn[] result = new PostgreIndexColumn[keyNumbers.length];
for (int i = 0; i < keyNumbers.length; i++) {
long colNumber = keyNumbers[i];
String attrExpression = null;
final PostgreAttribute attr = PostgreUtils.getAttributeByNum(attributes, (int) colNumber);
if (attr == null) {
if (colNumber == 0 && expr != null) {
// It's ok, function index or something
attrExpression = JDBCUtils.queryString(session, "select pg_catalog.pg_get_indexdef(?, ?, true)", object.getIndexId(), i + 1);
} else {
log.warn("Bad index attribute index: " + colNumber);
}
}
int options = keyOptions == null || keyOptions.length < keyNumbers.length ? 0 : keyOptions[i];
PostgreIndexColumn col = new PostgreIndexColumn(
object,
attr,
attrExpression,
i,
(options & 0x01) != 0, // This is a kind of lazy hack. Actually this flag depends on access method.
false);
result[i] = col;
}
return result;
}
@Override
protected void cacheChildren(DBRProgressMonitor monitor, PostgreIndex index, List<PostgreIndexColumn> rows)
{
index.setColumns(rows);
}
}
/**
* Procedures cache implementation
*/
static class ProceduresCache extends JDBCObjectLookupCache<PostgreSchema, PostgreProcedure> {
ProceduresCache()
{
super();
}
@NotNull
@Override
public JDBCStatement prepareLookupStatement(@NotNull JDBCSession session, @NotNull PostgreSchema owner, @Nullable PostgreProcedure object, @Nullable String objectName) throws SQLException {
JDBCPreparedStatement dbStat = session.prepareStatement(
"SELECT p.oid,p.*,d.description\n" +
"FROM pg_catalog.pg_proc p\n" +
"LEFT OUTER JOIN pg_catalog.pg_description d ON d.objoid=p.oid\n" +
"WHERE p.pronamespace=?" +
(object == null ? "" : " AND p.oid=?") +
"\nORDER BY p.proname"
);
dbStat.setLong(1, owner.getObjectId());
if (object != null) {
dbStat.setLong(2, object.getObjectId());
}
return dbStat;
}
@Override
protected PostgreProcedure fetchObject(@NotNull JDBCSession session, @NotNull PostgreSchema owner, @NotNull JDBCResultSet dbResult)
throws SQLException, DBException
{
return new PostgreProcedure(owner, dbResult);
}
}
}