helper for wherex_to_rowlist. returns [SingleTableCond,...], [CartesianCond,...]

def classify_wherex(scope_, fromx, wherex):
  "helper for wherex_to_rowlist. returns [SingleTableCond,...], [CartesianCond,...]"
  exprs = []
  for exp in fromx:
    if isinstance(exp, sqparse2.JoinX):
      # todo: probably just add exp.on_stmt as a CartesianCond. don't write this until tests are ready.
      # todo: do join-on clauses get special scoping w.r.t. column names? check spec.
      raise NotImplementedError('join')
    elif isinstance(exp, basestring):
      exprs.append(exp)
  def test_and(exp):
    return isinstance(exp, sqparse2.BinX) and exp.op.op == 'and'
  def binx_splitter(exp):
    return [exp.left, exp.right]
  exprs += treepath.flatten_tree(test_and, binx_splitter, wherex) if wherex else [] # wherex is None if not given
  single_conds = []
  cartesian_conds = []
  for exp in exprs:
    if isinstance(exp, basestring):
      # note: bare table names need their own case because they don't work with resolve_column
      single_conds.append(SingleTableCond(exp, exp))
    else:
      tables = zip(*map(scope_.resolve_column, names_from_exp(exp)))[0]
      if len(tables) > 1:
        cartesian_conds.append(CartesianCond(exp))
      else:
        single_conds.append(SingleTableCond(tables[0], exp))
  return single_conds, cartesian_conds