@Implementation
  public int update(String table, ContentValues values, String whereClause, String[] whereArgs) {
    SQLStringAndBindings sqlUpdateString = buildUpdateString(table, values, whereClause, whereArgs);

    try {
      PreparedStatement statement = connection.prepareStatement(sqlUpdateString.sql);
      Iterator<Object> columns = sqlUpdateString.columnValues.iterator();
      int i = 1;
      while (columns.hasNext()) {
        statement.setObject(i++, columns.next());
      }

      return statement.executeUpdate();
    } catch (SQLException e) {
      throw new RuntimeException("SQL exception in update", e);
    }
  }
  @Implementation
  public long insert(String table, String nullColumnHack, ContentValues values) {
    SQLStringAndBindings sqlInsertString = buildInsertString(table, values);
    try {
      PreparedStatement statement =
          connection.prepareStatement(sqlInsertString.sql, Statement.RETURN_GENERATED_KEYS);
      Iterator<Object> columns = sqlInsertString.columnValues.iterator();
      int i = 1;
      while (columns.hasNext()) {
        statement.setObject(i++, columns.next());
      }

      statement.executeUpdate();

      ResultSet resultSet = statement.getGeneratedKeys();
      if (resultSet.first()) {
        return resultSet.getLong(1);
      }
    } catch (SQLException e) {
      throw new RuntimeException("SQL exception in insert", e);
    }
    return -1;
  }