Testing Database Engines via Pivoted Query Synthesis

87
Testing Database Engines via Pivoted Query Synthesis Manuel Rigger Zhendong Su ETH Zurich, Switzerland 11/05/2020 @RiggerManuel @ast_eth https://people.inf.ethz.ch/suz/

Transcript of Testing Database Engines via Pivoted Query Synthesis

Page 1: Testing Database Engines via Pivoted Query Synthesis

Testing Database Engines via Pivoted Query Synthesis

Manuel Rigger Zhendong Su

ETH Zurich, Switzerland

11/05/2020

@RiggerManuel @ast_eth https://people.inf.ethz.ch/suz/

Page 2: Testing Database Engines via Pivoted Query Synthesis

2

Database Management Systems (DBMSs)

PostgreSQL

Page 3: Testing Database Engines via Pivoted Query Synthesis

3

Database Management Systems (DBMSs)

PostgreSQL

“it is seems likely that there are over one trillion (1e12) SQLite databases in active use”

https://www.sqlite.org/mostdeployed.html

Page 4: Testing Database Engines via Pivoted Query Synthesis

4

Database Management Systems (DBMSs)

PostgreSQL

We found 96 unique bugs in these DBMSs, 78 of which were fixed!

Page 5: Testing Database Engines via Pivoted Query Synthesis

5

Goal: Find Logic Bugs

Logic bugs: DBMS returns an incorrect result set

Page 6: Testing Database Engines via Pivoted Query Synthesis

6

Example: SQLite3 Bug

c0

0

1

2

NULL

t0CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

https://sqlite.org/src/tktview/80256748471a01

Page 7: Testing Database Engines via Pivoted Query Synthesis

7

Example: SQLite3 Bug

c0

0

1

2

NULL

t0CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

IS NOT is a “null-safe” comparison operator

https://sqlite.org/src/tktview/80256748471a01

Page 8: Testing Database Engines via Pivoted Query Synthesis

8

Example: SQLite3 Bug

c0

0

1

2

NULL

t0CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

https://sqlite.org/src/tktview/80256748471a01

Page 9: Testing Database Engines via Pivoted Query Synthesis

9

Example: SQLite3 Bug

c0

0

1

2

NULL

t0

0

CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

TRUE

https://sqlite.org/src/tktview/80256748471a01

Page 10: Testing Database Engines via Pivoted Query Synthesis

10

Example: SQLite3 Bug

c0

0

1

2

NULL

t0

0

CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

TRUE

0

https://sqlite.org/src/tktview/80256748471a01

Page 11: Testing Database Engines via Pivoted Query Synthesis

11

Example: SQLite3 Bug

c0

0

1

2

NULL

t0

1

CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

0

FALSE

https://sqlite.org/src/tktview/80256748471a01

Page 12: Testing Database Engines via Pivoted Query Synthesis

12

Example: SQLite3 Bug

c0

0

1

2

NULL

t0

0

2

2

CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

TRUE

https://sqlite.org/src/tktview/80256748471a01

Page 13: Testing Database Engines via Pivoted Query Synthesis

13

Example: SQLite3 Bug

c0

0

1

2

NULL

t0

0

2

NULL

NULL

CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

TRUE

https://sqlite.org/src/tktview/80256748471a01

Page 14: Testing Database Engines via Pivoted Query Synthesis

14

Example: SQLite3 Bug

c0

0

1

2

NULL

t0

NULL

CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

TRUE

0

2

NULLhttps://sqlite.org/src/tktview/80256748471a01

Page 15: Testing Database Engines via Pivoted Query Synthesis

15

Example: SQLite3 Bug

c0

0

1

2

NULL

t0

NULL

CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

TRUE

0

2

NULL

0

2

https://sqlite.org/src/tktview/80256748471a01

Page 16: Testing Database Engines via Pivoted Query Synthesis

16

Example: SQLite3 Bug

c0

0

1

2

NULL

t0

NULL

CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

TRUE

NULL was not contained

in the result set!

0

2

NULL

0

2

