======
Cursor
======

    >>> from crate.client import connect

    >>> connection = connect(client=connection_client_mocked)
    >>> cursor = connection.cursor()

The rowcount and duration attribute is -1 in case no ``execute()`` has been performed on the cursor.

    >>> cursor.rowcount
    -1

    >>> cursor.duration
    -1


Hardcode the next response of the mocked connection client, so we won't need a sql statement
to execute::

    >>> connection.client.set_next_response({
    ...     "rows":[ [ "North West Ripple", 1 ], [ "Arkintoofle Minor", 3 ], [ "Alpha Centauri", 3 ] ],
    ...     "cols":[ "name", "position" ],
    ...     "rowcount":3,
    ...     "duration":123
    ... })

fetchone()
==========

Calling ``fetchone()`` on the cursor object the first time after an execute returns the first row::

    >>> cursor.execute('')

    >>> cursor.fetchone()
    ['North West Ripple', 1]

Each call to ``fetchone()`` increments the cursor and returns the next row::

    >>> cursor.fetchone()
    ['Arkintoofle Minor', 3]

One more iteration::

    >>> cursor.next()
    ['Alpha Centauri', 3]

The iteration is stopped after the last row is returned.
A further call to ``fetchone()`` returns an empty result:

    >>> cursor.fetchone()

fetchmany()
===========

``fetchmany()`` takes an argument which specifies the number of rows we want to fetch::

    >>> cursor.execute('')

    >>> cursor.fetchmany(2)
    [['North West Ripple', 1], ['Arkintoofle Minor', 3]]

If the specified number of rows not being available, fewer rows may returned::

    >>> cursor.fetchmany(2)
    [['Alpha Centauri', 3]]

    >>> cursor.execute('')

If no number of rows are specified it defaults to the current cursor.arraysize::

    >>> cursor.arraysize
    1

    >>> cursor.fetchmany()
    [['North West Ripple', 1]]

    >>> cursor.execute('')
    >>> cursor.arraysize = 2
    >>> cursor.fetchmany()
    [['North West Ripple', 1], ['Arkintoofle Minor', 3]]

If zero number of rows are specified, all rows left are returned::

    >>> cursor.fetchmany(0)
    [['Alpha Centauri', 3]]

fetchall()
==========

``fetchall()`` fetches all (remaining) rows of a query result::

    >>> cursor.execute('')

    >>> cursor.fetchall()
    [['North West Ripple', 1], ['Arkintoofle Minor', 3], ['Alpha Centauri', 3]]

Since all data was fetched 'None' is returned by ``fetchone()``::

    >>> cursor.fetchone()

And each other call returns an empty sequence::

    >>> cursor.fetchmany(2)
    []

    >>> cursor.fetchmany()
    []

    >>> cursor.fetchall()
    []

description
===========

    >>> cursor.description
    (('name', None, None, None, None, None, None), ('position', None, None, None, None, None, None))

rowcount
========

The ``rowcount`` property specifies the number of rows that the last ``execute()`` produced::

    >>> cursor.execute('')
    >>> cursor.rowcount
    3

The attribute is -1 in case close has been performed on the cursor::

    >>> cursor.close()
    >>> cursor.rowcount
    -1

duration
========

The ``duration`` property specifies the server-side duration in milliseconds of the last query
issued by ``execute()``::

    >>> cursor = connection.cursor()
    >>> cursor.execute('')
    >>> cursor.duration
    123

The attribute is -1 in case close has been performed on the cursor::

    >>> cursor.close()
    >>> cursor.duration
    -1

executemany
===========

``executemany()`` allows to execute a single sql statement against a sequence
of parameters. The resulting ``rowcount`` and ``duration`` are the sum of all
calls made to the server during this method execution.::

    >>> cursor = connection.cursor()

    >>> cursor.executemany('', (1,2,3))
    >>> cursor.rowcount
    9
    >>> cursor.duration
    369

As executemany cannot keep all the possible resultrows during execution of many statements
and executemany is not intended to be used with statements returning result sets
the result will always be empty::

    >>> cursor.fetchall()
    []

close()
=======

After closing a cursor the connection will be unusable. If any operation is attempted with the
closed connection an ``ProgrammingError`` exception will be raised::

    >>> cursor = connection.cursor()
    >>> cursor.execute('')
    >>> cursor.fetchone()
    ['North West Ripple', 1]

    >>> cursor.close()
    >>> cursor.fetchone()
    Traceback (most recent call last):
    ...
    ProgrammingError: Cursor closed

    >>> cursor.fetchmany()
    Traceback (most recent call last):
    ...
    ProgrammingError: Cursor closed

    >>> cursor.fetchall()
    Traceback (most recent call last):
    ...
    ProgrammingError: Cursor closed

    >>> cursor.next()
    Traceback (most recent call last):
    ...
    ProgrammingError: Cursor closed

