mirror of
https://github.com/mariadb-corporation/mariadb-connector-python.git
synced 2025-07-28 06:40:03 +00:00
connection and cursor class are now written in
native python
This commit is contained in:
@ -90,9 +90,29 @@ int clock_gettime(int dummy, struct timespec *ct);
|
||||
#define MAX_TPC_XID_SIZE 64
|
||||
#define POOL_DEFAULT_SIZE 5
|
||||
|
||||
/* Placeholder for missing documentation */
|
||||
#define MISSING_DOC NULL
|
||||
|
||||
/* Magic constant for checking dynamic columns */
|
||||
#define PYTHON_DYNCOL_VALUE 0xA378BD8E
|
||||
|
||||
typedef struct st_lex_str {
|
||||
char *str;
|
||||
size_t length;
|
||||
} MrdbString;
|
||||
|
||||
enum enum_binary_command {
|
||||
SQL_NONE= 0,
|
||||
SQL_INSERT,
|
||||
SQL_UPDATE,
|
||||
SQL_REPLACE,
|
||||
SQL_DELETE,
|
||||
SQL_CALL,
|
||||
SQL_DO,
|
||||
SQL_SELECT,
|
||||
SQL_OTHER=255
|
||||
};
|
||||
|
||||
enum enum_extended_field_type
|
||||
{
|
||||
EXT_TYPE_NONE=0,
|
||||
@ -125,19 +145,15 @@ enum enum_tpc_state
|
||||
|
||||
enum enum_paramstyle
|
||||
{
|
||||
NONE=0,
|
||||
QMARK,
|
||||
FORMAT,
|
||||
PYFORMAT
|
||||
NONE= 0,
|
||||
QMARK= 1,
|
||||
FORMAT= 2,
|
||||
PYFORMAT= 3
|
||||
};
|
||||
|
||||
typedef struct st_lex_str {
|
||||
char *str;
|
||||
size_t length;
|
||||
} MrdbString;
|
||||
|
||||
typedef struct st_parser {
|
||||
MrdbString statement;
|
||||
MrdbString *keys;
|
||||
uint8_t in_literal[3];
|
||||
uint8_t in_comment;
|
||||
uint8_t in_values;
|
||||
@ -146,8 +162,9 @@ typedef struct st_parser {
|
||||
uint32_t param_count;
|
||||
uint32_t key_count;
|
||||
char* value_ofs;
|
||||
PyObject *param_list;
|
||||
enum enum_paramstyle paramstyle;
|
||||
MrdbString *keys;
|
||||
enum enum_binary_command command;
|
||||
MYSQL *mysql;
|
||||
} MrdbParser;
|
||||
|
||||
@ -170,6 +187,7 @@ typedef struct {
|
||||
const char *collation;
|
||||
uint8_t inuse;
|
||||
uint8_t status;
|
||||
uint8_t asynchronous;
|
||||
struct timespec last_used;
|
||||
/* capabilities */
|
||||
unsigned long client_capabilities;
|
||||
@ -222,6 +240,16 @@ typedef struct {
|
||||
MYSQL_TIME tm;
|
||||
} MrdbParamValue;
|
||||
|
||||
typedef struct {
|
||||
char *statement;
|
||||
Py_ssize_t statement_len;
|
||||
enum enum_paramstyle paramstyle;
|
||||
uint32_t paramcount;
|
||||
uint8_t is_text;
|
||||
PyObject *paramlist;
|
||||
PyObject *keys;
|
||||
} MrdbParseInfo;
|
||||
|
||||
/* PEP-249: Cursor object */
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
@ -230,7 +258,6 @@ typedef struct {
|
||||
MYSQL_RES *result;
|
||||
PyObject *data;
|
||||
uint32_t array_size;
|
||||
uint32_t param_count;
|
||||
uint32_t row_array_size; /* for fetch many */
|
||||
MrdbParamInfo *paraminfo;
|
||||
MrdbParamValue *value;
|
||||
@ -238,10 +265,11 @@ typedef struct {
|
||||
MYSQL_BIND *bind;
|
||||
MYSQL_FIELD *fields;
|
||||
char *statement;
|
||||
unsigned long statement_len;
|
||||
size_t statement_len;
|
||||
PyObject **values;
|
||||
PyStructSequence_Field *sequence_fields;
|
||||
PyTypeObject *sequence_type;
|
||||
MrdbParseInfo parseinfo;
|
||||
unsigned long prefetch_rows;
|
||||
unsigned long cursor_type;
|
||||
int64_t affected_rows;
|
||||
@ -251,13 +279,12 @@ typedef struct {
|
||||
unsigned long row_number;
|
||||
enum enum_result_format result_format;
|
||||
uint8_t is_prepared;
|
||||
uint8_t is_buffered;
|
||||
char is_buffered;
|
||||
uint8_t fetched;
|
||||
uint8_t is_closed;
|
||||
uint8_t is_text;
|
||||
uint8_t is_binary;
|
||||
MrdbParser *parser;
|
||||
uint8_t reprepare;
|
||||
PyThreadState *thread_state;
|
||||
enum enum_paramstyle paramstyle;
|
||||
} MrdbCursor;
|
||||
|
||||
typedef struct
|
||||
@ -309,9 +336,6 @@ mariadb_throw_exception(void *handle,
|
||||
|
||||
enum enum_extended_field_type mariadb_extended_field_type(const MYSQL_FIELD *field);
|
||||
|
||||
PyObject *
|
||||
MrdbConnection_affected_rows(MrdbConnection *self);
|
||||
|
||||
PyObject *
|
||||
MrdbConnection_ping(MrdbConnection *self);
|
||||
|
||||
|
@ -8,7 +8,6 @@ Minimum supported Python version is 3.6
|
||||
'''
|
||||
|
||||
from ._mariadb import (
|
||||
Binary,
|
||||
DataError,
|
||||
DatabaseError,
|
||||
Error,
|
||||
@ -30,6 +29,7 @@ _POOLS= _CONNECTION_POOLS= {}
|
||||
from mariadb.dbapi20 import *
|
||||
from mariadb.connectionpool import *
|
||||
from mariadb.cursor import Cursor
|
||||
from mariadb.async_connections import *
|
||||
from mariadb.release_info import __version__ as __version__
|
||||
from mariadb.release_info import __version_info__ as __version_info__
|
||||
from mariadb.release_info import __author__ as __author__
|
||||
@ -43,14 +43,18 @@ def Binary(obj):
|
||||
|
||||
def connect(*args, **kwargs):
|
||||
from mariadb.connections import Connection
|
||||
if kwargs and "pool_name" in kwargs:
|
||||
if not kwargs["pool_name"] in mariadb._CONNECTION_POOLS:
|
||||
pool= mariadb.ConnectionPool(**kwargs)
|
||||
else:
|
||||
pool= mariadb._CONNECTION_POOLS[kwargs["pool_name"]]
|
||||
c= pool.get_connection()
|
||||
return c
|
||||
if kwargs:
|
||||
if "pool_name" in kwargs:
|
||||
if not kwargs["pool_name"] in mariadb._CONNECTION_POOLS:
|
||||
pool= mariadb.ConnectionPool(**kwargs)
|
||||
else:
|
||||
pool= mariadb._CONNECTION_POOLS[kwargs["pool_name"]]
|
||||
c= pool.get_connection()
|
||||
return c
|
||||
is_async= kwargs.get("asynchronous", False)
|
||||
if is_async:
|
||||
return AsyncConnection(*args, **kwargs)
|
||||
|
||||
return Connection(*args, **kwargs)
|
||||
|
||||
Connection= connect
|
||||
|
||||
|
BIN
mariadb/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
mariadb/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
95
mariadb/async_connections.py
Normal file
95
mariadb/async_connections.py
Normal file
@ -0,0 +1,95 @@
|
||||
#
|
||||
# Copyright (C) 2021 Georg Richter and MariaDB Corporation AB
|
||||
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Library General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later version.
|
||||
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Library General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU Library General Public
|
||||
# License along with this library; if not see <http://www.gnu.org/licenses>
|
||||
# or write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
|
||||
#
|
||||
|
||||
import mariadb
|
||||
import socket
|
||||
import time
|
||||
|
||||
from mariadb.constants import STATUS
|
||||
|
||||
_DEFAULT_CHARSET = "utf8mb4"
|
||||
_DEFAULT_COLLATION = "utf8mb4_general_ci"
|
||||
|
||||
class AsyncConnection(mariadb._mariadb.connection):
|
||||
"""MariaDB connection class"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._socket= None
|
||||
self.__in_use= 0
|
||||
self.__pool = None
|
||||
self.__last_used = 0
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
async def _execute_command(self, command):
|
||||
print("comand: ")
|
||||
print(command)
|
||||
super().query(command)
|
||||
|
||||
async def _read_response(self):
|
||||
super()._read_response()
|
||||
|
||||
async def query(self, command):
|
||||
await self._execute_command(command)
|
||||
await self._read_response()
|
||||
|
||||
def cursor(self, **kwargs):
|
||||
return mariadb.Cursor(self, **kwargs)
|
||||
|
||||
|
||||
def close(self):
|
||||
if self._Connection__pool:
|
||||
self._Connection__pool._close_connection(self)
|
||||
else:
|
||||
super().close()
|
||||
|
||||
def __enter__(self):
|
||||
"Returns a copy of the connection."
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
"Closes connection."
|
||||
self.close()
|
||||
|
||||
@property
|
||||
def character_set(self):
|
||||
"""Client character set."""
|
||||
return _DEFAULT_CHARSET
|
||||
|
||||
@property
|
||||
def collation(self):
|
||||
"""Client character set collation"""
|
||||
return _DEFAULT_COLLATION
|
||||
|
||||
@property
|
||||
def server_status(self):
|
||||
"""Returns server status flags."""
|
||||
return super()._server_status
|
||||
|
||||
@property
|
||||
def socket(self):
|
||||
"""Returns the socket used for database connection"""
|
||||
|
||||
fno= self.get_socket()
|
||||
if not self._socket:
|
||||
self._socket= socket.socket(fileno=fno)
|
||||
# in case of a possible reconnect, file descriptor has changed
|
||||
elif fno != self._socket.fileno():
|
||||
self._socket= socket.socket(fileno=fno)
|
||||
return self._socket
|
53
mariadb/codecs.py
Normal file
53
mariadb/codecs.py
Normal file
@ -0,0 +1,53 @@
|
||||
from mariadb.constants import FIELD_TYPE
|
||||
import decimal
|
||||
|
||||
|
||||
def get_mariadb_type(value):
|
||||
""" get corresponding MariaDB field type for given Python object """
|
||||
|
||||
if value is None:
|
||||
return FIELD_TYPE.NULL
|
||||
|
||||
if isinstance(value, int):
|
||||
if value.bit_length() < 9:
|
||||
return FIELD_TYPE.TINY
|
||||
if value.bit_length() < 17:
|
||||
return FIELD_TYPE.SHORT
|
||||
return FIELD_TYPE.LONG
|
||||
|
||||
if isinstance(value, float):
|
||||
return FIELD_TYPE.DOUBLE
|
||||
|
||||
if isinstance(value, decimal.Decimal):
|
||||
return FIELD_TYPE.NEWDECIMAL
|
||||
|
||||
if isinstance(value,str):
|
||||
return FIELD_TYPE.VAR_STRING
|
||||
|
||||
if isinstance(value, datetime.date):
|
||||
return FIELD_TYPE.DATE
|
||||
|
||||
if isinstance(value, datetime.time):
|
||||
return FIELD_TYPE.TIME
|
||||
|
||||
if isinstance(value, datetime.datetime):
|
||||
return FIELD_TYPE.DATETIME
|
||||
|
||||
if isinstance(value, bytes):
|
||||
return FIELD_TYPE.LONG_BLOB
|
||||
|
||||
raise mariadb.DataError("Unknown or not supported datatype")
|
||||
|
||||
def get_execute_parameter_types(cursor):
|
||||
"""
|
||||
returns bytearray with MariaDB parameter types
|
||||
"""
|
||||
param_types= bytearray()
|
||||
|
||||
if cursor.paramcount == 0:
|
||||
raise mariadb.DataError("Invalid number of parameters")
|
||||
|
||||
for column_value in cursor._data:
|
||||
param_types.append(get_mariadb_type(column_value))
|
||||
|
||||
return param_types
|
@ -36,7 +36,7 @@ class Connection(mariadb._mariadb.connection):
|
||||
self.__last_used = 0
|
||||
|
||||
# self._autocommit= kwargs.pop("autocommit", True)
|
||||
# self._converter= kwargs.pop("converter", None)
|
||||
self._converter= kwargs.pop("converter", None)
|
||||
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
|
@ -26,3 +26,9 @@ CAN_HANDLE_EXPIRED_PASSWORDS = 1 < 22
|
||||
SESSION_TRACKING = 1 << 23
|
||||
SSL_VERIFY_SERVER_CERT = 1 << 30
|
||||
REMEMBER_OPTIONS = 1 << 31
|
||||
|
||||
# MariaDB specific capabilities
|
||||
PROGRESS = 1 << 32
|
||||
BULK_OPERATIONS = 1 << 34
|
||||
EXTENDED_METADATA = 1 << 35
|
||||
CACHE_METDATA = 1 << 36
|
||||
|
20
mariadb/constants/STATUS.py
Normal file
20
mariadb/constants/STATUS.py
Normal file
@ -0,0 +1,20 @@
|
||||
''' MariaDB status flags
|
||||
|
||||
These flas describe the current status of the database server.
|
||||
'''
|
||||
|
||||
IN_TRANS = 1
|
||||
AUTOCOMMIT = 2
|
||||
MORE_RESULTS_EXIST = 8
|
||||
QUERY_NO_GOOD_INDEX_USED =16
|
||||
QUERY_NO_INDEX_USED = 32
|
||||
CURSOR_EXISTS = 64
|
||||
LAST_ROW_SENT = 128
|
||||
DB_DROPPED = 256
|
||||
NO_BACKSLASH_ESCAPES = 512
|
||||
METADATA_CHANGED = 1024
|
||||
QUERY_WAS_SLOW = 2048
|
||||
PS_OUT_PARAMS = 4096
|
||||
IN_TRANS_READONLY = 8192
|
||||
SESSION_STATE_CHANGED = 16384
|
||||
ANSI_QUOTES = 32768
|
259
mariadb/cursor.py
Normal file
259
mariadb/cursor.py
Normal file
@ -0,0 +1,259 @@
|
||||
#
|
||||
# Copyright (C) 2020-2021 Georg Richter and MariaDB Corporation AB
|
||||
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Library General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later version.
|
||||
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Library General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU Library General Public
|
||||
# License along with this library; if not see <http://www.gnu.org/licenses>
|
||||
# or write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
|
||||
#
|
||||
|
||||
import mariadb, collections
|
||||
from mariadb.codecs import *
|
||||
from numbers import Number
|
||||
from mariadb.constants import *
|
||||
|
||||
PARAMSTYLE_QMARK= 1
|
||||
PARAMSTYLE_FORMAT= 2
|
||||
PARAMSTYLE_PYFORMAT= 3
|
||||
|
||||
RESULT_TUPLE= 0
|
||||
RESULT_NAMEDTUPLE= 1
|
||||
RESULT_DICTIONARY= 2
|
||||
|
||||
class Cursor(mariadb._mariadb.cursor):
|
||||
"""Returns a MariaDB cursor object"""
|
||||
|
||||
def __init__(self, connection, **kwargs):
|
||||
|
||||
self._dictionary= False
|
||||
self._named_tuple= False
|
||||
self._connection= connection
|
||||
self._resulttype= RESULT_TUPLE
|
||||
self._description= None
|
||||
self._transformed_statement= None
|
||||
self._prepared= False
|
||||
self._parsed= False
|
||||
self._prev_stmt= None
|
||||
self._force_binary= None
|
||||
|
||||
self._parseinfo= None
|
||||
self._data= None
|
||||
|
||||
if not connection:
|
||||
raise mariadb.ProgrammingError("Invalid or no connection provided")
|
||||
|
||||
if kwargs:
|
||||
rtype= kwargs.pop("named_tuple", False)
|
||||
if rtype:
|
||||
self._resulttype= RESULT_NAMEDTUPLE
|
||||
else:
|
||||
rtype= kwargs.pop("dictionary", False)
|
||||
if rtype:
|
||||
self._resulttype= RESULT_DICTIONARY
|
||||
buffered= kwargs.pop("buffered", False)
|
||||
self.buffered= buffered
|
||||
self._prepared= kwargs.pop("prepared", False)
|
||||
self._force_binary= kwargs.pop("binary", False)
|
||||
|
||||
super().__init__(connection, **kwargs)
|
||||
|
||||
|
||||
def _add_text_params(self):
|
||||
new_stmt= self.statement
|
||||
replace_diff= 0
|
||||
for i in range (0,len(self._paramlist)):
|
||||
if self._paramstyle == PARAMSTYLE_PYFORMAT:
|
||||
val= self._data[self._parseinfo["keys"][i]]
|
||||
else:
|
||||
val= self._data[i]
|
||||
if val is None:
|
||||
replace= "NULL";
|
||||
else:
|
||||
if isinstance(val, Number):
|
||||
replace= val.__str__()
|
||||
else:
|
||||
replace= "\"%s\"" % self.connection.escape_string(val.__str__())
|
||||
start= self._paramlist[i] + replace_diff
|
||||
end= self._paramlist[i] + replace_diff + 1
|
||||
|
||||
new_stmt= new_stmt[:start] + replace.__str__() + new_stmt[end:]
|
||||
replace_diff+= len(replace) - 1
|
||||
return new_stmt
|
||||
|
||||
def _check_execute_params(self):
|
||||
# check data format
|
||||
if self._paramstyle == PARAMSTYLE_QMARK or \
|
||||
self._paramstyle == PARAMSTYLE_FORMAT:
|
||||
if not isinstance(self._data, (tuple,list)):
|
||||
raise mariadb.ProgrammingError("Data arguent nust be Tuple or List")
|
||||
|
||||
if self._paramstyle == PARAMSTYLE_PYFORMAT and\
|
||||
not isinstance(self._data, dict):
|
||||
raise mariadb.ProgrammingError("Data arguent nust be Dictionary")
|
||||
|
||||
print(self._paramlist)
|
||||
|
||||
# check if number of place holders match the number of
|
||||
# supplied elements in data tuple
|
||||
if (not self._data and len(self._paramlist) > 0) or \
|
||||
(len(self._data) != len(self._paramlist)):
|
||||
raise mariadb.DataError("Number of parameters in statement (%s)"\
|
||||
" doesn't match the number of data elements (%s)."\
|
||||
% (len(self._paramlist), len(self._data)))
|
||||
|
||||
def _parse_execute(self, statement, data=()):
|
||||
"""
|
||||
Simple SQL statement parsing:
|
||||
"""
|
||||
|
||||
if not statement:
|
||||
raise mariadb.ProgrammingError("empty statement")
|
||||
|
||||
# parse statement
|
||||
print("statement: %s" % statement)
|
||||
print("prev statement: %s" % self._prev_stmt)
|
||||
if self._prev_stmt != statement:
|
||||
super()._parse(statement)
|
||||
self._prev_stmt= statement
|
||||
self._reprepare= True
|
||||
print("param_count: %s" % self.paramcount)
|
||||
print("parsed")
|
||||
else:
|
||||
self._reprepare= False
|
||||
print("not parsed")
|
||||
|
||||
self._data= data
|
||||
|
||||
self._check_execute_params()
|
||||
|
||||
if self._text:
|
||||
# in text mode we need to substitute parameters
|
||||
# and store transformed statement
|
||||
if (self.paramcount > 0):
|
||||
self._transformed_statement= self._add_text_params()
|
||||
else:
|
||||
self._transformed_statement= self.statement
|
||||
|
||||
def nextset(self):
|
||||
return super()._nextset()
|
||||
|
||||
def execute(self, statement, data=(), buffered=False):
|
||||
"""
|
||||
place holder for execute() description
|
||||
"""
|
||||
|
||||
if buffered:
|
||||
self.buffered= 1
|
||||
|
||||
# parse statement and check param style
|
||||
if not self._parsed or not self._prepared:
|
||||
self._parse_execute(statement, (data))
|
||||
self._parsed= True
|
||||
self._description= None
|
||||
|
||||
if (self._paramstyle == 3 and not isinstance(data, dict)):
|
||||
raise TypeError("Argument 2 must be Dict")
|
||||
elif (not isinstance(data, (tuple, list))):
|
||||
raise TypeError("Argument 2 must be Tuple or List")
|
||||
|
||||
if len(data):
|
||||
self._data= data
|
||||
else:
|
||||
self._data= None
|
||||
|
||||
if self._force_binary:
|
||||
self._text= False
|
||||
|
||||
if self._text:
|
||||
self._execute_text(self._transformed_statement)
|
||||
self._readresponse()
|
||||
else:
|
||||
self._data= data
|
||||
self._execute_binary()
|
||||
|
||||
self._initresult()
|
||||
|
||||
def executemany(self, statement, data=[]):
|
||||
""" Bulk operations """
|
||||
|
||||
|
||||
# If the server doesn't support bulk operations, we need to emulate
|
||||
# by looping
|
||||
if (self.connection.server_capabilities & (CLIENT.BULK_OPERATIONS >> 32)):
|
||||
for row in data:
|
||||
self.execute(statement, row)
|
||||
else:
|
||||
# parse statement
|
||||
self._parse_execute(statement, (data))
|
||||
|
||||
def _fetch_row(self):
|
||||
if not self.field_count:
|
||||
return()
|
||||
row= super().fetchone()
|
||||
if self._connection._converter:
|
||||
l= list(row)
|
||||
if not self._description:
|
||||
self._description= super().description
|
||||
for i,v in enumerate(row):
|
||||
type= self.description[i][1]
|
||||
if type in self._connection._converter:
|
||||
func= self._connection._converter[type]
|
||||
l[i]= func(v)
|
||||
else:
|
||||
l[i]= v
|
||||
row= tuple(l)
|
||||
return row
|
||||
|
||||
def fetchone(self):
|
||||
row= self._fetch_row()
|
||||
if not row:
|
||||
return row
|
||||
if self._resulttype == RESULT_DICTIONARY:
|
||||
ret= dict(zip(list(d[0] for d in self.description),row))
|
||||
elif self._resulttype == RESULT_NAMEDTUPLE:
|
||||
ret= collections.namedtuple('Row1', list(d[0] for d in self.description));
|
||||
ret= ret._make(row)
|
||||
else:
|
||||
ret= row
|
||||
return ret
|
||||
|
||||
def fetchall(self):
|
||||
rows=[];
|
||||
for row in self:
|
||||
rows.append((row))
|
||||
return rows
|
||||
|
||||
def close(self):
|
||||
super().close()
|
||||
|
||||
def __enter__(self):
|
||||
"""Returns a copy of the cursor."""
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_val, exc_tb):
|
||||
"""Closes cursor."""
|
||||
self.close()
|
||||
|
||||
@property
|
||||
def rowcount(self):
|
||||
if not self.statement:
|
||||
return -1;
|
||||
if not self.field_count:
|
||||
return 0;
|
||||
return super().rowcount
|
||||
|
||||
@property
|
||||
def connection(self):
|
||||
"""Read-Only attribute which returns the reference to the connection
|
||||
object on which the cursor was created."""
|
||||
return self._connection
|
@ -935,7 +935,7 @@ mariadb_get_parameter(MrdbCursor *self,
|
||||
/* check if row_nr and column_nr are in the range from
|
||||
0 to (value - 1) */
|
||||
if (row_nr > (self->array_size - 1) ||
|
||||
column_nr > (self->param_count - 1))
|
||||
column_nr > (self->parseinfo.paramcount - 1))
|
||||
{
|
||||
mariadb_throw_exception(self->stmt, Mariadb_DataError, 0,
|
||||
"Can't access data at row %d, column %d",
|
||||
@ -953,7 +953,7 @@ mariadb_get_parameter(MrdbCursor *self,
|
||||
else
|
||||
row= self->data;
|
||||
|
||||
if (self->parser->paramstyle != PYFORMAT)
|
||||
if (self->paramstyle != PYFORMAT)
|
||||
{
|
||||
if (!(column= ListOrTuple_GetItem(row, column_nr)))
|
||||
{
|
||||
@ -964,12 +964,13 @@ mariadb_get_parameter(MrdbCursor *self,
|
||||
}
|
||||
} else
|
||||
{
|
||||
PyObject *key= PyUnicode_FromString(self->parser->keys[column_nr].str);
|
||||
PyObject *key;
|
||||
|
||||
key= PyTuple_GetItem(self->parseinfo.keys, column_nr);
|
||||
if (!PyDict_Contains(row, key))
|
||||
{
|
||||
mariadb_throw_exception(self->stmt, Mariadb_DataError, 0,
|
||||
"Can't find key '%s' in parameter data",
|
||||
self->parser->keys[column_nr]);
|
||||
"Can't find key in parameter data");
|
||||
goto end;
|
||||
}
|
||||
column= PyDict_GetItem(row, key);
|
||||
@ -1166,7 +1167,7 @@ mariadb_check_bulk_parameters(MrdbCursor *self,
|
||||
for (i=0; i < self->array_size; i++)
|
||||
{
|
||||
PyObject *obj= ListOrTuple_GetItem(data, i);
|
||||
if (self->parser->paramstyle != PYFORMAT &&
|
||||
if (self->paramstyle != PYFORMAT &&
|
||||
(!CHECK_TYPE(obj, &PyTuple_Type) &&
|
||||
!CHECK_TYPE(obj, &PyList_Type)))
|
||||
{
|
||||
@ -1175,7 +1176,7 @@ mariadb_check_bulk_parameters(MrdbCursor *self,
|
||||
" (Row data must be provided as tuple(s))", i+1);
|
||||
return 1;
|
||||
}
|
||||
if (self->parser->paramstyle == PYFORMAT &&
|
||||
if (self->paramstyle == PYFORMAT &&
|
||||
!CHECK_TYPE(obj, &PyDict_Type))
|
||||
{
|
||||
mariadb_throw_exception(NULL, Mariadb_DataError, 0,
|
||||
@ -1184,12 +1185,9 @@ mariadb_check_bulk_parameters(MrdbCursor *self,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!self->param_count && !self->is_prepared)
|
||||
self->param_count= self->parser->param_count;
|
||||
|
||||
if (!self->param_count ||
|
||||
(self->parser->paramstyle != PYFORMAT &&
|
||||
self->param_count != ListOrTuple_Size(obj)))
|
||||
if (!self->parseinfo.paramcount ||
|
||||
(self->paramstyle != PYFORMAT &&
|
||||
self->parseinfo.paramcount != ListOrTuple_Size(obj)))
|
||||
{
|
||||
mariadb_throw_exception(self->stmt, Mariadb_DataError, 1,
|
||||
"Invalid number of parameters in row %d", i+1);
|
||||
@ -1198,25 +1196,25 @@ mariadb_check_bulk_parameters(MrdbCursor *self,
|
||||
}
|
||||
|
||||
if (!self->is_prepared &&
|
||||
!(self->params= PyMem_RawCalloc(self->param_count,
|
||||
!(self->params= PyMem_RawCalloc(self->parseinfo.paramcount,
|
||||
sizeof(MYSQL_BIND))))
|
||||
{
|
||||
mariadb_throw_exception(NULL, Mariadb_InterfaceError, 0,
|
||||
"Not enough memory (tried to allocated %lld bytes)",
|
||||
self->param_count * sizeof(MYSQL_BIND));
|
||||
self->parseinfo.paramcount * sizeof(MYSQL_BIND));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(self->value= PyMem_RawCalloc(self->param_count,
|
||||
if (!(self->value= PyMem_RawCalloc(self->parseinfo.paramcount,
|
||||
sizeof(MrdbParamValue))))
|
||||
{
|
||||
mariadb_throw_exception(NULL, Mariadb_InterfaceError, 0,
|
||||
"Not enough memory (tried to allocated %lld bytes)",
|
||||
self->param_count * sizeof(MrdbParamValue));
|
||||
self->parseinfo.paramcount * sizeof(MrdbParamValue));
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i=0; i < self->param_count; i++)
|
||||
for (i=0; i < self->parseinfo.paramcount; i++)
|
||||
{
|
||||
if (mariadb_get_parameter_info(self, &self->params[i], i))
|
||||
goto error;
|
||||
@ -1233,12 +1231,8 @@ mariadb_check_execute_parameters(MrdbCursor *self,
|
||||
PyObject *data)
|
||||
{
|
||||
uint32_t i;
|
||||
if (!self->param_count)
|
||||
{
|
||||
self->param_count= self->parser->param_count;
|
||||
}
|
||||
|
||||
if (!self->param_count)
|
||||
if (!self->parseinfo.paramcount)
|
||||
{
|
||||
mariadb_throw_exception(NULL, Mariadb_DataError, 0,
|
||||
"Invalid number of parameters");
|
||||
@ -1246,23 +1240,23 @@ mariadb_check_execute_parameters(MrdbCursor *self,
|
||||
}
|
||||
|
||||
if (!self->params &&
|
||||
!(self->params= PyMem_RawCalloc(self->param_count, sizeof(MYSQL_BIND))))
|
||||
!(self->params= PyMem_RawCalloc(self->parseinfo.paramcount, sizeof(MYSQL_BIND))))
|
||||
{
|
||||
mariadb_throw_exception(NULL, Mariadb_InterfaceError, 0,
|
||||
"Not enough memory (tried to allocated %lld bytes)",
|
||||
self->param_count * sizeof(MYSQL_BIND));
|
||||
self->parseinfo.paramcount * sizeof(MYSQL_BIND));
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!(self->value= PyMem_RawCalloc(self->param_count, sizeof(MrdbParamValue))))
|
||||
if (!(self->value= PyMem_RawCalloc(self->parseinfo.paramcount, sizeof(MrdbParamValue))))
|
||||
{
|
||||
mariadb_throw_exception(NULL, Mariadb_InterfaceError, 0,
|
||||
"Not enough memory (tried to allocated %lld bytes)",
|
||||
self->param_count * sizeof(MrdbParamValue));
|
||||
self->parseinfo.paramcount * sizeof(MrdbParamValue));
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (i=0; i < self->param_count; i++)
|
||||
for (i=0; i < self->parseinfo.paramcount; i++)
|
||||
{
|
||||
if (mariadb_get_parameter_info(self, &self->params[i], i))
|
||||
{
|
||||
@ -1444,7 +1438,7 @@ mariadb_param_update(void *data, MYSQL_BIND *bind, uint32_t row_nr)
|
||||
|
||||
MARIADB_UNBLOCK_THREADS(self);
|
||||
|
||||
for (i=0; i < self->param_count; i++)
|
||||
for (i=0; i < self->parseinfo.paramcount; i++)
|
||||
{
|
||||
if (mariadb_get_parameter(self, (self->array_size > 0),
|
||||
row_nr, i, &self->value[i]))
|
||||
|
@ -20,6 +20,13 @@
|
||||
#include "mariadb_python.h"
|
||||
#include "docs/connection.h"
|
||||
|
||||
#define MADB_SET_OPTION(m,o,v)\
|
||||
if (mysql_optionsv((m), (o), (v)))\
|
||||
{\
|
||||
mariadb_throw_exception(self->mysql, NULL, 0, NULL);\
|
||||
return -1;\
|
||||
}
|
||||
|
||||
char *dsn_keys[]= {
|
||||
"dsn", "host", "user", "password", "database", "port", "unix_socket",
|
||||
"connect_timeout", "read_timeout", "write_timeout",
|
||||
@ -31,7 +38,7 @@ char *dsn_keys[]= {
|
||||
"client_flag", "pool_name", "pool_size",
|
||||
"pool_reset_connection", "plugin_dir",
|
||||
"username", "db", "passwd",
|
||||
"autocommit", "converter",
|
||||
"autocommit", "converter", "asynchronous",
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -47,6 +54,9 @@ static PyObject
|
||||
static PyObject *
|
||||
MrdbConnection_exception(PyObject *self, void *closure);
|
||||
|
||||
static PyObject *
|
||||
MrdbConnection_query(MrdbConnection *self, PyObject *args);
|
||||
|
||||
#define GETTER_EXCEPTION(name, exception, doc)\
|
||||
{ name,MrdbConnection_exception, NULL, doc, &exception }
|
||||
|
||||
@ -93,6 +103,10 @@ MrdbConnection_get_server_version(MrdbConnection *self);
|
||||
static PyObject *
|
||||
MrdbConnection_get_server_status(MrdbConnection *self);
|
||||
|
||||
PyObject *
|
||||
MrdbConnection_executecommand(MrdbConnection *self,
|
||||
PyObject *args);
|
||||
|
||||
static PyGetSetDef
|
||||
MrdbConnection_sets[]=
|
||||
{
|
||||
@ -131,6 +145,9 @@ MrdbConnection_sets[]=
|
||||
static PyMethodDef
|
||||
MrdbConnection_Methods[] =
|
||||
{
|
||||
{"_query", (PyCFunction)MrdbConnection_query,
|
||||
METH_VARARGS,
|
||||
NULL},
|
||||
/* PEP-249 methods */
|
||||
{"close", (PyCFunction)MrdbConnection_close,
|
||||
METH_NOARGS,
|
||||
@ -209,6 +226,11 @@ MrdbConnection_Methods[] =
|
||||
METH_VARARGS,
|
||||
connection_escape_string__doc__
|
||||
},
|
||||
/* Internal methods */
|
||||
{ "_execute_command",
|
||||
(PyCFunction)MrdbConnection_executecommand,
|
||||
METH_VARARGS, NULL
|
||||
},
|
||||
{NULL} /* always last */
|
||||
};
|
||||
|
||||
@ -265,6 +287,16 @@ PyMemberDef MrdbConnection_Members[] =
|
||||
offsetof(MrdbConnection, tls_version),
|
||||
READONLY,
|
||||
"TLS protocol version used by connection"},
|
||||
{"client_capabilities",
|
||||
T_ULONG,
|
||||
offsetof(MrdbConnection, server_capabilities),
|
||||
READONLY,
|
||||
"Client capabilities"},
|
||||
{"server_capabilities",
|
||||
T_ULONG,
|
||||
offsetof(MrdbConnection, server_capabilities),
|
||||
READONLY,
|
||||
"Server capabilities"},
|
||||
{NULL} /* always last */
|
||||
};
|
||||
|
||||
@ -311,9 +343,10 @@ MrdbConnection_Initialize(MrdbConnection *self,
|
||||
compress= 0, ssl_verify_cert= 0;
|
||||
PyObject *autocommit_obj= NULL;
|
||||
PyObject *converter= NULL;
|
||||
PyObject *asynchronous= NULL;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, dsnargs,
|
||||
"|zzzzziziiibbzzzzzzzzzzibizibzzzzOO:connect",
|
||||
"|zzzzziziiibbzzzzzzzzzzibizibzzzzO!OO!:connect",
|
||||
dsn_keys,
|
||||
&dsn, &host, &user, &password, &schema, &port, &socket,
|
||||
&connect_timeout, &read_timeout, &write_timeout,
|
||||
@ -325,21 +358,13 @@ MrdbConnection_Initialize(MrdbConnection *self,
|
||||
&client_flags, &pool_name, &pool_size,
|
||||
&reset_session, &plugin_dir,
|
||||
&user, &schema, &password,
|
||||
&autocommit_obj, &converter))
|
||||
&PyBool_Type, &autocommit_obj,
|
||||
&converter,
|
||||
&PyBool_Type, &asynchronous))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (autocommit_obj)
|
||||
{
|
||||
if (autocommit_obj != Py_None &&
|
||||
!CHECK_TYPE(autocommit_obj, &PyBool_Type))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "Argument must be boolean or None");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dsn)
|
||||
{
|
||||
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 1,
|
||||
@ -370,40 +395,50 @@ MrdbConnection_Initialize(MrdbConnection *self,
|
||||
|
||||
if (local_infile != 0xFF)
|
||||
{
|
||||
mysql_optionsv(self->mysql, MYSQL_OPT_LOCAL_INFILE, &local_infile);
|
||||
MADB_SET_OPTION(self->mysql, MYSQL_OPT_LOCAL_INFILE, &local_infile);
|
||||
}
|
||||
|
||||
if (compress)
|
||||
{
|
||||
mysql_optionsv(self->mysql, MYSQL_OPT_COMPRESS, 1);
|
||||
MADB_SET_OPTION(self->mysql, MYSQL_OPT_COMPRESS, 1);
|
||||
}
|
||||
|
||||
if (init_command)
|
||||
{
|
||||
mysql_optionsv(self->mysql, MYSQL_INIT_COMMAND, init_command);
|
||||
MADB_SET_OPTION(self->mysql, MYSQL_INIT_COMMAND, init_command);
|
||||
}
|
||||
|
||||
if (plugin_dir) {
|
||||
mysql_optionsv(self->mysql, MYSQL_PLUGIN_DIR, plugin_dir);
|
||||
MADB_SET_OPTION(self->mysql, MYSQL_PLUGIN_DIR, plugin_dir);
|
||||
} else {
|
||||
#if defined(DEFAULT_PLUGINS_SUBDIR)
|
||||
mysql_optionsv(self->mysql, MYSQL_PLUGIN_DIR, DEFAULT_PLUGINS_SUBDIR);
|
||||
MADB_SET_OPTION(self->mysql, MYSQL_PLUGIN_DIR, DEFAULT_PLUGINS_SUBDIR);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* read defaults from configuration file(s) */
|
||||
if (default_file)
|
||||
mysql_optionsv(self->mysql, MYSQL_READ_DEFAULT_FILE, default_file);
|
||||
{
|
||||
MADB_SET_OPTION(self->mysql, MYSQL_READ_DEFAULT_FILE, default_file);
|
||||
}
|
||||
if (default_group)
|
||||
mysql_optionsv(self->mysql, MYSQL_READ_DEFAULT_GROUP, default_group);
|
||||
{
|
||||
MADB_SET_OPTION(self->mysql, MYSQL_READ_DEFAULT_GROUP, default_group);
|
||||
}
|
||||
|
||||
/* set timeouts */
|
||||
if (connect_timeout)
|
||||
mysql_optionsv(self->mysql, MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout);
|
||||
{
|
||||
MADB_SET_OPTION(self->mysql, MYSQL_OPT_CONNECT_TIMEOUT, &connect_timeout);
|
||||
}
|
||||
if (read_timeout)
|
||||
mysql_optionsv(self->mysql, MYSQL_OPT_READ_TIMEOUT, &read_timeout);
|
||||
{
|
||||
MADB_SET_OPTION(self->mysql, MYSQL_OPT_READ_TIMEOUT, &read_timeout);
|
||||
}
|
||||
if (write_timeout)
|
||||
mysql_optionsv(self->mysql, MYSQL_OPT_WRITE_TIMEOUT, &write_timeout);
|
||||
{
|
||||
MADB_SET_OPTION(self->mysql, MYSQL_OPT_WRITE_TIMEOUT, &write_timeout);
|
||||
}
|
||||
|
||||
/* set TLS/SSL options */
|
||||
if (ssl_enforce || ssl_key || ssl_ca || ssl_cert || ssl_capath || ssl_cipher)
|
||||
@ -413,11 +448,18 @@ MrdbConnection_Initialize(MrdbConnection *self,
|
||||
(const char *)ssl_capath,
|
||||
(const char *)ssl_cipher);
|
||||
if (ssl_crl)
|
||||
mysql_optionsv(self->mysql, MYSQL_OPT_SSL_CRL, ssl_crl);
|
||||
{
|
||||
MADB_SET_OPTION(self->mysql, MYSQL_OPT_SSL_CRL, ssl_crl);
|
||||
}
|
||||
if (ssl_crlpath)
|
||||
mysql_optionsv(self->mysql, MYSQL_OPT_SSL_CRLPATH, ssl_crlpath);
|
||||
{
|
||||
MADB_SET_OPTION(self->mysql, MYSQL_OPT_SSL_CRLPATH, ssl_crlpath);
|
||||
}
|
||||
if (ssl_verify_cert)
|
||||
mysql_optionsv(self->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (unsigned char *) &ssl_verify_cert);
|
||||
{
|
||||
MADB_SET_OPTION(self->mysql, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (unsigned char *) &ssl_verify_cert);
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
mysql_real_connect(self->mysql, host, user, password, schema, port,
|
||||
socket, client_flags);
|
||||
@ -460,7 +502,13 @@ MrdbConnection_Initialize(MrdbConnection *self,
|
||||
PyTuple_SetItem(self->server_version_info, 2, PyLong_FromLong(patch)))
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
if (asynchronous && PyObject_IsTrue(asynchronous))
|
||||
{
|
||||
self->asynchronous= 1;
|
||||
MADB_SET_OPTION(self->mysql, MARIADB_OPT_SKIP_READ_RESPONSE, &self->asynchronous);
|
||||
}
|
||||
*/
|
||||
end:
|
||||
if (PyErr_Occurred())
|
||||
return -1;
|
||||
@ -580,19 +628,86 @@ void MrdbConnection_dealloc(MrdbConnection *self)
|
||||
mysql_close(self->mysql);
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
Py_DECREF(self->server_version_info);
|
||||
Py_XDECREF(self->server_version_info);
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *
|
||||
MrdbConnection_executecommand(MrdbConnection *self,
|
||||
PyObject *args)
|
||||
{
|
||||
char *cmd;
|
||||
int rc;
|
||||
|
||||
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||
if (!PyArg_ParseTuple(args, "s", &cmd))
|
||||
return NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
rc= mysql_send_query(self->mysql, cmd, strlen(cmd));
|
||||
Py_END_ALLOW_THREADS;
|
||||
|
||||
if (rc)
|
||||
{
|
||||
mariadb_throw_exception(self->mysql, NULL, 0, NULL);
|
||||
return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
PyObject *
|
||||
MrdbConnection_readresponse(MrdbConnection *self)
|
||||
{
|
||||
int rc;
|
||||
PyObject *result, *tmp;
|
||||
|
||||
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
rc= self->mysql->methods->db_read_query_result(self->mysql);
|
||||
Py_END_ALLOW_THREADS;
|
||||
|
||||
if (rc)
|
||||
{
|
||||
mariadb_throw_exception(self->mysql, NULL, 0, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
result= PyDict_New();
|
||||
|
||||
tmp= PyLong_FromLong((long)mysql_field_count(self->mysql));
|
||||
PyDict_SetItemString(result, "field_count", tmp);
|
||||
Py_DECREF(tmp);
|
||||
|
||||
tmp= PyLong_FromLong((long)mysql_affected_rows(self->mysql));
|
||||
PyDict_SetItemString(result, "affected_rows", tmp);
|
||||
Py_DECREF(tmp);
|
||||
|
||||
tmp= PyLong_FromLong((long)mysql_insert_id(self->mysql));
|
||||
PyDict_SetItemString(result, "insert_id", tmp);
|
||||
Py_DECREF(tmp);
|
||||
|
||||
tmp= PyLong_FromLong((long)self->mysql->server_status);
|
||||
PyDict_SetItemString(result, "server_status", tmp);
|
||||
Py_DECREF(tmp);
|
||||
|
||||
tmp= PyLong_FromLong((long)mysql_warning_count(self->mysql));
|
||||
PyDict_SetItemString(result, "warning_count", tmp);
|
||||
Py_DECREF(tmp);
|
||||
|
||||
return result;
|
||||
}
|
||||
*/
|
||||
|
||||
PyObject *MrdbConnection_close(MrdbConnection *self)
|
||||
{
|
||||
MARIADB_CHECK_CONNECTION(self, NULL);
|
||||
/* Todo: check if all the cursor stuff is deleted (when using prepared
|
||||
statements this should be handled in mysql_close) */
|
||||
|
||||
if (self->converter)
|
||||
Py_DECREF(self->converter);
|
||||
Py_XDECREF(self->converter);
|
||||
self->converter= NULL;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
@ -1329,6 +1444,27 @@ static PyObject *MrdbConnection_get_server_status(MrdbConnection *self)
|
||||
return PyLong_FromLong((long)server_status);
|
||||
}
|
||||
|
||||
static PyObject *MrdbConnection_query(MrdbConnection *self, PyObject *args)
|
||||
{
|
||||
char *cmd;
|
||||
int rc;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &cmd))
|
||||
return NULL;
|
||||
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
rc= mysql_send_query(self->mysql, cmd, strlen(cmd));
|
||||
Py_END_ALLOW_THREADS;
|
||||
|
||||
if (rc)
|
||||
{
|
||||
mariadb_throw_exception(self->mysql, NULL, 0, NULL);
|
||||
return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/* vim: set tabstop=4 */
|
||||
/* vim: set shiftwidth=4 */
|
||||
/* vim: set expandtab */
|
||||
|
@ -38,6 +38,18 @@ static PyObject *
|
||||
MrdbCursor_executemany(MrdbCursor *self,
|
||||
PyObject *args);
|
||||
|
||||
static PyObject *
|
||||
MrdbCursor_execute_binary(MrdbCursor *self);
|
||||
|
||||
static PyObject *
|
||||
MrdbCursor_InitResultSet(MrdbCursor *self);
|
||||
|
||||
static PyObject *
|
||||
MrdbCursor_execute_text(MrdbCursor *self, PyObject *args);
|
||||
|
||||
static PyObject *
|
||||
MrdbCursor_parse(MrdbCursor *self, PyObject *args);
|
||||
|
||||
static PyObject *
|
||||
MrdbCursor_description(MrdbCursor *self);
|
||||
|
||||
@ -67,6 +79,9 @@ MrdbCursor_fieldcount(MrdbCursor *self);
|
||||
void
|
||||
field_fetch_fromtext(MrdbCursor *self, char *data, unsigned int column);
|
||||
|
||||
static PyObject *
|
||||
MrdbCursor_readresponse(MrdbCursor *self);
|
||||
|
||||
void
|
||||
field_fetch_callback(void *data, unsigned int column, unsigned char **row);
|
||||
static PyObject *mariadb_get_sequence_or_tuple(MrdbCursor *self);
|
||||
@ -85,19 +100,19 @@ strncpy((a)->statement, (s), (l));\
|
||||
(a)->statement[(l)]= 0;
|
||||
|
||||
#define CURSOR_FIELD_COUNT(a)\
|
||||
((a)->is_text ? mysql_field_count((a)->connection->mysql) : (a)->stmt ? mysql_stmt_field_count((a)->stmt) : 0)
|
||||
((a)->parseinfo.is_text ? mysql_field_count((a)->connection->mysql) : (a)->stmt ? mysql_stmt_field_count((a)->stmt) : 0)
|
||||
|
||||
#define CURSOR_WARNING_COUNT(a)\
|
||||
(((a)->is_text) ? (long)mysql_warning_count((a)->connection->mysql) : ((a)->stmt) ? (long)mysql_stmt_warning_count((a)->stmt) : 0L)
|
||||
(((a)->parseinfo.is_text) ? (long)mysql_warning_count((a)->connection->mysql) : ((a)->stmt) ? (long)mysql_stmt_warning_count((a)->stmt) : 0L)
|
||||
|
||||
#define CURSOR_AFFECTED_ROWS(a)\
|
||||
(int64_t)((a)->is_text ? mysql_affected_rows((a)->connection->mysql) : (a)->stmt ? mysql_stmt_affected_rows((a)->stmt) : 0)
|
||||
(int64_t)((a)->parseinfo.is_text ? mysql_affected_rows((a)->connection->mysql) : (a)->stmt ? mysql_stmt_affected_rows((a)->stmt) : 0)
|
||||
|
||||
#define CURSOR_INSERT_ID(a)\
|
||||
((a)->is_text ? mysql_insert_id((a)->connection->mysql) : (a)->stmt ? mysql_stmt_insert_id((a)->stmt) : 0)
|
||||
((a)->parseinfo.is_text ? mysql_insert_id((a)->connection->mysql) : (a)->stmt ? mysql_stmt_insert_id((a)->stmt) : 0)
|
||||
|
||||
#define CURSOR_NUM_ROWS(a)\
|
||||
((a)->is_text ? mysql_num_rows((a)->result) : (a)->stmt ? mysql_stmt_num_rows((a)->stmt) : 0)
|
||||
((a)->parseinfo.is_text ? mysql_num_rows((a)->result) : (a)->stmt ? mysql_stmt_num_rows((a)->stmt) : 0)
|
||||
|
||||
static char *mariadb_named_tuple_name= "mariadb.Row";
|
||||
static char *mariadb_named_tuple_desc= "Named tupled row";
|
||||
@ -106,8 +121,6 @@ static PyObject *Mariadb_no_operation(MrdbCursor *,
|
||||
static PyObject *Mariadb_row_count(MrdbCursor *self);
|
||||
static PyObject *Mariadb_row_number(MrdbCursor *self);
|
||||
static PyObject *MrdbCursor_warnings(MrdbCursor *self);
|
||||
static PyObject *MrdbCursor_getbuffered(MrdbCursor *self);
|
||||
static int MrdbCursor_setbuffered(MrdbCursor *self, PyObject *arg);
|
||||
static PyObject *MrdbCursor_lastrowid(MrdbCursor *self);
|
||||
static PyObject *MrdbCursor_closed(MrdbCursor *self);
|
||||
static PyObject *MrdbCursor_sp_outparams(MrdbCursor *self);
|
||||
@ -125,8 +138,6 @@ static PyGetSetDef MrdbCursor_sets[]=
|
||||
cursor_warnings__doc__, NULL},
|
||||
{"closed", (getter)MrdbCursor_closed, NULL,
|
||||
cursor_closed__doc__, NULL},
|
||||
{"buffered", (getter)MrdbCursor_getbuffered, (setter)MrdbCursor_setbuffered,
|
||||
cursor_buffered__doc__, NULL},
|
||||
{"rownumber", (getter)Mariadb_row_number, NULL,
|
||||
cursor_rownumber__doc__, NULL},
|
||||
{"sp_outparams", (getter)MrdbCursor_sp_outparams, NULL,
|
||||
@ -161,7 +172,7 @@ static PyMethodDef MrdbCursor_Methods[] =
|
||||
{"fieldcount", (PyCFunction)MrdbCursor_fieldcount,
|
||||
METH_NOARGS,
|
||||
cursor_field_count__doc__},
|
||||
{"nextset", (PyCFunction)MrdbCursor_nextset,
|
||||
{"_nextset", (PyCFunction)MrdbCursor_nextset,
|
||||
METH_NOARGS,
|
||||
cursor_nextset__doc__},
|
||||
{"setinputsizes", (PyCFunction)Mariadb_no_operation,
|
||||
@ -176,6 +187,22 @@ static PyMethodDef MrdbCursor_Methods[] =
|
||||
{"scroll", (PyCFunction)MrdbCursor_scroll,
|
||||
METH_VARARGS | METH_KEYWORDS,
|
||||
cursor_scroll__doc__},
|
||||
/* internal helper functions */
|
||||
{"_initresult", (PyCFunction)MrdbCursor_InitResultSet,
|
||||
METH_NOARGS,
|
||||
NULL},
|
||||
{"_parse", (PyCFunction)MrdbCursor_parse,
|
||||
METH_VARARGS,
|
||||
NULL},
|
||||
{"_readresponse", (PyCFunction)MrdbCursor_readresponse,
|
||||
METH_NOARGS,
|
||||
NULL},
|
||||
{"_execute_text", (PyCFunction)MrdbCursor_execute_text,
|
||||
METH_VARARGS,
|
||||
NULL},
|
||||
{"_execute_binary", (PyCFunction)MrdbCursor_execute_binary,
|
||||
METH_NOARGS,
|
||||
NULL},
|
||||
{NULL} /* always last */
|
||||
};
|
||||
|
||||
@ -183,11 +210,46 @@ static struct PyMemberDef MrdbCursor_Members[] =
|
||||
{
|
||||
{"statement",
|
||||
T_STRING,
|
||||
offsetof(MrdbCursor, statement),
|
||||
offsetof(MrdbCursor, parseinfo.statement),
|
||||
READONLY,
|
||||
cursor_statement__doc__},
|
||||
{"_paramstyle",
|
||||
T_UINT,
|
||||
offsetof(MrdbCursor, parseinfo.paramstyle),
|
||||
READONLY,
|
||||
MISSING_DOC},
|
||||
{"_reprepare",
|
||||
T_UINT,
|
||||
offsetof(MrdbCursor, reprepare),
|
||||
0,
|
||||
MISSING_DOC},
|
||||
{"_text",
|
||||
T_BOOL,
|
||||
offsetof(MrdbCursor, parseinfo.is_text),
|
||||
0,
|
||||
MISSING_DOC},
|
||||
{"_paramlist",
|
||||
T_OBJECT,
|
||||
offsetof(MrdbCursor, parseinfo.paramlist),
|
||||
READONLY,
|
||||
MISSING_DOC},
|
||||
{"_keys",
|
||||
T_OBJECT,
|
||||
offsetof(MrdbCursor, parseinfo.keys),
|
||||
READONLY,
|
||||
MISSING_DOC},
|
||||
{"paramcount",
|
||||
T_UINT,
|
||||
offsetof(MrdbCursor, parseinfo.paramcount),
|
||||
READONLY,
|
||||
MISSING_DOC},
|
||||
{"_data",
|
||||
T_OBJECT,
|
||||
offsetof(MrdbCursor, data),
|
||||
0,
|
||||
MISSING_DOC},
|
||||
{"buffered",
|
||||
T_BYTE,
|
||||
T_BOOL,
|
||||
offsetof(MrdbCursor, is_buffered),
|
||||
0,
|
||||
cursor_buffered__doc__},
|
||||
@ -196,6 +258,23 @@ static struct PyMemberDef MrdbCursor_Members[] =
|
||||
offsetof(MrdbCursor, row_array_size),
|
||||
0,
|
||||
cursor_arraysize__doc__},
|
||||
{"field_count",
|
||||
T_UINT,
|
||||
offsetof(MrdbCursor, field_count),
|
||||
READONLY,
|
||||
"Number of columns"},
|
||||
{"affected_rows",
|
||||
T_ULONGLONG,
|
||||
offsetof(MrdbCursor, affected_rows),
|
||||
READONLY,
|
||||
"Number of affected rows"},
|
||||
{"insert_id",
|
||||
T_UINT,
|
||||
offsetof(MrdbCursor, lastrow_id),
|
||||
READONLY,
|
||||
"returns the ID generated by a query on a table with a column " \
|
||||
"having the AUTO_INCREMENT attribute or the value for the last "\
|
||||
"usage of LAST_INSERT_ID()"},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
@ -211,14 +290,11 @@ buffered: buffered or unbuffered result sets
|
||||
static int MrdbCursor_initialize(MrdbCursor *self, PyObject *args,
|
||||
PyObject *kwargs)
|
||||
{
|
||||
char *key_words[]= {"", "named_tuple", "dictionary", "prefetch_size", "cursor_type",
|
||||
"buffered", "prepared", "binary", NULL};
|
||||
char *key_words[]= {"", "prefetch_size", "cursor_type",
|
||||
"prepared", "binary", NULL};
|
||||
PyObject *connection;
|
||||
uint8_t is_named_tuple= 0;
|
||||
uint8_t is_dictionary= 0;
|
||||
unsigned long cursor_type= 0,
|
||||
prefetch_rows= 0;
|
||||
uint8_t is_buffered= 0;
|
||||
uint8_t is_prepared= 0;
|
||||
uint8_t is_binary= 0;
|
||||
|
||||
@ -226,9 +302,8 @@ static int MrdbCursor_initialize(MrdbCursor *self, PyObject *args,
|
||||
return -1;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
|
||||
"O!|bbkkbbb", key_words, &MrdbConnection_Type, &connection,
|
||||
&is_named_tuple, &is_dictionary, &prefetch_rows, &cursor_type, &is_buffered,
|
||||
&is_prepared, &is_binary))
|
||||
"O!|kkii", key_words, &MrdbConnection_Type, &connection,
|
||||
&prefetch_rows, &cursor_type, &is_prepared, &is_binary))
|
||||
return -1;
|
||||
|
||||
if (!((MrdbConnection *)connection)->mysql)
|
||||
@ -246,29 +321,11 @@ static int MrdbCursor_initialize(MrdbCursor *self, PyObject *args,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (is_named_tuple && is_dictionary)
|
||||
{
|
||||
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 0,
|
||||
"Results can be returned either as named tuple or as dictionary, but not as both.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (is_named_tuple)
|
||||
{
|
||||
self->result_format= RESULT_NAMED_TUPLE;
|
||||
} else if (is_dictionary)
|
||||
{
|
||||
self->result_format= RESULT_DICTIONARY;
|
||||
}
|
||||
|
||||
|
||||
Py_INCREF(connection);
|
||||
self->connection= (MrdbConnection *)connection;
|
||||
self->is_buffered= is_buffered ? is_buffered : self->connection->is_buffered;
|
||||
self->is_binary= is_binary;
|
||||
|
||||
self->is_prepared= is_prepared;
|
||||
self->is_text= 0;
|
||||
self->parseinfo.is_text= 0;
|
||||
self->stmt= NULL;
|
||||
|
||||
self->cursor_type= cursor_type;
|
||||
@ -366,12 +423,20 @@ static PyObject *Mariadb_no_operation(MrdbCursor *self,
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
void MrdbCursor_clearparseinfo(MrdbParseInfo *parseinfo)
|
||||
{
|
||||
if (parseinfo->statement)
|
||||
MARIADB_FREE_MEM(parseinfo->statement);
|
||||
Py_XDECREF(parseinfo->keys);
|
||||
memset(parseinfo, 0, sizeof(MrdbParseInfo));
|
||||
}
|
||||
|
||||
/* {{{ MrdbCursor_clear_result(MrdbCursor *self)
|
||||
clear pending result sets
|
||||
*/
|
||||
static void MrdbCursor_clear_result(MrdbCursor *self)
|
||||
{
|
||||
if (!self->is_text &&
|
||||
if (!self->parseinfo.is_text &&
|
||||
self->stmt)
|
||||
{
|
||||
/* free current result */
|
||||
@ -382,7 +447,7 @@ static void MrdbCursor_clear_result(MrdbCursor *self)
|
||||
{
|
||||
mysql_stmt_free_result(self->stmt);
|
||||
}
|
||||
} else if (self->is_text)
|
||||
} else if (self->parseinfo.is_text)
|
||||
{
|
||||
/* free current result */
|
||||
if (self->result)
|
||||
@ -413,7 +478,7 @@ void MrdbCursor_clear(MrdbCursor *self, uint8_t new_stmt)
|
||||
/* clear pending result sets */
|
||||
MrdbCursor_clear_result(self);
|
||||
|
||||
if (!self->is_text && self->stmt) {
|
||||
if (!self->parseinfo.is_text && self->stmt) {
|
||||
if (new_stmt)
|
||||
{
|
||||
mysql_stmt_close(self->stmt);
|
||||
@ -439,7 +504,8 @@ void MrdbCursor_clear(MrdbCursor *self, uint8_t new_stmt)
|
||||
self->fields= NULL;
|
||||
self->row_count= 0;
|
||||
self->affected_rows= 0;
|
||||
self->param_count= 0;
|
||||
MARIADB_FREE_MEM(self->parseinfo.statement);
|
||||
memset(&self->parseinfo, 0, sizeof(MrdbParseInfo));
|
||||
MARIADB_FREE_MEM(self->values);
|
||||
MARIADB_FREE_MEM(self->bind);
|
||||
MARIADB_FREE_MEM(self->statement);
|
||||
@ -474,7 +540,7 @@ void ma_cursor_close(MrdbCursor *self)
|
||||
if (!self->is_closed)
|
||||
{
|
||||
MrdbCursor_clear_result(self);
|
||||
if (!self->is_text && self->stmt)
|
||||
if (!self->parseinfo.is_text && self->stmt)
|
||||
{
|
||||
/* Todo: check if all the cursor stuff is deleted (when using prepared
|
||||
statements this should be handled in mysql_stmt_close) */
|
||||
@ -485,14 +551,9 @@ void ma_cursor_close(MrdbCursor *self)
|
||||
}
|
||||
MrdbCursor_clear(self, 0);
|
||||
|
||||
if (self->is_text && self->stmt)
|
||||
if (!self->parseinfo.is_text && self->stmt)
|
||||
mysql_stmt_close(self->stmt);
|
||||
|
||||
if (self->parser)
|
||||
{
|
||||
MrdbParser_end(self->parser);
|
||||
self->parser= NULL;
|
||||
}
|
||||
self->is_closed= 1;
|
||||
}
|
||||
}
|
||||
@ -520,7 +581,7 @@ static int Mrdb_GetFieldInfo(MrdbCursor *self)
|
||||
|
||||
if (self->field_count)
|
||||
{
|
||||
if (self->is_text)
|
||||
if (self->parseinfo.is_text)
|
||||
{
|
||||
self->result= (self->is_buffered) ? mysql_store_result(self->connection->mysql) :
|
||||
mysql_use_result(self->connection->mysql);
|
||||
@ -541,7 +602,7 @@ static int Mrdb_GetFieldInfo(MrdbCursor *self)
|
||||
|
||||
self->affected_rows= CURSOR_AFFECTED_ROWS(self);
|
||||
|
||||
self->fields= (self->is_text) ? mysql_fetch_fields(self->result) :
|
||||
self->fields= (self->parseinfo.is_text) ? mysql_fetch_fields(self->result) :
|
||||
mariadb_stmt_fetch_fields(self->stmt);
|
||||
|
||||
if (self->result_format == RESULT_NAMED_TUPLE) {
|
||||
@ -571,10 +632,8 @@ static int Mrdb_GetFieldInfo(MrdbCursor *self)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int MrdbCursor_InitResultSet(MrdbCursor *self)
|
||||
PyObject *MrdbCursor_InitResultSet(MrdbCursor *self)
|
||||
{
|
||||
self->field_count= CURSOR_FIELD_COUNT(self);
|
||||
|
||||
MARIADB_FREE_MEM(self->sequence_fields);
|
||||
MARIADB_FREE_MEM(self->values);
|
||||
|
||||
@ -585,13 +644,22 @@ static int MrdbCursor_InitResultSet(MrdbCursor *self)
|
||||
}
|
||||
|
||||
if (Mrdb_GetFieldInfo(self))
|
||||
return 1;
|
||||
return NULL;
|
||||
|
||||
if (!(self->values= (PyObject**)PyMem_RawCalloc(self->field_count, sizeof(PyObject *))))
|
||||
return 1;
|
||||
if (!self->is_text)
|
||||
return NULL;
|
||||
if (!self->parseinfo.is_text)
|
||||
mysql_stmt_attr_set(self->stmt, STMT_ATTR_CB_RESULT, field_fetch_callback);
|
||||
return 0;
|
||||
|
||||
if (self->field_count)
|
||||
{
|
||||
self->row_count= CURSOR_NUM_ROWS(self);
|
||||
} else {
|
||||
self->row_count= CURSOR_AFFECTED_ROWS(self);
|
||||
}
|
||||
self->lastrow_id= CURSOR_INSERT_ID(self);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static Py_ssize_t data_count(PyObject *data)
|
||||
@ -612,26 +680,38 @@ static Py_ssize_t data_count(PyObject *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Mrdb_execute_direct(MrdbCursor *self)
|
||||
static int Mrdb_execute_direct(MrdbCursor *self,
|
||||
const char *statement,
|
||||
size_t statement_len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
MARIADB_BEGIN_ALLOW_THREADS(self);
|
||||
|
||||
/* clear pending result sets */
|
||||
MrdbCursor_clear_result(self);
|
||||
|
||||
/* if stmt is already prepared */
|
||||
if (!self->reprepare)
|
||||
{
|
||||
rc= mysql_stmt_execute(self->stmt);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* execute_direct was implemented together with bulk operations, so we need
|
||||
to check if MARIADB_CLIENT_STMT_BULK_OPERATIONS is set in extended server
|
||||
capabilities */
|
||||
if (!(self->connection->extended_server_capabilities &
|
||||
(MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32)))
|
||||
{
|
||||
if (!(rc= mysql_stmt_prepare(self->stmt, self->parser->statement.str,
|
||||
(unsigned long)self->parser->statement.length)))
|
||||
if (!(rc= mysql_stmt_prepare(self->stmt, statement, (unsigned long)statement_len)))
|
||||
{
|
||||
rc= mysql_stmt_execute(self->stmt);
|
||||
}
|
||||
} else {
|
||||
rc= mariadb_stmt_execute_direct(self->stmt, self->parser->statement.str,
|
||||
self->parser->statement.length);
|
||||
rc= mariadb_stmt_execute_direct(self->stmt, statement, statement_len);
|
||||
}
|
||||
end:
|
||||
MARIADB_END_ALLOW_THREADS(self);
|
||||
return rc;
|
||||
}
|
||||
@ -650,7 +730,6 @@ PyObject *MrdbCursor_execute(MrdbCursor *self,
|
||||
int rc= 0;
|
||||
int8_t is_buffered= -1;
|
||||
static char *key_words[]= {"", "", "buffered", NULL};
|
||||
char errmsg[128];
|
||||
|
||||
MARIADB_CHECK_STMT(self);
|
||||
if (PyErr_Occurred())
|
||||
@ -661,22 +740,20 @@ PyObject *MrdbCursor_execute(MrdbCursor *self,
|
||||
return NULL;
|
||||
|
||||
/* If we don't have a prepared cursor, we need to end/free parser */
|
||||
if (!self->is_prepared && self->parser)
|
||||
if (!self->is_prepared && self->parseinfo.statement)
|
||||
{
|
||||
MrdbParser_end(self->parser);
|
||||
self->parser= NULL;
|
||||
MARIADB_FREE_MEM(self->parseinfo.statement);
|
||||
memset(&self->parseinfo, 0, sizeof(MrdbParseInfo));
|
||||
}
|
||||
|
||||
if (is_buffered != -1)
|
||||
self->is_buffered= is_buffered;
|
||||
|
||||
/* if there are no parameters specified, we execute the statement in text protocol */
|
||||
if (!data_count(Data) && !self->cursor_type && !self->is_binary)
|
||||
if (!data_count(Data) && !self->cursor_type && self->parseinfo.is_text)
|
||||
{
|
||||
/* in case statement was executed before, we need to clear, since we don't use
|
||||
binary protocol */
|
||||
MrdbParser_end(self->parser);
|
||||
self->parser= NULL;
|
||||
MrdbCursor_clear(self, 0);
|
||||
MARIADB_BEGIN_ALLOW_THREADS(self);
|
||||
rc= mysql_real_query(self->connection->mysql, statement, (unsigned long)statement_len);
|
||||
@ -686,7 +763,7 @@ PyObject *MrdbCursor_execute(MrdbCursor *self,
|
||||
mariadb_throw_exception(self->connection->mysql, NULL, 0, NULL);
|
||||
goto error;
|
||||
}
|
||||
self->is_text= 1;
|
||||
self->parseinfo.is_text= 1;
|
||||
CURSOR_SET_STATEMENT(self, statement, statement_len);
|
||||
}
|
||||
else
|
||||
@ -713,12 +790,10 @@ PyObject *MrdbCursor_execute(MrdbCursor *self,
|
||||
do_prepare= 0;
|
||||
} else {
|
||||
MrdbCursor_clear(self, 1);
|
||||
MrdbParser_end(self->parser);
|
||||
self->parser= NULL;
|
||||
}
|
||||
}
|
||||
self->is_text= 0;
|
||||
|
||||
self->parseinfo.is_text= 0;
|
||||
/*
|
||||
if (!self->parser)
|
||||
{
|
||||
self->parser= MrdbParser_init(self->connection->mysql, statement, statement_len);
|
||||
@ -753,19 +828,18 @@ PyObject *MrdbCursor_execute(MrdbCursor *self,
|
||||
|
||||
self->data= Data;
|
||||
|
||||
/* Load values */
|
||||
if (mariadb_param_update(self, self->params, 0))
|
||||
goto error;
|
||||
}
|
||||
} */
|
||||
if (do_prepare)
|
||||
{
|
||||
mysql_stmt_attr_set(self->stmt, STMT_ATTR_CURSOR_TYPE, &self->cursor_type);
|
||||
mysql_stmt_attr_set(self->stmt, STMT_ATTR_PREFETCH_ROWS, &self->prefetch_rows);
|
||||
mysql_stmt_attr_set(self->stmt, STMT_ATTR_PREBIND_PARAMS, &self->param_count);
|
||||
mysql_stmt_attr_set(self->stmt, STMT_ATTR_PREBIND_PARAMS, &self->parseinfo.paramcount);
|
||||
mysql_stmt_attr_set(self->stmt, STMT_ATTR_CB_USER_DATA, (void *)self);
|
||||
mysql_stmt_bind_param(self->stmt, self->params);
|
||||
|
||||
rc= Mrdb_execute_direct(self);
|
||||
rc= Mrdb_execute_direct(self, statement, statement_len);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
@ -774,7 +848,7 @@ PyObject *MrdbCursor_execute(MrdbCursor *self,
|
||||
if (mysql_stmt_errno(self->stmt) == ER_UNSUPPORTED_PS)
|
||||
{
|
||||
MARIADB_BEGIN_ALLOW_THREADS(self);
|
||||
self->is_text= 0;
|
||||
self->parseinfo.is_text= 0;
|
||||
rc= mysql_real_query(self->connection->mysql, statement, (unsigned long)statement_len);
|
||||
MARIADB_END_ALLOW_THREADS(self);
|
||||
|
||||
@ -836,8 +910,6 @@ end:
|
||||
error:
|
||||
self->row_count= -1;
|
||||
self->lastrow_id= 0;
|
||||
MrdbParser_end(self->parser);
|
||||
self->parser= NULL;
|
||||
MrdbCursor_clear(self, 0);
|
||||
return NULL;
|
||||
}
|
||||
@ -944,7 +1016,7 @@ static int MrdbCursor_fetchinternal(MrdbCursor *self)
|
||||
|
||||
self->fetched= 1;
|
||||
|
||||
if (!self->is_text)
|
||||
if (!self->parseinfo.is_text)
|
||||
{
|
||||
rc= mysql_stmt_fetch(self->stmt);
|
||||
if (rc == MYSQL_NO_DATA)
|
||||
@ -1084,7 +1156,7 @@ MrdbCursor_scroll(MrdbCursor *self,
|
||||
new_position= position; /* absolute */
|
||||
}
|
||||
|
||||
if (!self->is_text)
|
||||
if (!self->parseinfo.is_text)
|
||||
{
|
||||
mysql_stmt_data_seek(self->stmt, new_position);
|
||||
}
|
||||
@ -1224,7 +1296,7 @@ MrdbCursor_fetchall(MrdbCursor *self)
|
||||
/* CONPY-99: Decrement Row to prevent memory leak */
|
||||
Py_DECREF(Row);
|
||||
}
|
||||
self->row_count= (self->is_text) ? mysql_num_rows(self->result) :
|
||||
self->row_count= (self->parseinfo.is_text) ? mysql_num_rows(self->result) :
|
||||
mysql_stmt_num_rows(self->stmt);
|
||||
return List;
|
||||
}
|
||||
@ -1244,7 +1316,7 @@ MrdbCursor_executemany_fallback(MrdbCursor *self,
|
||||
if (rc)
|
||||
goto error_mysql;
|
||||
|
||||
if (mysql_stmt_attr_set(self->stmt, STMT_ATTR_PREBIND_PARAMS, &self->param_count))
|
||||
if (mysql_stmt_attr_set(self->stmt, STMT_ATTR_PREBIND_PARAMS, &self->parseinfo.paramcount))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
@ -1266,8 +1338,8 @@ MrdbCursor_executemany_fallback(MrdbCursor *self,
|
||||
MARIADB_BEGIN_ALLOW_THREADS(self);
|
||||
if (i==0)
|
||||
{
|
||||
rc= mysql_stmt_prepare(self->stmt, self->parser->statement.str,
|
||||
(unsigned long)self->parser->statement.length);
|
||||
rc= mysql_stmt_prepare(self->stmt, self->parseinfo.statement,
|
||||
(unsigned long)self->parseinfo.statement_len);
|
||||
}
|
||||
if (!rc)
|
||||
{
|
||||
@ -1305,7 +1377,6 @@ MrdbCursor_executemany(MrdbCursor *self,
|
||||
Py_ssize_t statement_len= 0;
|
||||
int rc;
|
||||
uint8_t do_prepare= 1;
|
||||
char errmsg[128];
|
||||
|
||||
MARIADB_CHECK_STMT(self);
|
||||
|
||||
@ -1336,8 +1407,6 @@ MrdbCursor_executemany(MrdbCursor *self,
|
||||
if (!self->is_prepared && self->statement)
|
||||
{
|
||||
MrdbCursor_clear(self, 0);
|
||||
MrdbParser_end(self->parser);
|
||||
self->parser= NULL;
|
||||
}
|
||||
|
||||
if (!self->stmt)
|
||||
@ -1348,12 +1417,8 @@ MrdbCursor_executemany(MrdbCursor *self,
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
self->is_text= 0;
|
||||
|
||||
if (!self->parser)
|
||||
{
|
||||
if (!(self->parser= MrdbParser_init(self->connection->mysql, statement, (size_t)statement_len)))
|
||||
/*
|
||||
if (!(self->parser= MrdbParser_init(self->connection->mysql, statement, (size_t)statement_len)))
|
||||
{
|
||||
exit(-1);
|
||||
}
|
||||
@ -1362,9 +1427,8 @@ MrdbCursor_executemany(MrdbCursor *self,
|
||||
PyErr_SetString(Mariadb_ProgrammingError, errmsg);
|
||||
goto error;
|
||||
}
|
||||
CURSOR_SET_STATEMENT(self, statement, statement_len);
|
||||
}
|
||||
|
||||
*/
|
||||
if (mariadb_check_bulk_parameters(self, self->data))
|
||||
goto error;
|
||||
|
||||
@ -1374,8 +1438,8 @@ MrdbCursor_executemany(MrdbCursor *self,
|
||||
if (!(self->connection->extended_server_capabilities &
|
||||
(MARIADB_CLIENT_STMT_BULK_OPERATIONS >> 32)))
|
||||
{
|
||||
if (MrdbCursor_executemany_fallback(self, self->parser->statement.str,
|
||||
self->parser->statement.length))
|
||||
if (MrdbCursor_executemany_fallback(self, self->parseinfo.statement,
|
||||
self->parseinfo.statement_len))
|
||||
goto error;
|
||||
MARIADB_FREE_MEM(self->values);
|
||||
Py_RETURN_NONE;
|
||||
@ -1384,13 +1448,13 @@ MrdbCursor_executemany(MrdbCursor *self,
|
||||
mysql_stmt_attr_set(self->stmt, STMT_ATTR_ARRAY_SIZE, &self->array_size);
|
||||
if (do_prepare)
|
||||
{
|
||||
mysql_stmt_attr_set(self->stmt, STMT_ATTR_PREBIND_PARAMS, &self->param_count);
|
||||
mysql_stmt_attr_set(self->stmt, STMT_ATTR_PREBIND_PARAMS, &self->parseinfo.paramcount);
|
||||
mysql_stmt_attr_set(self->stmt, STMT_ATTR_CB_USER_DATA, (void *)self);
|
||||
mysql_stmt_attr_set(self->stmt, STMT_ATTR_CB_PARAM, mariadb_param_update);
|
||||
|
||||
mysql_stmt_bind_param(self->stmt, self->params);
|
||||
|
||||
if (Mrdb_execute_direct(self))
|
||||
// if (Mrdb_execute_direct(self))
|
||||
{
|
||||
mariadb_throw_exception(self->stmt, NULL, 1, NULL);
|
||||
goto error;
|
||||
@ -1413,8 +1477,6 @@ MrdbCursor_executemany(MrdbCursor *self,
|
||||
Py_RETURN_NONE;
|
||||
error:
|
||||
MrdbCursor_clear(self, 0);
|
||||
MrdbParser_end(self->parser);
|
||||
self->parser= NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1428,16 +1490,9 @@ MrdbCursor_nextset(MrdbCursor *self)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
/* hmmm */
|
||||
if (!self->field_count)
|
||||
{
|
||||
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 0,
|
||||
"Cursor doesn't have a result set");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MARIADB_BEGIN_ALLOW_THREADS(self);
|
||||
if (!self->is_text)
|
||||
if (!self->parseinfo.is_text)
|
||||
rc= mysql_stmt_next_result(self->stmt);
|
||||
else
|
||||
{
|
||||
@ -1455,9 +1510,9 @@ MrdbCursor_nextset(MrdbCursor *self)
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
if (CURSOR_FIELD_COUNT(self))
|
||||
if ((self->field_count= CURSOR_FIELD_COUNT(self)))
|
||||
{
|
||||
if (MrdbCursor_InitResultSet(self))
|
||||
if (!MrdbCursor_InitResultSet(self))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
@ -1471,13 +1526,7 @@ MrdbCursor_nextset(MrdbCursor *self)
|
||||
static PyObject *
|
||||
Mariadb_row_count(MrdbCursor *self)
|
||||
{
|
||||
/* PEP-249 requires to return -1 if the cursor was not executed before */
|
||||
if (!self->statement)
|
||||
{
|
||||
return PyLong_FromLongLong(-1);
|
||||
}
|
||||
|
||||
return PyLong_FromLongLong(self->row_count);
|
||||
return PyLong_FromLongLong(CURSOR_NUM_ROWS(self));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
@ -1499,29 +1548,6 @@ MrdbCursor_warnings(MrdbCursor *self)
|
||||
return PyLong_FromLong((long)CURSOR_WARNING_COUNT(self));
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
MrdbCursor_getbuffered(MrdbCursor *self)
|
||||
{
|
||||
if (self->is_buffered)
|
||||
{
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
MrdbCursor_setbuffered(MrdbCursor *self, PyObject *arg)
|
||||
{
|
||||
if (!arg || !CHECK_TYPE(arg, &PyBool_Type))
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "Argument must be boolean");
|
||||
return -1;
|
||||
}
|
||||
|
||||
self->is_buffered= PyObject_IsTrue(arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
MrdbCursor_lastrowid(MrdbCursor *self)
|
||||
{
|
||||
@ -1628,3 +1654,169 @@ end:
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
MrdbCursor_parse(MrdbCursor *self, PyObject *args)
|
||||
{
|
||||
const char *statement= NULL;
|
||||
Py_ssize_t statement_len= 0;
|
||||
MrdbParser *parser= NULL;
|
||||
char errmsg[128];
|
||||
|
||||
if (self->parseinfo.statement)
|
||||
{
|
||||
MrdbCursor_clearparseinfo(&self->parseinfo);
|
||||
}
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#|Ob", &statement, &statement_len))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(parser= MrdbParser_init(self->connection->mysql, statement, statement_len)))
|
||||
{
|
||||
mariadb_throw_exception(NULL, Mariadb_ProgrammingError, 0,
|
||||
"Can't initialize parser.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (MrdbParser_parse(parser, 0, errmsg, 128))
|
||||
{
|
||||
MrdbParser_end(parser);
|
||||
PyErr_SetString(Mariadb_ProgrammingError, errmsg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* cleanup and save some parser stuff */
|
||||
|
||||
self->parseinfo.paramcount= parser->param_count;
|
||||
self->parseinfo.paramstyle= parser->paramstyle;
|
||||
self->parseinfo.statement= PyMem_RawCalloc(parser->statement.length + 1, 1);
|
||||
memcpy(self->parseinfo.statement, parser->statement.str, parser->statement.length);
|
||||
self->parseinfo.statement_len= parser->statement.length;
|
||||
self->parseinfo.paramlist= parser->param_list;
|
||||
self->parseinfo.is_text= (parser->command == SQL_NONE || parser->command == SQL_OTHER);
|
||||
|
||||
if (parser->paramstyle == PYFORMAT && parser->keys)
|
||||
{
|
||||
PyObject *tmp= PyTuple_New(parser->param_count);
|
||||
for (uint32_t i= 0; i < parser->param_count; i++)
|
||||
{
|
||||
PyObject *key;
|
||||
key= PyUnicode_FromString(parser->keys[i].str);
|
||||
PyTuple_SetItem(tmp, i, key);
|
||||
}
|
||||
self->parseinfo.keys= tmp;
|
||||
}
|
||||
MrdbParser_end(parser);
|
||||
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
MrdbCursor_execute_binary(MrdbCursor *self)
|
||||
{
|
||||
int rc;
|
||||
|
||||
MARIADB_CHECK_CONNECTION(self->connection, NULL);
|
||||
|
||||
if (!self->stmt &&
|
||||
!(self->stmt= mysql_stmt_init(self->connection->mysql)))
|
||||
{
|
||||
mariadb_throw_exception(self->connection->mysql, NULL, 0, NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (self->data && self->parseinfo.paramcount)
|
||||
{
|
||||
if (mariadb_check_execute_parameters(self, self->data))
|
||||
goto error;
|
||||
|
||||
/* Load values */
|
||||
if (mariadb_param_update(self, self->params, 0))
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (self->reprepare)
|
||||
{
|
||||
printf("restting statement\n");
|
||||
mysql_stmt_reset(self->stmt);
|
||||
mysql_stmt_attr_set(self->stmt, STMT_ATTR_PREBIND_PARAMS, &self->parseinfo.paramcount);
|
||||
mysql_stmt_attr_set(self->stmt, STMT_ATTR_CB_USER_DATA, (void *)self);
|
||||
}
|
||||
|
||||
if (self->parseinfo.paramcount)
|
||||
mysql_stmt_bind_param(self->stmt, self->params);
|
||||
|
||||
if ((rc= Mrdb_execute_direct(self, self->parseinfo.statement, self->parseinfo.statement_len)))
|
||||
{
|
||||
mariadb_throw_exception(self->connection->mysql, NULL, 0, NULL);
|
||||
goto error;
|
||||
}
|
||||
|
||||
self->field_count= mysql_stmt_field_count(self->stmt);
|
||||
Py_RETURN_NONE;
|
||||
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
MrdbCursor_execute_text(MrdbCursor *self, PyObject *args)
|
||||
{
|
||||
int rc;
|
||||
MYSQL *db;
|
||||
char *statement;
|
||||
size_t statement_len;
|
||||
|
||||
MARIADB_CHECK_CONNECTION(self->connection, NULL);
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#", &statement, &statement_len))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
db= self->connection->mysql;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
rc= mysql_send_query(db, statement, statement_len);
|
||||
Py_END_ALLOW_THREADS;
|
||||
|
||||
if (rc)
|
||||
{
|
||||
mariadb_throw_exception(db, NULL, 0, NULL);
|
||||
return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
MrdbCursor_readresponse(MrdbCursor *self)
|
||||
{
|
||||
int rc;
|
||||
MYSQL *db;
|
||||
|
||||
MARIADB_CHECK_CONNECTION(self->connection, NULL);
|
||||
|
||||
db= self->connection->mysql;
|
||||
|
||||
if (self->parseinfo.is_text)
|
||||
{
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
rc= db->methods->db_read_query_result(db);
|
||||
Py_END_ALLOW_THREADS;
|
||||
|
||||
if (rc)
|
||||
{
|
||||
mariadb_throw_exception(db, NULL, 0, NULL);
|
||||
return NULL;
|
||||
}
|
||||
self->field_count= mysql_field_count(self->connection->mysql);
|
||||
} else
|
||||
{
|
||||
self->field_count= mysql_stmt_field_count(self->stmt);
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,20 @@ const char *comment_start= "/*";
|
||||
const char *comment_end= "*/";
|
||||
const char literals[3]= {'\'', '\"', '`'};
|
||||
|
||||
static struct {
|
||||
enum enum_binary_command command;
|
||||
MrdbString str;
|
||||
} binary_command[] =
|
||||
{
|
||||
{SQL_INSERT, {"INSERT", 6}},
|
||||
{SQL_UPDATE, {"UPDATE", 6}},
|
||||
{SQL_REPLACE, {"REPLACE", 7}},
|
||||
{SQL_DELETE, {"DELETE", 6}},
|
||||
{SQL_CALL, {"CALL", 4}},
|
||||
{SQL_DO, {"DO", 2}},
|
||||
{SQL_NONE, {NULL, 0}}
|
||||
};
|
||||
|
||||
static uint8_t
|
||||
check_keyword(char* ofs, char* end, char* keyword, size_t keylen)
|
||||
{
|
||||
@ -92,6 +106,8 @@ MrdbParser_init(MYSQL *mysql, const char *statement, size_t length)
|
||||
memcpy(p->statement.str, statement, length);
|
||||
p->statement.length= length;
|
||||
p->mysql= mysql;
|
||||
p->param_list= PyList_New(0);
|
||||
p->param_count= 0;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
@ -242,6 +258,7 @@ cont:
|
||||
/* parmastyle = qmark */
|
||||
if (*a == '?')
|
||||
{
|
||||
PyObject *tmp;
|
||||
if (p->paramstyle && p->paramstyle != QMARK)
|
||||
{
|
||||
parser_error(errmsg, errmsg_len,
|
||||
@ -250,6 +267,9 @@ cont:
|
||||
}
|
||||
p->paramstyle= QMARK;
|
||||
p->param_count++;
|
||||
tmp= PyLong_FromLong((long)(a - p->statement.str));
|
||||
PyList_Append(p->param_list, tmp);
|
||||
Py_DECREF(tmp);
|
||||
a++;
|
||||
continue;
|
||||
}
|
||||
@ -259,6 +279,7 @@ cont:
|
||||
/* paramstyle format */
|
||||
if (*(a+1) == 's' || *(a+1) == 'd')
|
||||
{
|
||||
PyObject *tmp;
|
||||
if (p->paramstyle && p->paramstyle != FORMAT)
|
||||
{
|
||||
parser_error(errmsg, errmsg_len,
|
||||
@ -269,6 +290,10 @@ cont:
|
||||
*a= '?';
|
||||
memmove(a+1, a+2, end - a);
|
||||
end--;
|
||||
|
||||
tmp= PyLong_FromLong((long)(a - p->statement.str));
|
||||
PyList_Append(p->param_list, tmp);
|
||||
Py_DECREF(tmp);
|
||||
a++;
|
||||
p->param_count++;
|
||||
continue;
|
||||
@ -276,6 +301,9 @@ cont:
|
||||
if (*(a+1) == '(')
|
||||
{
|
||||
char *val_end= strstr(a+1, ")s");
|
||||
PyObject *tmp;
|
||||
|
||||
|
||||
if (val_end)
|
||||
{
|
||||
ssize_t keylen= val_end - a + 1;
|
||||
@ -288,6 +316,9 @@ cont:
|
||||
p->paramstyle= PYFORMAT;
|
||||
*a= '?';
|
||||
p->param_count++;
|
||||
tmp= PyLong_FromLong((long)(a - p->statement.str));
|
||||
PyList_Append(p->param_list, tmp);
|
||||
Py_DECREF(tmp);
|
||||
if (p->keys)
|
||||
{
|
||||
MrdbString *m;
|
||||
@ -317,7 +348,7 @@ cont:
|
||||
memcpy(p->keys[p->param_count - 1].str, a + 2, keylen - 3);
|
||||
|
||||
p->keys[p->param_count - 1].length= keylen - 3;
|
||||
memmove(a+1, val_end+2, end - a - keylen);
|
||||
memmove(a+1, val_end+2, end - a - keylen + 1);
|
||||
a+= 1;
|
||||
end -= keylen;
|
||||
continue;
|
||||
@ -346,7 +377,24 @@ cont:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* determine SQL command */
|
||||
if (p->command == SQL_NONE && p->param_count)
|
||||
{
|
||||
for (uint8_t i=0; binary_command[i].str.str; i++)
|
||||
{
|
||||
if (check_keyword(a, end, binary_command[i].str.str,
|
||||
binary_command[i].str.length))
|
||||
{
|
||||
p->command= binary_command[i].command;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (p->command == SQL_NONE)
|
||||
p->command= SQL_OTHER;
|
||||
}
|
||||
|
||||
}
|
||||
lastchar= *a;
|
||||
a++;
|
||||
}
|
||||
|
60
mariadb/mariadb_protocol.py
Normal file
60
mariadb/mariadb_protocol.py
Normal file
@ -0,0 +1,60 @@
|
||||
#
|
||||
# Copyright (C) 2021 Georg Richter and MariaDB Corporation AB
|
||||
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Library General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2 of the License, or (at your option) any later version.
|
||||
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Library General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU Library General Public
|
||||
# License along with this library; if not see <http://www.gnu.org/licenses>
|
||||
# or write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin St., Fifth Floor, Boston, MA 02110, USA
|
||||
#
|
||||
|
||||
import struct
|
||||
|
||||
PROT_CMD_SLEEP= 0
|
||||
PROT_CMD_QUIT= 1
|
||||
PROT_CMD_INIT_DB= 2
|
||||
PROT_CMD_QUERY= 3
|
||||
PROT_CMD_FIELD_LIST= 4
|
||||
PROT_CMD_CREATE_DB= 5
|
||||
PROT_CMD_DROP_DB= 6
|
||||
PROT_CMD_REFRESH= 7
|
||||
PROT_CMD_SHUTDOWN= 8
|
||||
PROT_CMD_STATISTICS= 9
|
||||
PROT_CMD_PROCESS_INFO= 10
|
||||
PROT_CMD_CONNECT= 11
|
||||
PROT_CMD_PROCESS_KILL= 12
|
||||
PROT_CMD_DEBUG= 13
|
||||
PROT_CMD_PING= 14
|
||||
PROT_CMD_TIME= 15,
|
||||
PROT_CMD_DELAYED_INSERT= 16
|
||||
PROT_CMD_CHANGE_USER= 17
|
||||
PROT_CMD_BINLOG_DUMP= 18
|
||||
PROT_CMD_TABLE_DUMP= 19
|
||||
PROT_CMD_CONNECT_OUT = 20
|
||||
PROT_CMD_REGISTER_SLAVE= 21
|
||||
PROT_CMD_STMT_PREPARE= 22
|
||||
PROT_CMD_STMT_EXECUTE= 23
|
||||
PROT_CMD_STMT_SEND_LONG_DATA = 24
|
||||
PROT_CMD_STMT_CLOSE= 25
|
||||
PROT_CMD_STMT_RESET= 26
|
||||
PROT_CMD_SET_OPTION= 27
|
||||
PROT_CMD_STMT_FETCH= 28
|
||||
PROT_CMD_DAEMON= 29
|
||||
PROT_CMD_UNSUPPORTED= 30
|
||||
PROT_CMD_RESET_CONNECTION= 31
|
||||
PROT_CMD_STMT_BULK_EXECUTE= 250
|
||||
|
||||
def prot_length(buffer_size):
|
||||
|
||||
def send_command(socket, command, buffer):
|
||||
|
||||
|
3
mariadb/release_info.py
Normal file
3
mariadb/release_info.py
Normal file
@ -0,0 +1,3 @@
|
||||
__author__='Georg Richter'
|
||||
__version__='1.1.0'
|
||||
__version_info__=(1, 1, 0, 'alpha', 0)
|
@ -42,7 +42,7 @@ def dequote(s):
|
||||
|
||||
|
||||
def get_config(options):
|
||||
required_version = "3.1.5"
|
||||
required_version = "3.2.0"
|
||||
no_env = 0
|
||||
static = options["link_static"]
|
||||
|
||||
|
2
setup.py
2
setup.py
@ -98,6 +98,6 @@ setup(name='mariadb',
|
||||
py_modules=['mariadb.__init__', 'mariadb.constants.CLIENT', 'mariadb.constants.CURSOR',
|
||||
'mariadb.constants.STATUS',
|
||||
'mariadb.field', 'mariadb.dbapi20', 'mariadb.connections', 'mariadb.connectionpool',
|
||||
'mariadb.cursor', 'mariadb.release_info',
|
||||
'mariadb.cursor', 'mariadb.release_info', 'mariadb.async_connections', 'mariadb.codecs',
|
||||
'mariadb.constants.FIELD_TYPE', 'mariadb.constants.FIELD_FLAG', 'mariadb.constants.INDICATOR'],
|
||||
)
|
||||
|
Reference in New Issue
Block a user