
/**
 *  PURPOSE  : Home screen confirm comp
 *  AUTHOR   : Mrunalini Sinkar
 */

package ibase.webitm.ejb.sys;

import ibase.system.config.ConnDriver;
import ibase.utility.BaseLogger;
import ibase.webitm.ejb.ActionHandlerEJB;
import ibase.webitm.ejb.ITMDBAccessEJB;
import ibase.webitm.ejb.ValidatorEJB;
import ibase.webitm.utility.GenericUtility;
import ibase.webitm.utility.ITMException;
import java.rmi.RemoteException;
import java.sql.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import ibase.webitm.utility.TransIDGenerator;
import ibase.utility.CommonConstants;
import ibase.utility.E12GenericUtility;
import ibase.utility.UserInfoBean;

public class ManageSqlConf extends ActionHandlerEJB {
	int reUpdateCnt = 0;
	String sqlError = "";

	public String confirm(String tranId, String xtraParams, String forcedFlag) throws RemoteException, ITMException {
		System.out.println("HeaderDetailConf Called!!!!!!!.......gsb .[" + tranId + "]");
		System.out.println("xtraParams !!!!!........[" + xtraParams + "]");

		String enterprise = getUserInfo().getEnterprise();
		enterprise = enterprise.trim();
		System.out.println("enterprise !!!!!........[" + enterprise + "]");

		boolean isError = false;

		String applDB = "", enterprises = "";
		String sql = "";
		String requestID = "";

		ResultSet rs = null;
		PreparedStatement pstmt = null;
		Connection con = null;
		String errString = "";
		String schemaName = "";
		String enterpriseSQL = "";
		ITMDBAccessEJB itmdbAccessLocal = null;
		boolean isThisObject = false;
		try {

			itmdbAccessLocal = new ITMDBAccessEJB();

			GenericUtility genericUtility = GenericUtility.getInstance();
			con = getConnection();
			con.setAutoCommit(false);
			String userId = checkNull(genericUtility.getValueFromXTRA_PARAMS(xtraParams, "loginCode"));
			String chgTerm = checkNull(genericUtility.getValueFromXTRA_PARAMS(xtraParams, "termId"));
			// Changes Start -- 13 Nov AJIT

			// After fetching applDB, enterprises, requestID
			System.out.println("Checking exec_rights dependency for tran_id gsb 75: " + tranId);

			String execRights = "";
			String tranIdRef = "";
			String selectedEnterprise = "";
			String confirmed = "";

			String checkSql = "SELECT tran_id__ref,EXEC_RIGHTS,enterprises,confirmed FROM SQL_CHANGES WHERE TRAN_ID = ?";
			pstmt = con.prepareStatement(checkSql);
			pstmt.setString(1, tranId);
			rs = pstmt.executeQuery();
			if (rs.next()) {
				tranIdRef = checkNull(rs.getString("tran_id__ref"));
				execRights = checkNull(rs.getString("EXEC_RIGHTS"));
				selectedEnterprise = checkNull(rs.getString("enterprises"));
				confirmed = checkNull(rs.getString("confirmed"));

			}
			if (rs != null) {
				rs.close();
				rs = null;
			}
			if (pstmt != null) {
				pstmt.close();
				pstmt = null;
			}

			if(execRights.trim().length()==0){
                BaseLogger.log("3", null, null, "Blank Execution Rights");
				errString = itmdbAccessLocal.getErrorString("confirmed", "MSQLBER", "", "", con);
				return errString;	
			}
			if (confirmed.trim().equalsIgnoreCase("Y")) {
				BaseLogger.log("3", null, null, "Transaction is already confirmed Tran ID:: " + tranId);
				errString = itmdbAccessLocal.getErrorString("confirmed", "VTCICONF1", "", "", con);
				return errString;
			}
			// Commented by Ajit D. on 03-DEC-25 -- START
			// if ("Q".equalsIgnoreCase(execRights)) {
			// System.out.println("This transaction has exec_rights = 'D'");
			// if(!enterprise.equalsIgnoreCase(selectedEnterprise.trim())) {
			// System.out.println("Enterprise Mismatch "+selectedEnterprise);
			// errString = itmdbAccessLocal.getErrorString("confirmed", "ENTMIS",
			// "","",con);
			// return errString; // Stop execution here
			// }
			// }
			// Commented by Ajit D. on 03-DEC-25 -- END

			// Comment out the validation block on confirmation of QC transaction by Ajit on
			// 20-APRIL[START]
			/*
			 * if ("Q".equalsIgnoreCase(execRights)) {
			 * System.out.
			 * println("This transaction has exec_rights = 'Q', checking for dependent 'D' confirmation..."
			 * );
			 * // if(!enterprise.equalsIgnoreCase(selectedEnterprise.trim())) {
			 * // System.out.println("Enterprise Mismatch  "+selectedEnterprise);
			 * // errString = itmdbAccessLocal.getErrorString("confirmed", "ENTMIS",
			 * "","",con);
			 * // return errString; // Stop execution here
			 * // }
			 * 
			 * // Fixed by Gagan B on 05-MAR-26 - using parameterized query to prevent SQL
			 * injection
			 * String qCheckSql =
			 * "SELECT CONFIRMED FROM SQL_CHANGES WHERE EXEC_RIGHTS = 'D' AND tran_id__ref = ?"
			 * ;
			 * pstmt = con.prepareStatement(qCheckSql);
			 * pstmt.setString(1, tranIdRef);
			 * rs = pstmt.executeQuery();
			 * 
			 * boolean qConfirmed = false;
			 * if (rs.next()) {
			 * String confirmedFlag = checkNull(rs.getString("CONFIRMED"));
			 * if ("Y".equalsIgnoreCase(confirmedFlag)) {
			 * qConfirmed = true;
			 * }
			 * }
			 * 
			 * if (rs != null) {
			 * rs.close();
			 * rs = null;
			 * }
			 * if (pstmt != null) {
			 * pstmt.close();
			 * pstmt = null;
			 * }
			 * 
			 * if (!qConfirmed) {
			 * System.out.
			 * println("Cannot confirm this transaction. The dependent record with exec_rights = 'Q' is not yet confirmed."
			 * );
			 * errString = itmdbAccessLocal.getErrorString("confirmed", "MSDNCONF",
			 * "","",con);
			 * return errString; // Stop execution here
			 * }
			 * }
			 */
			// Comment out the validation block on confirmation of QC transaction by Ajit on
			// 20-APRIL[START]

			// Added for PILOT: P transaction can only be confirmed after Q (QC) is
			// confirmed
			if ("P".equalsIgnoreCase(execRights)) {
				System.out
						.println("This transaction has exec_rights = 'P', checking for dependent 'Q' confirmation...");

				// Fixed by Gagan B on 05-MAR-26 - using parameterized query to prevent SQL
				// injection
				String pCheckSql = "SELECT CONFIRMED FROM SQL_CHANGES WHERE EXEC_RIGHTS = 'Q' AND tran_id__ref = ?";
				pstmt = con.prepareStatement(pCheckSql);
				pstmt.setString(1, tranIdRef);
				rs = pstmt.executeQuery();

				boolean qConfirmedForPilot = false;
				if (rs.next()) {
					String confirmedFlag = checkNull(rs.getString("CONFIRMED"));
					if ("Y".equalsIgnoreCase(confirmedFlag)) {
						qConfirmedForPilot = true;
					}
				}

				if (rs != null) {
					rs.close();
					rs = null;
				}
				if (pstmt != null) {
					pstmt.close();
					pstmt = null;
				}

				if (!qConfirmedForPilot) {
					System.out.println(
							"Cannot confirm PILOT transaction. The dependent QC record with exec_rights = 'Q' is not yet confirmed.");
					errString = itmdbAccessLocal.getErrorString("confirmed", "MSQNCONF", "", "", con);
					return errString; // Stop execution here
				}
			}



			// Added for CLIENT DEV: C transaction can only be confirmed after P (PILOT) is
			// confirmed
			if ("C".equalsIgnoreCase(execRights)) {
				System.out
						.println("This transaction has exec_rights = 'C', checking for dependent 'C' confirmation...");

				
				String cCheckSql = "SELECT CONFIRMED FROM SQL_CHANGES WHERE EXEC_RIGHTS = 'P' AND tran_id__ref = ?";
				pstmt = con.prepareStatement(cCheckSql);
				pstmt.setString(1, tranIdRef);
				rs = pstmt.executeQuery();

				boolean pConfirmedForClientDev = false;
				if (rs.next()) {
					String confirmedFlag = checkNull(rs.getString("CONFIRMED"));
					if ("Y".equalsIgnoreCase(confirmedFlag)) {
						pConfirmedForClientDev = true;
					}
				}

				if (rs != null) {
					rs.close();
					rs = null;
				}
				if (pstmt != null) {
					pstmt.close();
					pstmt = null;
				}

				if (!pConfirmedForClientDev) {
					System.out.println(
							"Cannot confirm Client Dev transaction. The dependent Pilot record with exec_rights = 'P' is not yet confirmed.");
					errString = itmdbAccessLocal.getErrorString("confirmed", "MSQLPNC", "", "", con);
					return errString; // Stop execution here
				}
			}


			// Changes Start -- 13 Nov AJIT (Condition for exec_rights = 'A')
			if ("A".equalsIgnoreCase(execRights)) {
				System.out.println(
						"This transaction has exec_rights = 'A', checking if dependent transactions are confirmed...");

				// Updated to include 'P' (PILOT) in the dependency check along with 'D' (Dev)
				// and 'Q' (QC)
				String depCheckSql = "SELECT TRAN_ID,TRAN_ID__REF, CONFIRMED FROM SQL_CHANGES " +
						"WHERE TRAN_ID__REF = ? AND EXEC_RIGHTS IN ('Q', 'P')";
				pstmt = con.prepareStatement(depCheckSql);
				pstmt.setString(1, tranId);
				rs = pstmt.executeQuery();

				boolean recordFound = false;
				boolean unconfirmedFound = false;
				String pendingTranId = "";

				while (rs.next()) {
					recordFound = true;

					String confirmedFlag = checkNull(rs.getString("CONFIRMED"));
					String depTranId = checkNull(rs.getString("TRAN_ID"));

					// If any dependent (D or Q) is not confirmed → block confirmation
					if (!"Y".equalsIgnoreCase(confirmedFlag)) {
						unconfirmedFound = true;
						pendingTranId = depTranId;
					}
				}

				if (rs != null) {
					rs.close();
					rs = null;
				}
				if (pstmt != null) {
					pstmt.close();
					pstmt = null;
				}

				// Added the code to fetch the Executive Approval value for Main transaction on
				// 21-APR[START]
				String execAprv = "";
				String wfStatus = "";
				String execAprvSql = "SELECT EXEC_APRV, WF_STATUS FROM SQL_CHANGES " +
						"WHERE TRAN_ID = ?";
				pstmt = con.prepareStatement(execAprvSql);
				pstmt.setString(1, tranIdRef);
				rs = pstmt.executeQuery();

				while (rs.next()) {
					execAprv = checkNull(rs.getString("EXEC_APRV"));
					wfStatus = checkNull(rs.getString("WF_STATUS"));

				}
				System.out.println("execAprv: " + execAprv);
				System.out.println("wfStatus: " + wfStatus);

				if (rs != null) {
					rs.close();
					rs = null;
				}
				if (pstmt != null) {
					pstmt.close();
					pstmt = null;
				}

				// Added the code to fetch the Executive Approval value for Main transaction on
				// 21-APR[END]

				// No dependent D/Q records found → workflow not yet approved

				// Added the condition if executive approval value is "Y" then only check the
				// workflow weather approved or not 21-APRIL
				if (execAprv.trim().equalsIgnoreCase("Y")) {
					if (!wfStatus.trim().equalsIgnoreCase("A")) {
						System.out.println("Cannot confirm. Workflow not approved for tran_id: " + tranId);
						errString = itmdbAccessLocal.getErrorString("confirmed", "WRKFNA", "", "", con);
						return errString;
					}

				}

				// Dependent D or Q exists but NOT confirmed → return error
				if (unconfirmedFound) {
					System.out.println(
							"Cannot confirm. Dependent transaction [" + pendingTranId + "] is not yet confirmed.");
					errString = itmdbAccessLocal.getErrorString("confirmed", "MSPNCONF", "", "", con);
					return errString;
				}

				System.out.println("All dependent D and Q transactions are confirmed. Proceeding...");
			}

			// Changes End -- 13 Nov AJIT (Condition for exec_rights = 'A')

			// Changes End -- 13 Nov AJIT (Condition for exec_rights = 'A')

			// Changes End -- 13 Nov AJIT

			// HashMap<String,String> schemaListMap= new HashMap<String,String>();
			ArrayList<String> enterpriseArrayList = new ArrayList<>();
			sql = "SELECT APPL_DB,ENTERPRISES,REQ_ID FROM SQL_CHANGES WHERE TRAN_ID=?";
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, tranId);
			rs = pstmt.executeQuery();
			if (rs.next()) {
				applDB = checkNull(rs.getString("APPL_DB"));
				enterprises = checkNull(rs.getString("ENTERPRISES"));
				requestID = checkNull(rs.getString("REQ_ID"));

			}
			if (pstmt != null) {
				pstmt.close();
				pstmt = null;
			}
			if (rs != null) {
				rs.close();
				rs = null;
			}

			// All Enterprise Case
			if (applDB.equalsIgnoreCase("E")) {
				// Added by Gagan B. on 13-NOV-25 [make connection with Driver for ENTERPRISE]
				// -- START
				Connection entCon = null;
				ConnDriver connDriver = new ConnDriver();
				entCon = connDriver.getConnectDB("Driver");
				// Added by Gagan B. on 13-NOV-25 [make connection with Driver for ENTERPRISE]
				// -- END

				// sql = "SELECT SCHEMA_NAME,ENTERPRISE FROM ENTERPRISE WHERE SCHEMA_NAME IS NOT
				// NULL";
				sql = "SELECT ENTERPRISE FROM ENTERPRISE WHERE SCHEMA_NAME IS NOT NULL";
				pstmt = entCon.prepareStatement(sql);
				rs = pstmt.executeQuery();
				while (rs.next()) {
					// schemaName = checkNull( rs.getString("SCHEMA_NAME") );
					// enterpriseSQL = checkNull( rs.getString("ENTERPRISE") );
					// schemaListMap.put(schemaName,enterpriseSQL);
					enterpriseArrayList.add(checkNull(rs.getString("ENTERPRISE")));
				}

				if (pstmt != null) {
					pstmt.close();
					pstmt = null;
				}
				if (rs != null) {
					rs.close();
					rs = null;
				}
				// Added by Gagan B. on 13-NOV-25 [make connection with Driver for ENTERPRISE]
				// -- START
				if (entCon != null && !entCon.isClosed()) {
					System.out.println("Closing entCon ");
					entCon.close();
					entCon = null;
					connDriver = null;
				}
				// Added by Gagan B. on 13-NOV-25 [make connection with Driver for ENTERPRISE]
				// -- END
			}

			if (applDB.equalsIgnoreCase("S")) {
				// Added by Gagan B. on 13-NOV-25 [make connection with Driver for ENTERPRISE]
				// -- START
				Connection entCon = null;
				ConnDriver connDriver = new ConnDriver();
				entCon = connDriver.getConnectDB("Driver");
				// Added by Gagan B. on 13-NOV-25 [make connection with Driver for ENTERPRISE]
				// -- END
				String EnterPriseInFormat = getFormattedStringBuff(enterprises);
				sql = "SELECT SCHEMA_NAME,ENTERPRISE FROM ENTERPRISE WHERE ENTERPRISE IN(" + EnterPriseInFormat + ") ";
				pstmt = entCon.prepareStatement(sql);
				rs = pstmt.executeQuery();
				while (rs.next()) {
					// schemaName = checkNull( rs.getString("SCHEMA_NAME") );
					// enterpriseSQL = checkNull( rs.getString("ENTERPRISE") );
					// schemaListMap.put(schemaName,enterpriseSQL);

					enterpriseArrayList.add(checkNull(rs.getString("ENTERPRISE")));
				}
				if (pstmt != null) {
					pstmt.close();
					pstmt = null;
				}
				if (rs != null) {
					rs.close();
					rs = null;
				}
				// Added by Gagan B. on 13-NOV-25 [make connection with Driver for ENTERPRISE]
				// -- START
				if (entCon != null && !entCon.isClosed()) {
					System.out.println("Closing entCon ");
					entCon.close();
					entCon = null;
					connDriver = null;
				}
				// Added by Gagan B. on 13-NOV-25 [make connection with Driver for ENTERPRISE]
				// -- END
			}

			sql = "SELECT ORA_STMNT,LINE_NO FROM SQL_CHANGES_DET WHERE TRAN_ID=?";
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, tranId);
			rs = pstmt.executeQuery();
			while (rs.next()) {
				String oracleStatment = checkNull(rs.getString("ORA_STMNT"));
				String linNo = checkNull(rs.getString("LINE_NO"));

				System.out.println("oracle execute statment[" + oracleStatment + "]");
				if (oracleStatment.lastIndexOf(";") != -1) {
					if (!oracleStatment.toUpperCase().startsWith("CREATE")) {
						BaseLogger.log("3", null, null, "Inside if oracleStatment [" + oracleStatment + "]");// Added by
																												// Ashish.J
						int endIndex = oracleStatment.lastIndexOf(";");
						oracleStatment = oracleStatment.substring(0, endIndex);
					} else if (oracleStatment.toUpperCase().startsWith("CREATE TABLE")) {
						BaseLogger.log("3", null, null, "Inside else oracleStatment [" + oracleStatment + "]");// Added
																												// by
																												// Ashish.J
						int endIndex = oracleStatment.lastIndexOf(";");
						oracleStatment = oracleStatment.substring(0, endIndex);
					}

				}
				if (oracleStatment.toUpperCase().startsWith("CREATE")
						&& !oracleStatment.toUpperCase().startsWith("CREATE TABLE")) {
					BaseLogger.log("3", null, null, "Inside is the object oracleStatment [" + oracleStatment + "]");// Added
																													// by
																													// Ashish.J
					isThisObject = true;

				}

				if ("Q".equalsIgnoreCase(execRights) || "C".equalsIgnoreCase(execRights)
						|| "P".equalsIgnoreCase(execRights)) {
					BaseLogger.log(
							"3",
							null,
							null,
							"For DEV, QC and PILOT transaction :: SQL :: " + oracleStatment +
									" :: enterprises :: [" + selectedEnterprise + "]");
					String QcDevEnterprise = "";
					String mainEnterprise = "";
					String dbMainForPilot = "";
					String dbClientDev = "";


					BaseLogger.log("3", null, null, "execRights [" + execRights + "]");
					if ("Q".equalsIgnoreCase(execRights)) {
						QcDevEnterprise = "APPVISQC";
						BaseLogger.log(
										"1",
										null,
										null,
										"Executing for QC ");
						// D/Q: enterprise code matches ENTERPRISE table directly
						processSqlForEnterprise(
								con,
								QcDevEnterprise,
								oracleStatment,
								tranId,
								linNo,
								requestID,
								userId,
								chgTerm);
					}

					// For PILOT, look up DB_PILOT from enterprise table using the main
					// transaction's enterprise (via TRAN_ID__REF)
					else if ("P".equalsIgnoreCase(execRights) || "C".equalsIgnoreCase(execRights)) {
						// First, get the enterprise from the main (A) transaction
						String mainEntSql = "SELECT ENTERPRISES FROM SQL_CHANGES WHERE TRAN_ID = ?";
						try (PreparedStatement mainEntPstmt = con.prepareStatement(mainEntSql)) {
							mainEntPstmt.setString(1, tranIdRef);
							try (ResultSet mainEntRs = mainEntPstmt.executeQuery()) {
								if (mainEntRs.next()) {
									mainEnterprise = checkNull(mainEntRs.getString("ENTERPRISES"));
								}
							}
						}

						BaseLogger.log("3", null, null, "mainEnterprise [" + mainEnterprise + "]");// Added
						if (mainEnterprise.isEmpty()) {
							throw new ITMException(new Exception(
									"Main transaction enterprise not found for TRAN_ID__REF: " + tranIdRef));
						}

						String[] enterprisesArr = mainEnterprise.split(",");

						for (String enterpriser : enterprisesArr) {

							// String placeholders = String.join(",",
							// Collections.nCopies(enterprisesArr.length, "?"));
							// Use the main transaction's enterprise to look up DB_PILOT and DB_MAIN
							String pilotDbLookupSql = "SELECT DB_PILOT, DB_MAIN, DB_DEV FROM ENTERPRISE WHERE ENTERPRISE IN (?)";
							try (PreparedStatement pilotLookupPstmt = con.prepareStatement(pilotDbLookupSql)) {

								pilotLookupPstmt.setString(1, enterpriser);

								try (ResultSet pilotLookupRs = pilotLookupPstmt.executeQuery()) {
									while (pilotLookupRs.next()) {
										QcDevEnterprise = checkNull(pilotLookupRs.getString("DB_PILOT"));
										dbMainForPilot = checkNull(pilotLookupRs.getString("DB_MAIN"));
										dbClientDev = checkNull(pilotLookupRs.getString("DB_DEV"));

									}
								}
							}
							if (QcDevEnterprise.isEmpty()) {
								throw new ITMException(
										new Exception("DB_PILOT not found for enterprise: " + mainEnterprise));
							}
							BaseLogger.log("3", null, null, "PILOT execution: using DB_PILOT [" + QcDevEnterprise
									+ "] from main enterprise [" + mainEnterprise + "]");

							Savepoint entSavepoint = null;

							try {
								// ENTERPRISE-LEVEL SAVEPOINT
								entSavepoint = con.setSavepoint("SP_" + QcDevEnterprise);

								if ("P".equalsIgnoreCase(execRights)) {
									// PILOT: DB_PILOT is a schema name, not an enterprise code,
									// so processSqlForEnterprise cannot look it up. Instead, apply
									// schema injection and call executeAndLog directly using the
									// main enterprise for connection lookup and DB_PILOT as target schema.
									String pilotInputSql = oracleStatment;
									String upperSqlP = checkNull(pilotInputSql).trim().toUpperCase();
									boolean isPlSqlBodyP = upperSqlP.startsWith("CREATE OR REPLACE FUNCTION")
											|| upperSqlP.startsWith("CREATE FUNCTION")
											|| upperSqlP.startsWith("CREATE OR REPLACE PROCEDURE")
											|| upperSqlP.startsWith("CREATE PROCEDURE")
											|| upperSqlP.startsWith("CREATE OR REPLACE PACKAGE")
											|| upperSqlP.startsWith("CREATE PACKAGE")
											|| upperSqlP.startsWith("CREATE OR REPLACE TYPE")
											|| upperSqlP.startsWith("CREATE TYPE")
											|| upperSqlP.startsWith("CREATE OR REPLACE TRIGGER")
											|| upperSqlP.startsWith("CREATE TRIGGER")
											|| upperSqlP.contains("NONEDITIONABLE");
									if (!isPlSqlBodyP) {
										pilotInputSql = injectSchemaPlaceholderSafe(pilotInputSql);
									}

									executeAndLog(
											QcDevEnterprise, // DB_PILOT schema name (target schema for SQL)
											pilotInputSql,
											tranId,
											enterpriser, // main enterprise code (for connection lookup and logging)
											linNo,
											requestID,
											userId,
											chgTerm,
											dbMainForPilot, // DB_MAIN (for synonym/grant references)
											"P",
											false);
								} else if ("C".equalsIgnoreCase(execRights)) {
									// CLIENT DEV: DB_DEV is a schema name, not an enterprise code,
									// so processSqlForEnterprise cannot look it up. Instead, apply
									// schema injection and call executeAndLog directly using the
									// main enterprise for connection lookup and DB_DEV as target schema.
									String pilotInputSql = oracleStatment;
									String upperSqlP = checkNull(pilotInputSql).trim().toUpperCase();
									boolean isPlSqlBodyP = upperSqlP.startsWith("CREATE OR REPLACE FUNCTION")
											|| upperSqlP.startsWith("CREATE FUNCTION")
											|| upperSqlP.startsWith("CREATE OR REPLACE PROCEDURE")
											|| upperSqlP.startsWith("CREATE PROCEDURE")
											|| upperSqlP.startsWith("CREATE OR REPLACE PACKAGE")
											|| upperSqlP.startsWith("CREATE PACKAGE")
											|| upperSqlP.startsWith("CREATE OR REPLACE TYPE")
											|| upperSqlP.startsWith("CREATE TYPE")
											|| upperSqlP.startsWith("CREATE OR REPLACE TRIGGER")
											|| upperSqlP.startsWith("CREATE TRIGGER")
											|| upperSqlP.contains("NONEDITIONABLE");
									if (!isPlSqlBodyP) {
										pilotInputSql = injectSchemaPlaceholderSafe(pilotInputSql);
									}

									executeAndLog(
											dbClientDev, // DB_DEV schema name (target schema for SQL)
											pilotInputSql,
											tranId,
											enterpriser, // main enterprise code (for connection lookup and logging)
											linNo,
											requestID,
											userId,
											chgTerm,
											dbMainForPilot, // DB_MAIN (for synonym/grant references)
											"C",
											false);
								}

								// commit enterprise success
								con.commit();

							} catch (Exception e) {

								// rollback ONLY this enterprise
								if (entSavepoint != null) {
									con.rollback(entSavepoint);
								}

								BaseLogger.log(
										"1",
										null,
										null,
										"Enterprise execution failed :: " + QcDevEnterprise + " :: " + e.getMessage());

								// continue next enterprise
							}
						}
					} else {
						
					}
				}
				if ("A".equalsIgnoreCase(execRights)) {

					BaseLogger.log(
							"3",
							null,
							null,
							"Multiple schema execution :: SQL :: " + oracleStatment +
									" :: enterprises :: [" + selectedEnterprise + "]");

					// VERY IMPORTANT
					con.setAutoCommit(false);
                    BaseLogger.log("1",null,null,"enterpriseArrayList :: " + enterpriseArrayList );

					String[] enterpriseArr = null;
					enterpriseArr = enterpriseArrayList.toArray(new String[0]);

					// Commented by Gagan B. on 02-FEB-26 to resolve the issue of when multiple
					// enterprise selected using checkbox, SQL only got executed in one single
					// enterprise.
					/*
					 * if(applDB.equalsIgnoreCase("S")) {
					 * enterpriseArr = enterpriseArrayList.get(0).split(",");
					 * }else if(applDB.equalsIgnoreCase("E")){
					 * 
					 * // Values are NOT comma-separated → copy list directly
					 * enterpriseArr = enterpriseArrayList.toArray(new String[0]);
					 * }
					 */
                       BaseLogger.log("1",null,null,"enterpriseArr :: " + Arrays.toString(enterpriseArr) );
					for (String enterpriseForExec : enterpriseArr) {
                       BaseLogger.log("1",null,null,"enterpriseForExec :: " + enterpriseForExec );

						String ent = enterpriseForExec.trim();
						if (ent.isEmpty()) {
							continue;
						}

						Savepoint entSavepoint = null;

						try {
							// ✅ ENTERPRISE-LEVEL SAVEPOINT
							entSavepoint = con.setSavepoint("SP_" + ent);

							processSqlForEnterprise(
									con,
									ent,
									oracleStatment,
									tranId,
									linNo,
									requestID,
									userId,
									chgTerm);

							// ✅ commit enterprise success
							con.commit();

						} catch (Exception e) {

							// ❌ rollback ONLY this enterprise
							if (entSavepoint != null) {
								con.rollback(entSavepoint);
							}

							BaseLogger.log("1", null, null,
									"Enterprise execution failed :: " + ent + " :: " + e.getMessage());

							// continue next enterprise
						}
					}

					continue;
				}

				// if( oracleStatment.toUpperCase().startsWith("ALTER") ||
				// oracleStatment.toUpperCase().startsWith("INSERT INTO") ||
				// oracleStatment.toUpperCase().startsWith("UPDATE") ||
				// oracleStatment.toUpperCase().startsWith("DELETE"))
				// {

				// Commented by Ajit on 06-JAN-26
				// executeQueries(con,schemaListMap,
				// oracleStatment,tranId,linNo,requestID,userId,chgTerm,isThisObject) ;
				// }

			}
			if (pstmt != null) {
				pstmt.close();
				pstmt = null;
			}
			if (rs != null) {
				rs.close();
				rs = null;
			}

