UpdatableMyConnectionView.java

/*
** Module   : UpdatableMyConnectionView.java
** Abstract : Trigger for _MyConnection  View
**
** Copyright (c) 2021-2022, Golden Code Development Corporation.
**
** -#- -I- --Date-- --------------------------------------Description----------------------------------------
** 001 IAS 20210401 Created initial version.
**     ECF 20210512 Fixed hard-coded references to "RECID" as primary key. Cleaned up format.
**     ECF 20220630 Fixed hard-coded references to converted _MyConnection column names which have changed.
*/

/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
** 
** Additional terms under GNU Affero GPL version 3 section 7:
** 
**   Under Section 7 of the GNU Affero GPL version 3, the following additional
**   terms apply to the works covered under the License.  These additional terms
**   are non-permissive additional terms allowed under Section 7 of the GNU
**   Affero GPL version 3 and may not be removed by you.
** 
**   0. Attribution Requirement.
** 
**     You must preserve all legal notices or author attributions in the covered
**     work or Appropriate Legal Notices displayed by works containing the covered
**     work.  You may not remove from the covered work any author or developer
**     credit already included within the covered work.
** 
**   1. No License To Use Trademarks.
** 
**     This license does not grant any license or rights to use the trademarks
**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
**     of Golden Code Development Corporation. You are not authorized to use the
**     name Golden Code, FWD, or the names of any author or contributor, for
**     publicity purposes without written authorization.
** 
**   2. No Misrepresentation of Affiliation.
** 
**     You may not represent yourself as Golden Code Development Corporation or FWD.
** 
**     You may not represent yourself for publicity purposes as associated with
**     Golden Code Development Corporation, FWD, or any author or contributor to
**     the covered work, without written authorization.
** 
**   3. No Misrepresentation of Source or Origin.
** 
**     You may not represent the covered work as solely your work.  All modified
**     versions of the covered work must be marked in a reasonable way to make it
**     clear that the modified work is not originating from Golden Code Development
**     Corporation or FWD.  All modified versions must contain the notices of
**     attribution required in this license.
*/

package com.goldencode.p2j.persist.h2;

import java.sql.*;
import java.util.*;
import java.util.Collections;
import org.h2.tools.*;
import com.goldencode.p2j.persist.orm.*;

/**
 * Trigger for _MyConnection  View 
 */
public class UpdatableMyConnectionView extends TriggerAdapter
{
   /** meta_mayconnection table column types */
   private static final List<Integer> FTYPES = Collections.unmodifiableList(
      Arrays.asList(Types.BIGINT,
                    Types.INTEGER,
                    Types.INTEGER,
                    Types.INTEGER,
                    Types.INTEGER,
                    Types.INTEGER,
                    Types.BIGINT));
   
   /** Map SQL types to Java classes */
   private static final Map<Integer, Class<?>> FJTYPES = Collections.unmodifiableMap(
      new HashMap<Integer, Class<?>>()
      {
         {
            put(Types.BIGINT, Long.class);
            put(Types.INTEGER, Integer.class);
         }
      }
   );
   
   /** PreparedStatement for DELETE */
   private PreparedStatement prepDelete;
   
   /** PreparedStatement for INSERT */
   private PreparedStatement prepInsert;
   
   /**
    * This method is called by the database engine once when initializing the
    * trigger. It is called when the trigger is created, as well as when the
    * database is opened. The default implementation initialized the result
    * sets.
    *
    * @param   conn
    *          A connection to the database.
    * @param   schemaName
    *          The name of the schema.
    * @param   triggerName
    *          The name of the trigger used in the CREATE TRIGGER statement.
    * @param   tableName
    *          The name of the table.
    * @param   before
    *          Whether the fire method is called before or after the operation is performed
    * @param   type
    *          The operation type: INSERT, UPDATE, DELETE, SELECT, or a combination (this parameter is a bit
    *          field)
    */
   @Override
   public void init(Connection conn,
                    String schemaName,
                    String triggerName,
                    String tableName,
                    boolean before,
                    int type)
   throws SQLException
   {
       prepDelete = conn.prepareStatement(
          "DELETE FROM meta_myconnection_ WHERE " + Session.PK + " = ? AND my_conn_user_id = fwdSession_1()");
       
       // INSERT and UPDATE triggers should return the FINAL values of the row.
       // Table TEST_TABLE has a generated column, so the FINAL row can be
       // different from the row that we try to insert here.
       prepInsert = conn.prepareStatement(
          "SELECT * FROM FINAL TABLE(INSERT INTO meta_myconnection_ VALUES (?, ?, ?, ?, ?, ?, ?))");
       
       super.init(conn, schemaName, triggerName, tableName, before, type);
   }
   
   /**
    * This method is called for each triggered action by the default
    * fire(Connection conn, Object[] oldRow, Object[] newRow) method.
    * ResultSet.next does not need to be called (and calling it has no effect;
    * it will always return true).
    * <p>
    * For "before" triggers, the new values of the new row may be changed
    * using the ResultSet.updateX methods.
    * </p>
    *
    * @param   conn
    *          A connection to the database.
    * @param   oldRow
    *          the old row, or null if no old row is available (for INSERT).
    * @param   newRow
    *          The new row, or null if no new row is available (for DELETE).
    * 
    * @throws  SQLException
    *          if the operation must be undone.
    */
   @Override
   public void fire(Connection conn, ResultSet oldRow, ResultSet newRow)
   throws SQLException
   {
       if (oldRow != null && oldRow.next())
       {
           prepDelete.setLong(1, oldRow.getLong(Session.PK));
           prepDelete.execute();
       }
       
       if (newRow != null && newRow.next())
       {
          for(int nc = 0; nc < FTYPES.size(); nc++)
          {
             Object val = newRow.getObject(nc + 1, javaType(nc));
             if (newRow.wasNull())
             {
                prepInsert.setNull(nc + 1, sqlType(nc));
             }
             else
             {
                prepInsert.setObject(nc + 1, val, sqlType(nc));
             }
          }
          try (ResultSet rs = prepInsert.executeQuery())
          {
             rs.next();
             for(int nc = 0; nc < FTYPES.size(); nc++)
             {
                newRow.updateObject(nc + 1, rs.getObject(nc + 1, javaType(nc)), sqlType(nc));
             }
          }
       }
   }
   
   /**
    * This method is called when the trigger is dropped. The default implementation does nothing.
    */
   @Override
   public void close()
   throws SQLException
   {
       prepInsert.close();
       prepDelete.close();
   }
   
   /**
    * Get the Java data type of the column.
    * 
    * @param   nc
    *          Column position.
    * 
    * @return  Java data type of the column.
    */
   private Class<?> javaType(int nc)
   {
      return FJTYPES.get(sqlType(nc));
   }
   
   /**
    * Get the SQL data type of the column;
    * 
    * @param   nc
    *          Column position.
    * 
    * @return  SQL data type of the column;
    */
   private Integer sqlType(int nc)
   {
      return FTYPES.get(nc);
   }
}