/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.phoenix.end2end;

import static org.junit.Assert.assertEquals;

import java.sql.*;
import org.junit.Test;
import org.junit.experimental.categories.Category;

@Category(ParallelStatsDisabledTest.class)
public class ArraysWithNullsIT extends ParallelStatsDisabledIT {

  @Test
  public void testArrayUpsertIntWithNulls() throws Exception {
    Connection conn = DriverManager.getConnection(getUrl());
    String t1 = generateUniqueName();
    conn.createStatement().execute("CREATE TABLE " + t1 + " ( k VARCHAR PRIMARY KEY, a INTEGER[])");

    PreparedStatement stmt =
      conn.prepareStatement("UPSERT INTO " + t1 + " VALUES('a',ARRAY[null,3,null])");
    stmt.execute();
    conn.commit();

    ResultSet rs = conn.createStatement().executeQuery("Select a from " + t1 + " where k = 'a'");
    rs.next();
    Array array = conn.createArrayOf("INTEGER", new Object[] { null, 3, null });

    assertEquals(rs.getArray(1), array);
    conn.close();

  }

  @Test
  public void testArrayUpsertVarcharWithNulls() throws Exception {
    Connection conn = DriverManager.getConnection(getUrl());
    String t2 = generateUniqueName();
    conn.createStatement().execute("CREATE TABLE " + t2 + " ( k VARCHAR PRIMARY KEY, a VARCHAR[])");

    PreparedStatement stmt =
      conn.prepareStatement("UPSERT INTO " + t2 + " VALUES('a',ARRAY['10',null])");
    stmt.execute();
    conn.commit();

    ResultSet rs = conn.createStatement().executeQuery("Select a from " + t2 + " where k = 'a'");
    rs.next();
    Array array = conn.createArrayOf("VARCHAR", new Object[] { "10", null });

    assertEquals(rs.getArray(1), array);
    conn.close();

  }

  @Test
  public void testArrayUpsertBigIntWithNulls() throws Exception {
    Connection conn = DriverManager.getConnection(getUrl());
    String t3 = generateUniqueName();
    conn.createStatement().execute("CREATE TABLE " + t3 + " ( k VARCHAR PRIMARY KEY, a BIGINT[])");

    PreparedStatement stmt =
      conn.prepareStatement("UPSERT INTO " + t3 + " VALUES('a',ARRAY[2,null,32335,4])");
    stmt.execute();
    conn.commit();

    ResultSet rs = conn.createStatement().executeQuery("Select a from " + t3 + " where k = 'a'");
    rs.next();
    Array array =
      conn.createArrayOf("BIGINT", new Object[] { (long) 2, null, (long) 32335, (long) 4 });

    assertEquals(rs.getArray(1), array);
    conn.close();

  }

  @Test
  public void testArrayUpsertFloatWithNulls() throws Exception {
    Connection conn = DriverManager.getConnection(getUrl());
    String t4 = generateUniqueName();
    conn.createStatement().execute("CREATE TABLE " + t4 + " ( k VARCHAR PRIMARY KEY, a FLOAT[])");

    PreparedStatement stmt =
      conn.prepareStatement("UPSERT INTO " + t4 + " VALUES('a',ARRAY[1.1,2.2,null,3.4])");
    stmt.execute();
    conn.commit();

    ResultSet rs = conn.createStatement().executeQuery("Select a from " + t4 + " where k = 'a'");
    rs.next();
    Array array =
      conn.createArrayOf("FLOAT", new Object[] { (float) 1.1, (float) 2.2, null, (float) 3.4 });

    assertEquals(rs.getArray(1), array);
    conn.close();

  }

  @Test
  public void testArrayUpsertSmallIntWithNulls() throws Exception {
    Connection conn = DriverManager.getConnection(getUrl());
    String t5 = generateUniqueName();
    conn.createStatement()
      .execute("CREATE TABLE " + t5 + " ( k VARCHAR PRIMARY KEY, a SMALLINT[])");

    PreparedStatement stmt =
      conn.prepareStatement("UPSERT INTO " + t5 + " VALUES('a',ARRAY[123,456,null,456])");
    stmt.execute();
    conn.commit();

    ResultSet rs = conn.createStatement().executeQuery("Select a from " + t5 + " where k = 'a'");
    rs.next();
    Array array =
      conn.createArrayOf("SMALLINT", new Object[] { (short) 123, (short) 456, null, (short) 456 });

    assertEquals(rs.getArray(1), array);
    conn.close();

  }

  @Test
  public void testArrayUpsertTinyIntWithNulls() throws Exception {
    Connection conn = DriverManager.getConnection(getUrl());
    String t6 = generateUniqueName();
    conn.createStatement().execute("CREATE TABLE " + t6 + " ( k VARCHAR PRIMARY KEY, a TINYINT[])");

    PreparedStatement stmt =
      conn.prepareStatement("UPSERT INTO " + t6 + " VALUES('a',ARRAY[123,45,null,45])");
    stmt.execute();
    conn.commit();

    ResultSet rs = conn.createStatement().executeQuery("Select a from " + t6 + " where k = 'a'");
    rs.next();
    Array array =
      conn.createArrayOf("TINYINT", new Object[] { (byte) 123, (byte) 45, null, (byte) 45 });

    assertEquals(rs.getArray(1), array);
    conn.close();

  }

