<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 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