From a4ee3e9c844cef597d6a54a7e875a2d5c8f4aade Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Thu, 5 Feb 2015 13:01:04 +0900 Subject: [PATCH 01/25] 0.3 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index b39f3d6..6cd1632 100755 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup( name="Tornado-MySQL", - version="0.2", + version="0.3", url='https://github.com/PyMySQL/Tornado-MySQL', author='INADA Naoki', author_email='songofacandy@gmail.com', From fdea36de86368ef3e62aa645ab2d10e5745cdd38 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 10 Feb 2015 17:48:20 +0900 Subject: [PATCH 02/25] Fix pool.begin() doesn't begin transaction --- tornado_mysql/pools.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tornado_mysql/pools.py b/tornado_mysql/pools.py index 21c6d82..7d7756f 100644 --- a/tornado_mysql/pools.py +++ b/tornado_mysql/pools.py @@ -111,6 +111,7 @@ def begin(self): :rtype: Future """ conn = yield self._get_conn() + yield conn.begin() trx = Transaction(self, conn) raise Return(trx) From fe216190ff8de68c3617e27eae41cea2362d0f11 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Wed, 11 Feb 2015 01:30:45 +0900 Subject: [PATCH 03/25] 0.4 --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6cd1632..c545f0d 100755 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ setup( name="Tornado-MySQL", - version="0.3", + version="0.4", url='https://github.com/PyMySQL/Tornado-MySQL', author='INADA Naoki', author_email='songofacandy@gmail.com', From dd44a8e55eb33cad043f24a8c0d5d6efdd0ff24c Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 14 Apr 2015 17:22:09 +0900 Subject: [PATCH 04/25] pool: Add max_open_connections option --- tornado_mysql/pools.py | 63 ++++++++++++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 15 deletions(-) diff --git a/tornado_mysql/pools.py b/tornado_mysql/pools.py index 7d7756f..58b3ce5 100644 --- a/tornado_mysql/pools.py +++ b/tornado_mysql/pools.py @@ -2,13 +2,14 @@ from __future__ import absolute_import, division, print_function from collections import deque -import sys import warnings from tornado.ioloop import IOLoop from tornado.gen import coroutine, Return -from tornado.concurrent import Future +from tornado.concurrent import Future, chain_future + from tornado_mysql import connect +from tornado_mysql.connections import Connection DEBUG = False @@ -32,52 +33,84 @@ def __init__(self, connect_kwargs, max_idle_connections=1, max_recycle_sec=3600, + max_open_connections=0, io_loop=None, ): """ :param dict connect_kwargs: kwargs for tornado_mysql.connect() :param int max_idle_connections: Max number of keeping connections. :param int max_recycle_sec: How long connections are recycled. + :param int max_open_connections: + Max number of opened connections. 0 means no limit. """ connect_kwargs['autocommit'] = True self.io_loop = io_loop or IOLoop.current() self.connect_kwargs = connect_kwargs - self.max_idle_connections = max_idle_connections + self.max_idle = max_idle_connections + self.max_open = max_open_connections self.max_recycle_sec = max_recycle_sec self._opened_conns = 0 self._free_conn = deque() + self._waitings = deque() + + def stat(self): + return (self._opened_conns, len(self._free_conn), len(self._waitings)) def _get_conn(self): now = self.io_loop.time() + + # Try to reuse in free pool while self._free_conn: conn = self._free_conn.popleft() if now - conn.connected_time > self.max_recycle_sec: self._close_async(conn) continue - _debug("Reusing connection from pool (opened=%d)" % (self._opened_conns,)) + _debug("Reusing connection from pool:", self.stat()) fut = Future() fut.set_result(conn) return fut - self._opened_conns += 1 - _debug("Creating new connection (opened=%d)" % (self._opened_conns,)) - return connect(**self.connect_kwargs) + # Open new connection + if self.max_open and self._opened_conns < self.max_open: + self._opened_conns += 1 + _debug("Creating new connection:", self.stat()) + return connect(**self.connect_kwargs) + + # Wait to other connection is released. + fut = Future() + self._waitings.append(fut) + return fut def _put_conn(self, conn): - if (len(self._free_conn) < self.max_idle_connections and + if (len(self._free_conn) < self.max_idle and self.io_loop.time() - conn.connected_time < self.max_recycle_sec): - self._free_conn.append(conn) + if self._waitings: + fut = self._waitings.popleft() + fut.set_result(conn) + _debug("Passing returned connection to waiter:", self.stat()) + else: + self._free_conn.append(conn) + _debug("Add conn to free pool:", self.stat()) else: self._close_async(conn) def _close_async(self, conn): - self.io_loop.add_future(conn.close_async(), callback=lambda f: None) - self._opened_conns -= 1 + self.io_loop.add_future(conn.close_async(), callback=self._after_close) def _close_conn(self, conn): conn.close() - self._opened_conns -= 1 + self._after_close() + + def _after_close(self, fut=None): + if self._waitings: + fut = self._waitings.popleft() + conn = Connection(**self.connect_kwargs) + cf = conn.connect() + self.io_loop.add_future(cf, callback=lambda f: fut.set_result(conn)) + else: + self._opened_conns -= 1 + _debug("Connection closed:", self.stat()) @coroutine def execute(self, query, params=None): @@ -94,11 +127,11 @@ def execute(self, query, params=None): cur = conn.cursor() yield cur.execute(query, params) yield cur.close() - self._put_conn(conn) except: - self._opened_conns -= 1 - conn.close() + self._close_conn(conn) raise + else: + self._put_conn(conn) raise Return(cur) @coroutine From 45c2ed0be0a031072821a96f0baa89e8186d18e5 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 14 Apr 2015 17:22:51 +0900 Subject: [PATCH 05/25] Update examples --- example.py => example/example.py | 0 example_pool.py => example/pool.py | 0 example/pool2.py | 38 ++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+) rename example.py => example/example.py (100%) rename example_pool.py => example/pool.py (100%) create mode 100644 example/pool2.py diff --git a/example.py b/example/example.py similarity index 100% rename from example.py rename to example/example.py diff --git a/example_pool.py b/example/pool.py similarity index 100% rename from example_pool.py rename to example/pool.py diff --git a/example/pool2.py b/example/pool2.py new file mode 100644 index 0000000..f41313f --- /dev/null +++ b/example/pool2.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +from __future__ import print_function + +import random +from tornado import ioloop, gen +from tornado_mysql import pools + + +pools.DEBUG = True + + +POOL = pools.Pool( + dict(host='127.0.0.1', port=3306, user='root', passwd='', db='mysql'), + max_idle_connections=2, + max_recycle_sec=3, + max_open_connections=5, +) + + +@gen.coroutine +def worker(n): + for i in range(20): + t = random.random() * 5 + print(n, "sleeping", t, "seconds") + cur = yield POOL.execute("SELECT SLEEP(%s)", (t,)) + print(n, cur.fetchall()) + yield gen.sleep(t) + + +@gen.coroutine +def main(): + workers = [worker(i) for i in range(10)] + yield workers + + +ioloop.IOLoop.current().run_sync(main) +print(POOL._opened_conns) + From 7b10471ec4499687ca2b7586f5d74bc134fdb5a4 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 14 Apr 2015 23:07:14 +0900 Subject: [PATCH 06/25] Close connection when conn.begin() fails --- tornado_mysql/pools.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tornado_mysql/pools.py b/tornado_mysql/pools.py index 58b3ce5..639ae46 100644 --- a/tornado_mysql/pools.py +++ b/tornado_mysql/pools.py @@ -144,7 +144,11 @@ def begin(self): :rtype: Future """ conn = yield self._get_conn() - yield conn.begin() + try: + yield conn.begin() + except: + self._close_conn(conn) + raise trx = Transaction(self, conn) raise Return(trx) From 125c663339fb2af054f42873bef221bbff73e22e Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 14 Apr 2015 23:09:34 +0900 Subject: [PATCH 07/25] nit fix --- tornado_mysql/pools.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tornado_mysql/pools.py b/tornado_mysql/pools.py index 639ae46..bc811ef 100644 --- a/tornado_mysql/pools.py +++ b/tornado_mysql/pools.py @@ -6,7 +6,7 @@ from tornado.ioloop import IOLoop from tornado.gen import coroutine, Return -from tornado.concurrent import Future, chain_future +from tornado.concurrent import Future from tornado_mysql import connect from tornado_mysql.connections import Connection @@ -55,6 +55,7 @@ def __init__(self, self._waitings = deque() def stat(self): + """Returns (opened connections, free connections, waiters)""" return (self._opened_conns, len(self._free_conn), len(self._waitings)) def _get_conn(self): From bd99b4d8575d2f49b0d5de355f588060d32fe760 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 14 Apr 2015 23:29:39 +0900 Subject: [PATCH 08/25] 0.5 --- MANIFEST.in | 1 - setup.py | 9 +-------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index c57b5ea..c2442c6 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,2 @@ include README.rst LICENSE CHANGELOG include runtests.py tox.ini -include example.py example_pool diff --git a/setup.py b/setup.py index c545f0d..cc0e1a7 100755 --- a/setup.py +++ b/setup.py @@ -1,21 +1,14 @@ #!/usr/bin/env python from setuptools import setup, find_packages -try: - with open('README.rst') as f: - readme = f.read() -except IOError: - readme = '' - setup( name="Tornado-MySQL", - version="0.4", + version="0.5", url='https://github.com/PyMySQL/Tornado-MySQL', author='INADA Naoki', author_email='songofacandy@gmail.com', description='Pure Python MySQL Driver for Tornado', install_requires=['tornado>=4.0'], - long_description=readme, license="MIT", packages=find_packages(), classifiers=[ From 4951ec25a49bec5d25ead95b162b4b61fd092020 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Fri, 17 Apr 2015 13:00:28 +0900 Subject: [PATCH 09/25] Fix _get_conn() hungup when max_open_connections=0 Fixes #6 --- tornado_mysql/pools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tornado_mysql/pools.py b/tornado_mysql/pools.py index bc811ef..f7c4b69 100644 --- a/tornado_mysql/pools.py +++ b/tornado_mysql/pools.py @@ -73,7 +73,7 @@ def _get_conn(self): return fut # Open new connection - if self.max_open and self._opened_conns < self.max_open: + if self.max_open == 0 or self._opened_conns < self.max_open: self._opened_conns += 1 _debug("Creating new connection:", self.stat()) return connect(**self.connect_kwargs) From e19a81edfac01bb7969ea2d6874837dbc713530f Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 26 May 2015 22:05:55 +0900 Subject: [PATCH 10/25] Decrement Pool._opened_conns when connect() raises exception --- tornado_mysql/pools.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tornado_mysql/pools.py b/tornado_mysql/pools.py index f7c4b69..058d712 100644 --- a/tornado_mysql/pools.py +++ b/tornado_mysql/pools.py @@ -58,7 +58,7 @@ def stat(self): """Returns (opened connections, free connections, waiters)""" return (self._opened_conns, len(self._free_conn), len(self._waitings)) - def _get_conn(self): + def _get_conn(self): # -> Future[connection] now = self.io_loop.time() # Try to reuse in free pool @@ -76,13 +76,19 @@ def _get_conn(self): if self.max_open == 0 or self._opened_conns < self.max_open: self._opened_conns += 1 _debug("Creating new connection:", self.stat()) - return connect(**self.connect_kwargs) + fut = connect(**self.connect_kwargs) + fut.add_done_callback(self._on_connect) # self._opened_conns -=1 on exception + return fut # Wait to other connection is released. fut = Future() self._waitings.append(fut) return fut + def _on_connect(self, fut): + if fut.exception(): + self._opened_conns -= 1 + def _put_conn(self, conn): if (len(self._free_conn) < self.max_idle and self.io_loop.time() - conn.connected_time < self.max_recycle_sec): From 085d6cd31e8dce17a4d5c98085a03d8adf896bda Mon Sep 17 00:00:00 2001 From: YuanLin Date: Wed, 29 Jul 2015 17:05:26 +0800 Subject: [PATCH 11/25] Fix transaction.execute args to kwargs Fix transaction.execute args to kwargs, keep execute interface same like pool.excute. --- tornado_mysql/pools.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tornado_mysql/pools.py b/tornado_mysql/pools.py index f7c4b69..db6048b 100644 --- a/tornado_mysql/pools.py +++ b/tornado_mysql/pools.py @@ -169,7 +169,7 @@ def _close(self): self._pool = self._conn = None @coroutine - def execute(self, query, args): + def execute(self, query, args=None): """ :return: Future[Cursor] :rtype: Future From b15bf91d9a4b7286b307de29243d82cc088b88b8 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 8 Sep 2015 10:20:28 +0900 Subject: [PATCH 12/25] mv PyMySQL tests --- {pymysql => tornado_mysql}/tests/data/load_local_data.txt | 0 {pymysql => tornado_mysql}/tests/data/load_local_warn_data.txt | 0 {pymysql => tornado_mysql}/tests/test_cursor.py | 0 {pymysql => tornado_mysql}/tests/test_load_local.py | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename {pymysql => tornado_mysql}/tests/data/load_local_data.txt (100%) rename {pymysql => tornado_mysql}/tests/data/load_local_warn_data.txt (100%) rename {pymysql => tornado_mysql}/tests/test_cursor.py (100%) rename {pymysql => tornado_mysql}/tests/test_load_local.py (100%) diff --git a/pymysql/tests/data/load_local_data.txt b/tornado_mysql/tests/data/load_local_data.txt similarity index 100% rename from pymysql/tests/data/load_local_data.txt rename to tornado_mysql/tests/data/load_local_data.txt diff --git a/pymysql/tests/data/load_local_warn_data.txt b/tornado_mysql/tests/data/load_local_warn_data.txt similarity index 100% rename from pymysql/tests/data/load_local_warn_data.txt rename to tornado_mysql/tests/data/load_local_warn_data.txt diff --git a/pymysql/tests/test_cursor.py b/tornado_mysql/tests/test_cursor.py similarity index 100% rename from pymysql/tests/test_cursor.py rename to tornado_mysql/tests/test_cursor.py diff --git a/pymysql/tests/test_load_local.py b/tornado_mysql/tests/test_load_local.py similarity index 100% rename from pymysql/tests/test_load_local.py rename to tornado_mysql/tests/test_load_local.py From b19db7f40b151322317f4e269ff09a8b8ad79034 Mon Sep 17 00:00:00 2001 From: Dmitry Orlov Date: Wed, 23 Sep 2015 18:49:06 +0300 Subject: [PATCH 13/25] [fea] logging with logging --- tornado_mysql/pools.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/tornado_mysql/pools.py b/tornado_mysql/pools.py index db6048b..8f09b74 100644 --- a/tornado_mysql/pools.py +++ b/tornado_mysql/pools.py @@ -3,6 +3,7 @@ from collections import deque import warnings +import logging from tornado.ioloop import IOLoop from tornado.gen import coroutine, Return @@ -12,12 +13,7 @@ from tornado_mysql.connections import Connection -DEBUG = False - - -def _debug(*msg): - if DEBUG: - print(*msg) +log = logging.getLogger("tornado_mysql.pools") class Pool(object): @@ -67,7 +63,7 @@ def _get_conn(self): if now - conn.connected_time > self.max_recycle_sec: self._close_async(conn) continue - _debug("Reusing connection from pool:", self.stat()) + log.debug("Reusing connection from pool: %s", self.stat()) fut = Future() fut.set_result(conn) return fut @@ -75,7 +71,7 @@ def _get_conn(self): # Open new connection if self.max_open == 0 or self._opened_conns < self.max_open: self._opened_conns += 1 - _debug("Creating new connection:", self.stat()) + log.debug("Creating new connection: %s", self.stat()) return connect(**self.connect_kwargs) # Wait to other connection is released. @@ -89,10 +85,10 @@ def _put_conn(self, conn): if self._waitings: fut = self._waitings.popleft() fut.set_result(conn) - _debug("Passing returned connection to waiter:", self.stat()) + log.debug("Passing returned connection to waiter: %s", self.stat()) else: self._free_conn.append(conn) - _debug("Add conn to free pool:", self.stat()) + log.debug("Add conn to free pool: %s", self.stat()) else: self._close_async(conn) @@ -111,7 +107,7 @@ def _after_close(self, fut=None): self.io_loop.add_future(cf, callback=lambda f: fut.set_result(conn)) else: self._opened_conns -= 1 - _debug("Connection closed:", self.stat()) + log.debug("Connection closed: %s", self.stat()) @coroutine def execute(self, query, params=None): @@ -194,4 +190,5 @@ def rollback(self): def __del__(self): if self._pool is not None: warnings.warn("Transaction has not committed or rollbacked.") + log.warn("Transaction has not committed or rollbacked.") self._pool._close_conn(self._conn) From 9780bf703f9f3791b7a1987ad3427ac201e3db1d Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Wed, 28 Oct 2015 22:19:00 +0900 Subject: [PATCH 14/25] close_async check connection is closed already --- tornado_mysql/connections.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tornado_mysql/connections.py b/tornado_mysql/connections.py index c266ed1..2a14f4e 100644 --- a/tornado_mysql/connections.py +++ b/tornado_mysql/connections.py @@ -624,6 +624,9 @@ def close(self): @gen.coroutine def close_async(self): """Send the quit message and close the socket""" + if self._stream is None or self._stream.closed(): + self._stream = None + return send_data = struct.pack(' Date: Wed, 28 Oct 2015 22:22:30 +0900 Subject: [PATCH 15/25] 0.5.1 --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index cc0e1a7..94d7a11 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ setup( name="Tornado-MySQL", - version="0.5", + version="0.5.1", url='https://github.com/PyMySQL/Tornado-MySQL', author='INADA Naoki', author_email='songofacandy@gmail.com', @@ -17,6 +17,7 @@ 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', 'Development Status :: 3 - Alpha', From 8c50eeece10c8c54bbce25a39d6c2489b1075d63 Mon Sep 17 00:00:00 2001 From: Ping Date: Fri, 6 Nov 2015 09:03:01 +0800 Subject: [PATCH 16/25] Add Cursor Class parameter for pool's excute function --- tornado_mysql/pools.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tornado_mysql/pools.py b/tornado_mysql/pools.py index 8f09b74..bb3e721 100644 --- a/tornado_mysql/pools.py +++ b/tornado_mysql/pools.py @@ -110,18 +110,19 @@ def _after_close(self, fut=None): log.debug("Connection closed: %s", self.stat()) @coroutine - def execute(self, query, params=None): + def execute(self, query, params=None, cursor=None): """Execute query in pool. Returns future yielding closed cursor. You can get rows, lastrowid, etc from the cursor. + :param cursor: cursor class(Cursor, DictCursor. etc.) :return: Future of cursor :rtype: Future """ conn = yield self._get_conn() try: - cur = conn.cursor() + cur = conn.cursor(cursor) yield cur.execute(query, params) yield cur.close() except: From ea950078d4baccdf7b5c6667a129947796d6b134 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Fri, 6 May 2016 21:52:25 +0900 Subject: [PATCH 17/25] remove LOAD LOCAL INFILE support --- .travis.databases.json | 2 +- tornado_mysql/connections.py | 77 +------------------------- tornado_mysql/tests/base.py | 2 +- tornado_mysql/tests/test_load_local.py | 68 ----------------------- 4 files changed, 3 insertions(+), 146 deletions(-) delete mode 100644 tornado_mysql/tests/test_load_local.py diff --git a/.travis.databases.json b/.travis.databases.json index f27349d..852209e 100644 --- a/.travis.databases.json +++ b/.travis.databases.json @@ -1,4 +1,4 @@ [ - {"host": "localhost", "user": "root", "passwd": "", "db": "test_pymysql", "use_unicode": true, "local_infile": true}, + {"host": "localhost", "user": "root", "passwd": "", "db": "test_pymysql", "use_unicode": true}, {"host": "localhost", "user": "root", "passwd": "", "db": "test_pymysql2" } ] diff --git a/tornado_mysql/connections.py b/tornado_mysql/connections.py index 2a14f4e..ef7e0b9 100644 --- a/tornado_mysql/connections.py +++ b/tornado_mysql/connections.py @@ -322,9 +322,6 @@ def is_resultset_packet(self): field_count = ord(self._data[0:1]) return 1 <= field_count <= 250 - def is_load_local_packet(self): - return self._data[0:1] == b'\xfb' - def is_error_packet(self): return self._data[0:1] == b'\xff' @@ -437,26 +434,6 @@ def __getattr__(self, key): return getattr(self.packet, key) -class LoadLocalPacketWrapper(object): - """ - Load Local Packet Wrapper. It uses an existing packet object, and wraps - around it, exposing useful variables while still providing access - to the original packet objects variables and methods. - """ - - def __init__(self, from_packet): - if not from_packet.is_load_local_packet(): - raise ValueError( - "Cannot create '{0}' object from invalid packet type".format( - self.__class__)) - - self.packet = from_packet - self.filename = self.packet.get_all_data()[1:] - if DEBUG: print("filename=", self.filename) - - def __getattr__(self, key): - return getattr(self.packet, key) - class Connection(object): """ @@ -476,8 +453,7 @@ def __init__(self, host="localhost", user=None, password="", client_flag=0, cursorclass=Cursor, init_command=None, connect_timeout=None, ssl=None, read_default_group=None, compress=None, named_pipe=None, no_delay=False, - autocommit=False, db=None, passwd=None, local_infile=False, - io_loop=None): + autocommit=False, db=None, passwd=None, io_loop=None): """ Establish a connection to the MySQL database. Accepts several arguments: @@ -511,7 +487,6 @@ def __init__(self, host="localhost", user=None, password="", no_delay: Disable Nagle's algorithm on the socket autocommit: Autocommit mode. None means use server default. (default: False) io_loop: Tornado IOLoop - local_infile: Boolean to enable the use of LOAD DATA LOCAL command. (default: False) db: Alias for database. (for compatibility to MySQLdb) passwd: Alias for password. (for compatibility to MySQLdb) @@ -529,9 +504,6 @@ def __init__(self, host="localhost", user=None, password="", if compress or named_pipe: raise NotImplementedError("compress and named_pipe arguments are not supported") - if local_infile: - client_flag |= CLIENT.LOCAL_FILES - if ssl and ('capath' in ssl or 'cipher' in ssl): raise NotImplementedError('ssl options capath and cipher are not supported') @@ -1063,8 +1035,6 @@ def read(self): if first_packet.is_ok_packet(): self._read_ok_packet(first_packet) - elif first_packet.is_load_local_packet(): - self._read_load_local_packet(first_packet) else: yield self._read_result_packet(first_packet) finally: @@ -1097,16 +1067,6 @@ def _read_ok_packet(self, first_packet): self.message = ok_packet.message self.has_next = ok_packet.has_next - def _read_load_local_packet(self, first_packet): - load_packet = LoadLocalPacketWrapper(first_packet) - sender = LoadLocalFile(load_packet.filename, self.connection) - sender.send_data() - - ok_packet = self.connection._read_packet() - if not ok_packet.is_ok_packet(): - raise OperationalError(2014, "Commands Out of Sync") - self._read_ok_packet(ok_packet) - def _check_packet_is_eof(self, packet): if packet.is_eof_packet(): eof_packet = EOFPacketWrapper(packet) @@ -1212,39 +1172,4 @@ def _get_descriptions(self): self.description = tuple(description) -class LoadLocalFile(object): - def __init__(self, filename, connection): - self.filename = filename - self.connection = connection - - def send_data(self): - """Send data packets from the local file to the server""" - if not self.connection.socket: - raise InterfaceError("(0, '')") - - # sequence id is 2 as we already sent a query packet - seq_id = 2 - try: - with open(self.filename, 'rb') as open_file: - chunk_size = MAX_PACKET_LEN - prelude = b"" - packet = b"" - packet_size = 0 - - while True: - chunk = open_file.read(chunk_size) - if not chunk: - break - packet = struct.pack(' Date: Fri, 6 May 2016 22:32:57 +0900 Subject: [PATCH 18/25] Add WARNING section to README --- README.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.rst b/README.rst index 3262f46..e22f1c8 100644 --- a/README.rst +++ b/README.rst @@ -9,6 +9,15 @@ Tornado-MySQL This package contains a fork of PyMySQL supporting Tornado. + +WARNING +------- + +This library is experimental. Don't use for production unless you can fix problem yourself. + +If you think async is efficient, you're wrong. You shoud try thread before this. +See also: http://techspot.zzzeek.org/2015/02/15/asynchronous-python-and-databases/ + Example ------- From 2009c18de8e8855ace2192acc056c960ff550edd Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Fri, 10 Feb 2017 20:22:02 +0900 Subject: [PATCH 19/25] fix #38 --- tornado_mysql/cursors.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tornado_mysql/cursors.py b/tornado_mysql/cursors.py index cbb7032..d5f7745 100644 --- a/tornado_mysql/cursors.py +++ b/tornado_mysql/cursors.py @@ -230,7 +230,7 @@ def callproc(self, procname, args=()): for i in range_type(len(args))])) yield self._query(q) self._executed = q - yield gen.Return(args) + raise gen.Return(args) def fetchone(self): ''' Fetch the next row ''' From 4223e5d5b6ae2248ce2d067ca03e10da4dd74643 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Fri, 10 Feb 2017 20:25:17 +0900 Subject: [PATCH 20/25] update README --- README.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.rst b/README.rst index e22f1c8..0eccfc7 100644 --- a/README.rst +++ b/README.rst @@ -18,6 +18,12 @@ This library is experimental. Don't use for production unless you can fix probl If you think async is efficient, you're wrong. You shoud try thread before this. See also: http://techspot.zzzeek.org/2015/02/15/asynchronous-python-and-databases/ +I don't have motivation to improve this library. I only fix bugs. **Please don't send feature request.** + +Instead, you should your time and energy to port your project to asyncio and newest Python 3. +Please don't pay your time to **adding** new feature to this project. + + Example ------- From 9419b3eefc6c848500fbfcdae3925a5c28513c1f Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 13 Mar 2018 20:19:24 +0900 Subject: [PATCH 21/25] Update README --- README.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.rst b/README.rst index 0eccfc7..2113850 100644 --- a/README.rst +++ b/README.rst @@ -18,10 +18,11 @@ This library is experimental. Don't use for production unless you can fix probl If you think async is efficient, you're wrong. You shoud try thread before this. See also: http://techspot.zzzeek.org/2015/02/15/asynchronous-python-and-databases/ -I don't have motivation to improve this library. I only fix bugs. **Please don't send feature request.** +I don't have motivation to maintain this library. I won't add new features. **Please don't send feature request.** +I'm very lazy about fix bugs. **Don't expect bugs are fixed when you want**. -Instead, you should your time and energy to port your project to asyncio and newest Python 3. -Please don't pay your time to **adding** new feature to this project. +Instead, you should use your time and energy to port your project to asyncio and newest Python 3. +Please don't pay your time for this project. Example From 08b8926cc5f12d8dbd550167e45273975254261b Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 13 Mar 2018 20:37:53 +0900 Subject: [PATCH 22/25] Update travis --- .travis.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1b9a0d9..b083841 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,19 +1,18 @@ sudo: false language: python -python: "3.4" -env: - - TOX_ENV=py27 - - TOX_ENV=py33 - - TOX_ENV=py34 - - TOX_ENV=pypy - - TOX_ENV=pypy3 +python: + - "3.6" + - "3.5" + - "3.4" + - "2.7" + - "pypy" install: - - pip install -U tox + - pip install -U tornado before_script: - "mysql -e 'create database test_pymysql DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;'" - "mysql -e 'create database test_pymysql2 DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_general_ci;'" - cp .travis.databases.json tornado_mysql/tests/databases.json -script: tox -e $TOX_ENV +script: ./runtests.py From 38c5f7b05bc5e7edacbd7ccaf044097c0e0a12ae Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 13 Mar 2018 20:40:30 +0900 Subject: [PATCH 23/25] Update README more --- README.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 2113850..6edfded 100644 --- a/README.rst +++ b/README.rst @@ -13,9 +13,9 @@ This package contains a fork of PyMySQL supporting Tornado. WARNING ------- -This library is experimental. Don't use for production unless you can fix problem yourself. +This library is experimental and unmaintained. Don't use for production unless you can fix problem yourself. -If you think async is efficient, you're wrong. You shoud try thread before this. +If you think async is efficient, you're wrong. You shoud try thread pool before this. See also: http://techspot.zzzeek.org/2015/02/15/asynchronous-python-and-databases/ I don't have motivation to maintain this library. I won't add new features. **Please don't send feature request.** @@ -24,6 +24,8 @@ I'm very lazy about fix bugs. **Don't expect bugs are fixed when you want**. Instead, you should use your time and energy to port your project to asyncio and newest Python 3. Please don't pay your time for this project. +You can use aio-libs/aiomysql or ``run_in_executor()`` in asyncio. + Example ------- From f6b9f6aa385f77c53d1e37a62e8cf15b64ced4aa Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 13 Mar 2018 20:49:48 +0900 Subject: [PATCH 24/25] fix pypy --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index b083841..e337c46 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,9 @@ python: - "2.7" - "pypy" +env: + - PYTHONIOENCODING=utf-8 + install: - pip install -U tornado From 293950f5e4fa9d951303a37dad38a0f93af97639 Mon Sep 17 00:00:00 2001 From: INADA Naoki Date: Tue, 13 Mar 2018 20:57:19 +0900 Subject: [PATCH 25/25] fix pypy --- tornado_mysql/cursors.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tornado_mysql/cursors.py b/tornado_mysql/cursors.py index d5f7745..fc4dfdb 100644 --- a/tornado_mysql/cursors.py +++ b/tornado_mysql/cursors.py @@ -302,7 +302,10 @@ def _do_get_result(self): def _show_warnings(self, conn): ws = yield conn.show_warnings() for w in ws: - warnings.warn(w[-1], err.Warning, 4) + msg = w[-1] + if PY2 and isinstance(msg, unicode): + msg = msg.encode('utf-8', 'replace') + warnings.warn(msg, err.Warning, 4) def __iter__(self): return iter(self.fetchone, None)