Add trace support for Postgresql jdbc driver 9.4.1207+
Looks like there was a major overhaul in postgresql jdbc driver code in 9.4.1207.
Postgresql plugin needs to support this change.

If anyone's willing to work on this this, please feel free to leave a message here.

related issue - #2157
plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/PostgreSqlPlugin.java plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/interceptor/PostgreSqlPreparedStatementCreateInterceptor1.java plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/interceptor/PostgreSqlPreparedStatementCreateInterceptor2.java plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/interceptor/PostgreSqlPreparedStatementCreateInterceptor3.java pom.xml
plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/PostgreSqlPlugin.java pom.xml
diff --git a/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/PostgreSqlPlugin.java b/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/PostgreSqlPlugin.java
index cfcfaec1a444..6c7f732b2738 100644
--- a/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/PostgreSqlPlugin.java
+++ b/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/PostgreSqlPlugin.java
@@ -37,7 +37,7 @@
 
 /**
  * @author Brad Hong
- *
+ * @author HyunGil Jeong
  */
 public class PostgreSqlPlugin implements ProfilerPlugin, TransformTemplateAware {
 
@@ -60,35 +60,34 @@ public void setup(ProfilerPluginSetupContext context) {
 
         context.addJdbcUrlParser(jdbcUrlParser);
 
-        addConnectionTransformer(config);
         addDriverTransformer();
-        addPreparedStatementTransformer(config);
+        addConnectionTransformers(config);
+        addStatementTransformers(config);
+        addPreparedStatementTransformers(config);
+
+        // pre 9.4.1207
+        addLegacyConnectionTransformers(config);
+        addLegacyStatementTransformers(config);
     }
 
-    private void addConnectionTransformer(final PostgreSqlConfig config) {
-        transformTemplate.transform("org.postgresql.jdbc4.Jdbc4Connection", new TransformCallback() {
+    private void addDriverTransformer() {
+        transformTemplate.transform("org.postgresql.Driver", new TransformCallback() {
 
             @Override
             public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
                 InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer);
 
-                if (!target.isInterceptable()) {
-                    return null;
-                }
-
-                target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor");
-
-                InstrumentUtils.findConstructor(target, "org.postgresql.util.HostSpec[]", "java.lang.String", "java.lang.String", "java.util.Properties", "java.lang.String")
-                        .addInterceptor("com.navercorp.pinpoint.plugin.jdbc.postgresql.interceptor.PostgreSQLConnectionCreateInterceptor");
-
-                InstrumentUtils.findMethod(target,"prepareStatement", "java.lang.String", "int", "int", "int")
-                        .addScopedInterceptor("com.navercorp.pinpoint.plugin.jdbc.postgresql.interceptor.PostgreSqlPreparedStatementCreateInterceptor3", POSTGRESQL_SCOPE);
+                InstrumentUtils.findMethod(target, "connect", "java.lang.String", "java.util.Properties")
+                        .addScopedInterceptor("com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.DriverConnectInterceptorV2",
+                                va(PostgreSqlConstants.POSTGRESQL, false), POSTGRESQL_SCOPE, ExecutionPolicy.ALWAYS);
 
                 return target.toBytecode();
             }
         });
-        transformTemplate.transform("org.postgresql.jdbc3.Jdbc3Connection", new TransformCallback() {
+    }
 
+    private void addConnectionTransformers(final PostgreSqlConfig config) {
+        transformTemplate.transform("org.postgresql.jdbc.PgConnection", new TransformCallback() {
             @Override
             public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
                 InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer);
@@ -97,8 +96,15 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin
                     return null;
                 }
 
+                InstrumentUtils.findConstructor(target, "org.postgresql.util.HostSpec[]", "java.lang.String", "java.lang.String", "java.util.Properties", "java.lang.String")
+                        .addInterceptor("com.navercorp.pinpoint.plugin.jdbc.postgresql.interceptor.PostgreSQLConnectionCreateInterceptor");
+
                 target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor");
 
+                // close
+                InstrumentUtils.findMethod(target, "close")
+                        .addScopedInterceptor("com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.ConnectionCloseInterceptor", POSTGRESQL_SCOPE);
+
                 // createStatement
                 final String statementCreate = "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.StatementCreateInterceptor";
                 InstrumentUtils.findMethod(target, "createStatement")
@@ -108,9 +114,134 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin
                 InstrumentUtils.findMethod(target, "createStatement", "int", "int", "int")
                         .addScopedInterceptor(statementCreate, POSTGRESQL_SCOPE);
 
+                // prepareStatement
+                final String preparedStatementCreate = "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.PreparedStatementCreateInterceptor";
+                InstrumentUtils.findMethod(target, "prepareStatement", "java.lang.String")
+                        .addScopedInterceptor(preparedStatementCreate, POSTGRESQL_SCOPE);
+                InstrumentUtils.findMethod(target, "prepareStatement", "java.lang.String", "int")
+                        .addScopedInterceptor(preparedStatementCreate, POSTGRESQL_SCOPE);
+                InstrumentUtils.findMethod(target, "prepareStatement", "java.lang.String", "int[]")
+                        .addScopedInterceptor(preparedStatementCreate, POSTGRESQL_SCOPE);
+                InstrumentUtils.findMethod(target, "prepareStatement", "java.lang.String", "int", "int")
+                        .addScopedInterceptor(preparedStatementCreate, POSTGRESQL_SCOPE);
+                InstrumentUtils.findMethod(target, "prepareStatement", "java.lang.String", "int", "int", "int")
+                        .addScopedInterceptor(preparedStatementCreate, POSTGRESQL_SCOPE);
+                InstrumentUtils.findMethod(target, "prepareStatement", "java.lang.String", "java.lang.String[]")
+                        .addScopedInterceptor(preparedStatementCreate, POSTGRESQL_SCOPE);
+
+                if (config.isProfileSetAutoCommit()) {
+                    InstrumentUtils.findMethod(target, "setAutoCommit", "boolean")
+                            .addScopedInterceptor("com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.TransactionSetAutoCommitInterceptor", POSTGRESQL_SCOPE);
+                }
+
+                if (config.isProfileCommit()) {
+                    InstrumentUtils.findMethod(target, "commit")
+                            .addScopedInterceptor("com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.TransactionCommitInterceptor", POSTGRESQL_SCOPE);
+                }
+
+                if (config.isProfileRollback()) {
+                    InstrumentUtils.findMethod(target, "rollback")
+                            .addScopedInterceptor("com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.TransactionRollbackInterceptor", POSTGRESQL_SCOPE);
+                }
+
                 return target.toBytecode();
             }
         });
+    }
+
+    private void addStatementTransformers(final PostgreSqlConfig config) {
+        TransformCallback transformer = new TransformCallback() {
+
+            @Override
+            public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
+                InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer);
+
+                if (!target.isInterceptable()) {
+                    return null;
+                }
+
+                target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor");
+
+                final String executeQueryInterceptor = "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.StatementExecuteQueryInterceptor";
+                InstrumentUtils.findMethod(target, "executeQuery", "java.lang.String")
+                        .addScopedInterceptor(executeQueryInterceptor, POSTGRESQL_SCOPE);
+
+                final String executeUpdateInterceptor = "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.StatementExecuteUpdateInterceptor";
+                InstrumentUtils.findMethod(target, "executeUpdate", "java.lang.String")
+                        .addScopedInterceptor(executeUpdateInterceptor, POSTGRESQL_SCOPE);
+                InstrumentUtils.findMethod(target, "executeUpdate", "java.lang.String", "int")
+                        .addScopedInterceptor(executeUpdateInterceptor, POSTGRESQL_SCOPE);
+                InstrumentUtils.findMethod(target, "execute", "java.lang.String")
+                        .addScopedInterceptor(executeUpdateInterceptor, POSTGRESQL_SCOPE);
+                InstrumentUtils.findMethod(target, "execute", "java.lang.String", "int")
+                        .addScopedInterceptor(executeUpdateInterceptor, POSTGRESQL_SCOPE);
+
+                // 9.4.1207 has setX methods in PgStatement
+                final PreparedStatementBindingMethodFilter excludes = PreparedStatementBindingMethodFilter.excludes("setRowId", "setNClob", "setSQLXML");
+                final List<InstrumentMethod> declaredMethods = target.getDeclaredMethods(excludes);
+                if (!declaredMethods.isEmpty()) {
+                    target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.ParsingResultAccessor");
+                    target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.BindValueAccessor");
+
+                    int maxBindValueSize = config.getMaxSqlBindValueSize();
+
+                    final String preparedStatementInterceptor = "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.PreparedStatementExecuteQueryInterceptor";
+                    InstrumentUtils.findMethod(target, "execute")
+                            .addScopedInterceptor(preparedStatementInterceptor, va(maxBindValueSize), POSTGRESQL_SCOPE);
+                    InstrumentUtils.findMethod(target, "executeQuery")
+                            .addScopedInterceptor(preparedStatementInterceptor, va(maxBindValueSize), POSTGRESQL_SCOPE);
+                    InstrumentUtils.findMethod(target, "executeUpdate")
+                            .addScopedInterceptor(preparedStatementInterceptor, va(maxBindValueSize), POSTGRESQL_SCOPE);
+
+                    for (InstrumentMethod method : declaredMethods) {
+                        method.addScopedInterceptor("com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.PreparedStatementBindVariableInterceptor", POSTGRESQL_SCOPE, ExecutionPolicy.BOUNDARY);
+                    }
+                }
+
+                return target.toBytecode();
+            }
+        };
+        transformTemplate.transform("org.postgresql.jdbc.PgStatement", transformer);
+    }
+
+    private void addPreparedStatementTransformers(final PostgreSqlConfig config) {
+        TransformCallback transformCallback = new TransformCallback() {
+
+            @Override
+            public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
+                InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer);
+
+                target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor");
+
+                // 9.4.1207 has setX methods in PgStatement
+                final PreparedStatementBindingMethodFilter excludes = PreparedStatementBindingMethodFilter.excludes("setRowId", "setNClob", "setSQLXML");
+                final List<InstrumentMethod> declaredMethods = target.getDeclaredMethods(excludes);
+                if (!declaredMethods.isEmpty()) {
+                    target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.ParsingResultAccessor");
+                    target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.BindValueAccessor");
+
+                    int maxBindValueSize = config.getMaxSqlBindValueSize();
+
+                    final String preparedStatementInterceptor = "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.PreparedStatementExecuteQueryInterceptor";
+                    InstrumentUtils.findMethod(target, "execute")
+                            .addScopedInterceptor(preparedStatementInterceptor, va(maxBindValueSize), POSTGRESQL_SCOPE);
+                    InstrumentUtils.findMethod(target, "executeQuery")
+                            .addScopedInterceptor(preparedStatementInterceptor, va(maxBindValueSize), POSTGRESQL_SCOPE);
+                    InstrumentUtils.findMethod(target, "executeUpdate")
+                            .addScopedInterceptor(preparedStatementInterceptor, va(maxBindValueSize), POSTGRESQL_SCOPE);
+
+                    for (InstrumentMethod method : declaredMethods) {
+                        method.addScopedInterceptor("com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.PreparedStatementBindVariableInterceptor", POSTGRESQL_SCOPE, ExecutionPolicy.BOUNDARY);
+                    }
+                }
+
+                return target.toBytecode();
+            }
+        };
+        transformTemplate.transform("org.postgresql.jdbc.PgPreparedStatement", transformCallback);
+    }
+
+    private void addLegacyConnectionTransformers(final PostgreSqlConfig config) {
         transformTemplate.transform("org.postgresql.jdbc2.AbstractJdbc2Connection", new TransformCallback() {
 
             @Override
@@ -127,11 +258,18 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin
                 InstrumentUtils.findMethod(target, "close")
                         .addScopedInterceptor("com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.ConnectionCloseInterceptor", POSTGRESQL_SCOPE);
 
+                // createStatement
+                final String statementCreate = "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.StatementCreateInterceptor";
+                InstrumentUtils.findMethod(target, "createStatement")
+                        .addScopedInterceptor(statementCreate, POSTGRESQL_SCOPE);
+
+                // prepareStatement
+                final String preparedStatementCreate = "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.PreparedStatementCreateInterceptor";
                 InstrumentUtils.findMethod(target, "prepareStatement", "java.lang.String")
-                        .addScopedInterceptor("com.navercorp.pinpoint.plugin.jdbc.postgresql.interceptor.PostgreSqlPreparedStatementCreateInterceptor1", POSTGRESQL_SCOPE);
+                        .addScopedInterceptor(preparedStatementCreate, POSTGRESQL_SCOPE);
 
                 if (config.isProfileSetAutoCommit()) {
-                    InstrumentUtils.findMethod(target, "setAutoCommit",  "boolean")
+                    InstrumentUtils.findMethod(target, "setAutoCommit", "boolean")
                             .addScopedInterceptor("com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.TransactionSetAutoCommitInterceptor", POSTGRESQL_SCOPE);
                 }
 
@@ -159,41 +297,59 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin
                     return null;
                 }
 
-                target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor");
+                // createStatement
+                final String statementCreate = "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.StatementCreateInterceptor";
+                InstrumentUtils.findMethod(target, "createStatement", "int", "int")
+                        .addScopedInterceptor(statementCreate, POSTGRESQL_SCOPE);
 
-                // preparedStatement
-                final String preparedStatementCreate = "com.navercorp.pinpoint.plugin.jdbc.postgresql.interceptor.PostgreSqlPreparedStatementCreateInterceptor2";
-                InstrumentUtils.findMethod(target, "prepareStatement",  "java.lang.String", "int")
+                // prepareStatement
+                final String preparedStatementCreate = "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.PreparedStatementCreateInterceptor";
+                InstrumentUtils.findMethod(target, "prepareStatement", "java.lang.String", "int")
                         .addScopedInterceptor(preparedStatementCreate, POSTGRESQL_SCOPE);
-                InstrumentUtils.findMethod(target, "prepareStatement",  "java.lang.String", "int[]")
+                InstrumentUtils.findMethod(target, "prepareStatement", "java.lang.String", "int[]")
                         .addScopedInterceptor(preparedStatementCreate, POSTGRESQL_SCOPE);
-                InstrumentUtils.findMethod(target, "prepareStatement",  "java.lang.String", "java.lang.String[]")
+                InstrumentUtils.findMethod(target, "prepareStatement", "java.lang.String", "int", "int")
                         .addScopedInterceptor(preparedStatementCreate, POSTGRESQL_SCOPE);
-                InstrumentUtils.findMethod(target, "prepareStatement",  "java.lang.String", "int", "int")
+                InstrumentUtils.findMethod(target, "prepareStatement", "java.lang.String", "java.lang.String[]")
                         .addScopedInterceptor(preparedStatementCreate, POSTGRESQL_SCOPE);
 
                 return target.toBytecode();
             }
         });