			String upSql = "UPDATE SQL_CHANGES SET CONFIRMED='Y',CONF_DATE=SYSDATE,EMP_CODE_APRV=?,EXECUTED='Y' WHERE TRAN_ID=?";
			pstmt = con.prepareStatement(upSql);
			pstmt.setString(1, userId);
			pstmt.setString(2, tranId);

			int updCnt = pstmt.executeUpdate();
			if (pstmt != null) {
				pstmt.close();
				pstmt = null;
			}
			System.out.println("update count is[" + updCnt + "]");
			if (updCnt > 0) {
				errString = itmdbAccessLocal.getErrorString("confirmed", "VTCONFIRM", "", "", con);
				System.out.println("errString is " + errString);

			}

			BaseLogger.log("1", null, null, "TRAN_ID__REF :: " + tranIdRef);
			BaseLogger.log("1", null, null, "execRights :: " + execRights);
			String upSqlRef = "UPDATE SQL_CHANGES SET TXN_STATUS = CASE " +
					"    WHEN ? = 'Q' THEN 'X' " +
					"    WHEN ? = 'P' THEN 'Y' " +
					"    WHEN ? = 'C' THEN 'E' " +
					"    WHEN ? = 'A' THEN 'Z' " +
					"    ELSE TXN_STATUS " +
					"END " +
					"WHERE TRAN_ID = ?";

