# 9/23/2011 Generate blocking row lock tests
import datetime

# generate sql write queries
def mysqlgen_select_for_update(k, kv, c, cv):
    print "select * from t where %s=%s for update;" % (k, kv)
def mysqlgen_select_for_update_range(k, c, where):
    print "select * from t where %s%s for update;" % (k, where)
def mysqlgen_update(k, kv, c, cv):
    print "update t set %s=%s where %s=%s;" % (c, c, k, kv);
def mysqlgen_update_range(k, c, where):
    print "update t set %s=%s where %s%s;" % (c, c, k, where);
def mysqlgen_insert_ignore(k, kv, c, cv):
    print "insert ignore t values(%s, %s);" % (kv, cv)
def mysqlgen_insert_on_dup_update(k, kv, c, cv):
    print "insert t values(%s, %s) on duplicate key update %s=%s;" % (kv, cv, c, c)
def mysqlgen_replace(k, kv, c, cv):
    print "replace t values(%s, %s);" % (kv, cv)

# genrate sql read queries
def mysqlgen_select_star():
    print "select * from t;"
def mysqlgen_select_where(k, where):
    print "select * from t where %s%s;" % (k, where)

# mysql test code generation
def mysqlgen_prepare():
    print "# prepare with some common parameters"
    print "connect(conn1, localhost, root);"
    print "set session transaction isolation level serializable;"
    print "connect(conn2, localhost, root);"
    print "set session transaction isolation level serializable;"
    print "connection conn1;"
    print ""
def mysqlgen_reload_table():
    print "# drop old table, generate new one. 4 rows"
    print "--disable_warnings"
    print "drop table if exists t;"
    print "--enable_warnings"
    print "create table t (a int primary key, b int) engine=tokudb;"
    for i in range(1, 7):
        mysqlgen_insert_ignore("a", i, "b", i*i)
    print ""
def mysqlgen_cleanup():
    print "# clean it all up"
    print "drop table t;"
    print ""
write_point_queries = [
        ("select for update", mysqlgen_select_for_update),
        ("update", mysqlgen_update),
        ("insert", mysqlgen_insert_ignore),
        ("replace", mysqlgen_replace) ]
write_range_queries = [
        ("select for update", mysqlgen_select_for_update_range),
        ("update", mysqlgen_update_range) ]
timeouts = [0, 500]

