/* * 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.dbeaver.DBException; import org.jkiss.dbeaver.Log; import org.jkiss.dbeaver.model.DBUtils; import org.jkiss.dbeaver.model.exec.DBCSession; 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.AbstractExecutionSource; import org.jkiss.dbeaver.model.impl.jdbc.JDBCUtils; import org.jkiss.dbeaver.model.impl.jdbc.cache.JDBCObjectCache; 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.DBSEntity; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collection; /** * PostgreTable base */ public abstract class PostgreTableReal extends PostgreTableBase { private static final Log log = Log.getLog(PostgreTableReal.class); public static final String CAT_STATISTICS = "Statistics"; private long rowCountEstimate; private Long rowCount; private Long diskSpace; final TriggerCache triggerCache = new TriggerCache(); protected PostgreTableReal(PostgreSchema catalog) { super(catalog); } protected PostgreTableReal( PostgreSchema catalog, ResultSet dbResult) { super(catalog, dbResult); this.rowCountEstimate = JDBCUtils.safeGetLong(dbResult, "reltuples"); } // Copy constructor public PostgreTableReal(PostgreSchema container, DBSEntity source, boolean persisted) { super(container, source, persisted); // Copy triggers if (source instanceof PostgreTableReal) { } } @Property(category = CAT_STATISTICS, viewable = true, order = 22) public long getRowCountEstimate() { return rowCountEstimate; } @Property(category = CAT_STATISTICS, viewable = false, expensive = true, order = 23) public synchronized Long getRowCount(DBRProgressMonitor monitor) { if (rowCount != null) { return rowCount; } if (!isPersisted()) { // Do not count rows for views return null; } // Query row count try (DBCSession session = DBUtils.openMetaSession(monitor, getDataSource(), "Read row count")) { rowCount = countData(new AbstractExecutionSource(this, session.getExecutionContext(), this), session, null); } catch (DBException e) { log.debug("Can't fetch row count", e); } if (rowCount == null) { rowCount = -1L; } return rowCount; } @Property(category = CAT_STATISTICS, viewable = false, expensive = true, order = 24) public synchronized Long getDiskSpace(DBRProgressMonitor monitor) { if (diskSpace != null) { return diskSpace; } if (!isPersisted() || this instanceof PostgreView) { // Do not count rows for views return null; } // Query row count try (DBCSession session = DBUtils.openMetaSession(monitor, getDataSource(), "Calculate relation size on disk")) { try (JDBCPreparedStatement dbStat = ((JDBCSession)session).prepareStatement("select pg_total_relation_size(?)")) { dbStat.setLong(1, getObjectId()); try (JDBCResultSet dbResult = dbStat.executeQuery()) { if (dbResult.next()) { diskSpace = dbResult.getLong(1); } } } } catch (Exception e) { log.debug("Can't fetch disk space", e); } if (diskSpace == null) { diskSpace = -1L; } return diskSpace; } @Override public Collection<PostgreTableConstraint> getConstraints(@NotNull DBRProgressMonitor monitor) throws DBException { return getSchema().constraintCache.getTypedObjects(monitor, getSchema(), this, PostgreTableConstraint.class); } public PostgreTableConstraintBase getConstraint(@NotNull DBRProgressMonitor monitor, String ukName) throws DBException { return getSchema().constraintCache.getObject(monitor, getSchema(), this, ukName); } @Association public Collection<PostgreTrigger> getTriggers(DBRProgressMonitor monitor) throws DBException { return triggerCache.getAllObjects(monitor, this); } public PostgreTrigger getTrigger(DBRProgressMonitor monitor, String name) throws DBException { return triggerCache.getObject(monitor, this, name); } @Override public void setObjectDefinitionText(String sourceText) throws DBException { throw new DBException("Table DDL is read-only"); } class TriggerCache extends JDBCObjectCache<PostgreTableReal, PostgreTrigger> { @Override protected JDBCStatement prepareObjectsStatement(@NotNull JDBCSession session, @NotNull PostgreTableReal owner) throws SQLException { return session.prepareStatement( "SELECT x.oid,x.*,p.pronamespace as func_schema_id" + "\nFROM pg_catalog.pg_trigger x" + "\nLEFT OUTER JOIN pg_catalog.pg_proc p ON p.oid=x.tgfoid " + "\nWHERE x.tgrelid=" + owner.getObjectId() + (getDataSource().isServerVersionAtLeast(9, 0) ? " AND NOT x.tgisinternal" : "")); } @Override protected PostgreTrigger fetchObject(@NotNull JDBCSession session, @NotNull PostgreTableReal owner, @NotNull JDBCResultSet dbResult) throws SQLException, DBException { return new PostgreTrigger(owner, dbResult); } } }