docs: def _alias_columns(self, sql):
          """Return tuple of SELECT and FROM clauses, aliasing duplicate column names."""
          qn = self.connection.ops.quote_name
  
          outer = list()
          inner = list()
          names_seen = list()
  
          # replace all parens with placeholders
          paren_depth, paren_buf = 0, ['']
          parens, i = {}, 0
          for ch in sql:
              if ch == '(':
                  i += 1
                  paren_depth += 1
                  paren_buf.append('')
              elif ch == ')':
                  paren_depth -= 1
                  key = '_placeholder_{0}'.format(i)
                  buf = paren_buf.pop()
  
                  # store the expanded paren string
                  buf = re.sub(r'%([^\(])', r'$$$\1', buf)
                  parens[key] = buf% parens
                  parens[key] = re.sub(r'\$\$\$([^\(])', r'%\1', parens[key])
                  #cannot use {} because IBM's DB2 uses {} as quotes
                  paren_buf[paren_depth] += '(%(' + key + ')s)'
              else:
                  paren_buf[paren_depth] += ch
  
          def _replace_sub(col):
              """Replace all placeholders with expanded values"""
              while _re_col_placeholder.search(col):
                  col = col.format(**parens)
              return col
  
          temp_sql = ''.join(paren_buf)
  
          # replace any bare %s with placeholders.  Needed when the WHERE
          # clause only contains one condition, and isn't wrapped in parens.
          # the placeholder_data is used to prevent the variable "i" from
          # being interpreted as a local variable in the replacement function
          placeholder_data = { "i": i }
          def _alias_placeholders(val):
              i = placeholder_data["i"]
              i += 1
              placeholder_data["i"] = i
              key = "_placeholder_{0}".format(i)
              parens[key] = "%s"
              return "%(" + key + ")s"
  
          temp_sql = re.sub("%s", _alias_placeholders, temp_sql)
  
          select_list, from_clause = _break(temp_sql, ' FROM ' + self.connection.ops.left_sql_quote)
  
          for col in [x.strip() for x in select_list.split(',')]:
              match = self._re_pat_col.search(col)
              if match:
                  col_name = match.group(1)
                  col_key = col_name.lower()
  
                  if col_key in names_seen:
                      alias = qn('{0}___{1}'.format(col_name, names_seen.count(col_key)))
                      outer.append(alias)
                      inner.append('{0} as {1}'.format(_replace_sub(col), alias))
                  else:
                      outer.append(qn(col_name))
                      inner.append(_replace_sub(col))
  
                  names_seen.append(col_key)
              else:
                  raise Exception('Unable to find a column name when parsing SQL: {0}'.format(col))
  
          return ', '.join(outer), ', '.join(inner) + (from_clause % parens)