IMPALA-4466: Improve Kudu CRUD test coverage

The results in the test files were verified by hand.

This patch also introduces a new test section 'DML_RESULTS', which
takes the name of a table as a comment and the contents of the
table as its body and then verifies that the body matches the
actual contents of the table. This makes it easy to check that a
DML operation has the desired effect on the contents of a table,
rather than always having to add another test case that runs a
select on the table. For now, this section cannot be used in a
test along with the RESULTS or ERRORS sections.

TODO: Refactor the DML test case handling (IMPALA-4471)

Change-Id: Ib9e7afbef60186edb00a9d11fbe5a8c64931add6
Reviewed-on: http://gerrit.cloudera.org:8080/4953
Reviewed-by: Matthew Jacobs <[email protected]>
Tested-by: Internal Jenkins


Project: http://git-wip-us.apache.org/repos/asf/incubator-impala/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-impala/commit/3833707d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-impala/tree/3833707d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-impala/diff/3833707d

Branch: refs/heads/master
Commit: 3833707dbd78dd39f6cf25060607a7b8ae9bff10
Parents: ab0d21a
Author: Thomas Tauber-Marshall <[email protected]>
Authored: Fri Nov 4 12:52:07 2016 -0700
Committer: Internal Jenkins <[email protected]>
Committed: Thu Nov 17 02:54:30 2016 +0000

----------------------------------------------------------------------
 .../queries/QueryTest/kudu_create.test          |  39 ++
 .../queries/QueryTest/kudu_crud.test            | 479 ------------------
 .../queries/QueryTest/kudu_delete.test          | 369 ++++++++++++++
 .../queries/QueryTest/kudu_insert.test          | 333 +++++++++++++
 .../queries/QueryTest/kudu_update.test          | 340 +++++++++++++
 .../queries/QueryTest/kudu_upsert.test          | 491 +++++++++++++++++++
 tests/common/impala_test_suite.py               |  16 +
 tests/common/test_result_verifier.py            |  16 +-
 tests/query_test/test_kudu.py                   |  13 +-
 tests/util/test_file_parser.py                  |  15 +-
 10 files changed, 1624 insertions(+), 487 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3833707d/testdata/workloads/functional-query/queries/QueryTest/kudu_create.test