https://sqlite.org/src/tktview/80256748471a01

Page 17: Testing Database Engines via Pivoted Query Synthesis

17

Background: Differential Testing

PostgreSQL

SELECT c0 FROM t0WHERE t0.c0 IS NOT 1;

Massive Stochastic Testing of SQL by Slutz, 1998.

Page 18: Testing Database Engines via Pivoted Query Synthesis

18

Background: Differential Testing

PostgreSQL

RS1

RS2

RS3

SELECT c0 FROM t0WHERE t0.c0 IS NOT 1;

Massive Stochastic Testing of SQL by Slutz, 1998.

Page 19: Testing Database Engines via Pivoted Query Synthesis

19

Background: Differential Testing

PostgreSQL

RS1

RS2

RS3

SELECT c0 FROM t0WHERE t0.c0 IS NOT 1;

Check that all DBMSs compute the same result (RS1 = RS2 = RS3)

Massive Stochastic Testing of SQL by Slutz, 1998.

Page 20: Testing Database Engines via Pivoted Query Synthesis

20

Background: Differential Testing

PostgreSQL

RS1

RS2

RS3

Page 21: Testing Database Engines via Pivoted Query Synthesis

21

Background: Differential Testing

PostgreSQL

RS1

RS2

RS3

Page 22: Testing Database Engines via Pivoted Query Synthesis

22

Background: Differential Testing

{0, 2}

Syntax error

Syntax error

PostgreSQL

Page 23: Testing Database Engines via Pivoted Query Synthesis

23

Background: Differential Testing

CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (3), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

Page 24: Testing Database Engines via Pivoted Query Synthesis

24

Background: Differential Testing

CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (3), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

MySQL and PostgreSQL require a data type definition

Page 25: Testing Database Engines via Pivoted Query Synthesis

25

Background: Differential Testing

CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (3), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

PostgreSQL provides an IS DISTINCT FROM operator, and MySQL a <=> null-safe comparison operator

Page 26: Testing Database Engines via Pivoted Query Synthesis

26

Idea: PQS

Pivoted Query Synthesis (PQS): Divide-and-conquer approach for testing DBMSs

Page 27: Testing Database Engines via Pivoted Query Synthesis

27

PQS Idea

c0

0

1

2

NULL

t0CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (3), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

Validate the result set based on one randomly-selected row

Page 28: Testing Database Engines via Pivoted Query Synthesis

28

PQS Idea

c0

0

1

2

NULL

t0CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (3), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

Pivot rowValidate the result set based on

one randomly-selected row

Page 29: Testing Database Engines via Pivoted Query Synthesis

29

PQS Idea

c0

0

1

2

NULL

t0CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (3), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

Generate a query that is guaranteed to at least fetch

the pivot row

NULL

TRUE

Page 30: Testing Database Engines via Pivoted Query Synthesis

30

PQS Idea

c0

0

1

2

NULL

t0CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (3), (NULL);SELECT c0 FROM t0 WHERE t0.c0 IS NOT 1;

If the pivot row is missing from the result set a bug has

been detected

0

2

Page 31: Testing Database Engines via Pivoted Query Synthesis

31

Approach

Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

Page 32: Testing Database Engines via Pivoted Query Synthesis

32

Approach

Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

CREATE TABLE t0(c0);CREATE INDEX i0 ON t0(1) WHERE c0 NOT NULL;INSERT INTO t0 (c0) VALUES (0), (1), (2), (3), (NULL);

Statements are heuristically generated based on the DBMS’ SQL dialect

Page 33: Testing Database Engines via Pivoted Query Synthesis

33

Approach

Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

One random row from multiple tables and views

Page 34: Testing Database Engines via Pivoted Query Synthesis

34

Approach

Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

Generate predicates that evaluate to TRUE for the pivot row and use them

in JOIN and WHERE clauses

SELECT c0 FROM t0WHERE

Page 35: Testing Database Engines via Pivoted Query Synthesis

35

Random Expression Generation

t0.c0 IS NOT 1;

Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

ISNOT

t0.c0 1

