call the stmt in tree with values subbed on the tables in t_d.
    ex is a parsed statement returned by parse_expression.
    values is the tuple of %s replacements.
    lockref can be anything as long as it stays the same; it's used for assigning tranaction ownership.
      (safest is to make it a pgmock_dbapi2.Connection, because that will rollback on close)

def apply_sql(self, ex, values, lockref):
    """call the stmt in tree with values subbed on the tables in t_d.
    ex is a parsed statement returned by parse_expression.
    values is the tuple of %s replacements.
    lockref can be anything as long as it stays the same; it's used for assigning tranaction ownership.
      (safest is to make it a pgmock_dbapi2.Connection, because that will rollback on close)
    """
    sqex.depth_first_sub(ex,values)
    with self.lock_db(lockref, isinstance(ex,sqparse2.StartX)):
      sqex.replace_subqueries(ex,self,table.Table)
      if isinstance(ex,sqparse2.SelectX): return sqex.run_select(ex,self,table.Table)
      elif isinstance(ex,sqparse2.InsertX): return self[ex.table].insert(ex.cols,ex.values,ex.ret,self)
      elif isinstance(ex,sqparse2.UpdateX):
        if len(ex.tables)!=1: raise NotImplementedError('multi-table update')
        return self[ex.tables[0]].update(ex.assigns,ex.where,ex.ret,self)
      elif isinstance(ex,sqparse2.CreateX): self.create(ex)
      elif isinstance(ex,sqparse2.IndexX): pass
      elif isinstance(ex,sqparse2.DeleteX): return self[ex.table].delete(ex.where,self)
      elif isinstance(ex,sqparse2.StartX): self.trans_start(lockref)
      elif isinstance(ex,sqparse2.CommitX): self.trans_commit()
      elif isinstance(ex,sqparse2.RollbackX): self.trans_rollback()
      elif isinstance(ex,sqparse2.DropX): self.drop(ex)
      else: raise TypeError(type(ex))