├── .gitignore ├── .travis.yml ├── CONTRIBUTING.md ├── LICENSE.txt ├── MANIFEST.in ├── PyMysqlPool ├── __init__.py ├── constant │ ├── __init__.py │ └── constant.py ├── db_util │ ├── __init__.py │ ├── db_config │ │ ├── __init__.py │ │ └── example_config.py │ ├── mysql_pool.py │ ├── mysql_util.py │ └── python_rf │ │ ├── __init__.py │ │ └── pool_convertor.py ├── example │ ├── __init__.py │ ├── example_case.py │ └── example_thread.py ├── log │ └── logging.err ├── mysql │ ├── __init__.py │ └── connector │ │ ├── __init__.py │ │ ├── abstracts.py │ │ ├── authentication.py │ │ ├── catch23.py │ │ ├── charsets.py │ │ ├── connection.py │ │ ├── connection_cext.py │ │ ├── constants.py │ │ ├── conversion.py │ │ ├── cursor.py │ │ ├── cursor_cext.py │ │ ├── custom_types.py │ │ ├── dbapi.py │ │ ├── django │ │ ├── __init__.py │ │ ├── base.py │ │ ├── client.py │ │ ├── compiler.py │ │ ├── creation.py │ │ ├── features.py │ │ ├── introspection.py │ │ ├── operations.py │ │ ├── schema.py │ │ └── validation.py │ │ ├── dpooling.py │ │ ├── errorcode.py │ │ ├── errors.py │ │ ├── fabric │ │ ├── __init__.py │ │ ├── balancing.py │ │ ├── caching.py │ │ └── connection.py │ │ ├── flask │ │ ├── __init__.py │ │ └── mysql.py │ │ ├── locales │ │ ├── __init__.py │ │ └── eng │ │ │ ├── __init__.py │ │ │ └── client_error.py │ │ ├── network.py │ │ ├── optionfiles.py │ │ ├── protocol.py │ │ ├── utils.py │ │ └── version.py └── util │ ├── __init__.py │ ├── balancer.py │ ├── date_util.py │ ├── log_util.py │ ├── logger.py │ ├── logger_err.py │ └── py_net_util.py ├── README.rst ├── docs ├── Makefile ├── build │ ├── doctrees │ │ ├── environment.pickle │ │ └── index.doctree │ └── html │ │ ├── .buildinfo │ │ ├── _sources │ │ └── index.rst.txt │ │ ├── _static │ │ ├── ajax-loader.gif │ │ ├── alabaster.css │ │ ├── basic.css │ │ ├── comment-bright.png │ │ ├── comment-close.png │ │ ├── comment.png │ │ ├── custom.css │ │ ├── doctools.js │ │ ├── down-pressed.png │ │ ├── down.png │ │ ├── file.png │ │ ├── jquery-3.1.0.js │ │ ├── jquery.js │ │ ├── minus.png │ │ ├── plus.png │ │ ├── pygments.css │ │ ├── searchtools.js │ │ ├── underscore-1.3.1.js │ │ ├── underscore.js │ │ ├── up-pressed.png │ │ ├── up.png │ │ └── websupport.js │ │ ├── genindex.html │ │ ├── index.html │ │ ├── objects.inv │ │ ├── search.html │ │ └── searchindex.js ├── make.bat └── source │ ├── conf.py │ └── index.rst ├── requirements.txt ├── setup.cfg ├── setup.py ├── test.py └── testssl.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | .idea/ 3 | python-mysql-pool.iml 4 | *.pypirc 5 | mysql_config.py 6 | example_config.py -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | language: python 4 | python: 5 | - "2.6" 6 | - "2.7" 7 | - "3.2" 8 | - "3.3" 9 | - "3.4" 10 | - "3.5" 11 | - "3.5-dev" # 3.5 development branch 12 | - "3.6" 13 | - "3.6-dev" # 3.6 development branch 14 | - "3.7-dev" # 3.7 development branch 15 | - "nightly" # currently points to 3.7-dev 16 | # command to install dependencies 17 | install: "pip install -r requirements.txt" 18 | # command to run tests 19 | script: python ./test.py 20 | 21 | 22 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/CONTRIBUTING.md -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, 2013 python-mysql-pool contributors 2 | #PyMysqlPool 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE.txt 2 | include README.rst 3 | include AUTHORS 4 | 5 | recursive-include tests *.py 6 | recursive-include docs *.bat 7 | recursive-include docs *.empty 8 | recursive-include docs *.py 9 | recursive-include docs *.rst 10 | recursive-include docs Makefile 11 | # Include the data files 12 | recursive-include PyMysqlPool * -------------------------------------------------------------------------------- /PyMysqlPool/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/PyMysqlPool/__init__.py -------------------------------------------------------------------------------- /PyMysqlPool/constant/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/PyMysqlPool/constant/__init__.py -------------------------------------------------------------------------------- /PyMysqlPool/constant/constant.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # coding=utf-8 4 | import os 5 | 6 | from PyMysqlPool.util.logger import * 7 | 8 | reload(sys) 9 | sys.setdefaultencoding('utf-8') 10 | 11 | currentPath = os.path.split(os.path.realpath(__file__))[0] 12 | # below is example 13 | # loggingerr=currentPath+'/../log/logging.err' 14 | 15 | loggErrorFile = '' 16 | loggingerr = currentPath + '/../log/%s' % (loggErrorFile,) 17 | 18 | # MAIN 19 | # =============================================== 20 | if __name__ == '__main__': 21 | logging.info('main starts...') 22 | print loggingerr 23 | logging.info('main stop') 24 | sys.exit(0) 25 | -------------------------------------------------------------------------------- /PyMysqlPool/db_util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/PyMysqlPool/db_util/__init__.py -------------------------------------------------------------------------------- /PyMysqlPool/db_util/db_config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/PyMysqlPool/db_util/db_config/__init__.py -------------------------------------------------------------------------------- /PyMysqlPool/db_util/db_config/example_config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # coding=utf-8 4 | """ 5 | can more db ,more pool 6 | """ 7 | example_config = { 8 | 'local': { 9 | 'host': "10.95.130.***", 'port': 8899, 10 | 'user': "root", 'passwd': "******", 11 | 'db': "marry", 'charset': "utf8", 12 | 'pool': { 13 | # use = 0 no pool else use pool 14 | "use": 1, 15 | # size is >=0, 0 is dynamic pool 16 | "size": 10, 17 | # pool name 18 | "name": "local", 19 | } 20 | }, 21 | 'poi': { 22 | 'host': "10.95.130.***", 'port': 8787, 23 | 'user': "lujunxu", 'passwd': "****", 24 | 'db': "poi_relation", 'charset': "utf8", 25 | 'pool': { 26 | # use = 0 no pool else use pool 27 | "use": 0, 28 | # size is >=0, 0 is dynamic pool 29 | "size": 0, 30 | # pool name 31 | "name": "poi", 32 | } 33 | }, 34 | } 35 | -------------------------------------------------------------------------------- /PyMysqlPool/db_util/mysql_pool.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # coding=utf-8 4 | import MySQLdb 5 | from mysql.connector import errors 6 | import PyMysqlPool.mysql.connector 7 | from PyMysqlPool.db_util.python_rf.pool_convertor import FuzzyMySQLConverter 8 | 9 | 10 | def get_pool_connection(_db_config): 11 | """ 12 | :param _db_config: 13 | :return: 14 | """ 15 | return get_pool_conn_implicitly(_db_config) 16 | 17 | 18 | def get_pool_conn_implicitly(_db_config): 19 | """ 20 | :param _db_config: 21 | :return: 22 | """ 23 | config = _db_config 24 | if 'pool' not in config: 25 | pool = None 26 | else: 27 | pool = config['pool'] 28 | if 'use' not in pool: 29 | raise errors.OperationalError("MySQL pool config error" 30 | " must pool key use") 31 | if 'size' not in pool: 32 | raise errors.OperationalError("MySQL pool config error" 33 | " must pool key size") 34 | if 'name' not in pool: 35 | raise errors.OperationalError("MySQL pool config error " 36 | "must pool key name") 37 | 38 | if pool and pool['use']: 39 | conn = PyMysqlPool.mysql.connector.connect(pool_name=pool['name'], 40 | pool_size=pool['size'], 41 | host=config['host'], 42 | port=config['port'], 43 | user=config['user'], 44 | passwd=config['passwd'], 45 | db=config['db'], 46 | charset=config['charset'], 47 | use_unicode=True, 48 | connect_timeout=1000) 49 | conn.set_converter_class(FuzzyMySQLConverter) 50 | else: 51 | conn = MySQLdb.connect(host=config['host'], 52 | port=config['port'], 53 | user=config['user'], 54 | passwd=config['passwd'], 55 | db=config['db'], 56 | charset=config['charset'], 57 | use_unicode=True) 58 | 59 | conn.start_transaction( 60 | consistent_snapshot=config.get('consistent_snapshot', False), 61 | isolation_level=config.get('isolation_level', None), 62 | readonly=config.get('readonly', None), 63 | ) 64 | 65 | return conn 66 | -------------------------------------------------------------------------------- /PyMysqlPool/db_util/mysql_util.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # coding=utf-8 4 | import sys 5 | from time import sleep 6 | 7 | from PyMysqlPool.db_util.mysql_pool import get_pool_connection 8 | from PyMysqlPool.mysql.connector.dpooling import PooledMySQLConnection 9 | from PyMysqlPool.util.log_util import get_caller_info_total, get_caller_function 10 | from PyMysqlPool.util.logger_err import rootLogger 11 | reload(sys) 12 | sys.setdefaultencoding('utf-8') 13 | import MySQLdb 14 | 15 | 16 | # =============================================== 17 | # FUNCTION 18 | # =============================================== 19 | def query(_db_config, _sql, _args): 20 | conn = get_pool_connection(_db_config) 21 | if not isinstance(conn, PooledMySQLConnection): 22 | cursor = conn.cursor(MySQLdb.cursors.DictCursor) 23 | else: 24 | cursor = conn.cursor(dictionary=True) 25 | result = () 26 | try: 27 | cursor.execute(_sql, _args) 28 | result = cursor.fetchall() 29 | except: 30 | pass 31 | rootLogger.error("query exception sql is %s ,_args is %s,stacks is %s", _sql, _args, get_caller_info_total()) 32 | rootLogger.exception("message") 33 | finally: 34 | cursor.close() 35 | conn.close() 36 | return result 37 | 38 | 39 | # =============================================== 40 | # FUNCTION not use pool 41 | # =============================================== 42 | def query_single(_db_config, _sql, _args): 43 | config = _db_config 44 | conn = MySQLdb.connect(host=config['host'], port=config['port'], user=config['user'], passwd=config['passwd'], 45 | db=config['db'], charset=config['charset'], use_unicode=True) 46 | cursor = conn.cursor(MySQLdb.cursors.DictCursor) 47 | result = () 48 | try: 49 | cursor.execute(_sql, _args) 50 | result = cursor.fetchall() 51 | except: 52 | pass 53 | rootLogger.error("query exception sql is %s ,_args is %s,stacks is %s", _sql, _args, get_caller_info_total()) 54 | rootLogger.exception("message") 55 | finally: 56 | cursor.close() 57 | conn.close() 58 | return result 59 | 60 | 61 | # =============================================== 62 | # FUNCTION 更新或者删除 63 | # =============================================== 64 | def insertOrUpdate(_db_config, _sql, _args): 65 | result = 0 66 | conn = get_pool_connection(_db_config) 67 | if not isinstance(conn, PooledMySQLConnection): 68 | cursor = conn.cursor(MySQLdb.cursors.DictCursor) 69 | else: 70 | cursor = conn.cursor(buffered=True) 71 | try: 72 | cursor.execute(_sql, _args) 73 | conn.commit() 74 | result = cursor.rowcount 75 | except: 76 | pass 77 | rootLogger.error("exception sql is %s ,_args is %s", _sql, _args) 78 | rootLogger.exception("message") 79 | conn.rollback() 80 | finally: 81 | print("affected rows = {}".format(cursor.rowcount)) 82 | cursor.close() 83 | conn.close() 84 | return result 85 | 86 | 87 | # =============================================== 88 | # FUNCTION 清空mysql数据 89 | # =============================================== 90 | def emptyTable(_db_config, _sql, _args): 91 | result = 0 92 | conn = get_pool_connection(_db_config) 93 | if not isinstance(conn, PooledMySQLConnection): 94 | cursor = conn.cursor(MySQLdb.cursors.DictCursor) 95 | else: 96 | cursor = conn.cursor(buffered=True) 97 | # conn.autocommit(True) #replace False -> True 98 | try: 99 | cursor.execute(_sql, _args) 100 | conn.commit() 101 | result = cursor.rowcount 102 | except: 103 | pass 104 | rootLogger.error(" emptyTable exception sql is %s ,_args is %s", _sql, _args) 105 | rootLogger.exception("message") 106 | conn.rollback() 107 | finally: 108 | print("affected rows = {}".format(cursor.rowcount)) 109 | cursor.close() 110 | conn.close() 111 | return result 112 | 113 | 114 | # =============================================== 115 | # FUNCTION 批量更新或者删除 116 | # =============================================== 117 | """ 118 | From MySQLdb User's Guide: 119 | 120 | c.executemany( 121 | "INSERT INTO breakfast (name, spam, eggs, sausage, price) 122 | VALUES (%s, %s, %s, %s, %s)", 123 | [ 124 | ("Spam and Sausage Lover's Plate", 5, 1, 8, 7.95 ), 125 | ("Not So Much Spam Plate", 3, 2, 0, 3.95 ), 126 | ("Don't Wany ANY SPAM! Plate", 0, 4, 3, 5.95 ) 127 | ] ) 128 | so in your case: 129 | 130 | c.executemany("insert into T (F1,F2) values (%s, %s)", 131 | [('a','b'),('c','d')]) 132 | 133 | """ 134 | 135 | 136 | def insertOrUpdatePatch(_db_config, _sql, _args): 137 | result = 0 138 | conn = get_pool_connection(_db_config) 139 | if not isinstance(conn, PooledMySQLConnection): 140 | cursor = conn.cursor(MySQLdb.cursors.DictCursor) 141 | else: 142 | cursor = conn.cursor(buffered=True) 143 | # conn.autocommit(True) #replace False -> True 144 | try: 145 | cursor.executemany(_sql, _args) 146 | conn.commit() 147 | result = cursor.rowcount 148 | except: 149 | pass 150 | rootLogger.error("insertOrUpdatePatch exception sql is %s ,_args is %s", _sql, _args) 151 | rootLogger.exception("message") 152 | conn.rollback() 153 | finally: 154 | print("affected rows = {}".format(cursor.rowcount)) 155 | cursor.close() 156 | conn.close() 157 | return result 158 | 159 | 160 | # =============================================== 161 | # FUNCTION 更新或者删除 162 | # =============================================== 163 | def insertOrUpdate_getId(_db_config, _sql, _args): 164 | result = 0 165 | id = 0 166 | config = _db_config 167 | conn = MySQLdb.connect(host=config['host'], port=config['port'], user=config['user'], passwd=config['passwd'], 168 | db=config['db'], charset=config['charset'], use_unicode=True) 169 | cursor = conn.cursor(MySQLdb.cursors.DictCursor) 170 | try: 171 | cursor.execute(_sql, _args) 172 | id = conn.insert_id() 173 | conn.commit() 174 | result = cursor.rowcount 175 | except: 176 | pass 177 | rootLogger.error("exception sql is %s ,_args is %s", _sql, _args) 178 | rootLogger.exception("message") 179 | conn.rollback() 180 | finally: 181 | print("affected rows = {}".format(cursor.rowcount)) 182 | cursor.close() 183 | conn.close() 184 | return result, id 185 | 186 | 187 | def try_for_threes(_db_config, _sql, _args): 188 | caller = get_caller_function() 189 | for i in xrange(0, 3, 1): 190 | sleep(2) 191 | caller(_db_config, _sql, _args) 192 | 193 | 194 | def check_record_exsit(_db_config, _sql, _args): 195 | result = 0 196 | conn = get_pool_connection(_db_config) 197 | if not isinstance(conn, PooledMySQLConnection): 198 | cursor = conn.cursor(MySQLdb.cursors.DictCursor) 199 | else: 200 | cursor = conn.cursor(buffered=True) 201 | try: 202 | cursor.execute(_sql, _args) # conn.commit() 203 | result = cursor.rowcount 204 | except: 205 | pass 206 | rootLogger.error("message") 207 | conn.rollback() 208 | finally: 209 | print("the record is has rows = {}".format(cursor.rowcount)) 210 | cursor.close() 211 | conn.close() 212 | return result 213 | -------------------------------------------------------------------------------- /PyMysqlPool/db_util/python_rf/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/PyMysqlPool/db_util/python_rf/__init__.py -------------------------------------------------------------------------------- /PyMysqlPool/example/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/PyMysqlPool/example/__init__.py -------------------------------------------------------------------------------- /PyMysqlPool/example/example_case.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # coding=utf-8 4 | import logging 5 | import sys 6 | 7 | from PyMysqlPool.db_util.db_config.example_config import example_config 8 | from PyMysqlPool.db_util.mysql_util import query, query_single, insertOrUpdate 9 | 10 | # MAIN 11 | # =============================================== 12 | 13 | """ 14 | use pool 15 | """ 16 | 17 | 18 | def query_pool(): 19 | job_status = 2 20 | _sql = "select * from master_job_list j where j.job_status !=%s " 21 | _args = (job_status,) 22 | task = query(example_config['local'], _sql, _args) 23 | logging.info("query_npool method query_npool result is %s ,input _data is %s ", task, _args) 24 | return 25 | 26 | 27 | """ 28 | pool in operation 29 | """ 30 | 31 | 32 | def query_pool_in(): 33 | job_status = 2 34 | _sql = "select * from master_job_list j where j.job_status in (%s) " 35 | _args = (job_status,) 36 | task = query(example_config['local'], _sql, _args) 37 | logging.info("query_npool method query_npool result is %s ,input _data is %s ", task, _args) 38 | return 39 | 40 | 41 | """ 42 | pool size special operation 43 | """ 44 | 45 | 46 | def query_pool_size(): 47 | job_status = 2 48 | _sql = "select * from master_job_list j where j.job_status in (%s) " 49 | _args = (job_status,) 50 | task = query(example_config['local'], _sql, _args) 51 | logging.info("query_npool method query_npool result is %s ,input _data is %s ", task, _args) 52 | return 53 | 54 | 55 | """ 56 | single query 57 | """ 58 | 59 | 60 | def query_npool(): 61 | job_status = 2 62 | _sql = "select * from master_job_list j where j.job_status !=%s " 63 | _args = (job_status,) 64 | task = query_single(example_config['local'], _sql, _args) 65 | logging.info("query_npool method query_npool result is %s ,input _data is %s ", task, _args) 66 | return 67 | 68 | 69 | """ 70 | insert 71 | """ 72 | 73 | 74 | def insert(nlp_rank_id, hit_query_word): 75 | # add more args 76 | _args = (nlp_rank_id, hit_query_word) 77 | _sql = """INSERT INTO nlp_rank_poi_online (nlp_rank_id,hit_query_word,rank_type,poi_list,poi_raw_list,article_id,city_id,status,create_time,version,source_from) VALUES (%s,%s,%s, %s, %s,%s, %s,%s, %s,%s,%s)""" 78 | affect = insertOrUpdate(example_config['local'], _sql, _args) 79 | logging.info("insert method insert result is %s ,input _data is %s ", affect, _args) 80 | return 81 | 82 | 83 | """ 84 | update 85 | """ 86 | 87 | 88 | def update(query_word, query_id): 89 | _args = (query_word, query_id) 90 | _sql = """update nlp_rank set query_word = %s WHERE id = %s""" 91 | affect = insertOrUpdate(example_config['local'], _sql, _args) 92 | logging.info("update method update result is %s ,input _data is %s ", affect, _args) 93 | return 94 | 95 | 96 | """ 97 | dynamic pool 98 | """ 99 | 100 | 101 | def d_query(): 102 | job_status = 1 103 | _sql = "select * from master_job_list j where j.job_status !=%s " 104 | _args = (job_status,) 105 | task = query(example_config['local'], _sql, _args) 106 | logging.info("query_npool method query_npool result is %s ,input _data is %s ", task, _args) 107 | return 108 | 109 | 110 | if __name__ == '__main__': 111 | logging.info('main starts...') 112 | d_query() 113 | logging.info('main stop') 114 | sys.exit(0) 115 | -------------------------------------------------------------------------------- /PyMysqlPool/example/example_thread.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # coding=utf-8 4 | import logging 5 | import sys 6 | from threading import Thread 7 | from PyMysqlPool.example.example_case import d_query 8 | 9 | 10 | def doPoiWork(): 11 | d_query() 12 | 13 | 14 | def thread_case(concurrent): 15 | for i in range(concurrent): 16 | t = Thread(target=doPoiWork, args=()) 17 | t.daemon = True 18 | t.start() 19 | 20 | 21 | if __name__ == '__main__': 22 | logging.info('main starts...') 23 | thread_case(100) 24 | logging.info('main stop') 25 | sys.exit(0) 26 | -------------------------------------------------------------------------------- /PyMysqlPool/log/logging.err: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/PyMysqlPool/log/logging.err -------------------------------------------------------------------------------- /PyMysqlPool/mysql/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/PyMysqlPool/mysql/__init__.py -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/__init__.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """ 25 | MySQL Connector/Python - MySQL driver written in Python 26 | """ 27 | 28 | try: 29 | import _mysql_connector # pylint: disable=F0401 30 | from .connection_cext import CMySQLConnection 31 | except ImportError: 32 | HAVE_CEXT = False 33 | else: 34 | HAVE_CEXT = True 35 | 36 | from . import version 37 | from .connection import MySQLConnection 38 | from .constants import FieldFlag, FieldType, CharacterSet, \ 39 | RefreshOption, ClientFlag 40 | from .dbapi import ( 41 | Date, Time, Timestamp, Binary, DateFromTicks, 42 | TimestampFromTicks, TimeFromTicks, 43 | STRING, BINARY, NUMBER, DATETIME, ROWID, 44 | apilevel, threadsafety, paramstyle) 45 | from .errors import ( # pylint: disable=W0622 46 | Error, Warning, InterfaceError, DatabaseError, 47 | NotSupportedError, DataError, IntegrityError, ProgrammingError, 48 | OperationalError, InternalError, custom_error_exception, PoolError) 49 | from .optionfiles import read_option_files 50 | 51 | _CONNECTION_POOLS = {} 52 | 53 | 54 | def _get_pooled_connection(**kwargs): 55 | """Return a pooled MySQL connection""" 56 | # If no pool name specified, generate one 57 | from .dpooling import ( 58 | MySQLConnectionPool, generate_pool_name, 59 | CONNECTION_POOL_LOCK) 60 | 61 | try: 62 | pool_name = kwargs['pool_name'] 63 | except KeyError: 64 | pool_name = generate_pool_name(**kwargs) 65 | 66 | # Setup the pool, ensuring only 1 thread can update at a time 67 | with CONNECTION_POOL_LOCK: 68 | if pool_name not in _CONNECTION_POOLS: 69 | _CONNECTION_POOLS[pool_name] = MySQLConnectionPool(**kwargs) 70 | elif isinstance(_CONNECTION_POOLS[pool_name], MySQLConnectionPool): 71 | # pool_size must be the same 72 | check_size = _CONNECTION_POOLS[pool_name].pool_size 73 | """ 74 | if ('pool_size' in kwargs 75 | and kwargs['pool_size'] != check_size): 76 | print ("Size will be changed " 77 | "for active pools.") 78 | """ 79 | 80 | # Return pooled connection 81 | try: 82 | return _CONNECTION_POOLS[pool_name].get_connection() 83 | except AttributeError: 84 | raise InterfaceError( 85 | "Failed getting connection from pool '{0}'".format(pool_name)) 86 | 87 | 88 | def _get_failover_connection(**kwargs): 89 | """Return a MySQL connection and try to failover if needed 90 | 91 | An InterfaceError is raise when no MySQL is available. ValueError is 92 | raised when the failover server configuration contains an illegal 93 | connection argument. Supported arguments are user, password, host, port, 94 | unix_socket and database. ValueError is also raised when the failover 95 | argument was not provided. 96 | 97 | Returns MySQLConnection instance. 98 | """ 99 | config = kwargs.copy() 100 | try: 101 | failover = config['failover'] 102 | except KeyError: 103 | raise ValueError('failover argument not provided') 104 | del config['failover'] 105 | 106 | support_cnx_args = set([ 107 | 'user', 'password', 'host', 'port', 'unix_socket', 108 | 'database', 'pool_name', 'pool_size', 'consistent_snapshot', 109 | 'init_command', 'readonly' 110 | ]) 111 | 112 | # First check if we can add all use the configuration 113 | for server in failover: 114 | diff = set(server.keys()) - support_cnx_args 115 | if diff: 116 | raise ValueError( 117 | "Unsupported connection argument {0} in failover: {1}".format( 118 | 's' if len(diff) > 1 else '', 119 | ', '.join(diff))) 120 | 121 | for server in failover: 122 | new_config = config.copy() 123 | new_config.update(server) 124 | try: 125 | return connect(**new_config) 126 | except Error: 127 | # If we failed to connect, we try the next server 128 | pass 129 | 130 | raise InterfaceError("Could not failover: no MySQL server available") 131 | 132 | 133 | def connect(*args, **kwargs): 134 | """Create or get a MySQL connection object 135 | 136 | In its simpliest form, Connect() will open a connection to a 137 | MySQL server and return a MySQLConnection object. 138 | 139 | When any connection pooling arguments are given, for example pool_name 140 | or pool_size, a pool is created or a previously one is used to return 141 | a PooledMySQLConnection. 142 | 143 | Returns MySQLConnection or PooledMySQLConnection. 144 | """ 145 | # Option files 146 | if 'option_files' in kwargs: 147 | new_config = read_option_files(**kwargs) 148 | return connect(**new_config) 149 | 150 | if all(['fabric' in kwargs, 'failover' in kwargs]): 151 | raise InterfaceError("fabric and failover arguments can not be used") 152 | 153 | if 'fabric' in kwargs: 154 | if 'pool_name' in kwargs: 155 | raise AttributeError("'pool_name' argument is not supported with " 156 | " MySQL Fabric. Use 'pool_size' instead.") 157 | from .fabric import connect as fabric_connect 158 | return fabric_connect(*args, **kwargs) 159 | 160 | # Failover 161 | if 'failover' in kwargs: 162 | return _get_failover_connection(**kwargs) 163 | 164 | # Pooled connections 165 | try: 166 | from .constants import CNX_POOL_ARGS 167 | if any([key in kwargs for key in CNX_POOL_ARGS]): 168 | return _get_pooled_connection(**kwargs) 169 | except NameError: 170 | # No pooling 171 | pass 172 | 173 | use_pure = kwargs.setdefault('use_pure', True) 174 | 175 | try: 176 | del kwargs['use_pure'] 177 | except KeyError: 178 | # Just making sure 'use_pure' is not kwargs 179 | pass 180 | 181 | if HAVE_CEXT and not use_pure: 182 | return CMySQLConnection(*args, **kwargs) 183 | else: 184 | return MySQLConnection(*args, **kwargs) 185 | 186 | 187 | Connect = connect # pylint: disable=C0103 188 | 189 | __version_info__ = version.VERSION 190 | __version__ = version.VERSION_TEXT 191 | 192 | __all__ = [ 193 | 'MySQLConnection', 'Connect', 'custom_error_exception', 194 | 195 | # Some useful constants 196 | 'FieldType', 'FieldFlag', 'ClientFlag', 'CharacterSet', 'RefreshOption', 197 | 'HAVE_CEXT', 198 | 199 | # Error handling 200 | 'Error', 'Warning', 201 | 'InterfaceError', 'DatabaseError', 202 | 'NotSupportedError', 'DataError', 'IntegrityError', 'ProgrammingError', 203 | 'OperationalError', 'InternalError', 204 | 205 | # DBAPI PEP 249 required exports 206 | 'connect', 'apilevel', 'threadsafety', 'paramstyle', 207 | 'Date', 'Time', 'Timestamp', 'Binary', 208 | 'DateFromTicks', 'DateFromTicks', 'TimestampFromTicks', 'TimeFromTicks', 209 | 'STRING', 'BINARY', 'NUMBER', 210 | 'DATETIME', 'ROWID', 211 | 212 | # C Extension 213 | 'CMySQLConnection', 214 | ] 215 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/authentication.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """Implementing support for MySQL Authentication Plugins""" 25 | 26 | import struct 27 | from hashlib import sha1 28 | 29 | from . import errors 30 | from .catch23 import PY2, isstr 31 | 32 | 33 | class BaseAuthPlugin(object): 34 | """Base class for authentication plugins 35 | 36 | 37 | Classes inheriting from BaseAuthPlugin should implement the method 38 | prepare_password(). When instantiating, auth_data argument is 39 | required. The username, password and database are optional. The 40 | ssl_enabled argument can be used to tell the plugin whether SSL is 41 | active or not. 42 | 43 | The method auth_response() method is used to retrieve the password 44 | which was prepared by prepare_password(). 45 | """ 46 | 47 | requires_ssl = False 48 | plugin_name = '' 49 | 50 | def __init__(self, auth_data, username=None, password=None, database=None, 51 | ssl_enabled=False): 52 | """Initialization""" 53 | self._auth_data = auth_data 54 | self._username = username 55 | self._password = password 56 | self._database = database 57 | self._ssl_enabled = ssl_enabled 58 | 59 | def prepare_password(self): 60 | """Prepares and returns password to be send to MySQL 61 | 62 | This method needs to be implemented by classes inheriting from 63 | this class. It is used by the auth_response() method. 64 | 65 | Raises NotImplementedError. 66 | """ 67 | raise NotImplementedError 68 | 69 | def auth_response(self): 70 | """Returns the prepared password to send to MySQL 71 | 72 | Raises InterfaceError on errors. For example, when SSL is required 73 | by not enabled. 74 | 75 | Returns str 76 | """ 77 | if self.requires_ssl and not self._ssl_enabled: 78 | raise errors.InterfaceError("{name} requires SSL".format( 79 | name=self.plugin_name)) 80 | return self.prepare_password() 81 | 82 | 83 | class MySQLNativePasswordAuthPlugin(BaseAuthPlugin): 84 | """Class implementing the MySQL Native Password authentication plugin""" 85 | 86 | requires_ssl = False 87 | plugin_name = 'mysql_native_password' 88 | 89 | def prepare_password(self): 90 | """Prepares and returns password as native MySQL 4.1+ password""" 91 | if not self._auth_data: 92 | raise errors.InterfaceError("Missing authentication data (seed)") 93 | 94 | if not self._password: 95 | return b'' 96 | password = self._password 97 | 98 | if isstr(self._password): 99 | password = self._password.encode('utf-8') 100 | else: 101 | password = self._password 102 | 103 | if PY2: 104 | password = buffer(password) # pylint: disable=E0602 105 | try: 106 | auth_data = buffer(self._auth_data) # pylint: disable=E0602 107 | except TypeError: 108 | raise errors.InterfaceError("Authentication data incorrect") 109 | else: 110 | password = password 111 | auth_data = self._auth_data 112 | 113 | hash4 = None 114 | try: 115 | hash1 = sha1(password).digest() 116 | hash2 = sha1(hash1).digest() 117 | hash3 = sha1(auth_data + hash2).digest() 118 | if PY2: 119 | xored = [ord(h1) ^ ord(h3) for (h1, h3) in zip(hash1, hash3)] 120 | else: 121 | xored = [h1 ^ h3 for (h1, h3) in zip(hash1, hash3)] 122 | hash4 = struct.pack('20B', *xored) 123 | except Exception as exc: 124 | raise errors.InterfaceError( 125 | "Failed scrambling password; {0}".format(exc)) 126 | 127 | return hash4 128 | 129 | 130 | class MySQLClearPasswordAuthPlugin(BaseAuthPlugin): 131 | """Class implementing the MySQL Clear Password authentication plugin""" 132 | 133 | requires_ssl = True 134 | plugin_name = 'mysql_clear_password' 135 | 136 | def prepare_password(self): 137 | """Returns password as as clear text""" 138 | if not self._password: 139 | return b'\x00' 140 | password = self._password 141 | 142 | if PY2: 143 | if isinstance(password, unicode): # pylint: disable=E0602 144 | password = password.encode('utf8') 145 | elif isinstance(password, str): 146 | password = password.encode('utf8') 147 | 148 | return password + b'\x00' 149 | 150 | 151 | class MySQLSHA256PasswordAuthPlugin(BaseAuthPlugin): 152 | """Class implementing the MySQL SHA256 authentication plugin 153 | 154 | Note that encrypting using RSA is not supported since the Python 155 | Standard Library does not provide this OpenSSL functionality. 156 | """ 157 | 158 | requires_ssl = True 159 | plugin_name = 'sha256_password' 160 | 161 | def prepare_password(self): 162 | """Returns password as as clear text""" 163 | if not self._password: 164 | return b'\x00' 165 | password = self._password 166 | 167 | if PY2: 168 | if isinstance(password, unicode): # pylint: disable=E0602 169 | password = password.encode('utf8') 170 | elif isinstance(password, str): 171 | password = password.encode('utf8') 172 | 173 | return password + b'\x00' 174 | 175 | 176 | def get_auth_plugin(plugin_name): 177 | """Return authentication class based on plugin name 178 | 179 | This function returns the class for the authentication plugin plugin_name. 180 | The returned class is a subclass of BaseAuthPlugin. 181 | 182 | Raises errors.NotSupportedError when plugin_name is not supported. 183 | 184 | Returns subclass of BaseAuthPlugin. 185 | """ 186 | for authclass in BaseAuthPlugin.__subclasses__(): # pylint: disable=E1101 187 | if authclass.plugin_name == plugin_name: 188 | return authclass 189 | 190 | raise errors.NotSupportedError( 191 | "Authentication plugin '{0}' is not supported".format(plugin_name)) 192 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/catch23.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """Python v2 to v3 migration module""" 25 | 26 | import struct 27 | import sys 28 | from decimal import Decimal 29 | 30 | from .custom_types import HexLiteral 31 | 32 | # pylint: disable=E0602,E1103 33 | 34 | PY2 = sys.version_info[0] == 2 35 | 36 | if PY2: 37 | NUMERIC_TYPES = (int, float, Decimal, HexLiteral, long) 38 | INT_TYPES = (int, long) 39 | UNICODE_TYPES = (unicode,) 40 | STRING_TYPES = (str, unicode) 41 | BYTE_TYPES = (bytearray,) 42 | else: 43 | NUMERIC_TYPES = (int, float, Decimal, HexLiteral) 44 | INT_TYPES = (int,) 45 | UNICODE_TYPES = (str,) 46 | STRING_TYPES = (str,) 47 | BYTE_TYPES = (bytearray, bytes) 48 | 49 | 50 | def init_bytearray(payload=b'', encoding='utf-8'): 51 | """Initializes a bytearray from the payload""" 52 | if isinstance(payload, bytearray): 53 | return payload 54 | 55 | if PY2: 56 | return bytearray(payload) 57 | 58 | if isinstance(payload, int): 59 | return bytearray(payload) 60 | elif not isinstance(payload, bytes): 61 | try: 62 | return bytearray(payload.encode(encoding=encoding)) 63 | except AttributeError: 64 | raise ValueError("payload must be a str or bytes") 65 | 66 | return bytearray(payload) 67 | 68 | 69 | def isstr(obj): 70 | """Returns whether a variable is a string""" 71 | if PY2: 72 | return isinstance(obj, basestring) 73 | else: 74 | return isinstance(obj, str) 75 | 76 | 77 | def isunicode(obj): 78 | """Returns whether a variable is a of unicode type""" 79 | if PY2: 80 | return isinstance(obj, unicode) 81 | else: 82 | return isinstance(obj, str) 83 | 84 | 85 | if PY2: 86 | def struct_unpack(fmt, buf): 87 | """Wrapper around struct.unpack handling buffer as bytes and strings""" 88 | if isinstance(buf, (bytearray, bytes)): 89 | return struct.unpack_from(fmt, buffer(buf)) 90 | return struct.unpack_from(fmt, buf) 91 | else: 92 | struct_unpack = struct.unpack # pylint: disable=C0103 93 | 94 | 95 | def make_abc(base_class): 96 | """Decorator used to create a abstract base class 97 | 98 | We use this decorator to create abstract base classes instead of 99 | using the abc-module. The decorator makes it possible to do the 100 | same in both Python v2 and v3 code. 101 | """ 102 | 103 | def wrapper(class_): 104 | """Wrapper""" 105 | attrs = class_.__dict__.copy() 106 | for attr in '__dict__', '__weakref__': 107 | attrs.pop(attr, None) # ignore missing attributes 108 | 109 | bases = class_.__bases__ 110 | if PY2: 111 | attrs['__metaclass__'] = class_ 112 | else: 113 | bases = (class_,) + bases 114 | return base_class(class_.__name__, bases, attrs) 115 | 116 | return wrapper 117 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/charsets.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # MySQL Connector/Python - MySQL driver written in Python. 4 | # Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. 5 | 6 | # MySQL Connector/Python is licensed under the terms of the GPLv2 7 | # , like most 8 | # MySQL Connectors. There are special exceptions to the terms and 9 | # conditions of the GPLv2 as it is applied to this software, see the 10 | # FOSS License Exception 11 | # . 12 | # 13 | # This program is free software; you can redistribute it and/or modify 14 | # it under the terms of the GNU General Public License as published by 15 | # the Free Software Foundation. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 25 | 26 | # This file was auto-generated. 27 | _GENERATED_ON = '2015-08-24' 28 | _MYSQL_VERSION = (5, 7, 8) 29 | 30 | """This module contains the MySQL Server Character Sets""" 31 | 32 | MYSQL_CHARACTER_SETS = [ 33 | # (character set name, collation, default) 34 | None, 35 | ("big5", "big5_chinese_ci", True), # 1 36 | ("latin2", "latin2_czech_cs", False), # 2 37 | ("dec8", "dec8_swedish_ci", True), # 3 38 | ("cp850", "cp850_general_ci", True), # 4 39 | ("latin1", "latin1_german1_ci", False), # 5 40 | ("hp8", "hp8_english_ci", True), # 6 41 | ("koi8r", "koi8r_general_ci", True), # 7 42 | ("latin1", "latin1_swedish_ci", True), # 8 43 | ("latin2", "latin2_general_ci", True), # 9 44 | ("swe7", "swe7_swedish_ci", True), # 10 45 | ("ascii", "ascii_general_ci", True), # 11 46 | ("ujis", "ujis_japanese_ci", True), # 12 47 | ("sjis", "sjis_japanese_ci", True), # 13 48 | ("cp1251", "cp1251_bulgarian_ci", False), # 14 49 | ("latin1", "latin1_danish_ci", False), # 15 50 | ("hebrew", "hebrew_general_ci", True), # 16 51 | None, 52 | ("tis620", "tis620_thai_ci", True), # 18 53 | ("euckr", "euckr_korean_ci", True), # 19 54 | ("latin7", "latin7_estonian_cs", False), # 20 55 | ("latin2", "latin2_hungarian_ci", False), # 21 56 | ("koi8u", "koi8u_general_ci", True), # 22 57 | ("cp1251", "cp1251_ukrainian_ci", False), # 23 58 | ("gb2312", "gb2312_chinese_ci", True), # 24 59 | ("greek", "greek_general_ci", True), # 25 60 | ("cp1250", "cp1250_general_ci", True), # 26 61 | ("latin2", "latin2_croatian_ci", False), # 27 62 | ("gbk", "gbk_chinese_ci", True), # 28 63 | ("cp1257", "cp1257_lithuanian_ci", False), # 29 64 | ("latin5", "latin5_turkish_ci", True), # 30 65 | ("latin1", "latin1_german2_ci", False), # 31 66 | ("armscii8", "armscii8_general_ci", True), # 32 67 | ("utf8", "utf8_general_ci", True), # 33 68 | ("cp1250", "cp1250_czech_cs", False), # 34 69 | ("ucs2", "ucs2_general_ci", True), # 35 70 | ("cp866", "cp866_general_ci", True), # 36 71 | ("keybcs2", "keybcs2_general_ci", True), # 37 72 | ("macce", "macce_general_ci", True), # 38 73 | ("macroman", "macroman_general_ci", True), # 39 74 | ("cp852", "cp852_general_ci", True), # 40 75 | ("latin7", "latin7_general_ci", True), # 41 76 | ("latin7", "latin7_general_cs", False), # 42 77 | ("macce", "macce_bin", False), # 43 78 | ("cp1250", "cp1250_croatian_ci", False), # 44 79 | ("utf8mb4", "utf8mb4_general_ci", True), # 45 80 | ("utf8mb4", "utf8mb4_bin", False), # 46 81 | ("latin1", "latin1_bin", False), # 47 82 | ("latin1", "latin1_general_ci", False), # 48 83 | ("latin1", "latin1_general_cs", False), # 49 84 | ("cp1251", "cp1251_bin", False), # 50 85 | ("cp1251", "cp1251_general_ci", True), # 51 86 | ("cp1251", "cp1251_general_cs", False), # 52 87 | ("macroman", "macroman_bin", False), # 53 88 | ("utf16", "utf16_general_ci", True), # 54 89 | ("utf16", "utf16_bin", False), # 55 90 | ("utf16le", "utf16le_general_ci", True), # 56 91 | ("cp1256", "cp1256_general_ci", True), # 57 92 | ("cp1257", "cp1257_bin", False), # 58 93 | ("cp1257", "cp1257_general_ci", True), # 59 94 | ("utf32", "utf32_general_ci", True), # 60 95 | ("utf32", "utf32_bin", False), # 61 96 | ("utf16le", "utf16le_bin", False), # 62 97 | ("binary", "binary", True), # 63 98 | ("armscii8", "armscii8_bin", False), # 64 99 | ("ascii", "ascii_bin", False), # 65 100 | ("cp1250", "cp1250_bin", False), # 66 101 | ("cp1256", "cp1256_bin", False), # 67 102 | ("cp866", "cp866_bin", False), # 68 103 | ("dec8", "dec8_bin", False), # 69 104 | ("greek", "greek_bin", False), # 70 105 | ("hebrew", "hebrew_bin", False), # 71 106 | ("hp8", "hp8_bin", False), # 72 107 | ("keybcs2", "keybcs2_bin", False), # 73 108 | ("koi8r", "koi8r_bin", False), # 74 109 | ("koi8u", "koi8u_bin", False), # 75 110 | None, 111 | ("latin2", "latin2_bin", False), # 77 112 | ("latin5", "latin5_bin", False), # 78 113 | ("latin7", "latin7_bin", False), # 79 114 | ("cp850", "cp850_bin", False), # 80 115 | ("cp852", "cp852_bin", False), # 81 116 | ("swe7", "swe7_bin", False), # 82 117 | ("utf8", "utf8_bin", False), # 83 118 | ("big5", "big5_bin", False), # 84 119 | ("euckr", "euckr_bin", False), # 85 120 | ("gb2312", "gb2312_bin", False), # 86 121 | ("gbk", "gbk_bin", False), # 87 122 | ("sjis", "sjis_bin", False), # 88 123 | ("tis620", "tis620_bin", False), # 89 124 | ("ucs2", "ucs2_bin", False), # 90 125 | ("ujis", "ujis_bin", False), # 91 126 | ("geostd8", "geostd8_general_ci", True), # 92 127 | ("geostd8", "geostd8_bin", False), # 93 128 | ("latin1", "latin1_spanish_ci", False), # 94 129 | ("cp932", "cp932_japanese_ci", True), # 95 130 | ("cp932", "cp932_bin", False), # 96 131 | ("eucjpms", "eucjpms_japanese_ci", True), # 97 132 | ("eucjpms", "eucjpms_bin", False), # 98 133 | ("cp1250", "cp1250_polish_ci", False), # 99 134 | None, 135 | ("utf16", "utf16_unicode_ci", False), # 101 136 | ("utf16", "utf16_icelandic_ci", False), # 102 137 | ("utf16", "utf16_latvian_ci", False), # 103 138 | ("utf16", "utf16_romanian_ci", False), # 104 139 | ("utf16", "utf16_slovenian_ci", False), # 105 140 | ("utf16", "utf16_polish_ci", False), # 106 141 | ("utf16", "utf16_estonian_ci", False), # 107 142 | ("utf16", "utf16_spanish_ci", False), # 108 143 | ("utf16", "utf16_swedish_ci", False), # 109 144 | ("utf16", "utf16_turkish_ci", False), # 110 145 | ("utf16", "utf16_czech_ci", False), # 111 146 | ("utf16", "utf16_danish_ci", False), # 112 147 | ("utf16", "utf16_lithuanian_ci", False), # 113 148 | ("utf16", "utf16_slovak_ci", False), # 114 149 | ("utf16", "utf16_spanish2_ci", False), # 115 150 | ("utf16", "utf16_roman_ci", False), # 116 151 | ("utf16", "utf16_persian_ci", False), # 117 152 | ("utf16", "utf16_esperanto_ci", False), # 118 153 | ("utf16", "utf16_hungarian_ci", False), # 119 154 | ("utf16", "utf16_sinhala_ci", False), # 120 155 | ("utf16", "utf16_german2_ci", False), # 121 156 | ("utf16", "utf16_croatian_ci", False), # 122 157 | ("utf16", "utf16_unicode_520_ci", False), # 123 158 | ("utf16", "utf16_vietnamese_ci", False), # 124 159 | None, 160 | None, 161 | None, 162 | ("ucs2", "ucs2_unicode_ci", False), # 128 163 | ("ucs2", "ucs2_icelandic_ci", False), # 129 164 | ("ucs2", "ucs2_latvian_ci", False), # 130 165 | ("ucs2", "ucs2_romanian_ci", False), # 131 166 | ("ucs2", "ucs2_slovenian_ci", False), # 132 167 | ("ucs2", "ucs2_polish_ci", False), # 133 168 | ("ucs2", "ucs2_estonian_ci", False), # 134 169 | ("ucs2", "ucs2_spanish_ci", False), # 135 170 | ("ucs2", "ucs2_swedish_ci", False), # 136 171 | ("ucs2", "ucs2_turkish_ci", False), # 137 172 | ("ucs2", "ucs2_czech_ci", False), # 138 173 | ("ucs2", "ucs2_danish_ci", False), # 139 174 | ("ucs2", "ucs2_lithuanian_ci", False), # 140 175 | ("ucs2", "ucs2_slovak_ci", False), # 141 176 | ("ucs2", "ucs2_spanish2_ci", False), # 142 177 | ("ucs2", "ucs2_roman_ci", False), # 143 178 | ("ucs2", "ucs2_persian_ci", False), # 144 179 | ("ucs2", "ucs2_esperanto_ci", False), # 145 180 | ("ucs2", "ucs2_hungarian_ci", False), # 146 181 | ("ucs2", "ucs2_sinhala_ci", False), # 147 182 | ("ucs2", "ucs2_german2_ci", False), # 148 183 | ("ucs2", "ucs2_croatian_ci", False), # 149 184 | ("ucs2", "ucs2_unicode_520_ci", False), # 150 185 | ("ucs2", "ucs2_vietnamese_ci", False), # 151 186 | None, 187 | None, 188 | None, 189 | None, 190 | None, 191 | None, 192 | None, 193 | ("ucs2", "ucs2_general_mysql500_ci", False), # 159 194 | ("utf32", "utf32_unicode_ci", False), # 160 195 | ("utf32", "utf32_icelandic_ci", False), # 161 196 | ("utf32", "utf32_latvian_ci", False), # 162 197 | ("utf32", "utf32_romanian_ci", False), # 163 198 | ("utf32", "utf32_slovenian_ci", False), # 164 199 | ("utf32", "utf32_polish_ci", False), # 165 200 | ("utf32", "utf32_estonian_ci", False), # 166 201 | ("utf32", "utf32_spanish_ci", False), # 167 202 | ("utf32", "utf32_swedish_ci", False), # 168 203 | ("utf32", "utf32_turkish_ci", False), # 169 204 | ("utf32", "utf32_czech_ci", False), # 170 205 | ("utf32", "utf32_danish_ci", False), # 171 206 | ("utf32", "utf32_lithuanian_ci", False), # 172 207 | ("utf32", "utf32_slovak_ci", False), # 173 208 | ("utf32", "utf32_spanish2_ci", False), # 174 209 | ("utf32", "utf32_roman_ci", False), # 175 210 | ("utf32", "utf32_persian_ci", False), # 176 211 | ("utf32", "utf32_esperanto_ci", False), # 177 212 | ("utf32", "utf32_hungarian_ci", False), # 178 213 | ("utf32", "utf32_sinhala_ci", False), # 179 214 | ("utf32", "utf32_german2_ci", False), # 180 215 | ("utf32", "utf32_croatian_ci", False), # 181 216 | ("utf32", "utf32_unicode_520_ci", False), # 182 217 | ("utf32", "utf32_vietnamese_ci", False), # 183 218 | None, 219 | None, 220 | None, 221 | None, 222 | None, 223 | None, 224 | None, 225 | None, 226 | ("utf8", "utf8_unicode_ci", False), # 192 227 | ("utf8", "utf8_icelandic_ci", False), # 193 228 | ("utf8", "utf8_latvian_ci", False), # 194 229 | ("utf8", "utf8_romanian_ci", False), # 195 230 | ("utf8", "utf8_slovenian_ci", False), # 196 231 | ("utf8", "utf8_polish_ci", False), # 197 232 | ("utf8", "utf8_estonian_ci", False), # 198 233 | ("utf8", "utf8_spanish_ci", False), # 199 234 | ("utf8", "utf8_swedish_ci", False), # 200 235 | ("utf8", "utf8_turkish_ci", False), # 201 236 | ("utf8", "utf8_czech_ci", False), # 202 237 | ("utf8", "utf8_danish_ci", False), # 203 238 | ("utf8", "utf8_lithuanian_ci", False), # 204 239 | ("utf8", "utf8_slovak_ci", False), # 205 240 | ("utf8", "utf8_spanish2_ci", False), # 206 241 | ("utf8", "utf8_roman_ci", False), # 207 242 | ("utf8", "utf8_persian_ci", False), # 208 243 | ("utf8", "utf8_esperanto_ci", False), # 209 244 | ("utf8", "utf8_hungarian_ci", False), # 210 245 | ("utf8", "utf8_sinhala_ci", False), # 211 246 | ("utf8", "utf8_german2_ci", False), # 212 247 | ("utf8", "utf8_croatian_ci", False), # 213 248 | ("utf8", "utf8_unicode_520_ci", False), # 214 249 | ("utf8", "utf8_vietnamese_ci", False), # 215 250 | None, 251 | None, 252 | None, 253 | None, 254 | None, 255 | None, 256 | None, 257 | ("utf8", "utf8_general_mysql500_ci", False), # 223 258 | ("utf8mb4", "utf8mb4_unicode_ci", False), # 224 259 | ("utf8mb4", "utf8mb4_icelandic_ci", False), # 225 260 | ("utf8mb4", "utf8mb4_latvian_ci", False), # 226 261 | ("utf8mb4", "utf8mb4_romanian_ci", False), # 227 262 | ("utf8mb4", "utf8mb4_slovenian_ci", False), # 228 263 | ("utf8mb4", "utf8mb4_polish_ci", False), # 229 264 | ("utf8mb4", "utf8mb4_estonian_ci", False), # 230 265 | ("utf8mb4", "utf8mb4_spanish_ci", False), # 231 266 | ("utf8mb4", "utf8mb4_swedish_ci", False), # 232 267 | ("utf8mb4", "utf8mb4_turkish_ci", False), # 233 268 | ("utf8mb4", "utf8mb4_czech_ci", False), # 234 269 | ("utf8mb4", "utf8mb4_danish_ci", False), # 235 270 | ("utf8mb4", "utf8mb4_lithuanian_ci", False), # 236 271 | ("utf8mb4", "utf8mb4_slovak_ci", False), # 237 272 | ("utf8mb4", "utf8mb4_spanish2_ci", False), # 238 273 | ("utf8mb4", "utf8mb4_roman_ci", False), # 239 274 | ("utf8mb4", "utf8mb4_persian_ci", False), # 240 275 | ("utf8mb4", "utf8mb4_esperanto_ci", False), # 241 276 | ("utf8mb4", "utf8mb4_hungarian_ci", False), # 242 277 | ("utf8mb4", "utf8mb4_sinhala_ci", False), # 243 278 | ("utf8mb4", "utf8mb4_german2_ci", False), # 244 279 | ("utf8mb4", "utf8mb4_croatian_ci", False), # 245 280 | ("utf8mb4", "utf8mb4_unicode_520_ci", False), # 246 281 | ("utf8mb4", "utf8mb4_vietnamese_ci", False), # 247 282 | ("gb18030", "gb18030_chinese_ci", True), # 248 283 | ("gb18030", "gb18030_bin", False), # 249 284 | ("gb18030", "gb18030_unicode_520_ci", False), # 250 285 | ] 286 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/custom_types.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """Custom Python types used by MySQL Connector/Python""" 25 | 26 | import sys 27 | 28 | 29 | class HexLiteral(str): 30 | """Class holding MySQL hex literals""" 31 | 32 | def __new__(cls, str_, charset='utf8'): 33 | if sys.version_info[0] == 2: 34 | hexed = ["%02x" % ord(i) for i in str_.encode(charset)] 35 | else: 36 | hexed = ["%02x" % i for i in str_.encode(charset)] 37 | obj = str.__new__(cls, ''.join(hexed)) 38 | obj.charset = charset 39 | obj.original = str_ 40 | return obj 41 | 42 | def __str__(self): 43 | return '0x' + self 44 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/dbapi.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """ 25 | This module implements some constructors and singletons as required by the 26 | DB API v2.0 (PEP-249). 27 | """ 28 | 29 | # Python Db API v2 30 | apilevel = '2.0' 31 | threadsafety = 1 32 | paramstyle = 'pyformat' 33 | 34 | import datetime 35 | import time 36 | 37 | from . import constants 38 | 39 | 40 | class _DBAPITypeObject(object): 41 | def __init__(self, *values): 42 | self.values = values 43 | 44 | def __eq__(self, other): 45 | if other in self.values: 46 | return True 47 | else: 48 | return False 49 | 50 | def __ne__(self, other): 51 | if other in self.values: 52 | return False 53 | else: 54 | return True 55 | 56 | 57 | Date = datetime.date 58 | Time = datetime.time 59 | Timestamp = datetime.datetime 60 | 61 | 62 | def DateFromTicks(ticks): 63 | return Date(*time.localtime(ticks)[:3]) 64 | 65 | 66 | def TimeFromTicks(ticks): 67 | return Time(*time.localtime(ticks)[3:6]) 68 | 69 | 70 | def TimestampFromTicks(ticks): 71 | return Timestamp(*time.localtime(ticks)[:6]) 72 | 73 | 74 | Binary = bytes 75 | 76 | STRING = _DBAPITypeObject(*constants.FieldType.get_string_types()) 77 | BINARY = _DBAPITypeObject(*constants.FieldType.get_binary_types()) 78 | NUMBER = _DBAPITypeObject(*constants.FieldType.get_number_types()) 79 | DATETIME = _DBAPITypeObject(*constants.FieldType.get_timestamp_types()) 80 | ROWID = _DBAPITypeObject() 81 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/django/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/PyMysqlPool/mysql/connector/django/__init__.py -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/django/client.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | 3 | import subprocess 4 | 5 | import django 6 | 7 | if django.VERSION >= (1, 8): 8 | from django.db.backends.base.client import BaseDatabaseClient 9 | else: 10 | from django.db.backends import BaseDatabaseClient 11 | 12 | 13 | class DatabaseClient(BaseDatabaseClient): 14 | executable_name = 'mysql' 15 | 16 | @classmethod 17 | def settings_to_cmd_args(cls, settings_dict): 18 | args = [cls.executable_name] 19 | 20 | db = settings_dict['OPTIONS'].get('database', settings_dict['NAME']) 21 | user = settings_dict['OPTIONS'].get('user', 22 | settings_dict['USER']) 23 | passwd = settings_dict['OPTIONS'].get('password', 24 | settings_dict['PASSWORD']) 25 | host = settings_dict['OPTIONS'].get('host', settings_dict['HOST']) 26 | port = settings_dict['OPTIONS'].get('port', settings_dict['PORT']) 27 | defaults_file = settings_dict['OPTIONS'].get('read_default_file') 28 | 29 | # --defaults-file should always be the first option 30 | if defaults_file: 31 | args.append("--defaults-file={0}".format(defaults_file)) 32 | 33 | # We force SQL_MODE to TRADITIONAL 34 | args.append("--init-command=SET @@session.SQL_MODE=TRADITIONAL") 35 | 36 | if user: 37 | args.append("--user={0}".format(user)) 38 | if passwd: 39 | args.append("--password={0}".format(passwd)) 40 | 41 | if host: 42 | if '/' in host: 43 | args.append("--socket={0}".format(host)) 44 | else: 45 | args.append("--host={0}".format(host)) 46 | 47 | if port: 48 | args.append("--port={0}".format(port)) 49 | 50 | if db: 51 | args.append("--database={0}".format(db)) 52 | 53 | return args 54 | 55 | def runshell(self): 56 | args = DatabaseClient.settings_to_cmd_args( 57 | self.connection.settings_dict) 58 | subprocess.call(args) 59 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/django/compiler.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | 3 | 4 | import django 5 | from django.db.models.sql import compiler 6 | 7 | try: 8 | from itertools import zip_longest as zip_longest 9 | except: 10 | from itertools import izip_longest as zip_longest 11 | 12 | 13 | # from django.utils.six.moves import zip_longest 14 | 15 | 16 | class SQLCompiler(compiler.SQLCompiler): 17 | def resolve_columns(self, row, fields=()): 18 | values = [] 19 | index_extra_select = len(self.query.extra_select) 20 | bool_fields = ("BooleanField", "NullBooleanField") 21 | for value, field in zip_longest(row[index_extra_select:], fields): 22 | if (field and field.get_internal_type() in bool_fields and 23 | value in (0, 1)): 24 | value = bool(value) 25 | values.append(value) 26 | return row[:index_extra_select] + tuple(values) 27 | 28 | if django.VERSION >= (1, 8): 29 | def as_subquery_condition(self, alias, columns, compiler): 30 | qn = compiler.quote_name_unless_alias 31 | qn2 = self.connection.ops.quote_name 32 | sql, params = self.as_sql() 33 | return '(%s) IN (%s)' % (', '.join('%s.%s' % (qn(alias), qn2(column)) for column in columns), sql), params 34 | else: 35 | def as_subquery_condition(self, alias, columns, qn): 36 | # Django 1.6 37 | qn2 = self.connection.ops.quote_name 38 | sql, params = self.as_sql() 39 | column_list = ', '.join( 40 | ['%s.%s' % (qn(alias), qn2(column)) for column in columns]) 41 | return '({0}) IN ({1})'.format(column_list, sql), params 42 | 43 | 44 | class SQLInsertCompiler(compiler.SQLInsertCompiler, SQLCompiler): 45 | pass 46 | 47 | 48 | class SQLDeleteCompiler(compiler.SQLDeleteCompiler, SQLCompiler): 49 | pass 50 | 51 | 52 | class SQLUpdateCompiler(compiler.SQLUpdateCompiler, SQLCompiler): 53 | pass 54 | 55 | 56 | class SQLAggregateCompiler(compiler.SQLAggregateCompiler, SQLCompiler): 57 | pass 58 | 59 | 60 | if django.VERSION < (1, 8): 61 | class SQLDateCompiler(compiler.SQLDateCompiler, SQLCompiler): 62 | pass 63 | 64 | 65 | if django.VERSION >= (1, 6): 66 | class SQLDateTimeCompiler(compiler.SQLDateTimeCompiler, SQLCompiler): 67 | # Django 1.6 68 | pass 69 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/django/creation.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | 3 | import django 4 | from django.db import models 5 | 6 | if django.VERSION >= (1, 8): 7 | from django.db.backends.base.creation import BaseDatabaseCreation 8 | else: 9 | from django.db.backends.creation import BaseDatabaseCreation 10 | if django.VERSION < (1, 7): 11 | from django.db.backends.util import truncate_name 12 | else: 13 | from django.db.backends.utils import truncate_name 14 | 15 | 16 | class DatabaseCreation(BaseDatabaseCreation): 17 | """Maps Django Field object with MySQL data types 18 | """ 19 | 20 | def __init__(self, connection): 21 | super(DatabaseCreation, self).__init__(connection) 22 | 23 | if django.VERSION < (1, 8): 24 | self.data_types = { 25 | 'AutoField': 'integer AUTO_INCREMENT', 26 | 'BinaryField': 'longblob', 27 | 'BooleanField': 'bool', 28 | 'CharField': 'varchar(%(max_length)s)', 29 | 'CommaSeparatedIntegerField': 'varchar(%(max_length)s)', 30 | 'DateField': 'date', 31 | 'DateTimeField': 'datetime', # ms support set later 32 | 'DecimalField': 'numeric(%(max_digits)s, %(decimal_places)s)', 33 | 'FileField': 'varchar(%(max_length)s)', 34 | 'FilePathField': 'varchar(%(max_length)s)', 35 | 'FloatField': 'double precision', 36 | 'IntegerField': 'integer', 37 | 'BigIntegerField': 'bigint', 38 | 'IPAddressField': 'char(15)', 39 | 40 | 'GenericIPAddressField': 'char(39)', 41 | 'NullBooleanField': 'bool', 42 | 'OneToOneField': 'integer', 43 | 'PositiveIntegerField': 'integer UNSIGNED', 44 | 'PositiveSmallIntegerField': 'smallint UNSIGNED', 45 | 'SlugField': 'varchar(%(max_length)s)', 46 | 'SmallIntegerField': 'smallint', 47 | 'TextField': 'longtext', 48 | 'TimeField': 'time', # ms support set later 49 | } 50 | 51 | # Support for microseconds 52 | if self.connection.mysql_version >= (5, 6, 4): 53 | self.data_types.update({ 54 | 'DateTimeField': 'datetime(6)', 55 | 'TimeField': 'time(6)', 56 | }) 57 | 58 | def sql_table_creation_suffix(self): 59 | suffix = [] 60 | if django.VERSION < (1, 7): 61 | if self.connection.settings_dict['TEST_CHARSET']: 62 | suffix.append('CHARACTER SET {0}'.format( 63 | self.connection.settings_dict['TEST_CHARSET'])) 64 | if self.connection.settings_dict['TEST_COLLATION']: 65 | suffix.append('COLLATE {0}'.format( 66 | self.connection.settings_dict['TEST_COLLATION'])) 67 | 68 | else: 69 | test_settings = self.connection.settings_dict['TEST'] 70 | if test_settings['CHARSET']: 71 | suffix.append('CHARACTER SET %s' % test_settings['CHARSET']) 72 | if test_settings['COLLATION']: 73 | suffix.append('COLLATE %s' % test_settings['COLLATION']) 74 | 75 | return ' '.join(suffix) 76 | 77 | if django.VERSION < (1, 6): 78 | def sql_for_inline_foreign_key_references(self, field, known_models, 79 | style): 80 | "All inline references are pending under MySQL" 81 | return [], True 82 | else: 83 | def sql_for_inline_foreign_key_references(self, model, field, 84 | known_models, style): 85 | "All inline references are pending under MySQL" 86 | return [], True 87 | 88 | def sql_for_inline_many_to_many_references(self, model, field, style): 89 | opts = model._meta 90 | qn = self.connection.ops.quote_name 91 | 92 | columndef = ' {column} {type} {options},' 93 | table_output = [ 94 | columndef.format( 95 | column=style.SQL_FIELD(qn(field.m2m_column_name())), 96 | type=style.SQL_COLTYPE(models.ForeignKey(model).db_type( 97 | connection=self.connection)), 98 | options=style.SQL_KEYWORD('NOT NULL') 99 | ), 100 | columndef.format( 101 | column=style.SQL_FIELD(qn(field.m2m_reverse_name())), 102 | type=style.SQL_COLTYPE(models.ForeignKey(field.rel.to).db_type( 103 | connection=self.connection)), 104 | options=style.SQL_KEYWORD('NOT NULL') 105 | ), 106 | ] 107 | 108 | deferred = [ 109 | (field.m2m_db_table(), field.m2m_column_name(), opts.db_table, 110 | opts.pk.column), 111 | (field.m2m_db_table(), field.m2m_reverse_name(), 112 | field.rel.to._meta.db_table, field.rel.to._meta.pk.column) 113 | ] 114 | return table_output, deferred 115 | 116 | def sql_destroy_indexes_for_fields(self, model, fields, style): 117 | # Django 1.6 118 | if len(fields) == 1 and fields[0].db_tablespace: 119 | tablespace_sql = self.connection.ops.tablespace_sql( 120 | fields[0].db_tablespace) 121 | elif model._meta.db_tablespace: 122 | tablespace_sql = self.connection.ops.tablespace_sql( 123 | model._meta.db_tablespace) 124 | else: 125 | tablespace_sql = "" 126 | if tablespace_sql: 127 | tablespace_sql = " " + tablespace_sql 128 | 129 | field_names = [] 130 | qn = self.connection.ops.quote_name 131 | for f in fields: 132 | field_names.append(style.SQL_FIELD(qn(f.column))) 133 | 134 | index_name = "{0}_{1}".format(model._meta.db_table, 135 | self._digest([f.name for f in fields])) 136 | 137 | return [ 138 | style.SQL_KEYWORD("DROP INDEX") + " " + 139 | style.SQL_TABLE(qn(truncate_name(index_name, 140 | self.connection.ops.max_name_length()))) + " " + 141 | style.SQL_KEYWORD("ON") + " " + 142 | style.SQL_TABLE(qn(model._meta.db_table)) + ";", 143 | ] 144 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/django/features.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | 3 | # New file added for Django 1.8 4 | 5 | import django 6 | 7 | if django.VERSION >= (1, 8): 8 | from django.db.backends.base.features import BaseDatabaseFeatures 9 | else: 10 | from django.db.backends import BaseDatabaseFeatures 11 | from django.utils.functional import cached_property 12 | from django.utils import six 13 | 14 | try: 15 | import pytz 16 | 17 | HAVE_PYTZ = True 18 | except ImportError: 19 | HAVE_PYTZ = False 20 | 21 | 22 | class DatabaseFeatures(BaseDatabaseFeatures): 23 | """Features specific to MySQL 24 | 25 | Microsecond precision is supported since MySQL 5.6.3 and turned on 26 | by default if this MySQL version is used. 27 | """ 28 | empty_fetchmany_value = [] 29 | update_can_self_select = False 30 | allows_group_by_pk = True 31 | related_fields_match_type = True 32 | allow_sliced_subqueries = False 33 | has_bulk_insert = True 34 | has_select_for_update = True 35 | has_select_for_update_nowait = False 36 | supports_forward_references = False 37 | supports_regex_backreferencing = False 38 | supports_date_lookup_using_string = False 39 | can_introspect_autofield = True 40 | can_introspect_binary_field = False 41 | can_introspect_small_integer_field = True 42 | supports_timezones = False 43 | requires_explicit_null_ordering_when_grouping = True 44 | allows_auto_pk_0 = False 45 | allows_primary_key_0 = False 46 | uses_savepoints = True 47 | atomic_transactions = False 48 | supports_column_check_constraints = False 49 | 50 | if django.VERSION < (1, 8): 51 | supports_long_model_names = False 52 | supports_binary_field = six.PY2 53 | can_introspect_boolean_field = False 54 | 55 | def __init__(self, connection): 56 | super(DatabaseFeatures, self).__init__(connection) 57 | 58 | @cached_property 59 | def supports_microsecond_precision(self): 60 | if self.connection.mysql_version >= (5, 6, 3): 61 | return True 62 | return False 63 | 64 | @cached_property 65 | def mysql_storage_engine(self): 66 | """Get default storage engine of MySQL 67 | 68 | This method creates a table without ENGINE table option and inspects 69 | which engine was used. 70 | 71 | Used by Django tests. 72 | """ 73 | tblname = 'INTROSPECT_TEST' 74 | 75 | droptable = 'DROP TABLE IF EXISTS {table}'.format(table=tblname) 76 | with self.connection.cursor() as cursor: 77 | cursor.execute(droptable) 78 | cursor.execute('CREATE TABLE {table} (X INT)'.format(table=tblname)) 79 | 80 | if self.connection.mysql_version >= (5, 0, 0): 81 | cursor.execute( 82 | "SELECT ENGINE FROM INFORMATION_SCHEMA.TABLES " 83 | "WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s", 84 | (self.connection.settings_dict['NAME'], tblname)) 85 | engine = cursor.fetchone()[0] 86 | else: 87 | # Very old MySQL servers.. 88 | cursor.execute("SHOW TABLE STATUS WHERE Name='{table}'".format( 89 | table=tblname)) 90 | engine = cursor.fetchone()[1] 91 | cursor.execute(droptable) 92 | 93 | self._cached_storage_engine = engine 94 | return engine 95 | 96 | @cached_property 97 | def _disabled_supports_transactions(self): 98 | return self.mysql_storage_engine == 'InnoDB' 99 | 100 | @cached_property 101 | def can_introspect_foreign_keys(self): 102 | """Confirm support for introspected foreign keys 103 | 104 | Only the InnoDB storage engine supports Foreigen Key (not taking 105 | into account MySQL Cluster here). 106 | """ 107 | return self.mysql_storage_engine == 'InnoDB' 108 | 109 | @cached_property 110 | def has_zoneinfo_database(self): 111 | """Tests if the time zone definitions are installed 112 | 113 | MySQL accepts full time zones names (eg. Africa/Nairobi) but rejects 114 | abbreviations (eg. EAT). When pytz isn't installed and the current 115 | time zone is LocalTimezone (the only sensible value in this context), 116 | the current time zone name will be an abbreviation. As a consequence, 117 | MySQL cannot perform time zone conversions reliably. 118 | """ 119 | # Django 1.6 120 | if not HAVE_PYTZ: 121 | return False 122 | 123 | with self.connection.cursor() as cursor: 124 | cursor.execute("SELECT 1 FROM mysql.time_zone LIMIT 1") 125 | return cursor.fetchall() != [] 126 | 127 | def introspected_boolean_field_type(self, *args, **kwargs): 128 | # New in Django 1.8 129 | return 'IntegerField' 130 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/django/operations.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | 3 | # New file added for Django 1.8 4 | 5 | from __future__ import unicode_literals 6 | 7 | import uuid 8 | 9 | import django 10 | from django.conf import settings 11 | 12 | if django.VERSION >= (1, 8): 13 | from django.db.backends.base.operations import BaseDatabaseOperations 14 | else: 15 | from django.db.backends import BaseDatabaseOperations 16 | from django.utils import six, timezone 17 | from django.utils.encoding import force_text 18 | 19 | try: 20 | from _mysql_connector import datetime_to_mysql, time_to_mysql 21 | except ImportError: 22 | HAVE_CEXT = False 23 | else: 24 | HAVE_CEXT = True 25 | 26 | 27 | class DatabaseOperations(BaseDatabaseOperations): 28 | compiler_module = "mysql.connector.django.compiler" 29 | 30 | # MySQL stores positive fields as UNSIGNED ints. 31 | if django.VERSION >= (1, 7): 32 | integer_field_ranges = dict(BaseDatabaseOperations.integer_field_ranges, 33 | PositiveSmallIntegerField=(0, 4294967295), 34 | PositiveIntegerField=( 35 | 0, 18446744073709551615), ) 36 | 37 | def date_extract_sql(self, lookup_type, field_name): 38 | # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html 39 | if lookup_type == 'week_day': 40 | # DAYOFWEEK() returns an integer, 1-7, Sunday=1. 41 | # Note: WEEKDAY() returns 0-6, Monday=0. 42 | return "DAYOFWEEK({0})".format(field_name) 43 | else: 44 | return "EXTRACT({0} FROM {1})".format( 45 | lookup_type.upper(), field_name) 46 | 47 | def date_trunc_sql(self, lookup_type, field_name): 48 | """Returns SQL simulating DATE_TRUNC 49 | 50 | This function uses MySQL functions DATE_FORMAT and CAST to 51 | simulate DATE_TRUNC. 52 | 53 | The field_name is returned when lookup_type is not supported. 54 | """ 55 | fields = ['year', 'month', 'day', 'hour', 'minute', 'second'] 56 | format = ('%Y-', '%m', '-%d', ' %H:', '%i', ':%S') 57 | format_def = ('0000-', '01', '-01', ' 00:', '00', ':00') 58 | try: 59 | i = fields.index(lookup_type) + 1 60 | except ValueError: 61 | # Wrong lookup type, just return the value from MySQL as-is 62 | sql = field_name 63 | else: 64 | format_str = ''.join([f for f in format[:i]] + 65 | [f for f in format_def[i:]]) 66 | sql = "CAST(DATE_FORMAT({0}, '{1}') AS DATETIME)".format( 67 | field_name, format_str) 68 | return sql 69 | 70 | def datetime_extract_sql(self, lookup_type, field_name, tzname): 71 | # Django 1.6 72 | if settings.USE_TZ: 73 | field_name = "CONVERT_TZ({0}, 'UTC', %s)".format(field_name) 74 | params = [tzname] 75 | else: 76 | params = [] 77 | 78 | # http://dev.mysql.com/doc/mysql/en/date-and-time-functions.html 79 | if lookup_type == 'week_day': 80 | # DAYOFWEEK() returns an integer, 1-7, Sunday=1. 81 | # Note: WEEKDAY() returns 0-6, Monday=0. 82 | sql = "DAYOFWEEK({0})".format(field_name) 83 | else: 84 | sql = "EXTRACT({0} FROM {1})".format(lookup_type.upper(), 85 | field_name) 86 | return sql, params 87 | 88 | def datetime_trunc_sql(self, lookup_type, field_name, tzname): 89 | # Django 1.6 90 | if settings.USE_TZ: 91 | field_name = "CONVERT_TZ({0}, 'UTC', %s)".format(field_name) 92 | params = [tzname] 93 | else: 94 | params = [] 95 | fields = ['year', 'month', 'day', 'hour', 'minute', 'second'] 96 | format_ = ('%Y-', '%m', '-%d', ' %H:', '%i', ':%S') 97 | format_def = ('0000-', '01', '-01', ' 00:', '00', ':00') 98 | try: 99 | i = fields.index(lookup_type) + 1 100 | except ValueError: 101 | sql = field_name 102 | else: 103 | format_str = ''.join([f for f in format_[:i]] + 104 | [f for f in format_def[i:]]) 105 | sql = "CAST(DATE_FORMAT({0}, '{1}') AS DATETIME)".format( 106 | field_name, format_str) 107 | return sql, params 108 | 109 | if django.VERSION >= (1, 8): 110 | def date_interval_sql(self, timedelta): 111 | """Returns SQL for calculating date/time intervals 112 | """ 113 | return "INTERVAL '%d 0:0:%d:%d' DAY_MICROSECOND" % ( 114 | timedelta.days, timedelta.seconds, timedelta.microseconds), [] 115 | else: 116 | def date_interval_sql(self, sql, connector, timedelta): 117 | """Returns SQL for calculating date/time intervals 118 | """ 119 | fmt = ( 120 | "({sql} {connector} INTERVAL '{days} " 121 | "0:0:{secs}:{msecs}' DAY_MICROSECOND)" 122 | ) 123 | return fmt.format( 124 | sql=sql, 125 | connector=connector, 126 | days=timedelta.days, 127 | secs=timedelta.seconds, 128 | msecs=timedelta.microseconds 129 | ) 130 | 131 | def format_for_duration_arithmetic(self, sql): 132 | if self.connection.features.supports_microsecond_precision: 133 | return 'INTERVAL %s MICROSECOND' % sql 134 | else: 135 | return 'INTERVAL FLOOR(%s / 1000000) SECOND' % sql 136 | 137 | def drop_foreignkey_sql(self): 138 | return "DROP FOREIGN KEY" 139 | 140 | def force_no_ordering(self): 141 | """ 142 | "ORDER BY NULL" prevents MySQL from implicitly ordering by grouped 143 | columns. If no ordering would otherwise be applied, we don't want any 144 | implicit sorting going on. 145 | """ 146 | if django.VERSION >= (1, 8): 147 | return [(None, ("NULL", [], False))] 148 | else: 149 | return ["NULL"] 150 | 151 | def fulltext_search_sql(self, field_name): 152 | return 'MATCH ({0}) AGAINST (%s IN BOOLEAN MODE)'.format(field_name) 153 | 154 | def last_executed_query(self, cursor, sql, params): 155 | return force_text(cursor.statement, errors='replace') 156 | 157 | def no_limit_value(self): 158 | # 2**64 - 1, as recommended by the MySQL documentation 159 | return 18446744073709551615 160 | 161 | def quote_name(self, name): 162 | if name.startswith("`") and name.endswith("`"): 163 | return name # Quoting once is enough. 164 | return "`{0}`".format(name) 165 | 166 | def random_function_sql(self): 167 | return 'RAND()' 168 | 169 | def sql_flush(self, style, tables, sequences, allow_cascade=False): 170 | if tables: 171 | sql = ['SET FOREIGN_KEY_CHECKS = 0;'] 172 | for table in tables: 173 | sql.append('{keyword} {table};'.format( 174 | keyword=style.SQL_KEYWORD('TRUNCATE'), 175 | table=style.SQL_FIELD(self.quote_name(table)))) 176 | sql.append('SET FOREIGN_KEY_CHECKS = 1;') 177 | sql.extend(self.sequence_reset_by_name_sql(style, sequences)) 178 | return sql 179 | else: 180 | return [] 181 | 182 | def validate_autopk_value(self, value): 183 | # MySQLism: zero in AUTO_INCREMENT field does not work. Refs #17653. 184 | if value == 0: 185 | raise ValueError('The database backend does not accept 0 as a ' 186 | 'value for AutoField.') 187 | return value 188 | 189 | def value_to_db_datetime(self, value): 190 | if value is None: 191 | return None 192 | # MySQL doesn't support tz-aware times 193 | if timezone.is_aware(value): 194 | if settings.USE_TZ: 195 | value = value.astimezone(timezone.utc).replace(tzinfo=None) 196 | else: 197 | raise ValueError( 198 | "MySQL backend does not support timezone-aware times." 199 | ) 200 | if not self.connection.features.supports_microsecond_precision: 201 | value = value.replace(microsecond=0) 202 | if not self.connection.use_pure: 203 | return datetime_to_mysql(value) 204 | return self.connection.converter.to_mysql(value) 205 | 206 | def value_to_db_time(self, value): 207 | if value is None: 208 | return None 209 | 210 | # MySQL doesn't support tz-aware times 211 | if timezone.is_aware(value): 212 | raise ValueError("MySQL backend does not support timezone-aware " 213 | "times.") 214 | 215 | if not self.connection.use_pure: 216 | return time_to_mysql(value) 217 | return self.connection.converter.to_mysql(value) 218 | 219 | def max_name_length(self): 220 | return 64 221 | 222 | def bulk_insert_sql(self, fields, num_values): 223 | placeholder_rows_sql = (", ".join(row) for row in num_values) 224 | values_sql = ", ".join("(%s)" % sql for sql in placeholder_rows_sql) 225 | return "VALUES " + values_sql 226 | 227 | if django.VERSION < (1, 8): 228 | def year_lookup_bounds(self, value): 229 | # Again, no microseconds 230 | first = '{0}-01-01 00:00:00' 231 | second = '{0}-12-31 23:59:59.999999' 232 | return [first.format(value), second.format(value)] 233 | 234 | def year_lookup_bounds_for_datetime_field(self, value): 235 | # Django 1.6 236 | # Again, no microseconds 237 | first, second = super(DatabaseOperations, 238 | self).year_lookup_bounds_for_datetime_field(value) 239 | if self.connection.mysql_version >= (5, 6, 4): 240 | return [first.replace(microsecond=0), second] 241 | else: 242 | return [first.replace(microsecond=0), 243 | second.replace(microsecond=0)] 244 | 245 | def sequence_reset_by_name_sql(self, style, sequences): 246 | # Truncate already resets the AUTO_INCREMENT field from 247 | # MySQL version 5.0.13 onwards. Refs #16961. 248 | res = [] 249 | if self.connection.mysql_version < (5, 0, 13): 250 | fmt = "{alter} {table} {{tablename}} {auto_inc} {field};".format( 251 | alter=style.SQL_KEYWORD('ALTER'), 252 | table=style.SQL_KEYWORD('TABLE'), 253 | auto_inc=style.SQL_KEYWORD('AUTO_INCREMENT'), 254 | field=style.SQL_FIELD('= 1') 255 | ) 256 | for sequence in sequences: 257 | tablename = style.SQL_TABLE(self.quote_name(sequence['table'])) 258 | res.append(fmt.format(tablename=tablename)) 259 | return res 260 | return res 261 | 262 | def savepoint_create_sql(self, sid): 263 | return "SAVEPOINT {0}".format(sid) 264 | 265 | def savepoint_commit_sql(self, sid): 266 | return "RELEASE SAVEPOINT {0}".format(sid) 267 | 268 | def savepoint_rollback_sql(self, sid): 269 | return "ROLLBACK TO SAVEPOINT {0}".format(sid) 270 | 271 | def combine_expression(self, connector, sub_expressions): 272 | """ 273 | MySQL requires special cases for ^ operators in query expressions 274 | """ 275 | if connector == '^': 276 | return 'POW(%s)' % ','.join(sub_expressions) 277 | return super(DatabaseOperations, self).combine_expression( 278 | connector, sub_expressions) 279 | 280 | def get_db_converters(self, expression): 281 | # New in Django 1.8 282 | converters = super(DatabaseOperations, self).get_db_converters( 283 | expression) 284 | internal_type = expression.output_field.get_internal_type() 285 | if internal_type in ['BooleanField', 'NullBooleanField']: 286 | converters.append(self.convert_booleanfield_value) 287 | if internal_type == 'UUIDField': 288 | converters.append(self.convert_uuidfield_value) 289 | if internal_type == 'TextField': 290 | converters.append(self.convert_textfield_value) 291 | return converters 292 | 293 | def convert_booleanfield_value(self, value, 294 | expression, connection, context): 295 | # New in Django 1.8 296 | if value in (0, 1): 297 | value = bool(value) 298 | return value 299 | 300 | def convert_uuidfield_value(self, value, expression, connection, context): 301 | # New in Django 1.8 302 | if value is not None: 303 | value = uuid.UUID(value) 304 | return value 305 | 306 | def convert_textfield_value(self, value, expression, connection, context): 307 | # New in Django 1.8 308 | if value is not None: 309 | value = force_text(value) 310 | return value 311 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/django/schema.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | 3 | # New file added for Django 1.7 4 | 5 | import django 6 | 7 | if django.VERSION >= (1, 8): 8 | from django.db.backends.base.schema import BaseDatabaseSchemaEditor 9 | else: 10 | from django.db.backends.schema import BaseDatabaseSchemaEditor 11 | from django.db.models import NOT_PROVIDED 12 | 13 | 14 | class DatabaseSchemaEditor(BaseDatabaseSchemaEditor): 15 | sql_rename_table = "RENAME TABLE %(old_table)s TO %(new_table)s" 16 | 17 | sql_alter_column_null = "MODIFY %(column)s %(type)s NULL" 18 | sql_alter_column_not_null = "MODIFY %(column)s %(type)s NOT NULL" 19 | sql_alter_column_type = "MODIFY %(column)s %(type)s" 20 | sql_rename_column = "ALTER TABLE %(table)s CHANGE %(old_column)s " \ 21 | "%(new_column)s %(type)s" 22 | 23 | sql_delete_unique = "ALTER TABLE %(table)s DROP INDEX %(name)s" 24 | 25 | sql_create_fk = "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s FOREIGN " \ 26 | "KEY (%(column)s) REFERENCES %(to_table)s (%(to_column)s)" 27 | sql_delete_fk = "ALTER TABLE %(table)s DROP FOREIGN KEY %(name)s" 28 | 29 | sql_delete_index = "DROP INDEX %(name)s ON %(table)s" 30 | 31 | alter_string_set_null = 'MODIFY %(column)s %(type)s NULL;' 32 | alter_string_drop_null = 'MODIFY %(column)s %(type)s NOT NULL;' 33 | 34 | sql_create_pk = "ALTER TABLE %(table)s ADD CONSTRAINT %(name)s " \ 35 | "PRIMARY KEY (%(columns)s)" 36 | sql_delete_pk = "ALTER TABLE %(table)s DROP PRIMARY KEY" 37 | 38 | def quote_value(self, value): 39 | # Inner import to allow module to fail to load gracefully 40 | from PyMysqlPool.mysql.connector.conversion import MySQLConverter 41 | return MySQLConverter.quote(MySQLConverter.escape(value)) 42 | 43 | def skip_default(self, field): 44 | """ 45 | MySQL doesn't accept default values for longtext and longblob 46 | and implicitly treats these columns as nullable. 47 | """ 48 | return field.db_type(self.connection) in ('longtext', 'longblob') 49 | 50 | def add_field(self, model, field): 51 | super(DatabaseSchemaEditor, self).add_field(model, field) 52 | 53 | # Simulate the effect of a one-off default. 54 | if (self.skip_default(field) 55 | and field.default not in (None, NOT_PROVIDED)): 56 | effective_default = self.effective_default(field) 57 | self.execute('UPDATE %(table)s SET %(column)s = %%s' % { 58 | 'table': self.quote_name(model._meta.db_table), 59 | 'column': self.quote_name(field.column), 60 | }, [effective_default]) 61 | 62 | def _model_indexes_sql(self, model): 63 | # New in Django 1.8 64 | storage = self.connection.introspection.get_storage_engine( 65 | self.connection.cursor(), model._meta.db_table 66 | ) 67 | if storage == "InnoDB": 68 | for field in model._meta.local_fields: 69 | if (field.db_index and not field.unique 70 | and field.get_internal_type() == "ForeignKey"): 71 | # Temporary setting db_index to False (in memory) to 72 | # disable index creation for FKs (index automatically 73 | # created by MySQL) 74 | field.db_index = False 75 | return super(DatabaseSchemaEditor, self)._model_indexes_sql(model) 76 | 77 | def _alter_column_type_sql(self, table, old_field, new_field, new_type): 78 | # New in Django 1.8 79 | # Keep null property of old field, if it has changed, it will be 80 | # handled separately 81 | if old_field.null: 82 | new_type += " NULL" 83 | else: 84 | new_type += " NOT NULL" 85 | return super(DatabaseSchemaEditor, self)._alter_column_type_sql( 86 | table, old_field, new_field, new_type) 87 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/django/validation.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | 3 | import django 4 | 5 | if django.VERSION >= (1, 8): 6 | from django.db.backends.base.validation import BaseDatabaseValidation 7 | else: 8 | from django.db.backends import BaseDatabaseValidation 9 | 10 | if django.VERSION < (1, 7): 11 | from django.db import models 12 | else: 13 | from django.core import checks 14 | from django.db import connection 15 | 16 | 17 | class DatabaseValidation(BaseDatabaseValidation): 18 | if django.VERSION < (1, 7): 19 | def validate_field(self, errors, opts, f): 20 | """ 21 | MySQL has the following field length restriction: 22 | No character (varchar) fields can have a length exceeding 255 23 | characters if they have a unique index on them. 24 | """ 25 | varchar_fields = (models.CharField, 26 | models.CommaSeparatedIntegerField, 27 | models.SlugField) 28 | if isinstance(f, varchar_fields) and f.max_length > 255 and f.unique: 29 | msg = ('"%(name)s": %(cls)s cannot have a "max_length" greater ' 30 | 'than 255 when using "unique=True".') 31 | errors.add(opts, msg % {'name': f.name, 32 | 'cls': f.__class__.__name__}) 33 | 34 | else: 35 | def check_field(self, field, **kwargs): 36 | """ 37 | MySQL has the following field length restriction: 38 | No character (varchar) fields can have a length exceeding 255 39 | characters if they have a unique index on them. 40 | """ 41 | # Django 1.7 42 | errors = super(DatabaseValidation, self).check_field(field, 43 | **kwargs) 44 | 45 | # Ignore any related fields. 46 | if getattr(field, 'rel', None) is None: 47 | field_type = field.db_type(connection) 48 | 49 | if field_type is None: 50 | return errors 51 | 52 | if (field_type.startswith('varchar') # Look for CharFields... 53 | and field.unique # ... that are unique 54 | and (field.max_length is None or 55 | int(field.max_length) > 255)): 56 | errors.append( 57 | checks.Error( 58 | ('MySQL does not allow unique CharFields to have a ' 59 | 'max_length > 255.'), 60 | hint=None, 61 | obj=field, 62 | id='mysql.E001', 63 | ) 64 | ) 65 | return errors 66 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/errors.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """Python exceptions 25 | """ 26 | 27 | from . import utils 28 | from .catch23 import PY2 29 | from .locales import get_client_error 30 | 31 | # _CUSTOM_ERROR_EXCEPTIONS holds custom exceptions and is ued by the 32 | # function custom_error_exception. _ERROR_EXCEPTIONS (at bottom of module) 33 | # is similar, but hardcoded exceptions. 34 | _CUSTOM_ERROR_EXCEPTIONS = {} 35 | 36 | 37 | def custom_error_exception(error=None, exception=None): 38 | """Define custom exceptions for MySQL server errors 39 | 40 | This function defines custom exceptions for MySQL server errors and 41 | returns the current set customizations. 42 | 43 | If error is a MySQL Server error number, then you have to pass also the 44 | exception class. 45 | 46 | The error argument can also be a dictionary in which case the key is 47 | the server error number, and value the exception to be raised. 48 | 49 | If none of the arguments are given, then custom_error_exception() will 50 | simply return the current set customizations. 51 | 52 | To reset the customizations, simply supply an empty dictionary. 53 | 54 | Examples: 55 | import mysql.connector 56 | from mysql.connector import errorcode 57 | 58 | # Server error 1028 should raise a DatabaseError 59 | mysql.connector.custom_error_exception( 60 | 1028, mysql.connector.DatabaseError) 61 | 62 | # Or using a dictionary: 63 | mysql.connector.custom_error_exception({ 64 | 1028: mysql.connector.DatabaseError, 65 | 1029: mysql.connector.OperationalError, 66 | }) 67 | 68 | # Reset 69 | mysql.connector.custom_error_exception({}) 70 | 71 | Returns a dictionary. 72 | """ 73 | global _CUSTOM_ERROR_EXCEPTIONS # pylint: disable=W0603 74 | 75 | if isinstance(error, dict) and not len(error): 76 | _CUSTOM_ERROR_EXCEPTIONS = {} 77 | return _CUSTOM_ERROR_EXCEPTIONS 78 | 79 | if not error and not exception: 80 | return _CUSTOM_ERROR_EXCEPTIONS 81 | 82 | if not isinstance(error, (int, dict)): 83 | raise ValueError( 84 | "The error argument should be either an integer or dictionary") 85 | 86 | if isinstance(error, int): 87 | error = {error: exception} 88 | 89 | for errno, exception in error.items(): 90 | if not isinstance(errno, int): 91 | raise ValueError("error number should be an integer") 92 | try: 93 | if not issubclass(exception, Exception): 94 | raise TypeError 95 | except TypeError: 96 | raise ValueError("exception should be subclass of Exception") 97 | _CUSTOM_ERROR_EXCEPTIONS[errno] = exception 98 | 99 | return _CUSTOM_ERROR_EXCEPTIONS 100 | 101 | 102 | def get_mysql_exception(errno, msg=None, sqlstate=None): 103 | """Get the exception matching the MySQL error 104 | 105 | This function will return an exception based on the SQLState. The given 106 | message will be passed on in the returned exception. 107 | 108 | The exception returned can be customized using the 109 | mysql.connector.custom_error_exception() function. 110 | 111 | Returns an Exception 112 | """ 113 | try: 114 | return _CUSTOM_ERROR_EXCEPTIONS[errno]( 115 | msg=msg, errno=errno, sqlstate=sqlstate) 116 | except KeyError: 117 | # Error was not mapped to particular exception 118 | pass 119 | 120 | try: 121 | return _ERROR_EXCEPTIONS[errno]( 122 | msg=msg, errno=errno, sqlstate=sqlstate) 123 | except KeyError: 124 | # Error was not mapped to particular exception 125 | pass 126 | 127 | if not sqlstate: 128 | return DatabaseError(msg=msg, errno=errno) 129 | 130 | try: 131 | return _SQLSTATE_CLASS_EXCEPTION[sqlstate[0:2]]( 132 | msg=msg, errno=errno, sqlstate=sqlstate) 133 | except KeyError: 134 | # Return default InterfaceError 135 | return DatabaseError(msg=msg, errno=errno, sqlstate=sqlstate) 136 | 137 | 138 | def get_exception(packet): 139 | """Returns an exception object based on the MySQL error 140 | 141 | Returns an exception object based on the MySQL error in the given 142 | packet. 143 | 144 | Returns an Error-Object. 145 | """ 146 | errno = errmsg = None 147 | 148 | try: 149 | if packet[4] != 255: 150 | raise ValueError("Packet is not an error packet") 151 | except IndexError as err: 152 | return InterfaceError("Failed getting Error information (%r)" % err) 153 | 154 | sqlstate = None 155 | try: 156 | packet = packet[5:] 157 | (packet, errno) = utils.read_int(packet, 2) 158 | if packet[0] != 35: 159 | # Error without SQLState 160 | if isinstance(packet, (bytes, bytearray)): 161 | errmsg = packet.decode('utf8') 162 | else: 163 | errmsg = packet 164 | else: 165 | (packet, sqlstate) = utils.read_bytes(packet[1:], 5) 166 | sqlstate = sqlstate.decode('utf8') 167 | errmsg = packet.decode('utf8') 168 | except Exception as err: # pylint: disable=W0703 169 | return InterfaceError("Failed getting Error information (%r)" % err) 170 | else: 171 | return get_mysql_exception(errno, errmsg, sqlstate) 172 | 173 | 174 | class Error(Exception): 175 | """Exception that is base class for all other error exceptions""" 176 | 177 | def __init__(self, msg=None, errno=None, values=None, sqlstate=None): 178 | super(Error, self).__init__() 179 | self.msg = msg 180 | self._full_msg = self.msg 181 | self.errno = errno or -1 182 | self.sqlstate = sqlstate 183 | 184 | if not self.msg and (2000 <= self.errno < 3000): 185 | self.msg = get_client_error(self.errno) 186 | if values is not None: 187 | try: 188 | self.msg = self.msg % values 189 | except TypeError as err: 190 | self.msg = "{0} (Warning: {1})".format(self.msg, str(err)) 191 | elif not self.msg: 192 | self._full_msg = self.msg = 'Unknown error' 193 | 194 | if self.msg and self.errno != -1: 195 | fields = { 196 | 'errno': self.errno, 197 | 'msg': self.msg.encode('utf8') if PY2 else self.msg 198 | } 199 | if self.sqlstate: 200 | fmt = '{errno} ({state}): {msg}' 201 | fields['state'] = self.sqlstate 202 | else: 203 | fmt = '{errno}: {msg}' 204 | self._full_msg = fmt.format(**fields) 205 | 206 | self.args = (self.errno, self._full_msg, self.sqlstate) 207 | 208 | def __str__(self): 209 | return self._full_msg 210 | 211 | 212 | class Warning(Exception): # pylint: disable=W0622 213 | """Exception for important warnings""" 214 | pass 215 | 216 | 217 | class InterfaceError(Error): 218 | """Exception for errors related to the interface""" 219 | pass 220 | 221 | 222 | class DatabaseError(Error): 223 | """Exception for errors related to the database""" 224 | pass 225 | 226 | 227 | class InternalError(DatabaseError): 228 | """Exception for errors internal database errors""" 229 | pass 230 | 231 | 232 | class OperationalError(DatabaseError): 233 | """Exception for errors related to the database's operation""" 234 | pass 235 | 236 | 237 | class ProgrammingError(DatabaseError): 238 | """Exception for errors programming errors""" 239 | pass 240 | 241 | 242 | class IntegrityError(DatabaseError): 243 | """Exception for errors regarding relational integrity""" 244 | pass 245 | 246 | 247 | class DataError(DatabaseError): 248 | """Exception for errors reporting problems with processed data""" 249 | pass 250 | 251 | 252 | class NotSupportedError(DatabaseError): 253 | """Exception for errors when an unsupported database feature was used""" 254 | pass 255 | 256 | 257 | class PoolError(Error): 258 | """Exception for errors relating to connection pooling""" 259 | pass 260 | 261 | 262 | class MySQLFabricError(Error): 263 | """Exception for errors relating to MySQL Fabric""" 264 | 265 | 266 | _SQLSTATE_CLASS_EXCEPTION = { 267 | '02': DataError, # no data 268 | '07': DatabaseError, # dynamic SQL error 269 | '08': OperationalError, # connection exception 270 | '0A': NotSupportedError, # feature not supported 271 | '21': DataError, # cardinality violation 272 | '22': DataError, # data exception 273 | '23': IntegrityError, # integrity constraint violation 274 | '24': ProgrammingError, # invalid cursor state 275 | '25': ProgrammingError, # invalid transaction state 276 | '26': ProgrammingError, # invalid SQL statement name 277 | '27': ProgrammingError, # triggered data change violation 278 | '28': ProgrammingError, # invalid authorization specification 279 | '2A': ProgrammingError, # direct SQL syntax error or access rule violation 280 | '2B': DatabaseError, # dependent privilege descriptors still exist 281 | '2C': ProgrammingError, # invalid character set name 282 | '2D': DatabaseError, # invalid transaction termination 283 | '2E': DatabaseError, # invalid connection name 284 | '33': DatabaseError, # invalid SQL descriptor name 285 | '34': ProgrammingError, # invalid cursor name 286 | '35': ProgrammingError, # invalid condition number 287 | '37': ProgrammingError, # dynamic SQL syntax error or access rule violation 288 | '3C': ProgrammingError, # ambiguous cursor name 289 | '3D': ProgrammingError, # invalid catalog name 290 | '3F': ProgrammingError, # invalid schema name 291 | '40': InternalError, # transaction rollback 292 | '42': ProgrammingError, # syntax error or access rule violation 293 | '44': InternalError, # with check option violation 294 | 'HZ': OperationalError, # remote database access 295 | 'XA': IntegrityError, 296 | '0K': OperationalError, 297 | 'HY': DatabaseError, # default when no SQLState provided by MySQL server 298 | } 299 | 300 | _ERROR_EXCEPTIONS = { 301 | 1243: ProgrammingError, 302 | 1210: ProgrammingError, 303 | 2002: InterfaceError, 304 | 2013: OperationalError, 305 | 2049: NotSupportedError, 306 | 2055: OperationalError, 307 | 2061: InterfaceError, 308 | } 309 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/fabric/__init__.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """MySQL Fabric support""" 25 | 26 | from collections import namedtuple 27 | 28 | # Order of field_names must match how Fabric is returning the data 29 | FabricMySQLServer = namedtuple( 30 | 'FabricMySQLServer', 31 | ['uuid', 'group', 'host', 'port', 'mode', 'status', 'weight'] 32 | ) 33 | 34 | # Order of field_names must match how Fabric is returning the data 35 | FabricShard = namedtuple( 36 | 'FabricShard', 37 | ['database', 'table', 'column', 'key', 38 | 'shard', 'shard_type', 'group', 'global_group'] 39 | ) 40 | 41 | from .connection import ( 42 | MODE_READONLY, MODE_READWRITE, 43 | STATUS_PRIMARY, STATUS_SECONDARY, 44 | SCOPE_GLOBAL, SCOPE_LOCAL, 45 | Fabric, FabricConnection, 46 | MySQLFabricConnection, 47 | FabricSet, 48 | ) 49 | 50 | 51 | def connect(**kwargs): 52 | """Create a MySQLFabricConnection object""" 53 | return MySQLFabricConnection(**kwargs) 54 | 55 | 56 | __all__ = [ 57 | 'MODE_READWRITE', 58 | 'MODE_READONLY', 59 | 'STATUS_PRIMARY', 60 | 'STATUS_SECONDARY', 61 | 'SCOPE_GLOBAL', 62 | 'SCOPE_LOCAL', 63 | 'FabricMySQLServer', 64 | 'FabricShard', 65 | 'connect', 66 | 'Fabric', 67 | 'FabricConnection', 68 | 'MySQLFabricConnection', 69 | 'FabricSet', 70 | ] 71 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/fabric/balancing.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2013, 2014, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """Implementing load balancing""" 25 | 26 | import decimal 27 | 28 | 29 | def _calc_ratio(part, whole): 30 | """Calculate ratio 31 | 32 | Returns int 33 | """ 34 | return int((part / whole * 100).quantize( 35 | decimal.Decimal('1'), rounding=decimal.ROUND_HALF_DOWN)) 36 | 37 | 38 | class BaseScheduling(object): 39 | """Base class for all scheduling classes dealing with load balancing""" 40 | 41 | def __init__(self): 42 | """Initialize""" 43 | self._members = [] 44 | self._ratios = [] 45 | 46 | def set_members(self, *args): 47 | """Set members and ratios 48 | 49 | This methods sets the members using the arguments passed. Each 50 | argument must be a sequence where the second item is the weight. 51 | The first element is an identifier. For example: 52 | 53 | ('server1', 0.6), ('server2', 0.8) 54 | 55 | Setting members means that the load will be reset. If the members 56 | are the same as previously set, nothing will be reset or set. 57 | 58 | If no arguments were given the members will be set to an empty 59 | list. 60 | 61 | Raises ValueError when weight can't be converted to a Decimal. 62 | """ 63 | raise NotImplementedError 64 | 65 | def get_next(self): 66 | """Returns the next member""" 67 | raise NotImplementedError 68 | 69 | @property 70 | def members(self): 71 | """Returns the members of this loadbalancer""" 72 | return self._members 73 | 74 | @property 75 | def ratios(self): 76 | """Returns the ratios for all members""" 77 | return self._ratios 78 | 79 | 80 | class WeightedRoundRobin(BaseScheduling): 81 | """Class for doing Weighted Round Robin balancing""" 82 | 83 | def __init__(self, *args): 84 | """Initializing""" 85 | super(WeightedRoundRobin, self).__init__() 86 | self._load = [] 87 | self._next_member = 0 88 | self._nr_members = 0 89 | 90 | if args: 91 | self.set_members(*args) 92 | 93 | @property 94 | def load(self): 95 | """Returns the current load""" 96 | return self._load 97 | 98 | def set_members(self, *args): 99 | if not args: 100 | # Reset members if nothing was given 101 | self._members = [] 102 | return 103 | new_members = [] 104 | for member in args: 105 | member = list(member) 106 | try: 107 | member[1] = decimal.Decimal(str(member[1])) 108 | except decimal.InvalidOperation: 109 | raise ValueError("Member '{member}' is invalid".format( 110 | member=member)) 111 | new_members.append(tuple(member)) 112 | 113 | new_members.sort(key=lambda x: x[1], reverse=True) 114 | if self._members == new_members: 115 | return 116 | self._members = new_members 117 | self._nr_members = len(new_members) 118 | 119 | min_weight = min(i[1] for i in self._members) 120 | self._ratios = [] 121 | for _, weight in self._members: 122 | self._ratios.append(int(weight / min_weight * 100)) 123 | self.reset() 124 | 125 | def reset(self): 126 | """Reset the load""" 127 | self._next_member = 0 128 | self._load = [0] * self._nr_members 129 | 130 | def get_next(self): 131 | """Returns the next member""" 132 | if self._ratios == self._load: 133 | self.reset() 134 | 135 | # Figure out the member to return 136 | current = self._next_member 137 | 138 | while self._load[current] == self._ratios[current]: 139 | current = (current + 1) % self._nr_members 140 | 141 | # Update the load and set next member 142 | self._load[current] += 1 143 | self._next_member = (current + 1) % self._nr_members 144 | 145 | # Return current 146 | return self._members[current] 147 | 148 | def __repr__(self): 149 | return "{class_}(load={load}, ratios={ratios})".format( 150 | class_=self.__class__, 151 | load=self.load, 152 | ratios=self.ratios 153 | ) 154 | 155 | def __eq__(self, other): 156 | return self._members == other.members 157 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/fabric/caching.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """Implementing caching mechanisms for MySQL Fabric""" 25 | 26 | import bisect 27 | import logging 28 | import threading 29 | from datetime import datetime, timedelta 30 | from hashlib import sha1 31 | 32 | from . import FabricShard 33 | 34 | _LOGGER = logging.getLogger('myconnpy-fabric') 35 | _CACHE_TTL = 1 * 60 # 1 minute 36 | 37 | 38 | def insort_right_rev(alist, new_element, low=0, high=None): 39 | """Similar to bisect.insort_right but for reverse sorted lists 40 | 41 | This code is similar to the Python code found in Lib/bisect.py. 42 | We simply change the comparison from 'less than' to 'greater than'. 43 | """ 44 | 45 | if low < 0: 46 | raise ValueError('low must be non-negative') 47 | if high is None: 48 | high = len(alist) 49 | while low < high: 50 | middle = (low + high) // 2 51 | if new_element > alist[middle]: 52 | high = middle 53 | else: 54 | low = middle + 1 55 | alist.insert(low, new_element) 56 | 57 | 58 | class CacheEntry(object): 59 | """Base class for MySQL Fabric cache entries""" 60 | 61 | def __init__(self, version=None, fabric_uuid=None, ttl=_CACHE_TTL): 62 | self.version = version 63 | self.fabric_uuid = fabric_uuid 64 | self.last_updated = datetime.utcnow() 65 | self._ttl = ttl 66 | 67 | @classmethod 68 | def hash_index(cls, part1, part2=None): 69 | """Create hash for indexing""" 70 | raise NotImplementedError 71 | 72 | @property 73 | def invalid(self): 74 | """Returns True if entry is not valid any longer 75 | 76 | This property returns True when the entry is not valid any longer. 77 | The entry is valid when now > (last updated + ttl), where ttl is 78 | in seconds. 79 | """ 80 | if not self.last_updated: 81 | return False 82 | atime = self.last_updated + timedelta(seconds=self._ttl) 83 | return datetime.utcnow() > atime 84 | 85 | def reset_ttl(self): 86 | """Reset the Time to Live""" 87 | self.last_updated = datetime.utcnow() 88 | 89 | def invalidate(self): 90 | """Invalidates the cache entry""" 91 | self.last_updated = None 92 | 93 | 94 | class CacheShardTable(CacheEntry): 95 | """Cache entry for a Fabric sharded table""" 96 | 97 | def __init__(self, shard, version=None, fabric_uuid=None): 98 | if not isinstance(shard, FabricShard): 99 | raise ValueError("shard argument must be a FabricShard instance") 100 | super(CacheShardTable, self).__init__(version=version, 101 | fabric_uuid=fabric_uuid) 102 | self.partitioning = {} 103 | self._shard = shard 104 | self.keys = [] 105 | self.keys_reversed = [] 106 | 107 | if shard.key and shard.group: 108 | self.add_partition(shard.key, shard.group) 109 | 110 | def __getattr__(self, attr): 111 | return getattr(self._shard, attr) 112 | 113 | def add_partition(self, key, group): 114 | """Add sharding information for a group""" 115 | if self.shard_type == 'RANGE': 116 | key = int(key) 117 | elif self.shard_type == 'RANGE_DATETIME': 118 | try: 119 | if ':' in key: 120 | key = datetime.strptime(key, "%Y-%m-%d %H:%M:%S") 121 | else: 122 | key = datetime.strptime(key, "%Y-%m-%d").date() 123 | except: 124 | raise ValueError( 125 | "RANGE_DATETIME key could not be parsed, was: {0}".format( 126 | key 127 | )) 128 | elif self.shard_type == 'RANGE_STRING': 129 | pass 130 | elif self.shard_type == "HASH": 131 | pass 132 | else: 133 | raise ValueError("Unsupported sharding type {0}".format( 134 | self.shard_type 135 | )) 136 | self.partitioning[key] = { 137 | 'group': group, 138 | } 139 | self.reset_ttl() 140 | bisect.insort_right(self.keys, key) 141 | insort_right_rev(self.keys_reversed, key) 142 | 143 | @classmethod 144 | def hash_index(cls, part1, part2=None): 145 | """Create hash for indexing""" 146 | return sha1(part1.encode('utf-8') + part2.encode('utf-8')).hexdigest() 147 | 148 | def __repr__(self): 149 | return "{class_}({database}.{table}.{column})".format( 150 | class_=self.__class__, 151 | database=self.database, 152 | table=self.table, 153 | column=self.column 154 | ) 155 | 156 | 157 | class CacheGroup(CacheEntry): 158 | """Cache entry for a Fabric group""" 159 | 160 | def __init__(self, group_name, servers): 161 | super(CacheGroup, self).__init__(version=None, fabric_uuid=None) 162 | self.group_name = group_name 163 | self.servers = servers 164 | 165 | @classmethod 166 | def hash_index(cls, part1, part2=None): 167 | """Create hash for indexing""" 168 | return sha1(part1.encode('utf-8')).hexdigest() 169 | 170 | def __repr__(self): 171 | return "{class_}({group})".format( 172 | class_=self.__class__, 173 | group=self.group_name, 174 | ) 175 | 176 | 177 | class FabricCache(object): 178 | """Singleton class for caching Fabric data 179 | 180 | Only one instance of this class can exists globally. 181 | """ 182 | 183 | def __init__(self, ttl=_CACHE_TTL): 184 | self._ttl = ttl 185 | self._sharding = {} 186 | self._groups = {} 187 | self.__sharding_lock = threading.Lock() 188 | self.__groups_lock = threading.Lock() 189 | 190 | def remove_group(self, entry_hash): 191 | """Remove cache entry for group""" 192 | with self.__groups_lock: 193 | try: 194 | del self._groups[entry_hash] 195 | except KeyError: 196 | # not cached, that's OK 197 | pass 198 | else: 199 | _LOGGER.debug("Group removed from cache") 200 | 201 | def remove_shardtable(self, entry_hash): 202 | """Remove cache entry for shard""" 203 | with self.__sharding_lock: 204 | try: 205 | del self._sharding[entry_hash] 206 | except KeyError: 207 | # not cached, that's OK 208 | pass 209 | 210 | def sharding_cache_table(self, shard, version=None, fabric_uuid=None): 211 | """Cache information about a shard""" 212 | entry_hash = CacheShardTable.hash_index(shard.database, shard.table) 213 | 214 | with self.__sharding_lock: 215 | try: 216 | entry = self._sharding[entry_hash] 217 | entry.add_partition(shard.key, shard.group) 218 | except KeyError: 219 | # New cache entry 220 | entry = CacheShardTable(shard, version=version, 221 | fabric_uuid=fabric_uuid) 222 | self._sharding[entry_hash] = entry 223 | 224 | def cache_group(self, group_name, servers): 225 | """Cache information about a group""" 226 | entry_hash = CacheGroup.hash_index(group_name) 227 | 228 | with self.__groups_lock: 229 | try: 230 | entry = self._groups[entry_hash] 231 | entry.servers = servers 232 | entry.reset_ttl() 233 | _LOGGER.debug("Recaching group {0} with {1}".format( 234 | group_name, servers)) 235 | except KeyError: 236 | # New cache entry 237 | entry = CacheGroup(group_name, servers) 238 | self._groups[entry_hash] = entry 239 | _LOGGER.debug("Caching group {0} with {1}".format( 240 | group_name, servers)) 241 | 242 | def sharding_search(self, database, table): 243 | """Search cache for a shard based on database and table""" 244 | entry_hash = CacheShardTable.hash_index(database, table) 245 | 246 | entry = None 247 | try: 248 | entry = self._sharding[entry_hash] 249 | if entry.invalid: 250 | _LOGGER.debug("{0} invalidated".format(entry)) 251 | self.remove_shardtable(entry_hash) 252 | return None 253 | except KeyError: 254 | # Nothing in cache 255 | return None 256 | 257 | return entry 258 | 259 | def group_search(self, group_name): 260 | """Search cache for a group based on its name""" 261 | entry_hash = CacheGroup.hash_index(group_name) 262 | 263 | entry = None 264 | try: 265 | entry = self._groups[entry_hash] 266 | if entry.invalid: 267 | _LOGGER.debug("{0} invalidated".format(entry)) 268 | self.remove_group(entry_hash) 269 | return None 270 | except KeyError: 271 | # Nothing in cache 272 | return None 273 | 274 | return entry 275 | 276 | def __repr__(self): 277 | return "{class_}(groups={nrgroups},shards={nrshards})".format( 278 | class_=self.__class__, 279 | nrgroups=len(self._groups), 280 | nrshards=len(self._sharding) 281 | ) 282 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/flask/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/PyMysqlPool/mysql/connector/flask/__init__.py -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/flask/mysql.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | from __future__ import absolute_import 3 | 4 | from PyMysqlPool.db_util.mysql_pool import get_pool_conn_implicitly 5 | 6 | try: 7 | from flask import _app_ctx_stack as _ctx_stack 8 | except ImportError: 9 | from flask import _request_ctx_stack as _ctx_stack 10 | 11 | 12 | class MySQL(object): 13 | def __init__(self, app=None, **connect_args): 14 | self.connect_args = connect_args 15 | if app is not None: 16 | self.app = app 17 | self.init_app(self.app) 18 | else: 19 | self.app = None 20 | 21 | def init_app(self, app): 22 | self.app = app 23 | self.app.config.setdefault('MYSQL_DATABASE_HOST', 'localhost') 24 | self.app.config.setdefault('MYSQL_DATABASE_PORT', 3306) 25 | self.app.config.setdefault('MYSQL_DATABASE_USER', None) 26 | self.app.config.setdefault('MYSQL_DATABASE_PASSWORD', None) 27 | self.app.config.setdefault('MYSQL_DATABASE_DB', None) 28 | self.app.config.setdefault('MYSQL_DATABASE_CHARSET', 'utf8') 29 | self.app.config.setdefault('MYSQL_USE_UNICODE', True) 30 | self.app.config.setdefault('MYSQL_USE_POOL', None) 31 | # Flask 0.9 or later 32 | if hasattr(app, 'teardown_appcontext'): 33 | self.app.teardown_request(self.teardown_request) 34 | # Flask 0.7 to 0.8 35 | elif hasattr(app, 'teardown_request'): 36 | self.app.teardown_request(self.teardown_request) 37 | # Older versions 38 | else: 39 | self.app.after_request(self.teardown_request) 40 | 41 | def connect(self): 42 | if self.app.config['MYSQL_DATABASE_HOST']: 43 | self.connect_args['host'] = self.app.config['MYSQL_DATABASE_HOST'] 44 | if self.app.config['MYSQL_DATABASE_PORT']: 45 | self.connect_args['port'] = self.app.config['MYSQL_DATABASE_PORT'] 46 | if self.app.config['MYSQL_DATABASE_USER']: 47 | self.connect_args['user'] = self.app.config['MYSQL_DATABASE_USER'] 48 | if self.app.config['MYSQL_DATABASE_PASSWORD']: 49 | self.connect_args['passwd'] = self.app.config['MYSQL_DATABASE_PASSWORD'] 50 | if self.app.config['MYSQL_DATABASE_DB']: 51 | self.connect_args['db'] = self.app.config['MYSQL_DATABASE_DB'] 52 | if self.app.config['MYSQL_DATABASE_CHARSET']: 53 | self.connect_args['charset'] = self.app.config['MYSQL_DATABASE_CHARSET'] 54 | if self.app.config['MYSQL_USE_UNICODE']: 55 | self.connect_args['use_unicode'] = self.app.config['MYSQL_USE_UNICODE'] 56 | if self.app.config['MYSQL_USE_POOL']: 57 | self.connect_args['pool'] = self.app.config['MYSQL_USE_POOL'] 58 | if self.app.config['MYSQL_CONSISTENT_SNAPSHOT']: 59 | self.connect_args['consistent_snapshot'] = self.app.config['MYSQL_CONSISTENT_SNAPSHOT'] 60 | if self.app.config['MYSQL_ISOLATION_LEVEL']: 61 | self.connect_args['isolation_level'] = self.app.config['MYSQL_ISOLATION_LEVEL'] 62 | if self.app.config['MYSQL_READONLY']: 63 | self.connect_args['readonly'] = self.app.config['MYSQL_READONLY'] 64 | return get_pool_conn_implicitly(self.connect_args) 65 | 66 | def teardown_request(self, exception): 67 | ctx = _ctx_stack.top 68 | if hasattr(ctx, "mysql_db"): 69 | ctx.mysql_db.close() 70 | 71 | def get_db(self): 72 | ctx = _ctx_stack.top 73 | if ctx is not None: 74 | if not hasattr(ctx, "mysql_db"): 75 | ctx.mysql_db = self.connect() 76 | return ctx.mysql_db 77 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/locales/__init__.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """Translations 25 | """ 26 | 27 | __all__ = [ 28 | 'get_client_error' 29 | ] 30 | 31 | from .. import errorcode 32 | 33 | 34 | def get_client_error(error, language='eng'): 35 | """Lookup client error 36 | 37 | This function will lookup the client error message based on the given 38 | error and return the error message. If the error was not found, 39 | None will be returned. 40 | 41 | Error can be either an integer or a string. For example: 42 | error: 2000 43 | error: CR_UNKNOWN_ERROR 44 | 45 | The language attribute can be used to retrieve a localized message, when 46 | available. 47 | 48 | Returns a string or None. 49 | """ 50 | try: 51 | tmp = __import__('mysql.connector.locales.{0}'.format(language), 52 | globals(), locals(), ['client_error']) 53 | except ImportError: 54 | raise ImportError("No localization support for language '{0}'".format( 55 | language)) 56 | client_error = tmp.client_error 57 | 58 | if isinstance(error, int): 59 | errno = error 60 | for key, value in errorcode.__dict__.items(): 61 | if value == errno: 62 | error = key 63 | break 64 | 65 | if isinstance(error, (str)): 66 | try: 67 | return getattr(client_error, error) 68 | except AttributeError: 69 | return None 70 | 71 | raise ValueError("error argument needs to be either an integer or string") 72 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/locales/eng/__init__.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """English Content 25 | """ 26 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/locales/eng/client_error.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # MySQL Connector/Python - MySQL driver written in Python. 4 | # Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. 5 | 6 | # MySQL Connector/Python is licensed under the terms of the GPLv2 7 | # , like most 8 | # MySQL Connectors. There are special exceptions to the terms and 9 | # conditions of the GPLv2 as it is applied to this software, see the 10 | # FOSS License Exception 11 | # . 12 | # 13 | # This program is free software; you can redistribute it and/or modify 14 | # it under the terms of the GNU General Public License as published by 15 | # the Free Software Foundation. 16 | # 17 | # This program is distributed in the hope that it will be useful, 18 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 | # GNU General Public License for more details. 21 | # 22 | # You should have received a copy of the GNU General Public License 23 | # along with this program; if not, write to the Free Software 24 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 25 | 26 | # This file was auto-generated. 27 | _GENERATED_ON = '2015-12-13' 28 | _MYSQL_VERSION = (5, 7, 10) 29 | 30 | # Start MySQL Error messages 31 | CR_UNKNOWN_ERROR = u"Unknown MySQL error" 32 | CR_SOCKET_CREATE_ERROR = u"Can't create UNIX socket (%s)" 33 | CR_CONNECTION_ERROR = u"Can't connect to local MySQL server through socket '%-.100s' (%s)" 34 | CR_CONN_HOST_ERROR = u"Can't connect to MySQL server on '%-.100s' (%s)" 35 | CR_IPSOCK_ERROR = u"Can't create TCP/IP socket (%s)" 36 | CR_UNKNOWN_HOST = u"Unknown MySQL server host '%-.100s' (%s)" 37 | CR_SERVER_GONE_ERROR = u"MySQL server has gone away" 38 | CR_VERSION_ERROR = u"Protocol mismatch; server version = %s, client version = %s" 39 | CR_OUT_OF_MEMORY = u"MySQL client ran out of memory" 40 | CR_WRONG_HOST_INFO = u"Wrong host info" 41 | CR_LOCALHOST_CONNECTION = u"Localhost via UNIX socket" 42 | CR_TCP_CONNECTION = u"%-.100s via TCP/IP" 43 | CR_SERVER_HANDSHAKE_ERR = u"Error in server handshake" 44 | CR_SERVER_LOST = u"Lost connection to MySQL server during query" 45 | CR_COMMANDS_OUT_OF_SYNC = u"Commands out of sync; you can't run this command now" 46 | CR_NAMEDPIPE_CONNECTION = u"Named pipe: %-.32s" 47 | CR_NAMEDPIPEWAIT_ERROR = u"Can't wait for named pipe to host: %-.64s pipe: %-.32s (%s)" 48 | CR_NAMEDPIPEOPEN_ERROR = u"Can't open named pipe to host: %-.64s pipe: %-.32s (%s)" 49 | CR_NAMEDPIPESETSTATE_ERROR = u"Can't set state of named pipe to host: %-.64s pipe: %-.32s (%s)" 50 | CR_CANT_READ_CHARSET = u"Can't initialize character set %-.32s (path: %-.100s)" 51 | CR_NET_PACKET_TOO_LARGE = u"Got packet bigger than 'max_allowed_packet' bytes" 52 | CR_EMBEDDED_CONNECTION = u"Embedded server" 53 | CR_PROBE_SLAVE_STATUS = u"Error on SHOW SLAVE STATUS:" 54 | CR_PROBE_SLAVE_HOSTS = u"Error on SHOW SLAVE HOSTS:" 55 | CR_PROBE_SLAVE_CONNECT = u"Error connecting to slave:" 56 | CR_PROBE_MASTER_CONNECT = u"Error connecting to master:" 57 | CR_SSL_CONNECTION_ERROR = u"SSL connection error: %-.100s" 58 | CR_MALFORMED_PACKET = u"Malformed packet" 59 | CR_WRONG_LICENSE = u"This client library is licensed only for use with MySQL servers having '%s' license" 60 | CR_NULL_POINTER = u"Invalid use of null pointer" 61 | CR_NO_PREPARE_STMT = u"Statement not prepared" 62 | CR_PARAMS_NOT_BOUND = u"No data supplied for parameters in prepared statement" 63 | CR_DATA_TRUNCATED = u"Data truncated" 64 | CR_NO_PARAMETERS_EXISTS = u"No parameters exist in the statement" 65 | CR_INVALID_PARAMETER_NO = u"Invalid parameter number" 66 | CR_INVALID_BUFFER_USE = u"Can't send long data for non-string/non-binary data types (parameter: %s)" 67 | CR_UNSUPPORTED_PARAM_TYPE = u"Using unsupported buffer type: %s (parameter: %s)" 68 | CR_SHARED_MEMORY_CONNECTION = u"Shared memory: %-.100s" 69 | CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR = u"Can't open shared memory; client could not create request event (%s)" 70 | CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR = u"Can't open shared memory; no answer event received from server (%s)" 71 | CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR = u"Can't open shared memory; server could not allocate file mapping (%s)" 72 | CR_SHARED_MEMORY_CONNECT_MAP_ERROR = u"Can't open shared memory; server could not get pointer to file mapping (%s)" 73 | CR_SHARED_MEMORY_FILE_MAP_ERROR = u"Can't open shared memory; client could not allocate file mapping (%s)" 74 | CR_SHARED_MEMORY_MAP_ERROR = u"Can't open shared memory; client could not get pointer to file mapping (%s)" 75 | CR_SHARED_MEMORY_EVENT_ERROR = u"Can't open shared memory; client could not create %s event (%s)" 76 | CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR = u"Can't open shared memory; no answer from server (%s)" 77 | CR_SHARED_MEMORY_CONNECT_SET_ERROR = u"Can't open shared memory; cannot send request event to server (%s)" 78 | CR_CONN_UNKNOW_PROTOCOL = u"Wrong or unknown protocol" 79 | CR_INVALID_CONN_HANDLE = u"Invalid connection handle" 80 | CR_UNUSED_1 = u"Connection using old (pre-4.1.1) authentication protocol refused (client option 'secure_auth' enabled)" 81 | CR_FETCH_CANCELED = u"Row retrieval was canceled by mysql_stmt_close() call" 82 | CR_NO_DATA = u"Attempt to read column without prior row fetch" 83 | CR_NO_STMT_METADATA = u"Prepared statement contains no metadata" 84 | CR_NO_RESULT_SET = u"Attempt to read a row while there is no result set associated with the statement" 85 | CR_NOT_IMPLEMENTED = u"This feature is not implemented yet" 86 | CR_SERVER_LOST_EXTENDED = u"Lost connection to MySQL server at '%s', system error: %s" 87 | CR_STMT_CLOSED = u"Statement closed indirectly because of a preceding %s() call" 88 | CR_NEW_STMT_METADATA = u"The number of columns in the result set differs from the number of bound buffers. You must reset the statement, rebind the result set columns, and execute the statement again" 89 | CR_ALREADY_CONNECTED = u"This handle is already connected. Use a separate handle for each connection." 90 | CR_AUTH_PLUGIN_CANNOT_LOAD = u"Authentication plugin '%s' cannot be loaded: %s" 91 | CR_DUPLICATE_CONNECTION_ATTR = u"There is an attribute with the same name already" 92 | CR_AUTH_PLUGIN_ERR = u"Authentication plugin '%s' reported error: %s" 93 | CR_INSECURE_API_ERR = u"Insecure API function call: '%s' Use instead: '%s'" 94 | # End MySQL Error messages 95 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/utils.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | 24 | """Utilities 25 | """ 26 | 27 | from __future__ import print_function 28 | 29 | __MYSQL_DEBUG__ = False 30 | 31 | import struct 32 | 33 | from .catch23 import struct_unpack 34 | 35 | 36 | def intread(buf): 37 | """Unpacks the given buffer to an integer""" 38 | try: 39 | if isinstance(buf, int): 40 | return buf 41 | length = len(buf) 42 | if length == 1: 43 | return buf[0] 44 | elif length <= 4: 45 | tmp = buf + b'\x00' * (4 - length) 46 | return struct_unpack(' 255: 61 | raise ValueError('int1store requires 0 <= i <= 255') 62 | else: 63 | return bytearray(struct.pack(' 65535: 73 | raise ValueError('int2store requires 0 <= i <= 65535') 74 | else: 75 | return bytearray(struct.pack(' 16777215: 85 | raise ValueError('int3store requires 0 <= i <= 16777215') 86 | else: 87 | return bytearray(struct.pack(' 4294967295: 97 | raise ValueError('int4store requires 0 <= i <= 4294967295') 98 | else: 99 | return bytearray(struct.pack(' 18446744073709551616: 109 | raise ValueError('int8store requires 0 <= i <= 2^64') 110 | else: 111 | return bytearray(struct.pack(' 18446744073709551616: 124 | raise ValueError('intstore requires 0 <= i <= 2^64') 125 | 126 | if i <= 255: 127 | formed_string = int1store 128 | elif i <= 65535: 129 | formed_string = int2store 130 | elif i <= 16777215: 131 | formed_string = int3store 132 | elif i <= 4294967295: 133 | formed_string = int4store 134 | else: 135 | formed_string = int8store 136 | 137 | return formed_string(i) 138 | 139 | 140 | def lc_int(i): 141 | """ 142 | Takes an unsigned integer and packs it as bytes, 143 | with the information of how much bytes the encoded int takes. 144 | """ 145 | if i < 0 or i > 18446744073709551616: 146 | raise ValueError('Requires 0 <= i <= 2^64') 147 | 148 | if i < 251: 149 | return bytearray(struct.pack(' 177 | +----------+------------------------- 178 | | length | a string goes here 179 | +----------+------------------------- 180 | 181 | If the string is bigger than 250, then it looks like this: 182 | 183 | <- 1b -><- 2/3/8 -> 184 | +------+-----------+------------------------- 185 | | type | length | a string goes here 186 | +------+-----------+------------------------- 187 | 188 | if type == \xfc: 189 | length is code in next 2 bytes 190 | elif type == \xfd: 191 | length is code in next 3 bytes 192 | elif type == \xfe: 193 | length is code in next 8 bytes 194 | 195 | NULL has a special value. If the buffer starts with \xfb then 196 | it's a NULL and we return None as value. 197 | 198 | Returns a tuple (trucated buffer, bytes). 199 | """ 200 | if buf[0] == 251: # \xfb 201 | # NULL value 202 | return (buf[1:], None) 203 | 204 | length = lsize = 0 205 | fst = buf[0] 206 | 207 | if fst <= 250: # \xFA 208 | length = fst 209 | return (buf[1 + length:], buf[1:length + 1]) 210 | elif fst == 252: 211 | lsize = 2 212 | elif fst == 253: 213 | lsize = 3 214 | if fst == 254: 215 | lsize = 8 216 | 217 | length = intread(buf[1:lsize + 1]) 218 | return (buf[lsize + length + 1:], buf[lsize + 1:length + lsize + 1]) 219 | 220 | 221 | def read_lc_string_list(buf): 222 | """Reads all length encoded strings from the given buffer 223 | 224 | Returns a list of bytes 225 | """ 226 | byteslst = [] 227 | 228 | sizes = {252: 2, 253: 3, 254: 8} 229 | 230 | buf_len = len(buf) 231 | pos = 0 232 | 233 | while pos < buf_len: 234 | first = buf[pos] 235 | if first == 255: 236 | # Special case when MySQL error 1317 is returned by MySQL. 237 | # We simply return None. 238 | return None 239 | if first == 251: 240 | # NULL value 241 | byteslst.append(None) 242 | pos += 1 243 | else: 244 | if first <= 250: 245 | length = first 246 | byteslst.append(buf[(pos + 1):length + (pos + 1)]) 247 | pos += 1 + length 248 | else: 249 | lsize = 0 250 | try: 251 | lsize = sizes[first] 252 | except KeyError: 253 | return None 254 | length = intread(buf[(pos + 1):lsize + (pos + 1)]) 255 | byteslst.append( 256 | buf[pos + 1 + lsize:length + lsize + (pos + 1)]) 257 | pos += 1 + lsize + length 258 | 259 | return tuple(byteslst) 260 | 261 | 262 | def read_string(buf, end=None, size=None): 263 | """ 264 | Reads a string up until a character or for a given size. 265 | 266 | Returns a tuple (trucated buffer, string). 267 | """ 268 | if end is None and size is None: 269 | raise ValueError('read_string() needs either end or size') 270 | 271 | if end is not None: 272 | try: 273 | idx = buf.index(end) 274 | except ValueError: 275 | raise ValueError("end byte not present in buffer") 276 | return (buf[idx + 1:], buf[0:idx]) 277 | elif size is not None: 278 | return read_bytes(buf, size) 279 | 280 | raise ValueError('read_string() needs either end or size (weird)') 281 | 282 | 283 | def read_int(buf, size): 284 | """Read an integer from buffer 285 | 286 | Returns a tuple (truncated buffer, int) 287 | """ 288 | 289 | try: 290 | res = intread(buf[0:size]) 291 | except: 292 | raise 293 | 294 | return (buf[size:], res) 295 | 296 | 297 | def read_lc_int(buf): 298 | """ 299 | Takes a buffer and reads an length code string from the start. 300 | 301 | Returns a tuple with buffer less the integer and the integer read. 302 | """ 303 | if not buf: 304 | raise ValueError("Empty buffer.") 305 | 306 | lcbyte = buf[0] 307 | if lcbyte == 251: 308 | return (buf[1:], None) 309 | elif lcbyte < 251: 310 | return (buf[1:], int(lcbyte)) 311 | elif lcbyte == 252: 312 | return (buf[3:], struct_unpack(' 0: 335 | digest = _digest_buffer(abuffer[0:limit]) 336 | else: 337 | digest = _digest_buffer(abuffer) 338 | print(prefix + ': ' + digest) 339 | else: 340 | print(_digest_buffer(abuffer)) 341 | -------------------------------------------------------------------------------- /PyMysqlPool/mysql/connector/version.py: -------------------------------------------------------------------------------- 1 | # MySQL Connector/Python - MySQL driver written in Python. 2 | # Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. 3 | 4 | # MySQL Connector/Python is licensed under the terms of the GPLv2 5 | # , like most 6 | # MySQL Connectors. There are special exceptions to the terms and 7 | # conditions of the GPLv2 as it is applied to this software, see the 8 | # FOSS License Exception 9 | # . 10 | # 11 | # This program is free software; you can redistribute it and/or modify 12 | # it under the terms of the GNU General Public License as published by 13 | # the Free Software Foundation. 14 | # 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | # 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 | """MySQL Connector/Python version information 24 | 25 | The file version.py gets installed and is available after installation 26 | as mysql.connector.version. 27 | """ 28 | 29 | VERSION = (2, 2, 2, 'b', 1) 30 | 31 | if VERSION[3] and VERSION[4]: 32 | VERSION_TEXT = '{0}.{1}.{2}{3}{4}'.format(*VERSION) 33 | else: 34 | VERSION_TEXT = '{0}.{1}.{2}'.format(*VERSION[0:3]) 35 | 36 | LICENSE = 'GPLv2 with FOSS License Exception' 37 | EDITION = '' # Added in package names, after the version 38 | -------------------------------------------------------------------------------- /PyMysqlPool/util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/PyMysqlPool/util/__init__.py -------------------------------------------------------------------------------- /PyMysqlPool/util/balancer.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # coding=utf-8 4 | import logging 5 | import sys 6 | import threading 7 | from time import sleep 8 | 9 | 10 | class RepeatedTimer(object): 11 | def __init__(self, interval, function, *args, **kwargs): 12 | self._timer = None 13 | self.interval = interval 14 | self.function = function 15 | self.args = args 16 | self.kwargs = kwargs 17 | self.is_running = False 18 | self.start() 19 | 20 | def _run(self): 21 | self.is_running = False 22 | self.start() 23 | self.function(*self.args, **self.kwargs) 24 | 25 | def start(self): 26 | if not self.is_running: 27 | self._timer = threading.Timer(self.interval, self._run) 28 | self._timer.daemon = True 29 | self._timer.start() 30 | self.is_running = True 31 | 32 | def stop(self): 33 | self._timer.cancel() 34 | self.is_running = False 35 | 36 | 37 | def hello(name): 38 | print "Hello %s!" % name 39 | 40 | 41 | if __name__ == '__main__': 42 | 43 | print "starting..." 44 | rt = RepeatedTimer(1, hello, "World") # it auto-starts, no need of rt.start() 45 | try: 46 | while (True): 47 | sleep(15) # your long-running job goes here... 48 | finally: 49 | rt.stop() # better in a try/finally block to make sure the program ends! 50 | -------------------------------------------------------------------------------- /PyMysqlPool/util/date_util.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # coding=utf-8 4 | import datetime 5 | 6 | 7 | def get_day_format(): 8 | now = datetime.datetime.now() 9 | today = now.strftime("%Y-%m-%d %H:%M:%S") 10 | return today 11 | 12 | 13 | def get_daystr_format(data): 14 | datastr = data.strftime("%Y-%m-%d %H:%M:%S") 15 | return datastr 16 | -------------------------------------------------------------------------------- /PyMysqlPool/util/log_util.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # coding=utf-8 4 | 5 | import inspect 6 | import os 7 | import sys 8 | from __builtin__ import str 9 | from datetime import datetime 10 | 11 | reload(sys) 12 | sys.setdefaultencoding('utf-8') 13 | from PyMysqlPool.util.logger import * 14 | 15 | old_f = sys.stdout 16 | 17 | 18 | class F: 19 | def write(self, x): 20 | old_f.write(x.replace("\n", " [%s]\n" % str(datetime.now()))) 21 | 22 | 23 | sys.stdout = F() 24 | 25 | 26 | def get_caller_function(): 27 | (frame, filename, line_number, function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[1] 28 | return function_name 29 | 30 | 31 | def get_caller_info_total(): 32 | frame_info = (frame, filename, line_number, function_name, lines, index) = \ 33 | inspect.getouterframes(inspect.currentframe())[0] 34 | return frame_info 35 | 36 | 37 | def get_caller_info(frames=None): 38 | if not frames: 39 | frames = len(inspect.getouterframes(inspect.currentframe())) 40 | (frame, filename, line_number, 41 | function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[frames - 1] 42 | else: 43 | (frame, filename, line_number, 44 | function_name, lines, index) = inspect.getouterframes(inspect.currentframe())[frames] 45 | print(frame, filename, line_number, function_name, lines, index) 46 | return filename 47 | 48 | 49 | # Disable 50 | def blockPrint(): 51 | sys.stdout = open(os.devnull, 'w') 52 | 53 | 54 | # Restore 55 | def enablePrint(): 56 | sys.stdout = sys.__stdout__ 57 | 58 | 59 | def disablePrint(): 60 | return open(os.devnull, 'w') 61 | 62 | 63 | def underline_print(string): 64 | under_str = "\033[4m%s\033[0m" % (str(string),) 65 | return under_str 66 | 67 | 68 | if __name__ == '__main__': 69 | logging.info('main starts...') 70 | logging.info('main stop') 71 | sys.exit(0) 72 | -------------------------------------------------------------------------------- /PyMysqlPool/util/logger.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # coding=utf-8 4 | import logging 5 | import sys 6 | 7 | logging.basicConfig(level=logging.NOTSET, 8 | format='[%(asctime)s][%(levelname)7s][%(threadName)s][%(filename)s:%(funcName)s:%(lineno)d] %(message)s', 9 | datefmt='%Y-%m-%d %H:%M:%S', 10 | stream=sys.stdout) 11 | # create logger 12 | logger = logging.getLogger('my-logger') 13 | logger.setLevel(logging.INFO) 14 | # create console handler and set level to debug 15 | ch = logging.StreamHandler(stream=sys.stdout) 16 | ch.setLevel(logging.INFO) 17 | # add ch to logger 18 | logger.addHandler(ch) 19 | # disable all 20 | # logger.propagate = False 21 | -------------------------------------------------------------------------------- /PyMysqlPool/util/logger_err.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # coding=utf-8 4 | import logging 5 | import sys 6 | 7 | from PyMysqlPool.constant.constant import loggingerr, loggErrorFile 8 | 9 | logging.basicConfig(level=logging.NOTSET, 10 | format='[%(asctime)s][%(levelname)7s][%(threadName)s][%(filename)s:%(funcName)s:%(lineno)d] %(message)s', 11 | datefmt='%Y-%m-%d %H:%M:%S', 12 | stream=sys.stdout) 13 | 14 | logFormatter = logging.Formatter( 15 | '[%(asctime)s][%(levelname)7s][%(threadName)s][%(filename)s:%(funcName)s:%(lineno)d] %(message)s') 16 | rootLogger = logging.getLogger(__name__) 17 | rootLogger.setLevel(logging.ERROR) 18 | 19 | 20 | # create console handler and set level to debug 21 | ch = logging.StreamHandler(stream=sys.stderr) 22 | ch.setLevel(logging.ERROR) 23 | # add ch to logger 24 | rootLogger.addHandler(ch) 25 | if loggErrorFile: 26 | fileHandler = logging.FileHandler("{0}".format(loggingerr)) 27 | fileHandler.setFormatter(logFormatter) 28 | rootLogger.addHandler(fileHandler) 29 | 30 | consoleHandler = logging.StreamHandler() 31 | consoleHandler.setFormatter(logFormatter) 32 | rootLogger.addHandler(consoleHandler) 33 | -------------------------------------------------------------------------------- /PyMysqlPool/util/py_net_util.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # coding=utf-8 4 | import socket 5 | 6 | 7 | def get_ip_address(): 8 | print socket.gethostbyname(socket.gethostname()) 9 | return socket.gethostbyname(socket.gethostname()) 10 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | PyMysqlPool 2 | ================== 3 | 4 | .. image:: https://api.travis-ci.org/LuciferJack/python-mysql-pool.svg?branch=master 5 | :target: https://travis-ci.org/LuciferJack/python-mysql-pool 6 | .. image:: https://img.shields.io/badge/license-MIT-blue.svg 7 | :target: https://github.com/LuciferJack/python-mysql-pool/blob/master/LICENSE.txt 8 | 9 | .. contents:: Table of Contents 10 | 11 | Desc 12 | ------------- 13 | python practical mysql pool desc: 14 | This package contains a pure-python mysql connector library. The goal of PyMysqlPool 15 | is to be a mysql pool and motivation from=>[lost connection to MySQL server during query] base on mysql-connector . 16 | 17 | feature 18 | * easy to use. 19 | * support 【no、fixed 、dynamic pool】. 20 | * manage 【fail/lost connection】. 21 | * support 【no、fixed 、dynamic pool】=>Django framework. 22 | * support 【no、fixed 、dynamic pool】=>Flask framework. 23 | 24 | Requirements 25 | ------------- 26 | * Python lib -- one of the following: 27 | MySQLdb 28 | * Python -- one of the following: 29 | success test in python >=2.7 30 | * MySQL Server -- one of the following: 31 | MySQL >= 5.5 (success test with >=5.5~) 32 | 33 | 34 | Installation 35 | ------------ 36 | 37 | The last stable release is available on PyPI and can be installed with ``pip``:: 38 | 39 | $ pip install PyMysqlPool 40 | 41 | You can installed with ``easy_install``:: 42 | 43 | $ easy_install PyMysqlPool 44 | 45 | You can installed with ``manually``:: 46 | 47 | $ git clone https://github.com/LuciferJack/python-mysql-pool.git or download ***.tar.gz 48 | 49 | $ cd PyMysqlPool-*** 50 | 51 | $ python setup.py install 52 | 53 | Documentation 54 | ------------- 55 | 56 | Documentation is available online: http://PyMysqlPool.readthedocs.io/ 57 | 58 | For support, please refer to the `StackOverflow 59 | `_. 60 | 61 | Example 62 | ------- 63 | 64 | .. _prototype: 65 | 66 | The following prototype_ pool examples below: 67 | 68 | 69 | .. code:: python 70 | 71 | step:1 72 | 73 | """ 74 | file: new a mysql_config.py file and change to your db config 75 | """ 76 | db_config = { 77 | 'local': { 78 | 'host': "10.95.130.***", 'port': 8899, 79 | 'user': "root", 'passwd': "****", 80 | 'db': "marry", 'charset': "utf8", 81 | 'isolation_level': 'READ COMMITTED', 82 | 'pool': { 83 | #use = 0 no pool else use pool 84 | "use":1, 85 | # size is >=0, 0 is dynamic pool 86 | "size":0, 87 | #pool name 88 | "name":"local", 89 | } 90 | }, 91 | 'poi': { 92 | 'host': "10.95.130.***", 'port': 8787, 93 | 'user': "lujunxu", 'passwd': "****", 94 | 'db': "poi_relation", 'charset': "utf8", 95 | 'pool': { 96 | #use = 0 no pool else use pool 97 | "use":0, 98 | # size is >=0, 0 is dynamic pool 99 | "size":0, 100 | #pool name 101 | "name":"poi", 102 | } 103 | }, 104 | } 105 | 106 | step:2 107 | 108 | """ 109 | Note:create your own table 110 | """ 111 | 112 | step:3 (example show below) 113 | 114 | from PyMysqlPool.db_util.mysql_util import query,query_single,insertOrUpdate, 115 | 116 | """ 117 | pool size special operation 118 | """ 119 | def query_pool_size(): 120 | job_status = 2 121 | _sql = "select * from master_job_list j where j.job_status in (%s) " 122 | _args = (job_status,) 123 | task = query(db_config['local'], _sql,_args) 124 | logging.info("query_npool method query_npool result is %s ,input _data is %s ", task , _args) 125 | return 126 | 127 | """ 128 | single query 129 | """ 130 | def query_npool(): 131 | job_status = 2 132 | _sql = "select * from master_job_list j where j.job_status !=%s " 133 | _args = (job_status,) 134 | task = query_single(db_config['local'], _sql,_args) 135 | logging.info("query_npool method query_npool result is %s ,input _data is %s ", task , _args) 136 | return 137 | 138 | """ 139 | insert 140 | """ 141 | def insert(nlp_rank_id,hit_query_word): 142 | #add more args 143 | _args = (nlp_rank_id,hit_query_word) 144 | _sql = """INSERT INTO nlp_rank_poi_online (nlp_rank_id,hit_query_word,rank_type,poi_list,poi_raw_list,article_id,city_id,status,create_time,version,source_from) VALUES (%s,%s,%s, %s, %s,%s, %s,%s, %s,%s,%s)""" 145 | affect = insertOrUpdate(db_config['local'], _sql, _args) 146 | logging.info("insert method insert result is %s ,input _data is %s ", affect , _args) 147 | return 148 | 149 | """ 150 | update 151 | """ 152 | def update(query_word,query_id): 153 | _args = (query_word,query_id) 154 | _sql = """update nlp_rank set query_word = %s WHERE id = %s""" 155 | affect = insertOrUpdate(db_config['local'], _sql, _args) 156 | logging.info("update method update result is %s ,input _data is %s ", affect , _args) 157 | return 158 | 159 | 160 | 161 | 162 | .. code:: python 163 | 164 | Django use example: 165 | 166 | """ 167 | file:settings.py 168 | change to your db config 169 | """ 170 | DATABASES = { 171 | 'default': { 172 | 'ENGINE': 'PyMysqlPool.mysql.connector.django', 173 | 'NAME': 'django', 174 | 'USER': 'root', 175 | 'PASSWORD': '*******', 176 | 'HOST': '10.95.130.***', 177 | 'PORT': '8899', 178 | 'OPTIONS': { 179 | 'isolation_level': 'READ COMMITTED', 180 | 'autocommit': True, 181 | 'pool': { 182 | #use = 0 no pool else use pool 183 | "use":1, 184 | # size is >=0, 0 is dynamic pool 185 | "size":0, 186 | #pool name 187 | "name":"local", 188 | } 189 | }, 190 | } 191 | } 192 | 193 | .. code:: python 194 | 195 | Flask use example: 196 | 197 | """ 198 | change to your db config 199 | """ 200 | from PyMysqlPool.mysql.connector.flask.mysql import MySQL 201 | 202 | app = Flask(__name__,template_folder='flaskPoolShowcase/flask_templates') 203 | #mysql config 204 | app.config.update( 205 | DEBUG=False, 206 | MYSQL_DATABASE_HOST='10.95.130.***', 207 | MYSQL_DATABASE_PORT=8899, 208 | MYSQL_DATABASE_USER='root', 209 | MYSQL_DATABASE_PASSWORD='******', 210 | MYSQL_DATABASE_DB='flask', 211 | MYSQL_ISOLATION_LEVEL='READ COMMITTED', 212 | MYSQL_USE_POOL= 213 | { 214 | #use = 0 no pool else use pool 215 | "use":0, 216 | # size is >=0, 0 is dynamic pool 217 | "size":10, 218 | #pool name 219 | "name":"local", 220 | }, 221 | ) 222 | mysql = MySQL() 223 | mysql.init_app(app) 224 | 225 | 226 | 227 | or use the connection type like prototype_ method. 228 | 229 | Resources 230 | --------- 231 | 232 | python mysql connector: https://dev.mysql.com/downloads/connector/python/ 233 | 234 | MySQL Reference Manuals: http://dev.mysql.com/doc/ 235 | 236 | MySQL client/server protocol: 237 | http://dev.mysql.com/doc/internals/en/client-server-protocol.html 238 | 239 | PyMysqlPool mailing list: https://groups.google.com/forum/#!forum/PyMysqlPool-users 240 | 241 | License 242 | ------- 243 | PyMysqlPool is released under the MIT License. See LICENSE for more information. 244 | 245 | Plan 246 | ------- 247 | | Dynamic Load Optimization. 248 | | Minimum number of connections to maximum performance. 249 | 250 | Scope 251 | ------- 252 | | Now use in **BaiDu** off-line calculation module. 253 | | Like this project, welcome to use and to enhance together. 254 | 255 | Frequency Ask 256 | ------------- 257 | * Django support -- test on one of the following: 258 | Django 1.11.5 259 | show case: https://github.com/LuciferJack/Django-pool-showcase 260 | * Flask support -- test on one of the following: 261 | Flask 0.12.2 262 | show case: https://github.com/LuciferJack/Flask-pool-showcase 263 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = python -msphinx 7 | SPHINXPROJ = PyMysqlPool 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/build/doctrees/environment.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/docs/build/doctrees/environment.pickle -------------------------------------------------------------------------------- /docs/build/doctrees/index.doctree: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/docs/build/doctrees/index.doctree -------------------------------------------------------------------------------- /docs/build/html/.buildinfo: -------------------------------------------------------------------------------- 1 | # Sphinx build info version 1 2 | # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. 3 | config: f4de14c5e1fd327fa731c4eac7c625e6 4 | tags: 645f666f9bcd5a90fca523b33c5a78b7 5 | -------------------------------------------------------------------------------- /docs/build/html/_sources/index.rst.txt: -------------------------------------------------------------------------------- 1 | .. PyMysqlPool documentation master file, created by 2 | sphinx-quickstart on Wed Aug 23 16:56:20 2017. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to PyMysqlPool's documentation! 7 | ======================================= 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | 14 | 15 | Indices and tables 16 | ================== 17 | 18 | * :ref:`genindex` 19 | * :ref:`modindex` 20 | * :ref:`search` 21 | -------------------------------------------------------------------------------- /docs/build/html/_static/ajax-loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/docs/build/html/_static/ajax-loader.gif -------------------------------------------------------------------------------- /docs/build/html/_static/comment-bright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/docs/build/html/_static/comment-bright.png -------------------------------------------------------------------------------- /docs/build/html/_static/comment-close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/docs/build/html/_static/comment-close.png -------------------------------------------------------------------------------- /docs/build/html/_static/comment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/docs/build/html/_static/comment.png -------------------------------------------------------------------------------- /docs/build/html/_static/custom.css: -------------------------------------------------------------------------------- 1 | /* This file intentionally left blank. */ 2 | -------------------------------------------------------------------------------- /docs/build/html/_static/doctools.js: -------------------------------------------------------------------------------- 1 | /* 2 | * doctools.js 3 | * ~~~~~~~~~~~ 4 | * 5 | * Sphinx JavaScript utilities for all documentation. 6 | * 7 | * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS. 8 | * :license: BSD, see LICENSE for details. 9 | * 10 | */ 11 | 12 | /** 13 | * select a different prefix for underscore 14 | */ 15 | $u = _.noConflict(); 16 | 17 | /** 18 | * make the code below compatible with browsers without 19 | * an installed firebug like debugger 20 | if (!window.console || !console.firebug) { 21 | var names = ["log", "debug", "info", "warn", "error", "assert", "dir", 22 | "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", 23 | "profile", "profileEnd"]; 24 | window.console = {}; 25 | for (var i = 0; i < names.length; ++i) 26 | window.console[names[i]] = function() {}; 27 | } 28 | */ 29 | 30 | /** 31 | * small helper function to urldecode strings 32 | */ 33 | jQuery.urldecode = function(x) { 34 | return decodeURIComponent(x).replace(/\+/g, ' '); 35 | }; 36 | 37 | /** 38 | * small helper function to urlencode strings 39 | */ 40 | jQuery.urlencode = encodeURIComponent; 41 | 42 | /** 43 | * This function returns the parsed url parameters of the 44 | * current request. Multiple values per key are supported, 45 | * it will always return arrays of strings for the value parts. 46 | */ 47 | jQuery.getQueryParameters = function(s) { 48 | if (typeof s == 'undefined') 49 | s = document.location.search; 50 | var parts = s.substr(s.indexOf('?') + 1).split('&'); 51 | var result = {}; 52 | for (var i = 0; i < parts.length; i++) { 53 | var tmp = parts[i].split('=', 2); 54 | var key = jQuery.urldecode(tmp[0]); 55 | var value = jQuery.urldecode(tmp[1]); 56 | if (key in result) 57 | result[key].push(value); 58 | else 59 | result[key] = [value]; 60 | } 61 | return result; 62 | }; 63 | 64 | /** 65 | * highlight a given string on a jquery object by wrapping it in 66 | * span elements with the given class name. 67 | */ 68 | jQuery.fn.highlightText = function(text, className) { 69 | function highlight(node) { 70 | if (node.nodeType == 3) { 71 | var val = node.nodeValue; 72 | var pos = val.toLowerCase().indexOf(text); 73 | if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { 74 | var span = document.createElement("span"); 75 | span.className = className; 76 | span.appendChild(document.createTextNode(val.substr(pos, text.length))); 77 | node.parentNode.insertBefore(span, node.parentNode.insertBefore( 78 | document.createTextNode(val.substr(pos + text.length)), 79 | node.nextSibling)); 80 | node.nodeValue = val.substr(0, pos); 81 | } 82 | } 83 | else if (!jQuery(node).is("button, select, textarea")) { 84 | jQuery.each(node.childNodes, function() { 85 | highlight(this); 86 | }); 87 | } 88 | } 89 | return this.each(function() { 90 | highlight(this); 91 | }); 92 | }; 93 | 94 | /* 95 | * backward compatibility for jQuery.browser 96 | * This will be supported until firefox bug is fixed. 97 | */ 98 | if (!jQuery.browser) { 99 | jQuery.uaMatch = function(ua) { 100 | ua = ua.toLowerCase(); 101 | 102 | var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || 103 | /(webkit)[ \/]([\w.]+)/.exec(ua) || 104 | /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || 105 | /(msie) ([\w.]+)/.exec(ua) || 106 | ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || 107 | []; 108 | 109 | return { 110 | browser: match[ 1 ] || "", 111 | version: match[ 2 ] || "0" 112 | }; 113 | }; 114 | jQuery.browser = {}; 115 | jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; 116 | } 117 | 118 | /** 119 | * Small JavaScript module for the documentation. 120 | */ 121 | var Documentation = { 122 | 123 | init : function() { 124 | this.fixFirefoxAnchorBug(); 125 | this.highlightSearchWords(); 126 | this.initIndexTable(); 127 | 128 | }, 129 | 130 | /** 131 | * i18n support 132 | */ 133 | TRANSLATIONS : {}, 134 | PLURAL_EXPR : function(n) { return n == 1 ? 0 : 1; }, 135 | LOCALE : 'unknown', 136 | 137 | // gettext and ngettext don't access this so that the functions 138 | // can safely bound to a different name (_ = Documentation.gettext) 139 | gettext : function(string) { 140 | var translated = Documentation.TRANSLATIONS[string]; 141 | if (typeof translated == 'undefined') 142 | return string; 143 | return (typeof translated == 'string') ? translated : translated[0]; 144 | }, 145 | 146 | ngettext : function(singular, plural, n) { 147 | var translated = Documentation.TRANSLATIONS[singular]; 148 | if (typeof translated == 'undefined') 149 | return (n == 1) ? singular : plural; 150 | return translated[Documentation.PLURALEXPR(n)]; 151 | }, 152 | 153 | addTranslations : function(catalog) { 154 | for (var key in catalog.messages) 155 | this.TRANSLATIONS[key] = catalog.messages[key]; 156 | this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); 157 | this.LOCALE = catalog.locale; 158 | }, 159 | 160 | /** 161 | * add context elements like header anchor links 162 | */ 163 | addContextElements : function() { 164 | $('div[id] > :header:first').each(function() { 165 | $('\u00B6'). 166 | attr('href', '#' + this.id). 167 | attr('title', _('Permalink to this headline')). 168 | appendTo(this); 169 | }); 170 | $('dt[id]').each(function() { 171 | $('\u00B6'). 172 | attr('href', '#' + this.id). 173 | attr('title', _('Permalink to this definition')). 174 | appendTo(this); 175 | }); 176 | }, 177 | 178 | /** 179 | * workaround a firefox stupidity 180 | * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 181 | */ 182 | fixFirefoxAnchorBug : function() { 183 | if (document.location.hash) 184 | window.setTimeout(function() { 185 | document.location.href += ''; 186 | }, 10); 187 | }, 188 | 189 | /** 190 | * highlight the search words provided in the url in the text 191 | */ 192 | highlightSearchWords : function() { 193 | var params = $.getQueryParameters(); 194 | var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; 195 | if (terms.length) { 196 | var body = $('div.body'); 197 | if (!body.length) { 198 | body = $('body'); 199 | } 200 | window.setTimeout(function() { 201 | $.each(terms, function() { 202 | body.highlightText(this.toLowerCase(), 'highlighted'); 203 | }); 204 | }, 10); 205 | $('') 207 | .appendTo($('#searchbox')); 208 | } 209 | }, 210 | 211 | /** 212 | * init the domain index toggle buttons 213 | */ 214 | initIndexTable : function() { 215 | var togglers = $('img.toggler').click(function() { 216 | var src = $(this).attr('src'); 217 | var idnum = $(this).attr('id').substr(7); 218 | $('tr.cg-' + idnum).toggle(); 219 | if (src.substr(-9) == 'minus.png') 220 | $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); 221 | else 222 | $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); 223 | }).css('display', ''); 224 | if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { 225 | togglers.click(); 226 | } 227 | }, 228 | 229 | /** 230 | * helper function to hide the search marks again 231 | */ 232 | hideSearchWords : function() { 233 | $('#searchbox .highlight-link').fadeOut(300); 234 | $('span.highlighted').removeClass('highlighted'); 235 | }, 236 | 237 | /** 238 | * make the url absolute 239 | */ 240 | makeURL : function(relativeURL) { 241 | return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; 242 | }, 243 | 244 | /** 245 | * get the current relative url 246 | */ 247 | getCurrentURL : function() { 248 | var path = document.location.pathname; 249 | var parts = path.split(/\//); 250 | $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { 251 | if (this == '..') 252 | parts.pop(); 253 | }); 254 | var url = parts.join('/'); 255 | return path.substring(url.lastIndexOf('/') + 1, path.length - 1); 256 | }, 257 | 258 | initOnKeyListeners: function() { 259 | $(document).keyup(function(event) { 260 | var activeElementType = document.activeElement.tagName; 261 | // don't navigate when in search box or textarea 262 | if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT') { 263 | switch (event.keyCode) { 264 | case 37: // left 265 | var prevHref = $('link[rel="prev"]').prop('href'); 266 | if (prevHref) { 267 | window.location.href = prevHref; 268 | return false; 269 | } 270 | case 39: // right 271 | var nextHref = $('link[rel="next"]').prop('href'); 272 | if (nextHref) { 273 | window.location.href = nextHref; 274 | return false; 275 | } 276 | } 277 | } 278 | }); 279 | } 280 | }; 281 | 282 | // quick alias for translations 283 | _ = Documentation.gettext; 284 | 285 | $(document).ready(function() { 286 | Documentation.init(); 287 | }); -------------------------------------------------------------------------------- /docs/build/html/_static/down-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/docs/build/html/_static/down-pressed.png -------------------------------------------------------------------------------- /docs/build/html/_static/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/docs/build/html/_static/down.png -------------------------------------------------------------------------------- /docs/build/html/_static/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/docs/build/html/_static/file.png -------------------------------------------------------------------------------- /docs/build/html/_static/minus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/docs/build/html/_static/minus.png -------------------------------------------------------------------------------- /docs/build/html/_static/plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/docs/build/html/_static/plus.png -------------------------------------------------------------------------------- /docs/build/html/_static/pygments.css: -------------------------------------------------------------------------------- 1 | .highlight .hll { background-color: #ffffcc } 2 | .highlight { background: #eeffcc; } 3 | .highlight .c { color: #408090; font-style: italic } /* Comment */ 4 | .highlight .err { border: 1px solid #FF0000 } /* Error */ 5 | .highlight .k { color: #007020; font-weight: bold } /* Keyword */ 6 | .highlight .o { color: #666666 } /* Operator */ 7 | .highlight .ch { color: #408090; font-style: italic } /* Comment.Hashbang */ 8 | .highlight .cm { color: #408090; font-style: italic } /* Comment.Multiline */ 9 | .highlight .cp { color: #007020 } /* Comment.Preproc */ 10 | .highlight .cpf { color: #408090; font-style: italic } /* Comment.PreprocFile */ 11 | .highlight .c1 { color: #408090; font-style: italic } /* Comment.Single */ 12 | .highlight .cs { color: #408090; background-color: #fff0f0 } /* Comment.Special */ 13 | .highlight .gd { color: #A00000 } /* Generic.Deleted */ 14 | .highlight .ge { font-style: italic } /* Generic.Emph */ 15 | .highlight .gr { color: #FF0000 } /* Generic.Error */ 16 | .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ 17 | .highlight .gi { color: #00A000 } /* Generic.Inserted */ 18 | .highlight .go { color: #333333 } /* Generic.Output */ 19 | .highlight .gp { color: #c65d09; font-weight: bold } /* Generic.Prompt */ 20 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 21 | .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ 22 | .highlight .gt { color: #0044DD } /* Generic.Traceback */ 23 | .highlight .kc { color: #007020; font-weight: bold } /* Keyword.Constant */ 24 | .highlight .kd { color: #007020; font-weight: bold } /* Keyword.Declaration */ 25 | .highlight .kn { color: #007020; font-weight: bold } /* Keyword.Namespace */ 26 | .highlight .kp { color: #007020 } /* Keyword.Pseudo */ 27 | .highlight .kr { color: #007020; font-weight: bold } /* Keyword.Reserved */ 28 | .highlight .kt { color: #902000 } /* Keyword.Type */ 29 | .highlight .m { color: #208050 } /* Literal.Number */ 30 | .highlight .s { color: #4070a0 } /* Literal.String */ 31 | .highlight .na { color: #4070a0 } /* Name.Attribute */ 32 | .highlight .nb { color: #007020 } /* Name.Builtin */ 33 | .highlight .nc { color: #0e84b5; font-weight: bold } /* Name.Class */ 34 | .highlight .no { color: #60add5 } /* Name.Constant */ 35 | .highlight .nd { color: #555555; font-weight: bold } /* Name.Decorator */ 36 | .highlight .ni { color: #d55537; font-weight: bold } /* Name.Entity */ 37 | .highlight .ne { color: #007020 } /* Name.Exception */ 38 | .highlight .nf { color: #06287e } /* Name.Function */ 39 | .highlight .nl { color: #002070; font-weight: bold } /* Name.Label */ 40 | .highlight .nn { color: #0e84b5; font-weight: bold } /* Name.Namespace */ 41 | .highlight .nt { color: #062873; font-weight: bold } /* Name.Tag */ 42 | .highlight .nv { color: #bb60d5 } /* Name.Variable */ 43 | .highlight .ow { color: #007020; font-weight: bold } /* Operator.Word */ 44 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 45 | .highlight .mb { color: #208050 } /* Literal.Number.Bin */ 46 | .highlight .mf { color: #208050 } /* Literal.Number.Float */ 47 | .highlight .mh { color: #208050 } /* Literal.Number.Hex */ 48 | .highlight .mi { color: #208050 } /* Literal.Number.Integer */ 49 | .highlight .mo { color: #208050 } /* Literal.Number.Oct */ 50 | .highlight .sa { color: #4070a0 } /* Literal.String.Affix */ 51 | .highlight .sb { color: #4070a0 } /* Literal.String.Backtick */ 52 | .highlight .sc { color: #4070a0 } /* Literal.String.Char */ 53 | .highlight .dl { color: #4070a0 } /* Literal.String.Delimiter */ 54 | .highlight .sd { color: #4070a0; font-style: italic } /* Literal.String.Doc */ 55 | .highlight .s2 { color: #4070a0 } /* Literal.String.Double */ 56 | .highlight .se { color: #4070a0; font-weight: bold } /* Literal.String.Escape */ 57 | .highlight .sh { color: #4070a0 } /* Literal.String.Heredoc */ 58 | .highlight .si { color: #70a0d0; font-style: italic } /* Literal.String.Interpol */ 59 | .highlight .sx { color: #c65d09 } /* Literal.String.Other */ 60 | .highlight .sr { color: #235388 } /* Literal.String.Regex */ 61 | .highlight .s1 { color: #4070a0 } /* Literal.String.Single */ 62 | .highlight .ss { color: #517918 } /* Literal.String.Symbol */ 63 | .highlight .bp { color: #007020 } /* Name.Builtin.Pseudo */ 64 | .highlight .fm { color: #06287e } /* Name.Function.Magic */ 65 | .highlight .vc { color: #bb60d5 } /* Name.Variable.Class */ 66 | .highlight .vg { color: #bb60d5 } /* Name.Variable.Global */ 67 | .highlight .vi { color: #bb60d5 } /* Name.Variable.Instance */ 68 | .highlight .vm { color: #bb60d5 } /* Name.Variable.Magic */ 69 | .highlight .il { color: #208050 } /* Literal.Number.Integer.Long */ -------------------------------------------------------------------------------- /docs/build/html/_static/underscore.js: -------------------------------------------------------------------------------- 1 | // Underscore.js 1.3.1 2 | // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. 3 | // Underscore is freely distributable under the MIT license. 4 | // Portions of Underscore are inspired or borrowed from Prototype, 5 | // Oliver Steele's Functional, and John Resig's Micro-Templating. 6 | // For all details and documentation: 7 | // http://documentcloud.github.com/underscore 8 | (function(){function q(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source== 9 | c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&q(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(b.has(a,h)&&(f++,!(g=b.has(c,h)&&q(a[h],c[h],d))))break;if(g){for(h in c)if(b.has(c, 10 | h)&&!f--)break;g=!f}}d.pop();return g}var r=this,G=r._,n={},k=Array.prototype,o=Object.prototype,i=k.slice,H=k.unshift,l=o.toString,I=o.hasOwnProperty,w=k.forEach,x=k.map,y=k.reduce,z=k.reduceRight,A=k.filter,B=k.every,C=k.some,p=k.indexOf,D=k.lastIndexOf,o=Array.isArray,J=Object.keys,s=Function.prototype.bind,b=function(a){return new m(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else r._=b;b.VERSION="1.3.1";var j=b.each= 11 | b.forEach=function(a,c,d){if(a!=null)if(w&&a.forEach===w)a.forEach(c,d);else if(a.length===+a.length)for(var e=0,f=a.length;e2;a== 12 | null&&(a=[]);if(y&&a.reduce===y)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(z&&a.reduceRight===z)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g,c,d,e):b.reduce(g,c)};b.find=b.detect= 13 | function(a,c,b){var e;E(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(A&&a.filter===A)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(B&&a.every===B)return a.every(c,b);j(a,function(a,g,h){if(!(e= 14 | e&&c.call(b,a,g,h)))return n});return e};var E=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(C&&a.some===C)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return n});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return p&&a.indexOf===p?a.indexOf(c)!=-1:b=E(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(b.isFunction(c)?c||a:a[c]).apply(a,d)})};b.pluck= 15 | function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;bd?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex=function(a, 17 | c,d){d||(d=b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}}; 24 | b.after=function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=J||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var c=[],d;for(d in a)b.has(a,d)&&(c[c.length]=d);return c};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)a[d]=b[d]});return a};b.defaults=function(a){j(i.call(arguments, 25 | 1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return q(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(b.has(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=o||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a===Object(a)}; 26 | b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!b.has(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)=="[object Date]"}; 27 | b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.has=function(a,b){return I.call(a,b)};b.noConflict=function(){r._=G;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a), 28 | function(c){K(c,b[c]=a[c])})};var L=0;b.uniqueId=function(a){var b=L++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var t=/.^/,u=function(a){return a.replace(/\\\\/g,"\\").replace(/\\'/g,"'")};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape||t,function(a,b){return"',_.escape("+ 29 | u(b)+"),'"}).replace(d.interpolate||t,function(a,b){return"',"+u(b)+",'"}).replace(d.evaluate||t,function(a,b){return"');"+u(b).replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};b.chain=function(a){return b(a).chain()};var m=function(a){this._wrapped=a};b.prototype=m.prototype;var v=function(a,c){return c?b(a).chain():a},K=function(a,c){m.prototype[a]= 30 | function(){var a=i.call(arguments);H.call(a,this._wrapped);return v(c.apply(b,a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];m.prototype[a]=function(){var d=this._wrapped;b.apply(d,arguments);var e=d.length;(a=="shift"||a=="splice")&&e===0&&delete d[0];return v(d,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];m.prototype[a]=function(){return v(b.apply(this._wrapped,arguments),this._chain)}});m.prototype.chain=function(){this._chain= 31 | true;return this};m.prototype.value=function(){return this._wrapped}}).call(this); 32 | -------------------------------------------------------------------------------- /docs/build/html/_static/up-pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/docs/build/html/_static/up-pressed.png -------------------------------------------------------------------------------- /docs/build/html/_static/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/docs/build/html/_static/up.png -------------------------------------------------------------------------------- /docs/build/html/genindex.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 8 | 9 | Index — PyMysqlPool 0.5 documentation 10 | 11 | 12 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 |
38 |
39 |
40 |
41 | 42 | 43 |

