001package io.ebeaninternal.server.core;
002
003import io.ebeaninternal.api.SpiEbeanServer;
004import io.ebeaninternal.api.SpiSqlUpdate;
005import io.ebeaninternal.api.SpiTransaction;
006import io.ebeaninternal.server.lib.Str;
007import io.ebeaninternal.server.persist.BatchControl;
008import io.ebeaninternal.server.persist.PersistExecute;
009import io.ebeaninternal.server.persist.TrimLogSql;
010
011/**
012 * Persist request specifically for CallableSql.
013 */
014public final class PersistRequestUpdateSql extends PersistRequest {
015
016  public enum SqlType {
017    SQL_UPDATE, SQL_DELETE, SQL_INSERT, SQL_UNKNOWN
018  }
019
020  private final SpiSqlUpdate updateSql;
021
022  private int rowCount;
023
024  private String bindLog;
025
026  private SqlType sqlType;
027
028  private String tableName;
029
030  private boolean addBatch;
031
032  private final boolean forceNoBatch;
033
034  private boolean batchThisRequest;
035  private boolean flushQueue;
036
037  public PersistRequestUpdateSql(SpiEbeanServer server, SpiSqlUpdate sqlUpdate,
038                                 SpiTransaction t, PersistExecute persistExecute, boolean forceNoBatch) {
039
040    super(server, t, persistExecute, sqlUpdate.getLabel());
041    this.type = Type.UPDATESQL;
042    this.updateSql = sqlUpdate;
043    this.forceNoBatch = forceNoBatch;
044    updateSql.reset();
045  }
046
047  public PersistRequestUpdateSql(SpiEbeanServer server, SpiSqlUpdate sqlUpdate,
048                                 SpiTransaction t, PersistExecute persistExecute) {
049    this(server, sqlUpdate, t, persistExecute, false);
050  }
051
052  @Override
053  public void profile(long offset, int flushCount) {
054    profileBase(EVT_UPDATESQL, offset, "", flushCount);
055  }
056
057  /**
058   * Add this statement to JDBC batch for later execution.
059   */
060  public int addBatch() {
061    this.addBatch = true;
062    return executeOrQueue();
063  }
064
065  /**
066   * Execute using jdbc batch.
067   */
068  public void executeAddBatch() {
069    this.addBatch = true;
070    persistExecute.executeSqlUpdate(this);
071  }
072
073  /**
074   * Add this request to BatchControl to flush later.
075   */
076  public void addToFlushQueue(boolean early) {
077    BatchControl control = transaction.getBatchControl();
078    if (control == null) {
079      control = persistExecute.createBatchControl(transaction);
080    }
081    flushQueue = true;
082    control.addToFlushQueue(this, early);
083  }
084
085  @Override
086  public boolean isFlushQueue() {
087    return flushQueue;
088  }
089
090  @Override
091  public int executeNow() {
092    return persistExecute.executeSqlUpdate(this);
093  }
094
095  @Override
096  public boolean isBatchThisRequest() {
097    return !forceNoBatch && (addBatch || super.isBatchThisRequest());
098  }
099
100  @Override
101  public int executeOrQueue() {
102    return executeStatement();
103  }
104
105  /**
106   * Return the UpdateSql.
107   */
108  public SpiSqlUpdate getUpdateSql() {
109    return updateSql;
110  }
111
112  /**
113   * No concurrency checking so just note the rowCount.
114   */
115  @Override
116  public void checkRowCount(int count) {
117    this.rowCount = count;
118  }
119
120  /**
121   * Not called for this type of request.
122   */
123  @Override
124  public void setGeneratedKey(Object idValue) {
125    updateSql.setGeneratedKey(idValue);
126  }
127
128  public boolean isGetGeneratedKeys() {
129    return updateSql.isGetGeneratedKeys();
130  }
131
132  /**
133   * Specify the type of statement executed. Used to automatically register
134   * with the transaction event.
135   */
136  public void setType(SqlType sqlType, String tableName) {
137    this.sqlType = sqlType;
138    this.tableName = tableName;
139  }
140
141  /**
142   * Set the bound values.
143   */
144  public void setBindLog(String bindLog) {
145    this.bindLog = bindLog;
146  }
147
148  public void startBind(boolean batchThisRequest) {
149    this.batchThisRequest = batchThisRequest;
150    super.startBind(batchThisRequest);
151  }
152
153  /**
154   * Log the sql bind used with jdbc batch.
155   */
156  public void logSqlBatchBind() {
157    if (transaction.isLogSql()) {
158      transaction.logSql(Str.add(" -- bind(", bindLog, ")"));
159    }
160  }
161
162  /**
163   * Perform post execute processing.
164   */
165  @Override
166  public void postExecute() {
167    if (startNanos > 0) {
168      persistExecute.collectSqlUpdate(label, startNanos);
169    }
170    if (transaction.isLogSql() && !batchThisRequest) {
171      transaction.logSql(Str.add(TrimLogSql.trim(updateSql.getGeneratedSql()), "; -- bind(", bindLog, ") rows(", String.valueOf(rowCount), ")"));
172    }
173
174    if (updateSql.isAutoTableMod()) {
175      // add the modification info to the TransactionEvent
176      // this is used to invalidate cached objects etc
177      switch (sqlType) {
178        case SQL_INSERT:
179          transaction.getEvent().add(tableName, true, false, false);
180          break;
181        case SQL_UPDATE:
182          transaction.getEvent().add(tableName, false, true, false);
183          break;
184        case SQL_DELETE:
185          transaction.getEvent().add(tableName, false, false, true);
186          break;
187        case SQL_UNKNOWN:
188          transaction.markNotQueryOnly();
189
190        default:
191          break;
192      }
193    }
194  }
195
196}