cursor.py 9.2 KB
Newer Older
1 2
# encoding:UTF-8
from .cinterface import *
S
slguan 已提交
3
from .error import *
4
from .constants import FieldType
5
from .result import *
S
slguan 已提交
6

7

8
class TaosCursor(object):
S
slguan 已提交
9 10 11 12 13
    """Database cursor which is used to manage the context of a fetch operation.

    Attributes:
        .description: Read-only attribute consists of 7-item sequences:

14 15
            > name (mandatory)
            > type_code (mandatory)
S
slguan 已提交
16 17 18 19 20 21 22 23 24 25
            > display_size
            > internal_size
            > precision
            > scale
            > null_ok

            This attribute will be None for operations that do not return rows or
            if the cursor has not had an operation invoked via the .execute*() method yet.

        .rowcount:This read-only attribute specifies the number of rows that the last
26
            .execute*() produced (for DQL statements like SELECT) or affected
S
slguan 已提交
27 28 29
    """

    def __init__(self, connection=None):
30
        self._description = []
S
slguan 已提交
31 32 33 34 35 36 37
        self._rowcount = -1
        self._connection = None
        self._result = None
        self._fields = None
        self._block = None
        self._block_rows = -1
        self._block_iter = 0
38
        self._affected_rows = 0
S
Shuduo Sang 已提交
39
        self._logfile = ""
S
slguan 已提交
40 41 42 43 44 45 46 47

        if connection is not None:
            self._connection = connection

    def __iter__(self):
        return self

    def __next__(self):
48 49 50 51 52 53
        return self._taos_next()

    def next(self):
        return self._taos_next()

    def _taos_next(self):
S
slguan 已提交
54 55 56 57
        if self._result is None or self._fields is None:
            raise OperationalError("Invalid use of fetch iterator")

        if self._block_rows <= self._block_iter:
58
            block, self._block_rows = taos_fetch_row(self._result, self._fields)
S
slguan 已提交
59 60 61 62 63
            if self._block_rows == 0:
                raise StopIteration
            self._block = list(map(tuple, zip(*block)))
            self._block_iter = 0

64
        data = self._block[self._block_iter]
S
slguan 已提交
65 66 67 68 69 70
        self._block_iter += 1

        return data

    @property
    def description(self):
71
        """Return the description of the object."""
S
slguan 已提交
72 73 74 75
        return self._description

    @property
    def rowcount(self):
76
        """Return the rowcount of the object"""
S
slguan 已提交
77 78
        return self._rowcount

79 80
    @property
    def affected_rows(self):
81
        """Return the rowcount of insertion"""
82 83
        return self._affected_rows

S
slguan 已提交
84 85 86 87 88 89 90
    def callproc(self, procname, *args):
        """Call a stored database procedure with the given name.

        Void functionality since no stored procedures.
        """
        pass

S
Shuduo Sang 已提交
91 92 93
    def log(self, logfile):
        self._logfile = logfile

S
slguan 已提交
94
    def close(self):
95
        """Close the cursor."""
S
slguan 已提交
96 97
        if self._connection is None:
            return False
98

S
slguan 已提交
99 100 101 102 103 104
        self._reset_result()
        self._connection = None

        return True

    def execute(self, operation, params=None):
105
        """Prepare and execute a database operation (query or command)."""
S
slguan 已提交
106 107 108 109 110 111
        if not operation:
            return None

        if not self._connection:
            # TODO : change the exception raised here
            raise ProgrammingError("Cursor is not connected")
112

S
slguan 已提交
113 114 115 116 117
        self._reset_result()

        stmt = operation
        if params is not None:
            pass
118 119 120

        # global querySeqNum
        # querySeqNum += 1
121
        # localSeqNum = querySeqNum # avoid race condition
122
        # print("   >> Exec Query ({}): {}".format(localSeqNum, str(stmt)))
123
        self._result = taos_query(self._connection._conn, stmt)
124
        # print("   << Query ({}) Exec Done".format(localSeqNum))
125
        if self._logfile:
S
Shuduo Sang 已提交
126 127 128
            with open(self._logfile, "a") as logfile:
                logfile.write("%s;\n" % operation)

129 130 131 132
        if taos_field_count(self._result) == 0:
            affected_rows = taos_affected_rows(self._result)
            self._affected_rows += affected_rows
            return affected_rows
S
slguan 已提交
133
        else:
134 135
            self._fields = taos_fetch_fields(self._result)
            return self._handle_result()
S
slguan 已提交
136 137

    def executemany(self, operation, seq_of_parameters):
138
        """Prepare a database operation (query or command) and then execute it against all parameter sequences or mappings found in the sequence seq_of_parameters."""
S
slguan 已提交
139 140 141
        pass

    def fetchone(self):
142
        """Fetch the next row of a query result set, returning a single sequence, or None when no more data is available."""
S
slguan 已提交
143 144 145 146 147
        pass

    def fetchmany(self):
        pass

148
    def istype(self, col, dataType):
149 150
        if dataType.upper() == "BOOL":
            if self._description[col][1] == FieldType.C_BOOL:
151
                return True
