353
									
								
								pgjdbc/src/test/java/org/postgresql/jdbc/FullTraceTest.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										353
									
								
								pgjdbc/src/test/java/org/postgresql/jdbc/FullTraceTest.java
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,353 @@
 | 
			
		||||
/*
 | 
			
		||||
 * Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
 | 
			
		||||
 *
 | 
			
		||||
 * openGauss is licensed under Mulan PSL v2.
 | 
			
		||||
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 | 
			
		||||
 * You may obtain a copy of Mulan PSL v2 at:
 | 
			
		||||
 *
 | 
			
		||||
 *           http://license.coscl.org.cn/MulanPSL2
 | 
			
		||||
 *
 | 
			
		||||
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 | 
			
		||||
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 | 
			
		||||
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 | 
			
		||||
 * See the Mulan PSL v2 for more details.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
package org.postgresql.jdbc;
 | 
			
		||||
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
import org.postgresql.test.TestUtil;
 | 
			
		||||
import org.postgresql.test.jdbc2.BaseTest4PG;
 | 
			
		||||
 | 
			
		||||
import java.sql.Connection;
 | 
			
		||||
import java.sql.PreparedStatement;
 | 
			
		||||
import java.sql.ResultSet;
 | 
			
		||||
import java.sql.Statement;
 | 
			
		||||
import java.util.Arrays;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Properties;
 | 
			
		||||
 | 
			
		||||
import static org.junit.Assert.assertTrue;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * test full trace.
 | 
			
		||||
 *
 | 
			
		||||
 * @author hwhbj
 | 
			
		||||
 * @since  2024-08-20
 | 
			
		||||
 */
 | 
			
		||||
public class FullTraceTest extends BaseTest4PG {
 | 
			
		||||
    private static final Integer WAIT_FLUSH_TIME = 1000;
 | 
			
		||||
    private static final String QUERY_STMT_HISTORY = "select db_time, net_trans_time from statement_history "
 | 
			
		||||
            + "where query like '%s'";
 | 
			
		||||
    private static final String RECORD_FULL_SQL = "set track_stmt_stat_level = 'L0,L0'";
 | 
			
		||||
    private static final String ENABLE_TRACE_SQL = "set enable_record_nettime = on";
 | 
			
		||||
 | 
			