Page 36: Testing Database Engines via Pivoted Query Synthesis

36

Random Expression Generation

t0.c0 IS NOT 1;

We implemented an expression evaluator for

each node

Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

ISNOT

t0.c0 1

Page 37: Testing Database Engines via Pivoted Query Synthesis

37

Random Expression Generation

c0

0

1

2

NULL

t0

Evaluate the tree based on the pivot row

Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

ISNOT

t0.c0 1

Page 38: Testing Database Engines via Pivoted Query Synthesis

38

Random Expression Generation

Column references return the values from the pivot row

c0

0

1

2

NULL

t0Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

ISNOT

t0.c0 1

Page 39: Testing Database Engines via Pivoted Query Synthesis

39

Random Expression Generation

Column references return the values from the pivot row

c0

0

1

2

NULL

t0Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

ISNOT

t0.c0 1

NULL

Page 40: Testing Database Engines via Pivoted Query Synthesis

40

Random Expression Generation

Constant nodes return their assigned literal values

c0

0

1

2

NULL

t0Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

ISNOT

t0.c0 1

NULL

Page 41: Testing Database Engines via Pivoted Query Synthesis

41

Random Expression Generation

Constant nodes return their assigned literal values

c0

0

1

2

NULL

t0Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

ISNOT

t0.c0 1

NULL 1

Page 42: Testing Database Engines via Pivoted Query Synthesis

42

Random Expression Generation

Compound nodes compute their result

based on their children

TRUE

c0

0

1

2

NULL

t0Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

ISNOT

t0.c0 1

NULL 1

Page 43: Testing Database Engines via Pivoted Query Synthesis

43

Random Expression Generation

Compound nodes compute their result

based on their children

TRUE

c0

0

1

2

NULL

t0Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

ISNOT

t0.c0 1

NULL 1

TRUE

Page 44: Testing Database Engines via Pivoted Query Synthesis

44

t0.c0 IS NOT 1;

Query Synthesis

SELECT c0 c0 FROM t0WHERE

Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

Page 45: Testing Database Engines via Pivoted Query Synthesis

45

t0.c0 IS NOT 1;

Query Synthesis

SELECT c0 c0 FROM t0WHERE

What if the expression does not evaluate to TRUE?

Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

Page 46: Testing Database Engines via Pivoted Query Synthesis

46

Random Expression Rectification

switch (result) {case TRUE:

result = randexpr;case FALSE:

result = NOT randexpr;case NULL:

result = randexpr IS NULL;}

Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

Page 47: Testing Database Engines via Pivoted Query Synthesis

47

Random Expression Rectification

switch (result) {case TRUE:

result = randexpr;case FALSE:

result = NOT randexpr;case NULL:

result = randexpr IS NULL;}

Alternatively, we could validate that the pivot row is

expectedly not fetched

Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

Page 48: Testing Database Engines via Pivoted Query Synthesis

48

Random Expression Rectification

Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

• DISTINCT clauses

• ORDER BY clauses

• DBMS-specific clauses (e.g., FOR UPDATE)

Page 49: Testing Database Engines via Pivoted Query Synthesis

49

Approach

SELECT (NULL) INTERSECTSELECT c0 FROM t0 WHERE NULL IS NOT 1;

Rely on the DBMS to check whether the row is contained

Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

Page 50: Testing Database Engines via Pivoted Query Synthesis

50

Approach

Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

Page 51: Testing Database Engines via Pivoted Query Synthesis

51

Approach

Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

Page 52: Testing Database Engines via Pivoted Query Synthesis

52

Approach

Randomly generate database

Selectpivot row

Generate query for the

pivot row

Validate that the pivot row is contained

We generate 100,000 queries for each generated database

Page 53: Testing Database Engines via Pivoted Query Synthesis

53

Implementation

https://github.com/sqlancer

Page 54: Testing Database Engines via Pivoted Query Synthesis

54

Bugs Overview

DBMS Fixed Verified

SQLite 64 0

MySQL 17 7

PostgreSQL 5 3

Page 55: Testing Database Engines via Pivoted Query Synthesis

55

Bugs Overview

