Changeset 978 for trunk


Ignore:
Timestamp:
Apr 21, 2019, 3:07:48 PM (5 months ago)
Author:
cito
Message:

Make classic query work as iterator

Mostly following Justin's proposal on the mailing list.

Location:
trunk
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/docs/contents/changelog.rst

    r977 r978  
    77- DB wrapper objects based on existing connections can now be closed and
    88  reopened properly (but the underlying connection will not be affected).
     9- The query objects in the classic API can now be used as iterators
     10  and will then yield the rows as tuples, similar to query.getresult().
     11  Thanks to Justin Pryzby for the proposal and most of the implementation.
     12- Added methods query.dictiter() and query.namediter() to the classic API
     13  which work like query.dictresult() and query.namedresult() except that
     14  they return iterators instead of lists.
     15- Deprecated query.ntuples() in the classic API, since len(query) can now
     16  be used and returns the same number.
     17- Added pg.get/set_namediter and deprecated pg.get/set_namedresult.
    918
    1019Vesion 5.0.7 (2019-mm-dd)
  • trunk/docs/contents/pg/connection.rst

    r973 r978  
    5151rows as a result (usually a select statement, but maybe also an
    5252``"insert/update ... returning"`` statement), this method returns
    53 a :class:`Query` that can be accessed via the
    54 :meth:`Query.getresult`, :meth:`Query.dictresult` or
    55 :meth:`Query.namedresult` methods or simply printed.
    56 Otherwise, it returns ``None``.
     53a :class:`Query`. Otherwise, it returns ``None``.
     54
     55You can use the :class:`Query` object as an iterator that yields all results
     56as tuples, or call :meth:`Query.getresult` to get the result as a list
     57of tuples. Alternatively, you can call :meth:`Query.dictresult` or
     58:meth:`Query.dictiter` if you want to get the rows as dictionaries,
     59or :meth:`Query.namedresult` or :meth:`Query.namediter` if you want to
     60get the rows as named tuples. You can also simply print the :class:`Query`
     61object to show the query results on the console.
    5762
    5863The SQL command may optionally contain positional parameters of the form
  • trunk/docs/contents/pg/module.rst

    r963 r978  
    309309which does exactly the same.
    310310
     311get/set_namediter -- conversion to named tuples
     312-----------------------------------------------
     313
     314.. function:: get_namediter()
     315
     316    Get the generator that converts to named tuples
     317
     318This returns the function used by PyGreSQL to construct the result of the
     319:meth:`Query.namediter` and :meth:`Query.namedresult` methods.
     320
     321.. versionadded:: 5.1
     322
     323.. function:: set_namediter(func)
     324
     325    Set a generator that will convert to named tuples
     326
     327    :param func: the generator to be used to convert results to named tuples
     328
     329You can use this if you want to create different kinds of named tuples
     330returned by the :meth:`Query.namediter` and :meth:`Query.namedresult` methods.
     331If you set this function to *None*, then normal tuples will be used.
     332
     333.. versionadded:: 5.1
     334
    311335get/set_namedresult -- conversion to named tuples
    312336-------------------------------------------------
     
    314338.. function:: get_namedresult()
    315339
    316     Get the function that converts to named tuples
    317 
    318 This returns the function used by PyGreSQL to construct the result of the
    319 :meth:`Query.namedresult` method.
    320 
    321 .. versionadded:: 4.1
     340    Get the generator that converts to named tuples
     341
     342.. deprecated:: 5.1
     343   Use :func:`get_namediter` instead.
    322344
    323345.. function:: set_namedresult(func)
    324346
    325     Set a function that will convert to named tuples
    326 
    327     :param func: the function to be used to convert results to named tuples
    328 
    329 You can use this if you want to create different kinds of named tuples
    330 returned by the :meth:`Query.namedresult` method.  If you set this function
    331 to *None*, then it will become equal to :meth:`Query.getresult`.
    332 
    333 .. versionadded:: 4.1
     347    Set a generator that will convert to named tuples
     348
     349    :param func: the generator to be used to convert results to named tuples
     350
     351.. deprecated:: 5.1
     352   Use :func:`set_namediter` instead.
    334353
    335354get/set_decimal -- decimal type to be used for numeric values
  • trunk/docs/contents/pg/query.rst

    r975 r978  
    77
    88The :class:`Query` object returned by :meth:`Connection.query` and
    9 :meth:`DB.query` provides the following methods for accessing
    10 the results of the query:
     9:meth:`DB.query` can be used as an iterator returning rows as tuples.
     10You can also directly access row tuples using their index, and get
     11the number of rows with the :func:`len` function. The :class:`Query`
     12class also provides the following methods for accessing the results
     13of the query:
    1114
    1215getresult -- get query values as list of tuples
     
    2932Note that since PyGreSQL 5.0 this method will return the values of array
    3033type columns as Python lists.
     34
     35Since PyGreSQL 5.1 the :class:`Query` can be also used directly as
     36an iterable sequence, i.e. you can iterate over the :class:`Query`
     37object to get the same tuples as returned by :meth:`Query.getresult`.
     38You can also call :func:`len` on a query to find the number of rows
     39in the result, and access row tuples using their index directly on
     40the :class:`Query` object.
    3141
    3242dictresult -- get query values as list of dictionaries
     
    7585
    7686.. versionadded:: 4.1
     87
     88dictiter -- get query values as iterator of dictionaries
     89--------------------------------------------------------
     90
     91.. method:: Query.dictiter()
     92
     93    Get query values as iterator of dictionaries
     94
     95    :returns: result values as an iterator of dictionaries
     96    :rtype: iterator
     97    :raises TypeError: too many (any) parameters
     98    :raises MemoryError: internal memory error
     99
     100This method returns query results as an iterator of dictionaries which have
     101the field names as keys.
     102
     103If the query has duplicate field names, you will get the value for the
     104field with the highest index in the query.
     105
     106.. versionadded:: 5.1
     107
     108namediter -- get query values as iterator of named tuples
     109---------------------------------------------------------
     110
     111.. method:: Query.namediter()
     112
     113    Get query values as iterator of named tuples
     114
     115    :returns: result values as an iterator of named tuples
     116    :rtype: iterator
     117    :raises TypeError: too many (any) parameters
     118    :raises TypeError: named tuples not supported
     119    :raises MemoryError: internal memory error
     120
     121This method returns query results as an iterator of named tuples with
     122proper field names.
     123
     124Column names in the database that are not valid as field names for
     125named tuples (particularly, names starting with an underscore) are
     126automatically renamed to valid positional names.
     127
     128.. versionadded:: 5.1
     129
    77130
    78131listfields -- list fields names of previous query result
     
    134187
    135188This method returns the number of tuples in the query result.
     189
     190.. deprecated:: 5.1
     191   You can use the normal :func:`len` function instead.
  • trunk/docs/contents/tutorial.rst

    r962 r978  
    107107    'durian'
    108108
     109In PyGreSQL 5.1 and newer, you can also use the :class:`Query` instance
     110directly as an iterator that yields the rows as tuples, and you can use
     111the methods :meth:`Query.dictiter` or :meth:`Query.namediter` to get
     112iterators yielding the rows as dictionaries or named tuples.
     113
    109114Using the method :meth:`DB.get_as_dict`, you can easily import the whole table
    110115into a Python dictionary mapping the primary key *id* to the *name*::
  • trunk/pg.py

    r977 r978  
    13121312
    13131313
    1314 def _namedresult(q):
    1315     """Get query result as named tuples."""
     1314def _dictiter(q):
     1315    """Get query result as an iterator of dictionaries."""
     1316    fields = q.listfields()
     1317    for r in q:
     1318        yield dict(zip(fields, r))
     1319
     1320
     1321def _namediter(q):
     1322    """Get query result as an iterator of named tuples."""
    13161323    row = _row_factory(q.listfields())
    1317     return [row(r) for r in q.getresult()]
     1324    for r in q:
     1325        yield row(r)
    13181326
    13191327
     
    13331341        """Return the stored result of this query."""
    13341342        return self.result
     1343
     1344    def __iter__(self):
     1345        return iter(self.result)
    13351346
    13361347
     
    13541365# Initialize the C module
    13551366
    1356 set_namedresult(_namedresult)
     1367set_dictiter(_dictiter)
     1368set_namediter(_namediter)
    13571369set_decimal(Decimal)
    13581370set_jsondecode(jsondecode)
  • trunk/pgmodule.c

    r957 r978  
    9090
    9191static PyObject *decimal = NULL, /* decimal type */
    92                                 *namedresult = NULL, /* function for getting named results */
     92                                *dictiter = NULL, /* function for getting named results */
     93                                *namediter = NULL, /* function for getting named results */
    9394                                *jsondecode = NULL; /* function for decoding json strings */
    9495static const char *date_format = NULL; /* date format that is always assumed */
     
    157158        int                     result_type;    /* result type (DDL/DML/DQL) */
    158159        long            arraysize;              /* array size for fetch method */
    159         int                     current_row;    /* current selected row */
     160        int                     current_row;    /* currently selected row */
    160161        int                     max_row;                /* number of rows in the result */
    161162        int                     num_fields;             /* number of fields in each row */
     
    177178        PGresult   *result;                     /* result content */
    178179        int                     encoding;               /* client encoding */
     180        int                     current_row;    /* currently selected row */
     181        int                     max_row;                /* number of rows in the result */
     182        int                     num_fields;             /* number of fields in each row */
     183        int                *col_types;          /* PyGreSQL column types */
    179184}       queryObject;
    180185#define is_queryObject(v) (PyType(v) == &queryType)
     
    932937                        char       *estr;
    933938                        Py_ssize_t      esize;
    934                         int quoted = 0, escaped =0;
     939                        int quoted = 0, escaped = 0;
    935940
    936941                        estr = s;
     
    16541659largeNew(connObject *pgcnx, Oid oid)
    16551660{
    1656         largeObject *npglo;
    1657 
    1658         if (!(npglo = PyObject_NEW(largeObject, &largeType)))
     1661        largeObject *large_obj;
     1662
     1663        if (!(large_obj = PyObject_NEW(largeObject, &largeType)))
    16591664                return NULL;
    16601665
    16611666        Py_XINCREF(pgcnx);
    1662         npglo->pgcnx = pgcnx;
    1663         npglo->lo_fd = -1;
    1664         npglo->lo_oid = oid;
    1665 
    1666         return npglo;
     1667        large_obj->pgcnx = pgcnx;
     1668        large_obj->lo_fd = -1;
     1669        large_obj->lo_oid = oid;
     1670
     1671        return large_obj;
    16671672}
    16681673
     
    21212126connSource(connObject *self, PyObject *noargs)
    21222127{
    2123         sourceObject *npgobj;
     2128        sourceObject *source_obj;
    21242129
    21252130        /* checks validity */
     
    21282133
    21292134        /* allocates new query object */
    2130         if (!(npgobj = PyObject_NEW(sourceObject, &sourceType)))
     2135        if (!(source_obj = PyObject_NEW(sourceObject, &sourceType)))
    21312136                return NULL;
    21322137
    21332138        /* initializes internal parameters */
    21342139        Py_XINCREF(self);
    2135         npgobj->pgcnx = self;
    2136         npgobj->result = NULL;
    2137         npgobj->valid = 1;
    2138         npgobj->arraysize = PG_ARRAYSIZE;
    2139 
    2140         return (PyObject *) npgobj;
     2140        source_obj->pgcnx = self;
     2141        source_obj->result = NULL;
     2142        source_obj->valid = 1;
     2143        source_obj->arraysize = PG_ARRAYSIZE;
     2144
     2145        return (PyObject *) source_obj;
    21412146}
    21422147
     
    21472152_connQuery(connObject *self, PyObject *args, int prepared)
    21482153{
    2149         PyObject        *query_obj;
     2154        PyObject        *query_str_obj;
    21502155        PyObject        *param_obj = NULL;
    21512156        char            *query;
    21522157        PGresult        *result;
    2153         queryObject *npgobj;
     2158        queryObject *query_obj;
    21542159        int                     encoding,
    21552160                                status,
     
    21632168
    21642169        /* get query args */
    2165         if (!PyArg_ParseTuple(args, "O|O", &query_obj, &param_obj))
     2170        if (!PyArg_ParseTuple(args, "O|O", &query_str_obj, &param_obj))
    21662171        {
    21672172                return NULL;
     
    21702175        encoding = PQclientEncoding(self->cnx);
    21712176
    2172         if (PyBytes_Check(query_obj))
    2173         {
    2174                 query = PyBytes_AsString(query_obj);
    2175                 query_obj = NULL;
    2176         }
    2177         else if (PyUnicode_Check(query_obj))
    2178         {
    2179                 query_obj = get_encoded_string(query_obj, encoding);
    2180                 if (!query_obj) return NULL; /* pass the UnicodeEncodeError */
    2181                 query = PyBytes_AsString(query_obj);
     2177        if (PyBytes_Check(query_str_obj))
     2178        {
     2179                query = PyBytes_AsString(query_str_obj);
     2180                query_str_obj = NULL;
     2181        }
     2182        else if (PyUnicode_Check(query_str_obj))
     2183        {
     2184                query_str_obj = get_encoded_string(query_str_obj, encoding);
     2185                if (!query_str_obj) return NULL; /* pass the UnicodeEncodeError */
     2186                query = PyBytes_AsString(query_str_obj);
    21822187        }
    21832188        else
     
    21982203                if (!param_obj)
    21992204                {
    2200                         Py_XDECREF(query_obj);
     2205                        Py_XDECREF(query_str_obj);
    22012206                        return NULL;
    22022207                }
     
    22302235                {
    22312236                        PyMem_Free((void *)parms); PyMem_Free(str);
    2232                         Py_XDECREF(query_obj); Py_XDECREF(param_obj);
     2237                        Py_XDECREF(query_str_obj); Py_XDECREF(param_obj);
    22332238                        return PyErr_NoMemory();
    22342239                }
     
    22572262                                        while (s != str) { s--; Py_DECREF(*s); }
    22582263                                        PyMem_Free(str);
    2259                                         Py_XDECREF(query_obj);
     2264                                        Py_XDECREF(query_str_obj);
    22602265                                        Py_XDECREF(param_obj);
    22612266                                        /* pass the UnicodeEncodeError */
     
    22732278                                        while (s != str) { s--; Py_DECREF(*s); }
    22742279                                        PyMem_Free(str);
    2275                                         Py_XDECREF(query_obj);
     2280                                        Py_XDECREF(query_str_obj);
    22762281                                        Py_XDECREF(param_obj);
    22772282                                        PyErr_SetString(PyExc_TypeError,
     
    23072312
    23082313        /* we don't need the query and its params any more */
    2309         Py_XDECREF(query_obj);
     2314        Py_XDECREF(query_str_obj);
    23102315        Py_XDECREF(param_obj);
    23112316
     
    23692374        }
    23702375
    2371         if (!(npgobj = PyObject_NEW(queryObject, &queryType)))
     2376        if (!(query_obj = PyObject_NEW(queryObject, &queryType)))
    23722377                return PyErr_NoMemory();
    23732378
    23742379        /* stores result and returns object */
    23752380        Py_XINCREF(self);
    2376         npgobj->pgcnx = self;
    2377         npgobj->result = result;
    2378         npgobj->encoding = encoding;
    2379         return (PyObject *) npgobj;
     2381        query_obj->pgcnx = self;
     2382        query_obj->result = result;
     2383        query_obj->encoding = encoding;
     2384        query_obj->current_row = 0;
     2385        query_obj->max_row = PQntuples(result);
     2386        query_obj->num_fields = PQnfields(result);
     2387        query_obj->col_types = get_col_types(result, query_obj->num_fields);
     2388        if (!query_obj->col_types) {
     2389                Py_DECREF(query_obj);
     2390                Py_DECREF(self);
     2391                return NULL;
     2392        }
     2393
     2394        return (PyObject *) query_obj;
    23802395}
    23812396
     
    24822497        if (result && PQresultStatus(result) == PGRES_COMMAND_OK)
    24832498        {
    2484                 queryObject *npgobj = PyObject_NEW(queryObject, &queryType);
    2485                 if (!npgobj)
     2499                queryObject *query_obj = PyObject_NEW(queryObject, &queryType);
     2500                if (!query_obj)
    24862501                        return PyErr_NoMemory();
    24872502                Py_XINCREF(self);
    2488                 npgobj->pgcnx = self;
    2489                 npgobj->result = result;
    2490                 return (PyObject *) npgobj;
     2503                query_obj->pgcnx = self;
     2504                query_obj->result = result;
     2505                query_obj->encoding = PQclientEncoding(self->cnx);
     2506                query_obj->current_row = 0;
     2507                query_obj->max_row = PQntuples(result);
     2508                query_obj->num_fields = PQnfields(result);
     2509                query_obj->col_types = get_col_types(result, query_obj->num_fields);
     2510                return (PyObject *) query_obj;
    24912511        }
    24922512        set_error(ProgrammingError, "Cannot describe prepared statement",
     
    45584578        int                     pgport;
    45594579        char            port_buffer[20];
    4560         connObject *npgobj;
     4580        connObject *conn_obj;
    45614581
    45624582        pghost = pgopt = pgdbname = pguser = pgpasswd = NULL;
     
    45944614#endif /* DEFAULT_VARS */
    45954615
    4596         if (!(npgobj = PyObject_NEW(connObject, &connType)))
     4616        if (!(conn_obj = PyObject_NEW(connObject, &connType)))
    45974617        {
    45984618                set_error_msg(InternalError, "Can't create new connection object");
     
    46004620        }
    46014621
    4602         npgobj->valid = 1;
    4603         npgobj->cnx = NULL;
    4604         npgobj->date_format = date_format;
    4605         npgobj->cast_hook = NULL;
    4606         npgobj->notice_receiver = NULL;
     4622        conn_obj->valid = 1;
     4623        conn_obj->cnx = NULL;
     4624        conn_obj->date_format = date_format;
     4625        conn_obj->cast_hook = NULL;
     4626        conn_obj->notice_receiver = NULL;
    46074627
    46084628        if (pgport != -1)
     
    46134633
    46144634        Py_BEGIN_ALLOW_THREADS
    4615         npgobj->cnx = PQsetdbLogin(pghost, pgport == -1 ? NULL : port_buffer,
     4635        conn_obj->cnx = PQsetdbLogin(pghost, pgport == -1 ? NULL : port_buffer,
    46164636                pgopt, NULL, pgdbname, pguser, pgpasswd);
    46174637        Py_END_ALLOW_THREADS
    46184638
    4619         if (PQstatus(npgobj->cnx) == CONNECTION_BAD)
    4620         {
    4621                 set_error(InternalError, "Cannot connect", npgobj->cnx, NULL);
    4622                 Py_XDECREF(npgobj);
    4623                 return NULL;
    4624         }
    4625 
    4626         return (PyObject *) npgobj;
     4639        if (PQstatus(conn_obj->cnx) == CONNECTION_BAD)
     4640        {
     4641                set_error(InternalError, "Cannot connect", conn_obj->cnx, NULL);
     4642                Py_XDECREF(conn_obj);
     4643                return NULL;
     4644        }
     4645
     4646        return (PyObject *) conn_obj;
    46274647}
    46284648
     
    46314651{
    46324652        Py_XDECREF(self->pgcnx);
     4653        if (self->col_types)
     4654                PyMem_Free(self->col_types);
    46334655        if (self->result)
    46344656                PQclear(self->result);
     
    46384660
    46394661/* get number of rows */
    4640 static char queryNTuples__doc__[] =
     4662static char queryNtuples__doc__[] =
    46414663"ntuples() -- return number of tuples returned by query";
    46424664
    46434665static PyObject *
    4644 queryNTuples(queryObject *self, PyObject *noargs)
    4645 {
    4646         return PyInt_FromLong((long) PQntuples(self->result));
     4666queryNtuples(queryObject *self, PyObject *noargs)
     4667{
     4668        return PyInt_FromLong(self->max_row);
    46474669}
    46484670
    46494671/* list fields names from query result */
    4650 static char queryListFields__doc__[] =
     4672static char queryListfields__doc__[] =
    46514673"listfields() -- List field names from result";
    46524674
    46534675static PyObject *
    4654 queryListFields(queryObject *self, PyObject *noargs)
    4655 {
    4656         int                     i,
    4657                                 n;
     4676queryListfields(queryObject *self, PyObject *noargs)
     4677{
     4678        int                     i;
    46584679        char       *name;
    46594680        PyObject   *fieldstuple,
     
    46614682
    46624683        /* builds tuple */
    4663         n = PQnfields(self->result);
    4664         fieldstuple = PyTuple_New(n);
    4665 
    4666         for (i = 0; i < n; ++i)
    4667         {
    4668                 name = PQfname(self->result, i);
    4669                 str = PyStr_FromString(name);
    4670                 PyTuple_SET_ITEM(fieldstuple, i, str);
    4671         }
    4672 
     4684        fieldstuple = PyTuple_New(self->num_fields);
     4685        if (fieldstuple) {
     4686                for (i = 0; i < self->num_fields; ++i)
     4687                {
     4688                        name = PQfname(self->result, i);
     4689                        str = PyStr_FromString(name);
     4690                        PyTuple_SET_ITEM(fieldstuple, i, str);
     4691                }
     4692        }
    46734693        return fieldstuple;
    46744694}
    46754695
    46764696/* get field name from last result */
    4677 static char queryFieldName__doc__[] =
     4697static char queryFieldname__doc__[] =
    46784698"fieldname(num) -- return name of field from result from its position";
    46794699
    46804700static PyObject *
    4681 queryFieldName(queryObject *self, PyObject *args)
     4701queryFieldname(queryObject *self, PyObject *args)
    46824702{
    46834703        int             i;
     
    46934713
    46944714        /* checks number validity */
    4695         if (i >= PQnfields(self->result))
     4715        if (i >= self->num_fields)
    46964716        {
    46974717                PyErr_SetString(PyExc_ValueError, "Invalid field number");
     
    47054725
    47064726/* gets fields number from name in last result */
    4707 static char queryFieldNumber__doc__[] =
     4727static char queryFieldnum__doc__[] =
    47084728"fieldnum(name) -- return position in query for field from its name";
    47094729
    47104730static PyObject *
    4711 queryFieldNumber(queryObject *self, PyObject *args)
     4731queryFieldnum(queryObject *self, PyObject *args)
    47124732{
    47134733        int             num;
     
    47324752}
    47334753
    4734 /* retrieves last result */
    4735 static char queryGetResult__doc__[] =
     4754/* The __iter__() method of the queryObject.
     4755   This returns the default iterator yielding rows as tuples. */
     4756static PyObject* queryGetIter(queryObject *self)
     4757{
     4758        self->current_row = 0;
     4759        Py_INCREF(self);
     4760        return (PyObject*)self;
     4761}
     4762
     4763/* Return the value in the given column of the current row. */
     4764static PyObject *
     4765getValueInColumn(queryObject *self, int column)
     4766{
     4767        if (PQgetisnull(self->result, self->current_row, column))
     4768        {
     4769                Py_INCREF(Py_None);
     4770                return Py_None;
     4771        }
     4772
     4773        /* get the string representation of the value */
     4774        /* note: this is always null-terminated text format */
     4775        char   *s = PQgetvalue(self->result, self->current_row, column);
     4776        /* get the PyGreSQL type of the column */
     4777        int             type = self->col_types[column];
     4778        /* cast the string representation into a Python object */
     4779        if (type & PYGRES_ARRAY)
     4780                return cast_array(s,
     4781                        PQgetlength(self->result, self->current_row, column),
     4782                        self->encoding, type, NULL, 0);
     4783        if (type == PYGRES_BYTEA)
     4784                return cast_bytea_text(s);
     4785        if (type == PYGRES_OTHER)
     4786                return cast_other(s,
     4787                        PQgetlength(self->result, self->current_row, column),
     4788                        self->encoding,
     4789                        PQftype(self->result, column), self->pgcnx->cast_hook);
     4790        if (type & PYGRES_TEXT)
     4791                return cast_sized_text(s,
     4792                        PQgetlength(self->result, self->current_row, column),
     4793                        self->encoding, type);
     4794        return cast_unsized_simple(s, type);
     4795}
     4796
     4797/* Return the current row as a tuple. */
     4798static PyObject *
     4799queryGetRowAsTuple(queryObject *self)
     4800{
     4801        PyObject   *row_tuple = NULL;
     4802        int                     j;
     4803
     4804        if (!(row_tuple = PyTuple_New(self->num_fields))) return NULL;
     4805
     4806        for (j = 0; j < self->num_fields; ++j)
     4807        {
     4808                PyObject *val = getValueInColumn(self, j);
     4809                if (!val)
     4810                {
     4811                        Py_DECREF(row_tuple); return NULL;
     4812                }
     4813                PyTuple_SET_ITEM(row_tuple, j, val);
     4814        }
     4815
     4816        return row_tuple;
     4817}
     4818
     4819/* The __next__() method of the queryObject.
     4820   Returns the current current row as a tuple and moves to the next one. */
     4821static PyObject *
     4822queryNext(queryObject *self, PyObject *noargs)
     4823{
     4824        PyObject   *row_tuple = NULL;
     4825
     4826        if (self->current_row >= self->max_row) {
     4827                PyErr_SetNone(PyExc_StopIteration);
     4828                return NULL;
     4829        }
     4830
     4831        row_tuple = queryGetRowAsTuple(self);
     4832        if (row_tuple) ++self->current_row;
     4833    return row_tuple;
     4834}
     4835
     4836/* Retrieves the last query result as a list of tuples. */
     4837static char queryGetresult__doc__[] =
    47364838"getresult() -- Get the result of a query\n\n"
    47374839"The result is returned as a list of rows, each one a tuple of fields\n"
     
    47394841
    47404842static PyObject *
    4741 queryGetResult(queryObject *self, PyObject *noargs)
    4742 {
    4743         PyObject   *reslist;
    4744         int                     i, m, n, *col_types;
    4745         int                     encoding = self->encoding;
    4746 
    4747         /* stores result in tuple */
    4748         m = PQntuples(self->result);
    4749         n = PQnfields(self->result);
    4750         if (!(reslist = PyList_New(m))) return NULL;
    4751 
    4752         if (!(col_types = get_col_types(self->result, n))) return NULL;
    4753 
    4754         for (i = 0; i < m; ++i)
    4755         {
    4756                 PyObject   *rowtuple;
    4757                 int                     j;
    4758 
    4759                 if (!(rowtuple = PyTuple_New(n)))
     4843queryGetresult(queryObject *self, PyObject *noargs)
     4844{
     4845        PyObject   *result_list;
     4846        int                     i;
     4847
     4848        if (!(result_list = PyList_New(self->max_row))) return NULL;
     4849
     4850        for (i = self->current_row = 0; i < self->max_row; ++i)
     4851        {
     4852                PyObject   *row_tuple = queryNext(self, noargs);
     4853                if (!row_tuple)
    47604854                {
    4761                         Py_DECREF(reslist);
    4762                         reslist = NULL;
    4763                         goto exit;
     4855                        Py_DECREF(result_list); return NULL;
    47644856                }
    4765 
    4766                 for (j = 0; j < n; ++j)
     4857                PyList_SET_ITEM(result_list, i, row_tuple);
     4858        }
     4859
     4860        return result_list;
     4861}
     4862
     4863/* Return the current row as a dict. */
     4864static PyObject *
     4865queryGetRowAsDict(queryObject *self)
     4866{
     4867        PyObject   *row_dict = NULL;
     4868        int                     j;
     4869
     4870        if (!(row_dict = PyDict_New())) return NULL;
     4871
     4872        for (j = 0; j < self->num_fields; ++j)
     4873        {
     4874                PyObject *val = getValueInColumn(self, j);
     4875                if (!val)
    47674876                {
    4768                         PyObject * val;
    4769 
    4770                         if (PQgetisnull(self->result, i, j))
    4771                         {
    4772                                 Py_INCREF(Py_None);
    4773                                 val = Py_None;
    4774                         }
    4775                         else /* not null */
    4776                         {
    4777                                 /* get the string representation of the value */
    4778                                 /* note: this is always null-terminated text format */
    4779                                 char   *s = PQgetvalue(self->result, i, j);
    4780                                 /* get the PyGreSQL type of the column */
    4781                                 int             type = col_types[j];
    4782 
    4783                                 if (type & PYGRES_ARRAY)
    4784                                         val = cast_array(s, PQgetlength(self->result, i, j),
    4785                                                 encoding, type, NULL, 0);
    4786                                 else if (type == PYGRES_BYTEA)
    4787                                         val = cast_bytea_text(s);
    4788                                 else if (type == PYGRES_OTHER)
    4789                                         val = cast_other(s,
    4790                                                 PQgetlength(self->result, i, j), encoding,
    4791                                                 PQftype(self->result, j), self->pgcnx->cast_hook);
    4792                                 else if (type & PYGRES_TEXT)
    4793                                         val = cast_sized_text(s, PQgetlength(self->result, i, j),
    4794                                                 encoding, type);
    4795                                 else
    4796                                         val = cast_unsized_simple(s, type);
    4797                         }
    4798 
    4799                         if (!val)
    4800                         {
    4801                                 Py_DECREF(reslist);
    4802                                 Py_DECREF(rowtuple);
    4803                                 reslist = NULL;
    4804                                 goto exit;
    4805                         }
    4806 
    4807                         PyTuple_SET_ITEM(rowtuple, j, val);
     4877                        Py_DECREF(row_dict); return NULL;
    48084878                }
    4809 
    4810                 PyList_SET_ITEM(reslist, i, rowtuple);
    4811         }
    4812 
    4813 exit:
    4814         PyMem_Free(col_types);
    4815 
    4816         /* returns list */
    4817         return reslist;
    4818 }
    4819 
    4820 /* retrieves last result as a list of dictionaries*/
    4821 static char queryDictResult__doc__[] =
     4879                PyDict_SetItemString(row_dict, PQfname(self->result, j), val);
     4880                Py_DECREF(val);
     4881        }
     4882
     4883        return row_dict;
     4884}
     4885
     4886/* Return the current current row as a dict and move to the next one. */
     4887static PyObject *
     4888queryNextDict(queryObject *self, PyObject *noargs)
     4889{
     4890        PyObject   *row_dict = NULL;
     4891
     4892        if (self->current_row >= self->max_row) {
     4893                PyErr_SetNone(PyExc_StopIteration);
     4894                return NULL;
     4895        }
     4896
     4897        row_dict = queryGetRowAsDict(self);
     4898        if (row_dict) ++self->current_row;
     4899    return row_dict;
     4900}
     4901
     4902/* Retrieve the last query result as a list of dictionaries. */
     4903static char queryDictresult__doc__[] =
    48224904"dictresult() -- Get the result of a query\n\n"
    48234905"The result is returned as a list of rows, each one a dictionary with\n"
    4824 "the field names used as the labels.\n";
    4825 
    4826 static PyObject *
    4827 queryDictResult(queryObject *self, PyObject *noargs)
    4828 {
    4829         PyObject   *reslist;
    4830         int                     i,
    4831                                 m,
    4832                                 n,
    4833                            *col_types;
    4834         int                     encoding = self->encoding;
    4835 
    4836         /* stores result in list */
    4837         m = PQntuples(self->result);
    4838         n = PQnfields(self->result);
    4839         if (!(reslist = PyList_New(m))) return NULL;
    4840 
    4841         if (!(col_types = get_col_types(self->result, n))) return NULL;
    4842 
    4843         for (i = 0; i < m; ++i)
    4844         {
    4845                 PyObject   *dict;
    4846                 int                     j;
    4847 
    4848                 if (!(dict = PyDict_New()))
     4906"the field names used as the keys.\n";
     4907
     4908static PyObject *
     4909queryDictresult(queryObject *self, PyObject *noargs)
     4910{
     4911        PyObject   *result_list;
     4912        int                     i;
     4913
     4914        if (!(result_list = PyList_New(self->max_row))) return NULL;
     4915
     4916        for (i = self->current_row = 0; i < self->max_row; ++i)
     4917        {
     4918                PyObject   *row_dict = queryNextDict(self, noargs);
     4919                if (!row_dict)
    48494920                {
    4850                         Py_DECREF(reslist);
    4851                         reslist = NULL;
    4852                         goto exit;
     4921                        Py_DECREF(result_list); return NULL;
    48534922                }
    4854 
    4855                 for (j = 0; j < n; ++j)
    4856                 {
    4857                         PyObject * val;
    4858 
    4859                         if (PQgetisnull(self->result, i, j))
    4860                         {
    4861                                 Py_INCREF(Py_None);
    4862                                 val = Py_None;
    4863                         }
    4864                         else /* not null */
    4865                         {
    4866                                 /* get the string representation of the value */
    4867                                 /* note: this is always null-terminated text format */
    4868                                 char   *s = PQgetvalue(self->result, i, j);
    4869                                 /* get the PyGreSQL type of the column */
    4870                                 int             type = col_types[j];
    4871 
    4872                                 if (type & PYGRES_ARRAY)
    4873                                         val = cast_array(s, PQgetlength(self->result, i, j),
    4874                                                 encoding, type, NULL, 0);
    4875                                 else if (type == PYGRES_BYTEA)
    4876                                         val = cast_bytea_text(s);
    4877                                 else if (type == PYGRES_OTHER)
    4878                                         val = cast_other(s,
    4879                                                 PQgetlength(self->result, i, j), encoding,
    4880                                                 PQftype(self->result, j), self->pgcnx->cast_hook);
    4881                                 else if (type & PYGRES_TEXT)
    4882                                         val = cast_sized_text(s, PQgetlength(self->result, i, j),
    4883                                                 encoding, type);
    4884                                 else
    4885                                         val = cast_unsized_simple(s, type);
    4886                         }
    4887 
    4888                         if (!val)
    4889                         {
    4890                                 Py_DECREF(dict);
    4891                                 Py_DECREF(reslist);
    4892                                 reslist = NULL;
    4893                                 goto exit;
    4894                         }
    4895 
    4896                         PyDict_SetItemString(dict, PQfname(self->result, j), val);
    4897                         Py_DECREF(val);
    4898                 }
    4899 
    4900                 PyList_SET_ITEM(reslist, i, dict);
    4901         }
    4902 
    4903 exit:
    4904         PyMem_Free(col_types);
    4905 
    4906         /* returns list */
    4907         return reslist;
    4908 }
    4909 
    4910 /* retrieves last result as named tuples */
    4911 static char queryNamedResult__doc__[] =
     4923                PyList_SET_ITEM(result_list, i, row_dict);
     4924        }
     4925
     4926        return result_list;
     4927}
     4928
     4929/* retrieves last result as iterator of dictionaries */
     4930static char queryDictiter__doc__[] =
     4931"dictiter() -- Get the result of a query\n\n"
     4932"The result is returned as an iterator of rows, each one a a dictionary\n"
     4933"with the field names used as the keys.\n";
     4934
     4935static PyObject *
     4936queryDictiter(queryObject *self, PyObject *noargs)
     4937{
     4938        if (dictiter) {
     4939                return PyObject_CallFunction(dictiter, "(O)", self);
     4940        }
     4941        return queryGetIter(self);
     4942}
     4943
     4944
     4945/* retrieves last result as list of named tuples */
     4946static char queryNamedresult__doc__[] =
    49124947"namedresult() -- Get the result of a query\n\n"
    4913 "The result is returned as a list of rows, each one a tuple of fields\n"
     4948"The result is returned as a list of rows, each one a named tuple of fields\n"
    49144949"in the order returned by the server.\n";
    49154950
    49164951static PyObject *
    4917 queryNamedResult(queryObject *self, PyObject *noargs)
    4918 {
    4919         PyObject   *ret;
    4920 
    4921         if (namedresult)
    4922         {
    4923                 ret = PyObject_CallFunction(namedresult, "(O)", self);
    4924 
    4925                 if (ret == NULL)
    4926                         return NULL;
    4927                 }
    4928         else
    4929         {
    4930                 ret = queryGetResult(self, NULL);
    4931         }
    4932 
    4933         return ret;
     4952queryNamedresult(queryObject *self, PyObject *noargs)
     4953{
     4954        if (namediter) {
     4955                PyObject* res = PyObject_CallFunction(namediter, "(O)", self);
     4956                if (res && PyList_Check(res))
     4957                        return res;
     4958                PyObject *res_list = PySequence_List(res);
     4959                Py_DECREF(res);
     4960                return res_list;
     4961        }
     4962        return queryGetresult(self, noargs);
     4963}
     4964
     4965/* retrieves last result as iterator of named tuples */
     4966static char queryNamediter__doc__[] =
     4967"namediter() -- Get the result of a query\n\n"
     4968"The result is returned as an iterator of rows, each one a named tuple\n"
     4969"of fields in the order returned by the server.\n";
     4970
     4971static PyObject *
     4972queryNamediter(queryObject *self, PyObject *noargs)
     4973{
     4974        if (namediter) {
     4975                PyObject* res = PyObject_CallFunction(namediter, "(O)", self);
     4976                if (res && !PyList_Check(res))
     4977                        return res;
     4978                PyObject* res_iter = (Py_TYPE(res)->tp_iter)((PyObject *)self);
     4979                Py_DECREF(res);
     4980                return res_iter;
     4981        }
     4982        return queryGetIter(self);
     4983}
     4984
     4985/* Return length of a query object. */
     4986static Py_ssize_t
     4987queryLen(PyObject *self)
     4988{
     4989        PyObject   *tmp;
     4990        long            len;
     4991
     4992        tmp = PyLong_FromLong(((queryObject*)self)->max_row);
     4993        len = PyLong_AsSsize_t(tmp);
     4994        Py_DECREF(tmp);
     4995        return len;
     4996}
     4997
     4998/* Return given item from a query object. */
     4999static PyObject *
     5000queryGetItem(PyObject *self, Py_ssize_t i)
     5001{
     5002        queryObject        *q = (queryObject *)self;
     5003        PyObject           *tmp;
     5004        long                    row;
     5005
     5006        tmp = PyLong_FromSize_t(i);
     5007        row = PyLong_AsLong(tmp);
     5008        Py_DECREF(tmp);
     5009
     5010        if (row < 0 || row >= q->max_row) {
     5011                PyErr_SetNone(PyExc_IndexError);
     5012                return NULL;
     5013        }
     5014
     5015        q->current_row = row;
     5016        return queryGetRowAsTuple(q);
    49345017}
    49355018
     
    50525135/* query object methods */
    50535136static struct PyMethodDef queryMethods[] = {
    5054         {"getresult", (PyCFunction) queryGetResult, METH_NOARGS,
    5055                         queryGetResult__doc__},
    5056         {"dictresult", (PyCFunction) queryDictResult, METH_NOARGS,
    5057                         queryDictResult__doc__},
    5058         {"namedresult", (PyCFunction) queryNamedResult, METH_NOARGS,
    5059                         queryNamedResult__doc__},
    5060         {"fieldname", (PyCFunction) queryFieldName, METH_VARARGS,
    5061                          queryFieldName__doc__},
    5062         {"fieldnum", (PyCFunction) queryFieldNumber, METH_VARARGS,
    5063                         queryFieldNumber__doc__},
    5064         {"listfields", (PyCFunction) queryListFields, METH_NOARGS,
    5065                         queryListFields__doc__},
    5066         {"ntuples", (PyCFunction) queryNTuples, METH_NOARGS,
    5067                         queryNTuples__doc__},
     5137        {"getresult", (PyCFunction) queryGetresult, METH_NOARGS,
     5138                        queryGetresult__doc__},
     5139        {"dictresult", (PyCFunction) queryDictresult, METH_NOARGS,
     5140                        queryDictresult__doc__},
     5141        {"dictiter", (PyCFunction) queryDictiter, METH_NOARGS,
     5142                        queryDictiter__doc__},
     5143        {"namedresult", (PyCFunction) queryNamedresult, METH_NOARGS,
     5144                        queryNamedresult__doc__},
     5145        {"namediter", (PyCFunction) queryNamediter, METH_NOARGS,
     5146                        queryNamediter__doc__},
     5147        {"fieldname", (PyCFunction) queryFieldname, METH_VARARGS,
     5148                         queryFieldname__doc__},
     5149        {"fieldnum", (PyCFunction) queryFieldnum, METH_VARARGS,
     5150                        queryFieldnum__doc__},
     5151        {"listfields", (PyCFunction) queryListfields, METH_NOARGS,
     5152                        queryListfields__doc__},
     5153        {"ntuples", (PyCFunction) queryNtuples, METH_NOARGS,
     5154                        queryNtuples__doc__},
    50685155        {NULL, NULL}
    50695156};
     5157
     5158/* query sequence protocol methods */
     5159static PySequenceMethods querySequenceMethods = {
     5160        (lenfunc) queryLen,                             /* sq_length */
     5161        0,                                                              /* sq_concat */
     5162        0,                                                              /* sq_repeat */
     5163        (ssizeargfunc) queryGetItem,    /* sq_item */
     5164        0,                                                              /* sq_ass_item */
     5165        0,                                                              /* sq_contains */
     5166        0,                                                              /* sq_inplace_concat */
     5167        0,                                                              /* sq_inplace_repeat */
     5168};
     5169
    50705170
    50715171/* query type definition */
    50725172static PyTypeObject queryType = {
    50735173        PyVarObject_HEAD_INIT(NULL, 0)
    5074         "pg.Query",                                             /* tp_name */
    5075         sizeof(queryObject),                    /* tp_basicsize */
    5076         0,                                                              /* tp_itemsize */
     5174        "pg.Query",                                     /* tp_name */
     5175        sizeof(queryObject),            /* tp_basicsize */
     5176        0,                                                      /* tp_itemsize */
    50775177        /* methods */
    5078         (destructor) queryDealloc,              /* tp_dealloc */
    5079         0,                                                              /* tp_print */
    5080         0,                                                              /* tp_getattr */
    5081         0,                                                              /* tp_setattr */
    5082         0,                                                              /* tp_compare */
    5083         0,                                                              /* tp_repr */
    5084         0,                                                              /* tp_as_number */
    5085         0,                                                              /* tp_as_sequence */
    5086         0,                                                              /* tp_as_mapping */
    5087         0,                                                              /* tp_hash */
    5088         0,                                                              /* tp_call */
    5089         (reprfunc) queryStr,                    /* tp_str */
    5090         PyObject_GenericGetAttr,                /* tp_getattro */
    5091         0,                                                              /* tp_setattro */
    5092         0,                                                              /* tp_as_buffer */
    5093         Py_TPFLAGS_DEFAULT,                             /* tp_flags */
    5094         0,                                                              /* tp_doc */
    5095         0,                                                              /* tp_traverse */
    5096         0,                                                              /* tp_clear */
    5097         0,                                                              /* tp_richcompare */
    5098         0,                                                              /* tp_weaklistoffset */
    5099         0,                                                              /* tp_iter */
    5100         0,                                                              /* tp_iternext */
    5101         queryMethods,                                   /* tp_methods */
     5178        (destructor) queryDealloc,      /* tp_dealloc */
     5179        0,                                                      /* tp_print */
     5180        0,                                                      /* tp_getattr */
     5181        0,                                                      /* tp_setattr */
     5182        0,                                                      /* tp_compare */
     5183        0,                                                      /* tp_repr */
     5184        0,                                                      /* tp_as_number */
     5185        &querySequenceMethods,          /* tp_as_sequence */
     5186        0,                                                      /* tp_as_mapping */
     5187        0,                                                      /* tp_hash */
     5188        0,                                                      /* tp_call */
     5189        (reprfunc) queryStr,            /* tp_str */
     5190        PyObject_GenericGetAttr,        /* tp_getattro */
     5191        0,                                                      /* tp_setattro */
     5192        0,                                                      /* tp_as_buffer */
     5193        Py_TPFLAGS_DEFAULT
     5194                |Py_TPFLAGS_HAVE_ITER,  /* tp_flags */
     5195        0,                                                      /* tp_doc */
     5196        0,                                                      /* tp_traverse */
     5197        0,                                                      /* tp_clear */
     5198        0,                                                      /* tp_richcompare */
     5199        0,                                                      /* tp_weaklistoffset */
     5200        (getiterfunc)queryGetIter,      /* tp_iter */
     5201        (iternextfunc)queryNext,        /* tp_iternext */
     5202        queryMethods,                           /* tp_methods */
    51025203};
    51035204
     
    54985599}
    54995600
    5500 /* get named result factory */
    5501 static char pgGetNamedresult__doc__[] =
    5502 "get_namedresult() -- get the function used for getting named results";
    5503 
    5504 static PyObject *
    5505 pgGetNamedresult(PyObject *self, PyObject *noargs)
     5601/* get dict result factory */
     5602static char pgGetDictiter__doc__[] =
     5603"get_dictiter() -- get the generator used for getting dict results";
     5604
     5605static PyObject *
     5606pgGetDictiter(PyObject *self, PyObject *noargs)
    55065607{
    55075608        PyObject *ret;
    55085609
    5509         ret = namedresult ? namedresult : Py_None;
     5610        ret = dictiter ? dictiter : Py_None;
    55105611        Py_INCREF(ret);
    55115612
     
    55135614}
    55145615
    5515 /* set named result factory */
    5516 static char pgSetNamedresult__doc__[] =
    5517 "set_namedresult(func) -- set a function to be used for getting named results";
    5518 
    5519 static PyObject *
    5520 pgSetNamedresult(PyObject *self, PyObject *func)
     5616/* set dict result factory */
     5617static char pgSetDictiter__doc__[] =
     5618"set_dictiter(func) -- set a generator to be used for getting dict results";
     5619
     5620static PyObject *
     5621pgSetDictiter(PyObject *self, PyObject *func)
    55215622{
    55225623        PyObject *ret = NULL;
     
    55245625        if (func == Py_None)
    55255626        {
    5526                 Py_XDECREF(namedresult); namedresult = NULL;
     5627                Py_XDECREF(dictiter); dictiter = NULL;
    55275628                Py_INCREF(Py_None); ret = Py_None;
    55285629        }
    55295630        else if (PyCallable_Check(func))
    55305631        {
    5531                 Py_XINCREF(func); Py_XDECREF(namedresult); namedresult = func;
     5632                Py_XINCREF(func); Py_XDECREF(dictiter); dictiter = func;
    55325633                Py_INCREF(Py_None); ret = Py_None;
    55335634        }
    55345635        else
    55355636                PyErr_SetString(PyExc_TypeError,
    5536                         "Function set_namedresult() expects"
     5637                        "Function set_dictiter() expects"
     5638                         " a callable or None as argument");
     5639
     5640        return ret;
     5641}
     5642
     5643/* get named result factory */
     5644static char pgGetNamediter__doc__[] =
     5645"get_namediter() -- get the generator used for getting named results";
     5646
     5647static PyObject *
     5648pgGetNamediter(PyObject *self, PyObject *noargs)
     5649{
     5650        PyObject *ret;
     5651
     5652        ret = namediter ? namediter : Py_None;
     5653        Py_INCREF(ret);
     5654
     5655        return ret;
     5656}
     5657
     5658/* set named result factory */
     5659static char pgSetNamediter__doc__[] =
     5660"set_namediter(func) -- set a generator to be used for getting named results";
     5661
     5662static PyObject *
     5663pgSetNamediter(PyObject *self, PyObject *func)
     5664{
     5665        PyObject *ret = NULL;
     5666
     5667        if (func == Py_None)
     5668        {
     5669                Py_XDECREF(namediter); namediter = NULL;
     5670                Py_INCREF(Py_None); ret = Py_None;
     5671        }
     5672        else if (PyCallable_Check(func))
     5673        {
     5674                Py_XINCREF(func); Py_XDECREF(namediter); namediter = func;
     5675                Py_INCREF(Py_None); ret = Py_None;
     5676        }
     5677        else
     5678                PyErr_SetString(PyExc_TypeError,
     5679                        "Function set_namediter() expects"
    55375680                         " a callable or None as argument");
    55385681
     
    60286171        {"set_bytea_escaped", (PyCFunction) pgSetByteaEscaped, METH_VARARGS,
    60296172                pgSetByteaEscaped__doc__},
    6030         {"get_namedresult", (PyCFunction) pgGetNamedresult, METH_NOARGS,
    6031                         pgGetNamedresult__doc__},
    6032         {"set_namedresult", (PyCFunction) pgSetNamedresult, METH_O,
    6033                         pgSetNamedresult__doc__},
     6173        {"get_dictiter", (PyCFunction) pgGetDictiter, METH_NOARGS,
     6174                        pgGetDictiter__doc__},
     6175        {"set_dictiter", (PyCFunction) pgSetDictiter, METH_O,
     6176                        pgSetDictiter__doc__},
     6177        {"get_namediter", (PyCFunction) pgGetNamediter, METH_NOARGS,
     6178                        pgGetNamediter__doc__},
     6179        {"set_namediter", (PyCFunction) pgSetNamediter, METH_O,
     6180                        pgSetNamediter__doc__},
     6181        /* get/set_namedresult is deprecated, use get/set_namediter */
     6182        {"get_namedresult", (PyCFunction) pgGetNamediter, METH_NOARGS,
     6183                        pgGetNamediter__doc__},
     6184        {"set_namedresult", (PyCFunction) pgSetNamediter, METH_O,
     6185                        pgSetNamediter__doc__},
    60346186        {"get_jsondecode", (PyCFunction) pgGetJsondecode, METH_NOARGS,
    60356187                        pgGetJsondecode__doc__},
  • trunk/py3c.h

    r780 r978  
    5252    PyMODINIT_FUNC PyInit_ ## name(void); \
    5353    PyMODINIT_FUNC PyInit_ ## name(void)
     54
     55/* Other */
     56
     57#define Py_TPFLAGS_HAVE_ITER 0 // not needed in Python 3
    5458
    5559#else
  • trunk/tests/test_classic_connection.py

    r969 r978  
    1919import os
    2020
    21 from collections import namedtuple
     21from collections import namedtuple, Iterable
    2222from decimal import Decimal
    2323
     
    550550        self.assertEqual(r, 3)
    551551
    552     def testNtuples(self):
     552    def testNtuples(self):  # deprecated
    553553        q = "select 1 where false"
    554554        r = self.c.query(q).ntuples()
     
    565565        self.assertIsInstance(r, int)
    566566        self.assertEqual(r, 6)
     567
     568    def testLen(self):
     569        q = "select 1 where false"
     570        self.assertEqual(len(self.c.query(q)), 0)
     571        q = ("select 1 as a, 2 as b, 3 as c, 4 as d"
     572            " union select 5 as a, 6 as b, 7 as c, 8 as d")
     573        self.assertEqual(len(self.c.query(q)), 2)
     574        q = ("select 1 union select 2 union select 3"
     575            " union select 4 union select 5 union select 6")
     576        self.assertEqual(len(self.c.query(q)), 6)
    567577
    568578    def testQuery(self):
     
    10971107    def testJson(self):
    10981108        self.assert_proper_cast('{}', 'json', dict)
     1109
     1110
     1111class TestQueryIterator(unittest.TestCase):
     1112    """Test the query operating as an iterator."""
     1113
     1114    def setUp(self):
     1115        self.c = connect()
     1116
     1117    def tearDown(self):
     1118        self.c.close()
     1119
     1120    def testLen(self):
     1121        r = self.c.query("select generate_series(3,7)")
     1122        self.assertEqual(len(r), 5)
     1123
     1124    def testGetItem(self):
     1125        r = self.c.query("select generate_series(7,9)")
     1126        self.assertEqual(r[0], (7,))
     1127        self.assertEqual(r[1], (8,))
     1128        self.assertEqual(r[2], (9,))
     1129
     1130    def testGetItemWithNegativeIndex(self):
     1131        r = self.c.query("select generate_series(7,9)")
     1132        self.assertEqual(r[-1], (9,))
     1133        self.assertEqual(r[-2], (8,))
     1134        self.assertEqual(r[-3], (7,))
     1135
     1136    def testGetItemOutOfRange(self):
     1137        r = self.c.query("select generate_series(7,9)")
     1138        self.assertRaises(IndexError, r.__getitem__, 3)
     1139
     1140    def testIterate(self):
     1141        r = self.c.query("select generate_series(3,5)")
     1142        self.assertNotIsInstance(r, (list, tuple))
     1143        self.assertIsInstance(r, Iterable)
     1144        self.assertEqual(list(r), [(3,), (4,), (5,)])
     1145        self.assertIsInstance(r[1], tuple)
     1146
     1147    def testIterateTwice(self):
     1148        r = self.c.query("select generate_series(3,5)")
     1149        for i in range(2):
     1150            self.assertEqual(list(r), [(3,), (4,), (5,)])
     1151
     1152    def testIterateTwoColumns(self):
     1153        r = self.c.query("select 1,2 union select 3,4")
     1154        self.assertIsInstance(r, Iterable)
     1155        self.assertEqual(list(r), [(1, 2), (3, 4)])
     1156
     1157    def testNext(self):
     1158        r = self.c.query("select generate_series(7,9)")
     1159        self.assertEqual(next(r), (7,))
     1160        self.assertEqual(next(r), (8,))
     1161        self.assertEqual(next(r), (9,))
     1162        self.assertRaises(StopIteration, next, r)
     1163
     1164    def testContains(self):
     1165        r = self.c.query("select generate_series(7,9)")
     1166        self.assertIn((8,), r)
     1167        self.assertNotIn((5,), r)
     1168
     1169    def testNamedIterate(self):
     1170        r = self.c.query("select generate_series(3,5) as number").namediter()
     1171        self.assertNotIsInstance(r, (list, tuple))
     1172        self.assertIsInstance(r, Iterable)
     1173        r = list(r)
     1174        self.assertEqual(r, [(3,), (4,), (5,)])
     1175        self.assertIsInstance(r[1], tuple)
     1176        self.assertEqual(r[1]._fields, ('number',))
     1177        self.assertEqual(r[1].number, 4)
     1178
     1179    def testNamedIterateTwoColumns(self):
     1180        r = self.c.query("select 1 as one, 2 as two"
     1181            " union select 3 as one, 4 as two").namediter()
     1182        self.assertIsInstance(r, Iterable)
     1183        r = list(r)
     1184        self.assertEqual(r, [(1, 2), (3, 4)])
     1185        self.assertEqual(r[0]._fields, ('one', 'two'))
     1186        self.assertEqual(r[0].one, 1)
     1187        self.assertEqual(r[1]._fields, ('one', 'two'))
     1188        self.assertEqual(r[1].two, 4)
     1189
     1190    def testNamedNext(self):
     1191        r = self.c.query("select generate_series(7,9) as number").namediter()
     1192        self.assertEqual(next(r), (7,))
     1193        self.assertEqual(next(r), (8,))
     1194        n = next(r)
     1195        self.assertEqual(n._fields, ('number',))
     1196        self.assertEqual(n.number, 9)
     1197        self.assertRaises(StopIteration, next, r)
     1198
     1199    def testNamedContains(self):
     1200        r = self.c.query("select generate_series(7,9)").namediter()
     1201        self.assertIn((8,), r)
     1202        self.assertNotIn((5,), r)
     1203
     1204    def testDictIterate(self):
     1205        r = self.c.query("select generate_series(3,5) as n").dictiter()
     1206        self.assertNotIsInstance(r, (list, tuple))
     1207        self.assertIsInstance(r, Iterable)
     1208        r = list(r)
     1209        self.assertEqual(r, [dict(n=3), dict(n=4), dict(n=5)])
     1210        self.assertIsInstance(r[1], dict)
     1211
     1212    def testDictIterateTwoColumns(self):
     1213        r = self.c.query("select 1 as one, 2 as two"
     1214            " union select 3 as one, 4 as two").dictiter()
     1215        self.assertIsInstance(r, Iterable)
     1216        r = list(r)
     1217        self.assertEqual(r, [dict(one=1, two=2), dict(one=3, two=4)])
     1218
     1219    def testDictNext(self):
     1220        r = self.c.query("select generate_series(7,9) as n").dictiter()
     1221        self.assertEqual(next(r), dict(n=7))
     1222        self.assertEqual(next(r), dict(n=8))
     1223        self.assertEqual(next(r), dict(n=9))
     1224        self.assertRaises(StopIteration, next, r)
     1225
     1226    def testNamedContains(self):
     1227        r = self.c.query("select generate_series(7,9) as n").dictiter()
     1228        self.assertIn(dict(n=8), r)
     1229        self.assertNotIn(dict(n=5), r)
    10991230
    11001231
     
    16151746            self.skipTest("cannot set English money locale")
    16161747        try:
    1617             r = query(select_money)
     1748            query(select_money)
    16181749        except pg.DataError:
    16191750            # this can happen if the currency signs cannot be
     
    16221753        pg.set_decimal_point(None)
    16231754        try:
    1624             r = r.getresult()[0][0]
     1755            r = query(select_money).getresult()[0][0]
    16251756        finally:
    16261757            pg.set_decimal_point(point)
    16271758        self.assertIsInstance(r, str)
    16281759        self.assertIn(r, en_money)
    1629         r = query(select_money)
    16301760        pg.set_decimal_point('')
    16311761        try:
    1632             r = r.getresult()[0][0]
     1762            r = query(select_money).getresult()[0][0]
    16331763        finally:
    16341764            pg.set_decimal_point(point)
    16351765        self.assertIsInstance(r, str)
    16361766        self.assertIn(r, en_money)
    1637         r = query(select_money)
    16381767        pg.set_decimal_point('.')
    16391768        try:
    1640             r = r.getresult()[0][0]
     1769            r = query(select_money).getresult()[0][0]
    16411770        finally:
    16421771            pg.set_decimal_point(point)
    16431772        self.assertIsInstance(r, d)
    16441773        self.assertEqual(r, proper_money)
    1645         r = query(select_money)
    16461774        pg.set_decimal_point(',')
    16471775        try:
    1648             r = r.getresult()[0][0]
     1776            r = query(select_money).getresult()[0][0]
    16491777        finally:
    16501778            pg.set_decimal_point(point)
    16511779        self.assertIsInstance(r, d)
    16521780        self.assertEqual(r, bad_money)
    1653         r = query(select_money)
    16541781        pg.set_decimal_point("'")
    16551782        try:
    1656             r = r.getresult()[0][0]
     1783            r = query(select_money).getresult()[0][0]
    16571784        finally:
    16581785            pg.set_decimal_point(point)
     
    16711798        select_money = select_money.replace('.', ',')
    16721799        try:
    1673             r = query(select_money)
     1800            query(select_money)
    16741801        except pg.DataError:
    16751802            self.skipTest("database does not support English money")
    16761803        pg.set_decimal_point(None)
    16771804        try:
    1678             r = r.getresult()[0][0]
     1805            r = query(select_money).getresult()[0][0]
    16791806        finally:
    16801807            pg.set_decimal_point(point)
    16811808        self.assertIsInstance(r, str)
    16821809        self.assertIn(r, de_money)
    1683         r = query(select_money)
    16841810        pg.set_decimal_point('')
    16851811        try:
    1686             r = r.getresult()[0][0]
     1812            r = query(select_money).getresult()[0][0]
    16871813        finally:
    16881814            pg.set_decimal_point(point)
    16891815        self.assertIsInstance(r, str)
    16901816        self.assertIn(r, de_money)
    1691         r = query(select_money)
    16921817        pg.set_decimal_point(',')
    16931818        try:
    1694             r = r.getresult()[0][0]
     1819            r = query(select_money).getresult()[0][0]
    16951820        finally:
    16961821            pg.set_decimal_point(point)
    16971822        self.assertIsInstance(r, d)
    16981823        self.assertEqual(r, proper_money)
    1699         r = query(select_money)
    17001824        pg.set_decimal_point('.')
    17011825        try:
    1702             r = r.getresult()[0][0]
     1826            r = query(select_money).getresult()[0][0]
    17031827        finally:
    17041828            pg.set_decimal_point(point)
    17051829        self.assertEqual(r, bad_money)
    1706         r = query(select_money)
    17071830        pg.set_decimal_point("'")
    17081831        try:
    1709             r = r.getresult()[0][0]
     1832            r = query(select_money).getresult()[0][0]
    17101833        finally:
    17111834            pg.set_decimal_point(point)
     
    17951918        self.assertIsInstance(r, bool)
    17961919        self.assertEqual(r, True)
    1797         r = query("select true::bool")
    17981920        pg.set_bool(False)
    17991921        try:
    1800             r = r.getresult()[0][0]
     1922            r = query("select true::bool").getresult()[0][0]
    18011923        finally:
    18021924            pg.set_bool(use_bool)
    18031925        self.assertIsInstance(r, str)
    18041926        self.assertIs(r, 't')
    1805         r = query("select true::bool")
    18061927        pg.set_bool(True)
    18071928        try:
    1808             r = r.getresult()[0][0]
     1929            r = query("select true::bool").getresult()[0][0]
    18091930        finally:
    18101931            pg.set_bool(use_bool)
     
    18591980        self.assertIsInstance(r, bytes)
    18601981        self.assertEqual(r, b'data')
    1861         r = query("select 'data'::bytea")
    18621982        pg.set_bytea_escaped(True)
    18631983        try:
    1864             r = r.getresult()[0][0]
     1984            r = query("select 'data'::bytea").getresult()[0][0]
    18651985        finally:
    18661986            pg.set_bytea_escaped(bytea_escaped)
    18671987        self.assertIsInstance(r, str)
    18681988        self.assertEqual(r, '\\x64617461')
    1869         r = query("select 'data'::bytea")
    18701989        pg.set_bytea_escaped(False)
    18711990        try:
    1872             r = r.getresult()[0][0]
     1991            r = query("select 'data'::bytea").getresult()[0][0]
    18731992        finally:
    18741993            pg.set_bytea_escaped(bytea_escaped)
     
    18761995        self.assertEqual(r, b'data')
    18771996
    1878     def testGetNamedresult(self):
     1997    def testGetDictditer(self):
     1998        dictiter = pg.get_dictiter()
     1999        # error if a parameter is passed
     2000        self.assertRaises(TypeError, pg.get_dictiter, dictiter)
     2001        self.assertIs(dictiter, pg._dictiter)  # the default setting
     2002
     2003    def testSetDictiter(self):
     2004        dictiter = pg.get_dictiter()
     2005        self.assertTrue(callable(dictiter))
     2006
     2007        query = self.c.query
     2008
     2009        r = query("select 1 as x, 2 as y").dictiter()
     2010        self.assertNotIsInstance(r, list)
     2011        r = next(r)
     2012        self.assertIsInstance(r, dict)
     2013        self.assertEqual(r, dict(x=1, y=2))
     2014
     2015        def listiter(q):
     2016            for row in q:
     2017                yield list(row)
     2018
     2019        pg.set_dictiter(listiter)
     2020        try:
     2021            r = pg.get_dictiter()
     2022            self.assertIs(r, listiter)
     2023            r = query("select 1 as x, 2 as y").dictiter()
     2024            self.assertNotIsInstance(r, list)
     2025            r = next(r)
     2026            self.assertIsInstance(r, list)
     2027            self.assertEqual(r, [1, 2])
     2028            self.assertNotIsInstance(r, dict)
     2029        finally:
     2030            pg.set_dictiter(dictiter)
     2031
     2032        r = pg.get_dictiter()
     2033        self.assertIs(r, dictiter)
     2034
     2035    def testGetNamediter(self):
     2036        namediter = pg.get_namediter()
     2037        # error if a parameter is passed
     2038        self.assertRaises(TypeError, pg.get_namediter, namediter)
     2039        self.assertIs(namediter, pg._namediter)  # the default setting
     2040
     2041    def testSetNamediter(self):
     2042        namediter = pg.get_namediter()
     2043        self.assertTrue(callable(namediter))
     2044
     2045        query = self.c.query
     2046
     2047        r = query("select 1 as x, 2 as y").namediter()
     2048        self.assertNotIsInstance(r, list)
     2049        r = next(r)
     2050        self.assertIsInstance(r, tuple)
     2051        self.assertEqual(r, (1, 2))
     2052        self.assertIsNot(type(r), tuple)
     2053        self.assertEqual(r._fields, ('x', 'y'))
     2054        self.assertEqual(r._asdict(), {'x': 1, 'y': 2})
     2055        self.assertEqual(r.__class__.__name__, 'Row')
     2056        r = query("select 1 as x, 2 as y").namedresult()
     2057        self.assertIsInstance(r, list)
     2058        r = r[0]
     2059        self.assertIsInstance(r, tuple)
     2060        self.assertEqual(r, (1, 2))
     2061        self.assertIsNot(type(r), tuple)
     2062        self.assertEqual(r._fields, ('x', 'y'))
     2063        self.assertEqual(r._asdict(), {'x': 1, 'y': 2})
     2064        self.assertEqual(r.__class__.__name__, 'Row')
     2065
     2066        def listiter(q):
     2067            for row in q:
     2068                yield list(row)
     2069
     2070        pg.set_namediter(listiter)
     2071        try:
     2072            r = pg.get_namediter()
     2073            self.assertIs(r, listiter)
     2074            r = query("select 1 as x, 2 as y").namediter()
     2075            self.assertNotIsInstance(r, list)
     2076            r = next(r)
     2077            self.assertIsInstance(r, list)
     2078            self.assertEqual(r, [1, 2])
     2079            self.assertIsNot(type(r), tuple)
     2080            self.assertFalse(hasattr(r, '_fields'))
     2081            self.assertNotEqual(r.__class__.__name__, 'Row')
     2082            r = query("select 1 as x, 2 as y").namedresult()
     2083            self.assertIsInstance(r, list)
     2084            r = r[0]
     2085            self.assertIsInstance(r, list)
     2086            self.assertEqual(r, [1, 2])
     2087            self.assertIsNot(type(r), tuple)
     2088            self.assertFalse(hasattr(r, '_fields'))
     2089            self.assertNotEqual(r.__class__.__name__, 'Row')
     2090        finally:
     2091            pg.set_namediter(namediter)
     2092
     2093        r = pg.get_namediter()
     2094        self.assertIs(r, namediter)
     2095
     2096    def testGetNamedresult(self):  # deprecated
    18792097        namedresult = pg.get_namedresult()
    18802098        # error if a parameter is passed
    18812099        self.assertRaises(TypeError, pg.get_namedresult, namedresult)
    1882         self.assertIs(namedresult, pg._namedresult)  # the default setting
    1883 
    1884     def testSetNamedresult(self):
     2100        self.assertIs(namedresult, pg._namediter)  # the default setting
     2101
     2102    def testSetNamedresult(self):  # deprecated
    18852103        namedresult = pg.get_namedresult()
    18862104        self.assertTrue(callable(namedresult))
  • trunk/tests/test_classic_functions.py

    r969 r978  
    10061006        self.assertIs(r, bytea_escaped)
    10071007
    1008     def testGetNamedresult(self):
     1008    def testGetDictiter(self):
     1009        r = pg.get_dictiter()
     1010        self.assertTrue(callable(r))
     1011        self.assertIs(r, pg._dictiter)
     1012
     1013    def testSetDictiter(self):
     1014        dictiter = pg.get_dictiter()
     1015        try:
     1016            pg.set_dictiter(None)
     1017            r = pg.get_dictiter()
     1018            self.assertIsNone(r)
     1019            f = lambda q: q
     1020            pg.set_dictiter(f)
     1021            r = pg.get_dictiter()
     1022            self.assertIs(r, f)
     1023            self.assertRaises(TypeError, pg.set_dictiter, 'invalid')
     1024        finally:
     1025            pg.set_dictiter(dictiter)
     1026        r = pg.get_dictiter()
     1027        self.assertIs(r, dictiter)
     1028
     1029    def testGetNamediter(self):
     1030        r = pg.get_namediter()
     1031        self.assertTrue(callable(r))
     1032        self.assertIs(r, pg._namediter)
     1033
     1034    def testSetNamediter(self):
     1035        namediter = pg.get_namediter()
     1036        try:
     1037            pg.set_namediter(None)
     1038            r = pg.get_namediter()
     1039            self.assertIsNone(r)
     1040            f = lambda q: q
     1041            pg.set_namediter(f)
     1042            r = pg.get_namediter()
     1043            self.assertIs(r, f)
     1044            self.assertRaises(TypeError, pg.set_namediter, 'invalid')
     1045        finally:
     1046            pg.set_namediter(namediter)
     1047        r = pg.get_namediter()
     1048        self.assertIs(r, namediter)
     1049
     1050    def testGetNamedresult(self):  # deprecated
    10091051        r = pg.get_namedresult()
    10101052        self.assertTrue(callable(r))
    1011         self.assertIs(r, pg._namedresult)
    1012 
    1013     def testSetNamedresult(self):
     1053        self.assertIs(r, pg._namediter)
     1054
     1055    def testSetNamedresult(self):  # deprecated
    10141056        namedresult = pg.get_namedresult()
    10151057        try:
Note: See TracChangeset for help on using the changeset viewer.