		||||
    private static Connection createConnection() throws Exception {
 | 
			
		||||
        return TestUtil.openDB();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static Connection createConnection(Properties props) throws Exception {
 | 
			
		||||
        return TestUtil.openDB(props);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static Connection createConnection(String dbName) throws Exception {
 | 
			
		||||
        return TestUtil.openDB(dbName);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private List<Integer> recordCount(String sql) throws Exception {
 | 
			
		||||
        String querySql = String.format(QUERY_STMT_HISTORY, sql);
 | 
			
		||||
        try (Connection conn = createConnection("postgres");
 | 
			
		||||
             PreparedStatement pstmt = conn.prepareStatement(querySql);
 | 
			
		||||
             ResultSet rs = pstmt.executeQuery()) {
 | 
			
		||||
            int count1 = 0;
 | 
			
		||||
            int count2 = 0;
 | 
			
		||||
            int count3 = 0;
 | 
			
		||||
            while (rs.next()) {
 | 
			
		||||
                int dbTime = rs.getInt(1);
 | 
			
		||||
                int netTransTime = rs.getInt(2);
 | 
			
		||||
                if (dbTime == 0 && netTransTime == 0) {
 | 
			
		||||
                    count1++;
 | 
			
		||||
                } else if (dbTime > 0 && netTransTime == 0) {
 | 
			
		||||
                    count2++;
 | 
			
		||||
                } else if (dbTime > 0 && netTransTime > 0) {
 | 
			
		||||
                    count3++;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return Arrays.asList(count1, count2, count3);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void setRecordFullSql(Connection conn) throws Exception {
 | 
			
		||||
        try (PreparedStatement pstmt = conn.prepareStatement(ENABLE_TRACE_SQL + ";" + RECORD_FULL_SQL)) {
 | 
			
		||||
            pstmt.execute();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void sendPreTimeAndFlush(Connection conn) throws Exception {
 | 
			
		||||
        /* send previous net_time */
 | 
			
		||||
        try (PreparedStatement pstmt = conn.prepareStatement("select 1;")) {
 | 
			
		||||
            pstmt.executeQuery();
 | 
			
		||||
            Thread.sleep(WAIT_FLUSH_TIME);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testExecuteMultiSqlPBE() throws Exception {
 | 
			
		||||
        String sql1 = "drop table if exists t1";
 | 
			
		||||
        String sql2 = "create table t1(id int)";
 | 
			
		||||
        List<Integer> beforeInfoSql1 = recordCount(sql1);
 | 
			
		||||
        List<Integer> beforeInfoSql2 = recordCount(sql2);
 | 
			
		||||
 | 
			
		||||
        /* PBEPBES */
 | 
			
		||||
        try (Connection conn = createConnection();
 | 
			
		||||
             PreparedStatement pstmt = conn.prepareStatement(sql1 + ";" + sql2)) {
 | 
			
		||||
            setRecordFullSql(conn);
 | 
			
		||||
            pstmt.execute();
 | 
			
		||||
            sendPreTimeAndFlush(conn);
 | 
			
		||||
 | 
			
		||||
            List<Integer> afterInfoSql1 = recordCount(sql1);
 | 
			
		||||
            List<Integer> afterInfoSql2 = recordCount(sql2);
 | 
			
		||||
 | 
			
		||||
            assertTrue(beforeInfoSql1.get(0) + 1 == afterInfoSql1.get(0));
 | 
			
		||||
            assertTrue(beforeInfoSql1.get(1) + 1 == afterInfoSql1.get(1));
 | 
			
		||||
            assertTrue(beforeInfoSql1.get(2) == afterInfoSql1.get(2));
 | 
			
		||||
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(0) + 1 == afterInfoSql2.get(0));
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(1) == afterInfoSql2.get(1));
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(2) + 1 == afterInfoSql2.get(2));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testExecuteBatchPBENoCache() throws Exception {
 | 
			
		||||
        Properties props = new Properties();
 | 
			
		||||
        props.setProperty("prepareThreshold", "0");
 | 
			
		||||
        String sql1 = "drop table if exists t1; create table t1(id int);";
 | 
			
		||||
        String sql2 = "insert into t1 values(?)";
 | 
			
		||||
        String sql2Record = "insert into t1 values(%)";
 | 
			
		||||
        List<Integer> beforeInfoSql2 = recordCount(sql2Record);
 | 
			
		||||
        /* PUES / PUES */
 | 
			
		||||
        try (Connection conn = createConnection(props);
 | 
			
		||||
             Statement stmt = conn.createStatement();
 | 
			
		||||
             PreparedStatement pstmt = conn.prepareStatement(sql2)) {
 | 
			
		||||
            stmt.execute(sql1);
 | 
			
		||||
            setRecordFullSql(conn);
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < 5000; ++i) {
 | 
			
		||||
                pstmt.setInt(1, i);
 | 
			
		||||
                pstmt.addBatch();
 | 
			
		||||
            }
 | 
			
		||||
            pstmt.executeBatch();
 | 
			
		||||
            for (int i = 0; i < 5000; ++i) {
 | 
			
		||||
                pstmt.setInt(1, i);
 | 
			
		||||
                pstmt.addBatch();
 | 
			
		||||
            }
 | 
			
		||||
            pstmt.executeBatch();
 | 
			
		||||
            sendPreTimeAndFlush(conn);
 | 
			
		||||
 | 
			
		||||
            List<Integer> afterInfoSql2 = recordCount(sql2Record);
 | 
			
		||||
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(0) + 2 == afterInfoSql2.get(0));
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(1) == afterInfoSql2.get(1));
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(2) + 2 == afterInfoSql2.get(2));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testExecuteBatchPBEUseCache() throws Exception {
 | 
			
		||||
        Properties props = new Properties();
 | 
			
		||||
        props.setProperty("prepareThreshold", "1");
 | 
			
		||||
        String sql1 = "drop table if exists t1; create table t1(id int);";
 | 
			
		||||
 | 
			
		||||
        String sql2 = "insert into t1 values(?)";
 | 
			
		||||
        String sql2Record = "insert into t1 values(%)";
 | 
			
		||||
        List<Integer> beforeInfoSql2 = recordCount(sql2Record);
 | 
			
		||||
 | 
			
		||||
        /* P/DS/S / UES / UES */
 | 
			
		||||
        try (Connection conn = createConnection(props);
 | 
			
		||||
             Statement stmt = conn.createStatement();
 | 
			
		||||
             PreparedStatement pstmt = conn.prepareStatement(sql2)) {
 | 
			
		||||
            stmt.execute(sql1);
 | 
			
		||||
            setRecordFullSql(conn);
 | 
			
		||||
            for (int i = 0; i < 5000; ++i) {
 | 
			
		||||
                pstmt.setInt(1, i);
 | 
			
		||||
                pstmt.addBatch();
 | 
			
		||||
            }
 | 
			
		||||
            pstmt.executeBatch();
 | 
			
		||||
            for (int i = 0; i < 5000; ++i) {
 | 
			
		||||
                pstmt.setInt(1, i);
 | 
			
		||||
                pstmt.addBatch();
 | 
			
		||||
            }
 | 
			
		||||
            pstmt.executeBatch();
 | 
			
		||||
            sendPreTimeAndFlush(conn);
 | 
			
		||||
 | 
			
		||||
            List<Integer> afterInfoSql2 = recordCount(sql2Record);
 | 
			
		||||
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(0) + 1 == afterInfoSql2.get(0));
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(1) == afterInfoSql2.get(1));
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(2) + 2 == afterInfoSql2.get(2));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testExecutePBENoCache() throws Exception {
 | 
			
		||||
        Properties props = new Properties();
 | 
			
		||||
        props.setProperty("prepareThreshold", "0");
 | 
			
		||||
        String sql1 = "drop table if exists t1; create table t1(id int, age int);";
 | 
			
		||||
 | 
			
		||||
        String sql2 = "select ? from t1;";
 | 
			
		||||
        String sql2Record = "select%from t1";
 | 
			
		||||
        List<Integer> beforeInfoSql2 = recordCount(sql2Record);
 | 
			
		||||
 | 
			
		||||
        /* PBES / PBES */
 | 
			
		||||
        try (Connection conn = createConnection(props);
 | 
			
		||||
             Statement stmt = conn.createStatement();
 | 
			
		||||
             PreparedStatement pstmt = conn.prepareStatement(sql2)) {
 | 
			
		||||
            stmt.execute(sql1);
 | 
			
		||||
            setRecordFullSql(conn);
 | 
			
		||||
 | 
			
		||||
            pstmt.setString(1, "id");
 | 
			
		||||
            pstmt.execute();
 | 
			
		||||
            pstmt.setString(1, "age");
 | 
			
		||||
            pstmt.execute();
 | 
			
		||||
            sendPreTimeAndFlush(conn);
 | 
			
		||||
 | 
			
		||||
            List<Integer> afterInfoSql2 = recordCount(sql2Record);
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(0) + 2 == afterInfoSql2.get(0));
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(1) == afterInfoSql2.get(1));
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(2) + 2 == afterInfoSql2.get(2));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testExecutePBEUseCache() throws Exception {
 | 
			
		||||
        Properties props = new Properties();
 | 
			
		||||
        props.setProperty("prepareThreshold", "1");
 | 
			
		||||
        String sql1 = "drop table if exists t1; create table t1(id int, age int);";
 | 
			
		||||
 | 
			
		||||
        String sql2 = "select ? from t1;";
 | 
			
		||||
        String sql2Record = "select%from t1";
 | 
			
		||||
        List<Integer> beforeInfoSql2 = recordCount(sql2Record);
 | 
			
		||||
 | 
			
		||||
        /* PBES/BES */
 | 
			
		||||
        try (Connection conn = createConnection(props);
 | 
			
		||||
             Statement stmt = conn.createStatement();
 | 
			
		||||
             PreparedStatement pstmt = conn.prepareStatement(sql2)) {
 | 
			
		||||
            stmt.execute(sql1);
 | 
			
		||||
            setRecordFullSql(conn);
 | 
			
		||||
 | 
			
		||||
            pstmt.setString(1, "id");
 | 
			
		||||
            pstmt.execute();
 | 
			
		||||
            pstmt.setString(1, "age");
 | 
			
		||||
            pstmt.execute();
 | 
			
		||||
            sendPreTimeAndFlush(conn);
 | 
			
		||||
 | 
			
		||||
            List<Integer> afterInfoSql2 = recordCount(sql2Record);
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(0) + 1 == afterInfoSql2.get(0));
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(1) == afterInfoSql2.get(1));
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(2) + 2 == afterInfoSql2.get(2));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testExecuteFetchSize() throws Exception {
 | 
			
		||||
        String sql1 = "drop table if exists t1; create table t1(id int)";
 | 
			
		||||
        String sql2 = "insert into t1 values(?)";
 | 
			
		||||
        String sql3 = "select * from t1";
 | 
			
		||||
        List<Integer> beforeInfoSql3 = recordCount(sql3);
 | 
			
		||||
        ResultSet rst = null;
 | 
			
		||||
 | 
			
		||||
        try (Connection conn = createConnection();
 | 
			
		||||
        Statement stmt = conn.createStatement();
 | 
			
		||||
        PreparedStatement pstmt = conn.prepareStatement(sql2);
 | 
			
		||||
        PreparedStatement pstmt1 = conn.prepareStatement(sql3)) {
 | 
			
		||||
            /* prepare data */
 | 
			
		||||
            stmt.execute(sql1);
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < 5000; ++i) {
 | 
			
		||||
                pstmt.setInt(1, i);
 | 
			
		||||
                pstmt.addBatch();
 | 
			
		||||
            }
 | 
			
		||||
            pstmt.executeBatch();
 | 
			
		||||
 | 
			
		||||
            conn.setAutoCommit(false);
 | 
			
		||||
            setRecordFullSql(conn);
 | 
			
		||||
 | 
			
		||||
            pstmt1.setFetchSize(1000);
 | 
			
		||||
            /* PBDES/ES/ES/ES/ES/ES */
 | 
			
		||||
            rst = pstmt1.executeQuery();
 | 
			
		||||
            while (rst.next()) {
 | 
			
		||||
                rst.getInt(1);
 | 
			
		||||
            }
 | 
			
		||||
            sendPreTimeAndFlush(conn);
 | 
			
		||||
 | 
			
		||||
            List<Integer> afterInfoSql3 = recordCount(sql3);
 | 
			
		||||
            assertTrue(beforeInfoSql3.get(0) + 1 == afterInfoSql3.get(0));
 | 
			
		||||
            assertTrue(beforeInfoSql3.get(1) == afterInfoSql3.get(1));
 | 
			
		||||
            assertTrue(beforeInfoSql3.get(2) + 6 == afterInfoSql3.get(2));
 | 
			
		||||
        } finally {
 | 
			
		||||
            if (rst != null) {
 | 
			
		||||
                rst.close();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testExecuteMultiSqlQ() throws Exception {
 | 
			
		||||
        Properties props = new Properties();
 | 
			
		||||
        props.setProperty("preferQueryMode", "simple");
 | 
			
		||||
 | 
			
		||||
        String sql1 = "drop table if exists t1";
 | 
			
		||||
        String sql2 = "create table t1(id int)";
 | 
			
		||||
        List<Integer> beforeInfoSql1 = recordCount(sql1);
 | 
			
		||||
        List<Integer> beforeInfoSql2 = recordCount(sql2);
 | 
			
		||||
        try (Connection conn = createConnection(props);
 | 
			
		||||
             PreparedStatement pstmt = conn.prepareStatement(sql1 + ";" + sql2)) {
 | 
			
		||||
            setRecordFullSql(conn);
 | 
			
		||||
            /* Q -> Q */
 | 
			
		||||
            pstmt.execute();
 | 
			
		||||
            sendPreTimeAndFlush(conn);
 | 
			
		||||
 | 
			
		||||
            List<Integer> afterInfoSql1 = recordCount(sql1);
 | 
			
		||||
            List<Integer> afterInfoSql2 = recordCount(sql2);
 | 
			
		||||
 | 
			
		||||
            assertTrue(beforeInfoSql1.get(0) == afterInfoSql1.get(0));
 | 
			
		||||
            assertTrue(beforeInfoSql1.get(1) + 1 == afterInfoSql1.get(1));
 | 
			
		||||
            assertTrue(beforeInfoSql1.get(2) == afterInfoSql1.get(2));
 | 
			
		||||
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(0) == afterInfoSql2.get(0));
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(1) == afterInfoSql2.get(1));
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(2) + 1 == afterInfoSql2.get(2));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Test
 | 
			
		||||
    public void testExecuteQ() throws Exception {
 | 
			
		||||
        Properties props = new Properties();
 | 
			
		||||
        props.setProperty("preferQueryMode", "simple");
 | 
			
		||||
 | 
			
		||||
        String sql1 = "drop table if exists t1; create table t1(id int, age int)";
 | 
			
		||||
        String sql2 = "select ? from t1";
 | 
			
		||||
        String sql2Record = "select%from t1";
 | 
			
		||||
        List<Integer> beforeInfoSql2 = recordCount(sql2Record);
 | 
			
		||||
 | 
			
		||||
        try (Connection conn = createConnection(props);
 | 
			
		||||
             Statement stmt = conn.createStatement();
 | 
			
		||||
             PreparedStatement pstmt = conn.prepareStatement(sql2)) {
 | 
			
		||||
            stmt.execute(sql1);
 | 
			
		||||
            setRecordFullSql(conn);
 | 
			
		||||
 | 
			
		||||
            /* Q / Q */
 | 
			
		||||
            pstmt.setString(1, "id");
 | 
			
		||||
            pstmt.execute();
 | 
			
		||||
            pstmt.setString(1, "age");
 | 
			
		||||
            pstmt.execute();
 | 
			
		||||
            sendPreTimeAndFlush(conn);
 | 
			
		||||
 | 
			
		||||
            List<Integer> afterInfoSql2 = recordCount(sql2Record);
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(0) == afterInfoSql2.get(0));
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(1) == afterInfoSql2.get(1));
 | 
			
		||||
            assertTrue(beforeInfoSql2.get(2) + 2 == afterInfoSql2.get(2));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -365,6 +365,10 @@ public class TestUtil {
 | 
			
		||||
   return openDB(props,getDatabase());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static Connection openDB(String dbName) throws Exception {
 | 
			
		||||
    return openDB(new Properties(), dbName);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public static Connection openDBPG(Properties props) throws Exception {
 | 
			
		||||
    return openDB(props,getDatabasePG());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user