public ValidationErrors validate(
      InsertOrUpdateStatement statement, Database database, SqlGeneratorChain sqlGeneratorChain) {
    ValidationErrors validationErrors = new ValidationErrors();
    validationErrors.checkRequiredField("tableName", statement.getTableName());
    validationErrors.checkRequiredField("columns", statement.getColumnValues());
    validationErrors.checkRequiredField("primaryKey", statement.getPrimaryKey());

    return validationErrors;
  }
  protected String getWhereClause(
      InsertOrUpdateStatement insertOrUpdateStatement, Database database) {
    StringBuffer where = new StringBuffer();

    String[] pkColumns = insertOrUpdateStatement.getPrimaryKey().split(",");

    for (String thisPkColumn : pkColumns) {
      where
          .append(
              database.escapeColumnName(
                  insertOrUpdateStatement.getSchemaName(),
                  insertOrUpdateStatement.getTableName(),
                  thisPkColumn))
          .append(" = ");
      Object newValue = insertOrUpdateStatement.getColumnValues().get(thisPkColumn);
      if (newValue == null || newValue.toString().equals("NULL")) {
        where.append("NULL");
      } else if (newValue instanceof String && database.shouldQuoteValue(((String) newValue))) {
        where.append("'").append(database.escapeStringForDatabase((String) newValue)).append("'");
      } else if (newValue instanceof Date) {
        where.append(database.getDateLiteral(((Date) newValue)));
      } else if (newValue instanceof Boolean) {
        if (((Boolean) newValue)) {
          where.append(
              TypeConverterFactory.getInstance()
                  .findTypeConverter(database)
                  .getBooleanType()
                  .getTrueBooleanValue());
        } else {
          where.append(
              TypeConverterFactory.getInstance()
                  .findTypeConverter(database)
                  .getBooleanType()
                  .getFalseBooleanValue());
        }
      } else {
        where.append(newValue);
      }

      where.append(" AND ");
    }

    where.delete(where.lastIndexOf(" AND "), where.lastIndexOf(" AND ") + " AND ".length());
    return where.toString();
  }
  @Override
  protected String getInsertStatement(
      InsertOrUpdateStatement insertOrUpdateStatement,
      Database database,
      SqlGeneratorChain sqlGeneratorChain) {
    StringBuilder columns = new StringBuilder();
    StringBuilder values = new StringBuilder();

    for (String columnKey : insertOrUpdateStatement.getColumnValues().keySet()) {
      columns.append(",");
      columns.append(columnKey);
      values.append(",");
      values.append(convertToString(insertOrUpdateStatement.getColumnValue(columnKey), database));
    }
    columns.deleteCharAt(0);
    values.deleteCharAt(0);
    return "INSERT (" + columns.toString() + ") VALUES (" + values.toString() + ")";
  }
 @Override
 protected String getRecordCheck(
     InsertOrUpdateStatement insertOrUpdateStatement, Database database, String whereClause) {
   StringBuilder sql = new StringBuilder();
   sql.append("MERGE INTO ");
   sql.append(insertOrUpdateStatement.getTableName());
   sql.append(" USING (VALUES (1)) ON ");
   sql.append(whereClause);
   sql.append(" WHEN NOT MATCHED THEN ");
   return sql.toString();
 }
  /**
   * @param insertOrUpdateStatement
   * @param database
   * @param whereClause
   * @param sqlGeneratorChain
   * @return the update statement, if there is nothing to update return null
   */
  protected String getUpdateStatement(
      InsertOrUpdateStatement insertOrUpdateStatement,
      Database database,
      String whereClause,
      SqlGeneratorChain sqlGeneratorChain)
      throws LiquibaseException {

    StringBuffer updateSqlString = new StringBuffer();

    UpdateGenerator update = new UpdateGenerator();
    UpdateStatement updateStatement =
        new UpdateStatement(
            insertOrUpdateStatement.getSchemaName(), insertOrUpdateStatement.getTableName());
    updateStatement.setWhereClause(whereClause + ";\n");

    String[] pkFields = insertOrUpdateStatement.getPrimaryKey().split(",");
    HashSet<String> hashPkFields = new HashSet<String>(Arrays.asList(pkFields));
    for (String columnKey : insertOrUpdateStatement.getColumnValues().keySet()) {
      if (!hashPkFields.contains(columnKey)) {
        updateStatement.addNewColumnValue(
            columnKey, insertOrUpdateStatement.getColumnValue(columnKey));
      }
    }
    // this isn't very elegant but the code fails above without any columns to update
    if (updateStatement.getNewColumnValues().isEmpty()) {
      throw new LiquibaseException("No fields to update in set clause");
    }

    Sql[] updateSql = update.generateSql(updateStatement, database, sqlGeneratorChain);

    for (Sql s : updateSql) {
      updateSqlString.append(s.toSql());
      updateSqlString.append(";");
    }

    updateSqlString.deleteCharAt(updateSqlString.lastIndexOf(";"));
    updateSqlString.append("\n");

    return updateSqlString.toString();
  }
  @Override
  protected String getUpdateStatement(
      InsertOrUpdateStatement insertOrUpdateStatement,
      Database database,
      String whereClause,
      SqlGeneratorChain sqlGeneratorChain) {

    StringBuilder sql = new StringBuilder("UPDATE SET ");

    //		String[] pkFields = insertOrUpdateStatement.getPrimaryKey().split(",");
    //		HashSet<String> hashPkFields = new HashSet<String>(Arrays.asList(pkFields));
    for (String columnKey : insertOrUpdateStatement.getColumnValues().keySet()) {
      //			if (!hashPkFields.contains(columnKey)) {
      sql.append(columnKey).append(" = ");
      sql.append(convertToString(insertOrUpdateStatement.getColumnValue(columnKey), database));
      sql.append(",");
      //			}
    }
    int lastComma = sql.lastIndexOf(",");
    if (lastComma > -1) {
      sql.deleteCharAt(lastComma);
    }
    return sql.toString();
  }