text: # -*- coding: utf-8 -*-
  
  from sqlalchemy import sql, create_engine
  from tabulator import exceptions
  from tabulator.parser import Parser
  
  
  class ExtendedSQLParser(Parser):
      """Parser to get data from SQL database.
      """
  
      # Public
  
      options = [
          'table',
          'order_by',
          'query'
      ]
  
      def __init__(self, loader, force_parse=False, table=None, order_by=None, query=None):
          if query is None and table is None:
              raise exceptions.TabulatorException('Format `sql` requires `table` or `query` options.')
  
          # Set attributes
          self.__loader = loader
          self.__table = table
          self.__order_by = order_by
          self.__query = query
          self.__force_parse = force_parse
          self.__engine = None
          self.__extended_rows = None
          self.__encoding = None
  
      @property
      def closed(self):
          return self.__engine is None
  
      def open(self, source, encoding=None):
          self.close()
          self.__engine = create_engine(source)
          self.__engine.update_execution_options(stream_results=True)
          self.__encoding = encoding
          self.reset()
  
      def close(self):
          if not self.closed:
              self.__engine.dispose()
              self.__engine = None
  
      def reset(self):
          self.__extended_rows = self.__iter_extended_rows()
  
      @property
      def encoding(self):
          return self.__encoding
  
      @property
      def extended_rows(self):
          return self.__extended_rows
  
      # Private
      def __iter_extended_rows(self):
          if self.__query is not None:
              query = self.__query
          else:
              table = sql.table(self.__table)
              order = sql.text(self.__order_by) if self.__order_by else None
              query = sql.select(['*']).select_from(table).order_by(order)
          result = self.__engine.execute(query)
          for row_number, row in enumerate(iter(result), start=1):
              yield (row_number, list(row.keys()), list(row))
  