  @Test
  public void testArrayUpsertBooleanWithNulls() throws Exception {
    Connection conn = DriverManager.getConnection(getUrl());
    String t7 = generateUniqueName();
    conn.createStatement().execute("CREATE TABLE " + t7 + " ( k VARCHAR PRIMARY KEY, a BOOLEAN[])");

    PreparedStatement stmt =
      conn.prepareStatement("UPSERT INTO " + t7 + " VALUES('a',ARRAY[true,false,null,true])");
    stmt.execute();
    conn.commit();

    ResultSet rs = conn.createStatement().executeQuery("Select a from " + t7 + " where k = 'a'");
    rs.next();
    Array array = conn.createArrayOf("BOOLEAN", new Object[] { true, false, null, true });

    assertEquals(rs.getArray(1), array);
    conn.close();

  }

  @Test
  public void testArrayUpsertDoubleWithNulls() throws Exception {
    Connection conn = DriverManager.getConnection(getUrl());
    String t8 = generateUniqueName();
    conn.createStatement().execute("CREATE TABLE " + t8 + " ( k VARCHAR PRIMARY KEY, a DOUBLE[])");

    PreparedStatement stmt =
      conn.prepareStatement("UPSERT INTO " + t8 + " VALUES('a',ARRAY[1.2,2.3,null,3.4])");
    stmt.execute();
    conn.commit();

    ResultSet rs = conn.createStatement().executeQuery("Select a from " + t8 + " where k = 'a'");
    rs.next();
    Array array = conn.createArrayOf("DOUBLE", new Object[] { 1.2, 2.3, null, 3.4 });

    assertEquals(rs.getArray(1), array);
    conn.close();

  }

  @Test
  public void testArrayUpsertDateWithNulls1() throws Exception {
    Connection conn = DriverManager.getConnection(getUrl());
    String t9 = generateUniqueName();
    conn.createStatement().execute("CREATE TABLE " + t9 + " ( k VARCHAR PRIMARY KEY, a DATE[])");
    PreparedStatement stmt = conn.prepareStatement("UPSERT INTO " + t9
      + " VALUES('a',ARRAY[TO_DATE('2015-05-20 06:12:14.184'),null,TO_DATE('2015-05-20 06:12:14.184'),null])");
    stmt.execute();
    conn.commit();

    ResultSet rs = conn.createStatement().executeQuery("Select a from " + t9 + " where k = 'a'");
    rs.next();
    Array array = conn.createArrayOf("DATE", new Date[] { new Date(1432102334184l), new Date(0l),
      new Date(1432102334184l), new Date(0l) });

    assertEquals(rs.getArray(1), array);
    conn.close();
  }

  @Test
  public void testArrayUpsertDateWithNulls2() throws Exception {
    Connection conn = DriverManager.getConnection(getUrl());
    String t10 = generateUniqueName();
    conn.createStatement().execute("CREATE TABLE " + t10 + " ( k VARCHAR PRIMARY KEY, a DATE[])");
    PreparedStatement stmt = conn.prepareStatement("UPSERT INTO " + t10
      + " VALUES('a',ARRAY[TO_DATE('1970-01-01 00:00:00.000'), TO_DATE('2015-05-20 06:12:14.184'),TO_DATE('2015-05-20 06:12:14.184')])");
    stmt.execute();
    conn.commit();

    ResultSet rs = conn.createStatement().executeQuery("Select a from " + t10 + " where k = 'a'");
    rs.next();
    Array array = conn.createArrayOf("DATE",
      new Date[] { new Date(0l), new Date(1432102334184l), new Date(1432102334184l) });

    assertEquals(rs.getArray(1), array);
    conn.close();
  }

  @Test
  public void testArrayUpsertTimeWithNulls1() throws Exception {
    Connection conn = DriverManager.getConnection(getUrl());
    String t11 = generateUniqueName();
    conn.createStatement().execute("CREATE TABLE " + t11 + " ( k VARCHAR PRIMARY KEY, a TIME[])");
    PreparedStatement stmt = conn.prepareStatement("UPSERT INTO " + t11
      + " VALUES('a',ARRAY[TO_TIME('2015-05-20 06:12:14.184'),null,TO_TIME('2015-05-20 06:12:14.184'),null])");
    stmt.execute();
    conn.commit();

    ResultSet rs = conn.createStatement().executeQuery("Select a from " + t11 + " where k = 'a'");
    rs.next();
    Array array = conn.createArrayOf("TIME", new Time[] { new Time(1432102334184l), new Time(0l),
      new Time(1432102334184l), new Time(0l) });

    assertEquals(rs.getArray(1), array);
    conn.close();
  }