-    }
 
-    private void addDriverTransformer() {
-        transformTemplate.transform("org.postgresql.Driver", new TransformCallback() {
+        TransformCallback concreteConnectionTransformCallback = new TransformCallback() {
 
             @Override
             public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
                 InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer);
 
-                InstrumentUtils.findMethod(target, "connect",  "java.lang.String", "java.util.Properties")
-                        .addScopedInterceptor("com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.DriverConnectInterceptorV2",
-                                va(PostgreSqlConstants.POSTGRESQL, false), POSTGRESQL_SCOPE, ExecutionPolicy.ALWAYS);
+                if (!target.isInterceptable()) {
+                    return null;
+                }
+
+                InstrumentUtils.findConstructor(target, "org.postgresql.util.HostSpec[]", "java.lang.String", "java.lang.String", "java.util.Properties", "java.lang.String")
+                        .addInterceptor("com.navercorp.pinpoint.plugin.jdbc.postgresql.interceptor.PostgreSQLConnectionCreateInterceptor");
+
+                // createStatement
+                final String statementCreate = "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.StatementCreateInterceptor";
+                InstrumentUtils.findMethod(target, "createStatement", "int", "int", "int")
+                        .addScopedInterceptor(statementCreate, POSTGRESQL_SCOPE);
+
+                // prepareStatement
+                final String preparedStatementCreate = "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.PreparedStatementCreateInterceptor";
+                InstrumentUtils.findMethod(target, "prepareStatement", "java.lang.String", "int", "int", "int")
+                        .addScopedInterceptor(preparedStatementCreate, POSTGRESQL_SCOPE);
 
                 return target.toBytecode();
             }
-        });
+        };
+        transformTemplate.transform("org.postgresql.jdbc3.Jdbc3Connection", concreteConnectionTransformCallback);
+        transformTemplate.transform("org.postgresql.jdbc3g.Jdbc3gConnection", concreteConnectionTransformCallback);
+        transformTemplate.transform("org.postgresql.jdbc4.Jdbc4Connection", concreteConnectionTransformCallback);
+        transformTemplate.transform("org.postgresql.jdbc42.Jdbc42Connection", concreteConnectionTransformCallback);
     }
 
