=== modified file 'src/com/goldencode/p2j/convert/db/ConversionData.java'
--- old/src/com/goldencode/p2j/convert/db/ConversionData.java	2022-05-26 17:40:26 +0000
+++ new/src/com/goldencode/p2j/convert/db/ConversionData.java	2023-01-09 10:36:39 +0000
@@ -15,6 +15,7 @@
 **     CA  20211012 Fixed generated WSDL and reworked SOAP support to rely on namespace, when resolving an
 **                  operation.
 **     GES 20220502 Match API method name change.
+**     RAA 20230109 Changed inline statement(s) to prepared statement(s).
 */
 
 /*
@@ -149,11 +150,12 @@
       {
          // check if the table exists
          boolean[] found = { false };
+         Object[] args = new Object[] {table.toUpperCase() + "__WORK"};
          helper.executeQuery("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES " +
-                             "WHERE TABLE_SCHEMA = SCHEMA() AND TABLE_NAME LIKE '" + table.toUpperCase() + "__WORK'", (rs) ->
+                             "WHERE TABLE_SCHEMA = SCHEMA() AND TABLE_NAME LIKE ?", (rs) ->
          {
             found[0] = true;
-         });
+         }, args);
          
          if (!found[0])
          {

=== modified file 'src/com/goldencode/p2j/persist/AbstractTempTable.java'
--- old/src/com/goldencode/p2j/persist/AbstractTempTable.java	2022-11-14 15:55:42 +0000
+++ new/src/com/goldencode/p2j/persist/AbstractTempTable.java	2023-01-09 10:38:43 +0000
@@ -57,6 +57,7 @@
 **                  delete it instead of handle.delete.
 **     IAS 20221003 Fixed error message for error 3131
 **     IAS 20221111 Added setter for the 'schemaMarshalLevel', fixed one for the 'namespaceURI'.
+**     RAA 20230109 Changed inline statement(s) to prepared statement(s).
 */
 
 /*
@@ -2575,11 +2576,11 @@
       sb.append(defBuffer.getTable());
       sb.append(" where ");
       sb.append(TemporaryBuffer.MULTIPLEX_FIELD_NAME);
-      sb.append(" = ");
-      sb.append(defBuffer.getMultiplexID());
+      sb.append(" = ?");
+      Object[] args = new Object[] {defBuffer.getMultiplexID()};
       try
       {
-         Object res = persistence.getSingleSQLResult(sb.toString(), null);
+         Object res = persistence.getSingleSQLResult(sb.toString(), args);
          if (res != null)
          {
             return true;

=== modified file 'src/com/goldencode/p2j/persist/BufferImpl.java'
--- old/src/com/goldencode/p2j/persist/BufferImpl.java	2023-01-07 22:47:28 +0000
+++ new/src/com/goldencode/p2j/persist/BufferImpl.java	2023-01-09 10:40:25 +0000
@@ -243,6 +243,7 @@
 **     CA  20221121 For a dynamic TEMP-TABLE, if the NAME attribute is changed, then the default-buffer's NAME
 **                  must be changed, too.
 **     SVL 20230108 Improved performance by replacing some "for-each" loops with indexed "for" loops.
+**     RAA 20230109 Changed inline statement(s) to prepared statement(s).
 */
 
 /*
@@ -9242,12 +9243,13 @@
          .append(Buffer.ORIGIN_ROWID_FIELD).append("=NULL, ")
          .append(Buffer.AFTER_ROWID_FIELD).append("=NULL")
          .append(" where ")
-         .append(TemporaryBuffer.MULTIPLEX_FIELD_NAME).append(" = ").append(afterBuf.getMultiplexID());
+         .append(TemporaryBuffer.MULTIPLEX_FIELD_NAME).append(" = ?");
       
+      Object[] args = new Object[] {afterBuf.getMultiplexID()};
       try
       {
          boolean noUndo = !beforeBuf.isUndoable();
-         int cnt = persistence.executeSQL(buf.toString(), null, noUndo);
+         int cnt = persistence.executeSQL(buf.toString(), args, noUndo);
          afterBuf.pruneSessionCache();
          if (log.isLoggable(Level.FINE))
          {

=== modified file 'src/com/goldencode/p2j/persist/FastCopyHelper.java'
--- old/src/com/goldencode/p2j/persist/FastCopyHelper.java	2022-10-12 20:04:38 +0000
+++ new/src/com/goldencode/p2j/persist/FastCopyHelper.java	2023-01-09 10:41:46 +0000
@@ -22,6 +22,7 @@
 **     ECF 20221006 Minor optimization.
 **     OM  20220913 Enhanced dialect API for sorting nulls.
 **     OM  20221012 Fixed regression in previous commit.
+**     RAA 20230109 Changed inline statement(s) to prepared statement(s).
 */
 
 /*
@@ -813,7 +814,9 @@
    private static void restartSequence(Persistence persistence, String sequenceName, Long start) 
    throws PersistenceException
    {
-      persistence.executeSQL("alter sequence " + sequenceName + " restart with " + start);
+      Object[] args = new Object[] {start};
+      String stmt = persistence.getDialect().getSequenceSetValString(sequenceName);
+      persistence.executeSQL(stmt, args);
    }
    
    /**

=== modified file 'src/com/goldencode/p2j/persist/TemporaryBuffer.java'
--- old/src/com/goldencode/p2j/persist/TemporaryBuffer.java	2022-12-06 13:47:32 +0000
+++ new/src/com/goldencode/p2j/persist/TemporaryBuffer.java	2023-01-09 10:46:17 +0000
@@ -628,6 +628,7 @@
 **     IAS 20221103          Fixed support for a binded table parameter.
 **     CA  20221206          If a REFERENCE-ONLY table is already bound to the same target table, do not 
 **                           re-bind. 
+**     RAA 20230109          Changed inline statement(s) to prepared statement(s).
 */
 
 /*
@@ -4799,11 +4800,12 @@
          // then update the flag for the after buffer:
          fql = new FQLExpression("update ");
          fql.append(getDMOImplementationName());
-         fql.append(" set _rowState = ").append(Integer.toString(Buffer.ROW_CREATED));
-         fql.append(" where ").append(MULTIPLEX_FIELD_NAME).append(" = ");
-         fql.append(Integer.toString(getMultiplexID()));
+         fql.append(" set _rowState = ?");
+         fql.append(" where ").append(MULTIPLEX_FIELD_NAME).append(" = ?");
          fql.append(" and (_rowState is null or _rowState = 0)");
-         persistence.deleteOrUpdate(fql.toFinalExpression(), null, getEntityName(), !isUndoable());
+         Object[] args = new Object[] {Integer.toString(Buffer.ROW_CREATED), 
+                                       Integer.toString(getMultiplexID())};
+         persistence.deleteOrUpdate(fql.toFinalExpression(), args, getEntityName(), !isUndoable());
       }
       catch (PersistenceException exc)
       {
@@ -5665,9 +5667,10 @@
       
       try
       {
+         Object[] args = new Object[] {getMultiplexID()};
          String sql = "select count(*) from " + getTable() + 
-                      " where " + MULTIPLEX_FIELD_NAME + " = " + getMultiplexID();
-         Long res = getPersistence().getSingleSQLResult(sql, null);
+                      " where " + MULTIPLEX_FIELD_NAME + " = ?";
+         Long res = getPersistence().getSingleSQLResult(sql, args);
          return res.intValue();
       
       }
@@ -7781,11 +7784,12 @@
       {
          if (!full)
          {
+            Object[] multiplexArgs = new Object[] {multiplexID};
             // execute a simple query to determine if there is any record in this virtual table
             String checkStmt = 
                   "select tt." + Session.PK + " from " + table + " tt " +
-                  "where tt." + MULTIPLEX_FIELD_NAME + " = " + multiplexID + " limit 1";
-            Long id = persistence.getSingleSQLResult(checkStmt, null);
+                  "where tt." + MULTIPLEX_FIELD_NAME + " = ?" + " limit 1";
+            Long id = persistence.getSingleSQLResult(checkStmt, multiplexArgs);
             full = (id == null);
          }
          

=== modified file 'src/com/goldencode/p2j/persist/dialect/Dialect.java'
--- old/src/com/goldencode/p2j/persist/dialect/Dialect.java	2022-11-01 01:24:34 +0000
+++ new/src/com/goldencode/p2j/persist/dialect/Dialect.java	2023-01-09 10:52:58 +0000
@@ -88,6 +88,7 @@
 **     OM  20221018          Added support for MariaDb lenient dialect.
 **     OM  20221026          Excluded table name from index name by default. It will be added as needed by
 **                           dialects.
+**     RAA 20230109          Added method getSequenceSetValString().
 */
 
 /*
@@ -759,6 +760,26 @@
    public abstract String getSequenceSetValString(String sequenceName, long newVal);
    
    /**
+    * Generate the appropriate select statement to reset the value of a sequence.
+    * 
+    * @param   sequenceName
+    *          The name of the sequence.
+    *
+    * @return  Dialect-specific string to set the current value of the sequence, or {@code null}
+    *          if not supported.
+    */
+   public abstract String getSequenceSetValString(String sequenceName);
+   
+   /**
+    * Generate the appropriate select statement to reset the value of a sequence.
+    * 
+    * @return  Dialect-specific string to set the current value of the sequence, or {@code null}
+    *          if not supported.
+    */
+   public abstract String getSequenceSetValString();
+   
+   /**
+    * 
     * Generate the appropriate select statement to retrieve the next value of a sequence.
     * 
     * @param   sequenceName
@@ -779,6 +800,17 @@
    public abstract String getSequenceCurrValString(String sequenceName);
    
    /**
+    * Generate the appropriate select statement to retrieve the current value of a sequence.
+    *
+    * @return  Dialect-specific string to query the sequence, or {@code null} if not supported.
+    */
+   public String getSequenceCurrValString()
+   {
+      throw new IllegalStateException(
+               "Current value of a sequence cannot be retrieved using prepared statements.");
+   }
+   
+   /**
     * Returns {@code true} if this dialect fully support the sequences as 4GL language (most important:
     * bounded values, cycle). If not fully supported, additional code is needed in P2J sequence class
     * implementation to fix this.

=== modified file 'src/com/goldencode/p2j/persist/dialect/MariaDbLenientDialect.java'
--- old/src/com/goldencode/p2j/persist/dialect/MariaDbLenientDialect.java	2022-11-03 00:24:27 +0000
+++ new/src/com/goldencode/p2j/persist/dialect/MariaDbLenientDialect.java	2023-01-09 10:57:04 +0000
@@ -9,6 +9,7 @@
 **                  becomes a subclass and will implement the methods to adhere to MariaDb strict(er) mode.
 **     OM  20221025 Improve sequence compatibility with 4GL.
 **     OM  20221026 Excluded table name from index name by default. It will be added as needed by dialects.
+**     RAA 20230109 Overrided method getSequenceSetValString().
 */
 
 /*
@@ -1074,6 +1075,37 @@
    }
    
    /**
+    * Generate the appropriate select statement to reset the value of a sequence.
+    *
+    * @param   sequenceName
+    *          The name of the sequence.
+    *
+    * @return  Dialect-specific string to set the current value of the sequence, or {@code null}
+    *          if not supported.
+    *
+    * @see  <a href="https://mariadb.com/kb/en/setval/">SETVAL() Function</a>
+    */
+   @Override
+   public String getSequenceSetValString(String sequenceName)
+   {
+      return "select setval(" + sequenceName + ", ?)";
+   }
+   
+   /**
+    * Generate the appropriate select statement to reset the value of a sequence.
+    *
+    * @return  Dialect-specific string to set the current value of the sequence, or {@code null}
+    *          if not supported.
+    *
+    * @see  <a href="https://mariadb.com/kb/en/setval/">SETVAL() Function</a>
+    */
+   @Override
+   public String getSequenceSetValString()
+   {
+      return "select setval(?, ?)";
+   }
+   
+   /**
     * Generate the appropriate select statement to retrieve the next value of a sequence.
     *
     * @param   sequenceName

=== modified file 'src/com/goldencode/p2j/persist/dialect/P2JH2Dialect.java'
--- old/src/com/goldencode/p2j/persist/dialect/P2JH2Dialect.java	2022-11-01 01:24:34 +0000
+++ new/src/com/goldencode/p2j/persist/dialect/P2JH2Dialect.java	2023-01-09 11:00:20 +0000
@@ -104,6 +104,7 @@
 **     OM  20221012          Fixed regression (invalid sort criteria) in previous commit.
 **     OM  20221026          Excluded table name from index name by default. It will be added as needed by
 **                           dialects.
+**     RAA 20230109          Overrided methods getSequenceSetValString() and getSequenceCurrValString().
 */
 
 /*
@@ -768,6 +769,35 @@
    }
    
    /**
+    * Generate the appropriate select statement to reset the value of a 
+    * sequence.
+    * 
+    * @param   sequenceName
+    *          The name of the sequence.
+    *
+    * @return  Dialect-specific string to query the sequence, or
+    *          <code>null</code> if not supported.
+    */
+   @Override
+   public String getSequenceSetValString(String sequenceName)
+   {
+      return "alter sequence " + sequenceName + " restart with ?";
+   }
+   
+   /**
+    * Generate the appropriate select statement to reset the value of a 
+    * sequence.
+    *
+    * @return  Dialect-specific string to query the sequence, or
+    *          <code>null</code> if not supported.
+    */
+   @Override
+   public String getSequenceSetValString()
+   {
+      throw new IllegalStateException("Can't reset value of a sequence with prepared statement in H2");
+   }
+   
+   /**
     * Generate the appropriate select statement to retrieve the current 
     * value of a sequence.
     * 
@@ -784,6 +814,21 @@
       return "select current_value from information_schema.sequences " +
              "where upper(sequence_name) = '" + sequenceName.toUpperCase() + "'";
    }
+   
+   /**
+    * Generate the appropriate select statement to retrieve the current 
+    * value of a sequence.
+    *
+    * @return  Dialect-specific string to query the sequence, or
+    *          <code>null</code> if not supported.
+    */
+   @Override
+   public String getSequenceCurrValString()
+   {
+      // this feature is not supported by H2 directly, use a workaround
+      return "select current_value from information_schema.sequences " +
+             "where upper(sequence_name) = ?";
+   }
 
    /**
     * Returns <code>true</code> if this dialect fully support the sequences as

=== modified file 'src/com/goldencode/p2j/persist/dialect/P2JPostgreSQLDialect.java'
--- old/src/com/goldencode/p2j/persist/dialect/P2JPostgreSQLDialect.java	2022-11-01 01:24:34 +0000
+++ new/src/com/goldencode/p2j/persist/dialect/P2JPostgreSQLDialect.java	2023-01-09 11:01:55 +0000
@@ -122,6 +122,7 @@
 **     IAS 20220921          Dialect-specific UDF schema.
 **     OM  20221026          Excluded table name from index name by default. It will be added as needed by
 **                           dialects.
+**     RAA 20230109          Overrided method getSequenceSetValString().
 */
 
 /*
@@ -1109,6 +1110,33 @@
    
    /**
     * Generate the appropriate select statement to retrieve the next value of a sequence.
+    * 
+    * @param   sequenceName
+    *          The name of the sequence.
+    *
+    * @return  Dialect-specific string to query the sequence, or
+    *          <code>null</code> if not supported.
+    */
+   @Override
+   public String getSequenceSetValString(String sequenceName)
+   {
+      return "select setval('" + sequenceName + "', ?)";
+   }
+   
+   /**
+    * Generate the appropriate select statement to retrieve the next value of a sequence.
+    *
+    * @return  Dialect-specific string to query the sequence, or
+    *          <code>null</code> if not supported.
+    */
+   @Override
+   public String getSequenceSetValString()
+   {
+      return "select setval(?, ?)";
+   }
+   
+   /**
+    * Generate the appropriate select statement to retrieve the next value of a sequence.
     *
     * @param   sequenceName
     *          The name of the sequence to be queried.

=== modified file 'src/com/goldencode/p2j/persist/dialect/P2JSQLServer2008Dialect.java'
--- old/src/com/goldencode/p2j/persist/dialect/P2JSQLServer2008Dialect.java	2022-10-27 02:35:45 +0000
+++ new/src/com/goldencode/p2j/persist/dialect/P2JSQLServer2008Dialect.java	2023-01-09 11:03:15 +0000
@@ -40,6 +40,7 @@
 **     IAS 20220816 Added getScriptRunner() method.
 **     IAS 20220913 Re-work processing of UDFs errors/warnings.
 **     OM  20221026 Excluded table name from index name by default. It will be added as needed by dialects.
+**     RAA 20230109 Overrided method getSequenceSetValString().
 */
 
 /*
@@ -961,6 +962,31 @@
    }
    
    /**
+    * Generate the appropriate select statement to reset the value of a sequence.
+    *
+    * @param   sequenceName
+    *          The name of the sequence.
+    *
+    * @return  Returning {@code null} since this dialect does not support sequences.
+    */
+   @Override
+   public String getSequenceSetValString(String sequenceName)
+   {
+      return null;
+   }
+   
+   /**
+    * Generate the appropriate select statement to reset the value of a sequence.
+    *
+    * @return  Returning {@code null} since this dialect does not support sequences.
+    */
+   @Override
+   public String getSequenceSetValString()
+   {
+      return null;
+   }
+   
+   /**
     * Generate the appropriate select statement to retrieve the next value of a sequence.
     *
     * @param   sequenceName

=== modified file 'src/com/goldencode/p2j/persist/dialect/P2JSQLServer2012Dialect.java'
--- old/src/com/goldencode/p2j/persist/dialect/P2JSQLServer2012Dialect.java	2021-03-18 11:47:13 +0000
+++ new/src/com/goldencode/p2j/persist/dialect/P2JSQLServer2012Dialect.java	2023-01-09 11:04:37 +0000
@@ -18,6 +18,7 @@
 ** 008 ECF 20200906 New ORM implementation.
 ** 008 IAS 20201204 Added id() method and support stub for word tables
 **     IAS 20210315 Refactored for working with word tables for _temp database
+**     RAA 20230109 Overrided method getSequenceCurrValString().
 **/
 
 /*
@@ -457,6 +458,21 @@
    }
    
    /**
+    * Generate the appropriate select statement to retrieve the current value of a sequence.
+    *
+    * @return  Dialect-specific string to query the sequence.
+    */
+   @Override
+   public String getSequenceCurrValString()
+   {
+      // the cast is needed because the column is of 'variant' datatype.
+      // the sql driver does not handle it and reports the following error: 
+      // 08S01 The "variant" data type is not supported.
+      return "select cast(current_value as bigint) " +
+             "from sys.sequences where name = ?";
+   }
+   
+   /**
     * Generate the appropriate select statement to retrieve the next value of a sequence.
     *
     * @param   sequenceName

=== modified file 'src/com/goldencode/p2j/persist/dirty/DefaultDirtyShareManager.java'
--- old/src/com/goldencode/p2j/persist/dirty/DefaultDirtyShareManager.java	2020-10-14 21:06:19 +0000
+++ new/src/com/goldencode/p2j/persist/dirty/DefaultDirtyShareManager.java	2023-01-09 11:06:04 +0000
@@ -75,6 +75,7 @@
 ** 028 ECF 20200906          New ORM implementation.
 ** 029 EVL 20200621          Adding NPE protection for lockSingle when index name is NULL or empty.
 ** 030 OM  20201012          Force use locally cached meta information instead of map lookup.
+** 031 RAA 20230109          Changed inline statement(s) to prepared statement(s).
 */
 
 /*
@@ -784,7 +785,7 @@
             }
             
             String hql = "delete from " + entity + 
-                         " where " + DatabaseManager.PRIMARY_KEY + " = " + id;
+                         " where " + DatabaseManager.PRIMARY_KEY + " = ?";
             Session session = null;
             boolean inTx = false;
             
@@ -793,6 +794,7 @@
                session = new Session(dirtyDatabase);
                inTx = session.beginTransaction();
                Query query = Session.createQuery(hql);
+               query.setParameter(0, id);
                query.executeUpdate(session);
                session.commit();
             }

=== modified file 'src/com/goldencode/p2j/persist/meta/TransactionTableUpdater.java'
--- old/src/com/goldencode/p2j/persist/meta/TransactionTableUpdater.java	2022-06-30 16:56:06 +0000
+++ new/src/com/goldencode/p2j/persist/meta/TransactionTableUpdater.java	2023-01-09 11:07:53 +0000
@@ -13,6 +13,7 @@
 **     OM  20201012 Force use locally cached meta information instead of map lookup.
 **     ECF 20220630 Fixed MinimalTrans getter/setter names to match conversion of historical names in _Trans
 **                  table.
+**     RAA 20230109 Changed inline statement(s) to prepared statement(s).
 */
 
 /*
@@ -197,6 +198,7 @@
          // drop all records that are no more valid
          StringBuilder buf = new StringBuilder(
                "delete from " + TRANS_TABLE + " where not trans_num in (");
+         List<Object> args = new ArrayList<>();
          Iterator<Integer> it = transactions.values().iterator();
          for (int i = 0; it.hasNext(); i++)
          {
@@ -205,10 +207,11 @@
                buf.append(',');
             }
             
-            buf.append(it.next());
+            args.add(it.next());
+            buf.append('?');
          }
          buf.append(')');
-         int delCounter = p.executeSQL(buf.toString());
+         int delCounter = p.executeSQL(buf.toString(), args.toArray());
          if (LOG.isLoggable(Level.FINE))
          {
             LOG.log(Level.FINE, "Dropped " + delCounter + " old _trans records from " + dbName);

=== modified file 'src/com/goldencode/p2j/persist/sequence/H2SequenceHandler.java'
--- old/src/com/goldencode/p2j/persist/sequence/H2SequenceHandler.java	2022-05-31 18:53:03 +0000
+++ new/src/com/goldencode/p2j/persist/sequence/H2SequenceHandler.java	2023-01-09 11:09:28 +0000
@@ -16,6 +16,7 @@
 ** 007 ECF 20180219 Reduce Hibernate session flushing, if possible.
 ** 008 OM  20200906 New ORM implementation.
 **     OM  20220531 Fixed an error message.
+**     RAA 20230109 Changed inline statement(s) to prepared statement(s).
 */
 
 /*
@@ -141,12 +142,13 @@
       
       Persistence persistence = ConnectionManager.getPersistence(ldbName);
       Dialect dialect = persistence.getDialect();
-      String strQuery = dialect.getSequenceCurrValString(seqName);
+      Object[] args = new Object[] {seqName};
+      String strQuery = dialect.getSequenceCurrValString();
       int64 ret;
       
       try
       {
-         ret = getResultValue(persistence.getSingleSQLResult(strQuery, null));
+         ret = getResultValue(persistence.getSingleSQLResult(strQuery, args));
       }
       catch (PersistenceException pe)
       {
@@ -366,11 +368,12 @@
       
       Persistence persistence = ConnectionManager.getPersistence(ldbName);
       Dialect dialect = persistence.getDialect();
-      String strQuery = dialect.getSequenceSetValString(seqName, newValFixed);
+      Object[] args = new Object[] {newValFixed};
+      String strQuery = dialect.getSequenceSetValString(seqName);
       
       try
       {
-         persistence.executeSQL(strQuery);
+         persistence.executeSQL(strQuery, args);
       }
       catch (PersistenceException pe)
       {

=== modified file 'src/com/goldencode/p2j/persist/sequence/PostgreSQLSequenceHandler.java'
--- old/src/com/goldencode/p2j/persist/sequence/PostgreSQLSequenceHandler.java	2022-10-14 10:18:06 +0000
+++ new/src/com/goldencode/p2j/persist/sequence/PostgreSQLSequenceHandler.java	2023-01-09 11:13:22 +0000
@@ -19,6 +19,7 @@
 **     OM  20220531 Fixed an error message.
 **     CA  20221014 Keep a lowercase map of crtSeqList sequence keys, as the change in 
 **                  SequenceManager.legacyMap will always load all sequences.
+**     RAA 20230109 Changed inline statement(s) to prepared statement(s).
 */
 
 /*
@@ -285,11 +286,12 @@
       
       Persistence persistence = ConnectionManager.getPersistence(ldbName);
       Dialect dialect = persistence.getDialect();
-      String setCrtValQuery = dialect.getSequenceSetValString(seqName, newVal);
+      Object[] args = new Object[] {seqName, newVal};
+      String setCrtValQuery = dialect.getSequenceSetValString();
       
       try
       {
-         persistence.getSingleSQLResult(setCrtValQuery, null);
+         persistence.getSingleSQLResult(setCrtValQuery, args);
       }
       catch (PersistenceException pe)
       {

=== modified file 'src/com/goldencode/p2j/report/ReportWorker.java'
--- old/src/com/goldencode/p2j/report/ReportWorker.java	2021-12-14 16:48:41 +0000
+++ new/src/com/goldencode/p2j/report/ReportWorker.java	2023-01-09 11:16:04 +0000
@@ -174,6 +174,7 @@
 **                           the latest version of H2).
 **     CA  20211214          The AST manager plugin must be context-local, for runtime conversion, as the 
 **                           InMemoryRegistryPlugin is not thread-safe.
+**     RAA 20230109          Changed inline statement(s) to prepared statement(s).
 */
 
 /*
@@ -453,29 +454,37 @@
          
          // read back the id that was autogenerated
          ResultSet rs = stmtReportInsert.getGeneratedKeys();
+         PreparedStatement stmt = null;
          rs.next();
          rpt.id = rs.getLong(1);
+         List<Object> args = new ArrayList<>();
          
          if (processTags && rpt.tags != null && !rpt.tags.isEmpty())
          {
-            StringBuilder buf = new StringBuilder("select id, name from tag where name in('");
+            StringBuilder buf = new StringBuilder("select id, name from tag where name in(");
             Iterator<String> iter = rpt.tags.iterator();
             for (int i = 0; iter.hasNext(); i++)
             {
                if (i > 0)
                {
-                  buf.append("', '");
+                  buf.append(", ");
                }
                String tag = iter.next();
                tag.replaceAll("\'", "\\\'");
-               buf.append(tag);
+               buf.append("?");
+               args.add(tag);
             }
-            buf.append("')");
+            buf.append(")");
             String sql = buf.toString();
             
             Map<String, Long> tagMap = new HashMap<>();
-            Statement stmt = connection.createStatement();
-            rs = stmt.executeQuery(sql);
+            stmt = connection.prepareStatement(sql);
+            for (int i = 0; i < args.size(); i++)
+            {
+               stmt.setObject(i + 1, args.get(i));
+            }
+            
+            rs = stmt.executeQuery();
             while (rs.next())
             {
                long tid = rs.getLong(1);
@@ -509,6 +518,16 @@
                stmtRptTagInsert.clearParameters();
             }
          }
+         
+         if (rs != null && !rs.isClosed())
+         {
+            rs.close();
+         }
+         
+         if (stmt != null && !stmt.isClosed())
+         {
+            stmt.close();
+         }
       }
       
       return rpt.id;

=== modified file 'src/com/goldencode/p2j/report/server/ReportApi.java'
--- old/src/com/goldencode/p2j/report/server/ReportApi.java	2022-08-23 08:40:08 +0000
+++ new/src/com/goldencode/p2j/report/server/ReportApi.java	2023-01-09 11:23:14 +0000
@@ -13,6 +13,7 @@
 **                  version of H2).
 **     OM  20220405 XmlFilePlugin can load either a file or a stream from application's jar.
 **     DDF 20220823 Replaced .nextvalue with next value for.
+**     RAA 20230109 Changed inline statement(s) to prepared statement(s).
 */
 
 /*
@@ -745,17 +746,20 @@
     */
    private static void applyFileFilter(Connection conn, Long profileId, long sessionId)
    {
-      try (Statement stmt = conn.createStatement())
+      PreparedStatement stmt = null;
+      ResultSet rs = null;
+      try
       {
          String sql;
-         ResultSet rs;
          
          if (profileId != null)
          {
             // if profileId is null, the active_file was just created and is already empty;
             // otherwise, delete all its records in preparation for re-population with the new
             // filter profile's data
-            stmt.execute("delete from active_file where sid = " + sessionId);
+            stmt = conn.prepareStatement("delete from active_file where sid = ?");
+            stmt.setObject(1, sessionId);
+            stmt.executeUpdate();
          }
          
          // Query file specs and types for the provided file filter profile; we will compose a
@@ -763,6 +767,7 @@
          // If provided profile id was null, get the default profile.
          
          int i;
+         int type = 0;
          
          // wildcard path specs first
          
@@ -776,9 +781,25 @@
          {
             sql = "select f.spec from file_filter f " +
                   "join filter_profile p on p.id = f.pid " +
-                  "where p.id = " + profileId + " and f.wild = true";
-         }
-         rs = stmt.executeQuery(sql);
+                  "where p.id = ?" + " and f.wild = true";
+            type = 1;
+         }
+         
+         if (stmt != null && !stmt.isClosed())
+         {
+            stmt.close();
+         }
+         
+         stmt = conn.prepareStatement(sql);
+         if (type == 1)
+         {
+            stmt.setObject(1, profileId);
+         }
+         
+         type = 0;
+         rs = stmt.executeQuery();
+
+         List<Object> args = new ArrayList<>();
          
          StringBuilder buf = new StringBuilder("insert into active_file (fid, sid) ");
          for (i = 0; rs.next(); i++)
@@ -792,10 +813,10 @@
             
             buf.append("select distinct(f.id), ");
             buf.append(sessionId);
-            buf.append(" from file f join ast_map a on a.fid = f.id where f.name like '");
-            buf.append(dbs.escapeLikeRValue(spec));
-            buf.setCharAt(buf.length() - 1, '%');
-            buf.append("'");
+            buf.append(" from file f join ast_map a on a.fid = f.id where f.name like ?");
+            String arg1 = dbs.escapeLikeRValue(spec);
+            arg1 = arg1.substring(0, arg1.length() - 1) + '%';
+            args.add(arg1);
          }
          
          if (profileId == null)