  @Test
  public void testArrayUpsertTimeWithNulls2() throws Exception {
    Connection conn = DriverManager.getConnection(getUrl());
    String t12 = generateUniqueName();
    conn.createStatement().execute("CREATE TABLE " + t12 + " ( k VARCHAR PRIMARY KEY, a TIME[])");
    PreparedStatement stmt = conn.prepareStatement("UPSERT INTO " + t12
      + " VALUES('a',ARRAY[TO_TIME('1970-01-01 00:00:00.000'), TO_TIME('2015-05-20 06:12:14.184'),null,TO_TIME('2015-05-20 06:12:14.184'),null])");
    stmt.execute();
    conn.commit();

    ResultSet rs = conn.createStatement().executeQuery("Select a from " + t12 + " where k = 'a'");
    rs.next();
    Array array = conn.createArrayOf("TIME", new Time[] { new Time(0l), new Time(1432102334184l),
      new Time(0l), new Time(1432102334184l), new Time(0l) });

    assertEquals(rs.getArray(1), array);
    conn.close();
  }

  @Test
  public void testArrayUpsertTimeStampWithNulls1() throws Exception {
    Connection conn = DriverManager.getConnection(getUrl());
    String t13 = generateUniqueName();
    conn.createStatement()
      .execute("CREATE TABLE " + t13 + " ( k VARCHAR PRIMARY KEY, a TIMESTAMP[])");
    PreparedStatement stmt = conn.prepareStatement("UPSERT INTO " + t13
      + " VALUES('a',ARRAY[TO_TIMESTAMP('2015-05-20 06:12:14.184'),null,TO_TIMESTAMP('2015-05-20 06:12:14.184'),TO_TIMESTAMP('1970-01-01 00:00:00.000')])");
    stmt.execute();
    conn.commit();

    ResultSet rs = conn.createStatement().executeQuery("Select a from " + t13 + " where k = 'a'");
    rs.next();

    assertEquals(rs.getArray(1),
      conn.createArrayOf("TIMESTAMP", new Timestamp[] { new Timestamp(1432102334184l),
        new Timestamp(0l), new Timestamp(1432102334184l), new Timestamp(0l) }));
    conn.close();
  }

  @Test
  public void testArrayUpsertTimeStampWithNulls2() throws Exception {
    Connection conn = DriverManager.getConnection(getUrl());
    String t14 = generateUniqueName();
    conn.createStatement()
      .execute("CREATE TABLE " + t14 + " ( k VARCHAR PRIMARY KEY, a TIMESTAMP[])");
    PreparedStatement stmt = conn.prepareStatement("UPSERT INTO " + t14
      + " VALUES('a',ARRAY[TO_TIMESTAMP('1970-01-01 00:00:00.000'),TO_TIMESTAMP('2015-05-20 06:12:14.184'),TO_TIMESTAMP('1970-01-01 00:00:00.000'),TO_TIMESTAMP('2015-05-20 06:12:14.184'),TO_TIMESTAMP('1970-01-01 00:00:00.000')])");
    stmt.execute();
    conn.commit();

    ResultSet rs = conn.createStatement().executeQuery("Select a from " + t14 + " where k = 'a'");
    rs.next();

    assertEquals(rs.getArray(1),
      conn.createArrayOf("TIMESTAMP",
        new Timestamp[] { new Timestamp(0l), new Timestamp(1432102334184l), new Timestamp(0l),
          new Timestamp(1432102334184l), new Timestamp(0l) }));
    conn.close();
  }

  @Test
  public void testArrayUpsertCharWithNulls1() throws Exception {
    Connection conn = DriverManager.getConnection(getUrl());
    String t15 = generateUniqueName();
    conn.createStatement()
      .execute("CREATE TABLE " + t15 + " ( k VARCHAR PRIMARY KEY, a CHAR(15)[])");
    PreparedStatement stmt =
      conn.prepareStatement("UPSERT INTO " + t15 + " VALUES('a',ARRAY['foo',null,'fo','foo'])");
    stmt.execute();
    conn.commit();

    ResultSet rs = conn.createStatement().executeQuery("Select a from " + t15 + " where k = 'a'");
    rs.next();

    assertEquals(rs.getArray(1),
      conn.createArrayOf("CHAR", new String[] { "foo", "", "fo", "foo" }));
    conn.close();
  }

  @Test
  public void testArrayUpsertCharWithNulls2() throws Exception {
    Connection conn = DriverManager.getConnection(getUrl());
    String t16 = generateUniqueName();
    conn.createStatement()
      .execute("CREATE TABLE " + t16 + " ( k VARCHAR PRIMARY KEY, a CHAR(15)[])");
    PreparedStatement stmt = conn
      .prepareStatement("UPSERT INTO " + t16 + " VALUES('a',ARRAY[null,'foo',null,'fo','foo'])");
    stmt.execute();
    conn.commit();

    ResultSet rs = conn.createStatement().executeQuery("Select a from " + t16 + " where k = 'a'");
    rs.next();

    assertEquals(rs.getArray(1),
      conn.createArrayOf("CHAR", new String[] { "", "foo", "", "fo", "foo" }));
    conn.close();
  }
}
