/**
 * Copyright (C) 2011 Akiban Technologies Inc.
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 */

package com.akiban.server.test.it.qp;

import com.akiban.qp.exec.UpdatePlannable;
import com.akiban.qp.exec.UpdateResult;
import com.akiban.qp.operator.Bindings;
import com.akiban.qp.operator.Cursor;
import com.akiban.qp.operator.Operator;
import com.akiban.qp.operator.UpdateFunction;
import com.akiban.qp.row.OverlayingRow;
import com.akiban.qp.row.Row;
import com.akiban.qp.row.RowBase;
import com.akiban.server.types.AkType;
import com.akiban.server.types.ToObjectValueTarget;
import com.akiban.server.types.conversion.Converters;
import static com.akiban.qp.operator.API.*;

import org.junit.Test;
import static org.junit.Assert.assertEquals;

public class UpdateIT extends OperatorITBase
{
    @Test
    public void basicUpdate() throws Exception {
        use(db);

        UpdateFunction updateFunction = new UpdateFunction() {
            @Override
            public boolean rowIsSelected(Row row) {
                return row.rowType().equals(customerRowType);
            }

            @Override
            public Row evaluate(Row original, Bindings bindings) {
                ToObjectValueTarget target = new ToObjectValueTarget();
                target.expectType(AkType.VARCHAR);
                Object obj = Converters.convert(original.eval(1), target).lastConvertedValue();
                String name = (String) obj; // TODO eventually use Expression for this
                name = name.toUpperCase();
                name = name + name;
                return new OverlayingRow(original).overlay(1, name);
            }
        };

        Operator groupScan = groupScan_Default(coi);
        UpdatePlannable updateOperator = update_Default(groupScan, updateFunction);
        UpdateResult result = updateOperator.run(NO_BINDINGS, adapter);
        assertEquals("rows modified", 2, result.rowsModified());
        assertEquals("rows touched", db.length, result.rowsTouched());

        Cursor executable = cursor(groupScan, adapter);
        RowBase[] expected = new RowBase[]{row(customerRowType, 1L, "XYZXYZ"),
                                           row(orderRowType, 11L, 1L, "ori"),
                                           row(itemRowType, 111L, 11L),
                                           row(itemRowType, 112L, 11L),
                                           row(orderRowType, 12L, 1L, "david"),
                                           row(itemRowType, 121L, 12L),
                                           row(itemRowType, 122L, 12L),
                                           row(customerRowType, 2L, "ABCABC"),
                                           row(orderRowType, 21L, 2L, "tom"),
                                           row(itemRowType, 211L, 21L),
                                           row(itemRowType, 212L, 21L),
                                           row(orderRowType, 22L, 2L, "jack"),
                                           row(itemRowType, 221L, 22L),
                                           row(itemRowType, 222L, 22L)
        };
        compareRows(expected, executable);
    }
    
}

@@ -1040,16 +1040,137 @@
 owBase;%0A
+import com.akiban.qp.rowtype.RowType;%0Aimport com.akiban.qp.rowtype.Schema;%0Aimport com.akiban.server.api.dml.scan.NewRow;%0A
 import c
@@ -3842,10 +3842,1534 @@
  %7D%0A    %0A
+    @Test%0A    public void halloween() throws Exception %7B%0A        // A table without any primary key will have a generated one,%0A        // which changes on update.%0A        final int tableId = createTable(%22schema%22, %22nokey%22, %22i int, j int%22);%0A        schema = new Schema(rowDefCache().ais());%0A        adapter = persistitAdapter(schema);%0A        final RowType tableRowType = schema.userTableRowType(userTable(tableId));%0A%0A        NewRow%5B%5D db = new NewRow%5B%5D %7B createNewRow(tableId, 1L, 0L) %7D;%0A        use(db);%0A%0A        UpdateFunction updateFunction = new UpdateFunction() %7B%0A                @Override%0A                public boolean rowIsSelected(Row row) %7B%0A                    return row.rowType().equals(tableRowType);%0A                %7D%0A%0A                @Override%0A                public Row evaluate(Row original, Bindings bindings) %7B%0A                    long j = original.eval(1).getInt();%0A                    return new OverlayingRow(original).overlay(1, j+1);%0A                %7D%0A            %7D;%0A%0A        Operator groupScan = groupScan_Default(groupTable(tableId));%0A        UpdatePlannable updateOperator = update_Default(groupScan, updateFunction);%0A        UpdateResult result = updateOperator.run(NO_BINDINGS, adapter);%0A        assertEquals(%22rows touched%22, 1, result.rowsTouched());%0A        assertEquals(%22rows modified%22, 1, result.rowsModified());%0A%0A        Cursor executable = cursor(groupScan, adapter);%0A        RowBase%5B%5D expected = new RowBase%5B%5D %7B row(tableRowType, 1L, 1L) %7D;%0A        compareRows(expected, executable);%0A    %7D%0A%0A
 %7D%0A

Add Halloween test.