docs: def get_query_columns(query):
      """
      :type query str
      :rtype: list[str]
      """
      columns = []
      last_keyword = None
      last_token = None
  
      # print(preprocess_query(query))
  
      # these keywords should not change the state of a parser
      # and not "reset" previously found SELECT keyword
      keywords_ignored = ['AS', 'AND', 'OR', 'IN', 'IS', 'NOT', 'NOT NULL', 'LIKE', 'CASE', 'WHEN']
  
      # these function should be ignored
      # and not "reset" previously found SELECT keyword
      functions_ignored = ['COUNT', 'MIN', 'MAX', 'FROM_UNIXTIME', 'DATE_FORMAT', 'CAST', 'CONVERT']
  
      for token in get_query_tokens(query):
          if token.is_keyword and token.value.upper() not in keywords_ignored:
              # keep the name of the last keyword, e.g. SELECT, FROM, WHERE, (ORDER) BY
              last_keyword = token.value.upper()
              # print('keyword', last_keyword)
          elif token.ttype is Name:
              # analyze the name tokens, column names and where condition values
              if last_keyword in ['SELECT', 'WHERE', 'BY', 'ON'] \
                      and last_token.value.upper() not in ['AS']:
                  # print(last_keyword, last_token, token.value)
  
                  if token.value.upper() not in functions_ignored:
                      if str(last_token) == '.':
                          # print('DOT', last_token, columns[-1])
  
                          # we have table.column notation example
                          # append column name to the last entry of columns
                          # as it is a table name in fact
                          table_name = columns[-1]
                          columns[-1] = '{}.{}'.format(table_name, token)
                      else:
                          columns.append(str(token.value))
              elif last_keyword in ['INTO'] and last_token.ttype is Punctuation:
                  # INSERT INTO `foo` (col1, `col2`) VALUES (..)
                  #  print(last_keyword, token, last_token)
                  columns.append(str(token.value).strip('`'))
          elif token.ttype is Wildcard:
              # handle * wildcard in SELECT part, but ignore count(*)
              # print(last_keyword, last_token, token.value)
              if last_keyword == 'SELECT' and last_token.value != '(':
  
                  if str(last_token) == '.':
                      # handle SELECT foo.*
                      table_name = columns[-1]
                      columns[-1] = '{}.{}'.format(table_name, str(token))
                  else:
                      columns.append(str(token.value))
  
          last_token = token
  
      return unique(columns)