DBMS Fixed Verified

SQLite 64 0

MySQL 17 7

PostgreSQL 5 3

96 bugs were unique, previously unknown ones

Page 56: Testing Database Engines via Pivoted Query Synthesis

56

Bugs Overview

The SQLite developers quickly responded to all our bug reports → we focused on this DBMS

DBMS Fixed Verified

SQLite 64 0

MySQL 17 7

PostgreSQL 5 3

Page 57: Testing Database Engines via Pivoted Query Synthesis

57

Oracles

DBMS Logic Error Crash

SQLite 46 17 2

MySQL 14 10 1

PostgreSQL 1 7 1

61 were logic bugs

Page 58: Testing Database Engines via Pivoted Query Synthesis

58

Example: SQLite

CREATE TABLE t1(c1, c2, c3, c4, PRIMARY KEY (c4, c3));INSERT INTO t1(c3) VALUES (0), (0), (0), (0), (0), (0),

(0), (0), (0), (0), (NULL), (1), (0);UPDATE t1 SET c2 = 0;INSERT INTO t1(c1) VALUES (0), (0), (NULL), (0), (0);ANALYZE t1;UPDATE t1 SET c3 = 1;SELECT DISTINCT * FROM t1 WHERE t1.c3 = 1;

https://www.sqlite.org/src/tktview?name=ced41c7c7d

Page 59: Testing Database Engines via Pivoted Query Synthesis

59

Example: SQLite

CREATE TABLE t1(c1, c2, c3, c4, PRIMARY KEY (c4, c3));INSERT INTO t1(c3) VALUES (0), (0), (0), (0), (0), (0),

(0), (0), (0), (0), (NULL), (1), (0);UPDATE t1 SET c2 = 0;INSERT INTO t1(c1) VALUES (0), (0), (NULL), (0), (0);ANALYZE t1;UPDATE t1 SET c3 = 1;SELECT DISTINCT * FROM t1 WHERE t1.c3 = 1;

ANALYZE gathers statistics about tables, which are then used for query planning

https://www.sqlite.org/src/tktview?name=ced41c7c7d

Page 60: Testing Database Engines via Pivoted Query Synthesis

60

Example: SQLite

CREATE TABLE t1(c1, c2, c3, c4, PRIMARY KEY (c4, c3));INSERT INTO t1(c3) VALUES (0), (0), (0), (0), (0), (0),

(0), (0), (0), (0), (NULL), (1), (0);UPDATE t1 SET c2 = 0;INSERT INTO t1(c1) VALUES (0), (0), (NULL), (0), (0);ANALYZE t1;UPDATE t1 SET c3 = 1;SELECT DISTINCT * FROM t1 WHERE t1.c3 = 1;

NULL 0 1 NULL

https://www.sqlite.org/src/tktview?name=ced41c7c7d

Page 61: Testing Database Engines via Pivoted Query Synthesis

61

Example: SQLite

CREATE TABLE t1(c1, c2, c3, c4, PRIMARY KEY (c4, c3));INSERT INTO t1(c3) VALUES (0), (0), (0), (0), (0), (0),

(0), (0), (0), (0), (NULL), (1), (0);UPDATE t1 SET c2 = 0;INSERT INTO t1(c1) VALUES (0), (0), (NULL), (0), (0);ANALYZE t1;UPDATE t1 SET c3 = 1;SELECT DISTINCT * FROM t1 WHERE t1.c3 = 1;

NULL 0 1 NULL

A bug in the skip-scan optimization caused

this logic bug

https://www.sqlite.org/src/tktview?name=ced41c7c7d

Page 62: Testing Database Engines via Pivoted Query Synthesis

62

Example: SQLite

CREATE TABLE t1(c1, c2, c3, c4, PRIMARY KEY (c4, c3));INSERT INTO t1(c3) VALUES (0), (0), (0), (0), (0), (0),

(0), (0), (0), (0), (NULL), (1), (0);UPDATE t1 SET c2 = 0;INSERT INTO t1(c1) VALUES (0), (0), (NULL), (0), (0);ANALYZE t1;UPDATE t1 SET c3 = 1;SELECT DISTINCT * FROM t1 WHERE t1.c3 = 1;

