docs: def sql(self,SQL,parameters=None,asrecarray=True,cache=True):
          """Execute sql statement.
  
          :Arguments:
             SQL : string
                Full SQL command; can contain the ``?`` place holder so that values
                supplied with the ``parameters`` keyword can be interpolated using
                the ``pysqlite`` interface.
             parameters : tuple
                Parameters for ``?`` interpolation.
             asrecarray : boolean
                ``True``: return a ``numpy.recarray`` if possible;
                ``False``: return records as a list of tuples. [``True``]
             cache : boolean
                Should the results be cached? Set to ``False`` for large queries to
                avoid memory issues. Queries with ``?`` place holders are never cached.
                [``True``]
  
          :Returns:
             For *asrecarray* = ``True`` a :class:`numpy.recarray` is returned; otherwise
             a simple list of tuples is returned.
  
          :Raises:
             :exc:`TypeError` if the conversion to :class:`~numpy.recarray` fails for
             any reason.
  
          .. warning::
  
             There are **no sanity checks** applied to the SQL.
  
          The last *cachesize* queries are cached (for *cache* = ``True``) and
          are returned directly unless the table has been modified.
  
          The string "__self__" in *SQL* is substituted with the table name. See
          the :meth:`SELECT` method for more details.
          """
          SQL = SQL.replace('__self__',self.name)
  
          # Cache the last N (query,result) tuples using a 'FIFO-dict'
          # of length N, where key = SQL; if we can use the cache
          # (cache=True) and if query in dict (AND cache
          # valid, ie it hasn't been emptied (??)) just return cache result.
          #
          # Never use the cache if place holders are used because then we
          # would return the same result for differing input!
          if not '?' in SQL and cache and SQL in self.__cache:
              return self.__cache[SQL]
  
          c = self.cursor
  
          if parameters is None:
              c.execute(SQL)              # no sanity checks!
          else:
              c.execute(SQL, parameters)  # no sanity checks; params should be tuple
  
          if c.rowcount > 0 or SQL.upper().find('DELETE') > -1:
              # table was (potentially) modified
              # rowcount does not change for DELETE, see
              # http://oss.itsystementwicklung.de/download/pysqlite/doc/sqlite3.html#cursor-objects
              # so we catch this case manually and invalidate the whole cache
              self.__cache.clear()
          result = c.fetchall()
          if not result:
              return []    # leaving here keeps cache invalidated
          if asrecarray:
              try:
                  names = [x[0] for x in c.description]   # first elements are column names
                  result = numpy.rec.fromrecords(result,names=names)
              except:
                  raise TypeError("SQLArray.sql(): failed to return recarray, try setting asrecarray=False to return tuples instead")
          else:
              pass      # keep as tuples/data structure as requested
          if cache:
              self.__cache.append(SQL,result)
          return result