content: package com.taobao.tddl.dbsync.binlog.event;
  
  import java.io.IOException;
  
  import com.taobao.tddl.dbsync.binlog.LogBuffer;
  
  /**
   * Event responsible for LOAD DATA execution, it similar to Query_log_event but
   * before executing the query it substitutes original filename in LOAD DATA
   * query with name of temporary file.
   * <ul>
   * <li>4 bytes. The ID of the file to load.</li>
   * <li>4 bytes. The start position within the statement for filename
   * substitution.</li>
   * <li>4 bytes. The end position within the statement for filename substitution.
   * </li>
   * <li>1 byte. How to handle duplicates: LOAD_DUP_ERROR = 0, LOAD_DUP_IGNORE =
   * 1, LOAD_DUP_REPLACE = 2</li>
   * </ul>
   * 
   * @author <a href="mailto:changyuan.lh@taobao.com">Changyuan.lh</a>
   * @version 1.0
   */
  public final class ExecuteLoadQueryLogEvent extends QueryLogEvent {
  
      /** file_id of temporary file */
      private long            fileId;
  
      /** pointer to the part of the query that should be substituted */
      private int             fnPosStart;
  
      /** pointer to the end of this part of query */
      private int             fnPosEnd;
  
      /*
       * Elements of this enum describe how LOAD DATA handles duplicates.
       */
      public static final int LOAD_DUP_ERROR          = 0;
      public static final int LOAD_DUP_IGNORE         = LOAD_DUP_ERROR + 1;
      public static final int LOAD_DUP_REPLACE        = LOAD_DUP_IGNORE + 1;
  
      /**
       * We have to store type of duplicate handling explicitly, because for LOAD
       * DATA it also depends on LOCAL option. And this part of query will be
       * rewritten during replication so this information may be lost...
       */
      private int             dupHandling;
  
      /* ELQ = "Execute Load Query" */
      public static final int ELQ_FILE_ID_OFFSET      = QUERY_HEADER_LEN;
      public static final int ELQ_FN_POS_START_OFFSET = ELQ_FILE_ID_OFFSET + 4;
      public static final int ELQ_FN_POS_END_OFFSET   = ELQ_FILE_ID_OFFSET + 8;
      public static final int ELQ_DUP_HANDLING_OFFSET = ELQ_FILE_ID_OFFSET + 12;
  
      public ExecuteLoadQueryLogEvent(LogHeader header, LogBuffer buffer, FormatDescriptionLogEvent descriptionEvent,
                                      boolean compatiablePercona) throws IOException{
          super(header, buffer, descriptionEvent, compatiablePercona);
  
          buffer.position(descriptionEvent.commonHeaderLen + ELQ_FILE_ID_OFFSET);
  
          fileId = buffer.getUint32(); // ELQ_FILE_ID_OFFSET
          fnPosStart = (int) buffer.getUint32(); // ELQ_FN_POS_START_OFFSET
          fnPosEnd = (int) buffer.getUint32(); // ELQ_FN_POS_END_OFFSET
          dupHandling = buffer.getInt8(); // ELQ_DUP_HANDLING_OFFSET
  
          final int len = query.length();
          if (fnPosStart > len || fnPosEnd > len || dupHandling > LOAD_DUP_REPLACE) {
              throw new IOException(String.format("Invalid ExecuteLoadQueryLogEvent: fn_pos_start=%d, "
                                                  + "fn_pos_end=%d, dup_handling=%d", fnPosStart, fnPosEnd, dupHandling));
          }
      }
  
      public final int getFilenamePosStart() {
          return fnPosStart;
      }
  
      public final int getFilenamePosEnd() {
          return fnPosEnd;
      }
  
      public final String getFilename() {
          if (query != null) return query.substring(fnPosStart, fnPosEnd).trim();
  
          return null;
      }
  
      public final long getFileId() {
          return fileId;
      }
  }
  