152 153
        if dataType.upper() == "TINYINT":
            if self._description[col][1] == FieldType.C_TINYINT:
154
                return True
155 156
        if dataType.upper() == "TINYINT UNSIGNED":
            if self._description[col][1] == FieldType.C_TINYINT_UNSIGNED:
157
                return True
158 159
        if dataType.upper() == "SMALLINT":
            if self._description[col][1] == FieldType.C_SMALLINT:
160
                return True
161 162
        if dataType.upper() == "SMALLINT UNSIGNED":
            if self._description[col][1] == FieldType.C_SMALLINT_UNSIGNED:
163
                return True
164 165
        if dataType.upper() == "INT":
            if self._description[col][1] == FieldType.C_INT:
166
                return True
167 168
        if dataType.upper() == "INT UNSIGNED":
            if self._description[col][1] == FieldType.C_INT_UNSIGNED:
169
                return True
170 171
        if dataType.upper() == "BIGINT":
            if self._description[col][1] == FieldType.C_BIGINT:
172
                return True
173 174
        if dataType.upper() == "BIGINT UNSIGNED":
            if self._description[col][1] == FieldType.C_BIGINT_UNSIGNED:
175
                return True
176 177
        if dataType.upper() == "FLOAT":
            if self._description[col][1] == FieldType.C_FLOAT:
178
                return True
179 180
        if dataType.upper() == "DOUBLE":
            if self._description[col][1] == FieldType.C_DOUBLE:
181
                return True
182 183
        if dataType.upper() == "BINARY":
            if self._description[col][1] == FieldType.C_BINARY:
184
                return True
185 186
        if dataType.upper() == "TIMESTAMP":
            if self._description[col][1] == FieldType.C_TIMESTAMP:
187
                return True
188 189
        if dataType.upper() == "NCHAR":
            if self._description[col][1] == FieldType.C_NCHAR:
190
                return True
191 192 193 194 195
        if dataType.upper() == "JSON BINARY":
            if self._description[col][1] == FieldType.C_JSON_BINARY:
                return True
        if dataType.upper() == "JSON NCHAR":
            if self._description[col][1] == FieldType.C_JSON_NCHAR:
wmmhello's avatar
wmmhello 已提交
196
                return True
197 198 199

        return False

200
    def fetchall_row(self):
201
        """Fetch all (remaining) rows of a query result, returning them as a sequence of sequences (e.g. a list of tuples). Note that the cursor's arraysize attribute can affect the performance of this operation."""
S
slguan 已提交
202 203
        if self._result is None or self._fields is None:
            raise OperationalError("Invalid use of fetchall")
204

S
slguan 已提交
205 206 207
        buffer = [[] for i in range(len(self._fields))]
        self._rowcount = 0
        while True:
208 209
            block, num_of_fields = taos_fetch_row(self._result, self._fields)
            errno = taos_errno(self._result)
B
Bomin Zhang 已提交
210
            if errno != 0:
211
                raise ProgrammingError(taos_errstr(self._result), errno)
212 213
            if num_of_fields == 0:
                break
S
slguan 已提交
214 215 216
            self._rowcount += num_of_fields
            for i in range(len(self._fields)):
                buffer[i].extend(block[i])
217
        return list(map(tuple, zip(*buffer)))
S
slguan 已提交
218

219
    def fetchall(self):
220
        if self._result is None:
221
            raise OperationalError("Invalid use of fetchall")
222 223
        fields = self._fields if self._fields is not None else taos_fetch_fields(self._result)
        buffer = [[] for i in range(len(fields))]
224 225
        self._rowcount = 0
        while True:
226 227
            block, num_of_fields = taos_fetch_block(self._result, self._fields)
            errno = taos_errno(self._result)
228
            if errno != 0:
229
                raise ProgrammingError(taos_errstr(self._result), errno)
230 231
            if num_of_fields == 0:
                break
232 233 234 235
            self._rowcount += num_of_fields
            for i in range(len(self._fields)):
                buffer[i].extend(block[i])
        return list(map(tuple, zip(*buffer)))
236

237 238 239 240
    def stop_query(self):
        if self._result != None:
            taos_stop_query(self._result)
            
S
slguan 已提交
241
    def nextset(self):
242
        """ """
S
slguan 已提交
243 244 245 246 247 248 249 250 251
        pass

    def setinputsize(self, sizes):
        pass

    def setutputsize(self, size, column=None):
        pass

    def _reset_result(self):
252
        """Reset the result to unused version."""
253
        self._description = []
S
slguan 已提交
254
        self._rowcount = -1
T
Tao Liu 已提交
255
        if self._result is not None:
256
            taos_free_result(self._result)
S
slguan 已提交
257 258 259 260 261
        self._result = None
        self._fields = None
        self._block = None
        self._block_rows = -1
        self._block_iter = 0
262
        self._affected_rows = 0
263

S
slguan 已提交
264
    def _handle_result(self):
265
        """Handle the return result from query."""
S
slguan 已提交
266 267
        self._description = []
        for ele in self._fields:
268
            self._description.append((ele["name"], ele["type"], None, None, None, None, False))
269

270
        return self._result
271 272 273

    def __del__(self):
        self.close()