diff --git a/README.md b/README.md
index 8b6152e..d21a85d 100644
--- a/README.md
+++ b/README.md
@@ -11,6 +11,9 @@
The default capture rate is one snapshot every 1 seconds.
PASH Viewer support PostgreSQL 10+ (and 9.4 - 9.6 with limited functions).
+ PASH Viewer now support PostgreSQL 13 as well.
+ SSL Connections are supported as well.
+
Read how it works: https://github.com/dbacvetkov/PASH-Viewer/wiki
Use superuser (postgres) to connect to DB, if you want to see query plans.
diff --git a/build.gradle b/build.gradle
index 3b3132d..7a0edd4 100644
--- a/build.gradle
+++ b/build.gradle
@@ -10,7 +10,7 @@
apply plugin: 'application'
apply plugin: 'java'
-version = '0.4.1'
+version = '0.4.3'
sourceCompatibility = 1.7
targetCompatibility = 1.7
diff --git a/lib/postgresql-42.2.18.jre7.jar b/lib/postgresql-42.2.18.jre7.jar
new file mode 100644
index 0000000..81f6fcc
Binary files /dev/null and b/lib/postgresql-42.2.18.jre7.jar differ
diff --git a/lib/postgresql-42.2.2.jre7.jar b/lib/postgresql-42.2.2.jre7.jar
deleted file mode 100644
index e58ce2c..0000000
Binary files a/lib/postgresql-42.2.2.jre7.jar and /dev/null differ
diff --git a/src/org/ash/database/ASHDatabasePG12.java b/src/org/ash/database/ASHDatabasePG12.java
new file mode 100644
index 0000000..8c8c589
--- /dev/null
+++ b/src/org/ash/database/ASHDatabasePG12.java
@@ -0,0 +1,805 @@
+/*
+ *-------------------
+ * The ASHDatabasePG12.java is part of ASH Viewer
+ *-------------------
+ *
+ * ASH Viewer is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * ASH Viewer 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with ASH Viewer. If not, see .
+ *
+ * Copyright (c) 2009, Alex Kardapolov, All rights reserved.
+ *
+ */
+package org.ash.database;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.math.BigInteger;
+
+import org.ash.conn.model.Model;
+import org.ash.datamodel.ActiveSessionHistory;
+import org.ash.datamodel.AshIdTime;
+import org.ash.datamodel.AshSqlIdTypeText;
+import org.ash.datatemp.SessionsTemp;
+import org.ash.datatemp.SqlsTemp;
+import org.ash.util.Utils;
+import org.ash.database.DBUtils;
+import org.jdesktop.swingx.treetable.TreeTableModel;
+import org.jfree.data.xy.CategoryTableXYDataset;
+
+import com.sleepycat.je.DatabaseException;
+import com.sleepycat.je.Sequence;
+import com.sleepycat.persist.EntityCursor;
+import com.sleepycat.persist.EntityStore;
+
+// dcvetkov import
+import org.ash.util.Options;
+
+/**
+ * The Class ASHDatabasePG12.
+ */
+public class ASHDatabasePG12 extends ASHDatabase {
+
+ /**
+ * The model.
+ */
+ private Model model;
+
+ /**
+ * The sequence.
+ */
+ private Sequence seq;
+
+ /**
+ * The BDB store.
+ */
+ private EntityStore store;
+
+ /**
+ * The BDB dao.
+ */
+ private AshDataAccessor dao;
+
+ /**
+ * The range for sqls and sessions temp (gantt)
+ */
+ private int rangeHalf = 7500;
+
+ /**
+ * The query ash.
+ */
+ private String queryASH = "SELECT current_timestamp, "
+ + "datname, pid, usesysid, usename, "
+ + "application_name, backend_type, "
+ + "coalesce(client_hostname, client_addr::text, 'localhost') as client_hostname, "
+ + "wait_event_type, wait_event, query, "
+ + "coalesce(query_start, xact_start, backend_start) as query_start, 1000 * EXTRACT(EPOCH FROM (clock_timestamp()-coalesce(query_start, xact_start, backend_start))) as duration "
+ + "from pg_stat_activity "
+ + "where state='active' and pid != pg_backend_pid()";
+
+ private String fileSeparator = System.getProperty("file.separator");
+ private String planDir = Options.getInstance().getPlanDir();
+
+
+
+ /**
+ * The k for sample_id after reconnect
+ */
+ private long kReconnect = 0;
+
+ /**
+ * Is reconnect
+ */
+ private boolean isReconnect = false;
+
+ /**
+ * Instantiates a new PG12 Database
+ *
+ * @param model0 the model0
+ */
+ public ASHDatabasePG12(Model model0) {
+ super(model0);
+ this.model = model0;
+ this.store = super.getStore();
+ this.dao = super.getDao();
+ }
+
+ /* (non-Javadoc)
+ * @see org.ash.database.DatabaseMain#loadToLocalBDB()
+ */
+ public void loadToLocalBDB() {
+
+ // Get max value of ash
+ super.initializeVarsOnLoad();
+
+ // Load data to activeSessionHistoryById
+ loadHistAshDataToLocal();
+
+ // dcvetkov
+ // super.loadToSubByEventAnd10Sec();
+ super.loadToSubByEventAnd10Sec_all_history_at_start();
+ }
+
+ /* (non-Javadoc)
+ * @see org.ash.database.DatabaseMain#loadToLocalBDBCollector()
+ */
+ public synchronized void loadToLocalBDBCollector() {
+ // Get max value of ash
+ // it does: sampleId = dao.ashById.sortedMap().lastKey();
+ super.initializeVarsAfterLoad9i();
+
+ // Load data to activeSessionHistoryById
+ loadAshDataToLocal();
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.ash.database.DatabaseMain#loadDataToChartPanelDataSet(org.jfree.data.xy.CategoryTableXYDataset)
+ */
+ public void loadDataToChartPanelDataSet(CategoryTableXYDataset _dataset) {
+ super.loadDataToChartPanelDataSet(_dataset);
+ }
+
+ /* (non-Javadoc)
+ * @see org.ash.database.DatabaseMain#updateDataToChartPanelDataSet()
+ */
+ public void updateDataToChartPanelDataSet() {
+ super.updateDataToChartPanelDataSet();
+ }
+
+ /**
+ * Load ash data to local.
+ */
+ private void loadAshDataToLocal() {
+
+ ResultSet resultSetAsh = null;
+ PreparedStatement statement = null;
+ Connection conn = null;
+
+ // Get sequence activeSessionHistoryId
+ try {
+ seq = store.getSequence("activeSessionHistoryId");
+ } catch (DatabaseException e) {
+ // e.printStackTrace();
+ }
+
+ try {
+
+ if (model.getConnectionPool() != null) {
+
+ String connDBName = getParameter("ASH.db");
+ int explainFreq = Options.getInstance().getExplainFreq();
+
+ conn = this.model.getConnectionPool().getConnection();
+
+ statement = conn.prepareStatement(this.queryASH);
+
+
+
+
+
+
+ // set ArraySize for current statement to improve performance
+ statement.setFetchSize(5000);
+ // set Timeout to 1 second
+ statement.setQueryTimeout(1);
+
+ resultSetAsh = statement.executeQuery();
+
+ while (resultSetAsh.next()) {
+
+ long activeSessionHistoryIdWait = 0;
+ try {
+ activeSessionHistoryIdWait = seq.get(null, 1);
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+
+ // Calculate sample time
+ java.sql.Timestamp PGDateSampleTime = resultSetAsh.getTimestamp("current_timestamp");
+ Long valueSampleIdTimeLongWait = (new Long(PGDateSampleTime.getTime()));
+
+
+
+
+
+
+
+ java.sql.Timestamp queryStartTS = resultSetAsh.getTimestamp("query_start");
+ Long queryStartLong = 0L;
+ if (queryStartTS != null) {
+ queryStartLong = (new Long(queryStartTS.getTime()));
+ }
+
+ Double duration = resultSetAsh.getDouble("duration");
+
+ Long sessionId = resultSetAsh.getLong("pid");
+ String backendType = resultSetAsh.getString("backend_type");
+
+ String databaseName = resultSetAsh.getString("datname");
+
+ Long userId = resultSetAsh.getLong("usesysid");
+ String userName = resultSetAsh.getString("usename");
+
+ String program = resultSetAsh.getString("application_name");
+
+ String query_text = resultSetAsh.getString("query");
+ if ((query_text == null) || (query_text.equals(""))) {
+ if(program != null && program.equals("pg_basebackup")) {
+ query_text = "backup";
+ } else if (program != null && (program.equals("walreceiver") || program.equals("walsender"))) {
+ query_text = "wal";
+ } else if(backendType != null && (backendType.equals("walreceiver") || backendType.equals("walsender"))) {
+ query_text = "wal";
+ } else {
+ query_text = "empty";
+ }
+ }
+
+ String query_text_norm = DBUtils.NormalizeSQL(query_text);
+ String command_type = DBUtils.GetSQLCommandType(query_text_norm);
+ String sqlId = DBUtils.md5Custom(query_text_norm);
+
+ /* System.out.println(query_text);
+ System.out.println(query_text_norm);
+ System.out.println(sqlId);
+ System.out.println("");
+ */
+ String hostname = resultSetAsh.getString("client_hostname");
+ String event = resultSetAsh.getString("wait_event");
+ String waitClass = resultSetAsh.getString("wait_event_type");
+
+ if ((waitClass == null) || (waitClass.equals(""))) {
+ waitClass = "CPU";
+ event = "CPU";
+ }
+
+ if ((event == null) || (event.equals(""))) {
+ event = waitClass;
+ }
+
+ if (event.equals("PgSleep")&&query_text.contains("pg_stat_activity_snapshot")) {
+ continue;
+ }
+
+ Double waitClassId = 0.0;
+
+ if (waitClass.equals("CPU")) {
+ waitClassId = 0.0;
+ } else if (waitClass.equals("IO")) {
+ waitClassId = 1.0;
+ } else if (waitClass.equals("Lock")) {
+ waitClassId = 2.0;
+ } else if (waitClass.equals("LWLock")) {
+ waitClassId = 3.0;
+ } else if (waitClass.equals("BufferPin")) {
+ waitClassId = 4.0;
+ } else if (waitClass.equals("Activity")) {
+ waitClassId = 5.0;
+ } else if (waitClass.equals("Extension")) {
+ waitClassId = 6.0;
+ } else if (waitClass.equals("Client")) {
+ waitClassId = 7.0;
+ } else if (waitClass.equals("IPC")) {
+ waitClassId = 8.0;
+ } else if (waitClass.equals("Timeout")) {
+ waitClassId = 9.0;
+ }
+
+ // Create row for wait event
+ try {
+ dao.ashById.putNoOverwrite(new AshIdTime(valueSampleIdTimeLongWait, valueSampleIdTimeLongWait.doubleValue()));
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+
+ // Load data for active session history (wait event)
+ try {
+ dao.activeSessionHistoryById
+ .putNoReturn(new ActiveSessionHistory(
+ activeSessionHistoryIdWait,
+ valueSampleIdTimeLongWait,
+ sessionId, backendType, userId, userName, sqlId, command_type,
+ event, waitClass, waitClassId, program, hostname, queryStartLong, duration));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ // dcvetkov: Load data for sqlid: command type and query text
+ try {
+ dao.ashSqlIdTypeTextId.putNoReturn(new AshSqlIdTypeText(sqlId, command_type, query_text_norm));
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+
+ // dcvetkov: explain plan
+ if (command_type.equals("SELECT") || command_type.equals("UPDATE") || command_type.equals("DELETE") || command_type.equals("INSERT")) {
+ if ((connDBName.length() > 0) && (explainFreq > 0)) {
+ DBUtils.explainPlan(sqlId, query_text, command_type, planDir, fileSeparator, connDBName, databaseName, conn, explainFreq);
+ // DBUtils.FindQueryID(sqlId, query_text_norm, conn);
+ }
+ }
+
+ }
+ if (conn != null) {
+ model.getConnectionPool().free(conn);
+ }
+ } else {
+ // Connect is lost
+ setReconnect(true);
+ model.closeConnectionPool();
+ model.connectionPoolInitReconnect();
+ }
+
+ } catch (SQLException e) {
+ System.out.println("SQL Exception occured: " + e.getMessage());
+ model.closeConnectionPool();
+ } finally {
+ if (resultSetAsh != null) {
+ try {
+ resultSetAsh.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ if (statement != null) {
+ try {
+ statement.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#calculateSqlsSessionsData(double,
+ * double)
+ */
+ public void calculateSqlsSessionsData(double beginTime, double endTime, String eventFlag) {
+
+ try {
+
+ SqlsTemp tmpSqlsTemp = null;
+ SessionsTemp tmpSessionsTemp = null;
+
+ if (eventFlag.equalsIgnoreCase("All")) {
+ tmpSqlsTemp = super.getSqlsTemp();
+ tmpSessionsTemp = super.getSessionsTemp();
+ } else {
+ tmpSqlsTemp = super.getSqlsTempDetail();
+ tmpSessionsTemp = super.getSessionsTempDetail();
+ }
+
+ // get sample id's for beginTime and endTime
+ EntityCursor ashSampleIds;
+ ashSampleIds = dao.doRangeQuery(dao.ashBySampleTime, beginTime - rangeHalf, true, endTime + rangeHalf, true);
+ /* Iterate on Ash by SampleTime. */
+ Iterator ashIter = ashSampleIds.iterator();
+
+ while (ashIter.hasNext()) {
+
+ AshIdTime ashSumMain = ashIter.next();
+
+ // get rows from ActiveSessionHistory for samplId
+ EntityCursor ActiveSessionHistoryCursor;
+ ActiveSessionHistoryCursor = dao.doRangeQuery(dao.activeSessionHistoryByAshId, ashSumMain.getsampleId(), true, ashSumMain.getsampleId(), true);
+ Iterator ActiveSessionHistoryIter = ActiveSessionHistoryCursor.iterator();
+
+ while (ActiveSessionHistoryIter.hasNext()) {
+ ActiveSessionHistory ASH = ActiveSessionHistoryIter.next();
+
+ // sql data
+ String sqlId = ASH.getSqlId();
+ double waitClassId = ASH.getWaitClassId();
+ // session data
+ Long sessionId = (Long) ASH.getSessionId();
+ String sessionidS = sessionId.toString().trim();
+ Long useridL = (Long) ASH.getUserId();
+ String usernameSess = ASH.getUserName();
+ String programSess = ASH.getProgram();
+ programSess = programSess + "@" + ASH.getHostname();
+ String backendSess = ASH.getBackendType();
+ String waitClass = ASH.getWaitClass();
+ String eventName = ASH.getEvent();
+
+ Long queryStart = ASH.getQueryStart();
+ Double duration = ASH.getDuration();
+
+ // Exit when current eventClas != eventFlag
+ if (!eventFlag.equalsIgnoreCase("All")) {
+ if (waitClass != null && waitClass.equalsIgnoreCase(eventFlag)) {
+ this.loadDataToTempSqlSession(tmpSqlsTemp,
+ tmpSessionsTemp, sqlId, waitClassId,
+ sessionId, sessionidS, 0.0, backendSess,
+ useridL, usernameSess, programSess, true, eventName, queryStart, duration);
+ }
+
+ } else {
+ this.loadDataToTempSqlSession(tmpSqlsTemp,
+ tmpSessionsTemp, sqlId, waitClassId,
+ sessionId, sessionidS, 0.0, backendSess,
+ useridL, usernameSess, programSess, false, eventFlag, queryStart, duration);
+ }
+ }
+ // Close cursor!!
+ ActiveSessionHistoryCursor.close();
+ }
+ tmpSqlsTemp.set_sum();
+ tmpSessionsTemp.set_sum();
+
+ // Close cursor!!
+ ashSampleIds.close();
+
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#loadCommandTypeFromDB(java.util.List)
+ */
+ public void loadSqlTextCommandTypeFromDB(List arraySqlId) {
+
+ // Load all sqlId
+ ArrayList sqlIdAll = new ArrayList();
+
+ Iterator arraySqlIdIter = arraySqlId.iterator();
+ while (arraySqlIdIter.hasNext()) {
+ String sqlId = arraySqlIdIter.next();
+ if (!isSqlTextExist(sqlId)) {
+ sqlIdAll.add(sqlId);
+ }
+ }
+
+ this.loadSqlTextSqlIdFromDB(sqlIdAll);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#isSqlPlanHashValueExist(java.lang.String)
+ */
+ public boolean isSqlTextExist(String sqlId) {
+ boolean res = false;
+ try {
+ res = dao.getAshSqlIdTypeTextId().contains(sqlId);
+ } catch (DatabaseException e) {
+ res = false;
+ }
+
+ return res;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#getSqlType(java.lang.String)
+ */
+ public String getSqlType(String sqlId) {
+ String sqlType = null;
+ try {
+ AshSqlIdTypeText ash = dao.ashSqlIdTypeTextId.get(sqlId);
+ if (ash != null) {
+ sqlType = ash.getCommandType();
+ } else {
+ sqlType = "";
+ }
+ } catch (DatabaseException e) {
+ sqlType = "";
+ e.printStackTrace();
+ }
+ return sqlType;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#getSqlText(java.lang.String)
+ */
+ public String getSqlText(String sqlId) {
+ String sqlText = null;
+ try {
+ AshSqlIdTypeText ash = dao.ashSqlIdTypeTextId.get(sqlId);
+ if (ash != null) {
+ sqlText = ash.getSqlText();
+ } else {
+ sqlText = "";
+ }
+
+ } catch (DatabaseException e) {
+ sqlText = "";
+ e.printStackTrace();
+ }
+ return sqlText;
+ }
+
+ /**
+ * Load data to temporary sql and sessions (gantt data)
+ *
+ * @param tmpSqlsTemp
+ * @param tmpSessionsTemp
+ * @param sqlId
+ * @param waitClassId
+ * @param sessionId
+ * @param sessionidS
+ * @param sessionSerial
+ * @param sessioniSerialS
+ * @param useridL
+ * @param programSess
+ * @param isDetail
+ * @param sqlPlanHashValue
+ */
+ private void loadDataToTempSqlSession(SqlsTemp tmpSqlsTemp,
+ SessionsTemp tmpSessionsTemp, String sqlId, double waitClassId, Long sessionId,
+ String sessionidS, Double sessionSerial, String backendType,
+ Long useridL, String usernameSess, String programSess, boolean isDetail,
+ String eventDetail, Long queryStart, Double duration) {
+
+ int count = 1;
+
+ /**
+ * Save data for sql row
+ */
+ if (sqlId != null) {
+ // Save SQL_ID and init
+ tmpSqlsTemp.setSqlId(sqlId);
+ // Save group event
+ tmpSqlsTemp.setTimeOfGroupEvent(sqlId, waitClassId, count);
+ tmpSqlsTemp.setSqlStats(sqlId, sessionId, queryStart, duration);
+ }
+
+ /**
+ * Save data for session row
+ */
+ tmpSessionsTemp.setSessionId(sessionidS, backendType, programSess, "", usernameSess);
+ tmpSessionsTemp.setTimeOfGroupEvent(sessionidS, waitClassId, count);
+
+ /**
+ * Save event detail data for sql and sessions row
+ */
+ if (isDetail) {
+ if (sqlId != null) {
+ tmpSqlsTemp.setTimeOfEventName(sqlId, waitClassId, eventDetail, count);
+ }
+ tmpSessionsTemp.setTimeOfEventName(sessionidS, waitClassId, eventDetail, count);
+ }
+ }
+
+ /**
+ * @return the kReconnect
+ */
+ private long getKReconnect() {
+ return kReconnect;
+ }
+
+ /**
+ * @param reconnect the kReconnect to set
+ */
+ private void setKReconnect(long reconnect) {
+ kReconnect = reconnect;
+ }
+
+ /**
+ * @return the isReconnect
+ */
+ private boolean isReconnect() {
+ return isReconnect;
+ }
+
+ /**
+ * @param isReconnect the isReconnect to set
+ */
+ private void setReconnect(boolean isReconnect) {
+ this.isReconnect = isReconnect;
+ }
+
+
+
+
+
+
+
+ private void loadHistAshDataToLocal() {
+
+ ResultSet resultSetAsh = null;
+ PreparedStatement statement = null;
+ Connection conn = null;
+
+ // Get sequence activeSessionHistoryId
+ try {
+ seq = store.getSequence("activeSessionHistoryId");
+ } catch (DatabaseException e) {
+ // e.printStackTrace();
+ }
+
+ try {
+
+ if (model.getConnectionPool() != null) {
+
+ conn = this.model.getConnectionPool().getConnection();
+
+ statement = conn.prepareStatement("select * from pg_stat_activity_history order by sample_time");
+
+ // set ArraySize for current statement to improve performance
+ statement.setFetchSize(5000);
+
+ try {
+ resultSetAsh = statement.executeQuery();
+ } catch (SQLException e) {
+ return;
+ }
+
+ while (resultSetAsh.next()) {
+
+ long activeSessionHistoryIdWait = 0;
+ try {
+ activeSessionHistoryIdWait = seq.get(null, 1);
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+
+ // Calculate sample time
+ java.sql.Timestamp PGDateSampleTime = resultSetAsh.getTimestamp("sample_time");
+ Long valueSampleIdTimeLongWait = (new Long(PGDateSampleTime.getTime()));
+
+ java.sql.Timestamp queryStartTS = resultSetAsh.getTimestamp("query_start");
+ Long queryStartLong = 0L;
+ if (queryStartTS != null) {
+ queryStartLong = (new Long(queryStartTS.getTime()));
+ }
+
+ Double duration = resultSetAsh.getDouble("duration");
+
+ Long sessionId = resultSetAsh.getLong("pid");
+ String backendType = resultSetAsh.getString("backend_type");
+
+ String databaseName = resultSetAsh.getString("datname");
+
+ Long userId = resultSetAsh.getLong("usesysid");
+ String userName = resultSetAsh.getString("usename");
+
+ String program = resultSetAsh.getString("application_name");
+
+ String query_text = resultSetAsh.getString("query");
+ if ((query_text == null) || (query_text.equals(""))) {
+ if (program.equals("pg_basebackup")) {
+ query_text = "backup";
+ } else if (program.equals("walreceiver") || program.equals("walsender")) {
+ query_text = "wal";
+ } else if (backendType.equals("walreceiver") || backendType.equals("walsender")) {
+ query_text = "wal";
+ } else {
+ query_text = "empty";
+ }
+ }
+ String query_text_norm = DBUtils.NormalizeSQL(query_text);
+ String command_type = DBUtils.GetSQLCommandType(query_text_norm);
+ String sqlId = DBUtils.md5Custom(query_text_norm);
+
+ /* System.out.println(query_text);
+ System.out.println(query_text_norm);
+ System.out.println(sqlId);
+ System.out.println("");
+ */
+ String hostname = resultSetAsh.getString("client_hostname");
+ String event = resultSetAsh.getString("wait_event");
+ String waitClass = resultSetAsh.getString("wait_event_type");
+
+ if (waitClass == null) {
+ waitClass = "CPU";
+ event = "CPU";
+ }
+
+ if ((event == null) || (event.equals(""))) {
+ event = waitClass;
+ }
+
+ if (event.equals("PgSleep")&&query_text.contains("pg_stat_activity_snapshot")) {
+ continue;
+ }
+
+ Double waitClassId = 0.0;
+
+ if (waitClass.equals("CPU")) {
+ waitClassId = 0.0;
+ } else if (waitClass.equals("IO")) {
+ waitClassId = 1.0;
+ } else if (waitClass.equals("Lock")) {
+ waitClassId = 2.0;
+ } else if (waitClass.equals("LWLock")) {
+ waitClassId = 3.0;
+ } else if (waitClass.equals("BufferPin")) {
+ waitClassId = 4.0;
+ } else if (waitClass.equals("Activity")) {
+ waitClassId = 5.0;
+ } else if (waitClass.equals("Extension")) {
+ waitClassId = 6.0;
+ } else if (waitClass.equals("Client")) {
+ waitClassId = 7.0;
+ } else if (waitClass.equals("IPC")) {
+ waitClassId = 8.0;
+ } else if (waitClass.equals("Timeout")) {
+ waitClassId = 9.0;
+ }
+
+ // Create row for wait event
+ try {
+ dao.ashById.putNoOverwrite(new AshIdTime(valueSampleIdTimeLongWait, valueSampleIdTimeLongWait.doubleValue()));
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+
+ // Load data for active session history (wait event)
+ try {
+ dao.activeSessionHistoryById
+ .putNoReturn(new ActiveSessionHistory(
+ activeSessionHistoryIdWait,
+ valueSampleIdTimeLongWait,
+ sessionId, backendType, userId, userName, sqlId, command_type,
+ event, waitClass, waitClassId, program, hostname, queryStartLong, duration));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ // dcvetkov: Load data for sqlid: command type and query text
+ try {
+ dao.ashSqlIdTypeTextId.putNoReturn(new AshSqlIdTypeText(sqlId, command_type, query_text_norm));
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+ }
+ if (conn != null) {
+ model.getConnectionPool().free(conn);
+ }
+ } else {
+ // Connect is lost
+ setReconnect(true);
+ model.closeConnectionPool();
+ model.connectionPoolInitReconnect();
+ }
+
+ } catch (SQLException e) {
+ System.out.println("SQL Exception occured: " + e.getMessage());
+ model.closeConnectionPool();
+ } finally {
+ if (resultSetAsh != null) {
+ try {
+ resultSetAsh.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ if (statement != null) {
+ try {
+ statement.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+
+}
diff --git a/src/org/ash/database/ASHDatabasePG12ASH.java b/src/org/ash/database/ASHDatabasePG12ASH.java
new file mode 100644
index 0000000..4ffe2ff
--- /dev/null
+++ b/src/org/ash/database/ASHDatabasePG12ASH.java
@@ -0,0 +1,620 @@
+/*
+ *-------------------
+ * The ASHDatabasePG12ASH.java is part of ASH Viewer
+ *-------------------
+ *
+ * ASH Viewer is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * ASH Viewer 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with ASH Viewer. If not, see .
+ *
+ * Copyright (c) 2009, Alex Kardapolov, All rights reserved.
+ *
+ */
+package org.ash.database;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.math.BigInteger;
+
+import org.ash.conn.model.Model;
+import org.ash.datamodel.ActiveSessionHistory;
+import org.ash.datamodel.AshIdTime;
+import org.ash.datamodel.AshSqlIdTypeText;
+import org.ash.datatemp.SessionsTemp;
+import org.ash.datatemp.SqlsTemp;
+import org.ash.util.Utils;
+import org.ash.database.DBUtils;
+import org.jdesktop.swingx.treetable.TreeTableModel;
+import org.jfree.data.xy.CategoryTableXYDataset;
+
+import com.sleepycat.je.DatabaseException;
+import com.sleepycat.je.Sequence;
+import com.sleepycat.persist.EntityCursor;
+import com.sleepycat.persist.EntityStore;
+
+// dcvetkov import
+import org.ash.util.Options;
+
+/**
+ * The Class ASHDatabasePG12ASH.
+ */
+public class ASHDatabasePG12ASH extends ASHDatabase {
+
+ /**
+ * The model.
+ */
+ private Model model;
+
+ /**
+ * The sequence.
+ */
+ private Sequence seq;
+
+ /**
+ * The BDB store.
+ */
+ private EntityStore store;
+
+ /**
+ * The BDB dao.
+ */
+ private AshDataAccessor dao;
+
+ /**
+ * The range for sqls and sessions temp (gantt)
+ */
+ private int rangeHalf = 7500;
+
+ /**
+ * The query ash.
+ */
+ private String queryASH = "SELECT ash_time, "
+ + "datname, pid, usesysid, usename, "
+ + "application_name, backend_type, "
+ + "coalesce(client_hostname, client_addr::text, 'localhost') as client_hostname, "
+ + "wait_event_type, wait_event, query, queryid, "
+ + "coalesce(query_start, xact_start, backend_start) as query_start, 1000 * EXTRACT(EPOCH FROM (ash_time - coalesce(query_start, xact_start, backend_start))) as duration "
+ + "from pg_active_session_history "
+ + "where state='active' and pid != pg_backend_pid()";
+
+ private String fileSeparator = System.getProperty("file.separator");
+ private String planDir = Options.getInstance().getPlanDir();
+
+
+ private java.sql.Timestamp PGDateLastSampleTime;
+ /**
+ * The k for sample_id after reconnect
+ */
+ private long kReconnect = 0;
+
+ /**
+ * Is reconnect
+ */
+ private boolean isReconnect = false;
+
+ /**
+ * Instantiates a new PG12 Database
+ *
+ * @param model0 the model0
+ */
+ public ASHDatabasePG12ASH(Model model0) {
+ super(model0);
+ this.model = model0;
+ this.store = super.getStore();
+ this.dao = super.getDao();
+ }
+
+ /* (non-Javadoc)
+ * @see org.ash.database.DatabaseMain#loadToLocalBDB()
+ */
+ public void loadToLocalBDB() {
+
+ // Get max value of ash
+ super.initializeVarsOnLoad();
+
+ // Load data to activeSessionHistoryById
+ loadAshDataToLocal();
+
+
+
+ super.loadToSubByEventAnd10Sec();
+ }
+
+ /* (non-Javadoc)
+ * @see org.ash.database.DatabaseMain#loadToLocalBDBCollector()
+ */
+ public synchronized void loadToLocalBDBCollector() {
+ // Get max value of ash
+ // it does: sampleId = dao.ashById.sortedMap().lastKey();
+ super.initializeVarsAfterLoad9i();
+
+ // Load data to activeSessionHistoryById
+ loadAshDataToLocal();
+ super.loadToSubByEventAnd10Sec();
+ }
+
+ /* (non-Javadoc)
+ * @see org.ash.database.DatabaseMain#loadDataToChartPanelDataSet(org.jfree.data.xy.CategoryTableXYDataset)
+ */
+ public void loadDataToChartPanelDataSet(CategoryTableXYDataset _dataset) {
+ super.loadDataToChartPanelDataSet(_dataset);
+ }
+
+ /* (non-Javadoc)
+ * @see org.ash.database.DatabaseMain#updateDataToChartPanelDataSet()
+ */
+ public void updateDataToChartPanelDataSet() {
+ super.updateDataToChartPanelDataSet();
+ }
+
+ /**
+ * Load ash data to local.
+ */
+ private void loadAshDataToLocal() {
+
+ ResultSet resultSetAsh = null;
+ PreparedStatement statement = null;
+ Connection conn = null;
+
+ // Get sequence activeSessionHistoryId
+ try {
+ seq = store.getSequence("activeSessionHistoryId");
+ } catch (DatabaseException e) {
+ // e.printStackTrace();
+ }
+
+ try {
+
+ if (model.getConnectionPool() != null) {
+
+ String connDBName = getParameter("ASH.db");
+ int explainFreq = Options.getInstance().getExplainFreq();
+
+ conn = this.model.getConnectionPool().getConnection();
+
+ if (PGDateLastSampleTime == null) {
+ statement = conn.prepareStatement(queryASH);
+ } else {
+ statement = conn.prepareStatement(queryASH + " and ash_time > ?");
+ statement.setTimestamp(1, PGDateLastSampleTime);
+ }
+
+ // set ArraySize for current statement to improve performance
+ statement.setFetchSize(5000);
+ // set Timeout to 1 second
+ statement.setQueryTimeout(1);
+
+ resultSetAsh = statement.executeQuery();
+
+ while (resultSetAsh.next()) {
+
+ long activeSessionHistoryIdWait = 0;
+ try {
+ activeSessionHistoryIdWait = seq.get(null, 1);
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+
+ // Calculate sample time
+ java.sql.Timestamp PGDateSampleTime = resultSetAsh.getTimestamp("ash_time");
+ Long valueSampleIdTimeLongWait = (new Long(PGDateSampleTime.getTime()));
+
+ if (PGDateLastSampleTime == null) {
+ PGDateLastSampleTime = PGDateSampleTime;
+ } else if(PGDateSampleTime.after(PGDateLastSampleTime)) {
+ PGDateLastSampleTime = PGDateSampleTime;
+ }
+
+ java.sql.Timestamp queryStartTS = resultSetAsh.getTimestamp("query_start");
+ Long queryStartLong = 0L;
+ if (queryStartTS != null) {
+ queryStartLong = (new Long(queryStartTS.getTime()));
+ }
+
+ Double duration = resultSetAsh.getDouble("duration");
+
+ Long sessionId = resultSetAsh.getLong("pid");
+ String backendType = resultSetAsh.getString("backend_type");
+
+ String databaseName = resultSetAsh.getString("datname");
+
+ Long userId = resultSetAsh.getLong("usesysid");
+ String userName = resultSetAsh.getString("usename");
+
+ String program = resultSetAsh.getString("application_name");
+
+ String query_text = resultSetAsh.getString("query");
+ if ((query_text == null) || (query_text.equals(""))) {
+ if(program != null && program.equals("pg_basebackup")) {
+ query_text = "backup";
+ } else if (program != null && (program.equals("walreceiver") || program.equals("walsender"))) {
+ query_text = "wal";
+ } else if(backendType != null && (backendType.equals("walreceiver") || backendType.equals("walsender"))) {
+ query_text = "wal";
+ } else if(backendType != null && (backendType.equals("autovacuum worker"))) {
+ query_text = "autovacuum";
+ } else {
+ query_text = "empty";
+ }
+ }
+
+ String query_text_norm = DBUtils.NormalizeSQL(query_text);
+ String command_type = DBUtils.GetSQLCommandType(query_text_norm);
+ Long queryid = resultSetAsh.getLong("queryid");
+ String sqlId = queryid.toString();
+
+ /* System.out.println(query_text);
+ System.out.println(query_text_norm);
+ System.out.println(sqlId);
+ System.out.println("");
+ */
+ String hostname = resultSetAsh.getString("client_hostname");
+ String event = resultSetAsh.getString("wait_event");
+ String waitClass = resultSetAsh.getString("wait_event_type");
+
+ if ((waitClass == null) || (waitClass.equals(""))) {
+ waitClass = "CPU";
+ event = "CPU";
+ }
+
+ if ((event == null) || (event.equals(""))) {
+ event = waitClass;
+ }
+
+ if (event.equals("PgSleep")&&query_text.contains("pg_stat_activity_snapshot")) {
+ continue;
+ }
+
+ Double waitClassId = 0.0;
+
+ if (waitClass.equals("CPU")) {
+ waitClassId = 0.0;
+ } else if (waitClass.equals("IO")) {
+ waitClassId = 1.0;
+ } else if (waitClass.equals("Lock")) {
+ waitClassId = 2.0;
+ } else if (waitClass.equals("LWLock")) {
+ waitClassId = 3.0;
+ } else if (waitClass.equals("BufferPin")) {
+ waitClassId = 4.0;
+ } else if (waitClass.equals("Activity")) {
+ waitClassId = 5.0;
+ } else if (waitClass.equals("Extension")) {
+ waitClassId = 6.0;
+ } else if (waitClass.equals("Client")) {
+ waitClassId = 7.0;
+ } else if (waitClass.equals("IPC")) {
+ waitClassId = 8.0;
+ } else if (waitClass.equals("Timeout")) {
+ waitClassId = 9.0;
+ }
+
+ // Create row for wait event
+ try {
+ dao.ashById.putNoOverwrite(new AshIdTime(valueSampleIdTimeLongWait, valueSampleIdTimeLongWait.doubleValue()));
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+
+ // Load data for active session history (wait event)
+ try {
+ dao.activeSessionHistoryById
+ .putNoReturn(new ActiveSessionHistory(
+ activeSessionHistoryIdWait,
+ valueSampleIdTimeLongWait,
+ sessionId, backendType, userId, userName, sqlId, command_type,
+ event, waitClass, waitClassId, program, hostname, queryStartLong, duration));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ // dcvetkov: Load data for sqlid: command type and query text
+ try {
+ dao.ashSqlIdTypeTextId.putNoReturn(new AshSqlIdTypeText(sqlId, command_type, query_text_norm));
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+
+ // dcvetkov: explain plan
+ if (command_type.equals("SELECT") || command_type.equals("UPDATE") || command_type.equals("DELETE") || command_type.equals("INSERT")) {
+ if ((connDBName.length() > 0) && (explainFreq > 0)) {
+ DBUtils.explainPlan(sqlId, query_text, command_type, planDir, fileSeparator, connDBName, databaseName, conn, explainFreq);
+ }
+ }
+
+ }
+ if (conn != null) {
+ model.getConnectionPool().free(conn);
+ }
+ } else {
+ // Connect is lost
+ setReconnect(true);
+ model.closeConnectionPool();
+ model.connectionPoolInitReconnect();
+ }
+
+ } catch (SQLException e) {
+ System.out.println("SQL Exception occured: " + e.getMessage());
+ model.closeConnectionPool();
+ } finally {
+ if (resultSetAsh != null) {
+ try {
+ resultSetAsh.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ if (statement != null) {
+ try {
+ statement.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#calculateSqlsSessionsData(double,
+ * double)
+ */
+ public void calculateSqlsSessionsData(double beginTime, double endTime, String eventFlag) {
+
+ try {
+
+ SqlsTemp tmpSqlsTemp = null;
+ SessionsTemp tmpSessionsTemp = null;
+
+ if (eventFlag.equalsIgnoreCase("All")) {
+ tmpSqlsTemp = super.getSqlsTemp();
+ tmpSessionsTemp = super.getSessionsTemp();
+ } else {
+ tmpSqlsTemp = super.getSqlsTempDetail();
+ tmpSessionsTemp = super.getSessionsTempDetail();
+ }
+
+ // get sample id's for beginTime and endTime
+ EntityCursor ashSampleIds;
+ ashSampleIds = dao.doRangeQuery(dao.ashBySampleTime, beginTime - rangeHalf, true, endTime + rangeHalf, true);
+ /* Iterate on Ash by SampleTime. */
+ Iterator ashIter = ashSampleIds.iterator();
+
+ while (ashIter.hasNext()) {
+
+ AshIdTime ashSumMain = ashIter.next();
+
+ // get rows from ActiveSessionHistory for samplId
+ EntityCursor ActiveSessionHistoryCursor;
+ ActiveSessionHistoryCursor = dao.doRangeQuery(dao.activeSessionHistoryByAshId, ashSumMain.getsampleId(), true, ashSumMain.getsampleId(), true);
+ Iterator ActiveSessionHistoryIter = ActiveSessionHistoryCursor.iterator();
+
+ while (ActiveSessionHistoryIter.hasNext()) {
+ ActiveSessionHistory ASH = ActiveSessionHistoryIter.next();
+
+ // sql data
+ String sqlId = ASH.getSqlId();
+ double waitClassId = ASH.getWaitClassId();
+ // session data
+ Long sessionId = (Long) ASH.getSessionId();
+ String sessionidS = sessionId.toString().trim();
+ Long useridL = (Long) ASH.getUserId();
+ String usernameSess = ASH.getUserName();
+ String programSess = ASH.getProgram();
+ programSess = programSess + "@" + ASH.getHostname();
+ String backendSess = ASH.getBackendType();
+ String waitClass = ASH.getWaitClass();
+ String eventName = ASH.getEvent();
+
+ Long queryStart = ASH.getQueryStart();
+ Double duration = ASH.getDuration();
+
+ // Exit when current eventClas != eventFlag
+ if (!eventFlag.equalsIgnoreCase("All")) {
+ if (waitClass != null && waitClass.equalsIgnoreCase(eventFlag)) {
+ this.loadDataToTempSqlSession(tmpSqlsTemp,
+ tmpSessionsTemp, sqlId, waitClassId,
+ sessionId, sessionidS, 0.0, backendSess,
+ useridL, usernameSess, programSess, true, eventName, queryStart, duration);
+ }
+
+ } else {
+ this.loadDataToTempSqlSession(tmpSqlsTemp,
+ tmpSessionsTemp, sqlId, waitClassId,
+ sessionId, sessionidS, 0.0, backendSess,
+ useridL, usernameSess, programSess, false, eventFlag, queryStart, duration);
+ }
+ }
+ // Close cursor!!
+ ActiveSessionHistoryCursor.close();
+ }
+ tmpSqlsTemp.set_sum();
+ tmpSessionsTemp.set_sum();
+
+ // Close cursor!!
+ ashSampleIds.close();
+
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#loadCommandTypeFromDB(java.util.List)
+ */
+ public void loadSqlTextCommandTypeFromDB(List arraySqlId) {
+
+ // Load all sqlId
+ ArrayList sqlIdAll = new ArrayList();
+
+ Iterator arraySqlIdIter = arraySqlId.iterator();
+ while (arraySqlIdIter.hasNext()) {
+ String sqlId = arraySqlIdIter.next();
+ if (!isSqlTextExist(sqlId)) {
+ sqlIdAll.add(sqlId);
+ }
+ }
+
+ this.loadSqlTextSqlIdFromDB(sqlIdAll);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#isSqlPlanHashValueExist(java.lang.String)
+ */
+ public boolean isSqlTextExist(String sqlId) {
+ boolean res = false;
+ try {
+ res = dao.getAshSqlIdTypeTextId().contains(sqlId);
+ } catch (DatabaseException e) {
+ res = false;
+ }
+
+ return res;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#getSqlType(java.lang.String)
+ */
+ public String getSqlType(String sqlId) {
+ String sqlType = null;
+ try {
+ AshSqlIdTypeText ash = dao.ashSqlIdTypeTextId.get(sqlId);
+ if (ash != null) {
+ sqlType = ash.getCommandType();
+ } else {
+ sqlType = "";
+ }
+ } catch (DatabaseException e) {
+ sqlType = "";
+ e.printStackTrace();
+ }
+ return sqlType;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#getSqlText(java.lang.String)
+ */
+ public String getSqlText(String sqlId) {
+ String sqlText = null;
+ try {
+ AshSqlIdTypeText ash = dao.ashSqlIdTypeTextId.get(sqlId);
+ if (ash != null) {
+ sqlText = ash.getSqlText();
+ } else {
+ sqlText = "";
+ }
+
+ } catch (DatabaseException e) {
+ sqlText = "";
+ e.printStackTrace();
+ }
+ return sqlText;
+ }
+
+ /**
+ * Load data to temporary sql and sessions (gantt data)
+ *
+ * @param tmpSqlsTemp
+ * @param tmpSessionsTemp
+ * @param sqlId
+ * @param waitClassId
+ * @param sessionId
+ * @param sessionidS
+ * @param sessionSerial
+ * @param sessioniSerialS
+ * @param useridL
+ * @param programSess
+ * @param isDetail
+ * @param sqlPlanHashValue
+ */
+ private void loadDataToTempSqlSession(SqlsTemp tmpSqlsTemp,
+ SessionsTemp tmpSessionsTemp, String sqlId, double waitClassId, Long sessionId,
+ String sessionidS, Double sessionSerial, String backendType,
+ Long useridL, String usernameSess, String programSess, boolean isDetail,
+ String eventDetail, Long queryStart, Double duration) {
+
+ int count = 1;
+
+ /**
+ * Save data for sql row
+ */
+ if (sqlId != null) {
+ // Save SQL_ID and init
+ tmpSqlsTemp.setSqlId(sqlId);
+ // Save group event
+ tmpSqlsTemp.setTimeOfGroupEvent(sqlId, waitClassId, count);
+ tmpSqlsTemp.setSqlStats(sqlId, sessionId, queryStart, duration);
+ }
+
+ /**
+ * Save data for session row
+ */
+ tmpSessionsTemp.setSessionId(sessionidS, backendType, programSess, "", usernameSess);
+ tmpSessionsTemp.setTimeOfGroupEvent(sessionidS, waitClassId, count);
+
+ /**
+ * Save event detail data for sql and sessions row
+ */
+ if (isDetail) {
+ if (sqlId != null) {
+ tmpSqlsTemp.setTimeOfEventName(sqlId, waitClassId, eventDetail, count);
+ }
+ tmpSessionsTemp.setTimeOfEventName(sessionidS, waitClassId, eventDetail, count);
+ }
+ }
+
+ /**
+ * @return the kReconnect
+ */
+ private long getKReconnect() {
+ return kReconnect;
+ }
+
+ /**
+ * @param reconnect the kReconnect to set
+ */
+ private void setKReconnect(long reconnect) {
+ kReconnect = reconnect;
+ }
+
+ /**
+ * @return the isReconnect
+ */
+ private boolean isReconnect() {
+ return isReconnect;
+ }
+
+ /**
+ * @param isReconnect the isReconnect to set
+ */
+ private void setReconnect(boolean isReconnect) {
+ this.isReconnect = isReconnect;
+ }
+
+}
diff --git a/src/org/ash/database/ASHDatabasePG13.java b/src/org/ash/database/ASHDatabasePG13.java
new file mode 100644
index 0000000..39839e4
--- /dev/null
+++ b/src/org/ash/database/ASHDatabasePG13.java
@@ -0,0 +1,805 @@
+/*
+ *-------------------
+ * The ASHDatabasePG13.java is part of ASH Viewer
+ *-------------------
+ *
+ * ASH Viewer is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * ASH Viewer 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with ASH Viewer. If not, see .
+ *
+ * Copyright (c) 2009, Alex Kardapolov, All rights reserved.
+ *
+ */
+package org.ash.database;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.math.BigInteger;
+
+import org.ash.conn.model.Model;
+import org.ash.datamodel.ActiveSessionHistory;
+import org.ash.datamodel.AshIdTime;
+import org.ash.datamodel.AshSqlIdTypeText;
+import org.ash.datatemp.SessionsTemp;
+import org.ash.datatemp.SqlsTemp;
+import org.ash.util.Utils;
+import org.ash.database.DBUtils;
+import org.jdesktop.swingx.treetable.TreeTableModel;
+import org.jfree.data.xy.CategoryTableXYDataset;
+
+import com.sleepycat.je.DatabaseException;
+import com.sleepycat.je.Sequence;
+import com.sleepycat.persist.EntityCursor;
+import com.sleepycat.persist.EntityStore;
+
+// dcvetkov import
+import org.ash.util.Options;
+
+/**
+ * The Class ASHDatabasePG13.
+ */
+public class ASHDatabasePG13 extends ASHDatabase {
+
+ /**
+ * The model.
+ */
+ private Model model;
+
+ /**
+ * The sequence.
+ */
+ private Sequence seq;
+
+ /**
+ * The BDB store.
+ */
+ private EntityStore store;
+
+ /**
+ * The BDB dao.
+ */
+ private AshDataAccessor dao;
+
+ /**
+ * The range for sqls and sessions temp (gantt)
+ */
+ private int rangeHalf = 7500;
+
+ /**
+ * The query ash.
+ */
+ private String queryASH = "SELECT current_timestamp, "
+ + "datname, pid, usesysid, usename, "
+ + "application_name, backend_type, "
+ + "coalesce(client_hostname, client_addr::text, 'localhost') as client_hostname, "
+ + "wait_event_type, wait_event, query, "
+ + "coalesce(query_start, xact_start, backend_start) as query_start, 1000 * EXTRACT(EPOCH FROM (clock_timestamp()-coalesce(query_start, xact_start, backend_start))) as duration "
+ + "from pg_stat_activity "
+ + "where state='active' and pid != pg_backend_pid()";
+
+ private String fileSeparator = System.getProperty("file.separator");
+ private String planDir = Options.getInstance().getPlanDir();
+
+
+
+ /**
+ * The k for sample_id after reconnect
+ */
+ private long kReconnect = 0;
+
+ /**
+ * Is reconnect
+ */
+ private boolean isReconnect = false;
+
+ /**
+ * Instantiates a new PG12 Database
+ *
+ * @param model0 the model0
+ */
+ public ASHDatabasePG13(Model model0) {
+ super(model0);
+ this.model = model0;
+ this.store = super.getStore();
+ this.dao = super.getDao();
+ }
+
+ /* (non-Javadoc)
+ * @see org.ash.database.DatabaseMain#loadToLocalBDB()
+ */
+ public void loadToLocalBDB() {
+
+ // Get max value of ash
+ super.initializeVarsOnLoad();
+
+ // Load data to activeSessionHistoryById
+ loadHistAshDataToLocal();
+
+ // dcvetkov
+ // super.loadToSubByEventAnd10Sec();
+ super.loadToSubByEventAnd10Sec_all_history_at_start();
+ }
+
+ /* (non-Javadoc)
+ * @see org.ash.database.DatabaseMain#loadToLocalBDBCollector()
+ */
+ public synchronized void loadToLocalBDBCollector() {
+ // Get max value of ash
+ // it does: sampleId = dao.ashById.sortedMap().lastKey();
+ super.initializeVarsAfterLoad9i();
+
+ // Load data to activeSessionHistoryById
+ loadAshDataToLocal();
+
+ }
+
+ /* (non-Javadoc)
+ * @see org.ash.database.DatabaseMain#loadDataToChartPanelDataSet(org.jfree.data.xy.CategoryTableXYDataset)
+ */
+ public void loadDataToChartPanelDataSet(CategoryTableXYDataset _dataset) {
+ super.loadDataToChartPanelDataSet(_dataset);
+ }
+
+ /* (non-Javadoc)
+ * @see org.ash.database.DatabaseMain#updateDataToChartPanelDataSet()
+ */
+ public void updateDataToChartPanelDataSet() {
+ super.updateDataToChartPanelDataSet();
+ }
+
+ /**
+ * Load ash data to local.
+ */
+ private void loadAshDataToLocal() {
+
+ ResultSet resultSetAsh = null;
+ PreparedStatement statement = null;
+ Connection conn = null;
+
+ // Get sequence activeSessionHistoryId
+ try {
+ seq = store.getSequence("activeSessionHistoryId");
+ } catch (DatabaseException e) {
+ // e.printStackTrace();
+ }
+
+ try {
+
+ if (model.getConnectionPool() != null) {
+
+ String connDBName = getParameter("ASH.db");
+ int explainFreq = Options.getInstance().getExplainFreq();
+
+ conn = this.model.getConnectionPool().getConnection();
+
+ statement = conn.prepareStatement(this.queryASH);
+
+
+
+
+
+
+ // set ArraySize for current statement to improve performance
+ statement.setFetchSize(5000);
+ // set Timeout to 1 second
+ statement.setQueryTimeout(1);
+
+ resultSetAsh = statement.executeQuery();
+
+ while (resultSetAsh.next()) {
+
+ long activeSessionHistoryIdWait = 0;
+ try {
+ activeSessionHistoryIdWait = seq.get(null, 1);
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+
+ // Calculate sample time
+ java.sql.Timestamp PGDateSampleTime = resultSetAsh.getTimestamp("current_timestamp");
+ Long valueSampleIdTimeLongWait = (new Long(PGDateSampleTime.getTime()));
+
+
+
+
+
+
+
+ java.sql.Timestamp queryStartTS = resultSetAsh.getTimestamp("query_start");
+ Long queryStartLong = 0L;
+ if (queryStartTS != null) {
+ queryStartLong = (new Long(queryStartTS.getTime()));
+ }
+
+ Double duration = resultSetAsh.getDouble("duration");
+
+ Long sessionId = resultSetAsh.getLong("pid");
+ String backendType = resultSetAsh.getString("backend_type");
+
+ String databaseName = resultSetAsh.getString("datname");
+
+ Long userId = resultSetAsh.getLong("usesysid");
+ String userName = resultSetAsh.getString("usename");
+
+ String program = resultSetAsh.getString("application_name");
+
+ String query_text = resultSetAsh.getString("query");
+ if ((query_text == null) || (query_text.equals(""))) {
+ if(program != null && program.equals("pg_basebackup")) {
+ query_text = "backup";
+ } else if (program != null && (program.equals("walreceiver") || program.equals("walsender"))) {
+ query_text = "wal";
+ } else if(backendType != null && (backendType.equals("walreceiver") || backendType.equals("walsender"))) {
+ query_text = "wal";
+ } else {
+ query_text = "empty";
+ }
+ }
+
+ String query_text_norm = DBUtils.NormalizeSQL(query_text);
+ String command_type = DBUtils.GetSQLCommandType(query_text_norm);
+ String sqlId = DBUtils.md5Custom(query_text_norm);
+
+ /* System.out.println(query_text);
+ System.out.println(query_text_norm);
+ System.out.println(sqlId);
+ System.out.println("");
+ */
+ String hostname = resultSetAsh.getString("client_hostname");
+ String event = resultSetAsh.getString("wait_event");
+ String waitClass = resultSetAsh.getString("wait_event_type");
+
+ if ((waitClass == null) || (waitClass.equals(""))) {
+ waitClass = "CPU";
+ event = "CPU";
+ }
+
+ if ((event == null) || (event.equals(""))) {
+ event = waitClass;
+ }
+
+ if (event.equals("PgSleep")&&query_text.contains("pg_stat_activity_snapshot")) {
+ continue;
+ }
+
+ Double waitClassId = 0.0;
+
+ if (waitClass.equals("CPU")) {
+ waitClassId = 0.0;
+ } else if (waitClass.equals("IO")) {
+ waitClassId = 1.0;
+ } else if (waitClass.equals("Lock")) {
+ waitClassId = 2.0;
+ } else if (waitClass.equals("LWLock")) {
+ waitClassId = 3.0;
+ } else if (waitClass.equals("BufferPin")) {
+ waitClassId = 4.0;
+ } else if (waitClass.equals("Activity")) {
+ waitClassId = 5.0;
+ } else if (waitClass.equals("Extension")) {
+ waitClassId = 6.0;
+ } else if (waitClass.equals("Client")) {
+ waitClassId = 7.0;
+ } else if (waitClass.equals("IPC")) {
+ waitClassId = 8.0;
+ } else if (waitClass.equals("Timeout")) {
+ waitClassId = 9.0;
+ }
+
+ // Create row for wait event
+ try {
+ dao.ashById.putNoOverwrite(new AshIdTime(valueSampleIdTimeLongWait, valueSampleIdTimeLongWait.doubleValue()));
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+
+ // Load data for active session history (wait event)
+ try {
+ dao.activeSessionHistoryById
+ .putNoReturn(new ActiveSessionHistory(
+ activeSessionHistoryIdWait,
+ valueSampleIdTimeLongWait,
+ sessionId, backendType, userId, userName, sqlId, command_type,
+ event, waitClass, waitClassId, program, hostname, queryStartLong, duration));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ // dcvetkov: Load data for sqlid: command type and query text
+ try {
+ dao.ashSqlIdTypeTextId.putNoReturn(new AshSqlIdTypeText(sqlId, command_type, query_text_norm));
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+
+ // dcvetkov: explain plan
+ if (command_type.equals("SELECT") || command_type.equals("UPDATE") || command_type.equals("DELETE") || command_type.equals("INSERT")) {
+ if ((connDBName.length() > 0) && (explainFreq > 0)) {
+ DBUtils.explainPlan(sqlId, query_text, command_type, planDir, fileSeparator, connDBName, databaseName, conn, explainFreq);
+ // DBUtils.FindQueryID(sqlId, query_text_norm, conn);
+ }
+ }
+
+ }
+ if (conn != null) {
+ model.getConnectionPool().free(conn);
+ }
+ } else {
+ // Connect is lost
+ setReconnect(true);
+ model.closeConnectionPool();
+ model.connectionPoolInitReconnect();
+ }
+
+ } catch (SQLException e) {
+ System.out.println("SQL Exception occured: " + e.getMessage());
+ model.closeConnectionPool();
+ } finally {
+ if (resultSetAsh != null) {
+ try {
+ resultSetAsh.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ if (statement != null) {
+ try {
+ statement.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#calculateSqlsSessionsData(double,
+ * double)
+ */
+ public void calculateSqlsSessionsData(double beginTime, double endTime, String eventFlag) {
+
+ try {
+
+ SqlsTemp tmpSqlsTemp = null;
+ SessionsTemp tmpSessionsTemp = null;
+
+ if (eventFlag.equalsIgnoreCase("All")) {
+ tmpSqlsTemp = super.getSqlsTemp();
+ tmpSessionsTemp = super.getSessionsTemp();
+ } else {
+ tmpSqlsTemp = super.getSqlsTempDetail();
+ tmpSessionsTemp = super.getSessionsTempDetail();
+ }
+
+ // get sample id's for beginTime and endTime
+ EntityCursor ashSampleIds;
+ ashSampleIds = dao.doRangeQuery(dao.ashBySampleTime, beginTime - rangeHalf, true, endTime + rangeHalf, true);
+ /* Iterate on Ash by SampleTime. */
+ Iterator ashIter = ashSampleIds.iterator();
+
+ while (ashIter.hasNext()) {
+
+ AshIdTime ashSumMain = ashIter.next();
+
+ // get rows from ActiveSessionHistory for samplId
+ EntityCursor ActiveSessionHistoryCursor;
+ ActiveSessionHistoryCursor = dao.doRangeQuery(dao.activeSessionHistoryByAshId, ashSumMain.getsampleId(), true, ashSumMain.getsampleId(), true);
+ Iterator ActiveSessionHistoryIter = ActiveSessionHistoryCursor.iterator();
+
+ while (ActiveSessionHistoryIter.hasNext()) {
+ ActiveSessionHistory ASH = ActiveSessionHistoryIter.next();
+
+ // sql data
+ String sqlId = ASH.getSqlId();
+ double waitClassId = ASH.getWaitClassId();
+ // session data
+ Long sessionId = (Long) ASH.getSessionId();
+ String sessionidS = sessionId.toString().trim();
+ Long useridL = (Long) ASH.getUserId();
+ String usernameSess = ASH.getUserName();
+ String programSess = ASH.getProgram();
+ programSess = programSess + "@" + ASH.getHostname();
+ String backendSess = ASH.getBackendType();
+ String waitClass = ASH.getWaitClass();
+ String eventName = ASH.getEvent();
+
+ Long queryStart = ASH.getQueryStart();
+ Double duration = ASH.getDuration();
+
+ // Exit when current eventClas != eventFlag
+ if (!eventFlag.equalsIgnoreCase("All")) {
+ if (waitClass != null && waitClass.equalsIgnoreCase(eventFlag)) {
+ this.loadDataToTempSqlSession(tmpSqlsTemp,
+ tmpSessionsTemp, sqlId, waitClassId,
+ sessionId, sessionidS, 0.0, backendSess,
+ useridL, usernameSess, programSess, true, eventName, queryStart, duration);
+ }
+
+ } else {
+ this.loadDataToTempSqlSession(tmpSqlsTemp,
+ tmpSessionsTemp, sqlId, waitClassId,
+ sessionId, sessionidS, 0.0, backendSess,
+ useridL, usernameSess, programSess, false, eventFlag, queryStart, duration);
+ }
+ }
+ // Close cursor!!
+ ActiveSessionHistoryCursor.close();
+ }
+ tmpSqlsTemp.set_sum();
+ tmpSessionsTemp.set_sum();
+
+ // Close cursor!!
+ ashSampleIds.close();
+
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#loadCommandTypeFromDB(java.util.List)
+ */
+ public void loadSqlTextCommandTypeFromDB(List arraySqlId) {
+
+ // Load all sqlId
+ ArrayList sqlIdAll = new ArrayList();
+
+ Iterator arraySqlIdIter = arraySqlId.iterator();
+ while (arraySqlIdIter.hasNext()) {
+ String sqlId = arraySqlIdIter.next();
+ if (!isSqlTextExist(sqlId)) {
+ sqlIdAll.add(sqlId);
+ }
+ }
+
+ this.loadSqlTextSqlIdFromDB(sqlIdAll);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#isSqlPlanHashValueExist(java.lang.String)
+ */
+ public boolean isSqlTextExist(String sqlId) {
+ boolean res = false;
+ try {
+ res = dao.getAshSqlIdTypeTextId().contains(sqlId);
+ } catch (DatabaseException e) {
+ res = false;
+ }
+
+ return res;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#getSqlType(java.lang.String)
+ */
+ public String getSqlType(String sqlId) {
+ String sqlType = null;
+ try {
+ AshSqlIdTypeText ash = dao.ashSqlIdTypeTextId.get(sqlId);
+ if (ash != null) {
+ sqlType = ash.getCommandType();
+ } else {
+ sqlType = "";
+ }
+ } catch (DatabaseException e) {
+ sqlType = "";
+ e.printStackTrace();
+ }
+ return sqlType;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#getSqlText(java.lang.String)
+ */
+ public String getSqlText(String sqlId) {
+ String sqlText = null;
+ try {
+ AshSqlIdTypeText ash = dao.ashSqlIdTypeTextId.get(sqlId);
+ if (ash != null) {
+ sqlText = ash.getSqlText();
+ } else {
+ sqlText = "";
+ }
+
+ } catch (DatabaseException e) {
+ sqlText = "";
+ e.printStackTrace();
+ }
+ return sqlText;
+ }
+
+ /**
+ * Load data to temporary sql and sessions (gantt data)
+ *
+ * @param tmpSqlsTemp
+ * @param tmpSessionsTemp
+ * @param sqlId
+ * @param waitClassId
+ * @param sessionId
+ * @param sessionidS
+ * @param sessionSerial
+ * @param sessioniSerialS
+ * @param useridL
+ * @param programSess
+ * @param isDetail
+ * @param sqlPlanHashValue
+ */
+ private void loadDataToTempSqlSession(SqlsTemp tmpSqlsTemp,
+ SessionsTemp tmpSessionsTemp, String sqlId, double waitClassId, Long sessionId,
+ String sessionidS, Double sessionSerial, String backendType,
+ Long useridL, String usernameSess, String programSess, boolean isDetail,
+ String eventDetail, Long queryStart, Double duration) {
+
+ int count = 1;
+
+ /**
+ * Save data for sql row
+ */
+ if (sqlId != null) {
+ // Save SQL_ID and init
+ tmpSqlsTemp.setSqlId(sqlId);
+ // Save group event
+ tmpSqlsTemp.setTimeOfGroupEvent(sqlId, waitClassId, count);
+ tmpSqlsTemp.setSqlStats(sqlId, sessionId, queryStart, duration);
+ }
+
+ /**
+ * Save data for session row
+ */
+ tmpSessionsTemp.setSessionId(sessionidS, backendType, programSess, "", usernameSess);
+ tmpSessionsTemp.setTimeOfGroupEvent(sessionidS, waitClassId, count);
+
+ /**
+ * Save event detail data for sql and sessions row
+ */
+ if (isDetail) {
+ if (sqlId != null) {
+ tmpSqlsTemp.setTimeOfEventName(sqlId, waitClassId, eventDetail, count);
+ }
+ tmpSessionsTemp.setTimeOfEventName(sessionidS, waitClassId, eventDetail, count);
+ }
+ }
+
+ /**
+ * @return the kReconnect
+ */
+ private long getKReconnect() {
+ return kReconnect;
+ }
+
+ /**
+ * @param reconnect the kReconnect to set
+ */
+ private void setKReconnect(long reconnect) {
+ kReconnect = reconnect;
+ }
+
+ /**
+ * @return the isReconnect
+ */
+ private boolean isReconnect() {
+ return isReconnect;
+ }
+
+ /**
+ * @param isReconnect the isReconnect to set
+ */
+ private void setReconnect(boolean isReconnect) {
+ this.isReconnect = isReconnect;
+ }
+
+
+
+
+
+
+
+ private void loadHistAshDataToLocal() {
+
+ ResultSet resultSetAsh = null;
+ PreparedStatement statement = null;
+ Connection conn = null;
+
+ // Get sequence activeSessionHistoryId
+ try {
+ seq = store.getSequence("activeSessionHistoryId");
+ } catch (DatabaseException e) {
+ // e.printStackTrace();
+ }
+
+ try {
+
+ if (model.getConnectionPool() != null) {
+
+ conn = this.model.getConnectionPool().getConnection();
+
+ statement = conn.prepareStatement("select * from pg_stat_activity_history order by sample_time");
+
+ // set ArraySize for current statement to improve performance
+ statement.setFetchSize(5000);
+
+ try {
+ resultSetAsh = statement.executeQuery();
+ } catch (SQLException e) {
+ return;
+ }
+
+ while (resultSetAsh.next()) {
+
+ long activeSessionHistoryIdWait = 0;
+ try {
+ activeSessionHistoryIdWait = seq.get(null, 1);
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+
+ // Calculate sample time
+ java.sql.Timestamp PGDateSampleTime = resultSetAsh.getTimestamp("sample_time");
+ Long valueSampleIdTimeLongWait = (new Long(PGDateSampleTime.getTime()));
+
+ java.sql.Timestamp queryStartTS = resultSetAsh.getTimestamp("query_start");
+ Long queryStartLong = 0L;
+ if (queryStartTS != null) {
+ queryStartLong = (new Long(queryStartTS.getTime()));
+ }
+
+ Double duration = resultSetAsh.getDouble("duration");
+
+ Long sessionId = resultSetAsh.getLong("pid");
+ String backendType = resultSetAsh.getString("backend_type");
+
+ String databaseName = resultSetAsh.getString("datname");
+
+ Long userId = resultSetAsh.getLong("usesysid");
+ String userName = resultSetAsh.getString("usename");
+
+ String program = resultSetAsh.getString("application_name");
+
+ String query_text = resultSetAsh.getString("query");
+ if ((query_text == null) || (query_text.equals(""))) {
+ if (program.equals("pg_basebackup")) {
+ query_text = "backup";
+ } else if (program.equals("walreceiver") || program.equals("walsender")) {
+ query_text = "wal";
+ } else if (backendType.equals("walreceiver") || backendType.equals("walsender")) {
+ query_text = "wal";
+ } else {
+ query_text = "empty";
+ }
+ }
+ String query_text_norm = DBUtils.NormalizeSQL(query_text);
+ String command_type = DBUtils.GetSQLCommandType(query_text_norm);
+ String sqlId = DBUtils.md5Custom(query_text_norm);
+
+ /* System.out.println(query_text);
+ System.out.println(query_text_norm);
+ System.out.println(sqlId);
+ System.out.println("");
+ */
+ String hostname = resultSetAsh.getString("client_hostname");
+ String event = resultSetAsh.getString("wait_event");
+ String waitClass = resultSetAsh.getString("wait_event_type");
+
+ if (waitClass == null) {
+ waitClass = "CPU";
+ event = "CPU";
+ }
+
+ if ((event == null) || (event.equals(""))) {
+ event = waitClass;
+ }
+
+ if (event.equals("PgSleep")&&query_text.contains("pg_stat_activity_snapshot")) {
+ continue;
+ }
+
+ Double waitClassId = 0.0;
+
+ if (waitClass.equals("CPU")) {
+ waitClassId = 0.0;
+ } else if (waitClass.equals("IO")) {
+ waitClassId = 1.0;
+ } else if (waitClass.equals("Lock")) {
+ waitClassId = 2.0;
+ } else if (waitClass.equals("LWLock")) {
+ waitClassId = 3.0;
+ } else if (waitClass.equals("BufferPin")) {
+ waitClassId = 4.0;
+ } else if (waitClass.equals("Activity")) {
+ waitClassId = 5.0;
+ } else if (waitClass.equals("Extension")) {
+ waitClassId = 6.0;
+ } else if (waitClass.equals("Client")) {
+ waitClassId = 7.0;
+ } else if (waitClass.equals("IPC")) {
+ waitClassId = 8.0;
+ } else if (waitClass.equals("Timeout")) {
+ waitClassId = 9.0;
+ }
+
+ // Create row for wait event
+ try {
+ dao.ashById.putNoOverwrite(new AshIdTime(valueSampleIdTimeLongWait, valueSampleIdTimeLongWait.doubleValue()));
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+
+ // Load data for active session history (wait event)
+ try {
+ dao.activeSessionHistoryById
+ .putNoReturn(new ActiveSessionHistory(
+ activeSessionHistoryIdWait,
+ valueSampleIdTimeLongWait,
+ sessionId, backendType, userId, userName, sqlId, command_type,
+ event, waitClass, waitClassId, program, hostname, queryStartLong, duration));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ // dcvetkov: Load data for sqlid: command type and query text
+ try {
+ dao.ashSqlIdTypeTextId.putNoReturn(new AshSqlIdTypeText(sqlId, command_type, query_text_norm));
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+ }
+ if (conn != null) {
+ model.getConnectionPool().free(conn);
+ }
+ } else {
+ // Connect is lost
+ setReconnect(true);
+ model.closeConnectionPool();
+ model.connectionPoolInitReconnect();
+ }
+
+ } catch (SQLException e) {
+ System.out.println("SQL Exception occured: " + e.getMessage());
+ model.closeConnectionPool();
+ } finally {
+ if (resultSetAsh != null) {
+ try {
+ resultSetAsh.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ if (statement != null) {
+ try {
+ statement.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+
+}
diff --git a/src/org/ash/database/ASHDatabasePG13ASH.java b/src/org/ash/database/ASHDatabasePG13ASH.java
new file mode 100644
index 0000000..16925eb
--- /dev/null
+++ b/src/org/ash/database/ASHDatabasePG13ASH.java
@@ -0,0 +1,620 @@
+/*
+ *-------------------
+ * The ASHDatabasePG13ASH.java is part of ASH Viewer
+ *-------------------
+ *
+ * ASH Viewer is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * ASH Viewer 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with ASH Viewer. If not, see .
+ *
+ * Copyright (c) 2009, Alex Kardapolov, All rights reserved.
+ *
+ */
+package org.ash.database;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.math.BigInteger;
+
+import org.ash.conn.model.Model;
+import org.ash.datamodel.ActiveSessionHistory;
+import org.ash.datamodel.AshIdTime;
+import org.ash.datamodel.AshSqlIdTypeText;
+import org.ash.datatemp.SessionsTemp;
+import org.ash.datatemp.SqlsTemp;
+import org.ash.util.Utils;
+import org.ash.database.DBUtils;
+import org.jdesktop.swingx.treetable.TreeTableModel;
+import org.jfree.data.xy.CategoryTableXYDataset;
+
+import com.sleepycat.je.DatabaseException;
+import com.sleepycat.je.Sequence;
+import com.sleepycat.persist.EntityCursor;
+import com.sleepycat.persist.EntityStore;
+
+// dcvetkov import
+import org.ash.util.Options;
+
+/**
+ * The Class ASHDatabasePG13ASH.
+ */
+public class ASHDatabasePG13ASH extends ASHDatabase {
+
+ /**
+ * The model.
+ */
+ private Model model;
+
+ /**
+ * The sequence.
+ */
+ private Sequence seq;
+
+ /**
+ * The BDB store.
+ */
+ private EntityStore store;
+
+ /**
+ * The BDB dao.
+ */
+ private AshDataAccessor dao;
+
+ /**
+ * The range for sqls and sessions temp (gantt)
+ */
+ private int rangeHalf = 7500;
+
+ /**
+ * The query ash.
+ */
+ private String queryASH = "SELECT ash_time, "
+ + "datname, pid, usesysid, usename, "
+ + "application_name, backend_type, "
+ + "coalesce(client_hostname, client_addr::text, 'localhost') as client_hostname, "
+ + "wait_event_type, wait_event, query, queryid, "
+ + "coalesce(query_start, xact_start, backend_start) as query_start, 1000 * EXTRACT(EPOCH FROM (ash_time - coalesce(query_start, xact_start, backend_start))) as duration "
+ + "from pg_active_session_history "
+ + "where state='active' and pid != pg_backend_pid()";
+
+ private String fileSeparator = System.getProperty("file.separator");
+ private String planDir = Options.getInstance().getPlanDir();
+
+
+ private java.sql.Timestamp PGDateLastSampleTime;
+ /**
+ * The k for sample_id after reconnect
+ */
+ private long kReconnect = 0;
+
+ /**
+ * Is reconnect
+ */
+ private boolean isReconnect = false;
+
+ /**
+ * Instantiates a new PG12 Database
+ *
+ * @param model0 the model0
+ */
+ public ASHDatabasePG13ASH(Model model0) {
+ super(model0);
+ this.model = model0;
+ this.store = super.getStore();
+ this.dao = super.getDao();
+ }
+
+ /* (non-Javadoc)
+ * @see org.ash.database.DatabaseMain#loadToLocalBDB()
+ */
+ public void loadToLocalBDB() {
+
+ // Get max value of ash
+ super.initializeVarsOnLoad();
+
+ // Load data to activeSessionHistoryById
+ loadAshDataToLocal();
+
+
+
+ super.loadToSubByEventAnd10Sec();
+ }
+
+ /* (non-Javadoc)
+ * @see org.ash.database.DatabaseMain#loadToLocalBDBCollector()
+ */
+ public synchronized void loadToLocalBDBCollector() {
+ // Get max value of ash
+ // it does: sampleId = dao.ashById.sortedMap().lastKey();
+ super.initializeVarsAfterLoad9i();
+
+ // Load data to activeSessionHistoryById
+ loadAshDataToLocal();
+ super.loadToSubByEventAnd10Sec();
+ }
+
+ /* (non-Javadoc)
+ * @see org.ash.database.DatabaseMain#loadDataToChartPanelDataSet(org.jfree.data.xy.CategoryTableXYDataset)
+ */
+ public void loadDataToChartPanelDataSet(CategoryTableXYDataset _dataset) {
+ super.loadDataToChartPanelDataSet(_dataset);
+ }
+
+ /* (non-Javadoc)
+ * @see org.ash.database.DatabaseMain#updateDataToChartPanelDataSet()
+ */
+ public void updateDataToChartPanelDataSet() {
+ super.updateDataToChartPanelDataSet();
+ }
+
+ /**
+ * Load ash data to local.
+ */
+ private void loadAshDataToLocal() {
+
+ ResultSet resultSetAsh = null;
+ PreparedStatement statement = null;
+ Connection conn = null;
+
+ // Get sequence activeSessionHistoryId
+ try {
+ seq = store.getSequence("activeSessionHistoryId");
+ } catch (DatabaseException e) {
+ // e.printStackTrace();
+ }
+
+ try {
+
+ if (model.getConnectionPool() != null) {
+
+ String connDBName = getParameter("ASH.db");
+ int explainFreq = Options.getInstance().getExplainFreq();
+
+ conn = this.model.getConnectionPool().getConnection();
+
+ if (PGDateLastSampleTime == null) {
+ statement = conn.prepareStatement(queryASH);
+ } else {
+ statement = conn.prepareStatement(queryASH + " and ash_time > ?");
+ statement.setTimestamp(1, PGDateLastSampleTime);
+ }
+
+ // set ArraySize for current statement to improve performance
+ statement.setFetchSize(5000);
+ // set Timeout to 1 second
+ statement.setQueryTimeout(1);
+
+ resultSetAsh = statement.executeQuery();
+
+ while (resultSetAsh.next()) {
+
+ long activeSessionHistoryIdWait = 0;
+ try {
+ activeSessionHistoryIdWait = seq.get(null, 1);
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+
+ // Calculate sample time
+ java.sql.Timestamp PGDateSampleTime = resultSetAsh.getTimestamp("ash_time");
+ Long valueSampleIdTimeLongWait = (new Long(PGDateSampleTime.getTime()));
+
+ if (PGDateLastSampleTime == null) {
+ PGDateLastSampleTime = PGDateSampleTime;
+ } else if(PGDateSampleTime.after(PGDateLastSampleTime)) {
+ PGDateLastSampleTime = PGDateSampleTime;
+ }
+
+ java.sql.Timestamp queryStartTS = resultSetAsh.getTimestamp("query_start");
+ Long queryStartLong = 0L;
+ if (queryStartTS != null) {
+ queryStartLong = (new Long(queryStartTS.getTime()));
+ }
+
+ Double duration = resultSetAsh.getDouble("duration");
+
+ Long sessionId = resultSetAsh.getLong("pid");
+ String backendType = resultSetAsh.getString("backend_type");
+
+ String databaseName = resultSetAsh.getString("datname");
+
+ Long userId = resultSetAsh.getLong("usesysid");
+ String userName = resultSetAsh.getString("usename");
+
+ String program = resultSetAsh.getString("application_name");
+
+ String query_text = resultSetAsh.getString("query");
+ if ((query_text == null) || (query_text.equals(""))) {
+ if(program != null && program.equals("pg_basebackup")) {
+ query_text = "backup";
+ } else if (program != null && (program.equals("walreceiver") || program.equals("walsender"))) {
+ query_text = "wal";
+ } else if(backendType != null && (backendType.equals("walreceiver") || backendType.equals("walsender"))) {
+ query_text = "wal";
+ } else if(backendType != null && (backendType.equals("autovacuum worker"))) {
+ query_text = "autovacuum";
+ } else {
+ query_text = "empty";
+ }
+ }
+
+ String query_text_norm = DBUtils.NormalizeSQL(query_text);
+ String command_type = DBUtils.GetSQLCommandType(query_text_norm);
+ Long queryid = resultSetAsh.getLong("queryid");
+ String sqlId = queryid.toString();
+
+ /* System.out.println(query_text);
+ System.out.println(query_text_norm);
+ System.out.println(sqlId);
+ System.out.println("");
+ */
+ String hostname = resultSetAsh.getString("client_hostname");
+ String event = resultSetAsh.getString("wait_event");
+ String waitClass = resultSetAsh.getString("wait_event_type");
+
+ if ((waitClass == null) || (waitClass.equals(""))) {
+ waitClass = "CPU";
+ event = "CPU";
+ }
+
+ if ((event == null) || (event.equals(""))) {
+ event = waitClass;
+ }
+
+ if (event.equals("PgSleep")&&query_text.contains("pg_stat_activity_snapshot")) {
+ continue;
+ }
+
+ Double waitClassId = 0.0;
+
+ if (waitClass.equals("CPU")) {
+ waitClassId = 0.0;
+ } else if (waitClass.equals("IO")) {
+ waitClassId = 1.0;
+ } else if (waitClass.equals("Lock")) {
+ waitClassId = 2.0;
+ } else if (waitClass.equals("LWLock")) {
+ waitClassId = 3.0;
+ } else if (waitClass.equals("BufferPin")) {
+ waitClassId = 4.0;
+ } else if (waitClass.equals("Activity")) {
+ waitClassId = 5.0;
+ } else if (waitClass.equals("Extension")) {
+ waitClassId = 6.0;
+ } else if (waitClass.equals("Client")) {
+ waitClassId = 7.0;
+ } else if (waitClass.equals("IPC")) {
+ waitClassId = 8.0;
+ } else if (waitClass.equals("Timeout")) {
+ waitClassId = 9.0;
+ }
+
+ // Create row for wait event
+ try {
+ dao.ashById.putNoOverwrite(new AshIdTime(valueSampleIdTimeLongWait, valueSampleIdTimeLongWait.doubleValue()));
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+
+ // Load data for active session history (wait event)
+ try {
+ dao.activeSessionHistoryById
+ .putNoReturn(new ActiveSessionHistory(
+ activeSessionHistoryIdWait,
+ valueSampleIdTimeLongWait,
+ sessionId, backendType, userId, userName, sqlId, command_type,
+ event, waitClass, waitClassId, program, hostname, queryStartLong, duration));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ // dcvetkov: Load data for sqlid: command type and query text
+ try {
+ dao.ashSqlIdTypeTextId.putNoReturn(new AshSqlIdTypeText(sqlId, command_type, query_text_norm));
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+
+ // dcvetkov: explain plan
+ if (command_type.equals("SELECT") || command_type.equals("UPDATE") || command_type.equals("DELETE") || command_type.equals("INSERT")) {
+ if ((connDBName.length() > 0) && (explainFreq > 0)) {
+ DBUtils.explainPlan(sqlId, query_text, command_type, planDir, fileSeparator, connDBName, databaseName, conn, explainFreq);
+ }
+ }
+
+ }
+ if (conn != null) {
+ model.getConnectionPool().free(conn);
+ }
+ } else {
+ // Connect is lost
+ setReconnect(true);
+ model.closeConnectionPool();
+ model.connectionPoolInitReconnect();
+ }
+
+ } catch (SQLException e) {
+ System.out.println("SQL Exception occured: " + e.getMessage());
+ model.closeConnectionPool();
+ } finally {
+ if (resultSetAsh != null) {
+ try {
+ resultSetAsh.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ if (statement != null) {
+ try {
+ statement.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#calculateSqlsSessionsData(double,
+ * double)
+ */
+ public void calculateSqlsSessionsData(double beginTime, double endTime, String eventFlag) {
+
+ try {
+
+ SqlsTemp tmpSqlsTemp = null;
+ SessionsTemp tmpSessionsTemp = null;
+
+ if (eventFlag.equalsIgnoreCase("All")) {
+ tmpSqlsTemp = super.getSqlsTemp();
+ tmpSessionsTemp = super.getSessionsTemp();
+ } else {
+ tmpSqlsTemp = super.getSqlsTempDetail();
+ tmpSessionsTemp = super.getSessionsTempDetail();
+ }
+
+ // get sample id's for beginTime and endTime
+ EntityCursor ashSampleIds;
+ ashSampleIds = dao.doRangeQuery(dao.ashBySampleTime, beginTime - rangeHalf, true, endTime + rangeHalf, true);
+ /* Iterate on Ash by SampleTime. */
+ Iterator ashIter = ashSampleIds.iterator();
+
+ while (ashIter.hasNext()) {
+
+ AshIdTime ashSumMain = ashIter.next();
+
+ // get rows from ActiveSessionHistory for samplId
+ EntityCursor ActiveSessionHistoryCursor;
+ ActiveSessionHistoryCursor = dao.doRangeQuery(dao.activeSessionHistoryByAshId, ashSumMain.getsampleId(), true, ashSumMain.getsampleId(), true);
+ Iterator ActiveSessionHistoryIter = ActiveSessionHistoryCursor.iterator();
+
+ while (ActiveSessionHistoryIter.hasNext()) {
+ ActiveSessionHistory ASH = ActiveSessionHistoryIter.next();
+
+ // sql data
+ String sqlId = ASH.getSqlId();
+ double waitClassId = ASH.getWaitClassId();
+ // session data
+ Long sessionId = (Long) ASH.getSessionId();
+ String sessionidS = sessionId.toString().trim();
+ Long useridL = (Long) ASH.getUserId();
+ String usernameSess = ASH.getUserName();
+ String programSess = ASH.getProgram();
+ programSess = programSess + "@" + ASH.getHostname();
+ String backendSess = ASH.getBackendType();
+ String waitClass = ASH.getWaitClass();
+ String eventName = ASH.getEvent();
+
+ Long queryStart = ASH.getQueryStart();
+ Double duration = ASH.getDuration();
+
+ // Exit when current eventClas != eventFlag
+ if (!eventFlag.equalsIgnoreCase("All")) {
+ if (waitClass != null && waitClass.equalsIgnoreCase(eventFlag)) {
+ this.loadDataToTempSqlSession(tmpSqlsTemp,
+ tmpSessionsTemp, sqlId, waitClassId,
+ sessionId, sessionidS, 0.0, backendSess,
+ useridL, usernameSess, programSess, true, eventName, queryStart, duration);
+ }
+
+ } else {
+ this.loadDataToTempSqlSession(tmpSqlsTemp,
+ tmpSessionsTemp, sqlId, waitClassId,
+ sessionId, sessionidS, 0.0, backendSess,
+ useridL, usernameSess, programSess, false, eventFlag, queryStart, duration);
+ }
+ }
+ // Close cursor!!
+ ActiveSessionHistoryCursor.close();
+ }
+ tmpSqlsTemp.set_sum();
+ tmpSessionsTemp.set_sum();
+
+ // Close cursor!!
+ ashSampleIds.close();
+
+ } catch (DatabaseException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#loadCommandTypeFromDB(java.util.List)
+ */
+ public void loadSqlTextCommandTypeFromDB(List arraySqlId) {
+
+ // Load all sqlId
+ ArrayList sqlIdAll = new ArrayList();
+
+ Iterator arraySqlIdIter = arraySqlId.iterator();
+ while (arraySqlIdIter.hasNext()) {
+ String sqlId = arraySqlIdIter.next();
+ if (!isSqlTextExist(sqlId)) {
+ sqlIdAll.add(sqlId);
+ }
+ }
+
+ this.loadSqlTextSqlIdFromDB(sqlIdAll);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#isSqlPlanHashValueExist(java.lang.String)
+ */
+ public boolean isSqlTextExist(String sqlId) {
+ boolean res = false;
+ try {
+ res = dao.getAshSqlIdTypeTextId().contains(sqlId);
+ } catch (DatabaseException e) {
+ res = false;
+ }
+
+ return res;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#getSqlType(java.lang.String)
+ */
+ public String getSqlType(String sqlId) {
+ String sqlType = null;
+ try {
+ AshSqlIdTypeText ash = dao.ashSqlIdTypeTextId.get(sqlId);
+ if (ash != null) {
+ sqlType = ash.getCommandType();
+ } else {
+ sqlType = "";
+ }
+ } catch (DatabaseException e) {
+ sqlType = "";
+ e.printStackTrace();
+ }
+ return sqlType;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.ash.database.DatabaseMain#getSqlText(java.lang.String)
+ */
+ public String getSqlText(String sqlId) {
+ String sqlText = null;
+ try {
+ AshSqlIdTypeText ash = dao.ashSqlIdTypeTextId.get(sqlId);
+ if (ash != null) {
+ sqlText = ash.getSqlText();
+ } else {
+ sqlText = "";
+ }
+
+ } catch (DatabaseException e) {
+ sqlText = "";
+ e.printStackTrace();
+ }
+ return sqlText;
+ }
+
+ /**
+ * Load data to temporary sql and sessions (gantt data)
+ *
+ * @param tmpSqlsTemp
+ * @param tmpSessionsTemp
+ * @param sqlId
+ * @param waitClassId
+ * @param sessionId
+ * @param sessionidS
+ * @param sessionSerial
+ * @param sessioniSerialS
+ * @param useridL
+ * @param programSess
+ * @param isDetail
+ * @param sqlPlanHashValue
+ */
+ private void loadDataToTempSqlSession(SqlsTemp tmpSqlsTemp,
+ SessionsTemp tmpSessionsTemp, String sqlId, double waitClassId, Long sessionId,
+ String sessionidS, Double sessionSerial, String backendType,
+ Long useridL, String usernameSess, String programSess, boolean isDetail,
+ String eventDetail, Long queryStart, Double duration) {
+
+ int count = 1;
+
+ /**
+ * Save data for sql row
+ */
+ if (sqlId != null) {
+ // Save SQL_ID and init
+ tmpSqlsTemp.setSqlId(sqlId);
+ // Save group event
+ tmpSqlsTemp.setTimeOfGroupEvent(sqlId, waitClassId, count);
+ tmpSqlsTemp.setSqlStats(sqlId, sessionId, queryStart, duration);
+ }
+
+ /**
+ * Save data for session row
+ */
+ tmpSessionsTemp.setSessionId(sessionidS, backendType, programSess, "", usernameSess);
+ tmpSessionsTemp.setTimeOfGroupEvent(sessionidS, waitClassId, count);
+
+ /**
+ * Save event detail data for sql and sessions row
+ */
+ if (isDetail) {
+ if (sqlId != null) {
+ tmpSqlsTemp.setTimeOfEventName(sqlId, waitClassId, eventDetail, count);
+ }
+ tmpSessionsTemp.setTimeOfEventName(sessionidS, waitClassId, eventDetail, count);
+ }
+ }
+
+ /**
+ * @return the kReconnect
+ */
+ private long getKReconnect() {
+ return kReconnect;
+ }
+
+ /**
+ * @param reconnect the kReconnect to set
+ */
+ private void setKReconnect(long reconnect) {
+ kReconnect = reconnect;
+ }
+
+ /**
+ * @return the isReconnect
+ */
+ private boolean isReconnect() {
+ return isReconnect;
+ }
+
+ /**
+ * @param isReconnect the isReconnect to set
+ */
+ private void setReconnect(boolean isReconnect) {
+ this.isReconnect = isReconnect;
+ }
+
+}
diff --git a/src/org/ash/gui/MainFrame.java b/src/org/ash/gui/MainFrame.java
index 7f07dcd..76983ff 100644
--- a/src/org/ash/gui/MainFrame.java
+++ b/src/org/ash/gui/MainFrame.java
@@ -335,8 +335,21 @@ private void initializeBerkeleyDatabaseAndLoading() {
String versionOracleDB = model.getVersionDB();
Boolean ASHsupport = model.getASHsupport();
-
- if (versionOracleDB.startsWith("11")) {
+ if (versionOracleDB.startsWith("13")) {
+ if(ASHsupport) {
+ this.database = new ASHDatabasePG13ASH(this.model);
+ } else {
+ this.database = new ASHDatabasePG13(this.model);
+ }
+ }
+ else if (versionOracleDB.startsWith("12")) {
+ if(ASHsupport) {
+ this.database = new ASHDatabasePG12ASH(this.model);
+ } else {
+ this.database = new ASHDatabasePG12(this.model);
+ }
+ }
+ else if (versionOracleDB.startsWith("11")) {
if(ASHsupport) {
this.database = new ASHDatabasePG10ASH(this.model);
} else {