@Override
  public void write(PreparedStatement statement) throws SQLException {
    // make sure we at least line up in size
    if (upsertValues.size() != columnMetaDataList.size()) {
      throw new UnsupportedOperationException(
          "Provided "
              + upsertValues.size()
              + " upsert values, but column metadata expects "
              + columnMetaDataList.size()
              + " columns.");
    }

    // correlate each value (v) to a column type (c) and an index (i)
    for (int i = 0; i < upsertValues.size(); i++) {
      Object v = upsertValues.get(i);
      ColumnInfo c = columnMetaDataList.get(i);

      if (v == null) {
        statement.setNull(i + 1, c.getSqlType());
        continue;
      }

      // both Java and Joda dates used to work in 4.2.3, but now they must be java.sql.Date
      // can override any other types here as needed
      final Object finalObj;
      final PDataType<?> finalType;
      if (v instanceof DateTime) {
        finalObj = new java.sql.Date(((DateTime) v).getMillis());
        finalType = PDate.INSTANCE;
      } else if (v instanceof java.util.Date) {
        finalObj = new java.sql.Date(((java.util.Date) v).getTime());
        finalType = PDate.INSTANCE;
      } else {
        finalObj = v;
        finalType = c.getPDataType();
      }

      if (finalObj instanceof Object[]) {
        setArrayInStatement(statement, finalType, (Object[]) finalObj, i + 1);
      } else if (finalObj instanceof byte[]) {
        // PVarbinary and PBinary are provided as byte[] but are treated as SQL objects
        if (PDataType.equalsAny(finalType, PVarbinary.INSTANCE, PBinary.INSTANCE)) {
          statement.setObject(i + 1, finalObj);
        }
        // otherwise set as array type
        setArrayInStatement(
            statement, finalType, primativeArrayToObjectArray((byte[]) finalObj), i + 1);
      } else if (finalObj instanceof short[]) {
        setArrayInStatement(
            statement, finalType, primativeArrayToObjectArray((short[]) finalObj), i + 1);
      } else if (finalObj instanceof int[]) {
        setArrayInStatement(
            statement, finalType, primativeArrayToObjectArray((int[]) finalObj), i + 1);
      } else if (finalObj instanceof long[]) {
        setArrayInStatement(
            statement, finalType, primativeArrayToObjectArray((long[]) finalObj), i + 1);
      } else if (finalObj instanceof float[]) {
        setArrayInStatement(
            statement, finalType, primativeArrayToObjectArray((float[]) finalObj), i + 1);
      } else if (finalObj instanceof double[]) {
        setArrayInStatement(
            statement, finalType, primativeArrayToObjectArray((double[]) finalObj), i + 1);
      } else {
        statement.setObject(i + 1, finalObj);
      }
    }
  }