@@ -808,9 +829,28 @@
          {
             sql = "select f.spec from file_filter f " +
                   "join filter_profile p on p.id = f.pid " +
-                  "where p.id = " + profileId + " and f.wild = false";
-         }
-         rs = stmt.executeQuery(sql);
+                  "where p.id = ?" + " and f.wild = false";
+            type = 1;
+         }
+         
+         if (rs != null && !rs.isClosed())
+         {
+            rs.close();
+         }
+         
+         if (stmt != null && !stmt.isClosed())
+         {
+            stmt.close();
+         }
+         
+         stmt = conn.prepareStatement(sql);
+         if (type == 1)
+         {
+            stmt.setObject(1, profileId);
+         }
+         
+         type = 0;
+         rs = stmt.executeQuery();
          
          int j = 0;
          for (; rs.next(); i++)
@@ -833,9 +873,7 @@
                buf.append(", ");
             }
             
-            buf.append("'");
-            buf.append(spec);
-            buf.append("'");
+            args.add(spec);
             
             if (++j == 100)
             {
@@ -851,7 +889,23 @@
          
          sql = buf.toString();
          
-         stmt.execute(sql);
+         if (rs != null && !rs.isClosed())
+         {
+            rs.close();
+         }
+         
+         if (stmt != null && !stmt.isClosed())
+         {
+            stmt.close();
+         }
+         
+         stmt = conn.prepareStatement(sql);
+         for (int k = 0; k < args.size();k++)
+         {
+            stmt.setObject(k + 1, args.get(k));
+         }
+         
+         stmt.execute();
          int uc = stmt.getUpdateCount();
          System.out.println("applyActiveFile update count: " + uc);
          
@@ -873,6 +927,25 @@
          
          throw new RuntimeException(exc);
       }