----------------------------------------------------------------------
diff --git 
a/testdata/workloads/functional-query/queries/QueryTest/kudu_create.test 
b/testdata/workloads/functional-query/queries/QueryTest/kudu_create.test
index 3d9916d..d04efd6 100644
--- a/testdata/workloads/functional-query/queries/QueryTest/kudu_create.test
+++ b/testdata/workloads/functional-query/queries/QueryTest/kudu_create.test
@@ -84,3 +84,42 @@ create table tab (a int primary key) distribute by range (a) 
(partition value =
 stored as kudu
 ---- RESULTS
 ====
+---- QUERY
+# Invalid hostname
+create table tdata_bogus_host (id int primary key, name string, valf float, 
vali bigint)
+  DISTRIBUTE BY RANGE (PARTITION 10 <= VALUES <= 30) STORED AS KUDU
+  TBLPROPERTIES('kudu.master_addresses' = 'bogus host name')
+---- CATCH
+Couldn't resolve this master's address bogus host name:7051
+====
+---- QUERY
+# Non-existing host
+create table tdata_non_existing_host
+(id int primary key, name string, valf float, vali bigint)
+  DISTRIBUTE BY RANGE (PARTITION 10 <= VALUES <= 30) STORED AS KUDU
+  TBLPROPERTIES('kudu.master_addresses' = 'bogus.host.name')
+---- CATCH
+Couldn't resolve this master's address bogus.host.name:7051
+====
+---- QUERY
+# Test that string case is ignored
+create table ignore_column_case (Id int, NAME string, vAlf float, vali bigint,
+  primary key (Id, NAME)) DISTRIBUTE BY RANGE (PARTITION VALUE = (1, 'Martin'))
+  STORED AS KUDU
+---- RESULTS
+====
+---- QUERY
+insert into ignore_column_case values (1, 'Martin', 1.0, 10);
+---- RESULTS
+: 1
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+====
+---- QUERY
+select ID, nAmE, VALF, VALI from ignore_column_case where NaMe = 'Martin';
+---- RESULTS
+1,'Martin',1.0,10
+---- TYPES
+INT,STRING,FLOAT,BIGINT
+====

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3833707d/testdata/workloads/functional-query/queries/QueryTest/kudu_crud.test
----------------------------------------------------------------------
diff --git 
a/testdata/workloads/functional-query/queries/QueryTest/kudu_crud.test 
b/testdata/workloads/functional-query/queries/QueryTest/kudu_crud.test
deleted file mode 100644
index 1ecfdf5..0000000
--- a/testdata/workloads/functional-query/queries/QueryTest/kudu_crud.test
+++ /dev/null
@@ -1,479 +0,0 @@
-====
----- QUERY
--- Invalid hostname
-create table tdata_bogus_host (id int primary key, name string, valf float, 
vali bigint)
-  DISTRIBUTE BY RANGE (PARTITION 10 <= VALUES <= 30) STORED AS KUDU
-  TBLPROPERTIES('kudu.master_addresses' = 'bogus host name')
----- CATCH
-Couldn't resolve this master's address bogus host name:7051
-====
----- QUERY
--- Non-existing host
-create table tdata_non_existing_host
-(id int primary key, name string, valf float, vali bigint)
-  DISTRIBUTE BY RANGE (PARTITION 10 <= VALUES <= 30) STORED AS KUDU
-  TBLPROPERTIES('kudu.master_addresses' = 'bogus.host.name')
----- CATCH
-Couldn't resolve this master's address bogus.host.name:7051
-====
----- QUERY
-create table tdata
-  (id int primary key, name string, valf float, vali bigint, valv string, valb 
boolean)
-  DISTRIBUTE BY RANGE (PARTITION VALUES < 10, PARTITION 10 <= VALUES < 30,
-  PARTITION 30 <= VALUES) STORED AS KUDU
----- RESULTS
-====
----- QUERY
-insert into tdata values
-(1, "martin", 1.0, 232232323, cast('a' as string), true),
-(2, "david", cast(1.0 as float), 99398493939, cast('b' as string), false),
-(3, "todd", cast(1.0 as float), 993393939, "c", true)
----- RESULTS
-: 3
----- RUNTIME_PROFILE
-NumModifiedRows: 3
-NumRowErrors: 0
-====
----- QUERY
-update tdata set vali=43 where id = 1
----- RESULTS
-# TODO: Verify row count after fixing IMPALA-3713 (Here and UPDATE/DELETE 
below)
----- RUNTIME_PROFILE
-NumModifiedRows: 1
-NumRowErrors: 0
-====
----- QUERY
-select * from tdata
----- RESULTS
-1,'martin',1.0,43,'a',true
-2,'david',1.0,99398493939,'b',false
-3,'todd',1.0,993393939,'c',true
----- TYPES
-INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN
-====
-====
----- QUERY
-# Try updating a string col where casting a value that is bigger than the 
varchar in the
-# cast. The value gets truncated and stored to the string col.
-update tdata set valv=cast('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' as varchar(20)) 
where id = 1
----- RESULTS
----- RUNTIME_PROFILE
-NumModifiedRows: 1
-NumRowErrors: 0
-====
----- QUERY
-select * from tdata
----- RESULTS
-1,'martin',1.0,43,'aaaaaaaaaaaaaaaaaaaa',true
-2,'david',1.0,99398493939,'b',false
-3,'todd',1.0,993393939,'c',true
----- TYPES
-INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN
-====
----- QUERY
-update tdata set valb=false where id = 1
----- RESULTS
----- RUNTIME_PROFILE
-NumModifiedRows: 1
-NumRowErrors: 0
-====
----- QUERY
-select * from tdata
----- RESULTS
-1,'martin',1.0,43,'aaaaaaaaaaaaaaaaaaaa',false
-2,'david',1.0,99398493939,'b',false
-3,'todd',1.0,993393939,'c',true
----- TYPES
-INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN
-====
----- QUERY
-update tdata set vali=43 where id > 1
----- RESULTS
----- RUNTIME_PROFILE
-NumModifiedRows: 2
-NumRowErrors: 0
-====
----- QUERY
-select * from tdata
----- RESULTS
-1,'martin',1.0,43,'aaaaaaaaaaaaaaaaaaaa',false
-2,'david',1.0,43,'b',false
-3,'todd',1.0,43,'c',true
----- TYPES
-INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN
-====
----- QUERY
-update tdata set name='unknown' where name = 'martin'
----- RESULTS
----- RUNTIME_PROFILE
-NumModifiedRows: 1
-NumRowErrors: 0
-====
----- QUERY
-select * from tdata
----- RESULTS
-1,'unknown',1.0,43,'aaaaaaaaaaaaaaaaaaaa',false
-2,'david',1.0,43,'b',false
-3,'todd',1.0,43,'c',true
----- TYPES
-INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN
-====
----- QUERY
-insert into tdata values
-(40, "he", cast(0.0 as float), 43, cast('e' as string), false),
-(120, "she", cast(0.0 as float), 99, cast('f' as string), true)
----- RESULTS
-: 2
----- RUNTIME_PROFILE
-NumModifiedRows: 2
-NumRowErrors: 0
-====
----- QUERY
-select * from tdata
----- RESULTS
-1,'unknown',1.0,43,'aaaaaaaaaaaaaaaaaaaa',false
-2,'david',1.0,43,'b',false
-3,'todd',1.0,43,'c',true
-40,'he',0.0,43,'e',false
-120,'she',0.0,99,'f',true
----- TYPES
-INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN
-====
----- QUERY
-update tdata set name=null where id = 40
----- RESULTS
----- RUNTIME_PROFILE
-NumModifiedRows: 1
-NumRowErrors: 0
-====
----- QUERY
-select * from tdata
----- RESULTS
-1,'unknown',1.0,43,'aaaaaaaaaaaaaaaaaaaa',false
-2,'david',1.0,43,'b',false
-3,'todd',1.0,43,'c',true
-40,'NULL',0.0,43,'e',false
-120,'she',0.0,99,'f',true
----- TYPES
-INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN
-====
----- QUERY
-update tdata set name='he' where id = 40
----- RUNTIME_PROFILE
-NumModifiedRows: 1
-NumRowErrors: 0
----- RESULTS
-====
----- QUERY
-select * from tdata
----- RESULTS
-1,'unknown',1.0,43,'aaaaaaaaaaaaaaaaaaaa',false
-2,'david',1.0,43,'b',false
-3,'todd',1.0,43,'c',true
-40,'he',0.0,43,'e',false
-120,'she',0.0,99,'f',true
----- TYPES
-INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN
-====
----- QUERY
-# Make sure we can insert empty strings into string columns and that we can 
scan them
-# back.
-insert into tdata values (320, '', 2.0, 932, cast('' as string), false)
----- RESULTS
-: 1
----- RUNTIME_PROFILE
-NumModifiedRows: 1
-NumRowErrors: 0
-====
----- QUERY
-select id, name, valv, valb from tdata where id = 320;
----- RESULTS
-320,'','',false
----- TYPES
-INT,STRING,STRING,BOOLEAN
-====
----- QUERY
--- Test that string case is ignored
-create table ignore_column_case (Id int, NAME string, vAlf float, vali bigint,
-  primary key (Id, NAME)) DISTRIBUTE BY RANGE (PARTITION VALUE = (1, 'Martin'))
-  STORED AS KUDU
----- RESULTS
-====
----- QUERY
-insert into ignore_column_case values (1, 'Martin', 1.0, 10);
----- RESULTS
-: 1
----- RUNTIME_PROFILE
-NumModifiedRows: 1
-NumRowErrors: 0
-====
----- QUERY
-select ID, nAmE, VALF, VALI from ignore_column_case where NaMe = 'Martin';
----- RESULTS
-1,'Martin',1.0,10
----- TYPES
-INT,STRING,FLOAT,BIGINT
-====
----- QUERY
-insert into tdata values
-(666, "The Devil", cast(1.2 as float), 43, cast('z' as string), true)
----- RESULTS
-: 1
----- RUNTIME_PROFILE
-NumModifiedRows: 1
-NumRowErrors: 0
-====
----- QUERY
-insert into tdata values
-(666, "The Devil", cast(1.2 as float), 43, cast('z' as VARCHAR(20)), true)
----- RESULTS
-: 0
----- RUNTIME_PROFILE
-NumModifiedRows: 0
-NumRowErrors: 1
-====
----- QUERY
--- Updating the same record many times: cross join produces 7 identical updates
-update a set a.name='Satan' from tdata a, tdata b where a.id = 666
----- RESULTS
----- RUNTIME_PROFILE
-NumModifiedRows: 7
-NumRowErrors: 0
-====
----- QUERY
-delete a from tdata a, tdata b where a.id = 666
----- RESULTS
----- RUNTIME_PROFILE
-NumModifiedRows: 1
-NumRowErrors: 6
-====
----- QUERY
-select * from tdata
----- RESULTS
-40,'he',0,43,'e',false
-120,'she',0,99,'f',true
-320,'',2,932,'',false
-1,'unknown',1,43,'aaaaaaaaaaaaaaaaaaaa',false
-2,'david',1,43,'b',false
-3,'todd',1,43,'c',true
----- TYPES
-INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN
-====
----- QUERY
-upsert into table tdata values (40, 'they', 1, 43, cast('e' as VARCHAR(20)), 
false),
-(1, NULL, 1, 0, cast('a' as VARCHAR(20)), true)
----- RESULTS
----- RUNTIME_PROFILE
-NumModifiedRows: 2
-NumRowErrors: 0
-====
----- QUERY
-select * from tdata
----- RESULTS
-40,'they',1,43,'e',false
-120,'she',0,99,'f',true
-320,'',2,932,'',false
-1,'NULL',1,0,'a',true
-2,'david',1,43,'b',false
-3,'todd',1,43,'c',true
----- TYPES
-INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN
-====
----- QUERY
-upsert into table tdata (id, valf) values (2, NULL), (120, 20), (0, 0)
----- RESULTS
-====
----- QUERY
-select * from tdata
----- RESULTS
-40,'they',1,43,'e',false
-120,'she',20,99,'f',true
-320,'',2,932,'',false
-1,'NULL',1,0,'a',true
-2,'david',NULL,43,'b',false
-3,'todd',1,43,'c',true
-0,'NULL',0,NULL,'NULL',NULL
----- TYPES
-INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN
-====
----- QUERY
-upsert into table tdata (valb, name, id)
-select false as valb, 'he' as name, id from tdata where id < 2
----- RESULTS
-====
----- QUERY
-select * from tdata
----- RESULTS
-40,'they',1,43,'e',false
-120,'she',20,99,'f',true
-320,'',2,932,'',false
-1,'he',1,0,'a',false
-2,'david',NULL,43,'b',false
-3,'todd',1,43,'c',true
-0,'he',0,NULL,'NULL',false
----- TYPES
-INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN
-====
----- QUERY
-upsert into table tdata (id, name) values (null, '')
----- RUNTIME_PROFILE
-NumModifiedRows: 0
-NumRowErrors: 1
-====
----- QUERY
-# IMPALA-3454: A delete that requires a rewrite may not get the Kudu column 
order correct
-# if the Kudu columns are of different types.
-create table impala_3454 (key_1 tinyint, key_2 bigint, PRIMARY KEY (key_1, 
key_2))
-  DISTRIBUTE BY HASH INTO 3 BUCKETS STORED AS KUDU
----- RESULTS
-====
----- QUERY
-insert into impala_3454 values
-(1, 1),
-(2, 2),
-(3, 3)
----- RESULTS
-: 3
-====
----- QUERY
-delete from impala_3454 where key_1 < (select max(key_2) from impala_3454)
----- RESULTS
----- RUNTIME_PROFILE
-NumModifiedRows: 2
-NumRowErrors: 0
-====
----- QUERY
-select * from impala_3454
----- RESULTS
-3,3
----- TYPES
-TINYINT,BIGINT
-====
----- QUERY
-CREATE TABLE kudu_test_tbl PRIMARY KEY(id)
-DISTRIBUTE BY RANGE(id) (PARTITION VALUES < 100, PARTITION 100 <= VALUES <= 
10000)
-STORED AS KUDU AS
-SELECT * FROM functional_kudu.alltypes WHERE id < 100;
----- RESULTS
-'Inserted 100 row(s)'
----- RUNTIME_PROFILE
-NumModifiedRows: 100
-NumRowErrors: 0
-====
----- QUERY
-INSERT INTO kudu_test_tbl
-SELECT * FROM functional_kudu.alltypes WHERE id < 100;
----- RESULTS
-: 0
----- RUNTIME_PROFILE
-NumModifiedRows: 0
-NumRowErrors: 100
-====
----- QUERY
-INSERT INTO kudu_test_tbl
-SELECT * FROM functional_kudu.alltypes;
----- RESULTS
-: 7200
----- RUNTIME_PROFILE
-NumModifiedRows: 7200
-NumRowErrors: 100
-====
----- QUERY
-# Test a larger UPDATE
-UPDATE kudu_test_tbl SET int_col = -1;
----- RESULTS
----- RUNTIME_PROFILE
-NumModifiedRows: 7300
-NumRowErrors: 0
-====
----- QUERY
-# Test a larger DELETE
-DELETE FROM kudu_test_tbl WHERE id > -1;
----- RESULTS
----- RUNTIME_PROFILE
-NumModifiedRows: 7300
-NumRowErrors: 0
-====
----- QUERY
-# Insert rows that are not covered by any of the existing range partitions
-# Only the row at 10000 is inserted.
-INSERT INTO kudu_test_tbl SELECT cast(id + 10000 as int), bool_col, 
tinyint_col,
-  smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, 
string_col,
-  timestamp_col, year, month
-FROM functional_kudu.alltypes
----- RUNTIME_PROFILE
-NumModifiedRows: 1
-NumRowErrors: 7299
-====
----- QUERY
-# Try to delete a row with a primary key value that is not covered by the 
existing range
-# partitions. This doesn't actually end up selecting any rows to modify.
-DELETE FROM kudu_test_tbl WHERE id = 10001
----- RESULTS
----- RUNTIME_PROFILE
-NumModifiedRows: 0
-NumRowErrors: 0
-====
----- QUERY
-# Try to update a row with a primary key value that is not covered by the 
existing range
-# partitions. This doesn't actually end up selecting any rows to modify.
-UPDATE kudu_test_tbl SET int_col = 10 WHERE id = 10001
----- RESULTS
----- RUNTIME_PROFILE
-NumModifiedRows: 0
-NumRowErrors: 0
-====
----- QUERY
-# IMPALA-2521: clustered insert into table.
-create table impala_2521
-(id bigint primary key, name string, zip int)
-distribute by hash into 3 buckets stored as kudu
----- RESULTS
-====
----- QUERY
-insert into impala_2521 /*+ clustered */
-select id, name, maxzip as zip
-from (
-select tinyint_col as id, cast(max(int_col) + 1 as int) as maxzip, string_col 
as name
-from functional_kudu.alltypessmall group by id, name
-) as sub;
----- RESULTS
-: 10
----- RUNTIME_PROFILE
-NumModifiedRows: 10
-NumRowErrors: 0
-====
----- QUERY
-select * from impala_2521
----- RESULTS
-0,'0',1
-1,'1',2
-2,'2',3
-3,'3',4
-4,'4',5
-5,'5',6
-6,'6',7
-7,'7',8
-8,'8',9
-9,'9',10
----- TYPES
-BIGINT,STRING,INT
-====
----- QUERY
-# Table with all supported types as primary key and distribution columns
-create table allkeytypes (i1 tinyint, i2 smallint, i3 int, i4 bigint, name 
string,
-  valf float, vald double, primary key (i1, i2, i3, i4, name)) distribute by
-  hash into 3 buckets, range (partition value = (1,1,1,1,'1'),
-  partition value = (2,2,2,2,'2'), partition value = (3,3,3,3,'3')) stored as 
kudu
----- RESULTS
-====
----- QUERY
-insert into allkeytypes select cast(id as tinyint), smallint_col, int_col,
-  cast (bigint_col/10 as bigint), string_col, float_col, double_col
-  from functional.alltypes where id > 0 and id < 10
----- RESULTS
-: 3
----- RUNTIME_PROFILE
-NumModifiedRows: 3
-NumRowErrors: 6
-====

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3833707d/testdata/workloads/functional-query/queries/QueryTest/kudu_delete.test
----------------------------------------------------------------------
diff --git 
a/testdata/workloads/functional-query/queries/QueryTest/kudu_delete.test 
b/testdata/workloads/functional-query/queries/QueryTest/kudu_delete.test
new file mode 100644
index 0000000..ac1bcc4
--- /dev/null
+++ b/testdata/workloads/functional-query/queries/QueryTest/kudu_delete.test
@@ -0,0 +1,369 @@
+====
+---- QUERY
+create table tdata
+  (id int primary key, valf float, vali bigint, valv string, valb boolean, 
valt tinyint,
+      vals smallint, vald double)
+  DISTRIBUTE BY RANGE (PARTITION VALUES < 100, PARTITION 100 <= VALUES < 1000,
+  PARTITION 1000 <= VALUES <= 10000) STORED AS KUDU
+---- RESULTS
+====
+---- QUERY
+insert into table tdata values
+(1, 1.0, 1, 'one', true, 1, 1, 1),
+(2, -2, 20, 'two', false, 0, 1, NULL),
+(3, 0, NULL, 'three', false, 10, 20, 30),
+(4, 5, 6, 'four', true, 7, 8, 9),
+(5, 0, 10, 'five', NULL, 15, 20, 25),
+(6, 9, 12, 'six', true, -1, -2, cast('inf' as double)),
+(7, NULL, 7, 'seven', false, 77, 777, NULL),
+(8, 0, 80, NULL, true, 10, 11, 12),
+(9, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+(127, 1, 2, '127', false, 3, 4, 5)
+---- RESULTS
+: 10
+====
+---- QUERY
+# single row, predicate on key
+delete from tdata where id = 1
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+2,-2,20,'two',false,0,1,NULL
+3,0,NULL,'three',false,10,20,30
+4,5,6,'four',true,7,8,9
+5,0,10,'five',NULL,15,20,25
+6,9,12,'six',true,-1,-2,Infinity
+7,NULL,7,'seven',false,77,777,NULL
+8,0,80,'NULL',true,10,11,12
+9,NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+127,1,2,'127',false,3,4,5
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# predicate on key, NULL
+delete from tdata where id is NULL
+---- RUNTIME_PROFILE
+NumModifiedRows: 0
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+2,-2,20,'two',false,0,1,NULL
+3,0,NULL,'three',false,10,20,30
+4,5,6,'four',true,7,8,9
+5,0,10,'five',NULL,15,20,25
+6,9,12,'six',true,-1,-2,Infinity
+7,NULL,7,'seven',false,77,777,NULL
+8,0,80,'NULL',true,10,11,12
+9,NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+127,1,2,'127',false,3,4,5
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# predicate on key, nothing is deleted
+delete from tdata where id = 10
+---- RUNTIME_PROFILE
+NumModifiedRows: 0
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+2,-2,20,'two',false,0,1,NULL
+3,0,NULL,'three',false,10,20,30
+4,5,6,'four',true,7,8,9
+5,0,10,'five',NULL,15,20,25
+6,9,12,'six',true,-1,-2,Infinity
+7,NULL,7,'seven',false,77,777,NULL
+8,0,80,'NULL',true,10,11,12
+9,NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+127,1,2,'127',false,3,4,5
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# predicate on key, boundary value
+delete from tdata where id = max_tinyint()
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+2,-2,20,'two',false,0,1,NULL
+3,0,NULL,'three',false,10,20,30
+4,5,6,'four',true,7,8,9
+5,0,10,'five',NULL,15,20,25
+6,9,12,'six',true,-1,-2,Infinity
+7,NULL,7,'seven',false,77,777,NULL
+8,0,80,'NULL',true,10,11,12
+9,NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# compound predicate on key
+delete from tdata where id > 6 and id < 8
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+2,-2,20,'two',false,0,1,NULL
+3,0,NULL,'three',false,10,20,30
+4,5,6,'four',true,7,8,9
+5,0,10,'five',NULL,15,20,25
+6,9,12,'six',true,-1,-2,Infinity
+8,0,80,'NULL',true,10,11,12
+9,NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# predicate on key, multiple rows
+delete from tdata where id % 4 = 0
+---- RUNTIME_PROFILE
+NumModifiedRows: 2
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+2,-2,20,'two',false,0,1,NULL
+3,0,NULL,'three',false,10,20,30
+5,0,10,'five',NULL,15,20,25
+6,9,12,'six',true,-1,-2,Infinity
+9,NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# insert new values, including some that were previously deleted
+insert into table tdata values
+(10, 20, 30, 'ten', true, 40, 50, 60),
+(1, 1.0, 1, 'one', true, 1, 1, 1),
+(11, -11, 11, 'eleven', false, 1, 11, 111),
+(8, 0, 80, NULL, true, 10, 11, 12)
+====
+---- QUERY
+# single row, predicate on non-key
+delete from tdata where valv = 'five'
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+2,-2,20,'two',false,0,1,NULL
+3,0,NULL,'three',false,10,20,30
+6,9,12,'six',true,-1,-2,Infinity
+9,NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+10,20,30,'ten',true,40,50,60
+1,1.0,1,'one',true,1,1,1
+11,-11,11,'eleven',false,1,11,111
+8,0,80,'NULL',true,10,11,12
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# predicate on non-key, NULL
+delete from tdata where valb is NULL
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+2,-2,20,'two',false,0,1,NULL
+3,0,NULL,'three',false,10,20,30
+6,9,12,'six',true,-1,-2,Infinity
+10,20,30,'ten',true,40,50,60
+1,1.0,1,'one',true,1,1,1
+11,-11,11,'eleven',false,1,11,111
+8,0,80,'NULL',true,10,11,12
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# predicate on non-key, nothing is deleted
+delete from tdata where vals = -100
+---- RUNTIME_PROFILE
+NumModifiedRows: 0
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+2,-2,20,'two',false,0,1,NULL
+3,0,NULL,'three',false,10,20,30
+6,9,12,'six',true,-1,-2,Infinity
+10,20,30,'ten',true,40,50,60
+1,1.0,1,'one',true,1,1,1
+11,-11,11,'eleven',false,1,11,111
+8,0,80,'NULL',true,10,11,12
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# predicate on non-key, compound predicate
+delete from tdata where valf = 0 and vali = 80
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+2,-2,20,'two',false,0,1,NULL
+3,0,NULL,'three',false,10,20,30
+6,9,12,'six',true,-1,-2,Infinity
+10,20,30,'ten',true,40,50,60
+1,1.0,1,'one',true,1,1,1
+11,-11,11,'eleven',false,1,11,111
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# predicate on non-key, multiple rows
+delete from tdata where vals % 10 = 0
+---- RUNTIME_PROFILE
+NumModifiedRows: 2
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+2,-2,20,'two',false,0,1,NULL
+6,9,12,'six',true,-1,-2,Infinity
+1,1.0,1,'one',true,1,1,1
+11,-11,11,'eleven',false,1,11,111
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# 'from' syntax - the join results in four deletes, 3 of which fail
+delete a from tdata a, tdata b where a.id = 11
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 3
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+2,-2,20,'two',false,0,1,NULL
+6,9,12,'six',true,-1,-2,Infinity
+1,1.0,1,'one',true,1,1,1
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# Try to delete a row with a primary key value that is not covered by the 
existing range
+# partitions. This doesn't actually end up selecting any rows to modify.
+delete from tdata where id = 10001
+---- RUNTIME_PROFILE
+NumModifiedRows: 0
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+2,-2,20,'two',false,0,1,NULL
+6,9,12,'six',true,-1,-2,Infinity
+1,1.0,1,'one',true,1,1,1
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+insert into tdata
+select cast(id + 100 as int), float_col, bigint_col, string_col, bool_col, 
tinyint_col,
+smallint_col, double_col
+from functional_kudu.alltypes
+---- RESULTS
+: 7300
+---- RUNTIME_PROFILE
+NumModifiedRows: 7300
+NumRowErrors: 0
+====
+---- QUERY
+# Test a larger DELETE
+delete from tdata where id > -1
+---- RUNTIME_PROFILE
+NumModifiedRows: 7303
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+create table multiple_key_cols
+  (string_col string, bigint_col bigint, tinyint_col tinyint, smallint_col 
smallint,
+   bool_col boolean, int_col int, double_col double, float_col float,
+   primary key (string_col, bigint_col, tinyint_col, smallint_col))
+  DISTRIBUTE BY HASH (string_col) INTO 16 BUCKETS STORED AS KUDU
+====
+---- QUERY
+insert into multiple_key_cols values
+('a', 1, 2, 3, true, 4, 5, NULL),
+('b', 1, 2, 3, false, 7, NULL, 9),
+('c', 4, 5, 6, true, 0, -1, 0),
+('d', 10, 20, 30, false, NULL, 40, 50)
+---- RESULTS
+: 4
+====
+---- QUERY
+# multiple key cols, predicate on one of them
+delete from multiple_key_cols where bigint_col = 1
+---- RUNTIME_PROFILE
+NumModifiedRows: 2
+NumRowErrors: 0
+---- LABELS
+STRING_COL, BIGINT_COL, TINYINT_COL, SMALLINT_COL, BOOL_COL, INT_COL, 
DOUBLE_COL, FLOAT_COL
+---- DML_RESULTS: multiple_key_cols
+'c',4,5,6,true,0,-1,0
+'d',10,20,30,false,NULL,40,50
+---- TYPES
+STRING,BIGINT,TINYINT,SMALLINT,BOOLEAN,INT,DOUBLE,FLOAT
+====
+---- QUERY
+# multiple key cols, predicate on non-key col
+delete from multiple_key_cols where bool_col = false
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+STRING_COL, BIGINT_COL, TINYINT_COL, SMALLINT_COL, BOOL_COL, INT_COL, 
DOUBLE_COL, FLOAT_COL
+---- DML_RESULTS: multiple_key_cols
+'c',4,5,6,true,0,-1,0
+---- TYPES
+STRING,BIGINT,TINYINT,SMALLINT,BOOLEAN,INT,DOUBLE,FLOAT
+====
+---- QUERY
+# IMPALA-3454: A delete that requires a rewrite may not get the Kudu column 
order correct
+# if the Kudu columns are of different types.
+create table impala_3454 (key_1 tinyint, key_2 bigint, PRIMARY KEY (key_1, 
key_2))
+  DISTRIBUTE BY HASH INTO 3 BUCKETS STORED AS KUDU
+---- RESULTS
+====
+---- QUERY
+insert into impala_3454 values
+(1, 1),
+(2, 2),
+(3, 3)
+---- RESULTS
+: 3
+====
+---- QUERY
+delete from impala_3454 where key_1 < (select max(key_2) from impala_3454)
+---- RESULTS
+---- RUNTIME_PROFILE
+NumModifiedRows: 2
+NumRowErrors: 0
+====
+---- QUERY
+select * from impala_3454
+---- RESULTS
+3,3
+---- TYPES
+TINYINT,BIGINT
+====

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3833707d/testdata/workloads/functional-query/queries/QueryTest/kudu_insert.test
----------------------------------------------------------------------
diff --git 
a/testdata/workloads/functional-query/queries/QueryTest/kudu_insert.test 
b/testdata/workloads/functional-query/queries/QueryTest/kudu_insert.test
new file mode 100644
index 0000000..44cae4a
--- /dev/null
+++ b/testdata/workloads/functional-query/queries/QueryTest/kudu_insert.test
@@ -0,0 +1,333 @@
+====
+---- QUERY
+create table tdata
+  (id int primary key, valf float, vali bigint, valv string, valb boolean, 
valt tinyint,
+   vals smallint, vald double)
+  DISTRIBUTE BY RANGE (PARTITION VALUES < 10, PARTITION 10 <= VALUES < 30,
+  PARTITION 30 <= VALUES) STORED AS KUDU
+---- RESULTS
+====
+---- QUERY
+# VALUES, single row, all target cols, no errors
+insert into tdata values (1, 1, 1, 'one', true, 1, 1, 1)
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,1,1,'one',true,1,1,1
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# VALUES, single row, all target cols, NULL
+insert into tdata values (2, NULL, NULL, NULL, NULL, NULL, NULL, NULL)
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,1,1,'one',true,1,1,1
+2,NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# VALUES, single row, all target cols, bounday values
+insert into tdata values
+(3, cast('nan' as float), max_bigint(), '', true, min_tinyint(), 
max_smallint(),
+  cast('-inf' as double))
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,1,1,'one',true,1,1,1
+2,NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+3,NaN,9223372036854775807,'',true,-128,32767,-Infinity
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# VALUES, single row, subset of target cols
+insert into tdata (valb, vald, id) values (true, 0, 4)
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,1,1,'one',true,1,1,1
+2,NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+3,NaN,9223372036854775807,'',true,-128,32767,-Infinity
+4,NULL,NULL,'NULL',true,NULL,NULL,0
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# VALUES, multiple rows, all target cols
+insert into tdata values
+(5, 5.0, 5, 'five', false, NULL, NULL, NULL),
+(6, 16, 60, '', true, 0, -1, -6),
+(7, NULL, 10, NULL, false, max_tinyint(), -7, 2)
+---- RUNTIME_PROFILE
+NumModifiedRows: 3
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,1,1,'one',true,1,1,1
+2,NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+3,NaN,9223372036854775807,'',true,-128,32767,-Infinity
+4,NULL,NULL,'NULL',true,NULL,NULL,0
+5,5.0,5,'five',false,NULL,NULL,NULL
+6,16,60,'',true,0,-1,-6
+7,NULL,10,'NULL',false,127,-7,2
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# VALUES, multiple rows, subset of cols
+insert into tdata (valv, valf, vali, id) values
+('eight', 88, 888, 8),
+(NULL, -9, -99, 9)
+---- RUNTIME_PROFILE
+NumModifiedRows: 2
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,1,1,'one',true,1,1,1
+2,NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+3,NaN,9223372036854775807,'',true,-128,32767,-Infinity
+4,NULL,NULL,'NULL',true,NULL,NULL,0
+5,5.0,5,'five',false,NULL,NULL,NULL
+6,16,60,'',true,0,-1,-6
+7,NULL,10,'NULL',false,127,-7,2
+8,88,888,'eight',NULL,NULL,NULL,NULL
+9,-9,-99,'NULL',NULL,NULL,NULL,NULL
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# SELECT, single row, all target cols
+insert into tdata
+select id, float_col, bigint_col, string_col, bool_col, tinyint_col, 
smallint_col, double_col
+from functional.alltypes where id = 10
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,1,1,'one',true,1,1,1
+2,NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+3,NaN,9223372036854775807,'',true,-128,32767,-Infinity
+4,NULL,NULL,'NULL',true,NULL,NULL,0
+5,5.0,5,'five',false,NULL,NULL,NULL
+6,16,60,'',true,0,-1,-6
+7,NULL,10,'NULL',false,127,-7,2
+8,88,888,'eight',NULL,NULL,NULL,NULL
+9,-9,-99,'NULL',NULL,NULL,NULL,NULL
+10,0,0,'0',true,0,0,0
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# SELECT, single row, subset of cols
+insert into tdata (id, vald, valb, vali)
+select id, double_col, bool_col, bigint_col
+from functional.alltypes where id = 11
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,1,1,'one',true,1,1,1
+2,NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+3,NaN,9223372036854775807,'',true,-128,32767,-Infinity
+4,NULL,NULL,'NULL',true,NULL,NULL,0
+5,5.0,5,'five',false,NULL,NULL,NULL
+6,16,60,'',true,0,-1,-6
+7,NULL,10,'NULL',false,127,-7,2
+8,88,888,'eight',NULL,NULL,NULL,NULL
+9,-9,-99,'NULL',NULL,NULL,NULL,NULL
+10,0,0,'0',true,0,0,0
+11,NULL,10,'NULL',false,NULL,NULL,10.1
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+delete tdata
+---- DML_RESULTS: tdata
+====
+---- QUERY
+# SELECT, multiple rows, all target cols
+insert into tdata
+select id, float_col, bigint_col, string_col, bool_col, tinyint_col, 
smallint_col, double_col
+from functional.alltypes where id < 2
+---- RUNTIME_PROFILE
+NumModifiedRows: 2
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+0,0,0,'0',true,0,0,0
+1,1.100000023841858,10,'1',false,1,1,10.1
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# SELECT, multiple rows, subset of cols
+insert into tdata (vals, id, valt, vald)
+select smallint_col, id, tinyint_col, double_col
+from functional.alltypes where id > 2 and id < 6
+---- RUNTIME_PROFILE
+NumModifiedRows: 3
+NumRowErrors: 0
+---- LABELS
+ID, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+0,0,0,'0',true,0,0,0
+1,1.100000023841858,10,'1',false,1,1,10.1
+3,NULL,NULL,'NULL',NULL,3,3,30.3
+4,NULL,NULL,'NULL',NULL,4,4,40.4
+5,NULL,NULL,'NULL',NULL,5,5,50.5
+---- TYPES
+INT,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# Make sure we can insert empty strings into string columns and that we can 
scan them
+# back.
+insert into tdata values (320, 2.0, 932, cast('' as string), false, 0, 0, 0)
+---- RESULTS
+: 1
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+====
+---- QUERY
+select id, valv, valb from tdata where id = 320;
+---- RESULTS
+320,'',false
+---- TYPES
+INT,STRING,BOOLEAN
+====
+---- QUERY
+insert into tdata values
+(666, cast(1.2 as float), 43, cast('z' as string), true, 0, 0, 0)
+---- RESULTS
+: 1
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+====
+---- QUERY
+# insert row with primary key that already exists
+insert into tdata values
+(666, cast(1.2 as float), 43, cast('z' as VARCHAR(20)), true, 0, 0, 0)
+---- RESULTS
+: 0
+---- RUNTIME_PROFILE
+NumModifiedRows: 0
+NumRowErrors: 1
+====
+---- QUERY
+create table kudu_test_tbl primary key(id)
+distribute by range(id) (partition values < 100, partition 100 <= values <= 
10000)
+stored as kudu as
+select * from functional_kudu.alltypes where id < 100;
+---- RESULTS
+'Inserted 100 row(s)'
+---- RUNTIME_PROFILE
+NumModifiedRows: 100
+NumRowErrors: 0
+====
+---- QUERY
+insert into kudu_test_tbl
+select * from functional_kudu.alltypes where id < 100;
+---- RESULTS
+: 0
+---- RUNTIME_PROFILE
+NumModifiedRows: 0
+NumRowErrors: 100
+====
+---- QUERY
+# large insert - 100 rows were already inserted above and result in errors
+insert into kudu_test_tbl
+select * from functional_kudu.alltypes;
+---- RESULTS
+: 7200
+---- RUNTIME_PROFILE
+NumModifiedRows: 7200
+NumRowErrors: 100
+====
+---- QUERY
+# Insert rows that are not covered by any of the existing range partitions
+# Only the row at 10000 is inserted.
+insert into kudu_test_tbl SELECT cast(id + 10000 as int), bool_col, 
tinyint_col,
+  smallint_col, int_col, bigint_col, float_col, double_col, date_string_col, 
string_col,
+  timestamp_col, year, month
+from functional_kudu.alltypes
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 7299
+====
+---- QUERY
+# IMPALA-2521: clustered insert into table.
+create table impala_2521
+(id bigint primary key, name string, zip int)
+distribute by hash into 3 buckets stored as kudu
+---- RESULTS
+====
+---- QUERY
+insert into impala_2521 /*+ clustered */
+select id, name, maxzip as zip
+from (
+select tinyint_col as id, cast(max(int_col) + 1 as int) as maxzip, string_col 
as name
+from functional_kudu.alltypessmall group by id, name
+) as sub;
+---- RESULTS
+: 10
+---- RUNTIME_PROFILE
+NumModifiedRows: 10
+NumRowErrors: 0
+====
+---- QUERY
+select * from impala_2521
+---- RESULTS
+0,'0',1
+1,'1',2
+2,'2',3
+3,'3',4
+4,'4',5
+5,'5',6
+6,'6',7
+7,'7',8
+8,'8',9
+9,'9',10
+---- TYPES
+BIGINT,STRING,INT
+====
+---- QUERY
+# Table with all supported types as primary key and distribution columns
+create table allkeytypes (i1 tinyint, i2 smallint, i3 int, i4 bigint, name 
string,
+  valf float, vald double, primary key (i1, i2, i3, i4, name)) distribute by
+  hash into 3 buckets, range (partition value = (1,1,1,1,'1'),
+  partition value = (2,2,2,2,'2'), partition value = (3,3,3,3,'3')) stored as 
kudu
+---- RESULTS
+====
+---- QUERY
+insert into allkeytypes select cast(id as tinyint), smallint_col, int_col,
+  cast (bigint_col/10 as bigint), string_col, float_col, double_col
+  from functional.alltypes where id > 0 and id < 10
+---- RESULTS
+: 3
+---- RUNTIME_PROFILE
+NumModifiedRows: 3
+NumRowErrors: 6
+====

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3833707d/testdata/workloads/functional-query/queries/QueryTest/kudu_update.test
----------------------------------------------------------------------
diff --git 
a/testdata/workloads/functional-query/queries/QueryTest/kudu_update.test 
b/testdata/workloads/functional-query/queries/QueryTest/kudu_update.test
new file mode 100644
index 0000000..fe0a6b1
--- /dev/null
+++ b/testdata/workloads/functional-query/queries/QueryTest/kudu_update.test
@@ -0,0 +1,340 @@
+====
+---- QUERY
+create table tdata
+  (id int primary key, name string, valf float, vali bigint, valv string, valb 
boolean,
+   valt tinyint, vals smallint, vald double)
+  DISTRIBUTE BY RANGE (PARTITION VALUES < 10, PARTITION 10 <= VALUES < 30,
+  PARTITION 30 <= VALUES <= 10000) STORED AS KUDU
+---- RESULTS
+====
+---- QUERY
+insert into tdata values
+(1, "martin", 1.0, 232232323, cast('a' as string), true, 1, 2, 3),
+(2, "david", cast(1.0 as float), 99398493939, cast('b' as string), false, 4, 
5, 6),
+(3, "todd", cast(1.0 as float), 993393939, "c", true, 7, 8, 9),
+(40, "he", cast(0.0 as float), 43, cast('e' as string), false, 50, 60, 70),
+(120, "she", cast(0.0 as float), 99, cast('f' as string), true, -1, 0, 1)
+---- RESULTS
+: 5
+---- RUNTIME_PROFILE
+NumModifiedRows: 5
+NumRowErrors: 0
+====
+---- QUERY
+# single row, equality on key, bigint
+# TODO: Verify row count in RESULTS after fixing IMPALA-3713, and supporting 
RESULTS and
+# DML_RESULTS in the same test case.
+update tdata set vali=43 where id = 1
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,'martin',1.0,43,'a',true,1,2,3
+2,'david',1.0,99398493939,'b',false,4,5,6
+3,'todd',1.0,993393939,'c',true,7,8,9
+40,'he',0.0,43,'e',false,50,60,70
+120,'she',0.0,99,'f',true,-1,0,1
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# single row, equality on key, string
+# Try updating a string col where casting a value that is bigger than the 
varchar in the
+# cast. The value gets truncated and stored to the string col.
+update tdata set valv=cast('aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' as varchar(20)) 
where id = 1
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,'martin',1.0,43,'aaaaaaaaaaaaaaaaaaaa',true,1,2,3
+2,'david',1.0,99398493939,'b',false,4,5,6
+3,'todd',1.0,993393939,'c',true,7,8,9
+40,'he',0.0,43,'e',false,50,60,70
+120,'she',0.0,99,'f',true,-1,0,1
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# single row, equality on key, boolean
+update tdata set valb=false where id = 1
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,'martin',1.0,43,'aaaaaaaaaaaaaaaaaaaa',false,1,2,3
+2,'david',1.0,99398493939,'b',false,4,5,6
+3,'todd',1.0,993393939,'c',true,7,8,9
+40,'he',0.0,43,'e',false,50,60,70
+120,'she',0.0,99,'f',true,-1,0,1
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# single row, equality on key, set to NULL
+update tdata set name=null where id = 40
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,'martin',1.0,43,'aaaaaaaaaaaaaaaaaaaa',false,1,2,3
+2,'david',1.0,99398493939,'b',false,4,5,6
+3,'todd',1.0,993393939,'c',true,7,8,9
+40,'NULL',0.0,43,'e',false,50,60,70
+120,'she',0.0,99,'f',true,-1,0,1
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# single row, equlity on key, set from NULL
+update tdata set name='he' where id = 40
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,'martin',1.0,43,'aaaaaaaaaaaaaaaaaaaa',false,1,2,3
+2,'david',1.0,99398493939,'b',false,4,5,6
+3,'todd',1.0,993393939,'c',true,7,8,9
+40,'he',0.0,43,'e',false,50,60,70
+120,'she',0.0,99,'f',true,-1,0,1
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# single row, equality on key, boundary value
+update tdata set vali = max_bigint() where id = 120
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,'martin',1.0,43,'aaaaaaaaaaaaaaaaaaaa',false,1,2,3
+2,'david',1.0,99398493939,'b',false,4,5,6
+3,'todd',1.0,993393939,'c',true,7,8,9
+40,'he',0.0,43,'e',false,50,60,70
+120,'she',0.0,9223372036854775807,'f',true,-1,0,1
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# single row, inequality on key, float
+update tdata set valf = -1 where id > 2 and id < 4
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,'martin',1.0,43,'aaaaaaaaaaaaaaaaaaaa',false,1,2,3
+2,'david',1.0,99398493939,'b',false,4,5,6
+3,'todd',-1.0,993393939,'c',true,7,8,9
+40,'he',0.0,43,'e',false,50,60,70
+120,'she',0.0,9223372036854775807,'f',true,-1,0,1
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# single row, inequality on key, tinyint
+update tdata set valt = 10 where id > 100
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,'martin',1.0,43,'aaaaaaaaaaaaaaaaaaaa',false,1,2,3
+2,'david',1.0,99398493939,'b',false,4,5,6
+3,'todd',-1.0,993393939,'c',true,7,8,9
+40,'he',0.0,43,'e',false,50,60,70
+120,'she',0.0,9223372036854775807,'f',true,10,0,1
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# single row, equality on non-key, string
+update tdata set name='unknown' where name = 'martin'
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,'unknown',1.0,43,'aaaaaaaaaaaaaaaaaaaa',false,1,2,3
+2,'david',1.0,99398493939,'b',false,4,5,6
+3,'todd',-1.0,993393939,'c',true,7,8,9
+40,'he',0.0,43,'e',false,50,60,70
+120,'she',0.0,9223372036854775807,'f',true,10,0,1
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# single row, inequality on non-key, double
+update tdata set vald = 0 where valf < 0
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,'unknown',1.0,43,'aaaaaaaaaaaaaaaaaaaa',false,1,2,3
+2,'david',1.0,99398493939,'b',false,4,5,6
+3,'todd',-1.0,993393939,'c',true,7,8,0
+40,'he',0.0,43,'e',false,50,60,70
+120,'she',0.0,9223372036854775807,'f',true,10,0,1
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# multiple rows, predicate on key
+update tdata set vali=43 where id > 1 and id < 10
+---- RUNTIME_PROFILE
+NumModifiedRows: 2
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,'unknown',1.0,43,'aaaaaaaaaaaaaaaaaaaa',false,1,2,3
+2,'david',1.0,43,'b',false,4,5,6
+3,'todd',-1.0,43,'c',true,7,8,0
+40,'he',0.0,43,'e',false,50,60,70
+120,'she',0.0,9223372036854775807,'f',true,10,0,1
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# multiple rows, predicate on non-key
+update tdata set valb=false where name LIKE '%he'
+---- RUNTIME_PROFILE
+NumModifiedRows: 2
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,'unknown',1.0,43,'aaaaaaaaaaaaaaaaaaaa',false,1,2,3
+2,'david',1.0,43,'b',false,4,5,6
+3,'todd',-1.0,43,'c',true,7,8,0
+40,'he',0.0,43,'e',false,50,60,70
+120,'she',0.0,9223372036854775807,'f',false,10,0,1
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# update the same row multiple times: cross join produces 5 identical updates
+update a set a.name='they' from tdata a, tdata b where a.id = 1
+---- RUNTIME_PROFILE
+NumModifiedRows: 5
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,'they',1.0,43,'aaaaaaaaaaaaaaaaaaaa',false,1,2,3
+2,'david',1.0,43,'b',false,4,5,6
+3,'todd',-1.0,43,'c',true,7,8,0
+40,'he',0.0,43,'e',false,50,60,70
+120,'she',0.0,9223372036854775807,'f',false,10,0,1
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# value of update is a constant expression
+update tdata set valf = 1 + 2 where id = 1
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,'they',3,43,'aaaaaaaaaaaaaaaaaaaa',false,1,2,3
+2,'david',1.0,43,'b',false,4,5,6
+3,'todd',-1.0,43,'c',true,7,8,0
+40,'he',0.0,43,'e',false,50,60,70
+120,'she',0.0,9223372036854775807,'f',false,10,0,1
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# value of update is a non-constant expression
+update tdata set name = concat(name, name) where id % 2 = 1
+---- RUNTIME_PROFILE
+NumModifiedRows: 2
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,'theythey',3,43,'aaaaaaaaaaaaaaaaaaaa',false,1,2,3
+2,'david',1.0,43,'b',false,4,5,6
+3,'toddtodd',-1.0,43,'c',true,7,8,0
+40,'he',0.0,43,'e',false,50,60,70
+120,'she',0.0,9223372036854775807,'f',false,10,0,1
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# error - update key column
+update tdata set id = 0 where name = 'he'
+---- CATCH
+Key column 'id' cannot be updated.
+====
+---- QUERY
+# no rows updated
+update tdata set name = 'none' where id = 10
+---- RUNTIME_PROFILE
+NumModifiedRows: 0
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,'theythey',3,43,'aaaaaaaaaaaaaaaaaaaa',false,1,2,3
+2,'david',1.0,43,'b',false,4,5,6
+3,'toddtodd',-1.0,43,'c',true,7,8,0
+40,'he',0.0,43,'e',false,50,60,70
+120,'she',0.0,9223372036854775807,'f',false,10,0,1
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# Try to update a row with a primary key value that is not covered by the 
existing range
+# partitions. This doesn't actually end up selecting any rows to modify.
+update tdata set vali = 10 where id = 10001
+---- RUNTIME_PROFILE
+NumModifiedRows: 0
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+1,'theythey',3,43,'aaaaaaaaaaaaaaaaaaaa',false,1,2,3
+2,'david',1.0,43,'b',false,4,5,6
+3,'toddtodd',-1.0,43,'c',true,7,8,0
+40,'he',0.0,43,'e',false,50,60,70
+120,'she',0.0,9223372036854775807,'f',false,10,0,1
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+insert into tdata
+select id, string_col, float_col, bigint_col, string_col, bool_col, 
tinyint_col,
+smallint_col, double_col from functional_kudu.alltypes
+---- RESULTS
+: 7295
+---- RUNTIME_PROFILE
+NumModifiedRows: 7295
+NumRowErrors: 5
+====
+---- QUERY
+# Test a larger UPDATE
+update tdata set vali = -1
+---- RESULTS
+---- RUNTIME_PROFILE
+NumModifiedRows: 7300
+NumRowErrors: 0
+====
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3833707d/testdata/workloads/functional-query/queries/QueryTest/kudu_upsert.test
----------------------------------------------------------------------
diff --git 
a/testdata/workloads/functional-query/queries/QueryTest/kudu_upsert.test 
b/testdata/workloads/functional-query/queries/QueryTest/kudu_upsert.test
new file mode 100644
index 0000000..5b5752a
--- /dev/null
+++ b/testdata/workloads/functional-query/queries/QueryTest/kudu_upsert.test
@@ -0,0 +1,491 @@
+====
+---- QUERY
+create table tdata
+  (id int primary key, name string, valf float, vali bigint, valv string, valb 
boolean,
+   valt tinyint, vals smallint, vald double)
+  DISTRIBUTE BY RANGE (PARTITION VALUES < 10, PARTITION 10 <= VALUES < 30,
+  PARTITION 30 <= VALUES) STORED AS KUDU
+---- RESULTS
+====
+---- QUERY
+insert into table tdata values
+(40,'he',0,43,'e',false,35,36,1.2),
+(1,'unknown',1,43,'aaaaaaaaaaaaaaaaaaaa',false,-1,-2,0),
+(2,'david',1,43,'b',false,0,0,0),
+(3,'todd',1,43,'c',true,3,3,3)
+---- RESULTS
+: 4
+====
+---- QUERY
+# VALUES, single row, all cols, results in insert
+upsert into table tdata values (4, 'a', 0, 1, 'b', false, 1, 2, 1.5)
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+40,'he',0,43,'e',false,35,36,1.2
+1,'unknown',1,43,'aaaaaaaaaaaaaaaaaaaa',false,-1,-2,0
+2,'david',1,43,'b',false,0,0,0
+3,'todd',1,43,'c',true,3,3,3
+4,'a',0,1,'b',false,1,2,1.5
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# VALUES, single row, all cols, results in update
+upsert into table tdata values (4, 'b', -1, 1, 'a', true, 2, 3, 2.5)
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+40,'he',0,43,'e',false,35,36,1.2
+1,'unknown',1,43,'aaaaaaaaaaaaaaaaaaaa',false,-1,-2,0
+2,'david',1,43,'b',false,0,0,0
+3,'todd',1,43,'c',true,3,3,3
+4,'b',-1,1,'a',true,2,3,2.5
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# VALUES, single row, all cols, insert NULL all types
+upsert into table tdata values (10, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 
NULL)
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+40,'he',0,43,'e',false,35,36,1.2
+1,'unknown',1,43,'aaaaaaaaaaaaaaaaaaaa',false,-1,-2,0
+2,'david',1,43,'b',false,0,0,0
+3,'todd',1,43,'c',true,3,3,3
+4,'b',-1,1,'a',true,2,3,2.5
+10,'NULL',NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# VALUES, single row, all cols, update NULL all types
+upsert into table tdata values (4, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 
NULL)
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+40,'he',0,43,'e',false,35,36,1.2
+1,'unknown',1,43,'aaaaaaaaaaaaaaaaaaaa',false,-1,-2,0
+2,'david',1,43,'b',false,0,0,0
+3,'todd',1,43,'c',true,3,3,3
+4,'NULL',NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+10,'NULL',NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# VALUES, single row, all cols, update from NULL all types
+upsert into table tdata values (4, 'four', 5, 6, 'f', true, 7, 8, 7.5)
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+40,'he',0,43,'e',false,35,36,1.2
+1,'unknown',1,43,'aaaaaaaaaaaaaaaaaaaa',false,-1,-2,0
+2,'david',1,43,'b',false,0,0,0
+3,'todd',1,43,'c',true,3,3,3
+4,'four',5,6,'f',true,7,8,7.5
+10,'NULL',NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# VALUES, single row, all cols, insert boundary values
+upsert into table tdata values
+(max_int(), '', cast('nan' as float), min_bigint(), '', true, max_tinyint(),
+  min_smallint(), cast('inf' as double))
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+40,'he',0,43,'e',false,35,36,1.2
+1,'unknown',1,43,'aaaaaaaaaaaaaaaaaaaa',false,-1,-2,0
+2,'david',1,43,'b',false,0,0,0
+3,'todd',1,43,'c',true,3,3,3
+4,'four',5,6,'f',true,7,8,7.5
+10,'NULL',NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+2147483647,'',NaN,-9223372036854775808,'',true,127,-32768,Infinity
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# VALUES, single row, all cols, update boundary values
+upsert into table tdata values
+(max_int(), '', cast('-inf' as float), max_bigint(), '', true, min_tinyint(),
+  max_smallint(), cast('nan' as double))
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+40,'he',0,43,'e',false,35,36,1.2
+1,'unknown',1,43,'aaaaaaaaaaaaaaaaaaaa',false,-1,-2,0
+2,'david',1,43,'b',false,0,0,0
+3,'todd',1,43,'c',true,3,3,3
+4,'four',5,6,'f',true,7,8,7.5
+10,'NULL',NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+2147483647,'',-Infinity,9223372036854775807,'',true,-128,32767,NaN
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# VALUES, single row, subset of cols, results in insert
+upsert into table tdata (id, name, vali, valb, vald) values (5, 'five', -5, 
NULL, 0.5)
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+40,'he',0,43,'e',false,35,36,1.2
+1,'unknown',1,43,'aaaaaaaaaaaaaaaaaaaa',false,-1,-2,0
+2,'david',1,43,'b',false,0,0,0
+3,'todd',1,43,'c',true,3,3,3
+4,'four',5,6,'f',true,7,8,7.5
+10,'NULL',NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+2147483647,'',-Infinity,9223372036854775807,'',true,-128,32767,NaN
+5,'five',NULL,-5,'NULL',NULL,NULL,NULL,0.5
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# VALUES, single row, subset of cols, results in update
+upsert into table tdata (id, name, valf, valv, valb) values (5, NULL, 0, 
'six', false)
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+40,'he',0,43,'e',false,35,36,1.2
+1,'unknown',1,43,'aaaaaaaaaaaaaaaaaaaa',false,-1,-2,0
+2,'david',1,43,'b',false,0,0,0
+3,'todd',1,43,'c',true,3,3,3
+4,'four',5,6,'f',true,7,8,7.5
+10,'NULL',NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+2147483647,'',-Infinity,9223372036854775807,'',true,-128,32767,NaN
+5,'NULL',0,-5,'six',false,NULL,NULL,0.5
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# VALUES, multiple rows, all cols, no errors
+upsert into table tdata values
+(1, 'one', NULL, 44, 'a', true, -1, -2, 0),
+(6, '', -6, 40, 'b', NULL, 0, 0, 10),
+(7, 'seven', 0, min_bigint(), NULL, true, 7, 1, 2),
+(2, 'you', cast('inf' as float), 0, 't', false, NULL, min_smallint(), 0)
+---- RUNTIME_PROFILE
+NumModifiedRows: 4
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+40,'he',0,43,'e',false,35,36,1.2
+1,'one',NULL,44,'a',true,-1,-2,0
+2,'you',Infinity,0,'t',false,NULL,-32768,0
+3,'todd',1,43,'c',true,3,3,3
+4,'four',5,6,'f',true,7,8,7.5
+10,'NULL',NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+2147483647,'',-Infinity,9223372036854775807,'',true,-128,32767,NaN
+5,'NULL',0,-5,'six',false,NULL,NULL,0.5
+6,'',-6,40,'b',NULL,0,0,10
+7,'seven',0,-9223372036854775808,'NULL',true,7,1,2
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# VALUES, multiple rows, subset of cols, no errors
+upsert into table tdata (id, valb, name, vali) values
+(1, true, NULL, 1),
+(8, false, 'hello', 2),
+(5, NULL, 'five', 10),
+(9, true, 'nine', 9)
+---- RUNTIME_PROFILE
+NumModifiedRows: 4
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+40,'he',0,43,'e',false,35,36,1.2
+1,'NULL',NULL,1,'a',true,-1,-2,0
+2,'you',Infinity,0,'t',false,NULL,-32768,0
+3,'todd',1,43,'c',true,3,3,3
+4,'four',5,6,'f',true,7,8,7.5
+10,'NULL',NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+2147483647,'',-Infinity,9223372036854775807,'',true,-128,32767,NaN
+5,'five',0,10,'six',NULL,NULL,NULL,0.5
+6,'',-6,40,'b',NULL,0,0,10
+7,'seven',0,-9223372036854775808,'NULL',true,7,1,2
+8,'hello',NULL,2,'NULL',false,NULL,NULL,NULL
+9,'nine',NULL,9,'NULL',true,NULL,NULL,NULL
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# SELECT, all cols, single row, no errors
+upsert into table tdata
+select id, 'a', valf, vali, valv, NULL, valt, vals, 3 from tdata where id = 1
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+40,'he',0,43,'e',false,35,36,1.2
+1,'a',NULL,1,'a',NULL,-1,-2,3
+2,'you',Infinity,0,'t',false,NULL,-32768,0
+3,'todd',1,43,'c',true,3,3,3
+4,'four',5,6,'f',true,7,8,7.5
+10,'NULL',NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+2147483647,'',-Infinity,9223372036854775807,'',true,-128,32767,NaN
+5,'five',0,10,'six',NULL,NULL,NULL,0.5
+6,'',-6,40,'b',NULL,0,0,10
+7,'seven',0,-9223372036854775808,'NULL',true,7,1,2
+8,'hello',NULL,2,'NULL',false,NULL,NULL,NULL
+9,'nine',NULL,9,'NULL',true,NULL,NULL,NULL
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# SELECT, all cols, multiple rows, no errors
+upsert into table tdata
+select id, valv, valf, vali, name, valb, valt, vals, vald from tdata where id 
% 2 = 0
+---- RUNTIME_PROFILE
+NumModifiedRows: 6
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+40,'e',0,43,'he',false,35,36,1.2
+1,'a',NULL,1,'a',NULL,-1,-2,3
+2,'t',Infinity,0,'you',false,NULL,-32768,0
+3,'todd',1,43,'c',true,3,3,3
+4,'f',5,6,'four',true,7,8,7.5
+10,'NULL',NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+2147483647,'',-Infinity,9223372036854775807,'',true,-128,32767,NaN
+5,'five',0,10,'six',NULL,NULL,NULL,0.5
+6,'b',-6,40,'',NULL,0,0,10
+7,'seven',0,-9223372036854775808,'NULL',true,7,1,2
+8,'NULL',NULL,2,'hello',false,NULL,NULL,NULL
+9,'nine',NULL,9,'NULL',true,NULL,NULL,NULL
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# SELECT, subset of cols, single row, no errors
+upsert into table tdata (id, valv, vali)
+select int_col, string_col, bigint_col from functional.alltypes where id = 0
+---- RUNTIME_PROFILE
+NumModifiedRows: 1
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+40,'e',0,43,'he',false,35,36,1.2
+1,'a',NULL,1,'a',NULL,-1,-2,3
+2,'t',Infinity,0,'you',false,NULL,-32768,0
+3,'todd',1,43,'c',true,3,3,3
+4,'f',5,6,'four',true,7,8,7.5
+10,'NULL',NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+2147483647,'',-Infinity,9223372036854775807,'',true,-128,32767,NaN
+5,'five',0,10,'six',NULL,NULL,NULL,0.5
+6,'b',-6,40,'',NULL,0,0,10
+7,'seven',0,-9223372036854775808,'NULL',true,7,1,2
+8,'NULL',NULL,2,'hello',false,NULL,NULL,NULL
+9,'nine',NULL,9,'NULL',true,NULL,NULL,NULL
+0,'NULL',NULL,0,'0',NULL,NULL,NULL,NULL
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# SELECT, subset of cols, multiple rows, no errors
+upsert into table tdata (id, valb, name, valt)
+select int_col, bool_col, string_col, tinyint_col from functional.alltypes 
where id < 4
+---- RUNTIME_PROFILE
+NumModifiedRows: 4
+NumRowErrors: 0
+---- LABELS
+ID, NAME, VALF, VALI, VALV, VALB, VALT, VALS, VALD
+---- DML_RESULTS: tdata
+40,'e',0,43,'he',false,35,36,1.2
+1,'1',NULL,1,'a',false,1,-2,3
+2,'2',Infinity,0,'you',true,2,-32768,0
+3,'3',1,43,'c',false,3,3,3
+4,'f',5,6,'four',true,7,8,7.5
+10,'NULL',NULL,NULL,'NULL',NULL,NULL,NULL,NULL
+2147483647,'',-Infinity,9223372036854775807,'',true,-128,32767,NaN
+5,'five',0,10,'six',NULL,NULL,NULL,0.5
+6,'b',-6,40,'',NULL,0,0,10
+7,'seven',0,-9223372036854775808,'NULL',true,7,1,2
+8,'NULL',NULL,2,'hello',false,NULL,NULL,NULL
+9,'nine',NULL,9,'NULL',true,NULL,NULL,NULL
+0,'0',NULL,0,'0',true,0,NULL,NULL
+---- TYPES
+INT,STRING,FLOAT,BIGINT,STRING,BOOLEAN,TINYINT,SMALLINT,DOUBLE
+====
+---- QUERY
+# VALUES, single row, all cols, null for non-nullable column
+upsert into table tdata values (null, '', 0, 0, cast('' as VARCHAR(20)), 
false, 0, 0, 0)
+---- RUNTIME_PROFILE
+NumModifiedRows: 0
+NumRowErrors: 1
+====
+---- QUERY
+# VALUES, single row, subset of cols, null for non-nullable column
+upsert into table tdata (id, name) values (null, '')
+---- RUNTIME_PROFILE
+NumModifiedRows: 0
+NumRowErrors: 1
+====
+---- QUERY
+# VALUES, multiple rows, all cols, null for non-nullable column
+upsert into table tdata values
+(3,'todd',1,43,'c',true,3,3,3),
+(4,'four',5,6,'f',true,7,8,7.5),
+(6,'',-6,40,'b',NULL,0,0,10),
+(NULL,'seven',0,0,'NULL',true,7,1,2)
+---- RUNTIME_PROFILE
+NumModifiedRows: 3
+NumRowErrors: 1
+====
+---- QUERY
+# VALUES, multiple rows, subset of cols, null for non-nullable column
+upsert into table tdata (id, valv, valt, vals) values
+(0, 'bbb', 1, 2),
+(NULL, 'aaa', 2, 1),
+(10, 'ccc', 11, 12)
+---- RUNTIME_PROFILE
+NumModifiedRows: 2
+NumRowErrors: 1
+====
+---- QUERY
+# high cardinality
+upsert into table tdata (id, valb, name, valt)
+select int_col, bool_col, string_col, tinyint_col from functional.alltypes 
limit 100
+---- RUNTIME_PROFILE
+NumModifiedRows: 100
+NumRowErrors: 0
+---- RESULTS
+====
+---- QUERY
+create table multiple_key_cols
+  (string_col string, bigint_col bigint, tinyint_col tinyint, smallint_col 
smallint,
+   bool_col boolean, int_col int, double_col double, float_col float,
+   primary key (string_col, bigint_col, tinyint_col, smallint_col))
+  DISTRIBUTE BY HASH (string_col) INTO 16 BUCKETS STORED AS KUDU
+====
+---- QUERY
+insert into multiple_key_cols values
+('a', 1, 2, 3, true, 4, 5, NULL),
+('b', 1, 2, 3, false, 7, NULL, 9)
+---- RESULTS
+: 2
+====
+---- QUERY
+# VALUES, multiple key columns, all cols
+upsert into table multiple_key_cols values
+('a', 1, 2, 3, true, NULL, 5, 6),
+('a', -1, -2, -3, true, 0, NULL, NULL),
+('c', 0, 0, 0, NULL, 10, 20, 30)
+---- RUNTIME_PROFILE
+NumModifiedRows: 3
+NumRowErrors: 0
+---- LABELS
+STRING_COL, BIGINT_COL, TINYINT_COL, SMALLINT_COL, BOOL_COL, INT_COL, 
DOUBLE_COL, FLOAT_COL
+---- DML_RESULTS: multiple_key_cols
+'a',1,2,3,true,NULL,5,6
+'a',-1,-2,-3,true,0,NULL,NULL
+'b',1,2,3,false,7,NULL,9
+'c',0,0,0,NULL,10,20,30
+---- TYPES
+STRING,BIGINT,TINYINT,SMALLINT,BOOLEAN,INT,DOUBLE,FLOAT
+====
+---- QUERY
+# VALUES, multiple key columns, subset of cols
+upsert into table multiple_key_cols
+(string_col, bool_col, bigint_col, smallint_col, tinyint_col) values
+('a', false, 1, 3, 2),
+('d', NULL, 0, 1, 2),
+('b', true, 1, 3, 3)
+---- RUNTIME_PROFILE
+NumModifiedRows: 3
+NumRowErrors: 0
+---- LABELS
+STRING_COL, BIGINT_COL, TINYINT_COL, SMALLINT_COL, BOOL_COL, INT_COL, 
DOUBLE_COL, FLOAT_COL
+---- DML_RESULTS: multiple_key_cols
+'a',1,2,3,false,NULL,5,6
+'a',-1,-2,-3,true,0,NULL,NULL
+'b',1,2,3,false,7,NULL,9
+'c',0,0,0,NULL,10,20,30
+'d',0,2,1,NULL,NULL,NULL,NULL
+'b',1,3,3,true,NULL,NULL,NULL
+---- TYPES
+STRING,BIGINT,TINYINT,SMALLINT,BOOLEAN,INT,DOUBLE,FLOAT
+====
+---- QUERY
+# SELECT, multiple key columns, all cols
+upsert into table multiple_key_cols
+select string_col, bigint_col, tinyint_col, smallint_col, false, -1, -2, -3
+from multiple_key_cols where string_col = 'a'
+---- RUNTIME_PROFILE
+NumModifiedRows: 2
+NumRowErrors: 0
+---- LABELS
+STRING_COL, BIGINT_COL, TINYINT_COL, SMALLINT_COL, BOOL_COL, INT_COL, 
DOUBLE_COL, FLOAT_COL
+---- DML_RESULTS: multiple_key_cols
+'a',1,2,3,false,-1,-2,-3
+'a',-1,-2,-3,false,-1,-2,-3
+'b',1,2,3,false,7,NULL,9
+'c',0,0,0,NULL,10,20,30
+'d',0,2,1,NULL,NULL,NULL,NULL
+'b',1,3,3,true,NULL,NULL,NULL
+---- TYPES
+STRING,BIGINT,TINYINT,SMALLINT,BOOLEAN,INT,DOUBLE,FLOAT
+====
+---- QUERY
+# SELECT, multiple key columns, subset of cols
+upsert into table multiple_key_cols
+(string_col, float_col, bigint_col, tinyint_col, double_col, smallint_col)
+select 'b', float_col, 1, tinyint_col, double_col, 3
+from functional.alltypes where id = 2 or id = 3
+---- RUNTIME_PROFILE
+NumModifiedRows: 2
+NumRowErrors: 0
+---- LABELS
+STRING_COL, BIGINT_COL, TINYINT_COL, SMALLINT_COL, BOOL_COL, INT_COL, 
DOUBLE_COL, FLOAT_COL
+---- DML_RESULTS: multiple_key_cols
+'a',1,2,3,false,-1,-2,-3
+'a',-1,-2,-3,false,-1,-2,-3
+'b',1,2,3,false,7,20.2,2.200000047683716
+'c',0,0,0,NULL,10,20,30
+'d',0,2,1,NULL,NULL,NULL,NULL
+'b',1,3,3,true,NULL,30.3,3.299999952316284
+---- TYPES
+STRING,BIGINT,TINYINT,SMALLINT,BOOLEAN,INT,DOUBLE,FLOAT
+====
+---- QUERY
+# missing key column
+upsert into table multiple_key_cols
+(string_col, tinyint_col, smallint_col) values ('a', 1, 1)
+---- CATCH
+All primary key columns must be specified for UPSERTing into Kudu tables. 
Missing columns are: bigint_col
+====
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3833707d/tests/common/impala_test_suite.py
----------------------------------------------------------------------
diff --git a/tests/common/impala_test_suite.py 
b/tests/common/impala_test_suite.py
index e287360..222f709 100644
--- a/tests/common/impala_test_suite.py
+++ b/tests/common/impala_test_suite.py
@@ -338,6 +338,11 @@ class ImpalaTestSuite(BaseTestSuite):
       if encoding: result.data = [row.decode(encoding) for row in result.data]
       # Replace $NAMENODE in the expected results with the actual namenode URI.
       if 'RESULTS' in test_section:
+        # Combining 'RESULTS' with 'DML_RESULTS" is currently unsupported 
because
+        # __verify_results_and_errors calls verify_raw_results which always 
checks
+        # ERRORS, TYPES, LABELS, etc. which doesn't make sense if there are two
+        # different result sets to consider (IMPALA-4471).
+        assert 'DML_RESULTS' not in test_section
         self.__verify_results_and_errors(vector, test_section, result, use_db)
       else:
         # TODO: Can't validate errors without expected results for now.
@@ -350,6 +355,17 @@ class ImpalaTestSuite(BaseTestSuite):
             .replace('$IMPALA_HOME', IMPALA_HOME)
       if 'RUNTIME_PROFILE' in test_section:
         verify_runtime_profile(test_section['RUNTIME_PROFILE'], 
result.runtime_profile)
+
+      if 'DML_RESULTS' in test_section:
+        assert 'ERRORS' not in test_section
+        # The limit is specified to ensure the queries aren't unbounded. We 
shouldn't have
+        # test files that are checking the contents of tables larger than that 
anyways.
+        dml_results_query = "select * from %s limit 1000" % \
+            test_section['DML_RESULTS_TABLE']
+        dml_result = self.__execute_query(target_impalad_client, 
dml_results_query)
+        verify_raw_results(test_section, dml_result,
+            vector.get_value('table_format').file_format,
+            pytest.config.option.update_results, result_section='DML_RESULTS')
     if pytest.config.option.update_results:
       output_file = os.path.join('/tmp', test_file_name.replace('/','_') + 
".test")
       write_test_file(output_file, sections, encoding=encoding)

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3833707d/tests/common/test_result_verifier.py
----------------------------------------------------------------------
diff --git a/tests/common/test_result_verifier.py 
b/tests/common/test_result_verifier.py
index 80daf09..c7f890a 100644
--- a/tests/common/test_result_verifier.py
+++ b/tests/common/test_result_verifier.py
@@ -286,19 +286,25 @@ def apply_error_match_filter(error_list, 
replace_filenames=True):
   return [replace_fn(row) for row in error_list]
 
 def verify_raw_results(test_section, exec_result, file_format, 
update_section=False,
-                       replace_filenames=True):
+                       replace_filenames=True, result_section='RESULTS'):
   """
-  Accepts a raw exec_result object and verifies it matches the expected 
results.
+  Accepts a raw exec_result object and verifies it matches the expected 
results,
+  including checking the ERRORS, TYPES, and LABELS test sections.
   If update_section is true, updates test_section with the actual results
   if they don't match the expected results. If update_section is false, failed
   verifications result in assertion failures, otherwise they are ignored.
 
   This process includes the parsing/transformation of the raw data results 
into the
   result format used in the tests.
+
+  The result_section parameter can be used to make this function check the 
results in
+  a DML_RESULTS section instead of the regular RESULTS section.
+  TODO: separate out the handling of sections like ERRORS from checking of 
query results
+  to allow regular RESULTS/ERRORS sections in tests with DML_RESULTS 
(IMPALA-4471).
   """
   expected_results = None