			pstmt = con.prepareStatement(upSqlRef);
			pstmt.setString(1, execRights);
			pstmt.setString(2, execRights);
			pstmt.setString(3, execRights);
			pstmt.setString(4, execRights);
			pstmt.setString(5, tranIdRef);

			int updCntRef = pstmt.executeUpdate();

			if (pstmt != null) {
				pstmt.close();
				pstmt = null;
			}

			BaseLogger.log("1", null, null, "Txn Status update count is [" + updCntRef + "]");

			if (execRights.trim().equalsIgnoreCase("A")) {
				BaseLogger.log("1", null, null, "Transaction confirmed for live");

				String updateClosedDetailsSql = "update sql_changes set CLOSED_YN = 'Y',TXN_STATUS = 'C', CLOSED_BY = ?, CLOSED_DATE = SYSDATE where tran_id = ?";
				PreparedStatement updateClosedDetailsPs = con.prepareStatement(updateClosedDetailsSql);
				updateClosedDetailsPs.setString(1, userId);
				updateClosedDetailsPs.setString(2, tranIdRef);
				int updateClosedDetailsCount = updateClosedDetailsPs.executeUpdate();
				BaseLogger.log("1", null, null, "updateClosedDetailsCount:: [" + updateClosedDetailsCount + "]");

			}

		} catch (Exception e) {
			isError = true;
			try {
				con.rollback();
			} catch (Exception e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
			throw new ITMException(e);
		} finally {
			try {
				System.out.println("Commiting and Closing Connection..........");
				if (!(isError)) {
					System.out.println("inside finally if");
					con.commit();
					// errString = itmdbAccessLocal.getErrorString("","TEMCONFIRM",loginEmpCode);
					// errString = itmdbAccessLocal.getErrorString("confirmed", "TEMCONFIRM",
					// "","",con);
				} else {
					System.out.println("inside finally rollback else");
					con.rollback();
				}
				if (pstmt != null) {
					System.out.println("inside finally if pstmt ");

					pstmt.close();
					pstmt = null;
				}
				if (con != null && !con.isClosed()) {
					System.out.println("inside finally if con ");
					con.close();
					con = null;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		System.out.println("errString is +++:" + errString);
		return errString;
	}

	private String checkNull(String input) {
		if (input == null) {
			input = "";
		}
		return input;
	}

	private String getFormattedStringBuff(String data) {
		StringBuffer dataString = new StringBuffer();
		try {
			String[] dataArr = null;

			if (data.indexOf(",") == -1) {
				dataString.append("'" + data + "'");
			} else {
				dataArr = data.split(",");
				for (int i = 0; i < dataArr.length; i++) {
					if (i == 0) {
						dataString.append("'" + dataArr[i] + "'");
					} else {
						dataString.append(",");
						dataString.append("'" + dataArr[i] + "'");
					}
				}
			}
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return dataString.toString();
	}

	// Commented by Gagan B. on 13-NOV-25 -- START
	/*
	 * private int executeQueries(Connection connection,HashMap<String,String>
	 * schemaListMap, String Sql,String tranID,String lineNo,String requestID,String
	 * userId,String chgTerm,boolean isThisObjectType)
	 * {
	 * BaseLogger.log("3", null, null, "Inside executeQueries gsb1 [" + Sql + "]");
	 * BaseLogger.log("3", null, null, "Inside executeQueries schemaListMap [" +
	 * schemaListMap + "]");
	 * 
	 * 
	 * ConnDriver connDriver = new ConnDriver();
	 * Connection conn = null;
	 * Statement stmnt = null;
	 * int updateCount=0;
	 * CallableStatement callableStmt = null;
	 * String error = "";//Added by Ashish.J
	 * 
	 * try
	 * {
	 * System.out.println("isThisObjectType gsb----:::::["+isThisObjectType+"]");
	 * if(!schemaListMap.isEmpty())
	 * {
	 * Iterator<String> itr = schemaListMap.keySet().iterator();
	 * while (itr.hasNext())
	 * {
	 * String schema = itr.next();
	 * String enterprise = schemaListMap.get(schema);
	 * int updCount = 0;
	 * 
	 * try {
	 * conn = connDriver.getConnectDB(schema);
	 * } catch (Exception e) {
	 * error=e.getMessage();
	 * BaseLogger.log("3", null, null, "Inside catch of error..["+error+"]");
	 * insertIntoSqlExectionLog(connection,tranID,enterprise,lineNo,requestID,Sql,
	 * updCount, "E" , userId,chgTerm,error);
	 * }
	 * 
	 * if( conn == null )
	 * {
	 * BaseLogger.log("3", null, null, "Unable to get connection for gsb"
	 * + " [" + schema + "]");
	 * //throw new Exception("Unable to get connection for [" + schema + "]");
	 * }
	 * 
	 * 
	 * if(checkNull(Sql).trim().length() > 0)
	 * {
	 * BaseLogger.log("3", null, null, "is the object---[" + isThisObjectType +
	 * "]");
	 * 
	 * if(isThisObjectType)
	 * {
	 * BaseLogger.log("3", null, null, "is the object if [" + isThisObjectType +
	 * "]");
	 * String plsql = " begin " +
	 * " dbms_metadata.set_transform_param ( DBMS_METADATA.SESSION_TRANSFORM, 'SQLTERMINATOR', false ); "
	 * +
	 * " end; ";
	 * callableStmt = conn.prepareCall(plsql);
	 * callableStmt.execute();
	 * 
	 * }
	 * 
	 * try
	 * {
	 * BaseLogger.log("3", null, null, "Inside try....");//Added by Ashish.J
	 * 
	 * stmnt = conn.createStatement();
	 * updCount = stmnt.executeUpdate(Sql);
	 * error="";
	 * BaseLogger.log("3", null, null, "Inside try of error..["+error+"]");//Added
	 * by Ashish.J
	 * BaseLogger.log("3", null, null, "schema...["+schema+"]updateCnt to get Sql ["
	 * + updCount + "]");
	 * insertIntoSqlExectionLog(connection,tranID,enterprise,lineNo,requestID,Sql,
	 * updCount, "C" , userId,chgTerm,error);
	 * 
	 * }
	 * catch(SQLException ise)
	 * {
	 * error=ise.getMessage();//Added by Ashish.J
	 * BaseLogger.log("3", null, null, "Inside catch of error..["+error+"]");
	 * //insertIntoSqlExectionLog(connection,tranID,enterprise,lineNo,requestID,Sql,
	 * userId,chgTerm);
	 * BaseLogger.log("3", null, null, "Inside catch....");
	 * insertIntoSqlExectionLog(connection,tranID,enterprise,lineNo,requestID,Sql,
	 * updCount, "E" , userId,chgTerm,error);
	 * }//Added by Ashish.J
	 * 
	 * finally
	 * {
	 * if (stmnt != null)
	 * {
	 * stmnt.close();
	 * stmnt = null;
	 * }
	 * }
	 * }
	 * 
	 * 
	 * Thread.sleep(100);
	 * conn.commit();
	 * }
	 * }
	 * 
	 * 
	 * }
	 * catch (Exception e)
	 * {
	 * try
	 * {
	 * BaseLogger.log("3", null, null,
	 * "Excepotion in executeAlterQueries occured while executing Alter Queries>>>>"
	 * +
	 * E12GenericUtility.checkNull(e.getMessage()));
	 * //conn.rollback();
	 * }
	 * // catch (SQLException sqle)
	 * catch (Exception sqle)
	 * {
	 * BaseLogger.log("3", null, null,
	 * "SQLException executeAlterQueries occured during rollback:: " +
	 * sqle.getMessage());
	 * sqle.printStackTrace();
	 * }
	 * e.printStackTrace();
	 * }
	 * finally
	 * {
	 * try
	 * {
	 * if (callableStmt != null)
	 * {
	 * callableStmt.close();
	 * callableStmt = null;
	 * }
	 * if (conn != null)
	 * {
	 * conn.close();
	 * conn = null;
	 * }
	 * }
	 * catch (SQLException sqle)
	 * {
	 * BaseLogger.log("3", null, null,
	 * "SQLException executeAlterQueries inside finally:: "+ sqle.getMessage());
	 * sqle.printStackTrace();
	 * }
	 * }
	 * return updateCount;
	 * }
	 */
	// Commented by Gagan B. on 13-NOV-25 -- END

	/*
	 * Added by Gagan B. on 13-NOV-25 [modifications in method to optimize and
	 * properly handle cases when
	 * connection could not be made with any schema in case of All Enterprise] --
	 * START
	 */
	private int executeQueries(Connection connection, HashMap<String, String> schemaListMap, String Sql, String tranID,
			String lineNo, String requestID, String userId, String chgTerm, boolean isThisObjectType) {
		ConnDriver connDriver = new ConnDriver();

		int updateCount = 0;

		if (schemaListMap == null || schemaListMap.isEmpty()) {
			BaseLogger.log("3", null, null, "Schema list is empty, skipping execution.");
			return 0;
		}

		BaseLogger.log("3", null, null, "Inside executeQueries. SQL to run: [" + Sql + "]");
		BaseLogger.log("3", null, null, "Total schemas to process: [" + schemaListMap.size() + "]");

		// Iterate through each schema provided in the map.
		Iterator<String> itr = schemaListMap.keySet().iterator();
		while (itr.hasNext()) {
			String schema = itr.next();
			String enterprise = schemaListMap.get(schema);

			Connection conn = null;
			Statement stmnt = null;
			CallableStatement callableStmt = null;
			String error = "";
			int updCount = 0;

			try {
				BaseLogger.log("3", null, null, "Attempting to connect to schema: [" + schema + "]");
				conn = connDriver.getConnectDB(schema);

				if (conn == null) {
					throw new Exception("Unable to get a valid connection for schema [" + schema + "]");
				}

				if (checkNull(Sql).trim().length() > 0) {
					if (isThisObjectType) {
						BaseLogger.log("3", null, null, "Executing as object type for schema [" + schema + "]");
						String plsql = " begin " +
								" dbms_metadata.set_transform_param ( DBMS_METADATA.SESSION_TRANSFORM, 'SQLTERMINATOR', false ); "
								+
								" end; ";
						callableStmt = conn.prepareCall(plsql);
						callableStmt.execute();
					}

					try {
						stmnt = conn.createStatement();
						updCount = stmnt.executeUpdate(Sql);
						updateCount = updCount; // Set the return value to the latest count.
						error = ""; // Clear any previous error string

						BaseLogger.log("3", null, null,
								"SUCCESS for schema [" + schema + "]. Rows affected: [" + updCount + "]");
						insertIntoSqlExectionLog(connection, tranID, enterprise, lineNo, requestID, Sql, updCount, "C",
								userId, chgTerm, error);
					} catch (SQLException ise) {
						error = ise.getMessage();
						BaseLogger.log("3", null, null,
								"FAILURE (SQLException) for schema [" + schema + "]. Error: [" + error + "]");
						insertIntoSqlExectionLog(connection, tranID, enterprise, lineNo, requestID, Sql, updCount, "E",
								userId, chgTerm, error);
					}
				}

				if (conn != null) {
					conn.commit();
				}

			} catch (Exception e) {
				error = e.getMessage();
				BaseLogger.log("3", null, null,
						"FAILURE (General Exception) for schema [" + schema + "]. Error: [" + error + "]");
				e.printStackTrace(); // Good for server logs to see the full trace.

				try {
					insertIntoSqlExectionLog(connection, tranID, enterprise, lineNo, requestID, Sql, 0, "E", userId,
							chgTerm, error);
				} catch (Exception logEx) {
					BaseLogger.log("3", null, null, "CRITICAL: Failed to log error for schema [" + schema + "]");
					logEx.printStackTrace();
				}
			} finally {
				BaseLogger.log("3", null, null, "Cleaning up resources for schema [" + schema + "]");
				try {
					if (callableStmt != null) {
						callableStmt.close();
					}
					if (stmnt != null) {
						stmnt.close();
					}
					if (conn != null) {
						conn.close();
					}
				} catch (SQLException sqle) {
					BaseLogger.log("3", null, null,
							"SQLException during resource cleanup for schema [" + schema + "]: " + sqle.getMessage());
					sqle.printStackTrace();
				}
			}

			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				Thread.currentThread().interrupt(); // Restore the interrupted status
			}
		}
		return updateCount;
	}
	/*
	 * Added by Gagan B. on 13-NOV-25 [modifications in method to optimize and
	 * properly handle cases when
	 * connection could not be made with any schema in case of All Enterprise] --
	 * END
	 */

	// Added by Ashish.J one more parameter has added sql_exception
	private String insertIntoSqlExectionLog(Connection conn, String refTranID, String enterprise, String lineNo,
			String requestID, String Sql, int updateCnt, String status, String userId, String chgTerm, String error)
			throws ITMException, RemoteException {
		System.out.println("inside insertIntoSqlExectionLog method");
		String errorString = "";
		int insCount = 0;
		PreparedStatement pstmtIns = null;
		ITMDBAccessEJB itmdbAccessLocal = new ITMDBAccessEJB();
		try {
			System.out.println("inside try of method");
			System.out.println("Sql_log SQL :: " + Sql);

			GenericUtility genericUtility = GenericUtility.getInstance();
			String Aformat = genericUtility.getApplDateFormat();
			java.text.SimpleDateFormat dtf = new java.text.SimpleDateFormat(Aformat);
			String currDate = dtf.format(new java.util.Date());
			System.out.println("currDate --> [" + currDate + "]");
			System.out.println("insertIntoSqlExectionLog in --> [" + error + "]");
			String tranID = generateTranID(conn);
			String insSql = "INSERT INTO SQL_EXEC_LOG(TRAN_ID,REF_TRAN_ID,ENTERPRISE,LINE_NO,REQ_ID,ORA_STMNT,CHG_DATE,CHG_USER,CHG_TERM,RESULT,STATUS,SQL_EXCEPTION) "
					+ "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)";
			pstmtIns = conn.prepareStatement(insSql);
			pstmtIns.setString(1, tranID);

			pstmtIns.setString(2, refTranID);
			pstmtIns.setString(3, enterprise);
			pstmtIns.setString(4, lineNo);
			pstmtIns.setString(5, requestID);
			pstmtIns.setString(6, Sql);
			pstmtIns.setTimestamp(7,
					java.sql.Timestamp.valueOf(genericUtility.getValidDateTimeString(checkNull(currDate),
							genericUtility.getApplDateFormat(), genericUtility.getDBDateFormat()))); // Added by kailash
																										// on 24-04-18.
			pstmtIns.setString(8, userId);
			pstmtIns.setString(9, chgTerm);
			pstmtIns.setInt(10, updateCnt);
			pstmtIns.setString(11, status);
			pstmtIns.setString(12, error);

			insCount = pstmtIns.executeUpdate();// Added by Ashish.J one more parameter has added sql_exception
			System.out.println("insCount into strg_meet_items[" + lineNo + "] insCount= [" + insCount + "]");
			pstmtIns.clearParameters();
			if (pstmtIns != null) {
				pstmtIns.close();
				pstmtIns = null;
			}
		} catch (Exception e) {
			errorString = itmdbAccessLocal.getErrorString("confirmed", "CONFFAILED", "", "", conn);
			return errorString;
		} finally {
			{
				try {
					if (pstmtIns != null) {
						pstmtIns.close();
						pstmtIns = null;

					}

				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
		}

		return errorString;
	}

	public String CancelLogTransaction(String tranId, String xtraParams, String forcedFlag)
			throws RemoteException, ITMException {
		boolean isError = false;
		ResultSet rs = null;
		PreparedStatement pstmt = null;
		Connection con = null;
		ITMDBAccessEJB itmdbAccessLocal = null;
		String errString = "";
		String status = "";
		String refTranId = "";
		String profileId = "";
		UserInfoBean userInfo;
		try {
			userInfo = getUserInfo();
			itmdbAccessLocal = new ITMDBAccessEJB();

			GenericUtility genericUtility = GenericUtility.getInstance();
			String userId = checkNull(genericUtility.getValueFromXTRA_PARAMS(xtraParams, "loginCode"));

			con = getConnection();
			con.setAutoCommit(false);

			profileId = checkNull(userInfo.getProfileId());

			// Added condition if profileId is not MSADMIN return a validation
			if (!profileId.trim().equalsIgnoreCase("MSADMIN")) {
				BaseLogger.log("3", getUserInfo(), null, "Only Admin can close this transaction.");
				return itmdbAccessLocal.getErrorString("", "MSQLCNA", "", "", con);
			}

			String sql = "SELECT STATUS, REF_TRAN_ID FROM SQL_EXEC_LOG WHERE TRAN_ID=?";
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, tranId);
			rs = pstmt.executeQuery();
			if (rs.next()) {
				status = checkNull(rs.getString("STATUS"));
				refTranId = checkNull(rs.getString("REF_TRAN_ID"));

			}
			if (pstmt != null) {
				pstmt.close();
				pstmt = null;
			}
			if (rs != null) {
				rs.close();
				rs = null;
			}
			if ("C".equalsIgnoreCase(status)) {
				errString = itmdbAccessLocal.getErrorString("confirmed", "VTECLNCANC", "", "", con);
				System.out.println("errString is " + errString);
			} else if ("X".equalsIgnoreCase(status)) {
				errString = itmdbAccessLocal.getErrorString("confirmed", "VTMCANL1", "", "", con);
				System.out.println("errString is:: " + errString);
			} else {
				String upSql = "UPDATE SQL_EXEC_LOG SET STATUS='X' WHERE TRAN_ID=?";
				pstmt = con.prepareStatement(upSql);
				pstmt.setString(1, tranId);

				int updCnt = pstmt.executeUpdate();
				if (pstmt != null) {
					pstmt.close();
					pstmt = null;
				}

				String tranIdRef = "";
				String getTranIdRef = "select tran_id__ref from sql_changes where tran_id = ?";
				PreparedStatement getTranIdRefPs = con.prepareStatement(getTranIdRef);
				getTranIdRefPs.setString(1, refTranId);
				ResultSet getTranIdRefRs = getTranIdRefPs.executeQuery();
				while (getTranIdRefRs.next()) {
					tranIdRef = checkNull(getTranIdRefRs.getString("tran_id__ref"));
				}
				if (getTranIdRefPs != null)
					getTranIdRefPs.close();
				if (getTranIdRefRs != null)
					getTranIdRefRs.close();
				BaseLogger.log("3", getUserInfo(), null, "ManageSqlClose --> tranIdRef [" + tranIdRef + "]");

				String updateClosedDetailsSql = "update sql_changes set CLOSED_YN = 'Y',TXN_STATUS = 'C', CLOSED_BY = ?, CLOSED_DATE = SYSDATE where tran_id = ?";
				PreparedStatement updateClosedDetailsPs = con.prepareStatement(updateClosedDetailsSql);
				updateClosedDetailsPs.setString(1, userId);
				updateClosedDetailsPs.setString(2, tranIdRef);
				int updateClosedDetailsCount = updateClosedDetailsPs.executeUpdate();
				BaseLogger.log("1", null, null, "updateClosedDetailsCount:: [" + updateClosedDetailsCount + "]");
				if (updateClosedDetailsPs != null)
					updateClosedDetailsPs.close();

				System.out.println("update count is[" + updCnt + "]");
				if (updCnt > 0) {
					errString = itmdbAccessLocal.getErrorString("confirmed", "VTLVECAR01", "", "", con);
					System.out.println("errString is " + errString);

				}
			}

		} catch (Exception e) {
			isError = true;
			try {
				con.rollback();
			} catch (Exception e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
			throw new ITMException(e);
		} finally {
			try {
				if (!(isError)) {
					con.commit();
					// errString = itmdbAccessLocal.getErrorString("","TEMCONFIRM",loginEmpCode);
					// errString = itmdbAccessLocal.getErrorString("confirmed", "TEMCONFIRM",
					// "","",con);
				} else {
					con.rollback();
				}
				if (pstmt != null) {

					pstmt.close();
					pstmt = null;
				}
				if (con != null && !con.isClosed()) {
					con.close();
					con = null;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		System.out.println("errString is +++:" + errString);
		return errString;
	}

	public String ConfirmLog(String tranId, String xtraParams, String forcedFlag) throws RemoteException, ITMException {
		System.out.println("managelogsql  ConfirmLog........[" + tranId + "]");

		boolean isError = false;

		String enterprises = "";
		String sql = "";

		ResultSet rs = null;
		PreparedStatement pstmt = null;
		Connection con = null;
		String errString = "";
		String schemaName = "";
		ITMDBAccessEJB itmdbAccessLocal = null;
		boolean isThisObject = false;
		String sqlExecute = "";
		try {

			itmdbAccessLocal = new ITMDBAccessEJB();

			GenericUtility genericUtility = GenericUtility.getInstance();
			con = getConnection();
			con.setAutoCommit(false);
			String userId = checkNull(genericUtility.getValueFromXTRA_PARAMS(xtraParams, "loginCode"));

			sql = "SELECT ENTERPRISE FROM SQL_EXEC_LOG WHERE TRAN_ID=?";
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, tranId);
			rs = pstmt.executeQuery();
			if (rs.next()) {
				enterprises = checkNull(rs.getString("ENTERPRISE"));
			}
			if (pstmt != null) {
				pstmt.close();
				pstmt = null;
			}
			if (rs != null) {
				rs.close();
				rs = null;
			}

			String EnterPriseInFormat = getFormattedStringBuff(enterprises);
			sql = "SELECT SCHEMA_NAME,ENTERPRISE FROM ENTERPRISE WHERE ENTERPRISE IN(" + EnterPriseInFormat + ") ";
			pstmt = con.prepareStatement(sql);
			rs = pstmt.executeQuery();
			if (rs.next()) {
				schemaName = checkNull(rs.getString("SCHEMA_NAME"));
			}
			if (pstmt != null) {
				pstmt.close();
				pstmt = null;
			}
			if (rs != null) {
				rs.close();
				rs = null;
			}

			sql = "SELECT ORA_STMNT FROM SQL_EXEC_LOG WHERE TRAN_ID=?";
			pstmt = con.prepareStatement(sql);
			pstmt.setString(1, tranId);
			rs = pstmt.executeQuery();
			if (rs.next()) {
				String oracleStatment = checkNull(rs.getString("ORA_STMNT"));

				System.out.println("oracle execute statment[" + oracleStatment + "]");
				if (oracleStatment.lastIndexOf(";") != -1) {
					if (!oracleStatment.toUpperCase().startsWith("CREATE")) {
						int endIndex = oracleStatment.lastIndexOf(";");
						oracleStatment = oracleStatment.substring(0, endIndex);
					} else if (oracleStatment.toUpperCase().startsWith("CREATE TABLE")) {
						int endIndex = oracleStatment.lastIndexOf(";");
						oracleStatment = oracleStatment.substring(0, endIndex);
					}

				}
				if (oracleStatment.toUpperCase().startsWith("CREATE")
						&& !oracleStatment.toUpperCase().startsWith("CREATE TABLE")) {
					isThisObject = true;

				}

				// if( oracleStatment.toUpperCase().startsWith("ALTER") ||
				// oracleStatment.toUpperCase().startsWith("INSERT INTO") ||
				// oracleStatment.toUpperCase().startsWith("UPDATE") ||
				// oracleStatment.toUpperCase().startsWith("DELETE"))
				// {
				sqlExecute = executeLogQueries(con, schemaName, oracleStatment, isThisObject);
				// }

			}
			if (pstmt != null) {
				pstmt.close();
				pstmt = null;
			}
			if (rs != null) {
				rs.close();
				rs = null;
			} // changed by Ashish.J
			if ("SUCCESS".equalsIgnoreCase(sqlExecute)) {
				// String upSql="UPDATE SQL_EXEC_LOG SET STATUS='C' WHERE TRAN_ID=?";
				String upSql = "UPDATE SQL_EXEC_LOG SET STATUS='C', RESULT = ?, SQL_EXCEPTION = ? WHERE TRAN_ID=?";
				pstmt = con.prepareStatement(upSql);
				pstmt.setInt(1, reUpdateCnt);
				pstmt.setString(2, sqlError);
				pstmt.setString(3, tranId);

				int updCnt = pstmt.executeUpdate();
				if (pstmt != null) {
					pstmt.close();
					pstmt = null;
				}
				System.out.println("inside if update count is[" + updCnt + "]");
				if (updCnt > 0) {
					errString = itmdbAccessLocal.getErrorString("confirmed", "VTCONFIRM", "", "", con);
					System.out.println("errString is " + errString);

				}
			} else {
				String upSql = "UPDATE SQL_EXEC_LOG SET STATUS='E', RESULT = ?, SQL_EXCEPTION = ? WHERE TRAN_ID=?";
				pstmt = con.prepareStatement(upSql);
				pstmt.setInt(1, reUpdateCnt);
				pstmt.setString(2, sqlError);
				pstmt.setString(3, tranId);

				int updCnt = pstmt.executeUpdate();
				if (pstmt != null) {
					pstmt.close();
					pstmt = null;
				}
				System.out.println("inside else update count is[" + updCnt + "]");
				errString = itmdbAccessLocal.getErrorString("confirmed", "CONFFAILED", "", "", con);
			}

		} // Changed by Ashish.J
		catch (Exception e) {
			isError = true;
			try {
				con.rollback();
			} catch (Exception e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
			throw new ITMException(e);
		} finally {
			try {
				System.out.println("Commiting and Closing Connection..........");
				if (!(isError)) {
					System.out.println("inside finally if");
					con.commit();
					// errString = itmdbAccessLocal.getErrorString("","TEMCONFIRM",loginEmpCode);
					// errString = itmdbAccessLocal.getErrorString("confirmed", "TEMCONFIRM",
					// "","",con);
				} else {
					System.out.println("inside finally rollback else");
					con.rollback();
				}
				if (pstmt != null) {
					System.out.println("inside finally if pstmt ");

					pstmt.close();
					pstmt = null;
				}
				if (con != null && !con.isClosed()) {
					System.out.println("inside finally if con ");
					con.close();
					con = null;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		System.out.println("errString is +++:" + errString);
		return errString;
	}

	private String executeLogQueries(Connection connection, String schemaName, String Sql, boolean isThisObjectType) {
		BaseLogger.log("3", null, null, "Inside executeQueries1 [" + Sql + "]");

		ConnDriver connDriver = new ConnDriver();
		Connection conn = null;
		Statement stmnt = null;
		int updateCount = 0;
		CallableStatement callableStmt = null;
		String ExecuteSql = "SUCCESS";
		try {

			System.out.println("isThisObjectType1:::::[" + isThisObjectType + "]");
			conn = connDriver.getConnectDB(schemaName);
			if (conn == null) {
				BaseLogger.log("3", null, null, "Unable to get connection for [" + schemaName + "]");
				throw new Exception("Unable to get connection for [" + schemaName + "]");
			}

			if (checkNull(Sql).trim().length() > 0) {

				if (isThisObjectType) {
					String plsql = " begin " +
							" dbms_metadata.set_transform_param ( DBMS_METADATA.SESSION_TRANSFORM, 'SQLTERMINATOR', false ); "
							+
							" end; ";
					callableStmt = conn.prepareCall(plsql);
					callableStmt.execute();

				}

				try {
					BaseLogger.log("3", null, null, "Inside manageconf try");
					stmnt = conn.createStatement();
					// int updateCnt = stmnt.executeUpdate(Sql);
					reUpdateCnt = stmnt.executeUpdate(Sql);
					BaseLogger.log("3", null, null,
							"schema[" + schemaName + "]updateCnt to get Sql [" + updateCount + "]");

				} catch (SQLException ise) {
					sqlError = ise.getMessage();
					BaseLogger.log("3", null, null, "Inside manageconf catch::" + ise.getMessage());
					ExecuteSql = "NOT EXECUTE";
					throw new ITMException(ise);
				}

				finally {
					if (stmnt != null) {
						stmnt.close();
						stmnt = null;
					}
				}
			}

			Thread.sleep(100);
			conn.commit();

		} catch (Exception e) {
			try {
				BaseLogger.log("3", null, null,
						"Excepotion in executeAlterQueries occured while executing Alter Queries>>>>::"
								+ e.getMessage());
				ExecuteSql = "NOT EXECUTE";
				conn.rollback();
				// sqlError = e.getMessage();
			} catch (SQLException sqle) {
				BaseLogger.log("3", null, null,
						"SQLException executeAlterQueries occured during rollback:: " + sqle.getMessage());
				sqle.printStackTrace();
			}
			e.printStackTrace();
		} finally {
			try {
				if (callableStmt != null) {
					callableStmt.close();
					callableStmt = null;
				}
				if (conn != null) {
					conn.close();
					conn = null;
				}
			} catch (SQLException sqle) {
				BaseLogger.log("3", null, null,
						"SQLException executeAlterQueries inside finally:: " + sqle.getMessage());
				sqle.printStackTrace();
			}
		}
		return ExecuteSql;
	}

	private String generateTranID(Connection conn) throws ITMException {
		String uniqueKey = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			// System.out.println("RealTimeReportPos : Generating Primary Key ...........");

			String keyStringQuery = "SELECT KEY_STRING, TRAN_ID_COL, REF_SER FROM TRANSETUP WHERE TRAN_WINDOW = 'w_sql_exec_log' ";
			pstmt = conn.prepareStatement(keyStringQuery);
			rs = pstmt.executeQuery();

			if (rs.next()) {
				String keyString = rs.getString("KEY_STRING");
				String keyCol = rs.getString("TRAN_ID_COL");
				String tranSer = rs.getString("REF_SER");
				String xmlValues = "<?xml version=\"1.0\" encoding=\"utf-8\"?><Root>";
				xmlValues = xmlValues + "<Header></Header>";
				xmlValues = xmlValues + "<Detail1>";
				xmlValues = xmlValues + "<tran_id></tran_id>";
				xmlValues = xmlValues + "</Detail1></Root>";
				TransIDGenerator tg = new TransIDGenerator(xmlValues, "BASE", CommonConstants.DB_NAME);
				uniqueKey = tg.generateTranSeqID(tranSer, keyCol, keyString, conn);
			}
			rs.close();
			rs = null;
			pstmt.close();
			pstmt = null;
		} catch (Exception exp) {
			System.out.println("Exception : RealTimeReportPos :generateTransID :==>\n");
			throw new ITMException(exp);
		} finally {
			try {
				if (rs != null) {
					rs.close();
					rs = null;
				}
				if (pstmt != null) {
					pstmt.close();
					pstmt = null;
				}
			} catch (Exception e) {
				System.out.println("Exception : RealTimeReportPos :getUniqueKey :finally==>");
				throw new ITMException(e);
			}
		}
		System.out.println("Generated Primary Key :" + uniqueKey);
		return uniqueKey;
	}

	// Created a method to execute the SQL in the schemas stored in the Enterprise
	// table for the provided enterprise value by Ajit on 03-DEC-25 -- START
	public void processSqlForEnterprise(
			Connection conn,
			String enterpriseCode,
			String inputSql,
			String tranId,
			String linNo,
			String requestID,
			String userId,
			String chgTerm) throws Exception {

		// Change by Gagan B. on 16-JAN-26
		// --- FIX: Don't inject placeholders into PL/SQL Bodies ---
		String upperSql = checkNull(inputSql).trim().toUpperCase();
		boolean isPlSqlBody = upperSql.startsWith("CREATE OR REPLACE FUNCTION")
				|| upperSql.startsWith("CREATE FUNCTION")
				|| upperSql.startsWith("CREATE OR REPLACE PROCEDURE")
				|| upperSql.startsWith("CREATE PROCEDURE")
				|| upperSql.startsWith("CREATE OR REPLACE PACKAGE")
				|| upperSql.startsWith("CREATE PACKAGE")
				|| upperSql.startsWith("CREATE OR REPLACE TYPE")
				|| upperSql.startsWith("CREATE TYPE")
				|| upperSql.startsWith("CREATE OR REPLACE TRIGGER")
				|| upperSql.startsWith("CREATE TRIGGER")
				|| upperSql.contains("NONEDITIONABLE"); // Catch the specific case

		if (!isPlSqlBody) {
			inputSql = injectSchemaPlaceholderSafe(inputSql);
		}
		System.out.println("inputSql gsb:::::>>>><<<<< " + inputSql);

		/*
		 * -------------------------------
		 * Fetch schemas
		 * -------------------------------
		 */
		String query = "SELECT DB_DEV, DB_MAIN, DB_READ, DB_PILOT " +
				"FROM enterprise WHERE enterprise = ?";

		String  dbMain, dbRead;

		try (PreparedStatement ps = conn.prepareStatement(query)) {
			ps.setString(1, enterpriseCode);
			try (ResultSet rs = ps.executeQuery()) {
				if (!rs.next()) {
					throw new Exception("No enterprise found for: " + enterpriseCode);
				}
				dbMain = rs.getString("DB_MAIN");
				dbRead = rs.getString("DB_READ");
			}
		}

		/*
		 * -------------------------------
		 * Get CURRENT_USER
		 * -------------------------------
		 */
		String currentUser;
		try (PreparedStatement ps = conn.prepareStatement("SELECT USER FROM DUAL");
				ResultSet rs = ps.executeQuery()) {

			rs.next();
			currentUser = rs.getString(1);
		}

		System.out.println("CURRENT_USER ::: " + currentUser);

		/*
		 * -------------------------------
		 * Schema execution rules
		 * -------------------------------
		 */
		Map<String, String> schemaRules = new LinkedHashMap<>();
		schemaRules.put(dbMain, "ALL");
		//schemaRules.put(dbDev, "ALL");
		schemaRules.put(dbRead, "SYN");
		//schemaRules.put(dbPilot, "SYN");

		String createObjectType = getCreateObjectType(inputSql);
		boolean isCreateObject = createObjectType != null;
		String objectName = isCreateObject ? extractObjectName(inputSql) : null;

		System.out.println("objectName ::: " + objectName);
		System.out.println("createObjectType ::: " + createObjectType);

		/*
		 * -------------------------------
		 * Execute per schema
		 * -------------------------------
		 */
		for (Map.Entry<String, String> entry : schemaRules.entrySet()) {

			String schemaName = entry.getKey();
			String rule = entry.getValue();

			if (schemaName == null || schemaName.trim().isEmpty())
				continue;

			/*
			 * =====================================
			 * CREATE / DDL FLOW
			 * =====================================
			 */
			if (isCreateObject) {

				if ("ALL".equals(rule)) {

					executeAndLog(
							schemaName,
							inputSql,
							tranId,
							enterpriseCode,
							linNo,
							requestID,
							userId,
							chgTerm,
							dbMain,
							"",
							true);

				} else if ("SYN".equals(rule)) {

					// // Skip synonym & grant if CURRENT_USER is owner
					// if (currentUser.equalsIgnoreCase(dbMain)) {
					// System.out.println(
					// "Skipping SYN. CURRENT_USER is DB_MAIN."
					// );
					// continue;
					// }

					/*
					 * -----------------------------
					 * Create synonym in CURRENT_USER
					 * -----------------------------
					 */
					String synonymSql = "CREATE SYNONYM " + schemaName + "." + objectName +
							" FOR " + dbMain + "." + objectName;

					executeAndLog(
							schemaName,
							synonymSql,
							tranId,
							enterpriseCode,
							linNo,
							requestID,
							userId,
							chgTerm,
							dbMain,
							"",
							false);

					/*
					 * -----------------------------
					 * Grant based on object type
					 * -----------------------------
					 */
					String grantSql = null;

					if ("TABLE".equalsIgnoreCase(createObjectType)
							|| "VIEW".equalsIgnoreCase(createObjectType)
							|| "SEQUENCE".equalsIgnoreCase(createObjectType)) {

						grantSql = "GRANT SELECT ON " + dbMain + "." + objectName +
								" TO " + schemaName;

					} else if ("PROCEDURE".equalsIgnoreCase(createObjectType)
							|| "FUNCTION".equalsIgnoreCase(createObjectType)
							|| "PACKAGE".equalsIgnoreCase(createObjectType)
							|| "TYPE".equalsIgnoreCase(createObjectType)) {

						grantSql = "GRANT EXECUTE ON " + dbMain + "." + objectName +
								" TO " + schemaName;
					}

					if (grantSql != null) {
						executeAndLog(
								schemaName,
								grantSql,
								tranId,
								enterpriseCode,
								linNo,
								requestID,
								userId,
								chgTerm,
								dbMain,
								"",
								false);
					}
				}

				continue; // Skip DML flow
			}

			/*
			 * =====================================
			 * INSERT / UPDATE / DELETE FLOW
			 * =====================================
			 */
			if ("SYN".equals(rule)) {
				System.out.println(
						"Skipping DML for SYN-only schema: " + schemaName);
				continue;
			}

			executeAndLog(
					schemaName,
					inputSql,
					tranId,
					enterpriseCode,
					linNo,
					requestID,
					userId,
					chgTerm,
					dbMain,
					"",
					false);
		}

		System.out.println("Execution completed successfully.");
	}

	// Created a method to execute the SQL in the schemas stored in the Enterprise
	// table for the provided enterprise value by Ajit on 03-DEC-25 -- END
	/*
	 * Changes done by Gagan B. on 10-FEB-26
	 * When a DROP command is executed, the system now automatically identifies and
	 * removes the corresponding synonym from the configured Read schema (as defined
	 * in the ENTERPRISE table).
	 */
	private void executeAndLog(
			String schemaName,
			String inputSql,
			String tranId,
			String enterpriseCode,
			String linNo,
			String requestID,
			String userId,
			String chgTerm,
			String dbMainSchema,
			String execRights,
			boolean rethrow) throws Exception {
		Connection conn = null;
		Connection connForQueryExec = null;
		ConnDriver connDriver = new ConnDriver();
		ConnDriver connDriver1 = new ConnDriver();

		String connForExec = "";

		BaseLogger.log("3", null, null, "executeAndLog inputSql: [" + inputSql + "]");

		String finalSql = applySchema(inputSql, schemaName);

		// Change by Gagan B. on 16-JAN-26
		finalSql = finalSql.trim();

		BaseLogger.log("3", null, null, ">>> EXECUTING SQL finalSql : [" + finalSql + "]");
		BaseLogger.log("3", null, null, "executeAndLog schemaName: [" + schemaName + "]");
		BaseLogger.log("3", null, null, "executeAndLog dbMainSchema: [" + dbMainSchema + "]");
		BaseLogger.log("3", null, null, "executeAndLog enterpriseCode: [" + enterpriseCode + "]");

		String execSchema = schemaName;
		String sqlUpper = finalSql.trim().toUpperCase();

		if (sqlUpper.startsWith("CREATE SYNONYM")
				|| sqlUpper.startsWith("GRANT SELECT ON")
				|| sqlUpper.startsWith("GRANT EXECUTE ON")) {
			execSchema = dbMainSchema;
		}

		System.out.println("execSchema:: " + execSchema);
		System.out.println("enterpriseCode:: " + enterpriseCode);

		try {
			conn = connDriver1.getConnectDB("Driver");
		} catch (Exception e) {
			System.out.println("Catch block for connection failed...." + e.getMessage());
			String error = e.getMessage();
			logSqlExecution(tranId, enterpriseCode, "0", requestID, finalSql, 0, "E", userId, chgTerm, error, "");
			return; // Stop execution if connection fails
		}

		// 1. Get the Connection String for the Main Execution
		String connForExecSql = "select schema_name from enterprise where enterprise = ?";
		PreparedStatement connForExecPstmt = conn.prepareStatement(connForExecSql);
		connForExecPstmt.setString(1, enterpriseCode);
		ResultSet connForExecRs = connForExecPstmt.executeQuery();
		while (connForExecRs.next()) {
			connForExec = connForExecRs.getString("schema_name");
		}


		if(execRights.trim().equalsIgnoreCase("P") || execRights.trim().equalsIgnoreCase("C")){
			connForExec = schemaName;
		}
		System.out.println("connForExec:: " + connForExec);

		// Connect to the specific schema
		connForQueryExec = connDriver.getConnectDB(connForExec);

		int updCount = 0;
		String error = null;

		try {
			Statement stmt = connForQueryExec.createStatement();

			if (isTrigger(finalSql) || isDdl(finalSql)) {
				// --- A. Execute the Main DDL (DROP TABLE/VIEW/SEQ) ---
				stmt.execute(finalSql);

				// --- B. Handle DROP SYNONYM Logic using Enterprise Config ---
				if (sqlUpper.startsWith("DROP ")) {
					PreparedStatement psEnt = null;
					ResultSet rsEnt = null;
					String dbRead = null;

					try {
						// 1. Extract Object Name from SQL (e.g., TESTMANGESQL1)
						String objName = getObjectNameFromDrop(finalSql);

						if (objName != null) {
							// Clean up object name
							objName = objName.replace("\"", "").trim();

							// 2. Query ENTERPRISE table to get DB_READ schema
							// We use 'conn' (the Driver connection) which has access to the enterprise
							// table
							String query = "SELECT DB_READ FROM enterprise WHERE enterprise = ?";
							psEnt = conn.prepareStatement(query);
							psEnt.setString(1, enterpriseCode);
							rsEnt = psEnt.executeQuery();

							if (rsEnt.next()) {
								dbRead = rsEnt.getString("DB_READ");
							}

							// 3. Construct and Execute DROP SYNONYM
							if (dbRead != null && !dbRead.isEmpty()) {
								// Construct: DROP SYNONYM APPVISREAD.TESTMANGESQL1
								String dropSynSql = "DROP SYNONYM " + dbRead + "." + objName;

								System.out.println(
										"Attempting to drop related synonym via Enterprise Config: " + dropSynSql);

								// Execute blindly. If it doesn't exist, we catch the exception.
								stmt.execute(dropSynSql);
								System.out.println("Synonym dropped successfully.");
							} else {
								System.out.println("Skipping synonym drop: DB_READ not found in Enterprise table.");
							}
						}
					} catch (SQLException synEx) {
						// Swallow exception specifically for synonym drop
						// (e.g., ORA-01434: synonym does not exist)
						System.out.println("Synonym drop skipped or failed (non-fatal): " + synEx.getMessage());
					} catch (Exception ex) {
						System.out.println("Error in synonym logic: " + ex.getMessage());
					} finally {
						if (rsEnt != null)
							try {
								rsEnt.close();
							} catch (Exception e) {
							}
						if (psEnt != null)
							try {
								psEnt.close();
							} catch (Exception e) {
							}

					}
				}
				// --- END SYNONYM LOGIC ---

			} else {
				// INSERT / UPDATE / DELETE
				updCount = stmt.executeUpdate(finalSql);
				connForQueryExec.commit();
			}

			logSqlExecution(
					tranId, enterpriseCode, linNo, requestID,
					finalSql, updCount, "C", userId, chgTerm, null, dbMainSchema);

		} catch (SQLException e) {
			try {
				if (connForQueryExec != null)
					connForQueryExec.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			error = e.getMessage();

			logSqlExecution(
					tranId, enterpriseCode, linNo, requestID,
					finalSql, updCount, "E", userId, chgTerm, error, dbMainSchema);

			// if (rethrow) {
			// 	System.out.println("In rethrow condition");
			// 	throw new RuntimeException(e);
			// }
		} finally {
			if (connForExecRs != null)
				connForExecRs.close();
			if (connForExecPstmt != null)
				connForExecPstmt.close();
			if (connForQueryExec != null)
				connForQueryExec.close();
			if (conn != null)
				conn.close();
		}
	}

	private boolean isDdl(String sql) {
		String s = sql.trim().toUpperCase();
		return s.startsWith("CREATE")
				|| s.startsWith("ALTER")
				|| s.startsWith("DROP")
				|| s.startsWith("GRANT")
				|| s.startsWith("EXECUTE")
				|| s.startsWith("REVOKE");
	}

	private boolean isTrigger(String sql) {
		return sql.trim().toUpperCase().startsWith("CREATE")
				&& sql.toUpperCase().contains(" TRIGGER ");
	}

	private void logSqlExecution(
			String tranId,
			String enterpriseCode,
			String linNo,
			String requestID,
			String sql,
			int updCount,
			String status,
			String userId,
			String chgTerm,
			String error,
			String schemaName) {
		Connection logConn = null;

		try {

			logConn = getConnection();
			logConn.setAutoCommit(true);

			insertIntoSqlExectionLog(
					logConn,
					tranId,
					enterpriseCode,
					linNo,
					requestID,
					sql,
					updCount,
					status,
					userId,
					chgTerm,
					error);

		} catch (Exception ex) {
			System.out.println("SQL LOGGING FAILED: " + ex.getMessage());
			ex.printStackTrace();
		} finally {
			try {
				if (logConn != null)
					logConn.close();
			} catch (Exception ignore) {
			}
		}
	}

	// Created a method to fetch the table name from provided SQL string by Ajit on
	// 03-DEC-25 -- START
	/*
	 * private String extractObjectName(String sql) {
	 * System.out.println("extractObjectName SQL::::::: "+sql);
	 * if (sql == null) return null;
	 * sql = removeComments(sql);
	 * String s = sql.replace("\n", " ")
	 * .replace("\t", " ")
	 * .trim()
	 * .toUpperCase();
	 * 
	 * s = s.replaceAll("\\s+", " ");
	 * 
	 * if (s.startsWith("CREATE OR REPLACE")) {
	 * s = s.replaceFirst("CREATE\\s+OR\\s+REPLACE\\s+", "CREATE ");
	 * }
	 * 
	 * String objectType = getCreateObjectType(s);
	 * if (objectType == null) return null;
	 * 
	 * String keyword;
	 * 
	 * switch (objectType) {
	 * case "TABLE":
	 * keyword = "CREATE TABLE";
	 * break;
	 * case "SEQUENCE":
	 * keyword = "CREATE SEQUENCE";
	 * break;
	 * case "TYPE":
	 * keyword = "CREATE TYPE";
	 * break;
	 * case "FUNCTION":
	 * keyword = "CREATE FUNCTION";
	 * break;
	 * case "PROCEDURE":
	 * keyword = "CREATE PROCEDURE";
	 * break;
	 * case "PACKAGE BODY":
	 * keyword = "CREATE PACKAGE BODY";
	 * break;
	 * case "PACKAGE":
	 * keyword = "CREATE PACKAGE";
	 * break;
	 * case "VIEW":
	 * keyword = "CREATE VIEW";
	 * break;
	 * case "SYNONYM":
	 * keyword = "CREATE SYNONYM";
	 * break;
	 * case "INDEX":
	 * keyword = "CREATE INDEX";
	 * break;
	 * case "TRIGGER":
	 * keyword = "CREATE TRIGGER";
	 * break;
	 * default:
	 * return null;
	 * }
	 * 
	 * int idx = s.indexOf(keyword);
	 * if (idx == -1) return null;
	 * 
	 * String after = s.substring(idx + keyword.length()).trim();
	 * 
	 * if ("PACKAGE BODY".equals(objectType)) {
	 * after = after.replaceFirst("^BODY\\s+", "");
	 * }
	 * 
	 * if (after.contains(".")) {
	 * after = after.substring(after.indexOf(".") + 1);
	 * }
	 * 
	 * after = after.split(
	 * "\\s|\\(",
	 * 2
	 * )[0].trim();
	 * 
	 * 
	 * after = after.replaceAll("[^A-Z0-9_]", "").trim();
	 * 
	 * return after;
	 * }
	 * //Created a method to fetch the table name from provided SQL string by Ajit
	 * on 03-DEC-25 -- END
	 */

	// Created a method to fetch the object name from input SQL string by Gagan B.
	// on 19-FEB-26 -- START
	private static String extractObjectName(String sql) {
		if (sql == null || sql.trim().isEmpty())
			return null;

		// 1. Remove comments
		sql = removeComments(sql);

		// 2. Regular Expression to find the object name
		// This regex looks for CREATE [OR REPLACE] [TYPE] then captures the next word
		// It handles: TABLE, VIEW, FUNCTION, PROCEDURE, PACKAGE [BODY], TRIGGER, etc.
		String regex = "(?i)CREATE\\s+(?:OR\\s+REPLACE\\s+)?(?:EDITIONABLE\\s+|NONEDITIONABLE\\s+)?(?:PACKAGE\\s+BODY|\\w+)\\s+([a-zA-Z0-9_.\"]+)";

		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(sql.trim());

		if (matcher.find()) {
			String fullName = matcher.group(1); // This might be "SCHEMA.NAME"

			// 3. Handle Schema prefix (e.g., HR.EMPLOYEES -> EMPLOYEES)
			if (fullName.contains(".")) {
				fullName = fullName.substring(fullName.lastIndexOf(".") + 1);
			}

			// 4. Clean up any remaining characters like quotes
			return fullName.replaceAll("[\"\\s+]", "").toUpperCase();
		}

		return null;
	}
	// Created a method to fetch the object name from input SQL string by Gagan B.
	// on 19-FEB-26 -- START

	// Created a method to add a placeholder before the table name which will be
	// replaced by the schema name by Ajit on 03-DEC-25 -- START
	/*
	 * Fixed by Gagan B. on 11-FEB-26
	 * Issue Fix:
	 * Added word boundry in regular expression to fix the regular expression which
	 * was causing issue in SQL which contained word action.
	 * Earlier it added schema incorrectly by checking "on" of action.
	 */
	public static String injectSchemaPlaceholder(String sql) {
		BaseLogger.log("3", null, null, "Inside injectSchemaPlaceholder SQL [" + sql + "]");

		String s = sql.trim();

		// Skip CREATE SYNONYM
		if (s.toUpperCase().startsWith("CREATE SYNONYM")) {
			return sql;
		}

		// CREATE OR REPLACE VIEW view_name
		// Added \\b before VIEW to ensure we don't match something like "REVIEW"
		// (unlikely but safe)
		s = s.replaceAll(
				"(?i)CREATE\\s+OR\\s+REPLACE\\s+VIEW\\s+(?!\\{SCHEMA\\}|[A-Z0-9_]+\\.)",
				"CREATE OR REPLACE VIEW {SCHEMA}.");

		// 1️⃣ PACKAGE BODY (FIRST)
		s = s.replaceAll(
				"(?i)CREATE\\s+OR\\s+REPLACE\\s+PACKAGE\\s+BODY\\s+(?![A-Z0-9_]+\\.)",
				"CREATE OR REPLACE PACKAGE BODY {SCHEMA}.");

		// 2️⃣ PACKAGE (EXCLUDE BODY)
		s = s.replaceAll(
				"(?i)CREATE\\s+OR\\s+REPLACE\\s+PACKAGE\\s+(?!BODY\\s+)(?![A-Z0-9_]+\\.)",
				"CREATE OR REPLACE PACKAGE {SCHEMA}.");

		// TRIGGER: ON table
		// FIX IS HERE: Added \\b before ON
		// This prevents matching "actiON", "positiON", "unicON", etc.
		s = s.replaceAll(
				"(?i)\\bON\\s+(?!\\{SCHEMA\\}|[A-Z0-9_]+\\.)",
				"ON {SCHEMA}.");

		// INSERT INTO table
		// Added \\b before INSERT
		s = s.replaceAll(
				"(?i)\\bINSERT\\s+INTO\\s+(?!\\{SCHEMA\\}|[A-Z0-9_]+\\.)",
				"INSERT INTO {SCHEMA}.");

		// UPDATE table
		// Added \\b before UPDATE (Prevents matching columns like 'last_update')
		s = s.replaceAll(
				"(?i)\\bUPDATE\\s+(?!\\{SCHEMA\\}|[A-Z0-9_]+\\.)",
				"UPDATE {SCHEMA}.");

		// DELETE FROM table
		// Added \\b before DELETE
		s = s.replaceAll(
				"(?i)\\bDELETE\\s+FROM\\s+(?!\\{SCHEMA\\}|[A-Z0-9_]+\\.)",
				"DELETE FROM {SCHEMA}.");

		// SELECT ... FROM table
		// Added \\b before FROM (Prevents matching columns like 'valid_from',
		// 'sent_from')
		s = s.replaceAll(
				"(?i)\\bFROM\\s+(?!\\{SCHEMA\\}|[A-Z0-9_]+\\.)",
				"FROM {SCHEMA}.");

		return s;
	}

	public static String injectSchemaPlaceholderSafe(String sql) {

		List<String> literals = new ArrayList<>();

		// Step 1: remove string literals
		String maskedSql = maskStringLiterals(sql, literals);

		// Step 2: apply schema placeholder logic
		maskedSql = injectSchemaPlaceholder(maskedSql);

		// Step 3: restore string literals
		return unmaskStringLiterals(maskedSql, literals);
	}

	private static String maskStringLiterals(String sql, List<String> literals) {

		Matcher matcher = Pattern.compile("'([^']|'')*'").matcher(sql);
		StringBuffer sb = new StringBuffer();
		int index = 0;

		while (matcher.find()) {
			literals.add(matcher.group());
			matcher.appendReplacement(sb, "__STR_" + index++ + "__");
		}
		matcher.appendTail(sb);

		return sb.toString();
	}

	private static String unmaskStringLiterals(String sql, List<String> literals) {

		for (int i = 0; i < literals.size(); i++) {
			sql = sql.replace("__STR_" + i + "__", literals.get(i));
		}
		return sql;
	}

	// Created a method to add a placeholder before the table name which will be
	// replaced by the schema name by Ajit on 03-DEC-25 -- END

	private String getCreateObjectType(String sql) {

		if (sql == null)
			return null;

		String s = sql.trim().toUpperCase();

		// 🔴 Normalize CREATE OR REPLACE
		if (s.startsWith("CREATE OR REPLACE")) {
			s = s.replaceFirst("CREATE\\s+OR\\s+REPLACE\\s+", "CREATE ");
		}

		// Remove EDITIONABLE / NONEDITIONABLE keywords
	s = s.replaceFirst("CREATE\\s+NONEDITIONABLE\\s+", "CREATE ");
	s = s.replaceFirst("CREATE\\s+EDITIONABLE\\s+", "CREATE ");

		if (s.startsWith("CREATE TABLE"))
			return "TABLE";
		if (s.startsWith("CREATE SEQUENCE"))
			return "SEQUENCE";
		if (s.startsWith("CREATE TYPE"))
			return "TYPE";
		if (s.startsWith("CREATE FUNCTION"))
			return "FUNCTION";
		if (s.startsWith("CREATE PROCEDURE"))
			return "PROCEDURE";
		if (s.startsWith("CREATE PACKAGE BODY"))
			return "PACKAGE BODY";
		if (s.startsWith("CREATE PACKAGE"))
			return "PACKAGE";
		if (s.startsWith("CREATE VIEW"))
			return "VIEW";
		if (s.startsWith("CREATE TRIGGER"))
			return "TRIGGER";
		return null;
	}

	private String applySchema(String sql, String schema) {
		String s = sql.trim();
		String schemaPrefix = schema + ".";

		// 1. Handle DML Placeholders first
		if (s.contains("{SCHEMA}")) {
			return s.replace("{SCHEMA}", schema);
		}

		// Change by Gagan B. on 16-JAN-26
		// --- Helper for Regex ---
		// Matches: CREATE [OR REPLACE] [EDITIONABLE|NONEDITIONABLE] [TYPE]
		// We capture the entire header up to the object name so we can append the
		// schema prefix.

		// CREATE TABLE
		if (s.matches("(?is)^CREATE\\s+TABLE\\s+.*")) {
			return s.replaceFirst("(?is)(CREATE\\s+TABLE\\s+)", "$1" + schemaPrefix);
		}

		// CREATE VIEW
		if (s.matches("(?is)^CREATE\\s+(OR\\s+REPLACE\\s+)?(?:FORCE\\s+|NOFORCE\\s+)?VIEW\\s+.*")) {
			return s.replaceFirst("(?is)(CREATE\\s+(?:OR\\s+REPLACE\\s+)?(?:FORCE\\s+|NOFORCE\\s+)?VIEW\\s+)",
					"$1" + schemaPrefix);
		}

		// CREATE SEQUENCE
		if (s.matches("(?is)^CREATE\\s+SEQUENCE\\s+.*")) {
			return s.replaceFirst("(?is)(CREATE\\s+SEQUENCE\\s+)", "$1" + schemaPrefix);
		}

		// CREATE FUNCTION (Fixed for NONEDITIONABLE)
		if (s.matches("(?is)^CREATE\\s+(OR\\s+REPLACE\\s+)?(?:(?:NON)?EDITIONABLE\\s+)?FUNCTION\\s+.*")) {
			return s.replaceFirst(
					"(?is)(CREATE\\s+(?:OR\\s+REPLACE\\s+)?(?:(?:NON)?EDITIONABLE\\s+)?FUNCTION\\s+)",
					"$1" + schemaPrefix);
		}

		// CREATE PROCEDURE (Fixed for NONEDITIONABLE)
		if (s.matches("(?is)^CREATE\\s+(OR\\s+REPLACE\\s+)?(?:(?:NON)?EDITIONABLE\\s+)?PROCEDURE\\s+.*")) {
			return s.replaceFirst(
					"(?is)(CREATE\\s+(?:OR\\s+REPLACE\\s+)?(?:(?:NON)?EDITIONABLE\\s+)?PROCEDURE\\s+)",
					"$1" + schemaPrefix);
		}

		// CREATE PACKAGE BODY (Fixed for NONEDITIONABLE)
		if (s.matches("(?is)^CREATE\\s+(OR\\s+REPLACE\\s+)?(?:(?:NON)?EDITIONABLE\\s+)?PACKAGE\\s+BODY\\s+.*")) {
			return s.replaceFirst(
					"(?is)(CREATE\\s+(?:OR\\s+REPLACE\\s+)?(?:(?:NON)?EDITIONABLE\\s+)?PACKAGE\\s+BODY\\s+)",
					"$1" + schemaPrefix);
		}

		// CREATE PACKAGE (Fixed for NONEDITIONABLE)
		if (s.matches("(?is)^CREATE\\s+(OR\\s+REPLACE\\s+)?(?:(?:NON)?EDITIONABLE\\s+)?PACKAGE\\s+.*")) {
			return s.replaceFirst(
					"(?is)(CREATE\\s+(?:OR\\s+REPLACE\\s+)?(?:(?:NON)?EDITIONABLE\\s+)?PACKAGE\\s+)",
					"$1" + schemaPrefix);
		}

		// CREATE TYPE (Fixed for NONEDITIONABLE)
		if (s.matches("(?is)^CREATE\\s+(OR\\s+REPLACE\\s+)?(?:(?:NON)?EDITIONABLE\\s+)?TYPE\\s+.*")) {
			return s.replaceFirst(
					"(?is)(CREATE\\s+(?:OR\\s+REPLACE\\s+)?(?:(?:NON)?EDITIONABLE\\s+)?TYPE\\s+)",
					"$1" + schemaPrefix);
		}

		// CREATE TRIGGER
		if (s.matches("(?is)^CREATE\\s+(OR\\s+REPLACE\\s+)?(?:(?:NON)?EDITIONABLE\\s+)?TRIGGER\\s+.*")) {
			// Triggers are tricky because of "ON table", but usually just prefixing the
			// trigger name is enough
			// if the table is in the same schema.
			return s.replaceFirst(
					"(?is)(CREATE\\s+(?:OR\\s+REPLACE\\s+)?(?:(?:NON)?EDITIONABLE\\s+)?TRIGGER\\s+)",
					"$1" + schemaPrefix);
		}

		return s;
	}

	private static String removeComments(String sql) {
		// Remove /* ... */ comments
		sql = sql.replaceAll("(?s)/\\*.*?\\*/", " ");
		// Remove -- comments
		sql = sql.replaceAll("(?m)--.*?$", " ");
		return sql;
	}

	private String getObjectNameFromDrop(String sql) {
		// Regex to find 'DROP [TYPE] [SCHEMA.]OBJECT'
		// It captures the last part (the object name) ignoring the schema prefix
		java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(
				"DROP\\s+(?:TABLE|VIEW|PROCEDURE|FUNCTION|SEQUENCE|PACKAGE)\\s+(?:[a-zA-Z0-9_]+\\.)?([a-zA-Z0-9_]+)",
				java.util.regex.Pattern.CASE_INSENSITIVE);
		java.util.regex.Matcher matcher = pattern.matcher(sql.trim());
		if (matcher.find()) {
			return matcher.group(1); // Returns the object name (e.g., "MY_TABLE")
		}
		return null;
	}

}