+      finally
+      {
+         try
+         {
+            if (rs != null && !rs.isClosed())
+            {
+               rs.close();
+            }
+            
+            if (stmt != null && !stmt.isClosed())
+            {
+               stmt.close();
+            }
+         }
+         catch (SQLException e)
+         {
+            e.printStackTrace();
+         }
+      }
    }
    
    /**
@@ -2513,29 +2586,33 @@
       buf.append("insert into search_history ");
       buf.append("select * from (select next value for seq_search_history_pk, '");
       buf.append(criteria);
-      buf.append("' ) x where not exists (select 1 from search_history where criteria = '");
-      buf.append(criteria);
-      buf.append("')");
+      buf.append("' ) x where not exists (select 1 from search_history where criteria = ?)");
+      Object histArg = criteria;
       String sqlInsSrchHist = buf.toString();
       
       // compose sql to insert into user_search table, if not already present
       buf.setLength(0);
       buf.append("insert into user_search select * from (select ");
       buf.append(user.getId());
-      buf.append(" as u, select id from search_history where criteria = '");
-      buf.append(criteria);
-      buf.append("' as s) x where exists (select 1 from search_history where criteria = '");
-      buf.append(criteria);
-      buf.append("') and not exists (select 1 from user_search where uid = x.u and sid = x.s)");
+      buf.append(" as u, select id from search_history where criteria = ?");
+      buf.append(" as s) x where exists (select 1 from search_history where criteria = ?");
+      buf.append(") and not exists (select 1 from user_search where uid = x.u and sid = x.s)");
+      Object usrArg = criteria;
       String sqlInsUsrSrch = buf.toString();
       
-      try (Statement stmt = conn.createStatement())
+      //tested with H2 1.4.200 and prepared statements now work with subselects
+      try (PreparedStatement stmt = conn.prepareStatement(sqlInsSrchHist))
       {
-         // we use Statement instead of PreparedStatement here because we need a substitution
-         // parameter in the select clauses of each statement, which H2 does not allow
-         stmt.execute(sqlInsSrchHist);
-         stmt.execute(sqlInsUsrSrch);
+         stmt.setObject(1, histArg);
+         stmt.execute();
       }
+      
+      try (PreparedStatement stmt = conn.prepareStatement(sqlInsUsrSrch))
+      {
+         stmt.setObject(1, usrArg);
+         stmt.setObject(2, usrArg);
+         stmt.execute();
+       }
    }
    
    /**