-  if 'RESULTS' in test_section:
-    expected_results = remove_comments(test_section['RESULTS'])
+  if result_section in test_section:
+    expected_results = remove_comments(test_section[result_section])
   else:
     assert 'ERRORS' not in test_section, "'ERRORS' section must have 
accompanying 'RESULTS' section"
     LOG.info("No results found. Skipping verification");
@@ -398,7 +404,7 @@ def verify_raw_results(test_section, exec_result, 
file_format, update_section=Fa
     VERIFIER_MAP[verifier](expected, actual)
   except AssertionError:
     if update_section:
-      test_section['RESULTS'] = join_section_lines(actual.result_list)
+      test_section[results_section] = join_section_lines(actual.result_list)
     else:
       raise
 

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3833707d/tests/query_test/test_kudu.py
----------------------------------------------------------------------
diff --git a/tests/query_test/test_kudu.py b/tests/query_test/test_kudu.py
index f5579ed..908fc54 100644
--- a/tests/query_test/test_kudu.py
+++ b/tests/query_test/test_kudu.py
@@ -43,8 +43,17 @@ class TestKuduOperations(KuduTestSuite):
   def test_kudu_scan_node(self, vector, unique_database):
     self.run_test_case('QueryTest/kudu-scan-node', vector, 
use_db=unique_database)
 
-  def test_kudu_crud(self, vector, unique_database):
-    self.run_test_case('QueryTest/kudu_crud', vector, use_db=unique_database)
+  def test_kudu_insert(self, vector, unique_database):
+    self.run_test_case('QueryTest/kudu_insert', vector, use_db=unique_database)
+
+  def test_kudu_update(self, vector, unique_database):
+    self.run_test_case('QueryTest/kudu_update', vector, use_db=unique_database)
+
+  def test_kudu_upsert(self, vector, unique_database):
+    self.run_test_case('QueryTest/kudu_upsert', vector, use_db=unique_database)
+
+  def test_kudu_delete(self, vector, unique_database):
+    self.run_test_case('QueryTest/kudu_delete', vector, use_db=unique_database)
 
   def test_kudu_partition_ddl(self, vector, unique_database):
     self.run_test_case('QueryTest/kudu_partition_ddl', vector, 
use_db=unique_database)

http://git-wip-us.apache.org/repos/asf/incubator-impala/blob/3833707d/tests/util/test_file_parser.py
----------------------------------------------------------------------
diff --git a/tests/util/test_file_parser.py b/tests/util/test_file_parser.py
index d4eb55c..886d8b7 100644
--- a/tests/util/test_file_parser.py
+++ b/tests/util/test_file_parser.py
@@ -93,7 +93,7 @@ def parse_query_test_file(file_name, 
valid_section_names=None, encoding=None):
   section_names = valid_section_names
   if section_names is None:
     section_names = ['QUERY', 'RESULTS', 'TYPES', 'LABELS', 'SETUP', 'CATCH', 
'ERRORS',
-        'USER', 'RUNTIME_PROFILE', 'SHELL']
+        'USER', 'RUNTIME_PROFILE', 'SHELL', 'DML_RESULTS']
   return parse_test_file(file_name, section_names, encoding=encoding,
       skip_unknown_sections=False)
 
@@ -227,6 +227,19 @@ def parse_test_file_text(text, valid_section_names, 
skip_unknown_sections=True):
           raise RuntimeError, 'Unknown subsection comment: %s' % 
subsection_comment
         continue
 
+      # The DML_RESULTS section is used to specify what the state of the table 
should be
+      # after executing a DML query (in the QUERY section). The target table 
name must
+      # be specified in a table comment, and then the expected rows in the 
table are the
+      # contents of the section. If the TYPES and LABELS sections are 
provided, they
+      # will be verified against the DML_RESULTS. Using both DML_RESULTS and 
RESULTS is
+      # not supported.
+      if subsection_name == 'DML_RESULTS':
+        if subsection_comment is None or subsection_comment == '':
+          raise RuntimeError, 'DML_RESULTS requires that the table is 
specified ' \
+              'in the comment.'
+        parsed_sections['DML_RESULTS_TABLE'] = subsection_comment
+        parsed_sections['VERIFIER'] = 'VERIFY_IS_EQUAL_SORTED'
+
       parsed_sections[subsection_name] = subsection_str
 
     if parsed_sections:

Reply via email to