NULL 0 1 NULL

0 NULL 1 NULL

NULL NULL 1 NULL

https://www.sqlite.org/src/tktview?name=ced41c7c7d

Page 63: Testing Database Engines via Pivoted Query Synthesis

63

Example: SQLite

CREATE TABLE t1(c1, c2, c3, c4, PRIMARY KEY (c4, c3));INSERT INTO t1(c3) VALUES (0), (0), (0), (0), (0), (0),

(0), (0), (0), (0), (NULL), (1), (0);UPDATE t1 SET c2 = 0;INSERT INTO t1(c1) VALUES (0), (0), (NULL), (0), (0);ANALYZE t1;UPDATE t1 SET c3 = 1;SELECT DISTINCT * FROM t1 WHERE t1.c3 = 1;

NULL 0 1 NULL

0 NULL 1 NULL

NULL NULL 1 NULL

https://www.sqlite.org/src/tktview?name=ced41c7c7d

The bug was classified as “Severe” and quickly fixed

Page 64: Testing Database Engines via Pivoted Query Synthesis

64

Result: Bug in PostgreSQL

CREATE TABLE t0(c0 INT PRIMARY KEY, c1 INT);CREATE TABLE t1(c0 INT) INHERITS (t0);INSERT INTO t0(c0, c1) VALUES(0, 0);

c0 c1

0 0

c0 c1

t0

t1

https://www.postgresql.org/message-id/CA%2Bu7OA7VLKf_vEr6kLF3MnWSA9LToJYncgpNX2tQ-oWzYCBQAw%40mail.gmail.com

Page 65: Testing Database Engines via Pivoted Query Synthesis

65

Result: Bug in PostgreSQL

CREATE TABLE t0(c0 INT PRIMARY KEY, c1 INT);CREATE TABLE t1(c0 INT) INHERITS (t0);INSERT INTO t0(c0, c1) VALUES(0, 0);INSERT INTO t1(c0, c1) VALUES(0, 1);

c0 c1

0 0

0 1

c0 c1

0 1

t0

t1

https://www.postgresql.org/message-id/CA%2Bu7OA7VLKf_vEr6kLF3MnWSA9LToJYncgpNX2tQ-oWzYCBQAw%40mail.gmail.com

Page 66: Testing Database Engines via Pivoted Query Synthesis

66

Result: Bug in PostgreSQL

CREATE TABLE t0(c0 INT PRIMARY KEY, c1 INT);CREATE TABLE t1(c0 INT) INHERITS (t0);INSERT INTO t0(c0, c1) VALUES(0, 0);INSERT INTO t1(c0, c1) VALUES(0, 1);

c0 c1

0 0

0 1

c0 c1

0 1

t0

t1The inheritance relationship

causes the row to be insertedboth in t0 and t1

https://www.postgresql.org/message-id/CA%2Bu7OA7VLKf_vEr6kLF3MnWSA9LToJYncgpNX2tQ-oWzYCBQAw%40mail.gmail.com

Page 67: Testing Database Engines via Pivoted Query Synthesis

67

Result: Bug in PostgreSQL

CREATE TABLE t0(c0 INT PRIMARY KEY, c1 INT);CREATE TABLE t1(c0 INT) INHERITS (t0);INSERT INTO t0(c0, c1) VALUES(0, 0);INSERT INTO t1(c0, c1) VALUES(0, 1);

c0 c1

0 0

0 1

c0 c1

0 1

t0

t1

SELECT c0, c1 FROM t0 GROUP BY c0, c1;

0 0

https://www.postgresql.org/message-id/CA%2Bu7OA7VLKf_vEr6kLF3MnWSA9LToJYncgpNX2tQ-oWzYCBQAw%40mail.gmail.com

Page 68: Testing Database Engines via Pivoted Query Synthesis

68

Result: Bug in PostgreSQL