# Here's where all the magic happens
print "# Tokutek"
print "# Blocking row lock tests;"
print "# Generated by %s on %s;" % (__file__, datetime.date.today())
print ""
mysqlgen_prepare()
mysqlgen_reload_table()
for timeout in timeouts:
    print "# testing with timeout %s" % timeout
    print "connection conn1;"
    print "set session tokudb_lock_timeout=%s;" % timeout
    print "connection conn2;"
    print "set session tokudb_lock_timeout=%s;" % timeout
    print ""
    print "# testing each point query vs each point query"
    for ta, qa in write_point_queries:
        # point vs point contention
        for tb, qb in write_point_queries:
            print "# testing conflict \"%s\" vs. \"%s\"" % (ta, tb)
            print "connection conn1;"
            print "begin;"
            print "# about to do qa.."
            qa("a", "1", "b", "100")
            print "connection conn2;"
            for k in range(1, 5):
                if k == 1:
                    print "--error ER_LOCK_WAIT_TIMEOUT"
                qb("a", k, "b", "100")
            # point write lock vs read query
            print "# make sure we can't read that row, but can read others."
            print "begin;"
            print "--error ER_LOCK_WAIT_TIMEOUT"
            mysqlgen_select_star()
            print "--error ER_LOCK_WAIT_TIMEOUT"
            mysqlgen_select_where("a", "=1")
            mysqlgen_select_where("a", ">=2")
            print "commit;"
            # Always check in the end that a commit
            # allows the other transaction full access
            print "connection conn1;"
            print "commit;"
            print "connection conn2;"
            qb("a", "1", "b", "100")
            print "begin;"
            mysqlgen_select_star()
            print "commit;"
            print "connection conn1;"
            print ""
            # test early commit
            if timeout > 0:
                print "# check that an early commit allows a blocked"
                print "# transaction to complete"
                print "connection conn1;"
                print "begin;"
                qa("a", "1", "b", "150")
                print "connection conn2;"
                # this makes the query asynchronous, so we can jump back
                # to the conn1 connection and commit it.
                print "send ",
                qb("a", "1", "b", "175")
                print "connection conn1;"
                print "commit;"
                print "connection conn2;"
                print "reap;"
       # point vs range contention
        for rt, rq in write_range_queries:
            print "# testing range query \"%s\" vs \"%s\"" % (rt, ta)
            print "connection conn1;"
            print "begin;"
            print ""
            qa("a", "1", "b", "100")
            print "connection conn2;"
            print "--error ER_LOCK_WAIT_TIMEOUT"
            rq("a", "b", "<=2")
            print "--error ER_LOCK_WAIT_TIMEOUT"
            rq("a", "b", ">=0")
            rq("a", "b", ">2")
            # write range lock vs read query
            print "# make sure we can't read that row, but can read others."
            print "begin;"
            print "--error ER_LOCK_WAIT_TIMEOUT"
            mysqlgen_select_star()
            print "--error ER_LOCK_WAIT_TIMEOUT"
            mysqlgen_select_where("a", "=1")
            mysqlgen_select_where("a", ">=2")
            print "commit;"
            # Always check in the end that a commit
            # allows the other transaction full access
            print "connection conn1;"
            print "commit;"
            print "connection conn2;"
            rq("a", "b", "<=2")
            rq("a", "b", ">=0")
            print "begin;"
            mysqlgen_select_star()
            print "commit;"
            print "connection conn1;"
            print ""
            # test early commit
            if timeout > 0:
                print "# check that an early commit allows a blocked"
                print "# transaction to complete"
                print "connection conn1;"
                print "begin;"
                qa("a", "1", "b", "150")
                print "connection conn2;"
                # this makes the query asynchronous, so we can jump back
                # to the conn1 connection and commit it.
                print "send ",
                rq("a", "b", "<=2")
                print "connection conn1;"
                print "commit;"
                print "connection conn2;"
                print "reap;"
    for rt, rq in write_range_queries:
        for rtb, rqb in write_range_queries:
            print "# testing range query \"%s\" vs range query \"%s\"" % (rt, rtb)
            print "connection conn1;"
            print "begin;"
            print ""
            rq("a", "b", ">=2 and a<=4")
            print "connection conn2;"
            print "--error ER_LOCK_WAIT_TIMEOUT"
            rqb("a", "b", ">=0 and a<=3")
            print "--error ER_LOCK_WAIT_TIMEOUT"
            rqb("a", "b", ">=3 and a<=6")
            print "--error ER_LOCK_WAIT_TIMEOUT"
            rqb("a", "b", "<=2")
            rqb("a", "b", ">=5")
            # point write lock vs read query
            print "# make sure we can't read that row, but can read others."
            print "begin;"
            print "--error ER_LOCK_WAIT_TIMEOUT"
            mysqlgen_select_star()
            print "--error ER_LOCK_WAIT_TIMEOUT"
            mysqlgen_select_where("a", "=2")
            print "--error ER_LOCK_WAIT_TIMEOUT"
            mysqlgen_select_where("a", ">=3 and a<=5")
            mysqlgen_select_where("a", ">=5")
            print "commit;"
            # Always check in the end that a commit
            # allows the other transaction full access
            print "connection conn1;"
            print "commit;"
            print "connection conn2;"
            rqb("a", "b", ">=0 and a<=3")
            rqb("a", "b", ">=3 and a<=6")
            rqb("a", "b", "<=2")
            print "begin;"
            mysqlgen_select_star()
            print "commit;"
            print "connection conn1;"
            print ""
            # test early commit
            if timeout > 0:
                print "# check that an early commit allows a blocked"
                print "# transaction to complete"
                print "connection conn1;"
                print "begin;"
                rq("a", "b", ">=2 and a<=4")
                print "connection conn2;"
                # this makes the query asynchronous, so we can jump back
                # to the conn1 connection and commit it.
                print "send ",
                rqb("a", "b", ">=0 and a<=3")
                print "connection conn1;"
                print "commit;"
                print "connection conn2;"
                print "reap;"
mysqlgen_cleanup()