-    private void addPreparedStatementTransformer(final PostgreSqlConfig config) {
+    private void addLegacyStatementTransformers(final PostgreSqlConfig config) {
         transformTemplate.transform("org.postgresql.jdbc2.AbstractJdbc2Statement", new TransformCallback() {
 
             @Override
@@ -214,18 +370,15 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin
                 InstrumentUtils.findMethod(target, "executeUpdate")
                         .addScopedInterceptor(preparedStatementInterceptor, va(maxBindValueSize), POSTGRESQL_SCOPE);
 
-                return target.toBytecode();
-            }
-        });
-        transformTemplate.transform("org.postgresql.jdbc3.AbstractJdbc3Statement", new TransformCallback() {
-
-            @Override
-            public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
-                InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer);
+                final String executeQueryInterceptor = "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.StatementExecuteQueryInterceptor";
+                InstrumentUtils.findMethod(target, "executeQuery", "java.lang.String")
+                        .addScopedInterceptor(executeQueryInterceptor, POSTGRESQL_SCOPE);
 
-                target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor");
-                target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.ParsingResultAccessor");
-                target.addField("com.navercorp.pinpoint.bootstrap.plugin.jdbc.BindValueAccessor");
+                final String executeUpdateInterceptor = "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.StatementExecuteUpdateInterceptor";
+                InstrumentUtils.findMethod(target, "executeUpdate", "java.lang.String")
+                        .addScopedInterceptor(executeUpdateInterceptor, POSTGRESQL_SCOPE);
+                InstrumentUtils.findMethod(target, "execute", "java.lang.String")
+                        .addScopedInterceptor(executeUpdateInterceptor, POSTGRESQL_SCOPE);
 
                 final PreparedStatementBindingMethodFilter excludes = PreparedStatementBindingMethodFilter.excludes("setRowId", "setNClob", "setSQLXML");
                 final List<InstrumentMethod> declaredMethods = target.getDeclaredMethods(excludes);
@@ -233,18 +386,19 @@ public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, Strin
                     method.addScopedInterceptor("com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.PreparedStatementBindVariableInterceptor", POSTGRESQL_SCOPE, ExecutionPolicy.BOUNDARY);
                 }
 
-                final String executeQueryInterceptor = "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.StatementExecuteQueryInterceptor";
-                InstrumentUtils.findMethod(target, "executeQuery", "java.lang.String")
-                        .addScopedInterceptor(executeQueryInterceptor, POSTGRESQL_SCOPE);
+                return target.toBytecode();
+            }
+        });
+        transformTemplate.transform("org.postgresql.jdbc3.AbstractJdbc3Statement", new TransformCallback() {
+
+            @Override
+            public byte[] doInTransform(Instrumentor instrumentor, ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws InstrumentException {
+                InstrumentClass target = instrumentor.getInstrumentClass(loader, className, classfileBuffer);
 
                 final String executeUpdateInterceptor = "com.navercorp.pinpoint.bootstrap.plugin.jdbc.interceptor.StatementExecuteUpdateInterceptor";
-                InstrumentUtils.findMethod(target, "executeUpdate", "java.lang.String")
-                        .addScopedInterceptor(executeUpdateInterceptor, POSTGRESQL_SCOPE);
-                InstrumentUtils.findMethod(target, "executeUpdate",  "java.lang.String", "int")
-                        .addScopedInterceptor(executeUpdateInterceptor, POSTGRESQL_SCOPE);
-                InstrumentUtils.findMethod(target, "execute",  "java.lang.String")
+                InstrumentUtils.findMethod(target, "executeUpdate", "java.lang.String", "int")
                         .addScopedInterceptor(executeUpdateInterceptor, POSTGRESQL_SCOPE);
-                InstrumentUtils.findMethod(target, "execute",  "java.lang.String", "int")
+                InstrumentUtils.findMethod(target, "execute", "java.lang.String", "int")
                         .addScopedInterceptor(executeUpdateInterceptor, POSTGRESQL_SCOPE);
 
                 return target.toBytecode();
diff --git a/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/interceptor/PostgreSqlPreparedStatementCreateInterceptor1.java b/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/interceptor/PostgreSqlPreparedStatementCreateInterceptor1.java
deleted file mode 100644
index a62aa46c1b88..000000000000
--- a/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/interceptor/PostgreSqlPreparedStatementCreateInterceptor1.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2014 NAVER Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.navercorp.pinpoint.plugin.jdbc.postgresql.interceptor;
-
-import com.navercorp.pinpoint.bootstrap.context.*;
-import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin;
-import com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor;
-import com.navercorp.pinpoint.bootstrap.plugin.jdbc.ParsingResultAccessor;
-import com.navercorp.pinpoint.bootstrap.plugin.jdbc.UnKnownDatabaseInfo;
-import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils;
-
-/**
- * @author Brad Hong
- */
-// #1375 Workaround java level Deadlock
-// https://oss.navercorp.com/pinpoint/pinpoint-naver/issues/1375
-//@TargetMethods({
-//        @TargetMethod(name="prepareStatement", paramTypes={ "java.lang.String" })
-//})
-public class PostgreSqlPreparedStatementCreateInterceptor1 extends SpanEventSimpleAroundInterceptorForPlugin {
-
-    public PostgreSqlPreparedStatementCreateInterceptor1(TraceContext context, MethodDescriptor descriptor) {
-        super(context, descriptor);
-    }
-
-    @Override
-    public void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args)  {
-        DatabaseInfo databaseInfo = null;
-        if (target instanceof DatabaseInfoAccessor) {
-            databaseInfo = ((DatabaseInfoAccessor)target)._$PINPOINT$_getDatabaseInfo();
-        }
-
-        if (databaseInfo == null) {
-            databaseInfo = UnKnownDatabaseInfo.INSTANCE;
-        }
-        
-        recorder.recordServiceType(databaseInfo.getType());
-        recorder.recordEndPoint(databaseInfo.getMultipleHost());
-        recorder.recordDestinationId(databaseInfo.getDatabaseId());
-    }
-
-    @Override
-    protected void prepareAfterTrace(Object target, Object[] args, Object result, Throwable throwable) {
-        final boolean success = InterceptorUtils.isSuccess(throwable);
-        if (success) {
-            if (target instanceof DatabaseInfoAccessor) {
-                // set databaseInfo to PreparedStatement only when preparedStatement is generated successfully.
-                final DatabaseInfo databaseInfo = ((DatabaseInfoAccessor)target)._$PINPOINT$_getDatabaseInfo();
-                if (databaseInfo != null) {
-                    if (result instanceof DatabaseInfoAccessor) {
-                        ((DatabaseInfoAccessor)result)._$PINPOINT$_setDatabaseInfo(databaseInfo);
-                    }
-                }
-            }
-            if (result instanceof ParsingResultAccessor) {
-                // 1. Don't check traceContext. preparedStatement can be created in other thread.
-                // 2. While sampling is active, the thread which creates preparedStatement could not be a sampling target. So record sql anyway. 
-                String sql = (String) args[0];
-                final ParsingResult parsingResult = traceContext.parseSql(sql);
-                if (parsingResult != null) {
-                    ((ParsingResultAccessor)result)._$PINPOINT$_setParsingResult(parsingResult);
-                } else {
-                    if (logger.isErrorEnabled()) {
-                        logger.error("sqlParsing fail. parsingResult is null sql:{}", sql);
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
-    public void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) {
-        if (result instanceof ParsingResultAccessor) {
-            ParsingResult parsingResult = ((ParsingResultAccessor)result)._$PINPOINT$_getParsingResult();
-            recorder.recordSqlParsingResult(parsingResult);
-        }
-        recorder.recordException(throwable);
-        recorder.recordApi(methodDescriptor);
-    }
-}
diff --git a/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/interceptor/PostgreSqlPreparedStatementCreateInterceptor2.java b/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/interceptor/PostgreSqlPreparedStatementCreateInterceptor2.java
deleted file mode 100644
index 6a5c18c0faa5..000000000000
--- a/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/interceptor/PostgreSqlPreparedStatementCreateInterceptor2.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2014 NAVER Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.navercorp.pinpoint.plugin.jdbc.postgresql.interceptor;
-
-import com.navercorp.pinpoint.bootstrap.context.*;
-import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin;
-import com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor;
-import com.navercorp.pinpoint.bootstrap.plugin.jdbc.ParsingResultAccessor;
-import com.navercorp.pinpoint.bootstrap.plugin.jdbc.UnKnownDatabaseInfo;
-import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils;
-
-/**
- * @author Brad Hong
- */
-// #1375 Workaround java level Deadlock
-// https://oss.navercorp.com/pinpoint/pinpoint-naver/issues/1375
-//@TargetMethods({
-//        @TargetMethod(name="prepareStatement", paramTypes={ "java.lang.String", "int" }),
-//        @TargetMethod(name="prepareStatement", paramTypes={ "java.lang.String", "int[]" }),
-//        @TargetMethod(name="prepareStatement", paramTypes={ "java.lang.String", "java.lang.String[]" }),
-//        @TargetMethod(name="prepareStatement", paramTypes={ "java.lang.String", "int", "int" })
-//})
-public class PostgreSqlPreparedStatementCreateInterceptor2 extends SpanEventSimpleAroundInterceptorForPlugin {
-
-    public PostgreSqlPreparedStatementCreateInterceptor2(TraceContext context, MethodDescriptor descriptor) {
-        super(context, descriptor);
-    }
-
-    @Override
-    public void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args)  {
-        DatabaseInfo databaseInfo = null;
-        if (target instanceof DatabaseInfoAccessor) {
-            databaseInfo = ((DatabaseInfoAccessor)target)._$PINPOINT$_getDatabaseInfo();
-        }
-
-        if (databaseInfo == null) {
-            databaseInfo = UnKnownDatabaseInfo.INSTANCE;
-        }
-        
-        recorder.recordServiceType(databaseInfo.getType());
-        recorder.recordEndPoint(databaseInfo.getMultipleHost());
-        recorder.recordDestinationId(databaseInfo.getDatabaseId());
-    }
-
-    @Override
-    protected void prepareAfterTrace(Object target, Object[] args, Object result, Throwable throwable) {
-        final boolean success = InterceptorUtils.isSuccess(throwable);
-        if (success) {
-            if (target instanceof DatabaseInfoAccessor) {
-                // set databaseInfo to PreparedStatement only when preparedStatement is generated successfully.
-                DatabaseInfo databaseInfo = ((DatabaseInfoAccessor)target)._$PINPOINT$_getDatabaseInfo();
-                if (databaseInfo != null) {
-                    if (result instanceof DatabaseInfoAccessor) {
-                        ((DatabaseInfoAccessor)result)._$PINPOINT$_setDatabaseInfo(databaseInfo);
-                    }
-                }
-            }
-            if (result instanceof ParsingResultAccessor) {
-                // 1. Don't check traceContext. preparedStatement can be created in other thread.
-                // 2. While sampling is active, the thread which creates preparedStatement could not be a sampling target. So record sql anyway. 
-                String sql = (String) args[0];
-                ParsingResult parsingResult = traceContext.parseSql(sql);
-                if (parsingResult != null) {
-                    ((ParsingResultAccessor)result)._$PINPOINT$_setParsingResult(parsingResult);
-                } else {
-                    if (logger.isErrorEnabled()) {
-                        logger.error("sqlParsing fail. parsingResult is null sql:{}", sql);
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
-    public void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) {
-        if (result instanceof ParsingResultAccessor) {
-            ParsingResult parsingResult = ((ParsingResultAccessor)result)._$PINPOINT$_getParsingResult();
-            recorder.recordSqlParsingResult(parsingResult);
-        }
-        recorder.recordException(throwable);
-        recorder.recordApi(methodDescriptor);
-    }
-}
diff --git a/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/interceptor/PostgreSqlPreparedStatementCreateInterceptor3.java b/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/interceptor/PostgreSqlPreparedStatementCreateInterceptor3.java
deleted file mode 100644
index aefc7d19a8d5..000000000000
--- a/plugins/postgresql-jdbc/src/main/java/com/navercorp/pinpoint/plugin/jdbc/postgresql/interceptor/PostgreSqlPreparedStatementCreateInterceptor3.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2014 NAVER Corp.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.navercorp.pinpoint.plugin.jdbc.postgresql.interceptor;
-
-import com.navercorp.pinpoint.bootstrap.context.*;
-import com.navercorp.pinpoint.bootstrap.interceptor.SpanEventSimpleAroundInterceptorForPlugin;
-import com.navercorp.pinpoint.bootstrap.plugin.jdbc.DatabaseInfoAccessor;
-import com.navercorp.pinpoint.bootstrap.plugin.jdbc.ParsingResultAccessor;
-import com.navercorp.pinpoint.bootstrap.plugin.jdbc.UnKnownDatabaseInfo;
-import com.navercorp.pinpoint.bootstrap.util.InterceptorUtils;
-
-/**
- * @author Brad Hong
- */
-// #1375 Workaround java level Deadlock
-// https://oss.navercorp.com/pinpoint/pinpoint-naver/issues/1375
-//@TargetMethods({
-//        @TargetMethod(name="prepareStatement", paramTypes={ "java.lang.String", "int", "int", "int" })
-//})
-public class PostgreSqlPreparedStatementCreateInterceptor3 extends SpanEventSimpleAroundInterceptorForPlugin {
-
-    public PostgreSqlPreparedStatementCreateInterceptor3(TraceContext context, MethodDescriptor descriptor) {
-        super(context, descriptor);
-    }
-
-    @Override
-    public void doInBeforeTrace(SpanEventRecorder recorder, Object target, Object[] args)  {
-        DatabaseInfo databaseInfo = null;
-        if (target instanceof DatabaseInfoAccessor) {
-            databaseInfo = ((DatabaseInfoAccessor)target)._$PINPOINT$_getDatabaseInfo();
-        }
-
-        if (databaseInfo == null) {
-            databaseInfo = UnKnownDatabaseInfo.INSTANCE;
-        }
-        
-        recorder.recordServiceType(databaseInfo.getType());
-        recorder.recordEndPoint(databaseInfo.getMultipleHost());
-        recorder.recordDestinationId(databaseInfo.getDatabaseId());
-    }
-
-    @Override
-    protected void prepareAfterTrace(Object target, Object[] args, Object result, Throwable throwable) {
-        final boolean success = InterceptorUtils.isSuccess(throwable);
-        if (success) {
-            if (target instanceof DatabaseInfoAccessor) {
-                // set databaseInfo to PreparedStatement only when preparedStatement is generated successfully.
-                DatabaseInfo databaseInfo = ((DatabaseInfoAccessor)target)._$PINPOINT$_getDatabaseInfo();
-                if (databaseInfo != null) {
-                    if (result instanceof DatabaseInfoAccessor) {
-                        ((DatabaseInfoAccessor)result)._$PINPOINT$_setDatabaseInfo(databaseInfo);
-                    }
-                }
-            }
-            if (result instanceof ParsingResultAccessor) {
-                // 1. Don't check traceContext. preparedStatement can be created in other thread.
-                // 2. While sampling is active, the thread which creates preparedStatement could not be a sampling target. So record sql anyway. 
-                String sql = (String) args[0];
-                ParsingResult parsingResult = traceContext.parseSql(sql);
-                if (parsingResult != null) {
-                    ((ParsingResultAccessor)result)._$PINPOINT$_setParsingResult(parsingResult);
-                } else {
-                    if (logger.isErrorEnabled()) {
-                        logger.error("sqlParsing fail. parsingResult is null sql:{}", sql);
-                    }
-                }
-            }
-        }
-    }
-
-    @Override
-    public void doInAfterTrace(SpanEventRecorder recorder, Object target, Object[] args, Object result, Throwable throwable) {
-        if (result instanceof ParsingResultAccessor) {
-            ParsingResult parsingResult = ((ParsingResultAccessor)result)._$PINPOINT$_getParsingResult();
-            recorder.recordSqlParsingResult(parsingResult);
-        }
-        recorder.recordException(throwable);
-        recorder.recordApi(methodDescriptor);
-    }
-}
diff --git a/pom.xml b/pom.xml
index fa363ab1d371..1289a392d151 100644
--- a/pom.xml
+++ b/pom.xml
@@ -402,9 +402,9 @@
                 <version>5.1.20</version>
             </dependency>
             <dependency>
-                <groupId>postgresql</groupId>
+                <groupId>org.postgresql</groupId>
                 <artifactId>postgresql</artifactId>
-                <version>9.1-901-1.jdbc4</version>
+                <version>9.4.1207</version>
             </dependency>
             <dependency>
                 <groupId>net.sourceforge.jtds</groupId>