CREATE TABLE t0(c0 INT PRIMARY KEY, c1 INT);CREATE TABLE t1(c0 INT) INHERITS (t0);INSERT INTO t0(c0, c1) VALUES(0, 0);INSERT INTO t1(c0, c1) VALUES(0, 1);

c0 c1

0 0

0 1

c0 c1

0 1

t0

t1

SELECT c0, c1 FROM t0 GROUP BY c0, c1;

0 0An optimization incorrectly

simplified the GROUP BY clause

https://www.postgresql.org/message-id/CA%2Bu7OA7VLKf_vEr6kLF3MnWSA9LToJYncgpNX2tQ-oWzYCBQAw%40mail.gmail.com

Page 69: Testing Database Engines via Pivoted Query Synthesis

69

Result: Bug in PostgreSQL

CREATE TABLE t0(c0 INT PRIMARY KEY, c1 INT);CREATE TABLE t1(c0 INT) INHERITS (t0);INSERT INTO t0(c0, c1) VALUES(0, 0);INSERT INTO t1(c0, c1) VALUES(0, 1);

c0 c1

0 0

0 1

c0 c1

0 1

t0

t1

SELECT c0, c1 FROM t0 GROUP BY c0, c1;

0 0

0 1✓

https://www.postgresql.org/message-id/CA%2Bu7OA7VLKf_vEr6kLF3MnWSA9LToJYncgpNX2tQ-oWzYCBQAw%40mail.gmail.com

Page 70: Testing Database Engines via Pivoted Query Synthesis

70

Result: Bug in MySQL

c0

1

t0CREATE TABLE t0(c0 INT);INSERT INTO t0(c0) VALUES (1);SELECT * FROM t0 WHERE 123 != (NOT (NOT 123));

{}

https://bugs.mysql.com/bug.php?id=95900

Page 71: Testing Database Engines via Pivoted Query Synthesis

71

Result: Bug in MySQL

c0

1

t0CREATE TABLE t0(c0 INT);INSERT INTO t0(c0) VALUES (1);SELECT * FROM t0 WHERE 123 != (NOT (NOT 123));

{} The double negation cannot

be removed due to MySQL’s flexible type system

https://bugs.mysql.com/bug.php?id=95900

Page 72: Testing Database Engines via Pivoted Query Synthesis

72

Result: Bug in MySQL

c0

1

t0CREATE TABLE t0(c0 INT);INSERT INTO t0(c0) VALUES (1);SELECT * FROM t0 WHERE 123 != (NOT (NOT 123));

0

https://bugs.mysql.com/bug.php?id=95900

Page 73: Testing Database Engines via Pivoted Query Synthesis

73

Oracles

DBMS Logic Error Crash

SQLite 46 17 2

MySQL 14 10 1

PostgreSQL 1 7 1

Error bugs are due to unexpected (internal) errors

Page 74: Testing Database Engines via Pivoted Query Synthesis

74

Example: SQLite3 Bug

CREATE TABLE t0(c0, c1 REAL PRIMARY KEY);INSERT INTO t0(c0, c1) VALUES(TRUE, 9223372036854775807), (TRUE, 0);UPDATE t0 SET c0 = NULL;UPDATE OR REPLACE t0 SET c1 = 1;SELECT DISTINCT * FROM t0 WHERE (t0.c0 IS NULL);

Database disk image is malformed

Page 75: Testing Database Engines via Pivoted Query Synthesis

75

Discussion: Implementation Effort

• Literal evaluator• Simpler than PL AST Interpreters → No mutable state

• Simpler than query engines → only a single row needs to be considered

Page 76: Testing Database Engines via Pivoted Query Synthesis

76

Discussion: Implementation Effort

• Literal evaluator• Simpler than PL AST Interpreters → No mutable state

• Simpler than query engines → only a single row needs to be considered

• Operators are implemented naively• The performance of the DBMS is the bottleneck

Page 77: Testing Database Engines via Pivoted Query Synthesis

77

Discussion: Implementation Effort

• Literal evaluator• Simpler than PL AST Interpreters → No mutable state

• Simpler than query engines → only a single row needs to be considered