Index

44 | 45 |
46 | 47 |
48 | 49 | 50 |
51 |
52 |
53 | 85 |
86 |
87 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /docs/build/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | Welcome to PyMysqlPool’s documentation! — PyMysqlPool 0.5 documentation 9 | 10 | 11 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 |
37 |
38 |
39 |
40 | 41 |
42 |

Welcome to PyMysqlPool’s documentation!

43 |
44 |
45 |
46 |
47 |

Indices and tables

48 | 53 |
54 | 55 | 56 |
57 |
58 |
59 | 91 |
92 |
93 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /docs/build/html/objects.inv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LuciferJack/python-mysql-pool/7b812c6fc7f04255620cb86f272a2d8900c2240d/docs/build/html/objects.inv -------------------------------------------------------------------------------- /docs/build/html/search.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | Search — PyMysqlPool 0.5 documentation 9 | 10 | 11 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
45 |
46 |
47 |
48 | 49 |

Search

50 |
51 | 52 |

53 | Please activate JavaScript to enable the search 54 | functionality. 55 |

56 |
57 |

58 | From here you can search these documents. Enter your search 59 | words into the box below and click "search". Note that the search 60 | function will automatically search for all of the words. Pages 61 | containing fewer words won't appear in the result list. 62 |

63 |
64 | 65 | 66 | 67 |
68 | 69 |
70 | 71 |
72 | 73 |
74 |
75 |
76 | 98 |
99 |
100 | 108 | 109 | 110 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /docs/build/html/searchindex.js: -------------------------------------------------------------------------------- 1 | Search.setIndex({docnames:["index"],envversion:52,filenames:["index.rst"],objects:{},objnames:{},objtypes:{},terms:{index:0,modul:0,page:0,search:0},titles:["Welcome to PyMysqlPool\u2019s documentation!"],titleterms:{document:0,indic:0,pymysqlpool:0,tabl:0,welcom:0}}) -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=python -msphinx 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | set SPHINXPROJ=PyMysqlPool 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The Sphinx module was not found. Make sure you have Sphinx installed, 20 | echo.then set the SPHINXBUILD environment variable to point to the full 21 | echo.path of the 'sphinx-build' executable. Alternatively you may add the 22 | echo.Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # PyMysqlPool documentation build configuration file, created by 4 | # sphinx-quickstart on Wed Aug 23 16:56:20 2017. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | # If extensions (or modules to document with autodoc) are in another directory, 16 | # add these directories to sys.path here. If the directory is relative to the 17 | # documentation root, use os.path.abspath to make it absolute, like shown here. 18 | # 19 | # import os 20 | # import sys 21 | # sys.path.insert(0, os.path.abspath('.')) 22 | 23 | 24 | # -- General configuration ------------------------------------------------ 25 | 26 | # If your documentation needs a minimal Sphinx version, state it here. 27 | # 28 | # needs_sphinx = '1.0' 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = [] 34 | 35 | # Add any paths that contain templates here, relative to this directory. 36 | templates_path = ['_templates'] 37 | 38 | # The suffix(es) of source filenames. 39 | # You can specify multiple suffix as a list of string: 40 | # 41 | # source_suffix = ['.rst', '.md'] 42 | source_suffix = '.rst' 43 | 44 | # The master toctree document. 45 | master_doc = 'index' 46 | 47 | # General information about the project. 48 | project = u'PyMysqlPool' 49 | copyright = u'2017, Lucifer Jack' 50 | author = u'Lucifer Jack' 51 | 52 | # The version info for the project you're documenting, acts as replacement for 53 | # |version| and |release|, also used in various other places throughout the 54 | # built documents. 55 | # 56 | # The short X.Y version. 57 | version = u'0.5' 58 | # The full version, including alpha/beta/rc tags. 59 | release = u'0.5' 60 | 61 | # The language for content autogenerated by Sphinx. Refer to documentation 62 | # for a list of supported languages. 63 | # 64 | # This is also used if you do content translation via gettext catalogs. 65 | # Usually you set "language" from the command line for these cases. 66 | language = None 67 | 68 | # List of patterns, relative to source directory, that match files and 69 | # directories to ignore when looking for source files. 70 | # This patterns also effect to html_static_path and html_extra_path 71 | exclude_patterns = [] 72 | 73 | # The name of the Pygments (syntax highlighting) style to use. 74 | pygments_style = 'sphinx' 75 | 76 | # If true, `todo` and `todoList` produce output, else they produce nothing. 77 | todo_include_todos = False 78 | 79 | # -- Options for HTML output ---------------------------------------------- 80 | 81 | # The theme to use for HTML and HTML Help pages. See the documentation for 82 | # a list of builtin themes. 83 | # 84 | html_theme = 'alabaster' 85 | 86 | # Theme options are theme-specific and customize the look and feel of a theme 87 | # further. For a list of options available for each theme, see the 88 | # documentation. 89 | # 90 | # html_theme_options = {} 91 | 92 | # Add any paths that contain custom static files (such as style sheets) here, 93 | # relative to this directory. They are copied after the builtin static files, 94 | # so a file named "default.css" will overwrite the builtin "default.css". 95 | html_static_path = ['_static'] 96 | 97 | # Custom sidebar templates, must be a dictionary that maps document names 98 | # to template names. 99 | # 100 | # This is required for the alabaster theme 101 | # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars 102 | html_sidebars = { 103 | '**': [ 104 | 'about.html', 105 | 'navigation.html', 106 | 'relations.html', # needs 'show_related': True theme option to display 107 | 'searchbox.html', 108 | 'donate.html', 109 | ] 110 | } 111 | 112 | # -- Options for HTMLHelp output ------------------------------------------ 113 | 114 | # Output file base name for HTML help builder. 115 | htmlhelp_basename = 'PyMysqlPooldoc' 116 | 117 | # -- Options for LaTeX output --------------------------------------------- 118 | 119 | latex_elements = { 120 | # The paper size ('letterpaper' or 'a4paper'). 121 | # 122 | # 'papersize': 'letterpaper', 123 | 124 | # The font size ('10pt', '11pt' or '12pt'). 125 | # 126 | # 'pointsize': '10pt', 127 | 128 | # Additional stuff for the LaTeX preamble. 129 | # 130 | # 'preamble': '', 131 | 132 | # Latex figure (float) alignment 133 | # 134 | # 'figure_align': 'htbp', 135 | } 136 | 137 | # Grouping the document tree into LaTeX files. List of tuples 138 | # (source start file, target name, title, 139 | # author, documentclass [howto, manual, or own class]). 140 | latex_documents = [ 141 | (master_doc, 'PyMysqlPool.tex', u'PyMysqlPool Documentation', 142 | u'Lucifer Jack', 'manual'), 143 | ] 144 | 145 | # -- Options for manual page output --------------------------------------- 146 | 147 | # One entry per manual page. List of tuples 148 | # (source start file, name, description, authors, manual section). 149 | man_pages = [ 150 | (master_doc, 'pymysqlpool', u'PyMysqlPool Documentation', 151 | [author], 1) 152 | ] 153 | 154 | # -- Options for Texinfo output ------------------------------------------- 155 | 156 | # Grouping the document tree into Texinfo files. List of tuples 157 | # (source start file, target name, title, author, 158 | # dir menu entry, description, category) 159 | texinfo_documents = [ 160 | (master_doc, 'PyMysqlPool', u'PyMysqlPool Documentation', 161 | author, 'PyMysqlPool', 'One line description of project.', 162 | 'Miscellaneous'), 163 | ] 164 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. PyMysqlPool documentation master file, created by 2 | sphinx-quickstart on Wed Aug 23 16:56:20 2017. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to PyMysqlPool's documentation! 7 | ======================================= 8 | 9 | .. toctree:: 10 | :maxdepth: 2 11 | :caption: Contents: 12 | 13 | 14 | 15 | Indices and tables 16 | ================== 17 | 18 | * :ref:`genindex` 19 | * :ref:`modindex` 20 | * :ref:`search` 21 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | pytest -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | description-file = README.rst 3 | [bdist_wheel] 4 | # This flag says that the code is written to work on both Python 2 and Python 5 | # 3. If at all possible, it is good practice to do this. If you cannot, you 6 | # will need to generate wheels for each Python version that you support. 7 | universal=1 -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """A setuptools based setup module. 2 | See: 3 | https://packaging.python.org/en/latest/distributing.html 4 | https://github.com/pypa/sampleproject 5 | """ 6 | 7 | # Always prefer setuptools over distutils 8 | import os 9 | from codecs import open 10 | from os import path 11 | 12 | from setuptools import setup, find_packages, Command 13 | 14 | here = path.abspath(path.dirname(__file__)) 15 | 16 | # Get the long description from the README file 17 | with open(path.join(here, 'README.rst'), encoding='utf-8') as f: 18 | long_description = f.read() 19 | 20 | 21 | class CleanCommand(Command): 22 | """Custom clean command to tidy up the project root.""" 23 | user_options = [] 24 | 25 | def initialize_options(self): 26 | pass 27 | 28 | def finalize_options(self): 29 | pass 30 | 31 | def run(self): 32 | os.system("find ./ -name '*.pyc' | xargs rm") 33 | 34 | 35 | # Further down when you call setup() 36 | 37 | setup( 38 | name='PyMysqlPool', 39 | 40 | # Versions should comply with PEP440. For a discussion on single-sourcing 41 | # the version across setup.py and the project code, see 42 | # https://packaging.python.org/en/latest/single_source_version.html 43 | version='1.0.9', 44 | 45 | description='python practical mysql pool -motivation from=>[lost connection to MySQL server during query] base on mysql-connector ' 46 | 'support fixed | dynamic pool', 47 | long_description=long_description, 48 | 49 | # The project's main homepage. 50 | url='https://codeload.github.com/LuciferJack/python-mysql-pool/zip/master', 51 | 52 | # Author details 53 | author='Lucifer Jack', 54 | author_email='lujunxucuc@gmail.com', 55 | 56 | # Choose your license 57 | license='MIT', 58 | 59 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 60 | classifiers=[ 61 | # How mature is this project? Common values are 62 | # 3 - Alpha 63 | # 4 - Beta 64 | # 5 - Production/Stable 65 | 'Development Status :: 3 - Alpha', 66 | 67 | # Indicate who your project is intended for 68 | 'Intended Audience :: Developers', 69 | 'Topic :: Database :: Database Engines/Servers', 70 | 71 | # Pick your license as you wish (should match "license" above) 72 | 'License :: OSI Approved :: MIT License', 73 | 74 | # Specify the Python versions you support here. In particular, ensure 75 | # that you indicate whether you support Python 2, Python 3 or both. 76 | 'Programming Language :: Python :: 2', 77 | 'Programming Language :: Python :: 2.7', 78 | 'Programming Language :: Python :: 3', 79 | 'Programming Language :: Python :: 3.3', 80 | 'Programming Language :: Python :: 3.4', 81 | 'Programming Language :: Python :: 3.5', 82 | ], 83 | 84 | # What does your project relate to? 85 | keywords=['mysql pool', 'queue', 'support list', 'dynamic pool', 'fixed pool'], 86 | 87 | # You can just specify the packages manually here if your project is 88 | # simple. Or you can use find_packages(). 89 | packages=find_packages(exclude=['contrib', 'docs', 'tests']), 90 | 91 | # Alternatively, if you want to distribute just a my_module.py, uncomment 92 | # this: 93 | # py_modules=["my_module"], 94 | 95 | # List run-time dependencies here. These will be installed by pip when 96 | # your project is installed. For an analysis of "install_requires" vs pip's 97 | # requirements files see: 98 | # https://packaging.python.org/en/latest/requirements.html 99 | install_requires=[ 100 | 'mysqlclient', 101 | 'mysql-connector-python-rf', 102 | 'wheel', 103 | ], 104 | 105 | # List additional groups of dependencies here (e.g. development 106 | # dependencies). You can install these using the following syntax, 107 | # for example: 108 | # $ pip install -e .[dev,test] 109 | extras_require={ 110 | # 'dev': ['check-manifest'], 111 | # 'test': ['coverage'], 112 | }, 113 | 114 | # If there are data files included in your packages that need to be 115 | # installed, specify them here. If using Python 2.6 or less, then these 116 | # have to be included in MANIFEST.in as well. 117 | package_data={ 118 | # 'sample': ['package_data.dat'], 119 | }, 120 | 121 | # Although 'package_data' is the preferred approach, in some case you may 122 | # need to place data files outside of your packages. See: 123 | # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files # noqa 124 | # In this case, 'data_file' will be installed into '/my_data' 125 | # data_files=[('my_data', ['data/data_file'])], 126 | 127 | # To provide executable scripts, use entry points in preference to the 128 | # "scripts" keyword. Entry points provide cross-platform support and allow 129 | # pip to create the appropriate form of executable for the target platform. 130 | entry_points={ 131 | # 'console_scripts': [ 132 | # 'sample=sample:main', 133 | # ], 134 | }, 135 | # ... Other setup options 136 | cmdclass={ 137 | 'clean': CleanCommand, 138 | } 139 | ) 140 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | import sys 4 | 5 | if __name__ == '__main__': 6 | logging.info('main starts...') 7 | logging.info('main stop') 8 | sys.exit(0) 9 | -------------------------------------------------------------------------------- /testssl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # coding=utf-8 4 | 5 | import ssl 6 | 7 | import requests 8 | 9 | print('OpenSSL: {0}'.format(ssl.OPENSSL_VERSION)) 10 | print('requests: {0}'.format(requests.__version__)) 11 | --------------------------------------------------------------------------------