• Operators are implemented naively• The performance of the DBMS is the bottleneck

• Higher implementation effort for functions (e.g. printf) and complex operators

Page 78: Testing Database Engines via Pivoted Query Synthesis

78

Discussion: Limitations

• Requires understanding of the SQL semantics

• Aggregate and window functions

• Ordering

• Duplicate rows

Page 79: Testing Database Engines via Pivoted Query Synthesis

79

Discussion: Bug Importance

https://www.mail-archive.com/[email protected]/msg117440.html

CREATE TABLE t0 (c0);CREATE TABLE t1 (c1);INSERT INTO t0 VALUES (1);SELECT c0 FROM t0 LEFT JOIN t1 ON c1=c0 WHERE NOT (c1 IS NOT NULL AND c1=2);

Page 80: Testing Database Engines via Pivoted Query Synthesis

80

Discussion: Bug Importance

This is a cut-down example, right ? You can't possibly mean to do that WHERE clause in production code.

https://www.mail-archive.com/[email protected]/msg117440.html

CREATE TABLE t0 (c0);CREATE TABLE t1 (c1);INSERT INTO t0 VALUES (1);SELECT c0 FROM t0 LEFT JOIN t1 ON c1=c0 WHERE NOT (c1 IS NOT NULL AND c1=2);

Page 81: Testing Database Engines via Pivoted Query Synthesis

81

Discussion: Bug Importance

I might not spell it like that myself, but a code generator would do it (and much worse!). This example was simplified from a query generated by a Django ORM queryset using .exclude(nullable_joined_table__column=1), for instance.

This is a cut-down example, right ? You can't possibly mean to do that WHERE clause in production code.

https://www.mail-archive.com/[email protected]/msg117440.html

CREATE TABLE t0 (c0);CREATE TABLE t1 (c1);INSERT INTO t0 VALUES (1);SELECT c0 FROM t0 LEFT JOIN t1 ON c1=c0 WHERE NOT (c1 IS NOT NULL AND c1=2);

Page 82: Testing Database Engines via Pivoted Query Synthesis

82

Discussion: Bug Importance

I might not spell it like that myself, but a code generator would do it (and much worse!). This example was simplified from a query generated by a Django ORM queryset using .exclude(nullable_joined_table__column=1), for instance.

This is a cut-down example, right ? You can't possibly mean to do that WHERE clause in production code.

https://www.mail-archive.com/[email protected]/msg117440.html

Even “obscure” bugs might affect users

CREATE TABLE t0 (c0);CREATE TABLE t1 (c1);INSERT INTO t0 VALUES (1);SELECT c0 FROM t0 LEFT JOIN t1 ON c1=c0 WHERE NOT (c1 IS NOT NULL AND c1=2);

Page 83: Testing Database Engines via Pivoted Query Synthesis

83

Overview

Pivoted Query Synthesis (PQS)

Non-optimizing Reference Engine

Construction (NoREC)

Ternary LogicQuery Partitioning

(TLP)

Page 84: Testing Database Engines via Pivoted Query Synthesis

84

Overview

Pivoted Query Synthesis (PQS)

Non-optimizing Reference Engine

Construction (NoREC)

Ternary LogicQuery Partitioning

(TLP)

Detecting optimization bugs by rewriting the query so that it cannot be optimized

>150 bugs

Page 85: Testing Database Engines via Pivoted Query Synthesis

85

Overview

Pivoted Query Synthesis (PQS)

Non-optimizing Reference Engine

Construction (NoREC)

Ternary LogicQuery Partitioning

(TLP)

Partition the query into several partitioning

queries, which is applicable to test various features

>150 bugs

Page 86: Testing Database Engines via Pivoted Query Synthesis

86

SQLancer: Supported DBMSs

PostgreSQL

Page 87: Testing Database Engines via Pivoted Query Synthesis

87

@RiggerManuel [email protected] SummaryGoal: Detect logic bugs PQS randomly selects a pivot row

Rectify a random expression Evaluation: Close to 100 bugs in DBMSs